| 1 | #include "mupdf/fitz.h" |
| 2 | #include "mupdf/pdf.h" |
| 3 | |
| 4 | #include <string.h> |
| 5 | #include <math.h> |
| 6 | |
| 7 | #define TILE |
| 8 | |
| 9 | /* |
| 10 | * Emit graphics calls to device. |
| 11 | */ |
| 12 | |
| 13 | typedef struct pdf_material_s pdf_material; |
| 14 | typedef struct pdf_run_processor_s pdf_run_processor; |
| 15 | |
| 16 | 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); |
| 17 | |
| 18 | enum |
| 19 | { |
| 20 | PDF_FILL, |
| 21 | PDF_STROKE, |
| 22 | }; |
| 23 | |
| 24 | enum |
| 25 | { |
| 26 | PDF_MAT_NONE, |
| 27 | PDF_MAT_COLOR, |
| 28 | PDF_MAT_PATTERN, |
| 29 | PDF_MAT_SHADE, |
| 30 | }; |
| 31 | |
| 32 | struct pdf_material_s |
| 33 | { |
| 34 | int kind; |
| 35 | fz_colorspace *colorspace; |
| 36 | pdf_pattern *pattern; |
| 37 | fz_shade *shade; |
| 38 | int gstate_num; |
| 39 | fz_color_params color_params; |
| 40 | float alpha; |
| 41 | float v[FZ_MAX_COLORS]; |
| 42 | }; |
| 43 | |
| 44 | struct pdf_gstate_s |
| 45 | { |
| 46 | fz_matrix ctm; |
| 47 | int clip_depth; |
| 48 | |
| 49 | /* path stroking */ |
| 50 | fz_stroke_state *stroke_state; |
| 51 | |
| 52 | /* materials */ |
| 53 | pdf_material stroke; |
| 54 | pdf_material fill; |
| 55 | |
| 56 | /* text state */ |
| 57 | pdf_text_state text; |
| 58 | |
| 59 | /* transparency */ |
| 60 | int blendmode; |
| 61 | pdf_obj *softmask; |
| 62 | pdf_obj *softmask_resources; |
| 63 | fz_matrix softmask_ctm; |
| 64 | float softmask_bc[FZ_MAX_COLORS]; |
| 65 | int luminosity; |
| 66 | }; |
| 67 | |
| 68 | struct pdf_run_processor_s |
| 69 | { |
| 70 | pdf_processor super; |
| 71 | fz_device *dev; |
| 72 | fz_cookie *cookie; |
| 73 | |
| 74 | fz_default_colorspaces *default_cs; |
| 75 | |
| 76 | /* path object state */ |
| 77 | fz_path *path; |
| 78 | int clip; |
| 79 | int clip_even_odd; |
| 80 | |
| 81 | /* text object state */ |
| 82 | pdf_text_object_state tos; |
| 83 | |
| 84 | /* graphics state */ |
| 85 | pdf_gstate *gstate; |
| 86 | int gcap; |
| 87 | int gtop; |
| 88 | int gbot; |
| 89 | int gparent; |
| 90 | }; |
| 91 | |
| 92 | typedef struct softmask_save_s softmask_save; |
| 93 | |
| 94 | struct softmask_save_s |
| 95 | { |
| 96 | pdf_obj *softmask; |
| 97 | pdf_obj *page_resources; |
| 98 | fz_matrix ctm; |
| 99 | }; |
| 100 | |
| 101 | static pdf_gstate * |
| 102 | begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save) |
| 103 | { |
| 104 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 105 | pdf_obj *softmask = gstate->softmask; |
| 106 | fz_rect mask_bbox; |
| 107 | fz_matrix tos_save[2], save_ctm; |
| 108 | fz_matrix mask_matrix; |
| 109 | fz_colorspace *mask_colorspace; |
| 110 | int saved_blendmode; |
| 111 | |
| 112 | save->softmask = softmask; |
| 113 | if (softmask == NULL) |
| 114 | return gstate; |
| 115 | save->page_resources = gstate->softmask_resources; |
| 116 | save->ctm = gstate->softmask_ctm; |
| 117 | save_ctm = gstate->ctm; |
| 118 | |
| 119 | mask_bbox = pdf_xobject_bbox(ctx, softmask); |
| 120 | mask_matrix = pdf_xobject_matrix(ctx, softmask); |
| 121 | |
| 122 | pdf_tos_save(ctx, &pr->tos, tos_save); |
| 123 | |
| 124 | if (gstate->luminosity) |
| 125 | mask_bbox = fz_infinite_rect; |
| 126 | else |
| 127 | { |
| 128 | mask_bbox = fz_transform_rect(mask_bbox, mask_matrix); |
| 129 | mask_bbox = fz_transform_rect(mask_bbox, gstate->softmask_ctm); |
| 130 | } |
| 131 | gstate->softmask = NULL; |
| 132 | gstate->softmask_resources = NULL; |
| 133 | gstate->ctm = gstate->softmask_ctm; |
| 134 | |
| 135 | saved_blendmode = gstate->blendmode; |
| 136 | |
| 137 | mask_colorspace = pdf_xobject_colorspace(ctx, softmask); |
| 138 | if (gstate->luminosity && !mask_colorspace) |
| 139 | mask_colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
| 140 | |
| 141 | fz_try(ctx) |
| 142 | { |
| 143 | fz_begin_mask(ctx, pr->dev, mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc, gstate->fill.color_params); |
| 144 | gstate->blendmode = 0; |
| 145 | pdf_run_xobject(ctx, pr, softmask, save->page_resources, fz_identity, 1); |
| 146 | gstate = pr->gstate + pr->gtop; |
| 147 | gstate->blendmode = saved_blendmode; |
| 148 | fz_end_mask(ctx, pr->dev); |
| 149 | } |
| 150 | fz_always(ctx) |
| 151 | fz_drop_colorspace(ctx, mask_colorspace); |
| 152 | fz_catch(ctx) |
| 153 | fz_rethrow(ctx); |
| 154 | |
| 155 | pdf_tos_restore(ctx, &pr->tos, tos_save); |
| 156 | |
| 157 | gstate = pr->gstate + pr->gtop; |
| 158 | gstate->ctm = save_ctm; |
| 159 | |
| 160 | return gstate; |
| 161 | } |
| 162 | |
| 163 | static void |
| 164 | end_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save) |
| 165 | { |
| 166 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 167 | |
| 168 | if (save->softmask == NULL) |
| 169 | return; |
| 170 | |
| 171 | gstate->softmask = save->softmask; |
| 172 | gstate->softmask_resources = save->page_resources; |
| 173 | gstate->softmask_ctm = save->ctm; |
| 174 | save->softmask = NULL; |
| 175 | save->page_resources = NULL; |
| 176 | |
| 177 | fz_pop_clip(ctx, pr->dev); |
| 178 | } |
| 179 | |
| 180 | static pdf_gstate * |
| 181 | pdf_begin_group(fz_context *ctx, pdf_run_processor *pr, fz_rect bbox, softmask_save *softmask) |
| 182 | { |
| 183 | pdf_gstate *gstate = begin_softmask(ctx, pr, softmask); |
| 184 | |
| 185 | if (gstate->blendmode) |
| 186 | fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1); |
| 187 | |
| 188 | return pr->gstate + pr->gtop; |
| 189 | } |
| 190 | |
| 191 | static void |
| 192 | pdf_end_group(fz_context *ctx, pdf_run_processor *pr, softmask_save *softmask) |
| 193 | { |
| 194 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 195 | |
| 196 | if (gstate->blendmode) |
| 197 | fz_end_group(ctx, pr->dev); |
| 198 | |
| 199 | end_softmask(ctx, pr, softmask); |
| 200 | } |
| 201 | |
| 202 | static void |
| 203 | pdf_show_shade(fz_context *ctx, pdf_run_processor *pr, fz_shade *shd) |
| 204 | { |
| 205 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 206 | fz_rect bbox; |
| 207 | softmask_save softmask = { NULL }; |
| 208 | |
| 209 | if (pr->super.hidden) |
| 210 | return; |
| 211 | |
| 212 | bbox = fz_bound_shade(ctx, shd, gstate->ctm); |
| 213 | |
| 214 | gstate = pdf_begin_group(ctx, pr, bbox, &softmask); |
| 215 | |
| 216 | /* FIXME: The gstate->ctm in the next line may be wrong; maybe |
| 217 | * it should be the parent gstates ctm? */ |
| 218 | fz_fill_shade(ctx, pr->dev, shd, gstate->ctm, gstate->fill.alpha, gstate->fill.color_params); |
| 219 | |
| 220 | pdf_end_group(ctx, pr, &softmask); |
| 221 | } |
| 222 | |
| 223 | static pdf_material * |
| 224 | pdf_keep_material(fz_context *ctx, pdf_material *mat) |
| 225 | { |
| 226 | if (mat->colorspace) |
| 227 | fz_keep_colorspace(ctx, mat->colorspace); |
| 228 | if (mat->pattern) |
| 229 | pdf_keep_pattern(ctx, mat->pattern); |
| 230 | if (mat->shade) |
| 231 | fz_keep_shade(ctx, mat->shade); |
| 232 | return mat; |
| 233 | } |
| 234 | |
| 235 | static pdf_material * |
| 236 | pdf_drop_material(fz_context *ctx, pdf_material *mat) |
| 237 | { |
| 238 | fz_drop_colorspace(ctx, mat->colorspace); |
| 239 | pdf_drop_pattern(ctx, mat->pattern); |
| 240 | fz_drop_shade(ctx, mat->shade); |
| 241 | return mat; |
| 242 | } |
| 243 | |
| 244 | static void |
| 245 | pdf_copy_pattern_gstate(fz_context *ctx, pdf_gstate *dst, const pdf_gstate *src) |
| 246 | { |
| 247 | dst->ctm = src->ctm; |
| 248 | |
| 249 | pdf_drop_font(ctx, dst->text.font); |
| 250 | dst->text.font = pdf_keep_font(ctx, src->text.font); |
| 251 | |
| 252 | pdf_drop_obj(ctx, dst->softmask); |
| 253 | dst->softmask = pdf_keep_obj(ctx, src->softmask); |
| 254 | |
| 255 | fz_drop_stroke_state(ctx, dst->stroke_state); |
| 256 | dst->stroke_state = fz_keep_stroke_state(ctx, src->stroke_state); |
| 257 | } |
| 258 | |
| 259 | static void |
| 260 | pdf_unset_pattern(fz_context *ctx, pdf_run_processor *pr, int what) |
| 261 | { |
| 262 | pdf_gstate *gs = pr->gstate + pr->gtop; |
| 263 | pdf_material *mat; |
| 264 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
| 265 | if (mat->kind == PDF_MAT_PATTERN) |
| 266 | { |
| 267 | pdf_drop_pattern(ctx, mat->pattern); |
| 268 | mat->pattern = NULL; |
| 269 | mat->kind = PDF_MAT_COLOR; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | static void |
| 274 | pdf_keep_gstate(fz_context *ctx, pdf_gstate *gs) |
| 275 | { |
| 276 | pdf_keep_material(ctx, &gs->stroke); |
| 277 | pdf_keep_material(ctx, &gs->fill); |
| 278 | if (gs->text.font) |
| 279 | pdf_keep_font(ctx, gs->text.font); |
| 280 | if (gs->softmask) |
| 281 | pdf_keep_obj(ctx, gs->softmask); |
| 282 | if (gs->softmask_resources) |
| 283 | pdf_keep_obj(ctx, gs->softmask_resources); |
| 284 | fz_keep_stroke_state(ctx, gs->stroke_state); |
| 285 | } |
| 286 | |
| 287 | static void |
| 288 | pdf_drop_gstate(fz_context *ctx, pdf_gstate *gs) |
| 289 | { |
| 290 | pdf_drop_material(ctx, &gs->stroke); |
| 291 | pdf_drop_material(ctx, &gs->fill); |
| 292 | pdf_drop_font(ctx, gs->text.font); |
| 293 | pdf_drop_obj(ctx, gs->softmask); |
| 294 | pdf_drop_obj(ctx, gs->softmask_resources); |
| 295 | fz_drop_stroke_state(ctx, gs->stroke_state); |
| 296 | } |
| 297 | |
| 298 | static void |
| 299 | pdf_gsave(fz_context *ctx, pdf_run_processor *pr) |
| 300 | { |
| 301 | if (pr->gtop == pr->gcap-1) |
| 302 | { |
| 303 | pr->gstate = fz_realloc_array(ctx, pr->gstate, pr->gcap*2, pdf_gstate); |
| 304 | pr->gcap *= 2; |
| 305 | } |
| 306 | |
| 307 | memcpy(&pr->gstate[pr->gtop + 1], &pr->gstate[pr->gtop], sizeof(pdf_gstate)); |
| 308 | |
| 309 | pr->gtop++; |
| 310 | pdf_keep_gstate(ctx, &pr->gstate[pr->gtop]); |
| 311 | } |
| 312 | |
| 313 | static void |
| 314 | pdf_grestore(fz_context *ctx, pdf_run_processor *pr) |
| 315 | { |
| 316 | pdf_gstate *gs = pr->gstate + pr->gtop; |
| 317 | int clip_depth = gs->clip_depth; |
| 318 | |
| 319 | if (pr->gtop <= pr->gbot) |
| 320 | { |
| 321 | fz_warn(ctx, "gstate underflow in content stream" ); |
| 322 | return; |
| 323 | } |
| 324 | |
| 325 | pdf_drop_gstate(ctx, gs); |
| 326 | pr->gtop --; |
| 327 | |
| 328 | gs = pr->gstate + pr->gtop; |
| 329 | while (clip_depth > gs->clip_depth) |
| 330 | { |
| 331 | fz_try(ctx) |
| 332 | { |
| 333 | fz_pop_clip(ctx, pr->dev); |
| 334 | } |
| 335 | fz_catch(ctx) |
| 336 | { |
| 337 | /* Silently swallow the problem - restores must |
| 338 | * never throw! */ |
| 339 | } |
| 340 | clip_depth--; |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | static pdf_gstate * |
| 345 | pdf_show_pattern(fz_context *ctx, pdf_run_processor *pr, pdf_pattern *pat, int pat_gstate_num, fz_rect area, int what) |
| 346 | { |
| 347 | pdf_gstate *gstate; |
| 348 | pdf_gstate *pat_gstate; |
| 349 | int gparent_save; |
| 350 | fz_matrix ptm, invptm, gparent_save_ctm; |
| 351 | int x0, y0, x1, y1; |
| 352 | float fx0, fy0, fx1, fy1; |
| 353 | fz_rect local_area; |
| 354 | int id; |
| 355 | |
| 356 | pdf_gsave(ctx, pr); |
| 357 | gstate = pr->gstate + pr->gtop; |
| 358 | pat_gstate = pr->gstate + pat_gstate_num; |
| 359 | |
| 360 | /* Patterns are run with the gstate of the parent */ |
| 361 | pdf_copy_pattern_gstate(ctx, gstate, pat_gstate); |
| 362 | |
| 363 | if (pat->ismask) |
| 364 | { |
| 365 | pdf_unset_pattern(ctx, pr, PDF_FILL); |
| 366 | pdf_unset_pattern(ctx, pr, PDF_STROKE); |
| 367 | if (what == PDF_FILL) |
| 368 | { |
| 369 | pdf_drop_material(ctx, &gstate->stroke); |
| 370 | pdf_keep_material(ctx, &gstate->fill); |
| 371 | gstate->stroke = gstate->fill; |
| 372 | } |
| 373 | if (what == PDF_STROKE) |
| 374 | { |
| 375 | pdf_drop_material(ctx, &gstate->fill); |
| 376 | pdf_keep_material(ctx, &gstate->stroke); |
| 377 | gstate->fill = gstate->stroke; |
| 378 | } |
| 379 | id = 0; /* don't cache uncolored patterns, since we colorize them when drawing */ |
| 380 | } |
| 381 | else |
| 382 | { |
| 383 | // TODO: unset only the current fill/stroke or both? |
| 384 | pdf_unset_pattern(ctx, pr, what); |
| 385 | id = pat->id; |
| 386 | } |
| 387 | |
| 388 | /* don't apply soft masks to objects in the pattern as well */ |
| 389 | if (gstate->softmask) |
| 390 | { |
| 391 | pdf_drop_obj(ctx, gstate->softmask); |
| 392 | gstate->softmask = NULL; |
| 393 | } |
| 394 | |
| 395 | ptm = fz_concat(pat->matrix, pat_gstate->ctm); |
| 396 | invptm = fz_invert_matrix(ptm); |
| 397 | |
| 398 | /* The parent_ctm is amended with our pattern matrix */ |
| 399 | gparent_save = pr->gparent; |
| 400 | pr->gparent = pr->gtop-1; |
| 401 | gparent_save_ctm = pr->gstate[pr->gparent].ctm; |
| 402 | pr->gstate[pr->gparent].ctm = ptm; |
| 403 | |
| 404 | /* patterns are painted using the parent_ctm. area = bbox of |
| 405 | * shape to be filled in device space. Map it back to pattern |
| 406 | * space. */ |
| 407 | local_area = fz_transform_rect(area, invptm); |
| 408 | |
| 409 | fx0 = (local_area.x0 - pat->bbox.x0) / pat->xstep; |
| 410 | fy0 = (local_area.y0 - pat->bbox.y0) / pat->ystep; |
| 411 | fx1 = (local_area.x1 - pat->bbox.x0) / pat->xstep; |
| 412 | fy1 = (local_area.y1 - pat->bbox.y0) / pat->ystep; |
| 413 | if (fx0 > fx1) |
| 414 | { |
| 415 | float t = fx0; fx0 = fx1; fx1 = t; |
| 416 | } |
| 417 | if (fy0 > fy1) |
| 418 | { |
| 419 | float t = fy0; fy0 = fy1; fy1 = t; |
| 420 | } |
| 421 | |
| 422 | #ifdef TILE |
| 423 | /* We have tried various formulations in the past, but this one is |
| 424 | * best we've found; only use it as a tile if a whole repeat is |
| 425 | * required in at least one direction. Note, that this allows for |
| 426 | * 'sections' of 4 tiles to be show, but all non-overlapping. */ |
| 427 | if (fx1-fx0 > 1 || fy1-fy0 > 1) |
| 428 | #else |
| 429 | if (0) |
| 430 | #endif |
| 431 | { |
| 432 | int cached = fz_begin_tile_id(ctx, pr->dev, local_area, pat->bbox, pat->xstep, pat->ystep, ptm, id); |
| 433 | if (!cached) |
| 434 | { |
| 435 | gstate->ctm = ptm; |
| 436 | pdf_gsave(ctx, pr); |
| 437 | pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL); |
| 438 | pdf_grestore(ctx, pr); |
| 439 | } |
| 440 | fz_end_tile(ctx, pr->dev); |
| 441 | } |
| 442 | else |
| 443 | { |
| 444 | int x, y; |
| 445 | |
| 446 | /* When calculating the number of tiles required, we adjust by |
| 447 | * a small amount to allow for rounding errors. By choosing |
| 448 | * this amount to be smaller than 1/256, we guarantee we won't |
| 449 | * cause problems that will be visible even under our most |
| 450 | * extreme antialiasing. */ |
| 451 | x0 = floorf(fx0 + 0.001f); |
| 452 | y0 = floorf(fy0 + 0.001f); |
| 453 | x1 = ceilf(fx1 - 0.001f); |
| 454 | y1 = ceilf(fy1 - 0.001f); |
| 455 | /* The above adjustments cause problems for sufficiently |
| 456 | * large values for xstep/ystep which may be used if the |
| 457 | * pattern is expected to be rendered exactly once. */ |
| 458 | if (fx1 > fx0 && x1 == x0) |
| 459 | x1 = x0 + 1; |
| 460 | if (fy1 > fy0 && y1 == y0) |
| 461 | y1 = y0 + 1; |
| 462 | |
| 463 | for (y = y0; y < y1; y++) |
| 464 | { |
| 465 | for (x = x0; x < x1; x++) |
| 466 | { |
| 467 | gstate->ctm = fz_pre_translate(ptm, x * pat->xstep, y * pat->ystep); |
| 468 | pdf_gsave(ctx, pr); |
| 469 | pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL); |
| 470 | pdf_grestore(ctx, pr); |
| 471 | } |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | pr->gstate[pr->gparent].ctm = gparent_save_ctm; |
| 476 | pr->gparent = gparent_save; |
| 477 | |
| 478 | pdf_grestore(ctx, pr); |
| 479 | |
| 480 | return pr->gstate + pr->gtop; |
| 481 | } |
| 482 | |
| 483 | static void |
| 484 | pdf_show_image_imp(fz_context *ctx, pdf_run_processor *pr, fz_image *image, fz_matrix image_ctm, fz_rect bbox) |
| 485 | { |
| 486 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 487 | |
| 488 | if (image->colorspace) |
| 489 | { |
| 490 | fz_fill_image(ctx, pr->dev, image, image_ctm, gstate->fill.alpha, gstate->fill.color_params); |
| 491 | } |
| 492 | else if (gstate->fill.kind == PDF_MAT_COLOR) |
| 493 | { |
| 494 | fz_fill_image_mask(ctx, pr->dev, image, image_ctm, gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params); |
| 495 | } |
| 496 | else if (gstate->fill.kind == PDF_MAT_PATTERN && gstate->fill.pattern) |
| 497 | { |
| 498 | fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox); |
| 499 | gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL); |
| 500 | fz_pop_clip(ctx, pr->dev); |
| 501 | } |
| 502 | else if (gstate->fill.kind == PDF_MAT_SHADE && gstate->fill.shade) |
| 503 | { |
| 504 | fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox); |
| 505 | fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params); |
| 506 | fz_pop_clip(ctx, pr->dev); |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | static void |
| 511 | pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image) |
| 512 | { |
| 513 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 514 | fz_matrix image_ctm; |
| 515 | fz_rect bbox; |
| 516 | |
| 517 | if (pr->super.hidden) |
| 518 | return; |
| 519 | |
| 520 | /* PDF has images bottom-up, so flip them right side up here */ |
| 521 | image_ctm = fz_pre_scale(fz_pre_translate(gstate->ctm, 0, 1), 1, -1); |
| 522 | |
| 523 | bbox = fz_transform_rect(fz_unit_rect, image_ctm); |
| 524 | |
| 525 | if (image->mask && gstate->blendmode) |
| 526 | { |
| 527 | /* apply blend group even though we skip the soft mask */ |
| 528 | fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1); |
| 529 | fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox); |
| 530 | pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); |
| 531 | fz_pop_clip(ctx, pr->dev); |
| 532 | fz_end_group(ctx, pr->dev); |
| 533 | } |
| 534 | else if (image->mask) |
| 535 | { |
| 536 | fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox); |
| 537 | pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); |
| 538 | fz_pop_clip(ctx, pr->dev); |
| 539 | } |
| 540 | else |
| 541 | { |
| 542 | softmask_save softmask = { NULL }; |
| 543 | gstate = pdf_begin_group(ctx, pr, bbox, &softmask); |
| 544 | pdf_show_image_imp(ctx, pr, image, image_ctm, bbox); |
| 545 | pdf_end_group(ctx, pr, &softmask); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | static void |
| 550 | pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, int dostroke, int even_odd) |
| 551 | { |
| 552 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 553 | fz_path *path; |
| 554 | fz_rect bbox; |
| 555 | softmask_save softmask = { NULL }; |
| 556 | int knockout_group = 0; |
| 557 | |
| 558 | if (dostroke) { |
| 559 | if (pr->dev->flags & (FZ_DEVFLAG_STROKECOLOR_UNDEFINED | FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED)) |
| 560 | pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; |
| 561 | else if (gstate->stroke_state->dash_len != 0 && pr->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED)) |
| 562 | pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; |
| 563 | else if (gstate->stroke_state->linejoin == FZ_LINEJOIN_MITER && (pr->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED)) |
| 564 | pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; |
| 565 | } |
| 566 | if (dofill) { |
| 567 | if (pr->dev->flags & FZ_DEVFLAG_FILLCOLOR_UNDEFINED) |
| 568 | pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; |
| 569 | } |
| 570 | |
| 571 | path = pr->path; |
| 572 | pr->path = fz_new_path(ctx); |
| 573 | |
| 574 | fz_try(ctx) |
| 575 | { |
| 576 | if (doclose) |
| 577 | fz_closepath(ctx, path); |
| 578 | |
| 579 | bbox = fz_bound_path(ctx, path, (dostroke ? gstate->stroke_state : NULL), gstate->ctm); |
| 580 | |
| 581 | if (pr->super.hidden) |
| 582 | dostroke = dofill = 0; |
| 583 | |
| 584 | if (dofill || dostroke) |
| 585 | gstate = pdf_begin_group(ctx, pr, bbox, &softmask); |
| 586 | |
| 587 | if (dofill && dostroke) |
| 588 | { |
| 589 | /* We may need to push a knockout group */ |
| 590 | if (gstate->stroke.alpha == 0) |
| 591 | { |
| 592 | /* No need for group, as stroke won't do anything */ |
| 593 | } |
| 594 | else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL) |
| 595 | { |
| 596 | /* No need for group, as stroke won't show up */ |
| 597 | } |
| 598 | else |
| 599 | { |
| 600 | knockout_group = 1; |
| 601 | fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 1, FZ_BLEND_NORMAL, 1); |
| 602 | } |
| 603 | } |
| 604 | |
| 605 | if (dofill) |
| 606 | { |
| 607 | switch (gstate->fill.kind) |
| 608 | { |
| 609 | case PDF_MAT_NONE: |
| 610 | break; |
| 611 | case PDF_MAT_COLOR: |
| 612 | fz_fill_path(ctx, pr->dev, path, even_odd, gstate->ctm, |
| 613 | gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params); |
| 614 | break; |
| 615 | case PDF_MAT_PATTERN: |
| 616 | if (gstate->fill.pattern) |
| 617 | { |
| 618 | fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox); |
| 619 | gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL); |
| 620 | fz_pop_clip(ctx, pr->dev); |
| 621 | } |
| 622 | break; |
| 623 | case PDF_MAT_SHADE: |
| 624 | if (gstate->fill.shade) |
| 625 | { |
| 626 | fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox); |
| 627 | /* The cluster and page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm. */ |
| 628 | fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params); |
| 629 | fz_pop_clip(ctx, pr->dev); |
| 630 | } |
| 631 | break; |
| 632 | } |
| 633 | } |
| 634 | |
| 635 | if (dostroke) |
| 636 | { |
| 637 | switch (gstate->stroke.kind) |
| 638 | { |
| 639 | case PDF_MAT_NONE: |
| 640 | break; |
| 641 | case PDF_MAT_COLOR: |
| 642 | fz_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, |
| 643 | gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params); |
| 644 | break; |
| 645 | case PDF_MAT_PATTERN: |
| 646 | if (gstate->stroke.pattern) |
| 647 | { |
| 648 | fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox); |
| 649 | gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, bbox, PDF_STROKE); |
| 650 | fz_pop_clip(ctx, pr->dev); |
| 651 | } |
| 652 | break; |
| 653 | case PDF_MAT_SHADE: |
| 654 | if (gstate->stroke.shade) |
| 655 | { |
| 656 | fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox); |
| 657 | fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params); |
| 658 | fz_pop_clip(ctx, pr->dev); |
| 659 | } |
| 660 | break; |
| 661 | } |
| 662 | } |
| 663 | |
| 664 | if (knockout_group) |
| 665 | fz_end_group(ctx, pr->dev); |
| 666 | |
| 667 | if (dofill || dostroke) |
| 668 | pdf_end_group(ctx, pr, &softmask); |
| 669 | |
| 670 | if (pr->clip) |
| 671 | { |
| 672 | gstate->clip_depth++; |
| 673 | fz_clip_path(ctx, pr->dev, path, pr->clip_even_odd, gstate->ctm, bbox); |
| 674 | pr->clip = 0; |
| 675 | } |
| 676 | } |
| 677 | fz_always(ctx) |
| 678 | { |
| 679 | fz_drop_path(ctx, path); |
| 680 | } |
| 681 | fz_catch(ctx) |
| 682 | { |
| 683 | fz_rethrow(ctx); |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | * Assemble and emit text |
| 689 | */ |
| 690 | |
| 691 | static pdf_gstate * |
| 692 | pdf_flush_text(fz_context *ctx, pdf_run_processor *pr) |
| 693 | { |
| 694 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 695 | fz_text *text; |
| 696 | int dofill; |
| 697 | int dostroke; |
| 698 | int doclip; |
| 699 | int doinvisible; |
| 700 | softmask_save softmask = { NULL }; |
| 701 | int knockout_group = 0; |
| 702 | |
| 703 | text = pdf_tos_get_text(ctx, &pr->tos); |
| 704 | if (!text) |
| 705 | return gstate; |
| 706 | |
| 707 | dofill = dostroke = doclip = doinvisible = 0; |
| 708 | switch (pr->tos.text_mode) |
| 709 | { |
| 710 | case 0: dofill = 1; break; |
| 711 | case 1: dostroke = 1; break; |
| 712 | case 2: dofill = dostroke = 1; break; |
| 713 | case 3: doinvisible = 1; break; |
| 714 | case 4: dofill = doclip = 1; break; |
| 715 | case 5: dostroke = doclip = 1; break; |
| 716 | case 6: dofill = dostroke = doclip = 1; break; |
| 717 | case 7: doclip = 1; break; |
| 718 | } |
| 719 | |
| 720 | if (pr->super.hidden) |
| 721 | dostroke = dofill = 0; |
| 722 | |
| 723 | fz_try(ctx) |
| 724 | { |
| 725 | fz_rect tb = fz_transform_rect(pr->tos.text_bbox, gstate->ctm); |
| 726 | if (dostroke) |
| 727 | tb = fz_adjust_rect_for_stroke(ctx, tb, gstate->stroke_state, gstate->ctm); |
| 728 | |
| 729 | /* Don't bother sending a text group with nothing in it */ |
| 730 | if (!text->head) |
| 731 | break; |
| 732 | |
| 733 | if (dofill || dostroke) |
| 734 | gstate = pdf_begin_group(ctx, pr, tb, &softmask); |
| 735 | |
| 736 | if (dofill && dostroke) |
| 737 | { |
| 738 | /* We may need to push a knockout group */ |
| 739 | if (gstate->stroke.alpha == 0) |
| 740 | { |
| 741 | /* No need for group, as stroke won't do anything */ |
| 742 | } |
| 743 | else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL) |
| 744 | { |
| 745 | /* No need for group, as stroke won't show up */ |
| 746 | } |
| 747 | else |
| 748 | { |
| 749 | knockout_group = 1; |
| 750 | fz_begin_group(ctx, pr->dev, tb, NULL, 0, 1, FZ_BLEND_NORMAL, 1); |
| 751 | } |
| 752 | } |
| 753 | |
| 754 | if (doinvisible) |
| 755 | fz_ignore_text(ctx, pr->dev, text, gstate->ctm); |
| 756 | |
| 757 | if (dofill) |
| 758 | { |
| 759 | switch (gstate->fill.kind) |
| 760 | { |
| 761 | case PDF_MAT_NONE: |
| 762 | break; |
| 763 | case PDF_MAT_COLOR: |
| 764 | fz_fill_text(ctx, pr->dev, text, gstate->ctm, |
| 765 | gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params); |
| 766 | break; |
| 767 | case PDF_MAT_PATTERN: |
| 768 | if (gstate->fill.pattern) |
| 769 | { |
| 770 | fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); |
| 771 | gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, tb, PDF_FILL); |
| 772 | fz_pop_clip(ctx, pr->dev); |
| 773 | } |
| 774 | break; |
| 775 | case PDF_MAT_SHADE: |
| 776 | if (gstate->fill.shade) |
| 777 | { |
| 778 | fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); |
| 779 | /* Page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm */ |
| 780 | fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params); |
| 781 | fz_pop_clip(ctx, pr->dev); |
| 782 | } |
| 783 | break; |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | if (dostroke) |
| 788 | { |
| 789 | switch (gstate->stroke.kind) |
| 790 | { |
| 791 | case PDF_MAT_NONE: |
| 792 | break; |
| 793 | case PDF_MAT_COLOR: |
| 794 | fz_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, |
| 795 | gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params); |
| 796 | break; |
| 797 | case PDF_MAT_PATTERN: |
| 798 | if (gstate->stroke.pattern) |
| 799 | { |
| 800 | fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb); |
| 801 | gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, tb, PDF_STROKE); |
| 802 | fz_pop_clip(ctx, pr->dev); |
| 803 | } |
| 804 | break; |
| 805 | case PDF_MAT_SHADE: |
| 806 | if (gstate->stroke.shade) |
| 807 | { |
| 808 | fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb); |
| 809 | fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params); |
| 810 | fz_pop_clip(ctx, pr->dev); |
| 811 | } |
| 812 | break; |
| 813 | } |
| 814 | } |
| 815 | |
| 816 | if (knockout_group) |
| 817 | fz_end_group(ctx, pr->dev); |
| 818 | |
| 819 | if (dofill || dostroke) |
| 820 | pdf_end_group(ctx, pr, &softmask); |
| 821 | |
| 822 | if (doclip) |
| 823 | { |
| 824 | gstate->clip_depth++; |
| 825 | fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb); |
| 826 | } |
| 827 | } |
| 828 | fz_always(ctx) |
| 829 | { |
| 830 | fz_drop_text(ctx, text); |
| 831 | } |
| 832 | fz_catch(ctx) |
| 833 | { |
| 834 | fz_rethrow(ctx); |
| 835 | } |
| 836 | |
| 837 | return pr->gstate + pr->gtop; |
| 838 | } |
| 839 | |
| 840 | static void |
| 841 | pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid) |
| 842 | { |
| 843 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 844 | pdf_font_desc *fontdesc = gstate->text.font; |
| 845 | fz_matrix trm; |
| 846 | int gid; |
| 847 | int ucsbuf[8]; |
| 848 | int ucslen; |
| 849 | int i; |
| 850 | int render_direct; |
| 851 | |
| 852 | gid = pdf_tos_make_trm(ctx, &pr->tos, &gstate->text, fontdesc, cid, &trm); |
| 853 | |
| 854 | /* If we are uncachable, then render direct. */ |
| 855 | render_direct = !fz_glyph_cacheable(ctx, fontdesc->font, gid); |
| 856 | |
| 857 | /* flush buffered text if rendermode has changed */ |
| 858 | if (!pr->tos.text || gstate->text.render != pr->tos.text_mode || render_direct) |
| 859 | { |
| 860 | gstate = pdf_flush_text(ctx, pr); |
| 861 | pdf_tos_reset(ctx, &pr->tos, gstate->text.render); |
| 862 | } |
| 863 | |
| 864 | if (render_direct) |
| 865 | { |
| 866 | /* Render the glyph stream direct here (only happens for |
| 867 | * type3 glyphs that seem to inherit current graphics |
| 868 | * attributes, or type 3 glyphs within type3 glyphs). */ |
| 869 | fz_matrix composed = fz_concat(trm, gstate->ctm); |
| 870 | fz_render_t3_glyph_direct(ctx, pr->dev, fontdesc->font, gid, composed, gstate, pr->default_cs); |
| 871 | /* Render text invisibly so that it can still be extracted. */ |
| 872 | pr->tos.text_mode = 3; |
| 873 | } |
| 874 | |
| 875 | ucslen = 0; |
| 876 | if (fontdesc->to_unicode) |
| 877 | ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf); |
| 878 | if (ucslen == 0 && (size_t)cid < fontdesc->cid_to_ucs_len) |
| 879 | { |
| 880 | ucsbuf[0] = fontdesc->cid_to_ucs[cid]; |
| 881 | ucslen = 1; |
| 882 | } |
| 883 | if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0)) |
| 884 | { |
| 885 | ucsbuf[0] = FZ_REPLACEMENT_CHARACTER; |
| 886 | ucslen = 1; |
| 887 | } |
| 888 | |
| 889 | /* add glyph to textobject */ |
| 890 | fz_show_glyph(ctx, pr->tos.text, fontdesc->font, trm, gid, ucsbuf[0], fontdesc->wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET); |
| 891 | |
| 892 | /* add filler glyphs for one-to-many unicode mapping */ |
| 893 | for (i = 1; i < ucslen; i++) |
| 894 | fz_show_glyph(ctx, pr->tos.text, fontdesc->font, trm, -1, ucsbuf[i], fontdesc->wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET); |
| 895 | |
| 896 | pdf_tos_move_after_char(ctx, &pr->tos); |
| 897 | } |
| 898 | |
| 899 | static void |
| 900 | pdf_show_space(fz_context *ctx, pdf_run_processor *pr, float tadj) |
| 901 | { |
| 902 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 903 | pdf_font_desc *fontdesc = gstate->text.font; |
| 904 | |
| 905 | if (fontdesc->wmode == 0) |
| 906 | pr->tos.tm = fz_pre_translate(pr->tos.tm, tadj * gstate->text.scale, 0); |
| 907 | else |
| 908 | pr->tos.tm = fz_pre_translate(pr->tos.tm, 0, tadj); |
| 909 | } |
| 910 | |
| 911 | static void |
| 912 | show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, int len) |
| 913 | { |
| 914 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 915 | pdf_font_desc *fontdesc = gstate->text.font; |
| 916 | unsigned char *end = buf + len; |
| 917 | unsigned int cpt; |
| 918 | int cid; |
| 919 | |
| 920 | while (buf < end) |
| 921 | { |
| 922 | int w = pdf_decode_cmap(fontdesc->encoding, buf, end, &cpt); |
| 923 | buf += w; |
| 924 | |
| 925 | cid = pdf_lookup_cmap(fontdesc->encoding, cpt); |
| 926 | if (cid >= 0) |
| 927 | pdf_show_char(ctx, pr, cid); |
| 928 | else |
| 929 | fz_warn(ctx, "cannot encode character" ); |
| 930 | if (cpt == 32 && w == 1) |
| 931 | pdf_show_space(ctx, pr, gstate->text.word_space); |
| 932 | } |
| 933 | } |
| 934 | |
| 935 | static void |
| 936 | pdf_show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, int len) |
| 937 | { |
| 938 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 939 | pdf_font_desc *fontdesc = gstate->text.font; |
| 940 | |
| 941 | if (!fontdesc) |
| 942 | { |
| 943 | fz_warn(ctx, "cannot draw text since font and size not set" ); |
| 944 | return; |
| 945 | } |
| 946 | |
| 947 | show_string(ctx, pr, buf, len); |
| 948 | } |
| 949 | |
| 950 | static void |
| 951 | pdf_show_text(fz_context *ctx, pdf_run_processor *pr, pdf_obj *text) |
| 952 | { |
| 953 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 954 | pdf_font_desc *fontdesc = gstate->text.font; |
| 955 | int i; |
| 956 | |
| 957 | if (!fontdesc) |
| 958 | { |
| 959 | fz_warn(ctx, "cannot draw text since font and size not set" ); |
| 960 | return; |
| 961 | } |
| 962 | |
| 963 | if (pdf_is_array(ctx, text)) |
| 964 | { |
| 965 | int n = pdf_array_len(ctx, text); |
| 966 | for (i = 0; i < n; i++) |
| 967 | { |
| 968 | pdf_obj *item = pdf_array_get(ctx, text, i); |
| 969 | if (pdf_is_string(ctx, item)) |
| 970 | show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, item), pdf_to_str_len(ctx, item)); |
| 971 | else |
| 972 | pdf_show_space(ctx, pr, - pdf_to_real(ctx, item) * gstate->text.size * 0.001f); |
| 973 | } |
| 974 | } |
| 975 | else if (pdf_is_string(ctx, text)) |
| 976 | { |
| 977 | pdf_show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text)); |
| 978 | } |
| 979 | } |
| 980 | |
| 981 | /* |
| 982 | * Interpreter and graphics state stack. |
| 983 | */ |
| 984 | |
| 985 | static void |
| 986 | pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, fz_matrix ctm) |
| 987 | { |
| 988 | gs->ctm = ctm; |
| 989 | gs->clip_depth = 0; |
| 990 | |
| 991 | gs->stroke_state = fz_new_stroke_state(ctx); |
| 992 | |
| 993 | gs->stroke.kind = PDF_MAT_COLOR; |
| 994 | gs->stroke.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
| 995 | gs->stroke.v[0] = 0; |
| 996 | gs->stroke.pattern = NULL; |
| 997 | gs->stroke.shade = NULL; |
| 998 | gs->stroke.alpha = 1; |
| 999 | gs->stroke.gstate_num = -1; |
| 1000 | |
| 1001 | gs->fill.kind = PDF_MAT_COLOR; |
| 1002 | gs->fill.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
| 1003 | gs->fill.v[0] = 0; |
| 1004 | gs->fill.pattern = NULL; |
| 1005 | gs->fill.shade = NULL; |
| 1006 | gs->fill.alpha = 1; |
| 1007 | gs->fill.gstate_num = -1; |
| 1008 | |
| 1009 | gs->text.char_space = 0; |
| 1010 | gs->text.word_space = 0; |
| 1011 | gs->text.scale = 1; |
| 1012 | gs->text.leading = 0; |
| 1013 | gs->text.font = NULL; |
| 1014 | gs->text.size = -1; |
| 1015 | gs->text.render = 0; |
| 1016 | gs->text.rise = 0; |
| 1017 | |
| 1018 | gs->blendmode = 0; |
| 1019 | gs->softmask = NULL; |
| 1020 | gs->softmask_resources = NULL; |
| 1021 | gs->softmask_ctm = fz_identity; |
| 1022 | gs->luminosity = 0; |
| 1023 | |
| 1024 | gs->fill.color_params = fz_default_color_params; |
| 1025 | gs->stroke.color_params = fz_default_color_params; |
| 1026 | } |
| 1027 | |
| 1028 | static void |
| 1029 | pdf_copy_gstate(fz_context *ctx, pdf_gstate *dst, pdf_gstate *src) |
| 1030 | { |
| 1031 | pdf_drop_gstate(ctx, dst); |
| 1032 | *dst = *src; |
| 1033 | pdf_keep_gstate(ctx, dst); |
| 1034 | } |
| 1035 | |
| 1036 | /* |
| 1037 | * Material state |
| 1038 | */ |
| 1039 | |
| 1040 | static void |
| 1041 | pdf_set_colorspace(fz_context *ctx, pdf_run_processor *pr, int what, fz_colorspace *colorspace) |
| 1042 | { |
| 1043 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1044 | pdf_material *mat; |
| 1045 | int n = fz_colorspace_n(ctx, colorspace); |
| 1046 | |
| 1047 | gstate = pdf_flush_text(ctx, pr); |
| 1048 | |
| 1049 | mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; |
| 1050 | |
| 1051 | fz_drop_colorspace(ctx, mat->colorspace); |
| 1052 | |
| 1053 | mat->kind = PDF_MAT_COLOR; |
| 1054 | mat->colorspace = fz_keep_colorspace(ctx, colorspace); |
| 1055 | |
| 1056 | mat->v[0] = 0; |
| 1057 | mat->v[1] = 0; |
| 1058 | mat->v[2] = 0; |
| 1059 | mat->v[3] = 1; |
| 1060 | |
| 1061 | if (pdf_is_tint_colorspace(ctx, colorspace)) |
| 1062 | { |
| 1063 | int i; |
| 1064 | for (i = 0; i < n; i++) |
| 1065 | mat->v[i] = 1.0f; |
| 1066 | } |
| 1067 | } |
| 1068 | |
| 1069 | static void |
| 1070 | pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v) |
| 1071 | { |
| 1072 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1073 | pdf_material *mat; |
| 1074 | |
| 1075 | gstate = pdf_flush_text(ctx, pr); |
| 1076 | |
| 1077 | mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; |
| 1078 | |
| 1079 | switch (mat->kind) |
| 1080 | { |
| 1081 | case PDF_MAT_PATTERN: |
| 1082 | case PDF_MAT_COLOR: |
| 1083 | fz_clamp_color(ctx, mat->colorspace, v, mat->v); |
| 1084 | break; |
| 1085 | default: |
| 1086 | fz_warn(ctx, "color incompatible with material" ); |
| 1087 | } |
| 1088 | |
| 1089 | mat->gstate_num = pr->gparent; |
| 1090 | } |
| 1091 | |
| 1092 | static void |
| 1093 | pdf_set_shade(fz_context *ctx, pdf_run_processor *pr, int what, fz_shade *shade) |
| 1094 | { |
| 1095 | pdf_gstate *gs; |
| 1096 | pdf_material *mat; |
| 1097 | |
| 1098 | gs = pdf_flush_text(ctx, pr); |
| 1099 | |
| 1100 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
| 1101 | |
| 1102 | fz_drop_shade(ctx, mat->shade); |
| 1103 | |
| 1104 | mat->kind = PDF_MAT_SHADE; |
| 1105 | mat->shade = fz_keep_shade(ctx, shade); |
| 1106 | |
| 1107 | mat->gstate_num = pr->gparent; |
| 1108 | } |
| 1109 | |
| 1110 | static void |
| 1111 | pdf_set_pattern(fz_context *ctx, pdf_run_processor *pr, int what, pdf_pattern *pat, float *v) |
| 1112 | { |
| 1113 | pdf_gstate *gs; |
| 1114 | pdf_material *mat; |
| 1115 | |
| 1116 | gs = pdf_flush_text(ctx, pr); |
| 1117 | |
| 1118 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
| 1119 | |
| 1120 | pdf_drop_pattern(ctx, mat->pattern); |
| 1121 | mat->pattern = NULL; |
| 1122 | |
| 1123 | mat->kind = PDF_MAT_PATTERN; |
| 1124 | if (pat) |
| 1125 | mat->pattern = pdf_keep_pattern(ctx, pat); |
| 1126 | |
| 1127 | if (v) |
| 1128 | pdf_set_color(ctx, pr, what, v); |
| 1129 | |
| 1130 | mat->gstate_num = pr->gparent; |
| 1131 | } |
| 1132 | |
| 1133 | static void |
| 1134 | pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_obj *xobj, pdf_obj *page_resources, fz_matrix transform, int is_smask) |
| 1135 | { |
| 1136 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1137 | pdf_gstate *gstate = NULL; |
| 1138 | int oldtop = 0; |
| 1139 | int oldbot = -1; |
| 1140 | softmask_save softmask = { NULL }; |
| 1141 | int gparent_save; |
| 1142 | fz_matrix gparent_save_ctm; |
| 1143 | pdf_obj *resources; |
| 1144 | fz_rect xobj_bbox; |
| 1145 | fz_matrix xobj_matrix; |
| 1146 | int transparency = 0; |
| 1147 | pdf_document *doc; |
| 1148 | fz_colorspace *cs = NULL; |
| 1149 | fz_default_colorspaces *save_default_cs = NULL; |
| 1150 | fz_default_colorspaces *xobj_default_cs = NULL; |
| 1151 | |
| 1152 | /* Avoid infinite recursion */ |
| 1153 | if (xobj == NULL || pdf_mark_obj(ctx, xobj)) |
| 1154 | return; |
| 1155 | |
| 1156 | fz_var(cs); |
| 1157 | fz_var(xobj_default_cs); |
| 1158 | |
| 1159 | gparent_save = pr->gparent; |
| 1160 | pr->gparent = pr->gtop; |
| 1161 | oldtop = pr->gtop; |
| 1162 | |
| 1163 | save_default_cs = pr->default_cs; |
| 1164 | |
| 1165 | fz_try(ctx) |
| 1166 | { |
| 1167 | pdf_gsave(ctx, pr); |
| 1168 | |
| 1169 | gstate = pr->gstate + pr->gtop; |
| 1170 | |
| 1171 | xobj_bbox = pdf_xobject_bbox(ctx, xobj); |
| 1172 | xobj_matrix = pdf_xobject_matrix(ctx, xobj); |
| 1173 | transparency = pdf_xobject_transparency(ctx, xobj); |
| 1174 | |
| 1175 | /* apply xobject's transform matrix */ |
| 1176 | transform = fz_concat(xobj_matrix, transform); |
| 1177 | gstate->ctm = fz_concat(transform, gstate->ctm); |
| 1178 | |
| 1179 | /* The gparent is updated with the modified ctm */ |
| 1180 | gparent_save_ctm = pr->gstate[pr->gparent].ctm; |
| 1181 | pr->gstate[pr->gparent].ctm = gstate->ctm; |
| 1182 | |
| 1183 | /* apply soft mask, create transparency group and reset state */ |
| 1184 | if (transparency) |
| 1185 | { |
| 1186 | int isolated = pdf_xobject_isolated(ctx, xobj); |
| 1187 | |
| 1188 | fz_rect bbox = fz_transform_rect(xobj_bbox, gstate->ctm); |
| 1189 | |
| 1190 | gstate = begin_softmask(ctx, pr, &softmask); |
| 1191 | |
| 1192 | if (isolated) |
| 1193 | cs = pdf_xobject_colorspace(ctx, xobj); |
| 1194 | fz_begin_group(ctx, pr->dev, bbox, |
| 1195 | cs, |
| 1196 | (is_smask ? 1 : isolated), |
| 1197 | pdf_xobject_knockout(ctx, xobj), |
| 1198 | gstate->blendmode, gstate->fill.alpha); |
| 1199 | |
| 1200 | gstate->blendmode = 0; |
| 1201 | gstate->stroke.alpha = 1; |
| 1202 | gstate->fill.alpha = 1; |
| 1203 | } |
| 1204 | |
| 1205 | pdf_gsave(ctx, pr); /* Save here so the clippath doesn't persist */ |
| 1206 | |
| 1207 | /* clip to the bounds */ |
| 1208 | fz_moveto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y0); |
| 1209 | fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y0); |
| 1210 | fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y1); |
| 1211 | fz_lineto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y1); |
| 1212 | fz_closepath(ctx, pr->path); |
| 1213 | pr->clip = 1; |
| 1214 | pdf_show_path(ctx, pr, 0, 0, 0, 0); |
| 1215 | |
| 1216 | /* run contents */ |
| 1217 | |
| 1218 | resources = pdf_xobject_resources(ctx, xobj); |
| 1219 | if (!resources) |
| 1220 | resources = page_resources; |
| 1221 | |
| 1222 | fz_try(ctx) |
| 1223 | xobj_default_cs = pdf_update_default_colorspaces(ctx, pr->default_cs, resources); |
| 1224 | fz_catch(ctx) |
| 1225 | { |
| 1226 | if (fz_caught(ctx) != FZ_ERROR_TRYLATER) |
| 1227 | fz_rethrow(ctx); |
| 1228 | if (pr->cookie) |
| 1229 | pr->cookie->incomplete = 1; |
| 1230 | } |
| 1231 | if (xobj_default_cs != save_default_cs) |
| 1232 | { |
| 1233 | fz_set_default_colorspaces(ctx, pr->dev, xobj_default_cs); |
| 1234 | pr->default_cs = xobj_default_cs; |
| 1235 | } |
| 1236 | |
| 1237 | doc = pdf_get_bound_document(ctx, xobj); |
| 1238 | |
| 1239 | oldbot = pr->gbot; |
| 1240 | pr->gbot = pr->gtop; |
| 1241 | |
| 1242 | pdf_process_contents(ctx, (pdf_processor*)pr, doc, resources, xobj, pr->cookie); |
| 1243 | |
| 1244 | /* Undo any gstate mismatches due to the pdf_process_contents call */ |
| 1245 | if (oldbot != -1) |
| 1246 | { |
| 1247 | while (pr->gtop > pr->gbot) |
| 1248 | { |
| 1249 | pdf_grestore(ctx, pr); |
| 1250 | } |
| 1251 | pr->gbot = oldbot; |
| 1252 | } |
| 1253 | |
| 1254 | pdf_grestore(ctx, pr); /* Remove the state we pushed for the clippath */ |
| 1255 | |
| 1256 | /* wrap up transparency stacks */ |
| 1257 | if (transparency) |
| 1258 | { |
| 1259 | fz_end_group(ctx, pr->dev); |
| 1260 | end_softmask(ctx, pr, &softmask); |
| 1261 | } |
| 1262 | |
| 1263 | pr->gstate[pr->gparent].ctm = gparent_save_ctm; |
| 1264 | pr->gparent = gparent_save; |
| 1265 | |
| 1266 | while (oldtop < pr->gtop) |
| 1267 | pdf_grestore(ctx, pr); |
| 1268 | |
| 1269 | if (xobj_default_cs != save_default_cs) |
| 1270 | { |
| 1271 | fz_set_default_colorspaces(ctx, pr->dev, save_default_cs); |
| 1272 | } |
| 1273 | } |
| 1274 | fz_always(ctx) |
| 1275 | { |
| 1276 | pr->default_cs = save_default_cs; |
| 1277 | fz_drop_default_colorspaces(ctx, xobj_default_cs); |
| 1278 | fz_drop_colorspace(ctx, cs); |
| 1279 | pdf_unmark_obj(ctx, xobj); |
| 1280 | } |
| 1281 | fz_catch(ctx) |
| 1282 | { |
| 1283 | pdf_drop_obj(ctx, softmask.softmask); |
| 1284 | pdf_drop_obj(ctx, softmask.page_resources); |
| 1285 | /* Note: Any SYNTAX errors should have been swallowed |
| 1286 | * by pdf_process_contents, but in case any escape from other |
| 1287 | * functions, recast the error type here to be safe. */ |
| 1288 | if (fz_caught(ctx) == FZ_ERROR_SYNTAX) |
| 1289 | fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in xobject" ); |
| 1290 | fz_rethrow(ctx); |
| 1291 | } |
| 1292 | } |
| 1293 | |
| 1294 | /* general graphics state */ |
| 1295 | |
| 1296 | static void pdf_run_w(fz_context *ctx, pdf_processor *proc, float linewidth) |
| 1297 | { |
| 1298 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1299 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1300 | |
| 1301 | pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; |
| 1302 | gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); |
| 1303 | gstate->stroke_state->linewidth = linewidth; |
| 1304 | } |
| 1305 | |
| 1306 | static void pdf_run_j(fz_context *ctx, pdf_processor *proc, int linejoin) |
| 1307 | { |
| 1308 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1309 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1310 | |
| 1311 | pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; |
| 1312 | gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); |
| 1313 | gstate->stroke_state->linejoin = linejoin; |
| 1314 | } |
| 1315 | |
| 1316 | static void pdf_run_J(fz_context *ctx, pdf_processor *proc, int linecap) |
| 1317 | { |
| 1318 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1319 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1320 | |
| 1321 | pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); |
| 1322 | gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); |
| 1323 | gstate->stroke_state->start_cap = linecap; |
| 1324 | gstate->stroke_state->dash_cap = linecap; |
| 1325 | gstate->stroke_state->end_cap = linecap; |
| 1326 | } |
| 1327 | |
| 1328 | static void pdf_run_M(fz_context *ctx, pdf_processor *proc, float miterlimit) |
| 1329 | { |
| 1330 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1331 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1332 | |
| 1333 | pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; |
| 1334 | gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); |
| 1335 | gstate->stroke_state->miterlimit = miterlimit; |
| 1336 | } |
| 1337 | |
| 1338 | static void pdf_run_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) |
| 1339 | { |
| 1340 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1341 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1342 | int len, i; |
| 1343 | |
| 1344 | len = pdf_array_len(ctx, array); |
| 1345 | gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(ctx, gstate->stroke_state, len); |
| 1346 | gstate->stroke_state->dash_len = len; |
| 1347 | for (i = 0; i < len; i++) |
| 1348 | gstate->stroke_state->dash_list[i] = pdf_array_get_real(ctx, array, i); |
| 1349 | gstate->stroke_state->dash_phase = phase; |
| 1350 | } |
| 1351 | |
| 1352 | static void pdf_run_ri(fz_context *ctx, pdf_processor *proc, const char *intent) |
| 1353 | { |
| 1354 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1355 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1356 | gstate->fill.color_params.ri = fz_lookup_rendering_intent(intent); |
| 1357 | gstate->stroke.color_params.ri = gstate->fill.color_params.ri; |
| 1358 | } |
| 1359 | |
| 1360 | static void pdf_run_gs_OP(fz_context *ctx, pdf_processor *proc, int b) |
| 1361 | { |
| 1362 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1363 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1364 | gstate->stroke.color_params.op = b; |
| 1365 | gstate->fill.color_params.op = b; |
| 1366 | } |
| 1367 | |
| 1368 | static void pdf_run_gs_op(fz_context *ctx, pdf_processor *proc, int b) |
| 1369 | { |
| 1370 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1371 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1372 | gstate->fill.color_params.op = b; |
| 1373 | } |
| 1374 | |
| 1375 | static void pdf_run_gs_OPM(fz_context *ctx, pdf_processor *proc, int i) |
| 1376 | { |
| 1377 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1378 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1379 | gstate->stroke.color_params.opm = i; |
| 1380 | gstate->fill.color_params.opm = i; |
| 1381 | } |
| 1382 | |
| 1383 | static void pdf_run_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *obj) |
| 1384 | { |
| 1385 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1386 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1387 | int on = pdf_name_eq(ctx, obj, PDF_NAME(ON)); |
| 1388 | /* The spec says that "ON" means on, "OFF" means "Off", and |
| 1389 | * "Default" or anything else means "Meh, do what you want." */ |
| 1390 | gstate->stroke.color_params.bp = on; |
| 1391 | gstate->fill.color_params.bp = on; |
| 1392 | } |
| 1393 | |
| 1394 | static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness) |
| 1395 | { |
| 1396 | } |
| 1397 | |
| 1398 | static void pdf_run_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) |
| 1399 | { |
| 1400 | } |
| 1401 | |
| 1402 | static void pdf_run_gs_end(fz_context *ctx, pdf_processor *proc) |
| 1403 | { |
| 1404 | } |
| 1405 | |
| 1406 | /* transparency graphics state */ |
| 1407 | |
| 1408 | static void pdf_run_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode) |
| 1409 | { |
| 1410 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1411 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1412 | gstate->blendmode = fz_lookup_blendmode(blendmode); |
| 1413 | } |
| 1414 | |
| 1415 | static void pdf_run_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha) |
| 1416 | { |
| 1417 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1418 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1419 | gstate->stroke.alpha = fz_clamp(alpha, 0, 1); |
| 1420 | } |
| 1421 | |
| 1422 | static void pdf_run_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha) |
| 1423 | { |
| 1424 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1425 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1426 | gstate->fill.alpha = fz_clamp(alpha, 0, 1); |
| 1427 | } |
| 1428 | |
| 1429 | static void pdf_run_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, pdf_obj *page_resources, float *bc, int luminosity) |
| 1430 | { |
| 1431 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1432 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1433 | int i; |
| 1434 | |
| 1435 | if (gstate->softmask) |
| 1436 | { |
| 1437 | pdf_drop_obj(ctx, gstate->softmask); |
| 1438 | gstate->softmask = NULL; |
| 1439 | pdf_drop_obj(ctx, gstate->softmask_resources); |
| 1440 | gstate->softmask_resources = NULL; |
| 1441 | } |
| 1442 | |
| 1443 | if (smask) |
| 1444 | { |
| 1445 | fz_colorspace *cs = pdf_xobject_colorspace(ctx, smask); |
| 1446 | int cs_n = 1; |
| 1447 | if (cs) |
| 1448 | cs_n = fz_colorspace_n(ctx, cs); |
| 1449 | gstate->softmask_ctm = gstate->ctm; |
| 1450 | gstate->softmask = pdf_keep_obj(ctx, smask); |
| 1451 | gstate->softmask_resources = pdf_keep_obj(ctx, page_resources); |
| 1452 | for (i = 0; i < cs_n; ++i) |
| 1453 | gstate->softmask_bc[i] = bc[i]; |
| 1454 | gstate->luminosity = luminosity; |
| 1455 | fz_drop_colorspace(ctx, cs); |
| 1456 | } |
| 1457 | } |
| 1458 | |
| 1459 | /* special graphics state */ |
| 1460 | |
| 1461 | static void pdf_run_q(fz_context *ctx, pdf_processor *proc) |
| 1462 | { |
| 1463 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1464 | pdf_gsave(ctx, pr); |
| 1465 | } |
| 1466 | |
| 1467 | static void pdf_run_Q(fz_context *ctx, pdf_processor *proc) |
| 1468 | { |
| 1469 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1470 | pdf_grestore(ctx, pr); |
| 1471 | } |
| 1472 | |
| 1473 | static void pdf_run_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) |
| 1474 | { |
| 1475 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1476 | pdf_gstate *gstate = pdf_flush_text(ctx, pr); |
| 1477 | fz_matrix m; |
| 1478 | |
| 1479 | m.a = a; |
| 1480 | m.b = b; |
| 1481 | m.c = c; |
| 1482 | m.d = d; |
| 1483 | m.e = e; |
| 1484 | m.f = f; |
| 1485 | gstate->ctm = fz_concat(m, gstate->ctm); |
| 1486 | } |
| 1487 | |
| 1488 | /* path construction */ |
| 1489 | |
| 1490 | static void pdf_run_m(fz_context *ctx, pdf_processor *proc, float x, float y) |
| 1491 | { |
| 1492 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1493 | fz_moveto(ctx, pr->path, x, y); |
| 1494 | } |
| 1495 | |
| 1496 | static void pdf_run_l(fz_context *ctx, pdf_processor *proc, float x, float y) |
| 1497 | { |
| 1498 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1499 | fz_lineto(ctx, pr->path, x, y); |
| 1500 | } |
| 1501 | static void pdf_run_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) |
| 1502 | { |
| 1503 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1504 | fz_curveto(ctx, pr->path, x1, y1, x2, y2, x3, y3); |
| 1505 | } |
| 1506 | |
| 1507 | static void pdf_run_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) |
| 1508 | { |
| 1509 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1510 | fz_curvetov(ctx, pr->path, x2, y2, x3, y3); |
| 1511 | } |
| 1512 | |
| 1513 | static void pdf_run_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) |
| 1514 | { |
| 1515 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1516 | fz_curvetoy(ctx, pr->path, x1, y1, x3, y3); |
| 1517 | } |
| 1518 | |
| 1519 | static void pdf_run_h(fz_context *ctx, pdf_processor *proc) |
| 1520 | { |
| 1521 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1522 | fz_closepath(ctx, pr->path); |
| 1523 | } |
| 1524 | |
| 1525 | static void pdf_run_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) |
| 1526 | { |
| 1527 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1528 | fz_rectto(ctx, pr->path, x, y, x+w, y+h); |
| 1529 | } |
| 1530 | |
| 1531 | /* path painting */ |
| 1532 | |
| 1533 | static void pdf_run_S(fz_context *ctx, pdf_processor *proc) |
| 1534 | { |
| 1535 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1536 | pdf_show_path(ctx, pr, 0, 0, 1, 0); |
| 1537 | } |
| 1538 | |
| 1539 | static void pdf_run_s(fz_context *ctx, pdf_processor *proc) |
| 1540 | { |
| 1541 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1542 | pdf_show_path(ctx, pr, 1, 0, 1, 0); |
| 1543 | } |
| 1544 | |
| 1545 | static void pdf_run_F(fz_context *ctx, pdf_processor *proc) |
| 1546 | { |
| 1547 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1548 | pdf_show_path(ctx, pr, 0, 1, 0, 0); |
| 1549 | } |
| 1550 | |
| 1551 | static void pdf_run_f(fz_context *ctx, pdf_processor *proc) |
| 1552 | { |
| 1553 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1554 | pdf_show_path(ctx, pr, 0, 1, 0, 0); |
| 1555 | } |
| 1556 | |
| 1557 | static void pdf_run_fstar(fz_context *ctx, pdf_processor *proc) |
| 1558 | { |
| 1559 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1560 | pdf_show_path(ctx, pr, 0, 1, 0, 1); |
| 1561 | } |
| 1562 | |
| 1563 | static void pdf_run_B(fz_context *ctx, pdf_processor *proc) |
| 1564 | { |
| 1565 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1566 | pdf_show_path(ctx, pr, 0, 1, 1, 0); |
| 1567 | } |
| 1568 | |
| 1569 | static void pdf_run_Bstar(fz_context *ctx, pdf_processor *proc) |
| 1570 | { |
| 1571 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1572 | pdf_show_path(ctx, pr, 0, 1, 1, 1); |
| 1573 | } |
| 1574 | |
| 1575 | static void pdf_run_b(fz_context *ctx, pdf_processor *proc) |
| 1576 | { |
| 1577 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1578 | pdf_show_path(ctx, pr, 1, 1, 1, 0); |
| 1579 | } |
| 1580 | |
| 1581 | static void pdf_run_bstar(fz_context *ctx, pdf_processor *proc) |
| 1582 | { |
| 1583 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1584 | pdf_show_path(ctx, pr, 1, 1, 1, 1); |
| 1585 | } |
| 1586 | |
| 1587 | static void pdf_run_n(fz_context *ctx, pdf_processor *proc) |
| 1588 | { |
| 1589 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1590 | pdf_show_path(ctx, pr, 0, 0, 0, 0); |
| 1591 | } |
| 1592 | |
| 1593 | /* clipping paths */ |
| 1594 | |
| 1595 | static void pdf_run_W(fz_context *ctx, pdf_processor *proc) |
| 1596 | { |
| 1597 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1598 | pr->clip = 1; |
| 1599 | pr->clip_even_odd = 0; |
| 1600 | } |
| 1601 | |
| 1602 | static void pdf_run_Wstar(fz_context *ctx, pdf_processor *proc) |
| 1603 | { |
| 1604 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1605 | pr->clip = 1; |
| 1606 | pr->clip_even_odd = 1; |
| 1607 | } |
| 1608 | |
| 1609 | /* text objects */ |
| 1610 | |
| 1611 | static void pdf_run_BT(fz_context *ctx, pdf_processor *proc) |
| 1612 | { |
| 1613 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1614 | pr->tos.tm = fz_identity; |
| 1615 | pr->tos.tlm = fz_identity; |
| 1616 | } |
| 1617 | |
| 1618 | static void pdf_run_ET(fz_context *ctx, pdf_processor *proc) |
| 1619 | { |
| 1620 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1621 | pdf_flush_text(ctx, pr); |
| 1622 | } |
| 1623 | |
| 1624 | /* text state */ |
| 1625 | |
| 1626 | static void pdf_run_Tc(fz_context *ctx, pdf_processor *proc, float charspace) |
| 1627 | { |
| 1628 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1629 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1630 | gstate->text.char_space = charspace; |
| 1631 | } |
| 1632 | |
| 1633 | static void pdf_run_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) |
| 1634 | { |
| 1635 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1636 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1637 | gstate->text.word_space = wordspace; |
| 1638 | } |
| 1639 | |
| 1640 | static void pdf_run_Tz(fz_context *ctx, pdf_processor *proc, float scale) |
| 1641 | { |
| 1642 | /* scale is as written in the file. It is 100 times smaller in |
| 1643 | * the gstate. */ |
| 1644 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1645 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1646 | gstate->text.scale = scale / 100; |
| 1647 | } |
| 1648 | |
| 1649 | static void pdf_run_TL(fz_context *ctx, pdf_processor *proc, float leading) |
| 1650 | { |
| 1651 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1652 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1653 | gstate->text.leading = leading; |
| 1654 | } |
| 1655 | |
| 1656 | static void pdf_run_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) |
| 1657 | { |
| 1658 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1659 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1660 | pdf_drop_font(ctx, gstate->text.font); |
| 1661 | gstate->text.font = pdf_keep_font(ctx, font); |
| 1662 | gstate->text.size = size; |
| 1663 | } |
| 1664 | |
| 1665 | static void pdf_run_Tr(fz_context *ctx, pdf_processor *proc, int render) |
| 1666 | { |
| 1667 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1668 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1669 | gstate->text.render = render; |
| 1670 | } |
| 1671 | |
| 1672 | static void pdf_run_Ts(fz_context *ctx, pdf_processor *proc, float rise) |
| 1673 | { |
| 1674 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1675 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1676 | gstate->text.rise = rise; |
| 1677 | } |
| 1678 | |
| 1679 | /* text positioning */ |
| 1680 | |
| 1681 | static void pdf_run_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) |
| 1682 | { |
| 1683 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1684 | pdf_tos_translate(&pr->tos, tx, ty); |
| 1685 | } |
| 1686 | |
| 1687 | static void pdf_run_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) |
| 1688 | { |
| 1689 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1690 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1691 | gstate->text.leading = -ty; |
| 1692 | pdf_tos_translate(&pr->tos, tx, ty); |
| 1693 | } |
| 1694 | |
| 1695 | static void pdf_run_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) |
| 1696 | { |
| 1697 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1698 | pdf_tos_set_matrix(&pr->tos, a, b, c, d, e, f); |
| 1699 | } |
| 1700 | |
| 1701 | static void pdf_run_Tstar(fz_context *ctx, pdf_processor *proc) |
| 1702 | { |
| 1703 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1704 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1705 | pdf_tos_newline(&pr->tos, gstate->text.leading); |
| 1706 | } |
| 1707 | |
| 1708 | /* text showing */ |
| 1709 | |
| 1710 | static void pdf_run_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *obj) |
| 1711 | { |
| 1712 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1713 | pdf_show_text(ctx, pr, obj); |
| 1714 | } |
| 1715 | |
| 1716 | static void pdf_run_Tj(fz_context *ctx, pdf_processor *proc, char *string, int string_len) |
| 1717 | { |
| 1718 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1719 | pdf_show_string(ctx, pr, (unsigned char *)string, string_len); |
| 1720 | } |
| 1721 | |
| 1722 | static void pdf_run_squote(fz_context *ctx, pdf_processor *proc, char *string, int string_len) |
| 1723 | { |
| 1724 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1725 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1726 | pdf_tos_newline(&pr->tos, gstate->text.leading); |
| 1727 | pdf_show_string(ctx, pr, (unsigned char*)string, string_len); |
| 1728 | } |
| 1729 | |
| 1730 | static void pdf_run_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *string, int string_len) |
| 1731 | { |
| 1732 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1733 | pdf_gstate *gstate = pr->gstate + pr->gtop; |
| 1734 | gstate->text.word_space = aw; |
| 1735 | gstate->text.char_space = ac; |
| 1736 | pdf_tos_newline(&pr->tos, gstate->text.leading); |
| 1737 | pdf_show_string(ctx, pr, (unsigned char*)string, string_len); |
| 1738 | } |
| 1739 | |
| 1740 | /* type 3 fonts */ |
| 1741 | |
| 1742 | static void pdf_run_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) |
| 1743 | { |
| 1744 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1745 | pr->dev->flags |= FZ_DEVFLAG_COLOR; |
| 1746 | } |
| 1747 | |
| 1748 | static void pdf_run_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) |
| 1749 | { |
| 1750 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1751 | pr->dev->flags |= FZ_DEVFLAG_MASK | FZ_DEVFLAG_BBOX_DEFINED; |
| 1752 | pr->dev->flags &= ~(FZ_DEVFLAG_FILLCOLOR_UNDEFINED | |
| 1753 | FZ_DEVFLAG_STROKECOLOR_UNDEFINED | |
| 1754 | FZ_DEVFLAG_STARTCAP_UNDEFINED | |
| 1755 | FZ_DEVFLAG_DASHCAP_UNDEFINED | |
| 1756 | FZ_DEVFLAG_ENDCAP_UNDEFINED | |
| 1757 | FZ_DEVFLAG_LINEJOIN_UNDEFINED | |
| 1758 | FZ_DEVFLAG_MITERLIMIT_UNDEFINED | |
| 1759 | FZ_DEVFLAG_LINEWIDTH_UNDEFINED); |
| 1760 | pr->dev->d1_rect.x0 = fz_min(llx, urx); |
| 1761 | pr->dev->d1_rect.y0 = fz_min(lly, ury); |
| 1762 | pr->dev->d1_rect.x1 = fz_max(llx, urx); |
| 1763 | pr->dev->d1_rect.y1 = fz_max(lly, ury); |
| 1764 | } |
| 1765 | |
| 1766 | /* color */ |
| 1767 | |
| 1768 | static void pdf_run_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) |
| 1769 | { |
| 1770 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1771 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1772 | if (!strcmp(name, "Pattern" )) |
| 1773 | pdf_set_pattern(ctx, pr, PDF_STROKE, NULL, NULL); |
| 1774 | else |
| 1775 | pdf_set_colorspace(ctx, pr, PDF_STROKE, colorspace); |
| 1776 | } |
| 1777 | |
| 1778 | static void pdf_run_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) |
| 1779 | { |
| 1780 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1781 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1782 | if (!strcmp(name, "Pattern" )) |
| 1783 | pdf_set_pattern(ctx, pr, PDF_FILL, NULL, NULL); |
| 1784 | else |
| 1785 | pdf_set_colorspace(ctx, pr, PDF_FILL, colorspace); |
| 1786 | } |
| 1787 | |
| 1788 | static void pdf_run_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) |
| 1789 | { |
| 1790 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1791 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1792 | pdf_set_color(ctx, pr, PDF_STROKE, color); |
| 1793 | } |
| 1794 | |
| 1795 | static void pdf_run_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) |
| 1796 | { |
| 1797 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1798 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1799 | pdf_set_color(ctx, pr, PDF_FILL, color); |
| 1800 | } |
| 1801 | |
| 1802 | static void pdf_run_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) |
| 1803 | { |
| 1804 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1805 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1806 | pdf_set_pattern(ctx, pr, PDF_STROKE, pat, color); |
| 1807 | } |
| 1808 | |
| 1809 | static void pdf_run_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) |
| 1810 | { |
| 1811 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1812 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1813 | pdf_set_pattern(ctx, pr, PDF_FILL, pat, color); |
| 1814 | } |
| 1815 | |
| 1816 | static void pdf_run_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 1817 | { |
| 1818 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1819 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1820 | pdf_set_shade(ctx, pr, PDF_STROKE, shade); |
| 1821 | } |
| 1822 | |
| 1823 | static void pdf_run_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 1824 | { |
| 1825 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1826 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1827 | pdf_set_shade(ctx, pr, PDF_FILL, shade); |
| 1828 | } |
| 1829 | |
| 1830 | static void pdf_run_G(fz_context *ctx, pdf_processor *proc, float g) |
| 1831 | { |
| 1832 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1833 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1834 | pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_gray(ctx)); |
| 1835 | pdf_set_color(ctx, pr, PDF_STROKE, &g); |
| 1836 | } |
| 1837 | |
| 1838 | static void pdf_run_g(fz_context *ctx, pdf_processor *proc, float g) |
| 1839 | { |
| 1840 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1841 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1842 | pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_gray(ctx)); |
| 1843 | pdf_set_color(ctx, pr, PDF_FILL, &g); |
| 1844 | } |
| 1845 | |
| 1846 | static void pdf_run_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) |
| 1847 | { |
| 1848 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1849 | float color[4] = {c, m, y, k}; |
| 1850 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1851 | pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_cmyk(ctx)); |
| 1852 | pdf_set_color(ctx, pr, PDF_STROKE, color); |
| 1853 | } |
| 1854 | |
| 1855 | static void pdf_run_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) |
| 1856 | { |
| 1857 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1858 | float color[4] = {c, m, y, k}; |
| 1859 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1860 | pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_cmyk(ctx)); |
| 1861 | pdf_set_color(ctx, pr, PDF_FILL, color); |
| 1862 | } |
| 1863 | |
| 1864 | static void pdf_run_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) |
| 1865 | { |
| 1866 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1867 | float color[3] = {r, g, b}; |
| 1868 | pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; |
| 1869 | pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_rgb(ctx)); |
| 1870 | pdf_set_color(ctx, pr, PDF_STROKE, color); |
| 1871 | } |
| 1872 | |
| 1873 | static void pdf_run_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) |
| 1874 | { |
| 1875 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1876 | float color[3] = {r, g, b}; |
| 1877 | pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; |
| 1878 | pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_rgb(ctx)); |
| 1879 | pdf_set_color(ctx, pr, PDF_FILL, color); |
| 1880 | } |
| 1881 | |
| 1882 | /* shadings, images, xobjects */ |
| 1883 | |
| 1884 | static void pdf_run_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace) |
| 1885 | { |
| 1886 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1887 | pdf_show_image(ctx, pr, image); |
| 1888 | } |
| 1889 | |
| 1890 | static void pdf_run_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 1891 | { |
| 1892 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1893 | pdf_show_shade(ctx, pr, shade); |
| 1894 | } |
| 1895 | |
| 1896 | static void pdf_run_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) |
| 1897 | { |
| 1898 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1899 | pdf_show_image(ctx, pr, image); |
| 1900 | } |
| 1901 | |
| 1902 | static void pdf_run_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj, pdf_obj *page_resources) |
| 1903 | { |
| 1904 | pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, page_resources, fz_identity, 0); |
| 1905 | } |
| 1906 | |
| 1907 | /* marked content */ |
| 1908 | |
| 1909 | static void pdf_run_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) |
| 1910 | { |
| 1911 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1912 | |
| 1913 | if (!tag) |
| 1914 | tag = "Untitled" ; |
| 1915 | |
| 1916 | fz_begin_layer(ctx, pr->dev, tag); |
| 1917 | } |
| 1918 | |
| 1919 | static void pdf_run_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) |
| 1920 | { |
| 1921 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1922 | const char *str; |
| 1923 | |
| 1924 | if (!tag) |
| 1925 | tag = "Untitled" ; |
| 1926 | |
| 1927 | str = pdf_dict_get_text_string(ctx, cooked, PDF_NAME(Name)); |
| 1928 | if (strlen(str) == 0) |
| 1929 | str = tag; |
| 1930 | |
| 1931 | fz_begin_layer(ctx, pr->dev, str); |
| 1932 | } |
| 1933 | |
| 1934 | static void pdf_run_EMC(fz_context *ctx, pdf_processor *proc) |
| 1935 | { |
| 1936 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1937 | |
| 1938 | fz_end_layer(ctx, pr->dev); |
| 1939 | } |
| 1940 | |
| 1941 | static void pdf_run_MP(fz_context *ctx, pdf_processor *proc, const char *tag) |
| 1942 | { |
| 1943 | pdf_run_BMC(ctx, proc, tag); |
| 1944 | pdf_run_EMC(ctx, proc); |
| 1945 | } |
| 1946 | |
| 1947 | static void pdf_run_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) |
| 1948 | { |
| 1949 | pdf_run_BDC(ctx, proc, tag, raw, cooked); |
| 1950 | pdf_run_EMC(ctx, proc); |
| 1951 | } |
| 1952 | |
| 1953 | /* compatibility */ |
| 1954 | |
| 1955 | static void pdf_run_BX(fz_context *ctx, pdf_processor *proc) |
| 1956 | { |
| 1957 | } |
| 1958 | |
| 1959 | static void pdf_run_EX(fz_context *ctx, pdf_processor *proc) |
| 1960 | { |
| 1961 | } |
| 1962 | |
| 1963 | static void pdf_run_END(fz_context *ctx, pdf_processor *proc) |
| 1964 | { |
| 1965 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1966 | pdf_flush_text(ctx, pr); |
| 1967 | } |
| 1968 | |
| 1969 | static void |
| 1970 | pdf_close_run_processor(fz_context *ctx, pdf_processor *proc) |
| 1971 | { |
| 1972 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1973 | |
| 1974 | while (pr->gtop) |
| 1975 | pdf_grestore(ctx, pr); |
| 1976 | |
| 1977 | while (pr->gstate[0].clip_depth) |
| 1978 | { |
| 1979 | fz_pop_clip(ctx, pr->dev); |
| 1980 | pr->gstate[0].clip_depth--; |
| 1981 | } |
| 1982 | } |
| 1983 | |
| 1984 | static void |
| 1985 | pdf_drop_run_processor(fz_context *ctx, pdf_processor *proc) |
| 1986 | { |
| 1987 | pdf_run_processor *pr = (pdf_run_processor *)proc; |
| 1988 | |
| 1989 | while (pr->gtop >= 0) |
| 1990 | { |
| 1991 | pdf_drop_gstate(ctx, &pr->gstate[pr->gtop]); |
| 1992 | pr->gtop--; |
| 1993 | } |
| 1994 | |
| 1995 | fz_drop_path(ctx, pr->path); |
| 1996 | fz_drop_text(ctx, pr->tos.text); |
| 1997 | |
| 1998 | fz_drop_default_colorspaces(ctx, pr->default_cs); |
| 1999 | |
| 2000 | fz_free(ctx, pr->gstate); |
| 2001 | } |
| 2002 | |
| 2003 | /* |
| 2004 | Create a new "run" processor. This maps |
| 2005 | from PDF operators to fz_device level calls. |
| 2006 | |
| 2007 | dev: The device to which the resulting device calls are to be |
| 2008 | sent. |
| 2009 | |
| 2010 | ctm: The initial transformation matrix to use. |
| 2011 | |
| 2012 | usage: A NULL terminated string that describes the 'usage' of |
| 2013 | this interpretation. Typically 'View', though 'Print' is also |
| 2014 | defined within the PDF reference manual, and others are possible. |
| 2015 | |
| 2016 | gstate: The initial graphics state. |
| 2017 | */ |
| 2018 | pdf_processor * |
| 2019 | pdf_new_run_processor(fz_context *ctx, fz_device *dev, fz_matrix ctm, const char *usage, pdf_gstate *gstate, fz_default_colorspaces *default_cs, fz_cookie *cookie) |
| 2020 | { |
| 2021 | pdf_run_processor *proc = pdf_new_processor(ctx, sizeof *proc); |
| 2022 | { |
| 2023 | proc->super.usage = usage; |
| 2024 | |
| 2025 | proc->super.close_processor = pdf_close_run_processor; |
| 2026 | proc->super.drop_processor = pdf_drop_run_processor; |
| 2027 | |
| 2028 | /* general graphics state */ |
| 2029 | proc->super.op_w = pdf_run_w; |
| 2030 | proc->super.op_j = pdf_run_j; |
| 2031 | proc->super.op_J = pdf_run_J; |
| 2032 | proc->super.op_M = pdf_run_M; |
| 2033 | proc->super.op_d = pdf_run_d; |
| 2034 | proc->super.op_ri = pdf_run_ri; |
| 2035 | proc->super.op_i = pdf_run_i; |
| 2036 | proc->super.op_gs_begin = pdf_run_gs_begin; |
| 2037 | proc->super.op_gs_end = pdf_run_gs_end; |
| 2038 | |
| 2039 | /* transparency graphics state */ |
| 2040 | proc->super.op_gs_BM = pdf_run_gs_BM; |
| 2041 | proc->super.op_gs_CA = pdf_run_gs_CA; |
| 2042 | proc->super.op_gs_ca = pdf_run_gs_ca; |
| 2043 | proc->super.op_gs_SMask = pdf_run_gs_SMask; |
| 2044 | |
| 2045 | /* special graphics state */ |
| 2046 | proc->super.op_q = pdf_run_q; |
| 2047 | proc->super.op_Q = pdf_run_Q; |
| 2048 | proc->super.op_cm = pdf_run_cm; |
| 2049 | |
| 2050 | /* path construction */ |
| 2051 | proc->super.op_m = pdf_run_m; |
| 2052 | proc->super.op_l = pdf_run_l; |
| 2053 | proc->super.op_c = pdf_run_c; |
| 2054 | proc->super.op_v = pdf_run_v; |
| 2055 | proc->super.op_y = pdf_run_y; |
| 2056 | proc->super.op_h = pdf_run_h; |
| 2057 | proc->super.op_re = pdf_run_re; |
| 2058 | |
| 2059 | /* path painting */ |
| 2060 | proc->super.op_S = pdf_run_S; |
| 2061 | proc->super.op_s = pdf_run_s; |
| 2062 | proc->super.op_F = pdf_run_F; |
| 2063 | proc->super.op_f = pdf_run_f; |
| 2064 | proc->super.op_fstar = pdf_run_fstar; |
| 2065 | proc->super.op_B = pdf_run_B; |
| 2066 | proc->super.op_Bstar = pdf_run_Bstar; |
| 2067 | proc->super.op_b = pdf_run_b; |
| 2068 | proc->super.op_bstar = pdf_run_bstar; |
| 2069 | proc->super.op_n = pdf_run_n; |
| 2070 | |
| 2071 | /* clipping paths */ |
| 2072 | proc->super.op_W = pdf_run_W; |
| 2073 | proc->super.op_Wstar = pdf_run_Wstar; |
| 2074 | |
| 2075 | /* text objects */ |
| 2076 | proc->super.op_BT = pdf_run_BT; |
| 2077 | proc->super.op_ET = pdf_run_ET; |
| 2078 | |
| 2079 | /* text state */ |
| 2080 | proc->super.op_Tc = pdf_run_Tc; |
| 2081 | proc->super.op_Tw = pdf_run_Tw; |
| 2082 | proc->super.op_Tz = pdf_run_Tz; |
| 2083 | proc->super.op_TL = pdf_run_TL; |
| 2084 | proc->super.op_Tf = pdf_run_Tf; |
| 2085 | proc->super.op_Tr = pdf_run_Tr; |
| 2086 | proc->super.op_Ts = pdf_run_Ts; |
| 2087 | |
| 2088 | /* text positioning */ |
| 2089 | proc->super.op_Td = pdf_run_Td; |
| 2090 | proc->super.op_TD = pdf_run_TD; |
| 2091 | proc->super.op_Tm = pdf_run_Tm; |
| 2092 | proc->super.op_Tstar = pdf_run_Tstar; |
| 2093 | |
| 2094 | /* text showing */ |
| 2095 | proc->super.op_TJ = pdf_run_TJ; |
| 2096 | proc->super.op_Tj = pdf_run_Tj; |
| 2097 | proc->super.op_squote = pdf_run_squote; |
| 2098 | proc->super.op_dquote = pdf_run_dquote; |
| 2099 | |
| 2100 | /* type 3 fonts */ |
| 2101 | proc->super.op_d0 = pdf_run_d0; |
| 2102 | proc->super.op_d1 = pdf_run_d1; |
| 2103 | |
| 2104 | /* color */ |
| 2105 | proc->super.op_CS = pdf_run_CS; |
| 2106 | proc->super.op_cs = pdf_run_cs; |
| 2107 | proc->super.op_SC_color = pdf_run_SC_color; |
| 2108 | proc->super.op_sc_color = pdf_run_sc_color; |
| 2109 | proc->super.op_SC_pattern = pdf_run_SC_pattern; |
| 2110 | proc->super.op_sc_pattern = pdf_run_sc_pattern; |
| 2111 | proc->super.op_SC_shade = pdf_run_SC_shade; |
| 2112 | proc->super.op_sc_shade = pdf_run_sc_shade; |
| 2113 | |
| 2114 | proc->super.op_G = pdf_run_G; |
| 2115 | proc->super.op_g = pdf_run_g; |
| 2116 | proc->super.op_RG = pdf_run_RG; |
| 2117 | proc->super.op_rg = pdf_run_rg; |
| 2118 | proc->super.op_K = pdf_run_K; |
| 2119 | proc->super.op_k = pdf_run_k; |
| 2120 | |
| 2121 | /* shadings, images, xobjects */ |
| 2122 | proc->super.op_sh = pdf_run_sh; |
| 2123 | if (dev->fill_image || dev->fill_image_mask || dev->clip_image_mask) |
| 2124 | { |
| 2125 | proc->super.op_BI = pdf_run_BI; |
| 2126 | proc->super.op_Do_image = pdf_run_Do_image; |
| 2127 | } |
| 2128 | proc->super.op_Do_form = pdf_run_Do_form; |
| 2129 | |
| 2130 | /* marked content */ |
| 2131 | proc->super.op_MP = pdf_run_MP; |
| 2132 | proc->super.op_DP = pdf_run_DP; |
| 2133 | proc->super.op_BMC = pdf_run_BMC; |
| 2134 | proc->super.op_BDC = pdf_run_BDC; |
| 2135 | proc->super.op_EMC = pdf_run_EMC; |
| 2136 | |
| 2137 | /* compatibility */ |
| 2138 | proc->super.op_BX = pdf_run_BX; |
| 2139 | proc->super.op_EX = pdf_run_EX; |
| 2140 | |
| 2141 | /* extgstate */ |
| 2142 | proc->super.op_gs_OP = pdf_run_gs_OP; |
| 2143 | proc->super.op_gs_op = pdf_run_gs_op; |
| 2144 | proc->super.op_gs_OPM = pdf_run_gs_OPM; |
| 2145 | proc->super.op_gs_UseBlackPtComp = pdf_run_gs_UseBlackPtComp; |
| 2146 | |
| 2147 | proc->super.op_END = pdf_run_END; |
| 2148 | } |
| 2149 | |
| 2150 | proc->dev = dev; |
| 2151 | proc->cookie = cookie; |
| 2152 | |
| 2153 | proc->default_cs = fz_keep_default_colorspaces(ctx, default_cs); |
| 2154 | |
| 2155 | proc->path = NULL; |
| 2156 | proc->clip = 0; |
| 2157 | proc->clip_even_odd = 0; |
| 2158 | |
| 2159 | proc->tos.text = NULL; |
| 2160 | proc->tos.tlm = fz_identity; |
| 2161 | proc->tos.tm = fz_identity; |
| 2162 | proc->tos.text_mode = 0; |
| 2163 | |
| 2164 | proc->gtop = -1; |
| 2165 | |
| 2166 | fz_try(ctx) |
| 2167 | { |
| 2168 | proc->path = fz_new_path(ctx); |
| 2169 | |
| 2170 | proc->gcap = 64; |
| 2171 | proc->gstate = fz_calloc(ctx, proc->gcap, sizeof(pdf_gstate)); |
| 2172 | |
| 2173 | proc->gtop = 0; |
| 2174 | pdf_init_gstate(ctx, &proc->gstate[0], ctm); |
| 2175 | |
| 2176 | if (gstate) |
| 2177 | { |
| 2178 | pdf_copy_gstate(ctx, &proc->gstate[0], gstate); |
| 2179 | proc->gstate[0].clip_depth = 0; |
| 2180 | proc->gstate[0].ctm = ctm; |
| 2181 | } |
| 2182 | } |
| 2183 | fz_catch(ctx) |
| 2184 | { |
| 2185 | pdf_drop_run_processor(ctx, (pdf_processor *) proc); |
| 2186 | fz_free(ctx, proc); |
| 2187 | fz_rethrow(ctx); |
| 2188 | } |
| 2189 | |
| 2190 | /* We need to save an extra level to allow for level 0 to be the parent gstate level. */ |
| 2191 | pdf_gsave(ctx, proc); |
| 2192 | |
| 2193 | return (pdf_processor*)proc; |
| 2194 | } |
| 2195 | |