1pub mod image;
6pub mod parallel;
7pub mod pdf;
8pub mod ps;
9#[cfg(feature = "raster")]
10pub mod raster;
11pub mod svg;
12pub mod text;
13
14pub use fop_types::{FopError, Result};
15pub use image::{ImageFormat, ImageInfo, ImagePlacement};
16pub use parallel::ParallelRenderer;
17pub use pdf::{
18 EncryptionAlgorithm, EncryptionDict, FontConfig, PdfCompliance, PdfDocument, PdfGraphics,
19 PdfPermissions, PdfRenderer, PdfSecurity, PdfValidator, ValidationResult,
20};
21pub use ps::{PsDocument, PsRenderer};
22#[cfg(feature = "raster")]
23pub use raster::{RasterFormat, RasterRenderer};
24pub use svg::{SvgDocument, SvgGraphics, SvgRenderer};
25pub use text::TextRenderer;
26
27#[cfg(test)]
28mod tests {
29 use fop_core::FoTreeBuilder;
30 use fop_layout::{AreaTree, LayoutEngine};
31 use std::io::Cursor;
32
33 fn minimal_area_tree() -> AreaTree {
35 let fo_xml = r##"<?xml version="1.0"?>
36<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
37 <fo:layout-master-set>
38 <fo:simple-page-master master-name="A4"
39 page-width="210mm" page-height="297mm"
40 margin-top="20mm" margin-bottom="20mm"
41 margin-left="20mm" margin-right="20mm">
42 <fo:region-body/>
43 </fo:simple-page-master>
44 </fo:layout-master-set>
45 <fo:page-sequence master-reference="A4">
46 <fo:flow flow-name="xsl-region-body">
47 <fo:block>Hello, world!</fo:block>
48 </fo:flow>
49 </fo:page-sequence>
50</fo:root>"##;
51 let builder = FoTreeBuilder::new();
52 let fo_tree = builder
53 .parse(Cursor::new(fo_xml))
54 .expect("test: should succeed");
55 let engine = LayoutEngine::new();
56 engine.layout(&fo_tree).expect("test: should succeed")
57 }
58
59 #[test]
62 fn test_pdf_render_produces_bytes() {
63 let area_tree = minimal_area_tree();
64 let renderer = crate::PdfRenderer::new();
65 let doc = renderer.render(&area_tree).expect("test: should succeed");
66 let bytes = doc.to_bytes().expect("test: should succeed");
67 assert!(!bytes.is_empty(), "PDF output must not be empty");
68 assert!(
69 bytes.starts_with(b"%PDF-"),
70 "PDF must start with %PDF- header"
71 );
72 }
73
74 #[test]
75 fn test_pdf_render_has_one_page() {
76 let area_tree = minimal_area_tree();
77 let renderer = crate::PdfRenderer::new();
78 let doc = renderer.render(&area_tree).expect("test: should succeed");
79 assert_eq!(
80 doc.pages.len(),
81 1,
82 "single page-sequence must produce 1 PDF page"
83 );
84 }
85
86 #[test]
87 fn test_pdf_render_has_eof() {
88 let area_tree = minimal_area_tree();
89 let renderer = crate::PdfRenderer::new();
90 let bytes = renderer
91 .render(&area_tree)
92 .expect("test: should succeed")
93 .to_bytes()
94 .expect("test: should succeed");
95 let content = String::from_utf8_lossy(&bytes);
96 assert!(content.contains("%%EOF"), "PDF must end with %%EOF");
97 }
98
99 #[test]
100 fn test_pdf_render_contains_text() {
101 let area_tree = minimal_area_tree();
102 let renderer = crate::PdfRenderer::new();
103 let bytes = renderer
104 .render(&area_tree)
105 .expect("test: should succeed")
106 .to_bytes()
107 .expect("test: should succeed");
108 let content = String::from_utf8_lossy(&bytes);
109 assert!(
110 content.contains("Hello, world!"),
111 "PDF must contain the rendered text"
112 );
113 }
114
115 #[test]
118 fn test_svg_render_produces_string() {
119 let area_tree = minimal_area_tree();
120 let renderer = crate::SvgRenderer::new();
121 let result = renderer
122 .render_to_svg(&area_tree)
123 .expect("test: should succeed");
124 assert!(!result.is_empty(), "SVG output must not be empty");
125 }
126
127 #[test]
128 fn test_svg_render_has_xml_declaration() {
129 let area_tree = minimal_area_tree();
130 let renderer = crate::SvgRenderer::new();
131 let result = renderer
132 .render_to_svg(&area_tree)
133 .expect("test: should succeed");
134 assert!(
135 result.starts_with("<?xml"),
136 "SVG output must start with XML declaration"
137 );
138 }
139
140 #[test]
141 fn test_svg_render_has_svg_element() {
142 let area_tree = minimal_area_tree();
143 let renderer = crate::SvgRenderer::new();
144 let result = renderer
145 .render_to_svg(&area_tree)
146 .expect("test: should succeed");
147 assert!(
148 result.contains("<svg"),
149 "SVG output must contain <svg element"
150 );
151 }
152
153 #[test]
154 fn test_svg_render_contains_text() {
155 let area_tree = minimal_area_tree();
156 let renderer = crate::SvgRenderer::new();
157 let result = renderer
158 .render_to_svg(&area_tree)
159 .expect("test: should succeed");
160 assert!(
161 result.contains("Hello, world!"),
162 "SVG output must contain the rendered text"
163 );
164 }
165
166 #[test]
167 fn test_svg_render_pages_produces_one_page() {
168 let area_tree = minimal_area_tree();
169 let renderer = crate::SvgRenderer::new();
170 let pages = renderer
171 .render_to_svg_pages(&area_tree)
172 .expect("test: should succeed");
173 assert_eq!(
174 pages.len(),
175 1,
176 "single page-sequence must produce 1 SVG page"
177 );
178 }
179
180 #[test]
181 fn test_svg_render_each_page_is_valid_svg() {
182 let area_tree = minimal_area_tree();
183 let renderer = crate::SvgRenderer::new();
184 let pages = renderer
185 .render_to_svg_pages(&area_tree)
186 .expect("test: should succeed");
187 for (i, page) in pages.iter().enumerate() {
188 assert!(
189 page.contains("<svg"),
190 "SVG page {i} must contain <svg element"
191 );
192 assert!(page.contains("</svg>"), "SVG page {i} must close </svg>");
193 }
194 }
195
196 #[test]
199 fn test_ps_render_produces_string() {
200 let area_tree = minimal_area_tree();
201 let renderer = crate::PsRenderer::new();
202 let result = renderer
203 .render_to_ps(&area_tree)
204 .expect("test: should succeed");
205 assert!(!result.is_empty(), "PostScript output must not be empty");
206 }
207
208 #[test]
209 fn test_ps_render_has_ps_header() {
210 let area_tree = minimal_area_tree();
211 let renderer = crate::PsRenderer::new();
212 let result = renderer
213 .render_to_ps(&area_tree)
214 .expect("test: should succeed");
215 assert!(
216 result.starts_with("%!PS-Adobe-3.0"),
217 "PostScript output must start with %!PS-Adobe-3.0"
218 );
219 }
220
221 #[test]
222 fn test_ps_render_has_eof() {
223 let area_tree = minimal_area_tree();
224 let renderer = crate::PsRenderer::new();
225 let result = renderer
226 .render_to_ps(&area_tree)
227 .expect("test: should succeed");
228 assert!(
229 result.contains("%%EOF"),
230 "PostScript output must contain %%EOF"
231 );
232 }
233
234 #[test]
235 fn test_ps_render_has_one_page() {
236 let area_tree = minimal_area_tree();
237 let renderer = crate::PsRenderer::new();
238 let result = renderer
239 .render_to_ps(&area_tree)
240 .expect("test: should succeed");
241 assert!(
242 result.contains("%%Pages: 1"),
243 "single page-sequence must produce 1 PostScript page"
244 );
245 }
246
247 #[test]
250 fn test_text_render_produces_string() {
251 let area_tree = minimal_area_tree();
252 let renderer = crate::TextRenderer::new();
253 let result = renderer
254 .render_to_text(&area_tree)
255 .expect("test: should succeed");
256 assert!(!result.is_empty(), "text output must not be empty");
257 }
258
259 #[test]
260 fn test_text_render_contains_content() {
261 let area_tree = minimal_area_tree();
262 let renderer = crate::TextRenderer::new();
263 let result = renderer
264 .render_to_text(&area_tree)
265 .expect("test: should succeed");
266 assert!(
267 result.contains("Hello, world!"),
268 "text output must contain the rendered text"
269 );
270 }
271
272 #[test]
275 fn test_all_renderers_constructible() {
276 let _pdf = crate::PdfRenderer::new();
277 let _svg = crate::SvgRenderer::new();
278 let _ps = crate::PsRenderer::new();
279 let _text = crate::TextRenderer::new();
280 }
282
283 #[test]
284 fn test_pdf_renderer_with_system_fonts_constructible() {
285 let renderer = crate::PdfRenderer::with_system_fonts();
286 let _ = renderer;
287 }
288}