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