/src/mupdf/source/pdf/pdf-run.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2026 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | #include "pdf-annot-imp.h" |
25 | | |
26 | | static void |
27 | | pdf_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) |
28 | 445 | { |
29 | 445 | fz_matrix page_ctm; |
30 | 445 | fz_rect mediabox; |
31 | 445 | pdf_processor *proc = NULL; |
32 | 445 | fz_default_colorspaces *default_cs = NULL; |
33 | 445 | int resources_pushed = 0; |
34 | 445 | int struct_parent_num; |
35 | 445 | pdf_obj *struct_parent; |
36 | | |
37 | 445 | fz_var(proc); |
38 | 445 | fz_var(default_cs); |
39 | 445 | fz_var(resources_pushed); |
40 | | |
41 | 445 | if (cookie && page->super.incomplete) |
42 | 0 | cookie->incomplete = 1; |
43 | | |
44 | 445 | pdf_annot_push_local_xref(ctx, annot); |
45 | | |
46 | 890 | fz_try(ctx) |
47 | 890 | { |
48 | 445 | default_cs = pdf_load_default_colorspaces(ctx, doc, page); |
49 | 445 | if (default_cs) |
50 | 445 | fz_set_default_colorspaces(ctx, dev, default_cs); |
51 | | |
52 | 445 | pdf_page_transform(ctx, page, &mediabox, &page_ctm); |
53 | | |
54 | 445 | ctm = fz_concat(page_ctm, ctm); |
55 | | |
56 | 445 | struct_parent = pdf_dict_getl(ctx, page->obj, PDF_NAME(StructParent), NULL); |
57 | 445 | struct_parent_num = pdf_to_int_default(ctx, struct_parent, -1); |
58 | | |
59 | 445 | proc = pdf_new_run_processor(ctx, page->doc, dev, ctm, struct_parent_num, usage, NULL, default_cs, cookie, NULL, NULL); |
60 | 445 | pdf_processor_push_resources(ctx, proc, pdf_page_resources(ctx, annot->page)); |
61 | 445 | resources_pushed = 1; |
62 | 445 | pdf_process_annot(ctx, proc, annot, cookie); |
63 | 445 | pdf_close_processor(ctx, proc); |
64 | 445 | } |
65 | 890 | fz_always(ctx) |
66 | 445 | { |
67 | 445 | if (resources_pushed) |
68 | 445 | pdf_drop_obj(ctx, pdf_processor_pop_resources(ctx, proc)); |
69 | 445 | pdf_drop_processor(ctx, proc); |
70 | 445 | fz_drop_default_colorspaces(ctx, default_cs); |
71 | 445 | pdf_annot_pop_local_xref(ctx, annot); |
72 | 445 | } |
73 | 445 | fz_catch(ctx) |
74 | 0 | fz_rethrow(ctx); |
75 | 445 | } |
76 | | |
77 | | static fz_rect pdf_page_cropbox(fz_context *ctx, pdf_page *page) |
78 | 326 | { |
79 | 326 | pdf_obj *obj = pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(CropBox)); |
80 | 326 | if (!obj) |
81 | 201 | obj = pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(MediaBox)); |
82 | 326 | return pdf_to_rect(ctx, obj); |
83 | 326 | } |
84 | | |
85 | | static fz_rect pdf_page_mediabox(fz_context *ctx, pdf_page *page) |
86 | 326 | { |
87 | 326 | return pdf_dict_get_inheritable_rect(ctx, page->obj, PDF_NAME(MediaBox)); |
88 | 326 | } |
89 | | |
90 | | static void |
91 | | pdf_run_page_contents_with_usage_imp(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
92 | 326 | { |
93 | 326 | fz_matrix page_ctm; |
94 | 326 | pdf_obj *resources; |
95 | 326 | pdf_obj *contents; |
96 | 326 | fz_rect fitzbox; |
97 | 326 | fz_rect mediabox, cropbox; |
98 | 326 | pdf_processor *proc = NULL; |
99 | 326 | fz_default_colorspaces *default_cs = NULL; |
100 | 326 | fz_colorspace *colorspace = NULL; |
101 | 326 | fz_path *path = NULL; |
102 | 326 | int struct_parent_num; |
103 | 326 | pdf_obj *struct_parent; |
104 | | |
105 | 326 | fz_var(proc); |
106 | 326 | fz_var(colorspace); |
107 | 326 | fz_var(default_cs); |
108 | 326 | fz_var(path); |
109 | | |
110 | 326 | if (cookie && page->super.incomplete) |
111 | 0 | cookie->incomplete = 1; |
112 | | |
113 | 652 | fz_try(ctx) |
114 | 652 | { |
115 | 326 | default_cs = pdf_load_default_colorspaces(ctx, doc, page); |
116 | 326 | if (default_cs) |
117 | 326 | fz_set_default_colorspaces(ctx, dev, default_cs); |
118 | | |
119 | 326 | pdf_page_transform(ctx, page, &fitzbox, &page_ctm); |
120 | 326 | ctm = fz_concat(page_ctm, ctm); |
121 | 326 | fitzbox = fz_transform_rect(fitzbox, ctm); |
122 | | |
123 | 326 | resources = pdf_page_resources(ctx, page); |
124 | 326 | contents = pdf_page_contents(ctx, page); |
125 | | |
126 | 326 | mediabox = pdf_page_mediabox(ctx, page); |
127 | 326 | cropbox = pdf_page_cropbox(ctx, page); |
128 | | |
129 | 326 | if (page->transparency) |
130 | 90 | { |
131 | 90 | pdf_obj *group = pdf_page_group(ctx, page); |
132 | | |
133 | 90 | if (group) |
134 | 1 | { |
135 | 1 | pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME(CS)); |
136 | 1 | if (cs) |
137 | 1 | { |
138 | 2 | fz_try(ctx) |
139 | 2 | colorspace = pdf_load_colorspace(ctx, cs); |
140 | 2 | fz_catch(ctx) |
141 | 0 | { |
142 | 0 | fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); |
143 | 0 | fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); |
144 | 0 | fz_report_error(ctx); |
145 | 0 | fz_warn(ctx, "Ignoring Page blending colorspace."); |
146 | 0 | } |
147 | 1 | if (!fz_is_valid_blend_colorspace(ctx, colorspace)) |
148 | 0 | { |
149 | 0 | fz_warn(ctx, "Ignoring invalid Page blending colorspace: %s.", colorspace->name); |
150 | 0 | fz_drop_colorspace(ctx, colorspace); |
151 | 0 | colorspace = NULL; |
152 | 0 | } |
153 | 1 | } |
154 | 1 | } |
155 | 89 | else |
156 | 89 | colorspace = fz_keep_colorspace(ctx, fz_default_output_intent(ctx, default_cs)); |
157 | | |
158 | 90 | fz_begin_group(ctx, dev, fitzbox, colorspace, 1, 0, 0, 1); |
159 | 90 | } |
160 | | |
161 | 326 | struct_parent = pdf_dict_get(ctx, page->obj, PDF_NAME(StructParents)); |
162 | 326 | struct_parent_num = pdf_to_int_default(ctx, struct_parent, -1); |
163 | | |
164 | | /* Clip content to CropBox if it is smaller than the MediaBox */ |
165 | 326 | if (cropbox.x0 > mediabox.x0 || cropbox.x1 < mediabox.x1 || cropbox.y0 > mediabox.y0 || cropbox.y1 < mediabox.y1) |
166 | 10 | { |
167 | 10 | path = fz_new_path(ctx); |
168 | 10 | fz_rectto(ctx, path, cropbox.x0, cropbox.y0, cropbox.x1, cropbox.y1); |
169 | 10 | fz_clip_path(ctx, dev, path, 1, ctm, fz_infinite_rect); |
170 | 10 | } |
171 | | |
172 | 326 | proc = pdf_new_run_processor(ctx, page->doc, dev, ctm, struct_parent_num, usage, NULL, default_cs, cookie, NULL, NULL); |
173 | 326 | pdf_process_contents(ctx, proc, doc, resources, contents, cookie, NULL); |
174 | 326 | pdf_close_processor(ctx, proc); |
175 | | |
176 | 326 | if (cropbox.x0 > mediabox.x0 || cropbox.x1 < mediabox.x1 || cropbox.y0 > mediabox.y0 || cropbox.y1 < mediabox.y1) |
177 | 10 | { |
178 | 10 | fz_pop_clip(ctx, dev); |
179 | 10 | } |
180 | | |
181 | 326 | if (page->transparency) |
182 | 88 | { |
183 | 88 | fz_end_group(ctx, dev); |
184 | 88 | } |
185 | 326 | } |
186 | 652 | fz_always(ctx) |
187 | 326 | { |
188 | 326 | fz_drop_path(ctx, path); |
189 | 326 | pdf_drop_processor(ctx, proc); |
190 | 326 | fz_drop_colorspace(ctx, colorspace); |
191 | 326 | fz_drop_default_colorspaces(ctx, default_cs); |
192 | 326 | } |
193 | 326 | fz_catch(ctx) |
194 | 4 | { |
195 | 4 | fz_rethrow(ctx); |
196 | 4 | } |
197 | 326 | } |
198 | | |
199 | | void pdf_run_page_contents_with_usage(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
200 | 326 | { |
201 | 326 | pdf_document *doc = page->doc; |
202 | 326 | int nocache; |
203 | | |
204 | 326 | nocache = !!(dev->hints & FZ_NO_CACHE); |
205 | 326 | if (nocache) |
206 | 0 | pdf_mark_xref(ctx, doc); |
207 | | |
208 | 652 | fz_try(ctx) |
209 | 652 | { |
210 | 326 | pdf_run_page_contents_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
211 | 326 | } |
212 | 652 | fz_always(ctx) |
213 | 326 | { |
214 | 326 | if (nocache) |
215 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
216 | 326 | } |
217 | 326 | fz_catch(ctx) |
218 | 4 | { |
219 | 4 | fz_rethrow(ctx); |
220 | 4 | } |
221 | 326 | } |
222 | | |
223 | | void pdf_run_page_contents(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
224 | 326 | { |
225 | 326 | pdf_run_page_contents_with_usage(ctx, page, dev, ctm, "View", cookie); |
226 | 326 | } |
227 | | |
228 | | void pdf_run_annot(fz_context *ctx, pdf_annot *annot, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
229 | 0 | { |
230 | 0 | pdf_page *page = annot->page; |
231 | 0 | pdf_document *doc; |
232 | 0 | int nocache; |
233 | |
|
234 | 0 | if (!page) |
235 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page"); |
236 | | |
237 | 0 | pdf_update_page(ctx, page); |
238 | |
|
239 | 0 | doc = page->doc; |
240 | |
|
241 | 0 | nocache = !!(dev->hints & FZ_NO_CACHE); |
242 | 0 | if (nocache) |
243 | 0 | pdf_mark_xref(ctx, doc); |
244 | 0 | fz_try(ctx) |
245 | 0 | { |
246 | 0 | pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, "View", cookie); |
247 | 0 | } |
248 | 0 | fz_always(ctx) |
249 | 0 | { |
250 | 0 | if (nocache) |
251 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
252 | 0 | } |
253 | 0 | fz_catch(ctx) |
254 | 0 | { |
255 | 0 | fz_rethrow(ctx); |
256 | 0 | } |
257 | 0 | } |
258 | | |
259 | | static void |
260 | | pdf_run_page_widgets_with_usage_imp(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
261 | 322 | { |
262 | 322 | pdf_annot *widget; |
263 | | |
264 | 322 | if (cookie && cookie->progress_max != (size_t)-1) |
265 | 0 | { |
266 | 0 | int count = 1; |
267 | 0 | for (widget = page->widgets; widget; widget = widget->next) |
268 | 0 | count++; |
269 | 0 | cookie->progress_max += count; |
270 | 0 | } |
271 | | |
272 | 682 | for (widget = page->widgets; widget; widget = widget->next) |
273 | 360 | { |
274 | | /* Check the cookie for aborting */ |
275 | 360 | if (cookie) |
276 | 0 | { |
277 | 0 | if (cookie->abort) |
278 | 0 | break; |
279 | 0 | cookie->progress++; |
280 | 0 | } |
281 | | |
282 | 360 | pdf_run_annot_with_usage(ctx, doc, page, widget, dev, ctm, usage, cookie); |
283 | 360 | } |
284 | 322 | } |
285 | | |
286 | | static void |
287 | | pdf_run_page_annots_with_usage_imp(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
288 | 322 | { |
289 | 322 | pdf_annot *annot; |
290 | | |
291 | 322 | if (cookie && cookie->progress_max != (size_t)-1) |
292 | 0 | { |
293 | 0 | int count = 1; |
294 | 0 | for (annot = page->annots; annot; annot = annot->next) |
295 | 0 | count++; |
296 | 0 | cookie->progress_max += count; |
297 | 0 | } |
298 | | |
299 | 407 | for (annot = page->annots; annot; annot = annot->next) |
300 | 85 | { |
301 | | /* Check the cookie for aborting */ |
302 | 85 | if (cookie) |
303 | 0 | { |
304 | 0 | if (cookie->abort) |
305 | 0 | break; |
306 | 0 | cookie->progress++; |
307 | 0 | } |
308 | | |
309 | 85 | pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, usage, cookie); |
310 | 85 | } |
311 | 322 | } |
312 | | |
313 | | void pdf_run_page_annots_with_usage(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
314 | 322 | { |
315 | 322 | pdf_document *doc = page->doc; |
316 | 322 | int nocache; |
317 | | |
318 | 322 | pdf_update_page(ctx, page); |
319 | | |
320 | 322 | nocache = !!(dev->hints & FZ_NO_CACHE); |
321 | 322 | if (nocache) |
322 | 0 | pdf_mark_xref(ctx, doc); |
323 | | |
324 | 644 | fz_try(ctx) |
325 | 644 | { |
326 | 322 | pdf_run_page_annots_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
327 | 322 | } |
328 | 644 | fz_always(ctx) |
329 | 322 | { |
330 | 322 | if (nocache) |
331 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
332 | 322 | } |
333 | 322 | fz_catch(ctx) |
334 | 0 | { |
335 | 0 | fz_rethrow(ctx); |
336 | 0 | } |
337 | 322 | } |
338 | | |
339 | | void pdf_run_page_annots(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
340 | 322 | { |
341 | 322 | pdf_run_page_annots_with_usage(ctx, page, dev, ctm, "View", cookie); |
342 | 322 | } |
343 | | |
344 | | void pdf_run_page_widgets_with_usage(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
345 | 322 | { |
346 | 322 | pdf_document *doc = page->doc; |
347 | 322 | int nocache; |
348 | | |
349 | 322 | pdf_update_page(ctx, page); |
350 | | |
351 | 322 | nocache = !!(dev->hints & FZ_NO_CACHE); |
352 | 322 | if (nocache) |
353 | 0 | pdf_mark_xref(ctx, doc); |
354 | | |
355 | 644 | fz_try(ctx) |
356 | 644 | { |
357 | 322 | pdf_run_page_widgets_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
358 | 322 | } |
359 | 644 | fz_always(ctx) |
360 | 322 | { |
361 | 322 | if (nocache) |
362 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
363 | 322 | } |
364 | 322 | fz_catch(ctx) |
365 | 0 | { |
366 | 0 | fz_rethrow(ctx); |
367 | 0 | } |
368 | 322 | } |
369 | | |
370 | | void pdf_run_page_widgets(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
371 | 322 | { |
372 | 322 | pdf_run_page_widgets_with_usage(ctx, page, dev, ctm, "View", cookie); |
373 | 322 | } |
374 | | |
375 | | void |
376 | | pdf_run_page_with_usage(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, const char *usage, fz_cookie *cookie) |
377 | 0 | { |
378 | 0 | pdf_document *doc = page->doc; |
379 | 0 | int nocache = !!(dev->hints & FZ_NO_CACHE); |
380 | |
|
381 | 0 | pdf_update_page(ctx, page); |
382 | |
|
383 | 0 | if (nocache) |
384 | 0 | pdf_mark_xref(ctx, doc); |
385 | 0 | fz_try(ctx) |
386 | 0 | { |
387 | 0 | pdf_run_page_contents_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
388 | 0 | pdf_run_page_annots_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
389 | 0 | pdf_run_page_widgets_with_usage_imp(ctx, doc, page, dev, ctm, usage, cookie); |
390 | 0 | } |
391 | 0 | fz_always(ctx) |
392 | 0 | { |
393 | 0 | if (nocache) |
394 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
395 | 0 | } |
396 | 0 | fz_catch(ctx) |
397 | 0 | { |
398 | 0 | fz_rethrow(ctx); |
399 | 0 | } |
400 | 0 | } |
401 | | |
402 | | void |
403 | | pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
404 | 0 | { |
405 | 0 | pdf_run_page_with_usage(ctx, page, dev, ctm, "View", cookie); |
406 | 0 | } |
407 | | |
408 | | void |
409 | | pdf_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, void *fill_gstate, void *stroke_gstate) |
410 | 0 | { |
411 | 0 | pdf_processor *proc; |
412 | |
|
413 | 0 | proc = pdf_new_run_processor(ctx, doc, dev, ctm, -1, "View", gstate, default_cs, NULL, fill_gstate, stroke_gstate); |
414 | 0 | fz_try(ctx) |
415 | 0 | { |
416 | 0 | pdf_process_glyph(ctx, proc, doc, resources, contents); |
417 | 0 | pdf_close_processor(ctx, proc); |
418 | 0 | } |
419 | 0 | fz_always(ctx) |
420 | 0 | pdf_drop_processor(ctx, proc); |
421 | 0 | fz_catch(ctx) |
422 | 0 | fz_rethrow(ctx); |
423 | 0 | } |
424 | | |
425 | | fz_structure |
426 | | pdf_structure_type(fz_context *ctx, pdf_obj *role_map, pdf_obj *tag) |
427 | 0 | { |
428 | | /* Perform Structure mapping to go from tag to standard. */ |
429 | 0 | if (role_map) |
430 | 0 | { |
431 | 0 | pdf_obj *o = pdf_dict_get(ctx, role_map, tag); |
432 | 0 | if (o) |
433 | 0 | tag = o; |
434 | 0 | } |
435 | |
|
436 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Document))) |
437 | 0 | return FZ_STRUCTURE_DOCUMENT; |
438 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Part))) |
439 | 0 | return FZ_STRUCTURE_PART; |
440 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Art))) |
441 | 0 | return FZ_STRUCTURE_ART; |
442 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Sect))) |
443 | 0 | return FZ_STRUCTURE_SECT; |
444 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Div))) |
445 | 0 | return FZ_STRUCTURE_DIV; |
446 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(BlockQuote))) |
447 | 0 | return FZ_STRUCTURE_BLOCKQUOTE; |
448 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Caption))) |
449 | 0 | return FZ_STRUCTURE_CAPTION; |
450 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TOC))) |
451 | 0 | return FZ_STRUCTURE_TOC; |
452 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TOCI))) |
453 | 0 | return FZ_STRUCTURE_TOCI; |
454 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Index))) |
455 | 0 | return FZ_STRUCTURE_INDEX; |
456 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(NonStruct))) |
457 | 0 | return FZ_STRUCTURE_NONSTRUCT; |
458 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Private))) |
459 | 0 | return FZ_STRUCTURE_PRIVATE; |
460 | | /* Grouping elements (PDF 2.0 - Table 364) */ |
461 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(DocumentFragment))) |
462 | 0 | return FZ_STRUCTURE_DOCUMENTFRAGMENT; |
463 | | /* Grouping elements (PDF 2.0 - Table 365) */ |
464 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Aside))) |
465 | 0 | return FZ_STRUCTURE_ASIDE; |
466 | | /* Grouping elements (PDF 2.0 - Table 366) */ |
467 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Title))) |
468 | 0 | return FZ_STRUCTURE_TITLE; |
469 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(FENote))) |
470 | 0 | return FZ_STRUCTURE_FENOTE; |
471 | | /* Grouping elements (PDF 2.0 - Table 367) */ |
472 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Sub))) |
473 | 0 | return FZ_STRUCTURE_SUB; |
474 | | |
475 | | /* Paragraphlike elements (PDF 1.7 - Table 10.21) */ |
476 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(P))) |
477 | 0 | return FZ_STRUCTURE_P; |
478 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H))) |
479 | 0 | return FZ_STRUCTURE_H; |
480 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H1))) |
481 | 0 | return FZ_STRUCTURE_H1; |
482 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H2))) |
483 | 0 | return FZ_STRUCTURE_H2; |
484 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H3))) |
485 | 0 | return FZ_STRUCTURE_H3; |
486 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H4))) |
487 | 0 | return FZ_STRUCTURE_H4; |
488 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H5))) |
489 | 0 | return FZ_STRUCTURE_H5; |
490 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(H6))) |
491 | 0 | return FZ_STRUCTURE_H6; |
492 | | |
493 | | /* List elements (PDF 1.7 - Table 10.23) */ |
494 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(L))) |
495 | 0 | return FZ_STRUCTURE_LIST; |
496 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(LI))) |
497 | 0 | return FZ_STRUCTURE_LISTITEM; |
498 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Lbl))) |
499 | 0 | return FZ_STRUCTURE_LABEL; |
500 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(LBody))) |
501 | 0 | return FZ_STRUCTURE_LISTBODY; |
502 | | |
503 | | /* Table elements (PDF 1.7 - Table 10.24) */ |
504 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Table))) |
505 | 0 | return FZ_STRUCTURE_TABLE; |
506 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TR))) |
507 | 0 | return FZ_STRUCTURE_TR; |
508 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TH))) |
509 | 0 | return FZ_STRUCTURE_TH; |
510 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TD))) |
511 | 0 | return FZ_STRUCTURE_TD; |
512 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(THead))) |
513 | 0 | return FZ_STRUCTURE_THEAD; |
514 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TBody))) |
515 | 0 | return FZ_STRUCTURE_TBODY; |
516 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(TFoot))) |
517 | 0 | return FZ_STRUCTURE_TFOOT; |
518 | | |
519 | | /* Inline elements (PDF 1.7 - Table 10.25) */ |
520 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Span))) |
521 | 0 | return FZ_STRUCTURE_SPAN; |
522 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Quote))) |
523 | 0 | return FZ_STRUCTURE_QUOTE; |
524 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Note))) |
525 | 0 | return FZ_STRUCTURE_NOTE; |
526 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Reference))) |
527 | 0 | return FZ_STRUCTURE_REFERENCE; |
528 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(BibEntry))) |
529 | 0 | return FZ_STRUCTURE_BIBENTRY; |
530 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Code))) |
531 | 0 | return FZ_STRUCTURE_CODE; |
532 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Link))) |
533 | 0 | return FZ_STRUCTURE_LINK; |
534 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Annot))) |
535 | 0 | return FZ_STRUCTURE_ANNOT; |
536 | | /* Inline elements (PDF 2.0 - Table 368) */ |
537 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Em))) |
538 | 0 | return FZ_STRUCTURE_EM; |
539 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Strong))) |
540 | 0 | return FZ_STRUCTURE_STRONG; |
541 | | |
542 | | /* Ruby inline element (PDF 1.7 - Table 10.26) */ |
543 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Ruby))) |
544 | 0 | return FZ_STRUCTURE_RUBY; |
545 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(RB))) |
546 | 0 | return FZ_STRUCTURE_RB; |
547 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(RT))) |
548 | 0 | return FZ_STRUCTURE_RT; |
549 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(RP))) |
550 | 0 | return FZ_STRUCTURE_RP; |
551 | | |
552 | | /* Warichu inline element (PDF 1.7 - Table 10.26) */ |
553 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Warichu))) |
554 | 0 | return FZ_STRUCTURE_WARICHU; |
555 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(WT))) |
556 | 0 | return FZ_STRUCTURE_WT; |
557 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(WP))) |
558 | 0 | return FZ_STRUCTURE_WP; |
559 | | |
560 | | /* Illustration elements (PDF 1.7 - Table 10.27) */ |
561 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Figure))) |
562 | 0 | return FZ_STRUCTURE_FIGURE; |
563 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Formula))) |
564 | 0 | return FZ_STRUCTURE_FORMULA; |
565 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Form))) |
566 | 0 | return FZ_STRUCTURE_FORM; |
567 | | |
568 | | /* Artifact structure type (PDF 2.0 - Table 375) */ |
569 | 0 | if (pdf_name_eq(ctx, tag, PDF_NAME(Artifact))) |
570 | 0 | return FZ_STRUCTURE_ARTIFACT; |
571 | | |
572 | 0 | return FZ_STRUCTURE_INVALID; |
573 | 0 | } |
574 | | |
575 | | /* The recursive descent of the structure tree uses an fz_try at each level. |
576 | | * At the risk of creating a foot cannon... "no one will need more than ~64 |
577 | | * levels of structure tree". */ |
578 | | static void |
579 | | run_ds(fz_context *ctx, fz_device *dev, pdf_obj *role_map, pdf_obj *obj, int idx, fz_cookie *cookie) |
580 | 0 | { |
581 | 0 | pdf_obj *k; |
582 | 0 | int i, n; |
583 | | |
584 | | /* Check the cookie for aborting */ |
585 | 0 | if (cookie) |
586 | 0 | { |
587 | 0 | if (cookie->abort) |
588 | 0 | return; |
589 | 0 | cookie->progress++; |
590 | 0 | } |
591 | | |
592 | 0 | if (pdf_is_number(ctx, obj)) |
593 | 0 | { |
594 | | /* A marked-content identifier denoting a marked content sequence. WHAT? */ |
595 | 0 | return; |
596 | 0 | } |
597 | | |
598 | 0 | if (pdf_mark_obj(ctx, obj)) |
599 | 0 | return; |
600 | | |
601 | 0 | fz_try(ctx) |
602 | 0 | { |
603 | 0 | fz_structure standard; |
604 | 0 | pdf_obj *tag = pdf_dict_get(ctx, obj, PDF_NAME(S)); |
605 | 0 | if (!tag) |
606 | 0 | break; |
607 | | |
608 | 0 | standard = pdf_structure_type(ctx, role_map, tag); |
609 | 0 | if (standard == FZ_STRUCTURE_INVALID) |
610 | 0 | break; |
611 | 0 | fz_begin_structure(ctx, dev, standard, pdf_to_name(ctx, tag), idx); |
612 | 0 | k = pdf_dict_get(ctx, obj, PDF_NAME(K)); |
613 | 0 | if (k) |
614 | 0 | { |
615 | 0 | n = pdf_array_len(ctx, k); |
616 | 0 | if (n == 0) |
617 | 0 | run_ds(ctx, dev, role_map, k, 0, cookie); |
618 | 0 | else |
619 | 0 | { |
620 | 0 | for (i = 0; i < n; i++) |
621 | 0 | run_ds(ctx, dev, role_map, pdf_array_get(ctx, k, i), i, cookie); |
622 | 0 | } |
623 | 0 | } |
624 | 0 | fz_end_structure(ctx, dev); |
625 | 0 | } |
626 | 0 | fz_always(ctx) |
627 | 0 | pdf_unmark_obj(ctx, obj); |
628 | 0 | fz_catch(ctx) |
629 | 0 | fz_rethrow(ctx); |
630 | 0 | } |
631 | | |
632 | | void pdf_run_document_structure(fz_context *ctx, pdf_document *doc, fz_device *dev, fz_cookie *cookie) |
633 | 0 | { |
634 | 0 | int nocache; |
635 | 0 | int marked = 0; |
636 | 0 | pdf_obj *rm, *k, *st = NULL; |
637 | |
|
638 | 0 | fz_var(marked); |
639 | 0 | fz_var(st); |
640 | |
|
641 | 0 | nocache = !!(dev->hints & FZ_NO_CACHE); |
642 | 0 | if (nocache) |
643 | 0 | pdf_mark_xref(ctx, doc); |
644 | |
|
645 | 0 | fz_try(ctx) |
646 | 0 | { |
647 | 0 | st = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root)), PDF_NAME(StructTreeRoot)); |
648 | 0 | rm = pdf_dict_get(ctx, st, PDF_NAME(RoleMap)); |
649 | |
|
650 | 0 | if (pdf_mark_obj(ctx, st)) |
651 | 0 | break; |
652 | 0 | marked = 1; |
653 | |
|
654 | 0 | k = pdf_dict_get(ctx, st, PDF_NAME(K)); |
655 | 0 | if (k) |
656 | 0 | { |
657 | 0 | int n = pdf_array_len(ctx, k); |
658 | 0 | if (n == 0) |
659 | 0 | run_ds(ctx, dev, rm, k, 0, cookie); |
660 | 0 | else |
661 | 0 | { |
662 | 0 | int i; |
663 | 0 | for (i = 0; i < n; i++) |
664 | 0 | run_ds(ctx, dev, rm, pdf_array_get(ctx, k, i), i, cookie); |
665 | 0 | } |
666 | 0 | } |
667 | 0 | } |
668 | 0 | fz_always(ctx) |
669 | 0 | { |
670 | 0 | if (marked) |
671 | 0 | pdf_unmark_obj(ctx, st); |
672 | 0 | if (nocache) |
673 | 0 | pdf_clear_xref_to_mark(ctx, doc); |
674 | 0 | } |
675 | 0 | fz_catch(ctx) |
676 | 0 | fz_rethrow(ctx); |
677 | 0 | } |