Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/pdf/pdf-op-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 "mupdf/pdf.h" | |
| 25 | |
| 26 #include <string.h> | |
| 27 #include <math.h> | |
| 28 | |
| 29 #include "mupdf/ucdn.h" | |
| 30 | |
| 31 #define TILE | |
| 32 | |
| 33 /* Enable this to watch changes in the structure stack. */ | |
| 34 #undef DEBUG_STRUCTURE | |
| 35 | |
| 36 /* | |
| 37 * Emit graphics calls to device. | |
| 38 */ | |
| 39 | |
| 40 typedef struct pdf_run_processor pdf_run_processor; | |
| 41 | |
| 42 static void pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_obj *xobj, pdf_obj *page_resources, fz_matrix transform, int is_smask); | |
| 43 | |
| 44 enum | |
| 45 { | |
| 46 PDF_FILL, | |
| 47 PDF_STROKE, | |
| 48 }; | |
| 49 | |
| 50 enum | |
| 51 { | |
| 52 PDF_MAT_NONE, | |
| 53 PDF_MAT_COLOR, | |
| 54 PDF_MAT_PATTERN, | |
| 55 PDF_MAT_SHADE, | |
| 56 }; | |
| 57 | |
| 58 typedef struct | |
| 59 { | |
| 60 int kind; | |
| 61 fz_colorspace *colorspace; | |
| 62 pdf_pattern *pattern; | |
| 63 fz_shade *shade; | |
| 64 int gstate_num; | |
| 65 fz_color_params color_params; | |
| 66 float alpha; | |
| 67 float v[FZ_MAX_COLORS]; | |
| 68 } pdf_material; | |
| 69 | |
| 70 struct pdf_gstate | |
| 71 { | |
| 72 fz_matrix ctm; | |
| 73 int clip_depth; | |
| 74 | |
| 75 /* path stroking */ | |
| 76 fz_stroke_state *stroke_state; | |
| 77 | |
| 78 /* materials */ | |
| 79 pdf_material stroke; | |
| 80 pdf_material fill; | |
| 81 | |
| 82 /* pattern paint type 2 */ | |
| 83 int ismask; | |
| 84 | |
| 85 /* text state */ | |
| 86 pdf_text_state text; | |
| 87 | |
| 88 /* transparency */ | |
| 89 int blendmode; | |
| 90 pdf_obj *softmask; | |
| 91 pdf_obj *softmask_resources; | |
| 92 pdf_obj *softmask_tr; | |
| 93 fz_matrix softmask_ctm; | |
| 94 fz_colorspace *softmask_cs; | |
| 95 float softmask_bc[FZ_MAX_COLORS]; | |
| 96 int luminosity; | |
| 97 }; | |
| 98 | |
| 99 typedef struct resources_stack | |
| 100 { | |
| 101 struct resources_stack *next; | |
| 102 pdf_obj *resources; | |
| 103 } resources_stack; | |
| 104 | |
| 105 typedef struct marked_content_stack | |
| 106 { | |
| 107 struct marked_content_stack *next; | |
| 108 pdf_obj *tag; | |
| 109 pdf_obj *val; | |
| 110 int structure_pushed; | |
| 111 } marked_content_stack; | |
| 112 | |
| 113 typedef struct begin_layer_stack | |
| 114 { | |
| 115 struct begin_layer_stack *next; | |
| 116 char *layer; | |
| 117 } begin_layer_stack; | |
| 118 | |
| 119 struct pdf_run_processor | |
| 120 { | |
| 121 pdf_processor super; | |
| 122 pdf_document *doc; | |
| 123 fz_device *dev; | |
| 124 fz_cookie *cookie; | |
| 125 | |
| 126 fz_default_colorspaces *default_cs; | |
| 127 | |
| 128 resources_stack *rstack; | |
| 129 | |
| 130 /* path object state */ | |
| 131 fz_path *path; | |
| 132 int clip; | |
| 133 int clip_even_odd; | |
| 134 | |
| 135 /* text object state */ | |
| 136 pdf_text_object_state tos; | |
| 137 int bidi; | |
| 138 | |
| 139 /* graphics state */ | |
| 140 pdf_gstate *gstate; | |
| 141 int gcap; | |
| 142 int gtop; | |
| 143 int gbot; | |
| 144 int gparent; | |
| 145 | |
| 146 /* xobject cycle detector */ | |
| 147 pdf_cycle_list *cycle; | |
| 148 | |
| 149 pdf_obj *role_map; | |
| 150 | |
| 151 marked_content_stack *marked_content; | |
| 152 pdf_obj *mcid_sent; | |
| 153 pdf_obj *pending_mcid_pop; | |
| 154 | |
| 155 int struct_parent; | |
| 156 int broken_struct_tree; | |
| 157 | |
| 158 /* Pending begin layers */ | |
| 159 begin_layer_stack *begin_layer; | |
| 160 begin_layer_stack **next_begin_layer; | |
| 161 | |
| 162 int mc_depth; | |
| 163 /* The nest_mark array holds a record of the way in which clips and | |
| 164 * marked content are nested to ensure we pop stuff in the same order | |
| 165 * that we push it - i.e. to keep calls nested nicely. An entry x, | |
| 166 * where x >= 0 represents that a push has happened for mc_depth == x. | |
| 167 * An entry x, where x < 0 means that -x clips have happened at this | |
| 168 * position. */ | |
| 169 int nest_depth; | |
| 170 int nest_mark[1024]; | |
| 171 }; | |
| 172 | |
| 173 /* Forward definition */ | |
| 174 static void | |
| 175 pop_any_pending_mcid_changes(fz_context *ctx, pdf_run_processor *pr); | |
| 176 | |
| 177 static void | |
| 178 push_begin_layer(fz_context *ctx, pdf_run_processor *proc, const char *str) | |
| 179 { | |
| 180 begin_layer_stack *s = fz_malloc_struct(ctx, begin_layer_stack); | |
| 181 | |
| 182 fz_try(ctx) | |
| 183 s->layer = fz_strdup(ctx, str); | |
| 184 fz_catch(ctx) | |
| 185 { | |
| 186 fz_free(ctx, s); | |
| 187 fz_rethrow(ctx); | |
| 188 } | |
| 189 | |
| 190 s->next = NULL; | |
| 191 *proc->next_begin_layer = s; | |
| 192 proc->next_begin_layer = &s->next; | |
| 193 } | |
| 194 | |
| 195 static void | |
| 196 flush_begin_layer(fz_context *ctx, pdf_run_processor *proc) | |
| 197 { | |
| 198 begin_layer_stack *s; | |
| 199 | |
| 200 while (proc->begin_layer) | |
| 201 { | |
| 202 s = proc->begin_layer; | |
| 203 | |
| 204 if (proc->nest_depth == nelem(proc->nest_mark)) | |
| 205 fz_throw(ctx, FZ_ERROR_LIMIT, "layer/clip nesting too deep"); | |
| 206 | |
| 207 proc->nest_mark[proc->nest_depth++] = ++proc->mc_depth; | |
| 208 | |
| 209 fz_begin_layer(ctx, proc->dev, s->layer); | |
| 210 proc->begin_layer = s->next; | |
| 211 fz_free(ctx, s->layer); | |
| 212 fz_free(ctx, s); | |
| 213 } | |
| 214 proc->next_begin_layer = &proc->begin_layer; | |
| 215 } | |
| 216 | |
| 217 static void nest_layer_clip(fz_context *ctx, pdf_run_processor *proc) | |
| 218 { | |
| 219 if (proc->nest_depth == nelem(proc->nest_mark)) | |
| 220 fz_throw(ctx, FZ_ERROR_LIMIT, "layer/clip nesting too deep"); | |
| 221 if (proc->nest_depth > 0 && proc->nest_mark[proc->nest_depth-1] < 0) | |
| 222 { | |
| 223 /* The last mark was a clip. Just increase that count. */ | |
| 224 proc->nest_mark[proc->nest_depth-1]--; | |
| 225 } | |
| 226 else | |
| 227 { | |
| 228 /* Create a new entry for a single clip. */ | |
| 229 proc->nest_mark[proc->nest_depth++] = -1; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 static void | |
| 234 do_end_layer(fz_context *ctx, pdf_run_processor *proc) | |
| 235 { | |
| 236 if (proc->nest_depth > 0 && proc->nest_mark[proc->nest_depth-1] == proc->mc_depth) | |
| 237 { | |
| 238 fz_end_layer(ctx, proc->dev); | |
| 239 proc->nest_depth--; | |
| 240 } | |
| 241 else | |
| 242 { | |
| 243 /* If EMC is unbalanced with q/Q, we will emit the end layer | |
| 244 * device call before or after the Q operator instead of its true location | |
| 245 */ | |
| 246 fz_warn(ctx, "invalid marked content and clip nesting"); | |
| 247 } | |
| 248 | |
| 249 if (proc->mc_depth > 0) | |
| 250 proc->mc_depth--; | |
| 251 } | |
| 252 | |
| 253 typedef struct | |
| 254 { | |
| 255 pdf_obj *softmask; | |
| 256 fz_colorspace *softmask_cs; | |
| 257 pdf_obj *page_resources; | |
| 258 fz_matrix ctm; | |
| 259 } softmask_save; | |
| 260 | |
| 261 static fz_function * | |
| 262 load_transfer_function(fz_context *ctx, pdf_obj *obj) | |
| 263 { | |
| 264 if (obj == NULL || pdf_name_eq(ctx, obj, PDF_NAME(Identity))) | |
| 265 return NULL; | |
| 266 | |
| 267 return (fz_function *)pdf_load_function(ctx, obj, 1, 1); | |
| 268 } | |
| 269 | |
| 270 static pdf_gstate * | |
| 271 begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save, fz_rect bbox) | |
| 272 { | |
| 273 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 274 pdf_obj *softmask = gstate->softmask; | |
| 275 fz_colorspace *softmask_cs = gstate->softmask_cs; | |
| 276 fz_rect mask_bbox; | |
| 277 fz_matrix tos_save[2], save_ctm; | |
| 278 fz_matrix mask_matrix; | |
| 279 fz_colorspace *mask_colorspace; | |
| 280 int saved_blendmode; | |
| 281 fz_function *tr = NULL; | |
| 282 | |
| 283 fz_var(tr); | |
| 284 | |
| 285 save->softmask = softmask; | |
| 286 if (softmask == NULL) | |
| 287 return gstate; | |
| 288 save->softmask_cs = softmask_cs; | |
| 289 save->page_resources = gstate->softmask_resources; | |
| 290 save->ctm = gstate->softmask_ctm; | |
| 291 save_ctm = gstate->ctm; | |
| 292 | |
| 293 mask_bbox = pdf_xobject_bbox(ctx, softmask); | |
| 294 mask_matrix = pdf_xobject_matrix(ctx, softmask); | |
| 295 | |
| 296 pdf_tos_save(ctx, &pr->tos, tos_save); | |
| 297 | |
| 298 mask_colorspace = gstate->softmask_cs; | |
| 299 if (gstate->luminosity && !mask_colorspace) | |
| 300 mask_colorspace = fz_device_gray(ctx); | |
| 301 | |
| 302 if (gstate->luminosity) | |
| 303 mask_bbox = fz_infinite_rect; | |
| 304 else | |
| 305 { | |
| 306 mask_bbox = fz_transform_rect(mask_bbox, mask_matrix); | |
| 307 mask_bbox = fz_transform_rect(mask_bbox, gstate->softmask_ctm); | |
| 308 } | |
| 309 mask_bbox = fz_intersect_rect(mask_bbox, bbox); | |
| 310 gstate->softmask = NULL; | |
| 311 gstate->softmask_cs = NULL; | |
| 312 gstate->softmask_resources = NULL; | |
| 313 gstate->ctm = gstate->softmask_ctm; | |
| 314 | |
| 315 saved_blendmode = gstate->blendmode; | |
| 316 | |
| 317 fz_try(ctx) | |
| 318 { | |
| 319 if (gstate->softmask_tr) | |
| 320 { | |
| 321 tr = load_transfer_function(ctx, gstate->softmask_tr); | |
| 322 pdf_drop_obj(ctx, gstate->softmask_tr); | |
| 323 gstate->softmask_tr = NULL; | |
| 324 } | |
| 325 | |
| 326 fz_begin_mask(ctx, pr->dev, mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc, gstate->fill.color_params); | |
| 327 gstate->blendmode = 0; | |
| 328 pdf_run_xobject(ctx, pr, softmask, save->page_resources, fz_identity, 1); | |
| 329 gstate = pr->gstate + pr->gtop; | |
| 330 gstate->blendmode = saved_blendmode; | |
| 331 fz_end_mask_tr(ctx, pr->dev, tr); | |
| 332 } | |
| 333 fz_always(ctx) | |
| 334 { | |
| 335 fz_drop_function(ctx, tr); | |
| 336 } | |
| 337 fz_catch(ctx) | |
| 338 fz_rethrow(ctx); | |
| 339 | |
| 340 pdf_tos_restore(ctx, &pr->tos, tos_save); | |
| 341 | |
| 342 gstate = pr->gstate + pr->gtop; | |
| 343 gstate->ctm = save_ctm; | |
| 344 | |
| 345 return gstate; | |
| 346 } | |
| 347 | |
| 348 static void | |
| 349 end_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save) | |
| 350 { | |
| 351 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 352 | |
| 353 if (save->softmask == NULL) | |
| 354 return; | |
| 355 | |
| 356 gstate->softmask = save->softmask; | |
| 357 gstate->softmask_cs = save->softmask_cs; | |
| 358 gstate->softmask_resources = save->page_resources; | |
| 359 gstate->softmask_ctm = save->ctm; | |
| 360 save->softmask = NULL; | |
| 361 save->page_resources = NULL; | |
| 362 | |
| 363 fz_pop_clip(ctx, pr->dev); | |
| 364 } | |
| 365 | |
| 366 static pdf_gstate * | |
| 367 pdf_begin_group(fz_context *ctx, pdf_run_processor *pr, fz_rect bbox, softmask_save *softmask) | |
| 368 { | |
| 369 pdf_gstate *gstate = begin_softmask(ctx, pr, softmask, bbox); | |
| 370 | |
| 371 if (gstate->blendmode) | |
| 372 fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1); | |
| 373 | |
| 374 return pr->gstate + pr->gtop; | |
| 375 } | |
| 376 | |
| 377 static void | |
| 378 pdf_end_group(fz_context *ctx, pdf_run_processor *pr, softmask_save *softmask) | |
| 379 { | |
| 380 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 381 | |
| 382 if (gstate->blendmode) | |
| 383 fz_end_group(ctx, pr->dev); | |
| 384 | |
| 385 end_softmask(ctx, pr, softmask); | |
| 386 } | |
| 387 | |
| 388 static void | |
| 389 pdf_show_shade(fz_context *ctx, pdf_run_processor *pr, fz_shade *shd) | |
| 390 { | |
| 391 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 392 fz_rect bbox; | |
| 393 softmask_save softmask = { NULL }; | |
| 394 | |
| 395 if (pr->super.hidden) | |
| 396 return; | |
| 397 | |
| 398 bbox = fz_bound_shade(ctx, shd, gstate->ctm); | |
| 399 | |
| 400 fz_try(ctx) | |
| 401 { | |
| 402 gstate = pdf_begin_group(ctx, pr, bbox, &softmask); | |
| 403 | |
| 404 /* FIXME: The gstate->ctm in the next line may be wrong; maybe | |
| 405 * it should be the parent gstates ctm? */ | |
| 406 fz_fill_shade(ctx, pr->dev, shd, gstate->ctm, gstate->fill.alpha, gstate->fill.color_params); | |
| 407 | |
| 408 pdf_end_group(ctx, pr, &softmask); | |
| 409 } | |
| 410 fz_catch(ctx) | |
| 411 { | |
| 412 pdf_drop_obj(ctx, softmask.softmask); | |
| 413 fz_drop_colorspace(ctx, softmask.softmask_cs); | |
| 414 pdf_drop_obj(ctx, softmask.page_resources); | |
| 415 fz_rethrow(ctx); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 static pdf_material * | |
| 420 pdf_keep_material(fz_context *ctx, pdf_material *mat) | |
| 421 { | |
| 422 if (mat->colorspace) | |
| 423 fz_keep_colorspace(ctx, mat->colorspace); | |
| 424 if (mat->pattern) | |
| 425 pdf_keep_pattern(ctx, mat->pattern); | |
| 426 if (mat->shade) | |
| 427 fz_keep_shade(ctx, mat->shade); | |
| 428 return mat; | |
| 429 } | |
| 430 | |
| 431 static pdf_material * | |
| 432 pdf_drop_material(fz_context *ctx, pdf_material *mat) | |
| 433 { | |
| 434 fz_drop_colorspace(ctx, mat->colorspace); | |
| 435 pdf_drop_pattern(ctx, mat->pattern); | |
| 436 fz_drop_shade(ctx, mat->shade); | |
| 437 return mat; | |
| 438 } | |
| 439 | |
| 440 static void | |
| 441 pdf_copy_pattern_gstate(fz_context *ctx, pdf_gstate *dst, const pdf_gstate *src) | |
| 442 { | |
| 443 pdf_font_desc *old_font = dst->text.font; | |
| 444 | |
| 445 dst->ctm = src->ctm; | |
| 446 | |
| 447 dst->text = src->text; | |
| 448 pdf_keep_font(ctx, src->text.font); | |
| 449 pdf_drop_font(ctx, old_font); | |
| 450 | |
| 451 pdf_drop_obj(ctx, dst->softmask); | |
| 452 dst->softmask = pdf_keep_obj(ctx, src->softmask); | |
| 453 | |
| 454 pdf_drop_obj(ctx, dst->softmask_resources); | |
| 455 dst->softmask_resources = pdf_keep_obj(ctx, src->softmask_resources); | |
| 456 | |
| 457 fz_drop_colorspace(ctx, dst->softmask_cs); | |
| 458 dst->softmask_cs = fz_keep_colorspace(ctx, src->softmask_cs); | |
| 459 | |
| 460 fz_drop_stroke_state(ctx, dst->stroke_state); | |
| 461 dst->stroke_state = fz_keep_stroke_state(ctx, src->stroke_state); | |
| 462 } | |
| 463 | |
| 464 static void | |
| 465 pdf_unset_pattern(fz_context *ctx, pdf_run_processor *pr, int what) | |
| 466 { | |
| 467 pdf_gstate *gs = pr->gstate + pr->gtop; | |
| 468 pdf_material *mat; | |
| 469 mat = what == PDF_FILL ? &gs->fill : &gs->stroke; | |
| 470 if (mat->kind == PDF_MAT_PATTERN) | |
| 471 { | |
| 472 pdf_drop_pattern(ctx, mat->pattern); | |
| 473 mat->pattern = NULL; | |
| 474 mat->kind = PDF_MAT_COLOR; | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 static void | |
| 479 pdf_keep_gstate(fz_context *ctx, pdf_gstate *gs) | |
| 480 { | |
| 481 pdf_keep_material(ctx, &gs->stroke); | |
| 482 pdf_keep_material(ctx, &gs->fill); | |
| 483 if (gs->text.font) | |
| 484 pdf_keep_font(ctx, gs->text.font); | |
| 485 if (gs->softmask) | |
| 486 pdf_keep_obj(ctx, gs->softmask); | |
| 487 if (gs->softmask_cs) | |
| 488 fz_keep_colorspace(ctx, gs->softmask_cs); | |
| 489 if (gs->softmask_resources) | |
| 490 pdf_keep_obj(ctx, gs->softmask_resources); | |
| 491 fz_keep_stroke_state(ctx, gs->stroke_state); | |
| 492 pdf_keep_obj(ctx, gs->softmask_tr); | |
| 493 } | |
| 494 | |
| 495 static void | |
| 496 pdf_drop_gstate(fz_context *ctx, pdf_gstate *gs) | |
| 497 { | |
| 498 pdf_drop_material(ctx, &gs->stroke); | |
| 499 pdf_drop_material(ctx, &gs->fill); | |
| 500 pdf_drop_font(ctx, gs->text.font); | |
| 501 pdf_drop_obj(ctx, gs->softmask); | |
| 502 fz_drop_colorspace(ctx, gs->softmask_cs); | |
| 503 pdf_drop_obj(ctx, gs->softmask_resources); | |
| 504 fz_drop_stroke_state(ctx, gs->stroke_state); | |
| 505 pdf_drop_obj(ctx, gs->softmask_tr); | |
| 506 } | |
| 507 | |
| 508 static void | |
| 509 pdf_gsave(fz_context *ctx, pdf_run_processor *pr) | |
| 510 { | |
| 511 if (pr->gtop == pr->gcap-1) | |
| 512 { | |
| 513 if (pr->gcap * 2 >= 4096) | |
| 514 fz_throw(ctx, FZ_ERROR_LIMIT, "too many nested graphics states"); | |
| 515 | |
| 516 pr->gstate = fz_realloc_array(ctx, pr->gstate, pr->gcap*2, pdf_gstate); | |
| 517 pr->gcap *= 2; | |
| 518 } | |
| 519 | |
| 520 memcpy(&pr->gstate[pr->gtop + 1], &pr->gstate[pr->gtop], sizeof(pdf_gstate)); | |
| 521 | |
| 522 pr->gtop++; | |
| 523 pdf_keep_gstate(ctx, &pr->gstate[pr->gtop]); | |
| 524 } | |
| 525 | |
| 526 static void | |
| 527 pdf_grestore(fz_context *ctx, pdf_run_processor *pr) | |
| 528 { | |
| 529 pdf_gstate *gs = pr->gstate + pr->gtop; | |
| 530 int clip_depth = gs->clip_depth; | |
| 531 | |
| 532 if (pr->gtop <= pr->gbot) | |
| 533 { | |
| 534 fz_warn(ctx, "gstate underflow in content stream"); | |
| 535 return; | |
| 536 } | |
| 537 | |
| 538 pdf_drop_gstate(ctx, gs); | |
| 539 pr->gtop --; | |
| 540 | |
| 541 gs = pr->gstate + pr->gtop; | |
| 542 while (clip_depth > gs->clip_depth) | |
| 543 { | |
| 544 fz_try(ctx) | |
| 545 { | |
| 546 // End layer early (before Q) if unbalanced Q appears between BMC and EMC. | |
| 547 while (pr->nest_depth > 0 && pr->nest_mark[pr->nest_depth-1] >= 0) | |
| 548 { | |
| 549 fz_end_layer(ctx, pr->dev); | |
| 550 pr->nest_depth--; | |
| 551 } | |
| 552 | |
| 553 if (pr->nest_depth > 0) | |
| 554 { | |
| 555 /* So this one must be a clip record. */ | |
| 556 fz_pop_clip(ctx, pr->dev); | |
| 557 /* Pop a single clip record off. */ | |
| 558 pr->nest_mark[pr->nest_depth-1]++; | |
| 559 if (pr->nest_mark[pr->nest_depth-1] == 0) | |
| 560 pr->nest_depth--; | |
| 561 } | |
| 562 | |
| 563 // End layer late (after Q) if unbalanced EMC appears between q and Q. | |
| 564 while (pr->nest_depth > 0 && pr->nest_mark[pr->nest_depth-1] > pr->mc_depth) | |
| 565 { | |
| 566 fz_end_layer(ctx, pr->dev); | |
| 567 pr->nest_depth--; | |
| 568 } | |
| 569 } | |
| 570 fz_catch(ctx) | |
| 571 { | |
| 572 /* Silently swallow the problem - restores must | |
| 573 * never throw! */ | |
| 574 fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); // FIXME - unsure if we can throw here? | |
| 575 fz_report_error(ctx); | |
| 576 } | |
| 577 clip_depth--; | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 static pdf_gstate * | |
| 582 pdf_show_pattern(fz_context *ctx, pdf_run_processor *pr, pdf_pattern *pat, int pat_gstate_num, fz_rect area, int what) | |
| 583 { | |
| 584 pdf_gstate *gstate; | |
| 585 pdf_gstate *pat_gstate; | |
| 586 int gparent_save; | |
| 587 fz_matrix ptm, invptm, gparent_save_ctm; | |
| 588 int x0, y0, x1, y1; | |
| 589 float fx0, fy0, fx1, fy1; | |
| 590 fz_rect local_area; | |
| 591 int oldbot; | |
| 592 int id; | |
| 593 | |
| 594 pdf_gsave(ctx, pr); | |
| 595 gstate = pr->gstate + pr->gtop; | |
| 596 pat_gstate = pr->gstate + pat_gstate_num; | |
| 597 | |
| 598 /* Patterns are run with the gstate of the parent */ | |
| 599 pdf_copy_pattern_gstate(ctx, gstate, pat_gstate); | |
| 600 | |
| 601 if (pat->ismask) | |
| 602 { | |
| 603 /* Inhibit any changes to the color since we're drawing an uncolored pattern. */ | |
| 604 gstate->ismask = 1; | |
| 605 pdf_unset_pattern(ctx, pr, PDF_FILL); | |
| 606 pdf_unset_pattern(ctx, pr, PDF_STROKE); | |
| 607 if (what == PDF_FILL) | |
| 608 { | |
| 609 pdf_drop_material(ctx, &gstate->stroke); | |
| 610 pdf_keep_material(ctx, &gstate->fill); | |
| 611 gstate->stroke = gstate->fill; | |
| 612 } | |
| 613 if (what == PDF_STROKE) | |
| 614 { | |
| 615 pdf_drop_material(ctx, &gstate->fill); | |
| 616 pdf_keep_material(ctx, &gstate->stroke); | |
| 617 gstate->fill = gstate->stroke; | |
| 618 } | |
| 619 id = 0; /* don't cache uncolored patterns, since we colorize them when drawing */ | |
| 620 } | |
| 621 else | |
| 622 { | |
| 623 // TODO: unset only the current fill/stroke or both? | |
| 624 pdf_unset_pattern(ctx, pr, what); | |
| 625 id = pat->id; | |
| 626 } | |
| 627 | |
| 628 /* don't apply soft masks to objects in the pattern as well */ | |
| 629 if (gstate->softmask) | |
| 630 { | |
| 631 pdf_drop_obj(ctx, gstate->softmask); | |
| 632 gstate->softmask = NULL; | |
| 633 } | |
| 634 | |
| 635 ptm = fz_concat(pat->matrix, pat_gstate->ctm); | |
| 636 invptm = fz_invert_matrix(ptm); | |
| 637 | |
| 638 /* The parent_ctm is amended with our pattern matrix */ | |
| 639 gparent_save = pr->gparent; | |
| 640 pr->gparent = pr->gtop-1; | |
| 641 gparent_save_ctm = pr->gstate[pr->gparent].ctm; | |
| 642 pr->gstate[pr->gparent].ctm = ptm; | |
| 643 | |
| 644 /* patterns are painted using the parent_ctm. area = bbox of | |
| 645 * shape to be filled in device space. Map it back to pattern | |
| 646 * space. */ | |
| 647 local_area = fz_transform_rect(area, invptm); | |
| 648 | |
| 649 fx0 = (local_area.x0 - pat->bbox.x0) / pat->xstep; | |
| 650 fy0 = (local_area.y0 - pat->bbox.y0) / pat->ystep; | |
| 651 fx1 = (local_area.x1 - pat->bbox.x0) / pat->xstep; | |
| 652 fy1 = (local_area.y1 - pat->bbox.y0) / pat->ystep; | |
| 653 if (fx0 > fx1) | |
| 654 { | |
| 655 float t = fx0; fx0 = fx1; fx1 = t; | |
| 656 } | |
| 657 if (fy0 > fy1) | |
| 658 { | |
| 659 float t = fy0; fy0 = fy1; fy1 = t; | |
| 660 } | |
| 661 | |
| 662 #ifdef TILE | |
| 663 /* We have tried various formulations in the past, but this one is | |
| 664 * best we've found; only use it as a tile if a whole repeat is | |
| 665 * required in at least one direction. Note, that this allows for | |
| 666 * 'sections' of 4 tiles to be show, but all non-overlapping. */ | |
| 667 if (fx1-fx0 > 1 || fy1-fy0 > 1) | |
| 668 #else | |
| 669 if (0) | |
| 670 #endif | |
| 671 { | |
| 672 int cached = fz_begin_tile_tid(ctx, pr->dev, local_area, pat->bbox, pat->xstep, pat->ystep, ptm, id, pat->document->super.id); | |
| 673 if (!cached) | |
| 674 { | |
| 675 gstate->ctm = ptm; | |
| 676 | |
| 677 oldbot = pr->gbot; | |
| 678 pr->gbot = pr->gtop; | |
| 679 | |
| 680 pdf_gsave(ctx, pr); | |
| 681 pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL, NULL); | |
| 682 pdf_grestore(ctx, pr); | |
| 683 | |
| 684 while (pr->gtop > pr->gbot) | |
| 685 pdf_grestore(ctx, pr); | |
| 686 pr->gbot = oldbot; | |
| 687 } | |
| 688 fz_end_tile(ctx, pr->dev); | |
| 689 } | |
| 690 else | |
| 691 { | |
| 692 int x, y; | |
| 693 | |
| 694 /* When calculating the number of tiles required, we adjust by | |
| 695 * a small amount to allow for rounding errors. By choosing | |
| 696 * this amount to be smaller than 1/256, we guarantee we won't | |
| 697 * cause problems that will be visible even under our most | |
| 698 * extreme antialiasing. */ | |
| 699 x0 = floorf(fx0 + 0.001f); | |
| 700 y0 = floorf(fy0 + 0.001f); | |
| 701 x1 = ceilf(fx1 - 0.001f); | |
| 702 y1 = ceilf(fy1 - 0.001f); | |
| 703 /* The above adjustments cause problems for sufficiently | |
| 704 * large values for xstep/ystep which may be used if the | |
| 705 * pattern is expected to be rendered exactly once. */ | |
| 706 if (fx1 > fx0 && x1 == x0) | |
| 707 x1 = x0 + 1; | |
| 708 if (fy1 > fy0 && y1 == y0) | |
| 709 y1 = y0 + 1; | |
| 710 | |
| 711 for (y = y0; y < y1; y++) | |
| 712 { | |
| 713 for (x = x0; x < x1; x++) | |
| 714 { | |
| 715 /* Calls to pdf_process_contents may cause the | |
| 716 * gstate array to be realloced to be larger. | |
| 717 * That can invalidate gstate. Hence reload | |
| 718 * it each time round the loop. */ | |
| 719 gstate = pr->gstate + pr->gtop; | |
| 720 gstate->ctm = fz_pre_translate(ptm, x * pat->xstep, y * pat->ystep); | |
| 721 | |
| 722 oldbot = pr->gbot; | |
| 723 pr->gbot = pr->gtop; | |
| 724 | |
| 725 pdf_gsave(ctx, pr); | |
| 726 pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL, NULL); | |
| 727 pdf_grestore(ctx, pr); | |
| 728 | |
| 729 while (pr->gtop > pr->gbot) | |
| 730 pdf_grestore(ctx, pr); | |
| 731 pr->gbot = oldbot; | |
| 732 } | |
| 733 } | |
| 734 } | |
| 735 | |
| 736 pr->gstate[pr->gparent].ctm = gparent_save_ctm; | |
| 737 pr->gparent = gparent_save; | |
| 738 | |
| 739 pdf_grestore(ctx, pr); | |
| 740 | |
| 741 return pr->gstate + pr->gtop; | |
| 742 } | |
| 743 | |
| 744 static void | |
| 745 pdf_show_image_imp(fz_context *ctx, pdf_run_processor *pr, fz_image *image, fz_matrix image_ctm, fz_rect bbox) | |
| 746 { | |
| 747 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 748 fz_color_params cp = gstate->fill.color_params; | |
| 749 | |
| 750 if (image->has_intent) | |
| 751 cp.ri = image->intent; | |
| 752 | |
| 753 if (image->colorspace) | |
| 754 { | |
| 755 fz_fill_image(ctx, pr->dev, image, image_ctm, gstate->fill.alpha, cp); | |
| 756 } | |
| 757 else if (gstate->fill.kind == PDF_MAT_COLOR) | |
| 758 { | |
| 759 fz_fill_image_mask(ctx, pr->dev, image, image_ctm, gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, cp); | |
| 760 } | |
| 761 else if (gstate->fill.kind == PDF_MAT_PATTERN && gstate->fill.pattern) | |
| 762 { | |
| 763 fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox); | |
| 764 gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL); | |
| 765 fz_pop_clip(ctx, pr->dev); | |
| 766 } | |
| 767 else if (gstate->fill.kind == PDF_MAT_SHADE && gstate->fill.shade) | |
| 768 { | |
| 769 fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox); | |
| 770 fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, cp); | |
| 771 fz_pop_clip(ctx, pr->dev); | |
| 772 } | |
| 773 } | |
| 774 | |
| 775 static void | |
| 776 pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image) | |
| 777 { | |
| 778 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 779 fz_matrix image_ctm; | |
| 780 fz_rect bbox; | |
| 781 | |
| 782 if (pr->super.hidden) | |
| 783 return; | |
| 784 | |
| 785 /* image can be NULL here if we are, for example, running to an | |
| 786 * stext device. */ | |
| 787 if (image == NULL) | |
| 788 return; | |
| 789 | |
| 790 pop_any_pending_mcid_changes(ctx, pr); | |
| 791 flush_begin_layer(ctx, pr); | |
| 792 | |
| 793 /* PDF has images bottom-up, so flip them right side up here */ | |
| 794 image_ctm = fz_pre_scale(fz_pre_translate(gstate->ctm, 0, 1), 1, -1); | |
| 795 | |
| 796 bbox = fz_transform_rect(fz_unit_rect, image_ctm); | |
| 797 | |
| 798 if (image->mask && gstate->blendmode) | |
| 799 { | |
| 800 /* apply blend group even though we skip the soft mask */ | |
| 801 fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1); | |
| 802 fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox); | |
| 803 pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); | |
| 804 fz_pop_clip(ctx, pr->dev); | |
| 805 fz_end_group(ctx, pr->dev); | |
| 806 } | |
| 807 else if (image->mask) | |
| 808 { | |
| 809 fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox); | |
| 810 pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); | |
| 811 fz_pop_clip(ctx, pr->dev); | |
| 812 } | |
| 813 else | |
| 814 { | |
| 815 softmask_save softmask = { NULL }; | |
| 816 fz_try(ctx) | |
| 817 { | |
| 818 gstate = pdf_begin_group(ctx, pr, bbox, &softmask); | |
| 819 pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); | |
| 820 pdf_end_group(ctx, pr, &softmask); | |
| 821 } | |
| 822 fz_catch(ctx) | |
| 823 { | |
| 824 pdf_drop_obj(ctx, softmask.softmask); | |
| 825 fz_drop_colorspace(ctx, softmask.softmask_cs); | |
| 826 pdf_drop_obj(ctx, softmask.page_resources); | |
| 827 fz_rethrow(ctx); | |
| 828 } | |
| 829 } | |
| 830 } | |
| 831 | |
| 832 static void | |
| 833 pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, int dostroke, int even_odd) | |
| 834 { | |
| 835 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 836 fz_path *path; | |
| 837 fz_rect bbox; | |
| 838 softmask_save softmask = { NULL }; | |
| 839 int knockout_group = 0; | |
| 840 | |
| 841 pop_any_pending_mcid_changes(ctx, pr); | |
| 842 flush_begin_layer(ctx, pr); | |
| 843 | |
| 844 if (dostroke) { | |
| 845 if (pr->dev->flags & (FZ_DEVFLAG_STROKECOLOR_UNDEFINED | FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED | FZ_DEVFLAG_DASH_PATTERN_UNDEFINED)) | |
| 846 pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; | |
| 847 else if (gstate->stroke_state->dash_len != 0 && pr->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED)) | |
| 848 pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; | |
| 849 else if (gstate->stroke_state->linejoin == FZ_LINEJOIN_MITER && (pr->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED)) | |
| 850 pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; | |
| 851 } | |
| 852 if (dofill) { | |
| 853 if (pr->dev->flags & FZ_DEVFLAG_FILLCOLOR_UNDEFINED) | |
| 854 pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; | |
| 855 } | |
| 856 | |
| 857 path = pr->path; | |
| 858 pr->path = fz_new_path(ctx); | |
| 859 | |
| 860 fz_try(ctx) | |
| 861 { | |
| 862 if (doclose) | |
| 863 fz_closepath(ctx, path); | |
| 864 | |
| 865 bbox = fz_bound_path(ctx, path, (dostroke ? gstate->stroke_state : NULL), gstate->ctm); | |
| 866 | |
| 867 if (pr->super.hidden) | |
| 868 dostroke = dofill = 0; | |
| 869 | |
| 870 if (dofill || dostroke) | |
| 871 gstate = pdf_begin_group(ctx, pr, bbox, &softmask); | |
| 872 | |
| 873 if (dofill && dostroke) | |
| 874 { | |
| 875 /* We may need to push a knockout group */ | |
| 876 if (gstate->stroke.alpha == 0) | |
| 877 { | |
| 878 /* No need for group, as stroke won't do anything */ | |
| 879 } | |
| 880 else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL) | |
| 881 { | |
| 882 /* No need for group, as stroke won't show up */ | |
| 883 } | |
| 884 else | |
| 885 { | |
| 886 knockout_group = 1; | |
| 887 fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 1, FZ_BLEND_NORMAL, 1); | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 if (dofill) | |
| 892 { | |
| 893 switch (gstate->fill.kind) | |
| 894 { | |
| 895 case PDF_MAT_NONE: | |
| 896 break; | |
| 897 case PDF_MAT_COLOR: | |
| 898 fz_fill_path(ctx, pr->dev, path, even_odd, gstate->ctm, | |
| 899 gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params); | |
| 900 break; | |
| 901 case PDF_MAT_PATTERN: | |
| 902 if (gstate->fill.pattern) | |
| 903 { | |
| 904 fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox); | |
| 905 gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL); | |
| 906 fz_pop_clip(ctx, pr->dev); | |
| 907 } | |
| 908 break; | |
| 909 case PDF_MAT_SHADE: | |
| 910 if (gstate->fill.shade) | |
| 911 { | |
| 912 fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox); | |
| 913 /* The cluster and page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm. */ | |
| 914 fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params); | |
| 915 fz_pop_clip(ctx, pr->dev); | |
| 916 } | |
| 917 break; | |
| 918 } | |
| 919 } | |
| 920 | |
| 921 if (dostroke) | |
| 922 { | |
| 923 switch (gstate->stroke.kind) | |
| 924 { | |
| 925 case PDF_MAT_NONE: | |
| 926 break; | |
| 927 case PDF_MAT_COLOR: | |
| 928 fz_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, | |
| 929 gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params); | |
| 930 break; | |
| 931 case PDF_MAT_PATTERN: | |
| 932 if (gstate->stroke.pattern) | |
| 933 { | |
| 934 fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox); | |
| 935 gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, bbox, PDF_STROKE); | |
| 936 fz_pop_clip(ctx, pr->dev); | |
| 937 } | |
| 938 break; | |
| 939 case PDF_MAT_SHADE: | |
| 940 if (gstate->stroke.shade) | |
| 941 { | |
| 942 fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox); | |
| 943 fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params); | |
| 944 fz_pop_clip(ctx, pr->dev); | |
| 945 } | |
| 946 break; | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 if (knockout_group) | |
| 951 fz_end_group(ctx, pr->dev); | |
| 952 | |
| 953 if (dofill || dostroke) | |
| 954 pdf_end_group(ctx, pr, &softmask); | |
| 955 | |
| 956 if (pr->clip) | |
| 957 { | |
| 958 nest_layer_clip(ctx, pr); | |
| 959 gstate->clip_depth++; | |
| 960 fz_clip_path(ctx, pr->dev, path, pr->clip_even_odd, gstate->ctm, bbox); | |
| 961 pr->clip = 0; | |
| 962 } | |
| 963 } | |
| 964 fz_always(ctx) | |
| 965 { | |
| 966 fz_drop_path(ctx, path); | |
| 967 } | |
| 968 fz_catch(ctx) | |
| 969 { | |
| 970 pdf_drop_obj(ctx, softmask.softmask); | |
| 971 fz_drop_colorspace(ctx, softmask.softmask_cs); | |
| 972 pdf_drop_obj(ctx, softmask.page_resources); | |
| 973 fz_rethrow(ctx); | |
| 974 } | |
| 975 } | |
| 976 | |
| 977 /* | |
| 978 * Assemble and emit text | |
| 979 */ | |
| 980 | |
| 981 static pdf_gstate * | |
| 982 pdf_flush_text(fz_context *ctx, pdf_run_processor *pr) | |
| 983 { | |
| 984 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 985 fz_text *text; | |
| 986 int dofill; | |
| 987 int dostroke; | |
| 988 int doclip; | |
| 989 int doinvisible; | |
| 990 softmask_save softmask = { NULL }; | |
| 991 int knockout_group = 0; | |
| 992 | |
| 993 text = pdf_tos_get_text(ctx, &pr->tos); | |
| 994 if (!text) | |
| 995 return gstate; | |
| 996 | |
| 997 pop_any_pending_mcid_changes(ctx, pr); | |
| 998 /* If we are going to output text, we need to have flushed any begin layers first. */ | |
| 999 flush_begin_layer(ctx, pr); | |
| 1000 | |
| 1001 dofill = dostroke = doclip = doinvisible = 0; | |
| 1002 switch (pr->tos.text_mode) | |
| 1003 { | |
| 1004 case 0: dofill = 1; break; | |
| 1005 case 1: dostroke = 1; break; | |
| 1006 case 2: dofill = dostroke = 1; break; | |
| 1007 case 3: doinvisible = 1; break; | |
| 1008 case 4: dofill = doclip = 1; break; | |
| 1009 case 5: dostroke = doclip = 1; break; | |
| 1010 case 6: dofill = dostroke = doclip = 1; break; | |
| 1011 case 7: doclip = 1; break; | |
| 1012 } | |
| 1013 | |
| 1014 if (pr->super.hidden) | |
| 1015 dostroke = dofill = 0; | |
| 1016 | |
| 1017 fz_try(ctx) | |
| 1018 { | |
| 1019 fz_rect tb = fz_transform_rect(pr->tos.text_bbox, gstate->ctm); | |
| 1020 if (dostroke) | |
| 1021 tb = fz_adjust_rect_for_stroke(ctx, tb, gstate->stroke_state, gstate->ctm); | |
| 1022 | |
| 1023 /* Don't bother sending a text group with nothing in it */ | |
| 1024 if (!text->head) | |
| 1025 break; | |
| 1026 | |
| 1027 if (dofill || dostroke) | |
| 1028 gstate = pdf_begin_group(ctx, pr, tb, &softmask); | |
| 1029 | |
| 1030 if (dofill && dostroke) | |
| 1031 { | |
| 1032 /* We may need to push a knockout group */ | |
| 1033 if (gstate->stroke.alpha == 0) | |
| 1034 { | |
| 1035 /* No need for group, as stroke won't do anything */ | |
| 1036 } | |
| 1037 else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL) | |
| 1038 { | |
| 1039 /* No need for group, as stroke won't show up */ | |
| 1040 } | |
| 1041 else | |
| 1042 { | |
| 1043 knockout_group = 1; | |
| 1044 fz_begin_group(ctx, pr->dev, tb, NULL, 0, 1, FZ_BLEND_NORMAL, 1); | |
| 1045 } | |
| 1046 } | |
| 1047 | |
| 1048 if (doinvisible) | |
| 1049 fz_ignore_text(ctx, pr->dev, text, gstate->ctm); | |
| 1050 | |
| 1051 if (dofill) | |
| 1052 { | |
| 1053 switch (gstate->fill.kind) | |
| 1054 { | |
| 1055 case PDF_MAT_NONE: | |
| 1056 break; | |
| 1057 case PDF_MAT_COLOR: | |
| 1058 fz_fill_text(ctx, pr->dev, text, gstate->ctm, | |
| 1059 gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params); | |
| 1060 break; | |
| 1061 case PDF_MAT_PATTERN: | |
| 1062 if (gstate->fill.pattern) | |
| 1063 { | |
| 1064 fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); | |
| 1065 gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, tb, PDF_FILL); | |
| 1066 fz_pop_clip(ctx, pr->dev); | |
| 1067 } | |
| 1068 break; | |
| 1069 case PDF_MAT_SHADE: | |
| 1070 if (gstate->fill.shade) | |
| 1071 { | |
| 1072 fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); | |
| 1073 /* Page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm */ | |
| 1074 fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params); | |
| 1075 fz_pop_clip(ctx, pr->dev); | |
| 1076 } | |
| 1077 break; | |
| 1078 } | |
| 1079 } | |
| 1080 | |
| 1081 if (dostroke) | |
| 1082 { | |
| 1083 switch (gstate->stroke.kind) | |
| 1084 { | |
| 1085 case PDF_MAT_NONE: | |
| 1086 break; | |
| 1087 case PDF_MAT_COLOR: | |
| 1088 fz_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, | |
| 1089 gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params); | |
| 1090 break; | |
| 1091 case PDF_MAT_PATTERN: | |
| 1092 if (gstate->stroke.pattern) | |
| 1093 { | |
| 1094 fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb); | |
| 1095 gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, tb, PDF_STROKE); | |
| 1096 fz_pop_clip(ctx, pr->dev); | |
| 1097 } | |
| 1098 break; | |
| 1099 case PDF_MAT_SHADE: | |
| 1100 if (gstate->stroke.shade) | |
| 1101 { | |
| 1102 fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb); | |
| 1103 fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params); | |
| 1104 fz_pop_clip(ctx, pr->dev); | |
| 1105 } | |
| 1106 break; | |
| 1107 } | |
| 1108 } | |
| 1109 | |
| 1110 if (knockout_group) | |
| 1111 fz_end_group(ctx, pr->dev); | |
| 1112 | |
| 1113 if (dofill || dostroke) | |
| 1114 pdf_end_group(ctx, pr, &softmask); | |
| 1115 | |
| 1116 if (doclip) | |
| 1117 { | |
| 1118 nest_layer_clip(ctx, pr); | |
| 1119 gstate->clip_depth++; | |
| 1120 fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); | |
| 1121 } | |
| 1122 } | |
| 1123 fz_always(ctx) | |
| 1124 { | |
| 1125 fz_drop_text(ctx, text); | |
| 1126 } | |
| 1127 fz_catch(ctx) | |
| 1128 { | |
| 1129 pdf_drop_obj(ctx, softmask.softmask); | |
| 1130 fz_drop_colorspace(ctx, softmask.softmask_cs); | |
| 1131 pdf_drop_obj(ctx, softmask.page_resources); | |
| 1132 fz_rethrow(ctx); | |
| 1133 } | |
| 1134 | |
| 1135 return pr->gstate + pr->gtop; | |
| 1136 } | |
| 1137 | |
| 1138 static int | |
| 1139 guess_bidi_level(int bidiclass, int cur_bidi) | |
| 1140 { | |
| 1141 switch (bidiclass) | |
| 1142 { | |
| 1143 /* strong */ | |
| 1144 case UCDN_BIDI_CLASS_L: return 0; | |
| 1145 case UCDN_BIDI_CLASS_R: return 1; | |
| 1146 case UCDN_BIDI_CLASS_AL: return 1; | |
| 1147 | |
| 1148 /* weak */ | |
| 1149 case UCDN_BIDI_CLASS_EN: | |
| 1150 case UCDN_BIDI_CLASS_ES: | |
| 1151 case UCDN_BIDI_CLASS_ET: | |
| 1152 return 0; | |
| 1153 case UCDN_BIDI_CLASS_AN: | |
| 1154 return 1; | |
| 1155 case UCDN_BIDI_CLASS_CS: | |
| 1156 case UCDN_BIDI_CLASS_NSM: | |
| 1157 case UCDN_BIDI_CLASS_BN: | |
| 1158 return cur_bidi; | |
| 1159 | |
| 1160 /* neutral */ | |
| 1161 case UCDN_BIDI_CLASS_B: | |
| 1162 case UCDN_BIDI_CLASS_S: | |
| 1163 case UCDN_BIDI_CLASS_WS: | |
| 1164 case UCDN_BIDI_CLASS_ON: | |
| 1165 return cur_bidi; | |
| 1166 | |
| 1167 /* embedding, override, pop ... we don't support them */ | |
| 1168 default: | |
| 1169 return 0; | |
| 1170 } | |
| 1171 } | |
| 1172 | |
| 1173 static void | |
| 1174 pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid, fz_text_language lang) | |
| 1175 { | |
| 1176 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1177 pdf_font_desc *fontdesc = gstate->text.font; | |
| 1178 fz_matrix trm; | |
| 1179 float adv; | |
| 1180 int gid; | |
| 1181 int ucsbuf[PDF_MRANGE_CAP]; | |
| 1182 int ucslen; | |
| 1183 int i; | |
| 1184 int render_direct; | |
| 1185 int type3_hitr; | |
| 1186 | |
| 1187 gid = pdf_tos_make_trm(ctx, &pr->tos, &gstate->text, fontdesc, cid, &trm, &adv); | |
| 1188 | |
| 1189 /* If we are uncachable, then render direct. */ | |
| 1190 render_direct = !fz_glyph_cacheable(ctx, fontdesc->font, gid); | |
| 1191 | |
| 1192 /* PDF spec: ISO 32000-2 latest version at the time of writing: | |
| 1193 * Section 9.3.6: | |
| 1194 * Where text is drawn using a Type 3 font: | |
| 1195 * + if text rendering mode is set to a value of 3 or 7, the text shall not be rendered. | |
| 1196 * + if text rendering mode is set to a value other than 3 or 7, the text shall be rendered using the glyph descriptions in the Type 3 font. | |
| 1197 * + If text rendering mode is set to a value of 4, 5, 6 or 7, nothing shall be added to the clipping path. | |
| 1198 */ | |
| 1199 type3_hitr = (fontdesc->font->t3procs && pr->tos.text_mode >= 4); | |
| 1200 | |
| 1201 /* flush buffered text if rendermode has changed */ | |
| 1202 if (!pr->tos.text || gstate->text.render != pr->tos.text_mode || render_direct || type3_hitr) | |
| 1203 { | |
| 1204 gstate = pdf_flush_text(ctx, pr); | |
| 1205 pdf_tos_reset(ctx, &pr->tos, gstate->text.render); | |
| 1206 } | |
| 1207 | |
| 1208 /* If Type3 and tr >= 4, then ignore the clipping path part. */ | |
| 1209 if (type3_hitr) | |
| 1210 pr->tos.text_mode -= 4; | |
| 1211 | |
| 1212 if (render_direct && pr->tos.text_mode != 3 /* or 7, by type3_hitr */) | |
| 1213 { | |
| 1214 /* Render the glyph stream direct here (only happens for | |
| 1215 * type3 glyphs that seem to inherit current graphics | |
| 1216 * attributes, or type 3 glyphs within type3 glyphs). */ | |
| 1217 fz_matrix composed = fz_concat(trm, gstate->ctm); | |
| 1218 /* Whatever problems the underlying char has is no concern of | |
| 1219 * ours. Store the flags, restore them afterwards. */ | |
| 1220 int old_flags = pr->dev->flags; | |
| 1221 pdf_gstate *fill_gstate = NULL; | |
| 1222 pdf_gstate *stroke_gstate = NULL; | |
| 1223 pdf_gsave(ctx, pr); | |
| 1224 gstate = pr->gstate + pr->gtop; | |
| 1225 if (gstate->fill.kind == PDF_MAT_PATTERN && gstate->fill.gstate_num >= 0) | |
| 1226 fill_gstate = pr->gstate + gstate->fill.gstate_num; | |
| 1227 if (gstate->stroke.kind == PDF_MAT_PATTERN && gstate->stroke.gstate_num >= 0) | |
| 1228 stroke_gstate = pr->gstate + gstate->stroke.gstate_num; | |
| 1229 pdf_drop_font(ctx, gstate->text.font); | |
| 1230 gstate->text.font = NULL; /* don't inherit the current font... */ | |
| 1231 fz_render_t3_glyph_direct(ctx, pr->dev, fontdesc->font, gid, composed, gstate, pr->default_cs, fill_gstate, stroke_gstate); | |
| 1232 pr->dev->flags = old_flags; | |
| 1233 pdf_grestore(ctx, pr); | |
| 1234 /* Render text invisibly so that it can still be extracted. */ | |
| 1235 pr->tos.text_mode = 3; | |
| 1236 } | |
| 1237 | |
| 1238 ucslen = 0; | |
| 1239 if (fontdesc->to_unicode) | |
| 1240 ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf); | |
| 1241 | |
| 1242 /* convert ascii whitespace control characters to spaces */ | |
| 1243 if (ucslen == 1 && (ucsbuf[0] >= 8 && ucsbuf[0] <= 13)) | |
| 1244 ucsbuf[0] = ' '; | |
| 1245 | |
| 1246 /* ignore obviously bad values in ToUnicode, fall back to the cid_to_ucs table */ | |
| 1247 if (ucslen == 1 && (ucsbuf[0] < 32 || (ucsbuf[0] >= 127 && ucsbuf[0] < 160))) | |
| 1248 ucslen = 0; | |
| 1249 | |
| 1250 if (ucslen == 0 && (size_t)cid < fontdesc->cid_to_ucs_len) | |
| 1251 { | |
| 1252 ucsbuf[0] = fontdesc->cid_to_ucs[cid]; | |
| 1253 ucslen = 1; | |
| 1254 } | |
| 1255 if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0)) | |
| 1256 { | |
| 1257 ucsbuf[0] = FZ_REPLACEMENT_CHARACTER; | |
| 1258 ucslen = 1; | |
| 1259 } | |
| 1260 | |
| 1261 /* guess bidi level from unicode value */ | |
| 1262 pr->bidi = guess_bidi_level(ucdn_get_bidi_class(ucsbuf[0]), pr->bidi); | |
| 1263 | |
| 1264 /* add glyph to textobject */ | |
| 1265 fz_show_glyph_aux(ctx, pr->tos.text, fontdesc->font, trm, adv, gid, ucsbuf[0], cid, fontdesc->wmode, pr->bidi, FZ_BIDI_NEUTRAL, lang); | |
| 1266 | |
| 1267 /* add filler glyphs for one-to-many unicode mapping */ | |
| 1268 for (i = 1; i < ucslen; i++) | |
| 1269 fz_show_glyph_aux(ctx, pr->tos.text, fontdesc->font, trm, 0, -1, ucsbuf[i], -1, fontdesc->wmode, pr->bidi, FZ_BIDI_NEUTRAL, lang); | |
| 1270 | |
| 1271 pdf_tos_move_after_char(ctx, &pr->tos); | |
| 1272 } | |
| 1273 | |
| 1274 static void | |
| 1275 pdf_show_space(fz_context *ctx, pdf_run_processor *pr, float tadj) | |
| 1276 { | |
| 1277 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1278 pdf_font_desc *fontdesc = gstate->text.font; | |
| 1279 | |
| 1280 if (fontdesc->wmode == 0) | |
| 1281 pr->tos.tm = fz_pre_translate(pr->tos.tm, tadj * gstate->text.scale, 0); | |
| 1282 else | |
| 1283 pr->tos.tm = fz_pre_translate(pr->tos.tm, 0, tadj); | |
| 1284 } | |
| 1285 | |
| 1286 static int | |
| 1287 int_in_singleton_or_array(fz_context *ctx, pdf_obj *k, int id) | |
| 1288 { | |
| 1289 /* In the most common case the /K value will be id. */ | |
| 1290 if (pdf_is_int(ctx, k) && pdf_to_int(ctx, k) == id) | |
| 1291 return 1; | |
| 1292 | |
| 1293 /* In the next most common case, there will be an array of | |
| 1294 * items, one of which is k. */ | |
| 1295 if (pdf_is_array(ctx, k)) | |
| 1296 { | |
| 1297 int i, n = pdf_array_len(ctx, k); | |
| 1298 | |
| 1299 for (i = 0; i < n; i++) | |
| 1300 { | |
| 1301 pdf_obj *o = pdf_array_get(ctx, k, i); | |
| 1302 if (pdf_is_int(ctx, o) && pdf_to_int(ctx, o) == id) | |
| 1303 return 1; | |
| 1304 } | |
| 1305 } | |
| 1306 | |
| 1307 return 0; | |
| 1308 } | |
| 1309 | |
| 1310 pdf_obj * | |
| 1311 pdf_lookup_mcid_in_mcids(fz_context *ctx, int id, pdf_obj *mcids) | |
| 1312 { | |
| 1313 pdf_obj *mcid = pdf_array_get(ctx, mcids, id); | |
| 1314 pdf_obj *k = pdf_dict_get(ctx, mcid, PDF_NAME(K)); | |
| 1315 int i, n; | |
| 1316 | |
| 1317 if (int_in_singleton_or_array(ctx, k, id)) | |
| 1318 return mcid; | |
| 1319 | |
| 1320 /* At this point, something has gone wrong. One common case that | |
| 1321 * appears to fail is where the MCIDs array has the right things | |
| 1322 * in, but at the wrong indexes. So do some searching. */ | |
| 1323 n = pdf_array_len(ctx, mcids); | |
| 1324 for (i = 0; i < n; i++) | |
| 1325 { | |
| 1326 pdf_obj *o = pdf_array_get(ctx, mcids, i); | |
| 1327 if (int_in_singleton_or_array(ctx, pdf_dict_get(ctx, o, PDF_NAME(K)), id)) | |
| 1328 return o; | |
| 1329 } | |
| 1330 | |
| 1331 return NULL; | |
| 1332 } | |
| 1333 | |
| 1334 static pdf_obj * | |
| 1335 lookup_mcid(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val) | |
| 1336 { | |
| 1337 pdf_obj *mcid; | |
| 1338 int id; | |
| 1339 pdf_obj *mcids; | |
| 1340 | |
| 1341 if (proc->struct_parent == -1) | |
| 1342 return NULL; | |
| 1343 | |
| 1344 mcid = pdf_dict_get(ctx, val, PDF_NAME(MCID)); | |
| 1345 if (!mcid) | |
| 1346 return NULL; | |
| 1347 | |
| 1348 if (!pdf_is_number(ctx, mcid)) | |
| 1349 return NULL; | |
| 1350 | |
| 1351 id = pdf_to_int(ctx, mcid); | |
| 1352 mcids = pdf_lookup_number(ctx, pdf_dict_getl(ctx, pdf_trailer(ctx, proc->doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), PDF_NAME(ParentTree), NULL), proc->struct_parent); | |
| 1353 return pdf_lookup_mcid_in_mcids(ctx, id, mcids); | |
| 1354 } | |
| 1355 | |
| 1356 static fz_text_language | |
| 1357 find_lang_from_mc(fz_context *ctx, pdf_run_processor *pr) | |
| 1358 { | |
| 1359 marked_content_stack *mc; | |
| 1360 | |
| 1361 for (mc = pr->marked_content; mc != NULL; mc = mc->next) | |
| 1362 { | |
| 1363 size_t len; | |
| 1364 const char *lang; | |
| 1365 | |
| 1366 lang = pdf_dict_get_string(ctx, mc->val, PDF_NAME(Lang), &len); | |
| 1367 if (!lang) | |
| 1368 lang = pdf_dict_get_string(ctx, lookup_mcid(ctx, pr, mc->val), PDF_NAME(Lang), &len); | |
| 1369 if (lang) | |
| 1370 { | |
| 1371 char text[8]; | |
| 1372 memcpy(text, lang, len < 8 ? len : 7); | |
| 1373 text[len < 8 ? len : 7] = 0; | |
| 1374 return fz_text_language_from_string(text); | |
| 1375 } | |
| 1376 } | |
| 1377 | |
| 1378 return FZ_LANG_UNSET; | |
| 1379 } | |
| 1380 | |
| 1381 static void | |
| 1382 show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, size_t len) | |
| 1383 { | |
| 1384 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1385 pdf_font_desc *fontdesc = gstate->text.font; | |
| 1386 unsigned char *end = buf + len; | |
| 1387 unsigned int cpt; | |
| 1388 int cid; | |
| 1389 fz_text_language lang = find_lang_from_mc(ctx, pr); | |
| 1390 | |
| 1391 pop_any_pending_mcid_changes(ctx, pr); | |
| 1392 flush_begin_layer(ctx, pr); | |
| 1393 | |
| 1394 while (buf < end) | |
| 1395 { | |
| 1396 int w = pdf_decode_cmap(fontdesc->encoding, buf, end, &cpt); | |
| 1397 buf += w; | |
| 1398 | |
| 1399 cid = pdf_lookup_cmap(fontdesc->encoding, cpt); | |
| 1400 if (cid >= 0) | |
| 1401 pdf_show_char(ctx, pr, cid, lang); | |
| 1402 else | |
| 1403 fz_warn(ctx, "cannot encode character"); | |
| 1404 if (cpt == 32 && w == 1) | |
| 1405 { | |
| 1406 /* Bug 703151: pdf_show_char can realloc gstate. */ | |
| 1407 gstate = pr->gstate + pr->gtop; | |
| 1408 pdf_show_space(ctx, pr, gstate->text.word_space); | |
| 1409 } | |
| 1410 } | |
| 1411 } | |
| 1412 | |
| 1413 static void | |
| 1414 pdf_show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, size_t len) | |
| 1415 { | |
| 1416 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1417 pdf_font_desc *fontdesc = gstate->text.font; | |
| 1418 | |
| 1419 if (!fontdesc) | |
| 1420 { | |
| 1421 fz_warn(ctx, "cannot draw text since font and size not set"); | |
| 1422 return; | |
| 1423 } | |
| 1424 | |
| 1425 show_string(ctx, pr, buf, len); | |
| 1426 } | |
| 1427 | |
| 1428 static void | |
| 1429 pdf_show_text(fz_context *ctx, pdf_run_processor *pr, pdf_obj *text) | |
| 1430 { | |
| 1431 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1432 pdf_font_desc *fontdesc = gstate->text.font; | |
| 1433 int i; | |
| 1434 | |
| 1435 if (!fontdesc) | |
| 1436 { | |
| 1437 fz_warn(ctx, "cannot draw text since font and size not set"); | |
| 1438 return; | |
| 1439 } | |
| 1440 | |
| 1441 if (pdf_is_array(ctx, text)) | |
| 1442 { | |
| 1443 int n = pdf_array_len(ctx, text); | |
| 1444 for (i = 0; i < n; i++) | |
| 1445 { | |
| 1446 pdf_obj *item = pdf_array_get(ctx, text, i); | |
| 1447 if (pdf_is_string(ctx, item)) | |
| 1448 show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, item), pdf_to_str_len(ctx, item)); | |
| 1449 else | |
| 1450 pdf_show_space(ctx, pr, - pdf_to_real(ctx, item) * gstate->text.size * 0.001f); | |
| 1451 } | |
| 1452 } | |
| 1453 else if (pdf_is_string(ctx, text)) | |
| 1454 { | |
| 1455 pdf_show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text)); | |
| 1456 } | |
| 1457 } | |
| 1458 | |
| 1459 /* | |
| 1460 * Interpreter and graphics state stack. | |
| 1461 */ | |
| 1462 | |
| 1463 static void | |
| 1464 pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, fz_matrix ctm) | |
| 1465 { | |
| 1466 gs->ctm = ctm; | |
| 1467 gs->clip_depth = 0; | |
| 1468 | |
| 1469 gs->stroke_state = fz_new_stroke_state(ctx); | |
| 1470 | |
| 1471 gs->stroke.kind = PDF_MAT_COLOR; | |
| 1472 gs->stroke.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); | |
| 1473 gs->stroke.v[0] = 0; | |
| 1474 gs->stroke.pattern = NULL; | |
| 1475 gs->stroke.shade = NULL; | |
| 1476 gs->stroke.alpha = 1; | |
| 1477 gs->stroke.gstate_num = -1; | |
| 1478 | |
| 1479 gs->fill.kind = PDF_MAT_COLOR; | |
| 1480 gs->fill.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); | |
| 1481 gs->fill.v[0] = 0; | |
| 1482 gs->fill.pattern = NULL; | |
| 1483 gs->fill.shade = NULL; | |
| 1484 gs->fill.alpha = 1; | |
| 1485 gs->fill.gstate_num = -1; | |
| 1486 | |
| 1487 gs->text.char_space = 0; | |
| 1488 gs->text.word_space = 0; | |
| 1489 gs->text.scale = 1; | |
| 1490 gs->text.leading = 0; | |
| 1491 gs->text.font = NULL; | |
| 1492 gs->text.size = -1; | |
| 1493 gs->text.render = 0; | |
| 1494 gs->text.rise = 0; | |
| 1495 | |
| 1496 gs->blendmode = 0; | |
| 1497 gs->softmask = NULL; | |
| 1498 gs->softmask_cs = NULL; | |
| 1499 gs->softmask_resources = NULL; | |
| 1500 gs->softmask_ctm = fz_identity; | |
| 1501 gs->luminosity = 0; | |
| 1502 | |
| 1503 gs->fill.color_params = fz_default_color_params; | |
| 1504 gs->stroke.color_params = fz_default_color_params; | |
| 1505 | |
| 1506 gs->ismask = 0; | |
| 1507 } | |
| 1508 | |
| 1509 static void | |
| 1510 pdf_copy_gstate(fz_context *ctx, pdf_gstate *dst, pdf_gstate *src) | |
| 1511 { | |
| 1512 pdf_drop_gstate(ctx, dst); | |
| 1513 *dst = *src; | |
| 1514 pdf_keep_gstate(ctx, dst); | |
| 1515 } | |
| 1516 | |
| 1517 /* | |
| 1518 * Material state | |
| 1519 */ | |
| 1520 | |
| 1521 static void | |
| 1522 pdf_set_colorspace(fz_context *ctx, pdf_run_processor *pr, int what, fz_colorspace *colorspace) | |
| 1523 { | |
| 1524 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1525 pdf_material *mat; | |
| 1526 int n = fz_colorspace_n(ctx, colorspace); | |
| 1527 | |
| 1528 gstate = pdf_flush_text(ctx, pr); | |
| 1529 | |
| 1530 /* Don't change color if we're drawing an uncolored pattern tile! */ | |
| 1531 if (gstate->ismask) | |
| 1532 return; | |
| 1533 | |
| 1534 mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; | |
| 1535 | |
| 1536 fz_drop_colorspace(ctx, mat->colorspace); | |
| 1537 | |
| 1538 mat->kind = PDF_MAT_COLOR; | |
| 1539 mat->colorspace = fz_keep_colorspace(ctx, colorspace); | |
| 1540 | |
| 1541 mat->v[0] = 0; | |
| 1542 mat->v[1] = 0; | |
| 1543 mat->v[2] = 0; | |
| 1544 mat->v[3] = 1; | |
| 1545 | |
| 1546 if (pdf_is_tint_colorspace(ctx, colorspace)) | |
| 1547 { | |
| 1548 int i; | |
| 1549 for (i = 0; i < n; i++) | |
| 1550 mat->v[i] = 1.0f; | |
| 1551 } | |
| 1552 } | |
| 1553 | |
| 1554 static void | |
| 1555 pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v) | |
| 1556 { | |
| 1557 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 1558 pdf_material *mat; | |
| 1559 | |
| 1560 gstate = pdf_flush_text(ctx, pr); | |
| 1561 | |
| 1562 /* Don't change color if we're drawing an uncolored pattern tile! */ | |
| 1563 if (gstate->ismask) | |
| 1564 return; | |
| 1565 | |
| 1566 mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; | |
| 1567 | |
| 1568 switch (mat->kind) | |
| 1569 { | |
| 1570 case PDF_MAT_PATTERN: | |
| 1571 case PDF_MAT_COLOR: | |
| 1572 fz_clamp_color(ctx, mat->colorspace, v, mat->v); | |
| 1573 break; | |
| 1574 default: | |
| 1575 fz_warn(ctx, "color incompatible with material"); | |
| 1576 } | |
| 1577 | |
| 1578 mat->gstate_num = pr->gparent; | |
| 1579 } | |
| 1580 | |
| 1581 static void | |
| 1582 pdf_set_shade(fz_context *ctx, pdf_run_processor *pr, int what, fz_shade *shade) | |
| 1583 { | |
| 1584 pdf_gstate *gs; | |
| 1585 pdf_material *mat; | |
| 1586 | |
| 1587 gs = pdf_flush_text(ctx, pr); | |
| 1588 | |
| 1589 mat = what == PDF_FILL ? &gs->fill : &gs->stroke; | |
| 1590 | |
| 1591 fz_drop_shade(ctx, mat->shade); | |
| 1592 | |
| 1593 mat->kind = PDF_MAT_SHADE; | |
| 1594 mat->shade = fz_keep_shade(ctx, shade); | |
| 1595 | |
| 1596 mat->gstate_num = pr->gparent; | |
| 1597 } | |
| 1598 | |
| 1599 static void | |
| 1600 pdf_set_pattern(fz_context *ctx, pdf_run_processor *pr, int what, pdf_pattern *pat, float *v) | |
| 1601 { | |
| 1602 pdf_gstate *gs; | |
| 1603 pdf_material *mat; | |
| 1604 | |
| 1605 gs = pdf_flush_text(ctx, pr); | |
| 1606 | |
| 1607 mat = what == PDF_FILL ? &gs->fill : &gs->stroke; | |
| 1608 | |
| 1609 pdf_drop_pattern(ctx, mat->pattern); | |
| 1610 mat->pattern = NULL; | |
| 1611 | |
| 1612 mat->kind = PDF_MAT_PATTERN; | |
| 1613 if (pat) | |
| 1614 mat->pattern = pdf_keep_pattern(ctx, pat); | |
| 1615 | |
| 1616 if (v) | |
| 1617 pdf_set_color(ctx, pr, what, v); | |
| 1618 | |
| 1619 mat->gstate_num = pr->gparent; | |
| 1620 } | |
| 1621 | |
| 1622 static void | |
| 1623 begin_metatext(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_obj *mcid, fz_metatext meta, pdf_obj *name) | |
| 1624 { | |
| 1625 pdf_obj *text = pdf_dict_get(ctx, val, name); | |
| 1626 | |
| 1627 if (!text) | |
| 1628 text = pdf_dict_get(ctx, mcid, name); | |
| 1629 if (!text) | |
| 1630 return; | |
| 1631 | |
| 1632 pdf_flush_text(ctx, proc); | |
| 1633 | |
| 1634 fz_begin_metatext(ctx, proc->dev, meta, pdf_to_text_string(ctx, text)); | |
| 1635 } | |
| 1636 | |
| 1637 static void | |
| 1638 end_metatext(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_obj *mcid, pdf_obj *name) | |
| 1639 { | |
| 1640 pdf_obj *text = pdf_dict_get(ctx, val, name); | |
| 1641 | |
| 1642 if (!text) | |
| 1643 text = pdf_dict_get(ctx, mcid, name); | |
| 1644 if (!text) | |
| 1645 return; | |
| 1646 | |
| 1647 pdf_flush_text(ctx, proc); | |
| 1648 | |
| 1649 fz_end_metatext(ctx, proc->dev); | |
| 1650 } | |
| 1651 | |
| 1652 static void | |
| 1653 begin_oc(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_cycle_list *cycle_up) | |
| 1654 { | |
| 1655 /* val has been resolved to a dict for us by the originally specified name | |
| 1656 * having been looked up in Properties already for us. Either there will | |
| 1657 * be a Name entry, or there will be an OCGs and it'll be a group one. */ | |
| 1658 pdf_cycle_list cycle; | |
| 1659 pdf_obj *obj; | |
| 1660 int i, n; | |
| 1661 | |
| 1662 if (pdf_cycle(ctx, &cycle, cycle_up, val)) | |
| 1663 return; | |
| 1664 | |
| 1665 obj = pdf_dict_get(ctx, val, PDF_NAME(Name)); | |
| 1666 if (obj) | |
| 1667 { | |
| 1668 const char *name = ""; | |
| 1669 pdf_flush_text(ctx, proc); | |
| 1670 if (pdf_is_name(ctx, obj)) | |
| 1671 name = pdf_to_name(ctx, obj); | |
| 1672 else if (pdf_is_string(ctx, obj)) | |
| 1673 name = pdf_to_text_string(ctx, obj); | |
| 1674 | |
| 1675 push_begin_layer(ctx, proc, name); | |
| 1676 return; | |
| 1677 } | |
| 1678 | |
| 1679 obj = pdf_dict_get(ctx, val, PDF_NAME(OCGs)); | |
| 1680 n = pdf_array_len(ctx, obj); | |
| 1681 for (i = 0; i < n; i++) | |
| 1682 { | |
| 1683 begin_oc(ctx, proc, pdf_array_get(ctx, obj, i), &cycle); | |
| 1684 } | |
| 1685 } | |
| 1686 | |
| 1687 static void | |
| 1688 end_oc(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_cycle_list *cycle_up) | |
| 1689 { | |
| 1690 /* val has been resolved to a dict for us by the originally specified name | |
| 1691 * having been looked up in Properties already for us. Either there will | |
| 1692 * be a Name entry, or there will be an OCGs and it'll be a group one. */ | |
| 1693 pdf_cycle_list cycle; | |
| 1694 pdf_obj *obj; | |
| 1695 int i, n; | |
| 1696 | |
| 1697 if (pdf_cycle(ctx, &cycle, cycle_up, val)) | |
| 1698 return; | |
| 1699 | |
| 1700 obj = pdf_dict_get(ctx, val, PDF_NAME(Name)); | |
| 1701 if (obj) | |
| 1702 { | |
| 1703 flush_begin_layer(ctx, proc); | |
| 1704 do_end_layer(ctx, proc); | |
| 1705 return; | |
| 1706 } | |
| 1707 | |
| 1708 obj = pdf_dict_get(ctx, val, PDF_NAME(OCGs)); | |
| 1709 n = pdf_array_len(ctx, obj); | |
| 1710 for (i = n-1; i >= 0; i--) | |
| 1711 { | |
| 1712 end_oc(ctx, proc, pdf_array_get(ctx, obj, i), &cycle); | |
| 1713 } | |
| 1714 } | |
| 1715 | |
| 1716 static void | |
| 1717 begin_layer(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val) | |
| 1718 { | |
| 1719 /* val has been resolved to a dict for us by the originally specified name | |
| 1720 * having been looked up in Properties already for us. Go with the 'Title' | |
| 1721 * entry. */ | |
| 1722 pdf_obj *obj = pdf_dict_get(ctx, val, PDF_NAME(Title)); | |
| 1723 if (obj) | |
| 1724 { | |
| 1725 pdf_flush_text(ctx, proc); | |
| 1726 push_begin_layer(ctx, proc, pdf_to_text_string(ctx, obj)); | |
| 1727 } | |
| 1728 } | |
| 1729 | |
| 1730 static void | |
| 1731 end_layer(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val) | |
| 1732 { | |
| 1733 /* val has been resolved to a dict for us by the originally specified name | |
| 1734 * having been looked up in Properties already for us. Go with the 'Title' | |
| 1735 * entry. */ | |
| 1736 pdf_obj *obj = pdf_dict_get(ctx, val, PDF_NAME(Title)); | |
| 1737 if (obj) | |
| 1738 { | |
| 1739 do_end_layer(ctx, proc); | |
| 1740 } | |
| 1741 } | |
| 1742 | |
| 1743 #ifdef DEBUG_STRUCTURE | |
| 1744 static void | |
| 1745 structure_dump(fz_context *ctx, const char *str, pdf_obj *obj) | |
| 1746 { | |
| 1747 fprintf(stderr, "%s STACK=", str); | |
| 1748 | |
| 1749 if (obj == NULL) | |
| 1750 { | |
| 1751 fprintf(stderr, "empty\n"); | |
| 1752 return; | |
| 1753 } | |
| 1754 | |
| 1755 do | |
| 1756 { | |
| 1757 pdf_obj *s = pdf_dict_get(ctx, obj, PDF_NAME(S)); | |
| 1758 int n = pdf_to_num(ctx, obj); | |
| 1759 fprintf(stderr, " %d", n); | |
| 1760 if (s) | |
| 1761 fprintf(stderr, "[%s]", pdf_to_name(ctx, s)); | |
| 1762 obj = pdf_dict_get(ctx, obj, PDF_NAME(P)); | |
| 1763 } | |
| 1764 while (obj); | |
| 1765 fprintf(stderr, "\n"); | |
| 1766 } | |
| 1767 #endif | |
| 1768 | |
| 1769 static void | |
| 1770 pop_structure_to(fz_context *ctx, pdf_run_processor *proc, pdf_obj *common) | |
| 1771 { | |
| 1772 pdf_obj *struct_tree_root = pdf_dict_getl(ctx, pdf_trailer(ctx, proc->doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), NULL); | |
| 1773 | |
| 1774 #ifdef DEBUG_STRUCTURE | |
| 1775 structure_dump(ctx, "pop_structure_to (before)", proc->mcid_sent); | |
| 1776 | |
| 1777 { | |
| 1778 int n = pdf_to_num(ctx, common); | |
| 1779 fprintf(stderr, "Popping until %d\n", n); | |
| 1780 } | |
| 1781 #endif | |
| 1782 | |
| 1783 while (proc->mcid_sent != NULL && pdf_objcmp(ctx, proc->mcid_sent, common)) | |
| 1784 { | |
| 1785 pdf_obj *p = pdf_dict_get(ctx, proc->mcid_sent, PDF_NAME(P)); | |
| 1786 pdf_obj *tag = pdf_dict_get(ctx, proc->mcid_sent, PDF_NAME(S)); | |
| 1787 fz_structure standard = pdf_structure_type(ctx, proc->role_map, tag); | |
| 1788 #ifdef DEBUG_STRUCTURE | |
| 1789 fprintf(stderr, "sending pop [tag=%s][std=%d]\n", pdf_to_name(ctx, tag) ? pdf_to_name(ctx, tag) : "null", standard); | |
| 1790 #endif | |
| 1791 if (standard != FZ_STRUCTURE_INVALID) | |
| 1792 fz_end_structure(ctx, proc->dev); | |
| 1793 pdf_drop_obj(ctx, proc->mcid_sent); | |
| 1794 proc->mcid_sent = pdf_keep_obj(ctx, p); | |
| 1795 if (!pdf_objcmp(ctx, p, struct_tree_root)) | |
| 1796 { | |
| 1797 pdf_drop_obj(ctx, proc->mcid_sent); | |
| 1798 proc->mcid_sent = NULL; | |
| 1799 break; | |
| 1800 } | |
| 1801 } | |
| 1802 #ifdef DEBUG_STRUCTURE | |
| 1803 structure_dump(ctx, "pop_structure_to (after)", proc->mcid_sent); | |
| 1804 #endif | |
| 1805 } | |
| 1806 | |
| 1807 static void | |
| 1808 pop_any_pending_mcid_changes(fz_context *ctx, pdf_run_processor *pr) | |
| 1809 { | |
| 1810 if (pr->pending_mcid_pop == NULL) | |
| 1811 return; | |
| 1812 | |
| 1813 pop_structure_to(ctx, pr, pr->pending_mcid_pop); | |
| 1814 pr->pending_mcid_pop = NULL; | |
| 1815 } | |
| 1816 | |
| 1817 struct line | |
| 1818 { | |
| 1819 pdf_obj *obj; | |
| 1820 struct line *child; | |
| 1821 }; | |
| 1822 | |
| 1823 static pdf_obj * | |
| 1824 find_most_recent_common_ancestor_imp(fz_context *ctx, pdf_obj *a, struct line *line_a, pdf_obj *b, struct line *line_b, pdf_cycle_list *cycle_up_a, pdf_cycle_list *cycle_up_b) | |
| 1825 { | |
| 1826 struct line line; | |
| 1827 pdf_obj *common = NULL; | |
| 1828 pdf_cycle_list cycle; | |
| 1829 pdf_obj *parent; | |
| 1830 | |
| 1831 /* First ascend one lineage. */ | |
| 1832 if (pdf_is_dict(ctx, a)) | |
| 1833 { | |
| 1834 if (pdf_cycle(ctx, &cycle, cycle_up_a, a)) | |
| 1835 fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in structure tree"); | |
| 1836 line.obj = a; | |
| 1837 line.child = line_a; | |
| 1838 parent = pdf_dict_get(ctx, a, PDF_NAME(P)); | |
| 1839 return find_most_recent_common_ancestor_imp(ctx, parent, &line, b, NULL, &cycle, NULL); | |
| 1840 } | |
| 1841 /* Then ascend the other lineage. */ | |
| 1842 else if (pdf_is_dict(ctx, b)) | |
| 1843 { | |
| 1844 if (pdf_cycle(ctx, &cycle, cycle_up_b, b)) | |
| 1845 fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in structure tree"); | |
| 1846 line.obj = b; | |
| 1847 line.child = line_b; | |
| 1848 parent = pdf_dict_get(ctx, b, PDF_NAME(P)); | |
| 1849 return find_most_recent_common_ancestor_imp(ctx, a, line_a, parent, &line, cycle_up_a, &cycle); | |
| 1850 } | |
| 1851 | |
| 1852 /* Once both lineages are know, traverse top-down to find most recent common ancestor. */ | |
| 1853 while (line_a && line_b && !pdf_objcmp(ctx, line_a->obj, line_b->obj)) | |
| 1854 { | |
| 1855 common = line_a->obj; | |
| 1856 line_a = line_a->child; | |
| 1857 line_b = line_b->child; | |
| 1858 } | |
| 1859 return common; | |
| 1860 } | |
| 1861 | |
| 1862 static pdf_obj * | |
| 1863 find_most_recent_common_ancestor(fz_context *ctx, pdf_obj *a, pdf_obj *b) | |
| 1864 { | |
| 1865 if (!pdf_is_dict(ctx, a) || !pdf_is_dict(ctx, b)) | |
| 1866 return NULL; | |
| 1867 return find_most_recent_common_ancestor_imp(ctx, a, NULL, b, NULL, NULL, NULL); | |
| 1868 } | |
| 1869 | |
| 1870 static int | |
| 1871 get_struct_index(fz_context *ctx, pdf_obj *send) | |
| 1872 { | |
| 1873 pdf_obj *p = pdf_dict_get(ctx, send, PDF_NAME(P)); | |
| 1874 pdf_obj *k; | |
| 1875 int i, n; | |
| 1876 | |
| 1877 if (p == NULL) | |
| 1878 return 0; /* Presumably the StructTreeRoot */ | |
| 1879 | |
| 1880 /* So, get the kids array. */ | |
| 1881 k = pdf_dict_get(ctx, p, PDF_NAME(K)); | |
| 1882 n = pdf_array_len(ctx, k); | |
| 1883 if (n == 0) | |
| 1884 { | |
| 1885 /* Not an array, presumably a singleton. */ | |
| 1886 if (pdf_objcmp(ctx, k, send) == 0) | |
| 1887 return 0; | |
| 1888 return -1; | |
| 1889 } | |
| 1890 for (i = 0; i < n; i++) | |
| 1891 { | |
| 1892 if (pdf_objcmp(ctx, pdf_array_get(ctx, k, i), send) == 0) | |
| 1893 return i; | |
| 1894 } | |
| 1895 return -1; | |
| 1896 } | |
| 1897 | |
| 1898 static int | |
| 1899 send_begin_structure(fz_context *ctx, pdf_run_processor *proc, pdf_obj *mc_dict) | |
| 1900 { | |
| 1901 pdf_obj *common = NULL; | |
| 1902 | |
| 1903 #ifdef DEBUG_STRUCTURE | |
| 1904 fprintf(stderr, "send_begin_structure %d\n", pdf_to_num(ctx, mc_dict)); | |
| 1905 structure_dump(ctx, "on entry", proc->mcid_sent); | |
| 1906 #endif | |
| 1907 | |
| 1908 /* We are currently nested in A,B,C,...E,F,mcid_sent. We want to update to | |
| 1909 * being in A,B,C,...G,H,mc_dict. So we need to find the lowest common point. */ | |
| 1910 common = find_most_recent_common_ancestor(ctx, proc->mcid_sent, mc_dict); | |
| 1911 | |
| 1912 /* So, we need to pop everything up to common (i.e. everything below common will be closed). */ | |
| 1913 pop_structure_to(ctx, proc, common); | |
| 1914 | |
| 1915 #ifdef DEBUG_STRUCTURE | |
| 1916 structure_dump(ctx, "after popping", proc->mcid_sent); | |
| 1917 #endif | |
| 1918 /* Now we need to send everything between common (proc->mcid_sent) and mc_dict. | |
| 1919 * Again, n^2 will do... */ | |
| 1920 while (pdf_objcmp(ctx, proc->mcid_sent, mc_dict)) | |
| 1921 { | |
| 1922 pdf_obj *send = mc_dict; | |
| 1923 fz_structure standard; | |
| 1924 pdf_obj *tag; | |
| 1925 int idx; | |
| 1926 pdf_obj *slowptr = send; | |
| 1927 int slow = 0; | |
| 1928 | |
| 1929 /* Run up the ancestor stack, looking for the first child of mcid_sent. | |
| 1930 * That's the one we need to send next. */ | |
| 1931 while (1) { | |
| 1932 pdf_obj *p = pdf_dict_get(ctx, send, PDF_NAME(P)); | |
| 1933 | |
| 1934 /* If we ever fail to find a dict, then do not step down lest | |
| 1935 * we can't get back later! */ | |
| 1936 if (!pdf_is_dict(ctx, send)) | |
| 1937 { | |
| 1938 fz_warn(ctx, "Bad parent link in structure tree. Ignoring structure."); | |
| 1939 proc->broken_struct_tree = 1; | |
| 1940 return 0; | |
| 1941 } | |
| 1942 /* If p is the one we last sent, then we want to send 'send' | |
| 1943 * next. Exit the loop. */ | |
| 1944 if (!pdf_objcmp(ctx, p, proc->mcid_sent)) | |
| 1945 break; | |
| 1946 | |
| 1947 /* We need to go at least one step further up the stack. */ | |
| 1948 send = p; | |
| 1949 | |
| 1950 /* Check for a loop in the parent tree. */ | |
| 1951 slow ^= 1; | |
| 1952 if (slow == 0) | |
| 1953 slowptr = pdf_dict_get(ctx, slowptr, PDF_NAME(P)); | |
| 1954 if (!pdf_objcmp(ctx, send, slowptr)) | |
| 1955 { | |
| 1956 fz_warn(ctx, "Loop found in structure tree. Ignoring structure."); | |
| 1957 proc->broken_struct_tree = 1; | |
| 1958 return 0; | |
| 1959 } | |
| 1960 } | |
| 1961 | |
| 1962 idx = get_struct_index(ctx, send); | |
| 1963 tag = pdf_dict_get(ctx, send, PDF_NAME(S)); | |
| 1964 standard = pdf_structure_type(ctx, proc->role_map, tag); | |
| 1965 #ifdef DEBUG_STRUCTURE | |
| 1966 fprintf(stderr, "sending %d[idx=%d][tag=%s][std=%d]\n", pdf_to_num(ctx, send), idx, pdf_to_name(ctx, tag) ? pdf_to_name(ctx, tag) : "null", standard); | |
| 1967 #endif | |
| 1968 if (standard != FZ_STRUCTURE_INVALID) | |
| 1969 fz_begin_structure(ctx, proc->dev, standard, pdf_to_name(ctx, tag), idx); | |
| 1970 | |
| 1971 pdf_drop_obj(ctx, proc->mcid_sent); | |
| 1972 proc->mcid_sent = pdf_keep_obj(ctx, send); | |
| 1973 } | |
| 1974 #ifdef DEBUG_STRUCTURE | |
| 1975 structure_dump(ctx, "on exit", proc->mcid_sent); | |
| 1976 #endif | |
| 1977 | |
| 1978 return 1; | |
| 1979 } | |
| 1980 | |
| 1981 static void | |
| 1982 push_marked_content(fz_context *ctx, pdf_run_processor *proc, const char *tagstr, pdf_obj *val) | |
| 1983 { | |
| 1984 pdf_obj *tag; | |
| 1985 marked_content_stack *mc = NULL; | |
| 1986 int drop_tag = 1; | |
| 1987 pdf_obj *mc_dict = NULL; | |
| 1988 | |
| 1989 /* Ignore any pending pops. */ | |
| 1990 proc->pending_mcid_pop = NULL; | |
| 1991 | |
| 1992 /* Flush any pending text so it's not in the wrong layer. */ | |
| 1993 pdf_flush_text(ctx, proc); | |
| 1994 | |
| 1995 if (!tagstr) | |
| 1996 tagstr = "Untitled"; | |
| 1997 tag = pdf_new_name(ctx, tagstr); | |
| 1998 | |
| 1999 fz_var(drop_tag); | |
| 2000 | |
| 2001 fz_try(ctx) | |
| 2002 { | |
| 2003 /* First, push it on the stack. */ | |
| 2004 mc = fz_malloc_struct(ctx, marked_content_stack); | |
| 2005 mc->next = proc->marked_content; | |
| 2006 mc->tag = tag; | |
| 2007 mc->val = pdf_keep_obj(ctx, val); | |
| 2008 mc->structure_pushed = 0; | |
| 2009 proc->marked_content = mc; | |
| 2010 drop_tag = 0; | |
| 2011 | |
| 2012 /* Check to see if val contains an MCID. */ | |
| 2013 mc_dict = lookup_mcid(ctx, proc, val); | |
| 2014 | |
| 2015 /* Start any optional content layers. */ | |
| 2016 if (pdf_name_eq(ctx, tag, PDF_NAME(OC))) | |
| 2017 begin_oc(ctx, proc, val, NULL); | |
| 2018 | |
| 2019 /* Special handling for common non-spec extension. */ | |
| 2020 if (pdf_name_eq(ctx, tag, PDF_NAME(Layer))) | |
| 2021 begin_layer(ctx, proc, val); | |
| 2022 | |
| 2023 /* Structure */ | |
| 2024 if (mc_dict && !proc->broken_struct_tree) | |
| 2025 { | |
| 2026 fz_try(ctx) | |
| 2027 mc->structure_pushed = send_begin_structure(ctx, proc, mc_dict); | |
| 2028 fz_catch(ctx) | |
| 2029 { | |
| 2030 fz_report_error(ctx); | |
| 2031 fz_warn(ctx, "structure tree broken, assume tree is missing"); | |
| 2032 proc->broken_struct_tree = 1; | |
| 2033 } | |
| 2034 } | |
| 2035 | |
| 2036 /* Previously, I'd tried to send stuff like: | |
| 2037 * /Artifact <</Type/Pagination>>BDC | |
| 2038 * as a structure entry, lured by the fact that 'Artifact' is a | |
| 2039 * structure tag. I now believe this is wrong. Only stuff with | |
| 2040 * an MCID pointer should be sent using the structure mechanism. | |
| 2041 */ | |
| 2042 | |
| 2043 /* ActualText */ | |
| 2044 begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ACTUALTEXT, PDF_NAME(ActualText)); | |
| 2045 | |
| 2046 /* Alt */ | |
| 2047 begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ALT, PDF_NAME(Alt)); | |
| 2048 | |
| 2049 /* Abbreviation */ | |
| 2050 begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ABBREVIATION, PDF_NAME(E)); | |
| 2051 | |
| 2052 /* Title */ | |
| 2053 begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_TITLE, PDF_NAME(T)); | |
| 2054 } | |
| 2055 fz_catch(ctx) | |
| 2056 { | |
| 2057 if (drop_tag) | |
| 2058 pdf_drop_obj(ctx, tag); | |
| 2059 fz_rethrow(ctx); | |
| 2060 } | |
| 2061 } | |
| 2062 | |
| 2063 static void | |
| 2064 pop_marked_content(fz_context *ctx, pdf_run_processor *proc, int neat) | |
| 2065 { | |
| 2066 marked_content_stack *mc = proc->marked_content; | |
| 2067 pdf_obj *val, *tag; | |
| 2068 pdf_obj *mc_dict = NULL; | |
| 2069 int pushed; | |
| 2070 | |
| 2071 if (mc == NULL) | |
| 2072 return; | |
| 2073 | |
| 2074 proc->marked_content = mc->next; | |
| 2075 tag = mc->tag; | |
| 2076 val = mc->val; | |
| 2077 pushed = mc->structure_pushed; | |
| 2078 fz_free(ctx, mc); | |
| 2079 | |
| 2080 /* If we're not interested in neatly closing any open layers etc | |
| 2081 * in the processor, (maybe we've had errors already), then just | |
| 2082 * exit here. */ | |
| 2083 if (!neat) | |
| 2084 { | |
| 2085 pdf_drop_obj(ctx, tag); | |
| 2086 pdf_drop_obj(ctx, val); | |
| 2087 return; | |
| 2088 } | |
| 2089 | |
| 2090 /* Close structure/layers here, in reverse order to how we opened them. */ | |
| 2091 fz_try(ctx) | |
| 2092 { | |
| 2093 /* Make sure that any pending text is written into the correct layer. */ | |
| 2094 pdf_flush_text(ctx, proc); | |
| 2095 | |
| 2096 /* Check to see if val contains an MCID. */ | |
| 2097 mc_dict = lookup_mcid(ctx, proc, val); | |
| 2098 | |
| 2099 /* Title */ | |
| 2100 end_metatext(ctx, proc, val, mc_dict, PDF_NAME(T)); | |
| 2101 | |
| 2102 /* Abbreviation */ | |
| 2103 end_metatext(ctx, proc, val, mc_dict, PDF_NAME(E)); | |
| 2104 | |
| 2105 /* Alt */ | |
| 2106 end_metatext(ctx, proc, val, mc_dict, PDF_NAME(Alt)); | |
| 2107 | |
| 2108 /* ActualText */ | |
| 2109 end_metatext(ctx, proc, val, mc_dict, PDF_NAME(ActualText)); | |
| 2110 | |
| 2111 /* Structure */ | |
| 2112 if (mc_dict && !proc->broken_struct_tree && pushed) | |
| 2113 { | |
| 2114 /* Is there a nested mc_dict? If so we want to pop back to that. | |
| 2115 * If not, we want to pop back to the top. | |
| 2116 * proc->marked_content = the previous one, but maybe not the | |
| 2117 * previous one with an mc_dict. So we may need to search further. | |
| 2118 */ | |
| 2119 pdf_obj *previous_mcid = NULL; | |
| 2120 marked_content_stack *mc_with_mcid = proc->marked_content; | |
| 2121 while (mc_with_mcid) | |
| 2122 { | |
| 2123 previous_mcid = lookup_mcid(ctx, proc, mc_with_mcid->val); | |
| 2124 if (previous_mcid != NULL) | |
| 2125 break; | |
| 2126 mc_with_mcid = mc_with_mcid->next; | |
| 2127 } | |
| 2128 | |
| 2129 proc->pending_mcid_pop = previous_mcid; | |
| 2130 } | |
| 2131 | |
| 2132 /* Finally, close any layers. */ | |
| 2133 if (pdf_name_eq(ctx, tag, PDF_NAME(Layer))) | |
| 2134 end_layer(ctx, proc, val); | |
| 2135 | |
| 2136 if (pdf_name_eq(ctx, tag, PDF_NAME(OC))) | |
| 2137 end_oc(ctx, proc, val, NULL); | |
| 2138 } | |
| 2139 fz_always(ctx) | |
| 2140 { | |
| 2141 pdf_drop_obj(ctx, tag); | |
| 2142 pdf_drop_obj(ctx, val); | |
| 2143 } | |
| 2144 fz_catch(ctx) | |
| 2145 fz_rethrow(ctx); | |
| 2146 } | |
| 2147 | |
| 2148 static void | |
| 2149 clear_marked_content(fz_context *ctx, pdf_run_processor *pr) | |
| 2150 { | |
| 2151 if (pr->marked_content == NULL) | |
| 2152 return; | |
| 2153 | |
| 2154 fz_try(ctx) | |
| 2155 while (pr->marked_content) | |
| 2156 pop_marked_content(ctx, pr, 1); | |
| 2157 fz_always(ctx) | |
| 2158 while (pr->marked_content) | |
| 2159 pop_marked_content(ctx, pr, 0); | |
| 2160 fz_catch(ctx) | |
| 2161 fz_rethrow(ctx); | |
| 2162 } | |
| 2163 | |
| 2164 static void | |
| 2165 pdf_run_xobject(fz_context *ctx, pdf_run_processor *pr, pdf_obj *xobj, pdf_obj *page_resources, fz_matrix transform, int is_smask) | |
| 2166 { | |
| 2167 pdf_cycle_list cycle_here; | |
| 2168 pdf_gstate *gstate = NULL; | |
| 2169 int oldtop = 0; | |
| 2170 int oldbot = -1; | |
| 2171 softmask_save softmask = { NULL }; | |
| 2172 int gparent_save; | |
| 2173 fz_matrix gparent_save_ctm; | |
| 2174 pdf_obj *resources; | |
| 2175 fz_rect xobj_bbox; | |
| 2176 fz_matrix xobj_matrix; | |
| 2177 int transparency = 0; | |
| 2178 pdf_document *doc; | |
| 2179 fz_colorspace *cs = NULL; | |
| 2180 fz_default_colorspaces *save_default_cs = NULL; | |
| 2181 fz_default_colorspaces *xobj_default_cs = NULL; | |
| 2182 marked_content_stack *save_marked_content = NULL; | |
| 2183 int save_struct_parent; | |
| 2184 pdf_obj *oc; | |
| 2185 | |
| 2186 /* Avoid infinite recursion */ | |
| 2187 pdf_cycle_list *cycle_up = pr->cycle; | |
| 2188 if (xobj == NULL || pdf_cycle(ctx, &cycle_here, cycle_up, xobj)) | |
| 2189 return; | |
| 2190 pr->cycle = &cycle_here; | |
| 2191 | |
| 2192 pop_any_pending_mcid_changes(ctx, pr); | |
| 2193 flush_begin_layer(ctx, pr); | |
| 2194 | |
| 2195 fz_var(cs); | |
| 2196 fz_var(xobj_default_cs); | |
| 2197 | |
| 2198 gparent_save = pr->gparent; | |
| 2199 pr->gparent = pr->gtop; | |
| 2200 oldtop = pr->gtop; | |
| 2201 | |
| 2202 save_default_cs = pr->default_cs; | |
| 2203 save_marked_content = pr->marked_content; | |
| 2204 pr->marked_content = NULL; | |
| 2205 save_struct_parent = pr->struct_parent; | |
| 2206 | |
| 2207 fz_try(ctx) | |
| 2208 { | |
| 2209 pr->struct_parent = pdf_dict_get_int_default(ctx, xobj, PDF_NAME(StructParent), -1); | |
| 2210 | |
| 2211 oc = pdf_dict_get(ctx, xobj, PDF_NAME(OC)); | |
| 2212 if (oc) | |
| 2213 begin_oc(ctx, pr, oc, NULL); | |
| 2214 | |
| 2215 pdf_gsave(ctx, pr); | |
| 2216 | |
| 2217 gstate = pr->gstate + pr->gtop; | |
| 2218 | |
| 2219 xobj_bbox = pdf_xobject_bbox(ctx, xobj); | |
| 2220 xobj_matrix = pdf_xobject_matrix(ctx, xobj); | |
| 2221 transparency = pdf_xobject_transparency(ctx, xobj); | |
| 2222 | |
| 2223 /* apply xobject's transform matrix */ | |
| 2224 transform = fz_concat(xobj_matrix, transform); | |
| 2225 gstate->ctm = fz_concat(transform, gstate->ctm); | |
| 2226 | |
| 2227 /* The gparent is updated with the modified ctm */ | |
| 2228 gparent_save_ctm = pr->gstate[pr->gparent].ctm; | |
| 2229 pr->gstate[pr->gparent].ctm = gstate->ctm; | |
| 2230 | |
| 2231 /* apply soft mask, create transparency group and reset state */ | |
| 2232 if (transparency) | |
| 2233 { | |
| 2234 int isolated = pdf_xobject_isolated(ctx, xobj); | |
| 2235 | |
| 2236 fz_rect bbox = fz_transform_rect(xobj_bbox, gstate->ctm); | |
| 2237 | |
| 2238 gstate = begin_softmask(ctx, pr, &softmask, bbox); | |
| 2239 | |
| 2240 if (isolated) | |
| 2241 cs = pdf_xobject_colorspace(ctx, xobj); | |
| 2242 fz_begin_group(ctx, pr->dev, bbox, | |
| 2243 cs, | |
| 2244 (is_smask ? 1 : isolated), | |
| 2245 pdf_xobject_knockout(ctx, xobj), | |
| 2246 gstate->blendmode, gstate->fill.alpha); | |
| 2247 | |
| 2248 gstate->blendmode = 0; | |
| 2249 gstate->stroke.alpha = 1; | |
| 2250 gstate->fill.alpha = 1; | |
| 2251 } | |
| 2252 | |
| 2253 pdf_gsave(ctx, pr); /* Save here so the clippath doesn't persist */ | |
| 2254 | |
| 2255 /* clip to the bounds */ | |
| 2256 fz_moveto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y0); | |
| 2257 fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y0); | |
| 2258 fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y1); | |
| 2259 fz_lineto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y1); | |
| 2260 fz_closepath(ctx, pr->path); | |
| 2261 pr->clip = 1; | |
| 2262 pdf_show_path(ctx, pr, 0, 0, 0, 0); | |
| 2263 | |
| 2264 /* run contents */ | |
| 2265 | |
| 2266 resources = pdf_xobject_resources(ctx, xobj); | |
| 2267 if (!resources) | |
| 2268 resources = page_resources; | |
| 2269 | |
| 2270 fz_try(ctx) | |
| 2271 xobj_default_cs = pdf_update_default_colorspaces(ctx, pr->default_cs, resources); | |
| 2272 fz_catch(ctx) | |
| 2273 { | |
| 2274 fz_rethrow_unless(ctx, FZ_ERROR_TRYLATER); | |
| 2275 fz_ignore_error(ctx); | |
| 2276 if (pr->cookie) | |
| 2277 pr->cookie->incomplete = 1; | |
| 2278 } | |
| 2279 if (xobj_default_cs != save_default_cs) | |
| 2280 { | |
| 2281 fz_set_default_colorspaces(ctx, pr->dev, xobj_default_cs); | |
| 2282 pr->default_cs = xobj_default_cs; | |
| 2283 } | |
| 2284 | |
| 2285 doc = pdf_get_bound_document(ctx, xobj); | |
| 2286 | |
| 2287 oldbot = pr->gbot; | |
| 2288 pr->gbot = pr->gtop; | |
| 2289 | |
| 2290 pdf_process_contents(ctx, (pdf_processor*)pr, doc, resources, xobj, pr->cookie, NULL); | |
| 2291 | |
| 2292 /* Undo any gstate mismatches due to the pdf_process_contents call */ | |
| 2293 if (oldbot != -1) | |
| 2294 { | |
| 2295 while (pr->gtop > pr->gbot) | |
| 2296 { | |
| 2297 pdf_grestore(ctx, pr); | |
| 2298 } | |
| 2299 pr->gbot = oldbot; | |
| 2300 } | |
| 2301 | |
| 2302 pdf_grestore(ctx, pr); /* Remove the state we pushed for the clippath */ | |
| 2303 | |
| 2304 /* wrap up transparency stacks */ | |
| 2305 if (transparency) | |
| 2306 { | |
| 2307 fz_end_group(ctx, pr->dev); | |
| 2308 end_softmask(ctx, pr, &softmask); | |
| 2309 } | |
| 2310 | |
| 2311 pr->gstate[pr->gparent].ctm = gparent_save_ctm; | |
| 2312 pr->gparent = gparent_save; | |
| 2313 | |
| 2314 while (oldtop < pr->gtop) | |
| 2315 pdf_grestore(ctx, pr); | |
| 2316 | |
| 2317 if (oc) | |
| 2318 end_oc(ctx, pr, oc, NULL); | |
| 2319 | |
| 2320 if (xobj_default_cs != save_default_cs) | |
| 2321 { | |
| 2322 fz_set_default_colorspaces(ctx, pr->dev, save_default_cs); | |
| 2323 } | |
| 2324 } | |
| 2325 fz_always(ctx) | |
| 2326 { | |
| 2327 clear_marked_content(ctx, pr); | |
| 2328 pr->marked_content = save_marked_content; | |
| 2329 pr->default_cs = save_default_cs; | |
| 2330 fz_drop_default_colorspaces(ctx, xobj_default_cs); | |
| 2331 fz_drop_colorspace(ctx, cs); | |
| 2332 pr->cycle = cycle_up; | |
| 2333 pr->struct_parent = save_struct_parent; | |
| 2334 } | |
| 2335 fz_catch(ctx) | |
| 2336 { | |
| 2337 pdf_drop_obj(ctx, softmask.softmask); | |
| 2338 fz_drop_colorspace(ctx, softmask.softmask_cs); | |
| 2339 pdf_drop_obj(ctx, softmask.page_resources); | |
| 2340 /* Note: Any SYNTAX errors should have been swallowed | |
| 2341 * by pdf_process_contents, but in case any escape from other | |
| 2342 * functions, recast the error type here to be safe. */ | |
| 2343 fz_morph_error(ctx, FZ_ERROR_SYNTAX, FZ_ERROR_FORMAT); | |
| 2344 fz_rethrow(ctx); | |
| 2345 } | |
| 2346 } | |
| 2347 | |
| 2348 /* general graphics state */ | |
| 2349 | |
| 2350 static void pdf_run_w(fz_context *ctx, pdf_processor *proc, float linewidth) | |
| 2351 { | |
| 2352 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2353 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2354 | |
| 2355 pop_any_pending_mcid_changes(ctx, pr); | |
| 2356 flush_begin_layer(ctx, pr); | |
| 2357 | |
| 2358 pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; | |
| 2359 gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); | |
| 2360 gstate->stroke_state->linewidth = linewidth; | |
| 2361 } | |
| 2362 | |
| 2363 static void pdf_run_j(fz_context *ctx, pdf_processor *proc, int linejoin) | |
| 2364 { | |
| 2365 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2366 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2367 | |
| 2368 pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; | |
| 2369 gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); | |
| 2370 gstate->stroke_state->linejoin = linejoin; | |
| 2371 } | |
| 2372 | |
| 2373 static void pdf_run_J(fz_context *ctx, pdf_processor *proc, int linecap) | |
| 2374 { | |
| 2375 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2376 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2377 | |
| 2378 pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); | |
| 2379 gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); | |
| 2380 gstate->stroke_state->start_cap = linecap; | |
| 2381 gstate->stroke_state->dash_cap = linecap; | |
| 2382 gstate->stroke_state->end_cap = linecap; | |
| 2383 } | |
| 2384 | |
| 2385 static void pdf_run_M(fz_context *ctx, pdf_processor *proc, float miterlimit) | |
| 2386 { | |
| 2387 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2388 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2389 | |
| 2390 pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; | |
| 2391 gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); | |
| 2392 gstate->stroke_state->miterlimit = miterlimit; | |
| 2393 } | |
| 2394 | |
| 2395 static void pdf_run_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) | |
| 2396 { | |
| 2397 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2398 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2399 int len, i; | |
| 2400 | |
| 2401 pr->dev->flags &= ~FZ_DEVFLAG_DASH_PATTERN_UNDEFINED; | |
| 2402 len = pdf_array_len(ctx, array); | |
| 2403 gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(ctx, gstate->stroke_state, len); | |
| 2404 for (i = 0; i < len; i++) | |
| 2405 gstate->stroke_state->dash_list[i] = pdf_array_get_real(ctx, array, i); | |
| 2406 gstate->stroke_state->dash_phase = phase; | |
| 2407 } | |
| 2408 | |
| 2409 static void pdf_run_ri(fz_context *ctx, pdf_processor *proc, const char *intent) | |
| 2410 { | |
| 2411 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2412 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2413 gstate->fill.color_params.ri = fz_lookup_rendering_intent(intent); | |
| 2414 gstate->stroke.color_params.ri = gstate->fill.color_params.ri; | |
| 2415 } | |
| 2416 | |
| 2417 static void pdf_run_gs_OP(fz_context *ctx, pdf_processor *proc, int b) | |
| 2418 { | |
| 2419 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2420 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2421 gstate->stroke.color_params.op = b; | |
| 2422 gstate->fill.color_params.op = b; | |
| 2423 } | |
| 2424 | |
| 2425 static void pdf_run_gs_op(fz_context *ctx, pdf_processor *proc, int b) | |
| 2426 { | |
| 2427 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2428 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2429 gstate->fill.color_params.op = b; | |
| 2430 } | |
| 2431 | |
| 2432 static void pdf_run_gs_OPM(fz_context *ctx, pdf_processor *proc, int i) | |
| 2433 { | |
| 2434 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2435 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2436 gstate->stroke.color_params.opm = i; | |
| 2437 gstate->fill.color_params.opm = i; | |
| 2438 } | |
| 2439 | |
| 2440 static void pdf_run_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *obj) | |
| 2441 { | |
| 2442 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2443 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2444 int on = pdf_name_eq(ctx, obj, PDF_NAME(ON)); | |
| 2445 /* The spec says that "ON" means on, "OFF" means "Off", and | |
| 2446 * "Default" or anything else means "Meh, do what you want." */ | |
| 2447 gstate->stroke.color_params.bp = on; | |
| 2448 gstate->fill.color_params.bp = on; | |
| 2449 } | |
| 2450 | |
| 2451 static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness) | |
| 2452 { | |
| 2453 } | |
| 2454 | |
| 2455 static void pdf_run_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) | |
| 2456 { | |
| 2457 } | |
| 2458 | |
| 2459 static void pdf_run_gs_end(fz_context *ctx, pdf_processor *proc) | |
| 2460 { | |
| 2461 } | |
| 2462 | |
| 2463 /* transparency graphics state */ | |
| 2464 | |
| 2465 static void pdf_run_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode) | |
| 2466 { | |
| 2467 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2468 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2469 gstate->blendmode = fz_lookup_blendmode(blendmode); | |
| 2470 } | |
| 2471 | |
| 2472 static void pdf_run_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha) | |
| 2473 { | |
| 2474 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2475 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2476 gstate->stroke.alpha = fz_clamp(alpha, 0, 1); | |
| 2477 } | |
| 2478 | |
| 2479 static void pdf_run_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha) | |
| 2480 { | |
| 2481 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2482 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2483 gstate->fill.alpha = fz_clamp(alpha, 0, 1); | |
| 2484 } | |
| 2485 | |
| 2486 static void pdf_run_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, fz_colorspace *smask_cs, float *bc, int luminosity, pdf_obj *tr) | |
| 2487 { | |
| 2488 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2489 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2490 int i; | |
| 2491 | |
| 2492 if (gstate->softmask) | |
| 2493 { | |
| 2494 pdf_drop_obj(ctx, gstate->softmask); | |
| 2495 gstate->softmask = NULL; | |
| 2496 fz_drop_colorspace(ctx, gstate->softmask_cs); | |
| 2497 gstate->softmask_cs = NULL; | |
| 2498 pdf_drop_obj(ctx, gstate->softmask_resources); | |
| 2499 gstate->softmask_resources = NULL; | |
| 2500 } | |
| 2501 | |
| 2502 if (smask) | |
| 2503 { | |
| 2504 int cs_n = fz_colorspace_n(ctx, smask_cs); | |
| 2505 gstate->softmask_ctm = gstate->ctm; | |
| 2506 gstate->softmask = pdf_keep_obj(ctx, smask); | |
| 2507 gstate->softmask_cs = fz_keep_colorspace(ctx, smask_cs); | |
| 2508 gstate->softmask_resources = pdf_keep_obj(ctx, pr->rstack->resources); | |
| 2509 pdf_drop_obj(ctx, gstate->softmask_tr); | |
| 2510 gstate->softmask_tr = NULL; | |
| 2511 if (tr) | |
| 2512 gstate->softmask_tr = pdf_keep_obj(ctx, tr); | |
| 2513 for (i = 0; i < cs_n; ++i) | |
| 2514 gstate->softmask_bc[i] = bc[i]; | |
| 2515 gstate->luminosity = luminosity; | |
| 2516 } | |
| 2517 } | |
| 2518 | |
| 2519 /* special graphics state */ | |
| 2520 | |
| 2521 static void pdf_run_q(fz_context *ctx, pdf_processor *proc) | |
| 2522 { | |
| 2523 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2524 flush_begin_layer(ctx, pr); | |
| 2525 pdf_gsave(ctx, pr); | |
| 2526 } | |
| 2527 | |
| 2528 static void pdf_run_Q(fz_context *ctx, pdf_processor *proc) | |
| 2529 { | |
| 2530 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2531 pdf_flush_text(ctx, pr); | |
| 2532 pdf_grestore(ctx, pr); | |
| 2533 } | |
| 2534 | |
| 2535 static void pdf_run_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) | |
| 2536 { | |
| 2537 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2538 pdf_gstate *gstate = pdf_flush_text(ctx, pr); | |
| 2539 fz_matrix m; | |
| 2540 | |
| 2541 m.a = a; | |
| 2542 m.b = b; | |
| 2543 m.c = c; | |
| 2544 m.d = d; | |
| 2545 m.e = e; | |
| 2546 m.f = f; | |
| 2547 gstate->ctm = fz_concat(m, gstate->ctm); | |
| 2548 } | |
| 2549 | |
| 2550 /* path construction */ | |
| 2551 | |
| 2552 static void pdf_run_m(fz_context *ctx, pdf_processor *proc, float x, float y) | |
| 2553 { | |
| 2554 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2555 fz_moveto(ctx, pr->path, x, y); | |
| 2556 } | |
| 2557 | |
| 2558 static void pdf_run_l(fz_context *ctx, pdf_processor *proc, float x, float y) | |
| 2559 { | |
| 2560 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2561 fz_lineto(ctx, pr->path, x, y); | |
| 2562 } | |
| 2563 static void pdf_run_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) | |
| 2564 { | |
| 2565 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2566 fz_curveto(ctx, pr->path, x1, y1, x2, y2, x3, y3); | |
| 2567 } | |
| 2568 | |
| 2569 static void pdf_run_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) | |
| 2570 { | |
| 2571 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2572 fz_curvetov(ctx, pr->path, x2, y2, x3, y3); | |
| 2573 } | |
| 2574 | |
| 2575 static void pdf_run_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) | |
| 2576 { | |
| 2577 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2578 fz_curvetoy(ctx, pr->path, x1, y1, x3, y3); | |
| 2579 } | |
| 2580 | |
| 2581 static void pdf_run_h(fz_context *ctx, pdf_processor *proc) | |
| 2582 { | |
| 2583 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2584 fz_closepath(ctx, pr->path); | |
| 2585 } | |
| 2586 | |
| 2587 static void pdf_run_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) | |
| 2588 { | |
| 2589 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2590 fz_rectto(ctx, pr->path, x, y, x+w, y+h); | |
| 2591 } | |
| 2592 | |
| 2593 /* path painting */ | |
| 2594 | |
| 2595 static void pdf_run_S(fz_context *ctx, pdf_processor *proc) | |
| 2596 { | |
| 2597 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2598 pdf_show_path(ctx, pr, 0, 0, 1, 0); | |
| 2599 } | |
| 2600 | |
| 2601 static void pdf_run_s(fz_context *ctx, pdf_processor *proc) | |
| 2602 { | |
| 2603 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2604 pdf_show_path(ctx, pr, 1, 0, 1, 0); | |
| 2605 } | |
| 2606 | |
| 2607 static void pdf_run_F(fz_context *ctx, pdf_processor *proc) | |
| 2608 { | |
| 2609 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2610 pdf_show_path(ctx, pr, 0, 1, 0, 0); | |
| 2611 } | |
| 2612 | |
| 2613 static void pdf_run_f(fz_context *ctx, pdf_processor *proc) | |
| 2614 { | |
| 2615 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2616 pdf_show_path(ctx, pr, 0, 1, 0, 0); | |
| 2617 } | |
| 2618 | |
| 2619 static void pdf_run_fstar(fz_context *ctx, pdf_processor *proc) | |
| 2620 { | |
| 2621 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2622 pdf_show_path(ctx, pr, 0, 1, 0, 1); | |
| 2623 } | |
| 2624 | |
| 2625 static void pdf_run_B(fz_context *ctx, pdf_processor *proc) | |
| 2626 { | |
| 2627 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2628 pdf_show_path(ctx, pr, 0, 1, 1, 0); | |
| 2629 } | |
| 2630 | |
| 2631 static void pdf_run_Bstar(fz_context *ctx, pdf_processor *proc) | |
| 2632 { | |
| 2633 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2634 pdf_show_path(ctx, pr, 0, 1, 1, 1); | |
| 2635 } | |
| 2636 | |
| 2637 static void pdf_run_b(fz_context *ctx, pdf_processor *proc) | |
| 2638 { | |
| 2639 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2640 pdf_show_path(ctx, pr, 1, 1, 1, 0); | |
| 2641 } | |
| 2642 | |
| 2643 static void pdf_run_bstar(fz_context *ctx, pdf_processor *proc) | |
| 2644 { | |
| 2645 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2646 pdf_show_path(ctx, pr, 1, 1, 1, 1); | |
| 2647 } | |
| 2648 | |
| 2649 static void pdf_run_n(fz_context *ctx, pdf_processor *proc) | |
| 2650 { | |
| 2651 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2652 pdf_show_path(ctx, pr, 0, 0, 0, 0); | |
| 2653 } | |
| 2654 | |
| 2655 /* clipping paths */ | |
| 2656 | |
| 2657 static void pdf_run_W(fz_context *ctx, pdf_processor *proc) | |
| 2658 { | |
| 2659 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2660 pdf_flush_text(ctx, pr); | |
| 2661 pr->clip = 1; | |
| 2662 pr->clip_even_odd = 0; | |
| 2663 } | |
| 2664 | |
| 2665 static void pdf_run_Wstar(fz_context *ctx, pdf_processor *proc) | |
| 2666 { | |
| 2667 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2668 pdf_flush_text(ctx, pr); | |
| 2669 pr->clip = 1; | |
| 2670 pr->clip_even_odd = 1; | |
| 2671 } | |
| 2672 | |
| 2673 /* text objects */ | |
| 2674 | |
| 2675 static void pdf_run_BT(fz_context *ctx, pdf_processor *proc) | |
| 2676 { | |
| 2677 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2678 pr->tos.tm = fz_identity; | |
| 2679 pr->tos.tlm = fz_identity; | |
| 2680 pr->bidi = 0; | |
| 2681 } | |
| 2682 | |
| 2683 static void pdf_run_ET(fz_context *ctx, pdf_processor *proc) | |
| 2684 { | |
| 2685 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2686 pdf_flush_text(ctx, pr); | |
| 2687 } | |
| 2688 | |
| 2689 /* text state */ | |
| 2690 | |
| 2691 static void pdf_run_Tc(fz_context *ctx, pdf_processor *proc, float charspace) | |
| 2692 { | |
| 2693 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2694 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2695 gstate->text.char_space = charspace; | |
| 2696 } | |
| 2697 | |
| 2698 static void pdf_run_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) | |
| 2699 { | |
| 2700 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2701 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2702 gstate->text.word_space = wordspace; | |
| 2703 } | |
| 2704 | |
| 2705 static void pdf_run_Tz(fz_context *ctx, pdf_processor *proc, float scale) | |
| 2706 { | |
| 2707 /* scale is as written in the file. It is 100 times smaller in | |
| 2708 * the gstate. */ | |
| 2709 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2710 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2711 gstate->text.scale = scale / 100; | |
| 2712 } | |
| 2713 | |
| 2714 static void pdf_run_TL(fz_context *ctx, pdf_processor *proc, float leading) | |
| 2715 { | |
| 2716 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2717 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2718 gstate->text.leading = leading; | |
| 2719 } | |
| 2720 | |
| 2721 static void pdf_run_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) | |
| 2722 { | |
| 2723 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2724 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2725 pdf_drop_font(ctx, gstate->text.font); | |
| 2726 gstate->text.font = pdf_keep_font(ctx, font); | |
| 2727 gstate->text.size = size; | |
| 2728 } | |
| 2729 | |
| 2730 static void pdf_run_Tr(fz_context *ctx, pdf_processor *proc, int render) | |
| 2731 { | |
| 2732 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2733 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2734 gstate->text.render = render; | |
| 2735 } | |
| 2736 | |
| 2737 static void pdf_run_Ts(fz_context *ctx, pdf_processor *proc, float rise) | |
| 2738 { | |
| 2739 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2740 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2741 gstate->text.rise = rise; | |
| 2742 } | |
| 2743 | |
| 2744 /* text positioning */ | |
| 2745 | |
| 2746 static void pdf_run_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) | |
| 2747 { | |
| 2748 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2749 pdf_tos_translate(&pr->tos, tx, ty); | |
| 2750 } | |
| 2751 | |
| 2752 static void pdf_run_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) | |
| 2753 { | |
| 2754 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2755 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2756 gstate->text.leading = -ty; | |
| 2757 pdf_tos_translate(&pr->tos, tx, ty); | |
| 2758 } | |
| 2759 | |
| 2760 static void pdf_run_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) | |
| 2761 { | |
| 2762 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2763 pdf_tos_set_matrix(&pr->tos, a, b, c, d, e, f); | |
| 2764 } | |
| 2765 | |
| 2766 static void pdf_run_Tstar(fz_context *ctx, pdf_processor *proc) | |
| 2767 { | |
| 2768 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2769 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2770 pdf_tos_newline(&pr->tos, gstate->text.leading); | |
| 2771 } | |
| 2772 | |
| 2773 /* text showing */ | |
| 2774 | |
| 2775 static void pdf_run_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *obj) | |
| 2776 { | |
| 2777 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2778 pdf_show_text(ctx, pr, obj); | |
| 2779 } | |
| 2780 | |
| 2781 static void pdf_run_Tj(fz_context *ctx, pdf_processor *proc, char *string, size_t string_len) | |
| 2782 { | |
| 2783 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2784 pdf_show_string(ctx, pr, (unsigned char *)string, string_len); | |
| 2785 } | |
| 2786 | |
| 2787 static void pdf_run_squote(fz_context *ctx, pdf_processor *proc, char *string, size_t string_len) | |
| 2788 { | |
| 2789 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2790 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2791 pdf_tos_newline(&pr->tos, gstate->text.leading); | |
| 2792 pdf_show_string(ctx, pr, (unsigned char*)string, string_len); | |
| 2793 } | |
| 2794 | |
| 2795 static void pdf_run_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *string, size_t string_len) | |
| 2796 { | |
| 2797 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2798 pdf_gstate *gstate = pr->gstate + pr->gtop; | |
| 2799 gstate->text.word_space = aw; | |
| 2800 gstate->text.char_space = ac; | |
| 2801 pdf_tos_newline(&pr->tos, gstate->text.leading); | |
| 2802 pdf_show_string(ctx, pr, (unsigned char*)string, string_len); | |
| 2803 } | |
| 2804 | |
| 2805 /* type 3 fonts */ | |
| 2806 | |
| 2807 static void pdf_run_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) | |
| 2808 { | |
| 2809 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2810 pr->dev->flags |= FZ_DEVFLAG_COLOR; | |
| 2811 } | |
| 2812 | |
| 2813 static void pdf_run_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) | |
| 2814 { | |
| 2815 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2816 pr->dev->flags |= FZ_DEVFLAG_MASK | FZ_DEVFLAG_BBOX_DEFINED; | |
| 2817 pr->dev->d1_rect.x0 = fz_min(llx, urx); | |
| 2818 pr->dev->d1_rect.y0 = fz_min(lly, ury); | |
| 2819 pr->dev->d1_rect.x1 = fz_max(llx, urx); | |
| 2820 pr->dev->d1_rect.y1 = fz_max(lly, ury); | |
| 2821 } | |
| 2822 | |
| 2823 /* color */ | |
| 2824 | |
| 2825 static void pdf_run_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) | |
| 2826 { | |
| 2827 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2828 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2829 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2830 return; | |
| 2831 if (!strcmp(name, "Pattern")) | |
| 2832 pdf_set_pattern(ctx, pr, PDF_STROKE, NULL, NULL); | |
| 2833 else | |
| 2834 pdf_set_colorspace(ctx, pr, PDF_STROKE, colorspace); | |
| 2835 } | |
| 2836 | |
| 2837 static void pdf_run_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) | |
| 2838 { | |
| 2839 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2840 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2841 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2842 return; | |
| 2843 if (!strcmp(name, "Pattern")) | |
| 2844 pdf_set_pattern(ctx, pr, PDF_FILL, NULL, NULL); | |
| 2845 else | |
| 2846 pdf_set_colorspace(ctx, pr, PDF_FILL, colorspace); | |
| 2847 } | |
| 2848 | |
| 2849 static void pdf_run_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) | |
| 2850 { | |
| 2851 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2852 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2853 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2854 return; | |
| 2855 pdf_set_color(ctx, pr, PDF_STROKE, color); | |
| 2856 } | |
| 2857 | |
| 2858 static void pdf_run_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) | |
| 2859 { | |
| 2860 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2861 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2862 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2863 return; | |
| 2864 pdf_set_color(ctx, pr, PDF_FILL, color); | |
| 2865 } | |
| 2866 | |
| 2867 static void pdf_run_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) | |
| 2868 { | |
| 2869 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2870 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2871 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2872 return; | |
| 2873 pdf_set_pattern(ctx, pr, PDF_STROKE, pat, color); | |
| 2874 } | |
| 2875 | |
| 2876 static void pdf_run_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) | |
| 2877 { | |
| 2878 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2879 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2880 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2881 return; | |
| 2882 pdf_set_pattern(ctx, pr, PDF_FILL, pat, color); | |
| 2883 } | |
| 2884 | |
| 2885 static void pdf_run_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) | |
| 2886 { | |
| 2887 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2888 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2889 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2890 return; | |
| 2891 pdf_set_shade(ctx, pr, PDF_STROKE, shade); | |
| 2892 } | |
| 2893 | |
| 2894 static void pdf_run_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) | |
| 2895 { | |
| 2896 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2897 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2898 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2899 return; | |
| 2900 pdf_set_shade(ctx, pr, PDF_FILL, shade); | |
| 2901 } | |
| 2902 | |
| 2903 static void pdf_run_G(fz_context *ctx, pdf_processor *proc, float g) | |
| 2904 { | |
| 2905 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2906 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2907 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2908 return; | |
| 2909 pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_gray(ctx)); | |
| 2910 pdf_set_color(ctx, pr, PDF_STROKE, &g); | |
| 2911 } | |
| 2912 | |
| 2913 static void pdf_run_g(fz_context *ctx, pdf_processor *proc, float g) | |
| 2914 { | |
| 2915 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2916 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2917 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2918 return; | |
| 2919 pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_gray(ctx)); | |
| 2920 pdf_set_color(ctx, pr, PDF_FILL, &g); | |
| 2921 } | |
| 2922 | |
| 2923 static void pdf_run_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) | |
| 2924 { | |
| 2925 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2926 float color[4] = {c, m, y, k}; | |
| 2927 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2928 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2929 return; | |
| 2930 pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_cmyk(ctx)); | |
| 2931 pdf_set_color(ctx, pr, PDF_STROKE, color); | |
| 2932 } | |
| 2933 | |
| 2934 static void pdf_run_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) | |
| 2935 { | |
| 2936 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2937 float color[4] = {c, m, y, k}; | |
| 2938 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2939 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2940 return; | |
| 2941 pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_cmyk(ctx)); | |
| 2942 pdf_set_color(ctx, pr, PDF_FILL, color); | |
| 2943 } | |
| 2944 | |
| 2945 static void pdf_run_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) | |
| 2946 { | |
| 2947 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2948 float color[3] = {r, g, b}; | |
| 2949 pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; | |
| 2950 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2951 return; | |
| 2952 pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_rgb(ctx)); | |
| 2953 pdf_set_color(ctx, pr, PDF_STROKE, color); | |
| 2954 } | |
| 2955 | |
| 2956 static void pdf_run_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) | |
| 2957 { | |
| 2958 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2959 float color[3] = {r, g, b}; | |
| 2960 pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; | |
| 2961 if (pr->dev->flags & FZ_DEVFLAG_MASK) | |
| 2962 return; | |
| 2963 pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_rgb(ctx)); | |
| 2964 pdf_set_color(ctx, pr, PDF_FILL, color); | |
| 2965 } | |
| 2966 | |
| 2967 /* shadings, images, xobjects */ | |
| 2968 | |
| 2969 static void pdf_run_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace) | |
| 2970 { | |
| 2971 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2972 pdf_show_image(ctx, pr, image); | |
| 2973 } | |
| 2974 | |
| 2975 static void pdf_run_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) | |
| 2976 { | |
| 2977 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2978 | |
| 2979 pop_any_pending_mcid_changes(ctx, pr); | |
| 2980 flush_begin_layer(ctx, pr); | |
| 2981 pdf_show_shade(ctx, pr, shade); | |
| 2982 } | |
| 2983 | |
| 2984 static void pdf_run_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) | |
| 2985 { | |
| 2986 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2987 pdf_show_image(ctx, pr, image); | |
| 2988 } | |
| 2989 | |
| 2990 static void pdf_run_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj) | |
| 2991 { | |
| 2992 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 2993 pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, pr->rstack->resources, fz_identity, 0); | |
| 2994 } | |
| 2995 | |
| 2996 /* marked content */ | |
| 2997 | |
| 2998 static void pdf_run_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) | |
| 2999 { | |
| 3000 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3001 push_marked_content(ctx, pr, tag, NULL); | |
| 3002 } | |
| 3003 | |
| 3004 static void pdf_run_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) | |
| 3005 { | |
| 3006 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3007 push_marked_content(ctx, pr, tag, cooked); | |
| 3008 } | |
| 3009 | |
| 3010 static void pdf_run_EMC(fz_context *ctx, pdf_processor *proc) | |
| 3011 { | |
| 3012 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3013 | |
| 3014 pop_marked_content(ctx, pr, 1); | |
| 3015 } | |
| 3016 | |
| 3017 static void pdf_run_MP(fz_context *ctx, pdf_processor *proc, const char *tag) | |
| 3018 { | |
| 3019 pdf_run_BMC(ctx, proc, tag); | |
| 3020 pdf_run_EMC(ctx, proc); | |
| 3021 } | |
| 3022 | |
| 3023 static void pdf_run_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) | |
| 3024 { | |
| 3025 pdf_run_BDC(ctx, proc, tag, raw, cooked); | |
| 3026 pdf_run_EMC(ctx, proc); | |
| 3027 } | |
| 3028 | |
| 3029 /* compatibility */ | |
| 3030 | |
| 3031 static void pdf_run_BX(fz_context *ctx, pdf_processor *proc) | |
| 3032 { | |
| 3033 } | |
| 3034 | |
| 3035 static void pdf_run_EX(fz_context *ctx, pdf_processor *proc) | |
| 3036 { | |
| 3037 } | |
| 3038 | |
| 3039 static void pdf_run_END(fz_context *ctx, pdf_processor *proc) | |
| 3040 { | |
| 3041 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3042 pdf_flush_text(ctx, pr); | |
| 3043 } | |
| 3044 | |
| 3045 static void | |
| 3046 pdf_close_run_processor(fz_context *ctx, pdf_processor *proc) | |
| 3047 { | |
| 3048 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3049 | |
| 3050 while (pr->gtop) | |
| 3051 pdf_grestore(ctx, pr); | |
| 3052 | |
| 3053 while (pr->nest_depth > 0) | |
| 3054 { | |
| 3055 if (pr->nest_mark[pr->nest_depth-1] < 0) | |
| 3056 { | |
| 3057 /* It's a clip. */ | |
| 3058 fz_pop_clip(ctx, pr->dev); | |
| 3059 pr->nest_mark[pr->nest_depth-1]++; | |
| 3060 if (pr->nest_mark[pr->nest_depth-1] == 0) | |
| 3061 pr->nest_depth--; | |
| 3062 } | |
| 3063 else | |
| 3064 { | |
| 3065 /* It's a layer. */ | |
| 3066 fz_end_layer(ctx, pr->dev); | |
| 3067 pr->nest_depth--; | |
| 3068 } | |
| 3069 } | |
| 3070 | |
| 3071 pop_structure_to(ctx, pr, NULL); | |
| 3072 | |
| 3073 clear_marked_content(ctx, pr); | |
| 3074 } | |
| 3075 | |
| 3076 static void | |
| 3077 pdf_drop_run_processor(fz_context *ctx, pdf_processor *proc) | |
| 3078 { | |
| 3079 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3080 | |
| 3081 while (pr->gtop >= 0) | |
| 3082 { | |
| 3083 pdf_drop_gstate(ctx, &pr->gstate[pr->gtop]); | |
| 3084 pr->gtop--; | |
| 3085 } | |
| 3086 | |
| 3087 fz_drop_path(ctx, pr->path); | |
| 3088 fz_drop_text(ctx, pr->tos.text); | |
| 3089 | |
| 3090 fz_drop_default_colorspaces(ctx, pr->default_cs); | |
| 3091 | |
| 3092 fz_free(ctx, pr->gstate); | |
| 3093 | |
| 3094 while (pr->rstack) | |
| 3095 { | |
| 3096 resources_stack *stk = pr->rstack; | |
| 3097 pr->rstack = stk->next; | |
| 3098 pdf_drop_obj(ctx, stk->resources); | |
| 3099 fz_free(ctx, stk); | |
| 3100 } | |
| 3101 | |
| 3102 while (pr->begin_layer) | |
| 3103 { | |
| 3104 begin_layer_stack *stk = pr->begin_layer; | |
| 3105 pr->begin_layer = stk->next; | |
| 3106 fz_free(ctx, stk->layer); | |
| 3107 fz_free(ctx, stk); | |
| 3108 } | |
| 3109 | |
| 3110 while (pr->marked_content) | |
| 3111 pop_marked_content(ctx, pr, 0); | |
| 3112 | |
| 3113 pdf_drop_obj(ctx, pr->mcid_sent); | |
| 3114 | |
| 3115 pdf_drop_document(ctx, pr->doc); | |
| 3116 pdf_drop_obj(ctx, pr->role_map); | |
| 3117 } | |
| 3118 | |
| 3119 static void | |
| 3120 pdf_run_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *resources) | |
| 3121 { | |
| 3122 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3123 resources_stack *stk = fz_malloc_struct(ctx, resources_stack); | |
| 3124 | |
| 3125 stk->next = pr->rstack; | |
| 3126 pr->rstack = stk; | |
| 3127 stk->resources = pdf_keep_obj(ctx, resources); | |
| 3128 } | |
| 3129 | |
| 3130 static pdf_obj * | |
| 3131 pdf_run_pop_resources(fz_context *ctx, pdf_processor *proc) | |
| 3132 { | |
| 3133 pdf_run_processor *pr = (pdf_run_processor *)proc; | |
| 3134 resources_stack *stk = pr->rstack; | |
| 3135 | |
| 3136 if (stk) | |
| 3137 { | |
| 3138 pr->rstack = stk->next; | |
| 3139 pdf_drop_obj(ctx, stk->resources); | |
| 3140 fz_free(ctx, stk); | |
| 3141 } | |
| 3142 | |
| 3143 return NULL; | |
| 3144 } | |
| 3145 | |
| 3146 /* | |
| 3147 Create a new "run" processor. This maps | |
| 3148 from PDF operators to fz_device level calls. | |
| 3149 | |
| 3150 dev: The device to which the resulting device calls are to be | |
| 3151 sent. | |
| 3152 | |
| 3153 ctm: The initial transformation matrix to use. | |
| 3154 | |
| 3155 usage: A NULL terminated string that describes the 'usage' of | |
| 3156 this interpretation. Typically 'View', though 'Print' is also | |
| 3157 defined within the PDF reference manual, and others are possible. | |
| 3158 | |
| 3159 gstate: The initial graphics state. | |
| 3160 */ | |
| 3161 pdf_processor * | |
| 3162 pdf_new_run_processor(fz_context *ctx, pdf_document *doc, fz_device *dev, fz_matrix ctm, int struct_parent, const char *usage, pdf_gstate *gstate, fz_default_colorspaces *default_cs, fz_cookie *cookie, pdf_gstate *fill_gstate, pdf_gstate *stroke_gstate) | |
| 3163 { | |
| 3164 pdf_run_processor *proc = pdf_new_processor(ctx, sizeof *proc); | |
| 3165 { | |
| 3166 proc->super.usage = usage; | |
| 3167 | |
| 3168 proc->super.close_processor = pdf_close_run_processor; | |
| 3169 proc->super.drop_processor = pdf_drop_run_processor; | |
| 3170 | |
| 3171 proc->super.push_resources = pdf_run_push_resources; | |
| 3172 proc->super.pop_resources = pdf_run_pop_resources; | |
| 3173 | |
| 3174 /* general graphics state */ | |
| 3175 proc->super.op_w = pdf_run_w; | |
| 3176 proc->super.op_j = pdf_run_j; | |
| 3177 proc->super.op_J = pdf_run_J; | |
| 3178 proc->super.op_M = pdf_run_M; | |
| 3179 proc->super.op_d = pdf_run_d; | |
| 3180 proc->super.op_ri = pdf_run_ri; | |
| 3181 proc->super.op_i = pdf_run_i; | |
| 3182 proc->super.op_gs_begin = pdf_run_gs_begin; | |
| 3183 proc->super.op_gs_end = pdf_run_gs_end; | |
| 3184 | |
| 3185 /* transparency graphics state */ | |
| 3186 proc->super.op_gs_BM = pdf_run_gs_BM; | |
| 3187 proc->super.op_gs_CA = pdf_run_gs_CA; | |
| 3188 proc->super.op_gs_ca = pdf_run_gs_ca; | |
| 3189 proc->super.op_gs_SMask = pdf_run_gs_SMask; | |
| 3190 | |
| 3191 /* special graphics state */ | |
| 3192 proc->super.op_q = pdf_run_q; | |
| 3193 proc->super.op_Q = pdf_run_Q; | |
| 3194 proc->super.op_cm = pdf_run_cm; | |
| 3195 | |
| 3196 /* path construction */ | |
| 3197 proc->super.op_m = pdf_run_m; | |
| 3198 proc->super.op_l = pdf_run_l; | |
| 3199 proc->super.op_c = pdf_run_c; | |
| 3200 proc->super.op_v = pdf_run_v; | |
| 3201 proc->super.op_y = pdf_run_y; | |
| 3202 proc->super.op_h = pdf_run_h; | |
| 3203 proc->super.op_re = pdf_run_re; | |
| 3204 | |
| 3205 /* path painting */ | |
| 3206 proc->super.op_S = pdf_run_S; | |
| 3207 proc->super.op_s = pdf_run_s; | |
| 3208 proc->super.op_F = pdf_run_F; | |
| 3209 proc->super.op_f = pdf_run_f; | |
| 3210 proc->super.op_fstar = pdf_run_fstar; | |
| 3211 proc->super.op_B = pdf_run_B; | |
| 3212 proc->super.op_Bstar = pdf_run_Bstar; | |
| 3213 proc->super.op_b = pdf_run_b; | |
| 3214 proc->super.op_bstar = pdf_run_bstar; | |
| 3215 proc->super.op_n = pdf_run_n; | |
| 3216 | |
| 3217 /* clipping paths */ | |
| 3218 proc->super.op_W = pdf_run_W; | |
| 3219 proc->super.op_Wstar = pdf_run_Wstar; | |
| 3220 | |
| 3221 /* text objects */ | |
| 3222 proc->super.op_BT = pdf_run_BT; | |
| 3223 proc->super.op_ET = pdf_run_ET; | |
| 3224 | |
| 3225 /* text state */ | |
| 3226 proc->super.op_Tc = pdf_run_Tc; | |
| 3227 proc->super.op_Tw = pdf_run_Tw; | |
| 3228 proc->super.op_Tz = pdf_run_Tz; | |
| 3229 proc->super.op_TL = pdf_run_TL; | |
| 3230 proc->super.op_Tf = pdf_run_Tf; | |
| 3231 proc->super.op_Tr = pdf_run_Tr; | |
| 3232 proc->super.op_Ts = pdf_run_Ts; | |
| 3233 | |
| 3234 /* text positioning */ | |
| 3235 proc->super.op_Td = pdf_run_Td; | |
| 3236 proc->super.op_TD = pdf_run_TD; | |
| 3237 proc->super.op_Tm = pdf_run_Tm; | |
| 3238 proc->super.op_Tstar = pdf_run_Tstar; | |
| 3239 | |
| 3240 /* text showing */ | |
| 3241 proc->super.op_TJ = pdf_run_TJ; | |
| 3242 proc->super.op_Tj = pdf_run_Tj; | |
| 3243 proc->super.op_squote = pdf_run_squote; | |
| 3244 proc->super.op_dquote = pdf_run_dquote; | |
| 3245 | |
| 3246 /* type 3 fonts */ | |
| 3247 proc->super.op_d0 = pdf_run_d0; | |
| 3248 proc->super.op_d1 = pdf_run_d1; | |
| 3249 | |
| 3250 /* color */ | |
| 3251 proc->super.op_CS = pdf_run_CS; | |
| 3252 proc->super.op_cs = pdf_run_cs; | |
| 3253 proc->super.op_SC_color = pdf_run_SC_color; | |
| 3254 proc->super.op_sc_color = pdf_run_sc_color; | |
| 3255 proc->super.op_SC_pattern = pdf_run_SC_pattern; | |
| 3256 proc->super.op_sc_pattern = pdf_run_sc_pattern; | |
| 3257 proc->super.op_SC_shade = pdf_run_SC_shade; | |
| 3258 proc->super.op_sc_shade = pdf_run_sc_shade; | |
| 3259 | |
| 3260 proc->super.op_G = pdf_run_G; | |
| 3261 proc->super.op_g = pdf_run_g; | |
| 3262 proc->super.op_RG = pdf_run_RG; | |
| 3263 proc->super.op_rg = pdf_run_rg; | |
| 3264 proc->super.op_K = pdf_run_K; | |
| 3265 proc->super.op_k = pdf_run_k; | |
| 3266 | |
| 3267 /* shadings, images, xobjects */ | |
| 3268 proc->super.op_sh = pdf_run_sh; | |
| 3269 if (dev->fill_image || dev->fill_image_mask || dev->clip_image_mask) | |
| 3270 { | |
| 3271 proc->super.op_BI = pdf_run_BI; | |
| 3272 proc->super.op_Do_image = pdf_run_Do_image; | |
| 3273 } | |
| 3274 proc->super.op_Do_form = pdf_run_Do_form; | |
| 3275 | |
| 3276 /* marked content */ | |
| 3277 proc->super.op_MP = pdf_run_MP; | |
| 3278 proc->super.op_DP = pdf_run_DP; | |
| 3279 proc->super.op_BMC = pdf_run_BMC; | |
| 3280 proc->super.op_BDC = pdf_run_BDC; | |
| 3281 proc->super.op_EMC = pdf_run_EMC; | |
| 3282 | |
| 3283 /* compatibility */ | |
| 3284 proc->super.op_BX = pdf_run_BX; | |
| 3285 proc->super.op_EX = pdf_run_EX; | |
| 3286 | |
| 3287 /* extgstate */ | |
| 3288 proc->super.op_gs_OP = pdf_run_gs_OP; | |
| 3289 proc->super.op_gs_op = pdf_run_gs_op; | |
| 3290 proc->super.op_gs_OPM = pdf_run_gs_OPM; | |
| 3291 proc->super.op_gs_UseBlackPtComp = pdf_run_gs_UseBlackPtComp; | |
| 3292 | |
| 3293 proc->super.op_END = pdf_run_END; | |
| 3294 } | |
| 3295 | |
| 3296 proc->super.requirements = 0; | |
| 3297 if ((dev->hints & FZ_DONT_DECODE_IMAGES) == 0) | |
| 3298 proc->super.requirements |= PDF_PROCESSOR_REQUIRES_DECODED_IMAGES; | |
| 3299 | |
| 3300 proc->doc = pdf_keep_document(ctx, doc); | |
| 3301 proc->dev = dev; | |
| 3302 proc->cookie = cookie; | |
| 3303 | |
| 3304 proc->default_cs = fz_keep_default_colorspaces(ctx, default_cs); | |
| 3305 | |
| 3306 proc->path = NULL; | |
| 3307 proc->clip = 0; | |
| 3308 proc->clip_even_odd = 0; | |
| 3309 | |
| 3310 proc->tos.text = NULL; | |
| 3311 proc->tos.tlm = fz_identity; | |
| 3312 proc->tos.tm = fz_identity; | |
| 3313 proc->tos.text_mode = 0; | |
| 3314 | |
| 3315 proc->gtop = -1; | |
| 3316 | |
| 3317 proc->marked_content = NULL; | |
| 3318 | |
| 3319 proc->next_begin_layer = &proc->begin_layer; | |
| 3320 | |
| 3321 fz_try(ctx) | |
| 3322 { | |
| 3323 proc->path = fz_new_path(ctx); | |
| 3324 | |
| 3325 proc->gcap = 64; | |
| 3326 proc->gstate = fz_malloc_struct_array(ctx, proc->gcap, pdf_gstate); | |
| 3327 | |
| 3328 proc->gtop = 0; | |
| 3329 pdf_init_gstate(ctx, &proc->gstate[0], ctm); | |
| 3330 | |
| 3331 if (fill_gstate) | |
| 3332 { | |
| 3333 pdf_copy_gstate(ctx, &proc->gstate[0], fill_gstate); | |
| 3334 proc->gstate[0].clip_depth = 0; | |
| 3335 proc->gtop++; | |
| 3336 } | |
| 3337 if (stroke_gstate) | |
| 3338 { | |
| 3339 pdf_copy_gstate(ctx, &proc->gstate[proc->gtop], stroke_gstate); | |
| 3340 proc->gstate[proc->gtop].clip_depth = 0; | |
| 3341 proc->gtop++; | |
| 3342 } | |
| 3343 if (gstate) | |
| 3344 { | |
| 3345 pdf_copy_gstate(ctx, &proc->gstate[proc->gtop], gstate); | |
| 3346 proc->gstate[proc->gtop].clip_depth = 0; | |
| 3347 proc->gstate[proc->gtop].ctm = ctm; | |
| 3348 } | |
| 3349 proc->gparent = proc->gtop; | |
| 3350 if (fill_gstate) | |
| 3351 proc->gstate[proc->gtop].fill.gstate_num = 0; | |
| 3352 if (stroke_gstate) | |
| 3353 proc->gstate[proc->gtop].fill.gstate_num = (fill_gstate != NULL); | |
| 3354 | |
| 3355 /* We need to save an extra level to allow for the parent gstate level. */ | |
| 3356 pdf_gsave(ctx, proc); | |
| 3357 | |
| 3358 /* Structure details */ | |
| 3359 { | |
| 3360 pdf_obj *struct_tree_root = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), NULL); | |
| 3361 proc->struct_parent = struct_parent; | |
| 3362 proc->role_map = pdf_keep_obj(ctx, pdf_dict_get(ctx, struct_tree_root, PDF_NAME(RoleMap))); | |
| 3363 | |
| 3364 /* Annotations and XObjects can be their own content items. We spot this by | |
| 3365 * the struct_parent looking up to be a singular object. */ | |
| 3366 if (struct_parent != -1 && struct_tree_root) | |
| 3367 { | |
| 3368 pdf_obj *struct_obj = pdf_lookup_number(ctx, pdf_dict_get(ctx, struct_tree_root, PDF_NAME(ParentTree)), struct_parent); | |
| 3369 if (pdf_is_dict(ctx, struct_obj)) | |
| 3370 send_begin_structure(ctx, proc, struct_obj); | |
| 3371 /* We always end structure as required on closedown, so this is safe. */ | |
| 3372 } | |
| 3373 } | |
| 3374 } | |
| 3375 fz_catch(ctx) | |
| 3376 { | |
| 3377 pdf_drop_run_processor(ctx, (pdf_processor *) proc); | |
| 3378 fz_free(ctx, proc); | |
| 3379 fz_rethrow(ctx); | |
| 3380 } | |
| 3381 | |
| 3382 return (pdf_processor*)proc; | |
| 3383 } |
