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
13typedef struct pdf_material_s pdf_material;
14typedef struct pdf_run_processor_s pdf_run_processor;
15
16static 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
18enum
19{
20 PDF_FILL,
21 PDF_STROKE,
22};
23
24enum
25{
26 PDF_MAT_NONE,
27 PDF_MAT_COLOR,
28 PDF_MAT_PATTERN,
29 PDF_MAT_SHADE,
30};
31
32struct 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
44struct 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
68struct 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
92typedef struct softmask_save_s softmask_save;
93
94struct softmask_save_s
95{
96 pdf_obj *softmask;
97 pdf_obj *page_resources;
98 fz_matrix ctm;
99};
100
101static pdf_gstate *
102begin_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
163static void
164end_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
180static pdf_gstate *
181pdf_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
191static void
192pdf_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
202static void
203pdf_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
223static pdf_material *
224pdf_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
235static pdf_material *
236pdf_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
244static void
245pdf_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
259static void
260pdf_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
273static void
274pdf_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
287static void
288pdf_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
298static void
299pdf_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
313static void
314pdf_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
344static pdf_gstate *
345pdf_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
483static void
484pdf_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
510static void
511pdf_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
549static void
550pdf_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
691static pdf_gstate *
692pdf_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
840static void
841pdf_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
899static void
900pdf_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
911static void
912show_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
935static void
936pdf_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
950static void
951pdf_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
985static void
986pdf_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
1028static void
1029pdf_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
1040static void
1041pdf_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
1069static void
1070pdf_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
1092static void
1093pdf_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
1110static void
1111pdf_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
1133static void
1134pdf_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
1296static 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
1306static 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
1316static 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
1328static 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
1338static 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
1352static 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
1360static 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
1368static 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
1375static 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
1383static 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
1394static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness)
1395{
1396}
1397
1398static void pdf_run_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
1399{
1400}
1401
1402static void pdf_run_gs_end(fz_context *ctx, pdf_processor *proc)
1403{
1404}
1405
1406/* transparency graphics state */
1407
1408static 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
1415static 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
1422static 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
1429static 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
1461static 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
1467static 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
1473static 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
1490static 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
1496static 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}
1501static 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
1507static 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
1513static 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
1519static 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
1525static 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
1533static 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
1539static 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
1545static 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
1551static 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
1557static 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
1563static 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
1569static 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
1575static 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
1581static 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
1587static 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
1595static 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
1602static 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
1611static 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
1618static 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
1626static 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
1633static 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
1640static 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
1649static 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
1656static 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
1665static 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
1672static 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
1681static 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
1687static 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
1695static 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
1701static 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
1710static 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
1716static 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
1722static 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
1730static 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
1742static 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
1748static 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
1768static 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
1778static 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
1788static 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
1795static 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
1802static 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
1809static 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
1816static 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
1823static 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
1830static 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
1838static 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
1846static 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
1855static 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
1864static 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
1873static 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
1884static 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
1890static 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
1896static 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
1902static 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
1909static 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
1919static 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
1934static 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
1941static 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
1947static 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
1955static void pdf_run_BX(fz_context *ctx, pdf_processor *proc)
1956{
1957}
1958
1959static void pdf_run_EX(fz_context *ctx, pdf_processor *proc)
1960{
1961}
1962
1963static 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
1969static void
1970pdf_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
1984static void
1985pdf_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*/
2018pdf_processor *
2019pdf_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