1#include "mupdf/fitz.h"
2#include "mupdf/pdf.h"
3
4static void
5pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
6{
7 fz_matrix page_ctm;
8 fz_rect mediabox;
9 pdf_processor *proc = NULL;
10 fz_default_colorspaces *default_cs = NULL;
11 int flags;
12
13 fz_var(proc);
14 fz_var(default_cs);
15
16 if (cookie && page->super.incomplete)
17 cookie->incomplete = 1;
18
19 fz_try(ctx)
20 {
21 default_cs = pdf_load_default_colorspaces(ctx, doc, page);
22 if (default_cs)
23 fz_set_default_colorspaces(ctx, dev, default_cs);
24
25 pdf_page_transform(ctx, page, &mediabox, &page_ctm);
26
27 flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
28 if (flags & PDF_ANNOT_IS_NO_ROTATE)
29 {
30 int rotate = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Rotate)));
31 fz_rect rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
32 fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm);
33 page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y));
34 page_ctm = fz_concat(page_ctm, fz_rotate(-rotate));
35 page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y));
36 }
37
38 ctm = fz_concat(page_ctm, ctm);
39
40 proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie);
41 pdf_process_annot(ctx, proc, doc, page, annot, cookie);
42 pdf_close_processor(ctx, proc);
43 }
44 fz_always(ctx)
45 {
46 pdf_drop_processor(ctx, proc);
47 fz_drop_default_colorspaces(ctx, default_cs);
48 }
49 fz_catch(ctx)
50 fz_rethrow(ctx);
51}
52
53static void
54pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
55{
56 fz_matrix page_ctm;
57 pdf_obj *resources;
58 pdf_obj *contents;
59 fz_rect mediabox;
60 pdf_processor *proc = NULL;
61 fz_default_colorspaces *default_cs = NULL;
62 fz_colorspace *colorspace = NULL;
63
64 fz_var(proc);
65 fz_var(colorspace);
66 fz_var(default_cs);
67
68 if (cookie && page->super.incomplete)
69 cookie->incomplete = 1;
70
71 fz_try(ctx)
72 {
73 default_cs = pdf_load_default_colorspaces(ctx, doc, page);
74 if (default_cs)
75 fz_set_default_colorspaces(ctx, dev, default_cs);
76
77 pdf_page_transform(ctx, page, &mediabox, &page_ctm);
78 ctm = fz_concat(page_ctm, ctm);
79 mediabox = fz_transform_rect(mediabox, ctm);
80
81 resources = pdf_page_resources(ctx, page);
82 contents = pdf_page_contents(ctx, page);
83
84 if (page->transparency)
85 {
86 pdf_obj *group = pdf_page_group(ctx, page);
87
88 if (group)
89 {
90 pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME(CS));
91 if (cs)
92 {
93 fz_try(ctx)
94 colorspace = pdf_load_colorspace(ctx, cs);
95 fz_catch(ctx)
96 {
97 fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
98 fz_warn(ctx, "Ignoring Page blending colorspace.");
99 }
100 if (!fz_is_valid_blend_colorspace(ctx, colorspace))
101 {
102 fz_warn(ctx, "Ignoring invalid Page blending colorspace: %s.", colorspace->name);
103 fz_drop_colorspace(ctx, colorspace);
104 colorspace = NULL;
105 }
106 }
107 }
108 else
109 colorspace = fz_keep_colorspace(ctx, fz_default_output_intent(ctx, default_cs));
110
111 fz_begin_group(ctx, dev, mediabox, colorspace, 1, 0, 0, 1);
112 }
113
114 proc = pdf_new_run_processor(ctx, dev, ctm, usage, NULL, default_cs, cookie);
115 pdf_process_contents(ctx, proc, doc, resources, contents, cookie);
116 pdf_close_processor(ctx, proc);
117
118 if (page->transparency)
119 {
120 fz_end_group(ctx, dev);
121 }
122 }
123 fz_always(ctx)
124 {
125 pdf_drop_processor(ctx, proc);
126 fz_drop_colorspace(ctx, colorspace);
127 fz_drop_default_colorspaces(ctx, default_cs);
128 }
129 fz_catch(ctx)
130 {
131 fz_rethrow(ctx);
132 }
133}
134
135/*
136 Interpret a loaded page and render it on a device.
137 Just the main page contents without the annotations
138
139 page: A page loaded by pdf_load_page.
140
141 dev: Device used for rendering, obtained from fz_new_*_device.
142
143 ctm: A transformation matrix applied to the objects on the page,
144 e.g. to scale or rotate the page contents as desired.
145*/
146void pdf_run_page_contents(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
147{
148 pdf_document *doc = page->doc;
149 int nocache;
150
151 nocache = !!(dev->hints & FZ_NO_CACHE);
152 if (nocache)
153 pdf_mark_xref(ctx, doc);
154
155 fz_try(ctx)
156 {
157 pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
158 }
159 fz_always(ctx)
160 {
161 if (nocache)
162 pdf_clear_xref_to_mark(ctx, doc);
163 }
164 fz_catch(ctx)
165 {
166 fz_rethrow(ctx);
167 }
168}
169
170/*
171 Interpret an annotation and render it on a device.
172
173 page: A page loaded by pdf_load_page.
174
175 annot: an annotation.
176
177 dev: Device used for rendering, obtained from fz_new_*_device.
178
179 ctm: A transformation matrix applied to the objects on the page,
180 e.g. to scale or rotate the page contents as desired.
181*/
182void pdf_run_annot(fz_context *ctx, pdf_annot *annot, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
183{
184 pdf_page *page = annot->page;
185 pdf_document *doc = page->doc;
186 int nocache;
187
188 nocache = !!(dev->hints & FZ_NO_CACHE);
189 if (nocache)
190 pdf_mark_xref(ctx, doc);
191 fz_try(ctx)
192 {
193 pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, "View", cookie);
194 }
195 fz_always(ctx)
196 {
197 if (nocache)
198 pdf_clear_xref_to_mark(ctx, doc);
199 }
200 fz_catch(ctx)
201 {
202 fz_rethrow(ctx);
203 }
204}
205
206static void
207pdf_run_page_widgets_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
208{
209 pdf_widget *widget;
210
211 if (cookie && cookie->progress_max != -1)
212 {
213 int count = 1;
214 for (widget = page->widgets; widget; widget = widget->next)
215 count++;
216 cookie->progress_max += count;
217 }
218
219 for (widget = page->widgets; widget; widget = widget->next)
220 {
221 /* Check the cookie for aborting */
222 if (cookie)
223 {
224 if (cookie->abort)
225 break;
226 cookie->progress++;
227 }
228
229 pdf_run_annot_with_usage(ctx, doc, page, widget, dev, ctm, usage, cookie);
230 }
231}
232
233static void
234pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
235{
236 pdf_annot *annot;
237
238 if (cookie && cookie->progress_max != -1)
239 {
240 int count = 1;
241 for (annot = page->annots; annot; annot = annot->next)
242 count++;
243 cookie->progress_max += count;
244 }
245
246 for (annot = page->annots; annot; annot = annot->next)
247 {
248 /* Check the cookie for aborting */
249 if (cookie)
250 {
251 if (cookie->abort)
252 break;
253 cookie->progress++;
254 }
255
256 pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, usage, cookie);
257 }
258}
259
260void pdf_run_page_annots(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
261{
262 pdf_document *doc = page->doc;
263 int nocache;
264
265 nocache = !!(dev->hints & FZ_NO_CACHE);
266 if (nocache)
267 pdf_mark_xref(ctx, doc);
268
269 fz_try(ctx)
270 {
271 pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
272 }
273 fz_always(ctx)
274 {
275 if (nocache)
276 pdf_clear_xref_to_mark(ctx, doc);
277 }
278 fz_catch(ctx)
279 {
280 fz_rethrow(ctx);
281 }
282}
283
284void pdf_run_page_widgets(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
285{
286 pdf_document *doc = page->doc;
287 int nocache;
288
289 nocache = !!(dev->hints & FZ_NO_CACHE);
290 if (nocache)
291 pdf_mark_xref(ctx, doc);
292
293 fz_try(ctx)
294 {
295 pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
296 }
297 fz_always(ctx)
298 {
299 if (nocache)
300 pdf_clear_xref_to_mark(ctx, doc);
301 }
302 fz_catch(ctx)
303 {
304 fz_rethrow(ctx);
305 }
306}
307
308/*
309 Interpret a loaded page and render it on a device.
310
311 page: A page loaded by pdf_load_page.
312
313 dev: Device used for rendering, obtained from fz_new_*_device.
314
315 ctm: A transformation matrix applied to the objects on the page,
316 e.g. to scale or rotate the page contents as desired.
317
318 usage: The 'usage' for displaying the file (typically
319 'View', 'Print' or 'Export'). NULL means 'View'.
320
321 cookie: A pointer to an optional fz_cookie structure that can be used
322 to track progress, collect errors etc.
323*/
324void
325pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie)
326{
327 int nocache = !!(dev->hints & FZ_NO_CACHE);
328
329 if (nocache)
330 pdf_mark_xref(ctx, doc);
331 fz_try(ctx)
332 {
333 pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
334 pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
335 pdf_run_page_widgets_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
336 }
337 fz_always(ctx)
338 {
339 if (nocache)
340 pdf_clear_xref_to_mark(ctx, doc);
341 }
342 fz_catch(ctx)
343 {
344 fz_rethrow(ctx);
345 }
346}
347
348/*
349 Interpret a loaded page and render it on a device.
350
351 page: A page loaded by pdf_load_page.
352
353 dev: Device used for rendering, obtained from fz_new_*_device.
354
355 ctm: A transformation matrix applied to the objects on the page,
356 e.g. to scale or rotate the page contents as desired.
357*/
358void
359pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
360{
361 pdf_document *doc = page->doc;
362 pdf_run_page_with_usage(ctx, doc, page, dev, ctm, "View", cookie);
363}
364
365void
366pdf_run_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, fz_default_colorspaces *default_cs)
367{
368 pdf_processor *proc;
369
370 proc = pdf_new_run_processor(ctx, dev, ctm, "View", gstate, default_cs, NULL);
371 fz_try(ctx)
372 {
373 pdf_process_glyph(ctx, proc, doc, resources, contents);
374 pdf_close_processor(ctx, proc);
375 }
376 fz_always(ctx)
377 pdf_drop_processor(ctx, proc);
378 fz_catch(ctx)
379 fz_rethrow(ctx);
380}
381