Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | #include "mupdf.h" |
||
3 | |||
4 | #define TILE |
||
5 | |||
6 | typedef struct pdf_material_s pdf_material; |
||
7 | typedef struct pdf_gstate_s pdf_gstate; |
||
8 | typedef struct pdf_csi_s pdf_csi; |
||
9 | |||
10 | enum |
||
11 | { |
||
12 | PDF_FILL, |
||
13 | PDF_STROKE, |
||
14 | }; |
||
15 | |||
16 | enum |
||
17 | { |
||
18 | PDF_MAT_NONE, |
||
19 | PDF_MAT_COLOR, |
||
20 | PDF_MAT_PATTERN, |
||
21 | PDF_MAT_SHADE, |
||
22 | }; |
||
23 | |||
24 | struct pdf_material_s |
||
25 | { |
||
26 | int kind; |
||
27 | fz_colorspace *colorspace; |
||
28 | pdf_pattern *pattern; |
||
29 | fz_shade *shade; |
||
30 | float alpha; |
||
31 | float v[32]; |
||
32 | }; |
||
33 | |||
34 | struct pdf_gstate_s |
||
35 | { |
||
36 | fz_matrix ctm; |
||
37 | int clip_depth; |
||
38 | |||
39 | /* path stroking */ |
||
40 | fz_stroke_state stroke_state; |
||
41 | |||
42 | /* materials */ |
||
43 | pdf_material stroke; |
||
44 | pdf_material fill; |
||
45 | |||
46 | /* text state */ |
||
47 | float char_space; |
||
48 | float word_space; |
||
49 | float scale; |
||
50 | float leading; |
||
51 | pdf_font_desc *font; |
||
52 | float size; |
||
53 | int render; |
||
54 | float rise; |
||
55 | |||
56 | /* transparency */ |
||
57 | int blendmode; |
||
58 | pdf_xobject *softmask; |
||
59 | fz_matrix softmask_ctm; |
||
60 | float softmask_bc[FZ_MAX_COLORS]; |
||
61 | int luminosity; |
||
62 | }; |
||
63 | |||
64 | struct pdf_csi_s |
||
65 | { |
||
66 | fz_device *dev; |
||
67 | pdf_xref *xref; |
||
68 | |||
69 | /* usage mode for optional content groups */ |
||
70 | char *target; /* "View", "Print", "Export" */ |
||
71 | |||
72 | /* interpreter stack */ |
||
73 | fz_obj *obj; |
||
74 | char name[256]; |
||
75 | unsigned char string[256]; |
||
76 | int string_len; |
||
77 | float stack[32]; |
||
78 | int top; |
||
79 | |||
80 | int xbalance; |
||
81 | int in_text; |
||
82 | |||
83 | /* path object state */ |
||
84 | fz_path *path; |
||
85 | |||
86 | /* text object state */ |
||
87 | fz_text *text; |
||
88 | fz_matrix tlm; |
||
89 | fz_matrix tm; |
||
90 | int text_mode; |
||
91 | int accumulate; |
||
92 | |||
93 | /* graphics state */ |
||
94 | fz_matrix top_ctm; |
||
95 | pdf_gstate gstate[64]; |
||
96 | int gtop; |
||
97 | }; |
||
98 | |||
99 | static fz_error pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents); |
||
100 | static fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform); |
||
101 | static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what); |
||
102 | |||
103 | |||
104 | static int |
||
105 | pdf_is_hidden_ocg(fz_obj *xobj, char *target) |
||
106 | { |
||
107 | char target_state[16]; |
||
108 | fz_obj *obj; |
||
109 | |||
110 | fz_strlcpy(target_state, target, sizeof target_state); |
||
111 | fz_strlcat(target_state, "State", sizeof target_state); |
||
112 | |||
113 | obj = fz_dict_gets(xobj, "OC"); |
||
114 | obj = fz_dict_gets(obj, "OCGs"); |
||
115 | if (fz_is_array(obj)) |
||
116 | obj = fz_array_get(obj, 0); |
||
117 | obj = fz_dict_gets(obj, "Usage"); |
||
118 | obj = fz_dict_gets(obj, target); |
||
119 | obj = fz_dict_gets(obj, target_state); |
||
120 | return !strcmp(fz_to_name(obj), "OFF"); |
||
121 | } |
||
122 | |||
123 | /* |
||
124 | * Emit graphics calls to device. |
||
125 | */ |
||
126 | |||
127 | static void |
||
128 | pdf_begin_group(pdf_csi *csi, fz_rect bbox) |
||
129 | { |
||
130 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
131 | fz_error error; |
||
132 | |||
133 | if (gstate->softmask) |
||
134 | { |
||
135 | pdf_xobject *softmask = gstate->softmask; |
||
136 | fz_rect bbox = fz_transform_rect(gstate->softmask_ctm, softmask->bbox); |
||
137 | fz_matrix save_ctm = gstate->ctm; |
||
138 | |||
139 | gstate->softmask = NULL; |
||
140 | gstate->ctm = gstate->softmask_ctm; |
||
141 | |||
142 | fz_begin_mask(csi->dev, bbox, gstate->luminosity, |
||
143 | softmask->colorspace, gstate->softmask_bc); |
||
144 | error = pdf_run_xobject(csi, NULL, softmask, fz_identity); |
||
145 | if (error) |
||
146 | fz_catch(error, "cannot run softmask"); |
||
147 | fz_end_mask(csi->dev); |
||
148 | |||
149 | gstate->softmask = softmask; |
||
150 | gstate->ctm = save_ctm; |
||
151 | } |
||
152 | |||
153 | if (gstate->blendmode) |
||
154 | fz_begin_group(csi->dev, bbox, 1, 0, gstate->blendmode, 1); |
||
155 | } |
||
156 | |||
157 | static void |
||
158 | pdf_end_group(pdf_csi *csi) |
||
159 | { |
||
160 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
161 | |||
162 | if (gstate->blendmode) |
||
163 | fz_end_group(csi->dev); |
||
164 | |||
165 | if (gstate->softmask) |
||
166 | fz_pop_clip(csi->dev); |
||
167 | } |
||
168 | |||
169 | static void |
||
170 | pdf_show_shade(pdf_csi *csi, fz_shade *shd) |
||
171 | { |
||
172 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
173 | fz_rect bbox; |
||
174 | |||
175 | bbox = fz_bound_shade(shd, gstate->ctm); |
||
176 | |||
177 | pdf_begin_group(csi, bbox); |
||
178 | |||
179 | fz_fill_shade(csi->dev, shd, gstate->ctm, gstate->fill.alpha); |
||
180 | |||
181 | pdf_end_group(csi); |
||
182 | } |
||
183 | |||
184 | static void |
||
185 | pdf_show_image(pdf_csi *csi, fz_pixmap *image) |
||
186 | { |
||
187 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
188 | fz_rect bbox; |
||
189 | |||
190 | bbox = fz_transform_rect(gstate->ctm, fz_unit_rect); |
||
191 | |||
192 | if (image->mask) |
||
193 | { |
||
194 | /* apply blend group even though we skip the softmask */ |
||
195 | if (gstate->blendmode) |
||
196 | fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1); |
||
197 | fz_clip_image_mask(csi->dev, image->mask, &bbox, gstate->ctm); |
||
198 | } |
||
199 | else |
||
200 | pdf_begin_group(csi, bbox); |
||
201 | |||
202 | if (!image->colorspace) |
||
203 | { |
||
204 | |||
205 | switch (gstate->fill.kind) |
||
206 | { |
||
207 | case PDF_MAT_NONE: |
||
208 | break; |
||
209 | case PDF_MAT_COLOR: |
||
210 | fz_fill_image_mask(csi->dev, image, gstate->ctm, |
||
211 | gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha); |
||
212 | break; |
||
213 | case PDF_MAT_PATTERN: |
||
214 | if (gstate->fill.pattern) |
||
215 | { |
||
216 | fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm); |
||
217 | pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL); |
||
218 | fz_pop_clip(csi->dev); |
||
219 | } |
||
220 | break; |
||
221 | case PDF_MAT_SHADE: |
||
222 | if (gstate->fill.shade) |
||
223 | { |
||
224 | fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm); |
||
225 | fz_fill_shade(csi->dev, gstate->fill.shade, gstate->ctm, gstate->fill.alpha); |
||
226 | fz_pop_clip(csi->dev); |
||
227 | } |
||
228 | break; |
||
229 | } |
||
230 | } |
||
231 | else |
||
232 | { |
||
233 | fz_fill_image(csi->dev, image, gstate->ctm, gstate->fill.alpha); |
||
234 | } |
||
235 | |||
236 | if (image->mask) |
||
237 | { |
||
238 | fz_pop_clip(csi->dev); |
||
239 | if (gstate->blendmode) |
||
240 | fz_end_group(csi->dev); |
||
241 | } |
||
242 | else |
||
243 | pdf_end_group(csi); |
||
244 | } |
||
245 | |||
246 | static void pdf_show_clip(pdf_csi *csi, int even_odd) |
||
247 | { |
||
248 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
249 | |||
250 | gstate->clip_depth++; |
||
251 | fz_clip_path(csi->dev, csi->path, NULL, even_odd, gstate->ctm); |
||
252 | } |
||
253 | |||
254 | static void |
||
255 | pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd) |
||
256 | { |
||
257 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
258 | fz_path *path; |
||
259 | fz_rect bbox; |
||
260 | |||
261 | path = csi->path; |
||
262 | csi->path = fz_new_path(); |
||
263 | |||
264 | if (doclose) |
||
265 | fz_closepath(path); |
||
266 | |||
267 | if (dostroke) |
||
268 | bbox = fz_bound_path(path, &gstate->stroke_state, gstate->ctm); |
||
269 | else |
||
270 | bbox = fz_bound_path(path, NULL, gstate->ctm); |
||
271 | |||
272 | if (dofill || dostroke) |
||
273 | pdf_begin_group(csi, bbox); |
||
274 | |||
275 | if (dofill) |
||
276 | { |
||
277 | switch (gstate->fill.kind) |
||
278 | { |
||
279 | case PDF_MAT_NONE: |
||
280 | break; |
||
281 | case PDF_MAT_COLOR: |
||
282 | fz_fill_path(csi->dev, path, even_odd, gstate->ctm, |
||
283 | gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha); |
||
284 | break; |
||
285 | case PDF_MAT_PATTERN: |
||
286 | if (gstate->fill.pattern) |
||
287 | { |
||
288 | fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm); |
||
289 | pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL); |
||
290 | fz_pop_clip(csi->dev); |
||
291 | } |
||
292 | break; |
||
293 | case PDF_MAT_SHADE: |
||
294 | if (gstate->fill.shade) |
||
295 | { |
||
296 | fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm); |
||
297 | fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha); |
||
298 | fz_pop_clip(csi->dev); |
||
299 | } |
||
300 | break; |
||
301 | } |
||
302 | } |
||
303 | |||
304 | if (dostroke) |
||
305 | { |
||
306 | switch (gstate->stroke.kind) |
||
307 | { |
||
308 | case PDF_MAT_NONE: |
||
309 | break; |
||
310 | case PDF_MAT_COLOR: |
||
311 | fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm, |
||
312 | gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha); |
||
313 | break; |
||
314 | case PDF_MAT_PATTERN: |
||
315 | if (gstate->stroke.pattern) |
||
316 | { |
||
317 | fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm); |
||
318 | pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL); |
||
319 | fz_pop_clip(csi->dev); |
||
320 | } |
||
321 | break; |
||
322 | case PDF_MAT_SHADE: |
||
323 | if (gstate->stroke.shade) |
||
324 | { |
||
325 | fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm); |
||
326 | fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha); |
||
327 | fz_pop_clip(csi->dev); |
||
328 | } |
||
329 | break; |
||
330 | } |
||
331 | } |
||
332 | |||
333 | if (dofill || dostroke) |
||
334 | pdf_end_group(csi); |
||
335 | |||
336 | fz_free_path(path); |
||
337 | } |
||
338 | |||
339 | /* |
||
340 | * Assemble and emit text |
||
341 | */ |
||
342 | |||
343 | static void |
||
344 | pdf_flush_text(pdf_csi *csi) |
||
345 | { |
||
346 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
347 | fz_text *text; |
||
348 | int dofill = 0; |
||
349 | int dostroke = 0; |
||
350 | int doclip = 0; |
||
351 | int doinvisible = 0; |
||
352 | fz_rect bbox; |
||
353 | |||
354 | if (!csi->text) |
||
355 | return; |
||
356 | text = csi->text; |
||
357 | csi->text = NULL; |
||
358 | |||
359 | dofill = dostroke = doclip = doinvisible = 0; |
||
360 | switch (csi->text_mode) |
||
361 | { |
||
362 | case 0: dofill = 1; break; |
||
363 | case 1: dostroke = 1; break; |
||
364 | case 2: dofill = dostroke = 1; break; |
||
365 | case 3: doinvisible = 1; break; |
||
366 | case 4: dofill = doclip = 1; break; |
||
367 | case 5: dostroke = doclip = 1; break; |
||
368 | case 6: dofill = dostroke = doclip = 1; break; |
||
369 | case 7: doclip = 1; break; |
||
370 | } |
||
371 | |||
372 | bbox = fz_bound_text(text, gstate->ctm); |
||
373 | |||
374 | pdf_begin_group(csi, bbox); |
||
375 | |||
376 | if (doinvisible) |
||
377 | fz_ignore_text(csi->dev, text, gstate->ctm); |
||
378 | |||
379 | if (doclip) |
||
380 | { |
||
381 | if (csi->accumulate < 2) |
||
382 | gstate->clip_depth++; |
||
383 | fz_clip_text(csi->dev, text, gstate->ctm, csi->accumulate); |
||
384 | csi->accumulate = 2; |
||
385 | } |
||
386 | |||
387 | if (dofill) |
||
388 | { |
||
389 | switch (gstate->fill.kind) |
||
390 | { |
||
391 | case PDF_MAT_NONE: |
||
392 | break; |
||
393 | case PDF_MAT_COLOR: |
||
394 | fz_fill_text(csi->dev, text, gstate->ctm, |
||
395 | gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha); |
||
396 | break; |
||
397 | case PDF_MAT_PATTERN: |
||
398 | if (gstate->fill.pattern) |
||
399 | { |
||
400 | fz_clip_text(csi->dev, text, gstate->ctm, 0); |
||
401 | pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL); |
||
402 | fz_pop_clip(csi->dev); |
||
403 | } |
||
404 | break; |
||
405 | case PDF_MAT_SHADE: |
||
406 | if (gstate->fill.shade) |
||
407 | { |
||
408 | fz_clip_text(csi->dev, text, gstate->ctm, 0); |
||
409 | fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha); |
||
410 | fz_pop_clip(csi->dev); |
||
411 | } |
||
412 | break; |
||
413 | } |
||
414 | } |
||
415 | |||
416 | if (dostroke) |
||
417 | { |
||
418 | switch (gstate->stroke.kind) |
||
419 | { |
||
420 | case PDF_MAT_NONE: |
||
421 | break; |
||
422 | case PDF_MAT_COLOR: |
||
423 | fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm, |
||
424 | gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha); |
||
425 | break; |
||
426 | case PDF_MAT_PATTERN: |
||
427 | if (gstate->stroke.pattern) |
||
428 | { |
||
429 | fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm); |
||
430 | pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL); |
||
431 | fz_pop_clip(csi->dev); |
||
432 | } |
||
433 | break; |
||
434 | case PDF_MAT_SHADE: |
||
435 | if (gstate->stroke.shade) |
||
436 | { |
||
437 | fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm); |
||
438 | fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha); |
||
439 | fz_pop_clip(csi->dev); |
||
440 | } |
||
441 | break; |
||
442 | } |
||
443 | } |
||
444 | |||
445 | pdf_end_group(csi); |
||
446 | |||
447 | fz_free_text(text); |
||
448 | } |
||
449 | |||
450 | static void |
||
451 | pdf_show_char(pdf_csi *csi, int cid) |
||
452 | { |
||
453 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
454 | pdf_font_desc *fontdesc = gstate->font; |
||
455 | fz_matrix tsm, trm; |
||
456 | float w0, w1, tx, ty; |
||
457 | pdf_hmtx h; |
||
458 | pdf_vmtx v; |
||
459 | int gid; |
||
460 | int ucsbuf[8]; |
||
461 | int ucslen; |
||
462 | int i; |
||
463 | |||
464 | tsm.a = gstate->size * gstate->scale; |
||
465 | tsm.b = 0; |
||
466 | tsm.c = 0; |
||
467 | tsm.d = gstate->size; |
||
468 | tsm.e = 0; |
||
469 | tsm.f = gstate->rise; |
||
470 | |||
471 | ucslen = 0; |
||
472 | if (fontdesc->to_unicode) |
||
473 | ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf); |
||
474 | if (ucslen == 0 && cid < fontdesc->cid_to_ucs_len) |
||
475 | { |
||
476 | ucsbuf[0] = fontdesc->cid_to_ucs[cid]; |
||
477 | ucslen = 1; |
||
478 | } |
||
479 | if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0)) |
||
480 | { |
||
481 | ucsbuf[0] = '?'; |
||
482 | ucslen = 1; |
||
483 | } |
||
484 | |||
485 | gid = pdf_font_cid_to_gid(fontdesc, cid); |
||
486 | |||
487 | if (fontdesc->wmode == 1) |
||
488 | { |
||
489 | v = pdf_get_vmtx(fontdesc, cid); |
||
490 | tsm.e -= v.x * gstate->size * 0.001f; |
||
491 | tsm.f -= v.y * gstate->size * 0.001f; |
||
492 | } |
||
493 | |||
494 | trm = fz_concat(tsm, csi->tm); |
||
495 | |||
496 | /* flush buffered text if face or matrix or rendermode has changed */ |
||
497 | if (!csi->text || |
||
498 | fontdesc->font != csi->text->font || |
||
499 | fontdesc->wmode != csi->text->wmode || |
||
500 | fabsf(trm.a - csi->text->trm.a) > FLT_EPSILON || |
||
501 | fabsf(trm.b - csi->text->trm.b) > FLT_EPSILON || |
||
502 | fabsf(trm.c - csi->text->trm.c) > FLT_EPSILON || |
||
503 | fabsf(trm.d - csi->text->trm.d) > FLT_EPSILON || |
||
504 | gstate->render != csi->text_mode) |
||
505 | { |
||
506 | pdf_flush_text(csi); |
||
507 | |||
508 | csi->text = fz_new_text(fontdesc->font, trm, fontdesc->wmode); |
||
509 | csi->text->trm.e = 0; |
||
510 | csi->text->trm.f = 0; |
||
511 | csi->text_mode = gstate->render; |
||
512 | } |
||
513 | |||
514 | /* add glyph to textobject */ |
||
515 | fz_add_text(csi->text, gid, ucsbuf[0], trm.e, trm.f); |
||
516 | |||
517 | /* add filler glyphs for one-to-many unicode mapping */ |
||
518 | for (i = 1; i < ucslen; i++) |
||
519 | fz_add_text(csi->text, -1, ucsbuf[i], trm.e, trm.f); |
||
520 | |||
521 | if (fontdesc->wmode == 0) |
||
522 | { |
||
523 | h = pdf_get_hmtx(fontdesc, cid); |
||
524 | w0 = h.w * 0.001f; |
||
525 | tx = (w0 * gstate->size + gstate->char_space) * gstate->scale; |
||
526 | csi->tm = fz_concat(fz_translate(tx, 0), csi->tm); |
||
527 | } |
||
528 | |||
529 | if (fontdesc->wmode == 1) |
||
530 | { |
||
531 | w1 = v.w * 0.001f; |
||
532 | ty = w1 * gstate->size + gstate->char_space; |
||
533 | csi->tm = fz_concat(fz_translate(0, ty), csi->tm); |
||
534 | } |
||
535 | } |
||
536 | |||
537 | static void |
||
538 | pdf_show_space(pdf_csi *csi, float tadj) |
||
539 | { |
||
540 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
541 | pdf_font_desc *fontdesc = gstate->font; |
||
542 | |||
543 | if (!fontdesc) |
||
544 | { |
||
545 | fz_warn("cannot draw text since font and size not set"); |
||
546 | return; |
||
547 | } |
||
548 | |||
549 | if (fontdesc->wmode == 0) |
||
550 | csi->tm = fz_concat(fz_translate(tadj * gstate->scale, 0), csi->tm); |
||
551 | else |
||
552 | csi->tm = fz_concat(fz_translate(0, tadj), csi->tm); |
||
553 | } |
||
554 | |||
555 | static void |
||
556 | pdf_show_string(pdf_csi *csi, unsigned char *buf, int len) |
||
557 | { |
||
558 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
559 | pdf_font_desc *fontdesc = gstate->font; |
||
560 | unsigned char *end = buf + len; |
||
561 | int cpt, cid; |
||
562 | |||
563 | if (!fontdesc) |
||
564 | { |
||
565 | fz_warn("cannot draw text since font and size not set"); |
||
566 | return; |
||
567 | } |
||
568 | |||
569 | while (buf < end) |
||
570 | { |
||
571 | buf = pdf_decode_cmap(fontdesc->encoding, buf, &cpt); |
||
572 | cid = pdf_lookup_cmap(fontdesc->encoding, cpt); |
||
573 | if (cid >= 0) |
||
574 | pdf_show_char(csi, cid); |
||
575 | else |
||
576 | fz_warn("cannot encode character with code point %#x", cpt); |
||
577 | if (cpt == 32) |
||
578 | pdf_show_space(csi, gstate->word_space); |
||
579 | } |
||
580 | } |
||
581 | |||
582 | static void |
||
583 | pdf_show_text(pdf_csi *csi, fz_obj *text) |
||
584 | { |
||
585 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
586 | int i; |
||
587 | |||
588 | if (fz_is_array(text)) |
||
589 | { |
||
590 | for (i = 0; i < fz_array_len(text); i++) |
||
591 | { |
||
592 | fz_obj *item = fz_array_get(text, i); |
||
593 | if (fz_is_string(item)) |
||
594 | pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item)); |
||
595 | else |
||
596 | pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f); |
||
597 | } |
||
598 | } |
||
599 | else if (fz_is_string(text)) |
||
600 | { |
||
601 | pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text)); |
||
602 | } |
||
603 | } |
||
604 | |||
605 | /* |
||
606 | * Interpreter and graphics state stack. |
||
607 | */ |
||
608 | |||
609 | static void |
||
610 | pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm) |
||
611 | { |
||
612 | gs->ctm = ctm; |
||
613 | gs->clip_depth = 0; |
||
614 | |||
615 | gs->stroke_state.start_cap = 0; |
||
616 | gs->stroke_state.dash_cap = 0; |
||
617 | gs->stroke_state.end_cap = 0; |
||
618 | gs->stroke_state.linejoin = 0; |
||
619 | gs->stroke_state.linewidth = 1; |
||
620 | gs->stroke_state.miterlimit = 10; |
||
621 | gs->stroke_state.dash_phase = 0; |
||
622 | gs->stroke_state.dash_len = 0; |
||
623 | memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list)); |
||
624 | |||
625 | gs->stroke.kind = PDF_MAT_COLOR; |
||
626 | gs->stroke.colorspace = fz_keep_colorspace(fz_device_gray); |
||
627 | gs->stroke.v[0] = 0; |
||
628 | gs->stroke.pattern = NULL; |
||
629 | gs->stroke.shade = NULL; |
||
630 | gs->stroke.alpha = 1; |
||
631 | |||
632 | gs->fill.kind = PDF_MAT_COLOR; |
||
633 | gs->fill.colorspace = fz_keep_colorspace(fz_device_gray); |
||
634 | gs->fill.v[0] = 0; |
||
635 | gs->fill.pattern = NULL; |
||
636 | gs->fill.shade = NULL; |
||
637 | gs->fill.alpha = 1; |
||
638 | |||
639 | gs->char_space = 0; |
||
640 | gs->word_space = 0; |
||
641 | gs->scale = 1; |
||
642 | gs->leading = 0; |
||
643 | gs->font = NULL; |
||
644 | gs->size = -1; |
||
645 | gs->render = 0; |
||
646 | gs->rise = 0; |
||
647 | |||
648 | gs->blendmode = 0; |
||
649 | gs->softmask = NULL; |
||
650 | gs->softmask_ctm = fz_identity; |
||
651 | gs->luminosity = 0; |
||
652 | } |
||
653 | |||
654 | static pdf_csi * |
||
655 | pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target) |
||
656 | { |
||
657 | pdf_csi *csi; |
||
658 | |||
659 | csi = fz_malloc(sizeof(pdf_csi)); |
||
660 | csi->xref = xref; |
||
661 | csi->dev = dev; |
||
662 | csi->target = target; |
||
663 | |||
664 | csi->top = 0; |
||
665 | csi->obj = NULL; |
||
666 | csi->name[0] = 0; |
||
667 | csi->string_len = 0; |
||
668 | memset(csi->stack, 0, sizeof csi->stack); |
||
669 | |||
670 | csi->xbalance = 0; |
||
671 | csi->in_text = 0; |
||
672 | |||
673 | csi->path = fz_new_path(); |
||
674 | |||
675 | csi->text = NULL; |
||
676 | csi->tlm = fz_identity; |
||
677 | csi->tm = fz_identity; |
||
678 | csi->text_mode = 0; |
||
679 | csi->accumulate = 1; |
||
680 | |||
681 | csi->top_ctm = ctm; |
||
682 | pdf_init_gstate(&csi->gstate[0], ctm); |
||
683 | csi->gtop = 0; |
||
684 | |||
685 | return csi; |
||
686 | } |
||
687 | |||
688 | static void |
||
689 | pdf_clear_stack(pdf_csi *csi) |
||
690 | { |
||
691 | int i; |
||
692 | |||
693 | if (csi->obj) |
||
694 | fz_drop_obj(csi->obj); |
||
695 | csi->obj = NULL; |
||
696 | |||
697 | csi->name[0] = 0; |
||
698 | csi->string_len = 0; |
||
699 | for (i = 0; i < csi->top; i++) |
||
700 | csi->stack[i] = 0; |
||
701 | |||
702 | csi->top = 0; |
||
703 | } |
||
704 | |||
705 | static pdf_material * |
||
706 | pdf_keep_material(pdf_material *mat) |
||
707 | { |
||
708 | if (mat->colorspace) |
||
709 | fz_keep_colorspace(mat->colorspace); |
||
710 | if (mat->pattern) |
||
711 | pdf_keep_pattern(mat->pattern); |
||
712 | if (mat->shade) |
||
713 | fz_keep_shade(mat->shade); |
||
714 | return mat; |
||
715 | } |
||
716 | |||
717 | static pdf_material * |
||
718 | pdf_drop_material(pdf_material *mat) |
||
719 | { |
||
720 | if (mat->colorspace) |
||
721 | fz_drop_colorspace(mat->colorspace); |
||
722 | if (mat->pattern) |
||
723 | pdf_drop_pattern(mat->pattern); |
||
724 | if (mat->shade) |
||
725 | fz_drop_shade(mat->shade); |
||
726 | return mat; |
||
727 | } |
||
728 | |||
729 | static void |
||
730 | pdf_gsave(pdf_csi *csi) |
||
731 | { |
||
732 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
733 | |||
734 | if (csi->gtop == nelem(csi->gstate) - 1) |
||
735 | { |
||
736 | fz_warn("gstate overflow in content stream"); |
||
737 | return; |
||
738 | } |
||
739 | |||
740 | memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate)); |
||
741 | |||
742 | csi->gtop ++; |
||
743 | |||
744 | pdf_keep_material(&gs->stroke); |
||
745 | pdf_keep_material(&gs->fill); |
||
746 | if (gs->font) |
||
747 | pdf_keep_font(gs->font); |
||
748 | if (gs->softmask) |
||
749 | pdf_keep_xobject(gs->softmask); |
||
750 | } |
||
751 | |||
752 | static void |
||
753 | pdf_grestore(pdf_csi *csi) |
||
754 | { |
||
755 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
756 | int clip_depth = gs->clip_depth; |
||
757 | |||
758 | if (csi->gtop == 0) |
||
759 | { |
||
760 | fz_warn("gstate underflow in content stream"); |
||
761 | return; |
||
762 | } |
||
763 | |||
764 | pdf_drop_material(&gs->stroke); |
||
765 | pdf_drop_material(&gs->fill); |
||
766 | if (gs->font) |
||
767 | pdf_drop_font(gs->font); |
||
768 | if (gs->softmask) |
||
769 | pdf_drop_xobject(gs->softmask); |
||
770 | |||
771 | csi->gtop --; |
||
772 | |||
773 | gs = csi->gstate + csi->gtop; |
||
774 | while (clip_depth > gs->clip_depth) |
||
775 | { |
||
776 | fz_pop_clip(csi->dev); |
||
777 | clip_depth--; |
||
778 | } |
||
779 | } |
||
780 | |||
781 | static void |
||
782 | pdf_free_csi(pdf_csi *csi) |
||
783 | { |
||
784 | while (csi->gtop) |
||
785 | pdf_grestore(csi); |
||
786 | |||
787 | pdf_drop_material(&csi->gstate[0].fill); |
||
788 | pdf_drop_material(&csi->gstate[0].stroke); |
||
789 | if (csi->gstate[0].font) |
||
790 | pdf_drop_font(csi->gstate[0].font); |
||
791 | if (csi->gstate[0].softmask) |
||
792 | pdf_drop_xobject(csi->gstate[0].softmask); |
||
793 | |||
794 | while (csi->gstate[0].clip_depth--) |
||
795 | fz_pop_clip(csi->dev); |
||
796 | |||
797 | if (csi->path) fz_free_path(csi->path); |
||
798 | if (csi->text) fz_free_text(csi->text); |
||
799 | |||
800 | pdf_clear_stack(csi); |
||
801 | |||
802 | fz_free(csi); |
||
803 | } |
||
804 | |||
805 | /* |
||
806 | * Material state |
||
807 | */ |
||
808 | |||
809 | static void |
||
810 | pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *colorspace) |
||
811 | { |
||
812 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
813 | pdf_material *mat; |
||
814 | |||
815 | pdf_flush_text(csi); |
||
816 | |||
817 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
||
818 | |||
819 | fz_drop_colorspace(mat->colorspace); |
||
820 | |||
821 | mat->kind = PDF_MAT_COLOR; |
||
822 | mat->colorspace = fz_keep_colorspace(colorspace); |
||
823 | |||
824 | mat->v[0] = 0; |
||
825 | mat->v[1] = 0; |
||
826 | mat->v[2] = 0; |
||
827 | mat->v[3] = 1; |
||
828 | } |
||
829 | |||
830 | static void |
||
831 | pdf_set_color(pdf_csi *csi, int what, float *v) |
||
832 | { |
||
833 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
834 | pdf_material *mat; |
||
835 | int i; |
||
836 | |||
837 | pdf_flush_text(csi); |
||
838 | |||
839 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
||
840 | |||
841 | switch (mat->kind) |
||
842 | { |
||
843 | case PDF_MAT_PATTERN: |
||
844 | case PDF_MAT_COLOR: |
||
845 | if (!strcmp(mat->colorspace->name, "Lab")) |
||
846 | { |
||
847 | mat->v[0] = v[0] / 100; |
||
848 | mat->v[1] = (v[1] + 100) / 200; |
||
849 | mat->v[2] = (v[2] + 100) / 200; |
||
850 | } |
||
851 | for (i = 0; i < mat->colorspace->n; i++) |
||
852 | mat->v[i] = v[i]; |
||
853 | break; |
||
854 | default: |
||
855 | fz_warn("color incompatible with material"); |
||
856 | } |
||
857 | } |
||
858 | |||
859 | static void |
||
860 | pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade) |
||
861 | { |
||
862 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
863 | pdf_material *mat; |
||
864 | |||
865 | pdf_flush_text(csi); |
||
866 | |||
867 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
||
868 | |||
869 | if (mat->shade) |
||
870 | fz_drop_shade(mat->shade); |
||
871 | |||
872 | mat->kind = PDF_MAT_SHADE; |
||
873 | mat->shade = fz_keep_shade(shade); |
||
874 | } |
||
875 | |||
876 | static void |
||
877 | pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v) |
||
878 | { |
||
879 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
880 | pdf_material *mat; |
||
881 | |||
882 | pdf_flush_text(csi); |
||
883 | |||
884 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
||
885 | |||
886 | if (mat->pattern) |
||
887 | pdf_drop_pattern(mat->pattern); |
||
888 | |||
889 | mat->kind = PDF_MAT_PATTERN; |
||
890 | if (pat) |
||
891 | mat->pattern = pdf_keep_pattern(pat); |
||
892 | else |
||
893 | mat->pattern = NULL; |
||
894 | |||
895 | if (v) |
||
896 | pdf_set_color(csi, what, v); |
||
897 | } |
||
898 | |||
899 | static void |
||
900 | pdf_unset_pattern(pdf_csi *csi, int what) |
||
901 | { |
||
902 | pdf_gstate *gs = csi->gstate + csi->gtop; |
||
903 | pdf_material *mat; |
||
904 | mat = what == PDF_FILL ? &gs->fill : &gs->stroke; |
||
905 | if (mat->kind == PDF_MAT_PATTERN) |
||
906 | { |
||
907 | if (mat->pattern) |
||
908 | pdf_drop_pattern(mat->pattern); |
||
909 | mat->pattern = NULL; |
||
910 | mat->kind = PDF_MAT_COLOR; |
||
911 | } |
||
912 | } |
||
913 | |||
914 | /* |
||
915 | * Patterns, XObjects and ExtGState |
||
916 | */ |
||
917 | |||
918 | static void |
||
919 | pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what) |
||
920 | { |
||
921 | pdf_gstate *gstate; |
||
922 | fz_matrix ptm, invptm; |
||
923 | fz_matrix oldtopctm; |
||
924 | fz_error error; |
||
925 | int x0, y0, x1, y1; |
||
926 | int oldtop; |
||
927 | |||
928 | pdf_gsave(csi); |
||
929 | gstate = csi->gstate + csi->gtop; |
||
930 | |||
931 | if (pat->ismask) |
||
932 | { |
||
933 | pdf_unset_pattern(csi, PDF_FILL); |
||
934 | pdf_unset_pattern(csi, PDF_STROKE); |
||
935 | if (what == PDF_FILL) |
||
936 | { |
||
937 | pdf_drop_material(&gstate->stroke); |
||
938 | pdf_keep_material(&gstate->fill); |
||
939 | gstate->stroke = gstate->fill; |
||
940 | } |
||
941 | if (what == PDF_STROKE) |
||
942 | { |
||
943 | pdf_drop_material(&gstate->fill); |
||
944 | pdf_keep_material(&gstate->stroke); |
||
945 | gstate->fill = gstate->stroke; |
||
946 | } |
||
947 | } |
||
948 | else |
||
949 | { |
||
950 | // TODO: unset only the current fill/stroke or both? |
||
951 | pdf_unset_pattern(csi, what); |
||
952 | } |
||
953 | |||
954 | /* don't apply softmasks to objects in the pattern as well */ |
||
955 | if (gstate->softmask) |
||
956 | { |
||
957 | pdf_drop_xobject(gstate->softmask); |
||
958 | gstate->softmask = NULL; |
||
959 | } |
||
960 | |||
961 | ptm = fz_concat(pat->matrix, csi->top_ctm); |
||
962 | invptm = fz_invert_matrix(ptm); |
||
963 | |||
964 | /* patterns are painted using the ctm in effect at the beginning of the content stream */ |
||
965 | /* get bbox of shape in pattern space for stamping */ |
||
966 | area = fz_transform_rect(invptm, area); |
||
967 | x0 = floorf(area.x0 / pat->xstep); |
||
968 | y0 = floorf(area.y0 / pat->ystep); |
||
969 | x1 = ceilf(area.x1 / pat->xstep); |
||
970 | y1 = ceilf(area.y1 / pat->ystep); |
||
971 | |||
972 | oldtopctm = csi->top_ctm; |
||
973 | oldtop = csi->gtop; |
||
974 | |||
975 | #ifdef TILE |
||
976 | if ((x1 - x0) * (y1 - y0) > 0) |
||
977 | { |
||
978 | fz_begin_tile(csi->dev, area, pat->bbox, pat->xstep, pat->ystep, ptm); |
||
979 | gstate->ctm = ptm; |
||
980 | csi->top_ctm = gstate->ctm; |
||
981 | pdf_gsave(csi); |
||
982 | error = pdf_run_buffer(csi, pat->resources, pat->contents); |
||
983 | if (error) |
||
984 | fz_catch(error, "cannot render pattern tile"); |
||
985 | pdf_grestore(csi); |
||
986 | while (oldtop < csi->gtop) |
||
987 | pdf_grestore(csi); |
||
988 | fz_end_tile(csi->dev); |
||
989 | } |
||
990 | #else |
||
991 | { |
||
992 | int x, y; |
||
993 | for (y = y0; y < y1; y++) |
||
994 | { |
||
995 | for (x = x0; x < x1; x++) |
||
996 | { |
||
997 | gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm); |
||
998 | csi->top_ctm = gstate->ctm; |
||
999 | error = pdf_run_csi_buffer(csi, pat->resources, pat->contents); |
||
1000 | while (oldtop < csi->gtop) |
||
1001 | pdf_grestore(csi); |
||
1002 | if (error) |
||
1003 | { |
||
1004 | fz_catch(error, "cannot render pattern tile"); |
||
1005 | goto cleanup; |
||
1006 | } |
||
1007 | } |
||
1008 | } |
||
1009 | } |
||
1010 | cleanup: |
||
1011 | #endif |
||
1012 | |||
1013 | csi->top_ctm = oldtopctm; |
||
1014 | |||
1015 | pdf_grestore(csi); |
||
1016 | } |
||
1017 | |||
1018 | static fz_error |
||
1019 | pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform) |
||
1020 | { |
||
1021 | fz_error error; |
||
1022 | pdf_gstate *gstate; |
||
1023 | fz_matrix oldtopctm; |
||
1024 | int oldtop; |
||
1025 | int popmask; |
||
1026 | |||
1027 | pdf_gsave(csi); |
||
1028 | |||
1029 | gstate = csi->gstate + csi->gtop; |
||
1030 | oldtop = csi->gtop; |
||
1031 | popmask = 0; |
||
1032 | |||
1033 | /* apply xobject's transform matrix */ |
||
1034 | transform = fz_concat(xobj->matrix, transform); |
||
1035 | gstate->ctm = fz_concat(transform, gstate->ctm); |
||
1036 | |||
1037 | /* apply soft mask, create transparency group and reset state */ |
||
1038 | if (xobj->transparency) |
||
1039 | { |
||
1040 | if (gstate->softmask) |
||
1041 | { |
||
1042 | pdf_xobject *softmask = gstate->softmask; |
||
1043 | fz_rect bbox = fz_transform_rect(gstate->ctm, xobj->bbox); |
||
1044 | |||
1045 | gstate->softmask = NULL; |
||
1046 | popmask = 1; |
||
1047 | |||
1048 | fz_begin_mask(csi->dev, bbox, gstate->luminosity, |
||
1049 | softmask->colorspace, gstate->softmask_bc); |
||
1050 | error = pdf_run_xobject(csi, resources, softmask, fz_identity); |
||
1051 | if (error) |
||
1052 | return fz_rethrow(error, "cannot run softmask"); |
||
1053 | fz_end_mask(csi->dev); |
||
1054 | |||
1055 | pdf_drop_xobject(softmask); |
||
1056 | } |
||
1057 | |||
1058 | fz_begin_group(csi->dev, |
||
1059 | fz_transform_rect(gstate->ctm, xobj->bbox), |
||
1060 | xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha); |
||
1061 | |||
1062 | gstate->blendmode = 0; |
||
1063 | gstate->stroke.alpha = 1; |
||
1064 | gstate->fill.alpha = 1; |
||
1065 | } |
||
1066 | |||
1067 | /* clip to the bounds */ |
||
1068 | |||
1069 | fz_moveto(csi->path, xobj->bbox.x0, xobj->bbox.y0); |
||
1070 | fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y0); |
||
1071 | fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y1); |
||
1072 | fz_lineto(csi->path, xobj->bbox.x0, xobj->bbox.y1); |
||
1073 | fz_closepath(csi->path); |
||
1074 | pdf_show_clip(csi, 0); |
||
1075 | pdf_show_path(csi, 0, 0, 0, 0); |
||
1076 | |||
1077 | /* run contents */ |
||
1078 | |||
1079 | oldtopctm = csi->top_ctm; |
||
1080 | csi->top_ctm = gstate->ctm; |
||
1081 | |||
1082 | if (xobj->resources) |
||
1083 | resources = xobj->resources; |
||
1084 | |||
1085 | error = pdf_run_buffer(csi, resources, xobj->contents); |
||
1086 | if (error) |
||
1087 | fz_catch(error, "cannot interpret XObject stream"); |
||
1088 | |||
1089 | csi->top_ctm = oldtopctm; |
||
1090 | |||
1091 | while (oldtop < csi->gtop) |
||
1092 | pdf_grestore(csi); |
||
1093 | |||
1094 | pdf_grestore(csi); |
||
1095 | |||
1096 | /* wrap up transparency stacks */ |
||
1097 | |||
1098 | if (xobj->transparency) |
||
1099 | { |
||
1100 | fz_end_group(csi->dev); |
||
1101 | if (popmask) |
||
1102 | fz_pop_clip(csi->dev); |
||
1103 | } |
||
1104 | |||
1105 | return fz_okay; |
||
1106 | } |
||
1107 | |||
1108 | static fz_error |
||
1109 | pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) |
||
1110 | { |
||
1111 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1112 | fz_colorspace *colorspace; |
||
1113 | int i, k; |
||
1114 | |||
1115 | pdf_flush_text(csi); |
||
1116 | |||
1117 | for (i = 0; i < fz_dict_len(extgstate); i++) |
||
1118 | { |
||
1119 | fz_obj *key = fz_dict_get_key(extgstate, i); |
||
1120 | fz_obj *val = fz_dict_get_val(extgstate, i); |
||
1121 | char *s = fz_to_name(key); |
||
1122 | |||
1123 | if (!strcmp(s, "Font")) |
||
1124 | { |
||
1125 | if (fz_is_array(val) && fz_array_len(val) == 2) |
||
1126 | { |
||
1127 | fz_error error; |
||
1128 | fz_obj *font = fz_array_get(val, 0); |
||
1129 | |||
1130 | if (gstate->font) |
||
1131 | { |
||
1132 | pdf_drop_font(gstate->font); |
||
1133 | gstate->font = NULL; |
||
1134 | } |
||
1135 | |||
1136 | error = pdf_load_font(&gstate->font, csi->xref, rdb, font); |
||
1137 | if (error) |
||
1138 | return fz_rethrow(error, "cannot load font (%d %d R)", fz_to_num(font), fz_to_gen(font)); |
||
1139 | if (!gstate->font) |
||
1140 | return fz_throw("cannot find font in store"); |
||
1141 | gstate->size = fz_to_real(fz_array_get(val, 1)); |
||
1142 | } |
||
1143 | else |
||
1144 | return fz_throw("malformed /Font dictionary"); |
||
1145 | } |
||
1146 | |||
1147 | else if (!strcmp(s, "LC")) |
||
1148 | { |
||
1149 | gstate->stroke_state.start_cap = fz_to_int(val); |
||
1150 | gstate->stroke_state.dash_cap = fz_to_int(val); |
||
1151 | gstate->stroke_state.end_cap = fz_to_int(val); |
||
1152 | } |
||
1153 | else if (!strcmp(s, "LW")) |
||
1154 | gstate->stroke_state.linewidth = fz_to_real(val); |
||
1155 | else if (!strcmp(s, "LJ")) |
||
1156 | gstate->stroke_state.linejoin = fz_to_int(val); |
||
1157 | else if (!strcmp(s, "ML")) |
||
1158 | gstate->stroke_state.miterlimit = fz_to_real(val); |
||
1159 | |||
1160 | else if (!strcmp(s, "D")) |
||
1161 | { |
||
1162 | if (fz_is_array(val) && fz_array_len(val) == 2) |
||
1163 | { |
||
1164 | fz_obj *dashes = fz_array_get(val, 0); |
||
1165 | gstate->stroke_state.dash_len = MAX(fz_array_len(dashes), 32); |
||
1166 | for (k = 0; k < gstate->stroke_state.dash_len; k++) |
||
1167 | gstate->stroke_state.dash_list[k] = fz_to_real(fz_array_get(dashes, k)); |
||
1168 | gstate->stroke_state.dash_phase = fz_to_real(fz_array_get(val, 1)); |
||
1169 | } |
||
1170 | else |
||
1171 | return fz_throw("malformed /D"); |
||
1172 | } |
||
1173 | |||
1174 | else if (!strcmp(s, "CA")) |
||
1175 | gstate->stroke.alpha = fz_to_real(val); |
||
1176 | |||
1177 | else if (!strcmp(s, "ca")) |
||
1178 | gstate->fill.alpha = fz_to_real(val); |
||
1179 | |||
1180 | else if (!strcmp(s, "BM")) |
||
1181 | { |
||
1182 | if (fz_is_array(val)) |
||
1183 | val = fz_array_get(val, 0); |
||
1184 | gstate->blendmode = fz_find_blendmode(fz_to_name(val)); |
||
1185 | } |
||
1186 | |||
1187 | else if (!strcmp(s, "SMask")) |
||
1188 | { |
||
1189 | if (fz_is_dict(val)) |
||
1190 | { |
||
1191 | fz_error error; |
||
1192 | pdf_xobject *xobj; |
||
1193 | fz_obj *group, *luminosity, *bc; |
||
1194 | |||
1195 | if (gstate->softmask) |
||
1196 | { |
||
1197 | pdf_drop_xobject(gstate->softmask); |
||
1198 | gstate->softmask = NULL; |
||
1199 | } |
||
1200 | |||
1201 | group = fz_dict_gets(val, "G"); |
||
1202 | if (!group) |
||
1203 | return fz_throw("cannot load softmask xobject (%d %d R)", fz_to_num(val), fz_to_gen(val)); |
||
1204 | error = pdf_load_xobject(&xobj, csi->xref, group); |
||
1205 | if (error) |
||
1206 | return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(val), fz_to_gen(val)); |
||
1207 | |||
1208 | colorspace = xobj->colorspace; |
||
1209 | if (!colorspace) |
||
1210 | colorspace = fz_device_gray; |
||
1211 | |||
1212 | gstate->softmask_ctm = fz_concat(xobj->matrix, gstate->ctm); |
||
1213 | gstate->softmask = xobj; |
||
1214 | for (k = 0; k < colorspace->n; k++) |
||
1215 | gstate->softmask_bc[k] = 0; |
||
1216 | |||
1217 | bc = fz_dict_gets(val, "BC"); |
||
1218 | if (fz_is_array(bc)) |
||
1219 | { |
||
1220 | for (k = 0; k < colorspace->n; k++) |
||
1221 | gstate->softmask_bc[k] = fz_to_real(fz_array_get(bc, k)); |
||
1222 | } |
||
1223 | |||
1224 | luminosity = fz_dict_gets(val, "S"); |
||
1225 | if (fz_is_name(luminosity) && !strcmp(fz_to_name(luminosity), "Luminosity")) |
||
1226 | gstate->luminosity = 1; |
||
1227 | else |
||
1228 | gstate->luminosity = 0; |
||
1229 | } |
||
1230 | else if (fz_is_name(val) && !strcmp(fz_to_name(val), "None")) |
||
1231 | { |
||
1232 | if (gstate->softmask) |
||
1233 | { |
||
1234 | pdf_drop_xobject(gstate->softmask); |
||
1235 | gstate->softmask = NULL; |
||
1236 | } |
||
1237 | } |
||
1238 | } |
||
1239 | |||
1240 | else if (!strcmp(s, "TR")) |
||
1241 | { |
||
1242 | if (fz_is_name(val) && strcmp(fz_to_name(val), "Identity")) |
||
1243 | fz_warn("ignoring transfer function"); |
||
1244 | } |
||
1245 | } |
||
1246 | |||
1247 | return fz_okay; |
||
1248 | } |
||
1249 | |||
1250 | /* |
||
1251 | * Operators |
||
1252 | */ |
||
1253 | |||
1254 | static void pdf_run_BDC(pdf_csi *csi) |
||
1255 | { |
||
1256 | } |
||
1257 | |||
1258 | static fz_error pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) |
||
1259 | { |
||
1260 | int ch; |
||
1261 | fz_error error; |
||
1262 | char *buf = csi->xref->scratch; |
||
1263 | int buflen = sizeof(csi->xref->scratch); |
||
1264 | fz_pixmap *img; |
||
1265 | fz_obj *obj; |
||
1266 | |||
1267 | error = pdf_parse_dict(&obj, csi->xref, file, buf, buflen); |
||
1268 | if (error) |
||
1269 | return fz_rethrow(error, "cannot parse inline image dictionary"); |
||
1270 | |||
1271 | /* read whitespace after ID keyword */ |
||
1272 | ch = fz_read_byte(file); |
||
1273 | if (ch == '\r') |
||
1274 | if (fz_peek_byte(file) == '\n') |
||
1275 | fz_read_byte(file); |
||
1276 | |||
1277 | error = pdf_load_inline_image(&img, csi->xref, rdb, obj, file); |
||
1278 | fz_drop_obj(obj); |
||
1279 | if (error) |
||
1280 | return fz_rethrow(error, "cannot load inline image"); |
||
1281 | |||
1282 | pdf_show_image(csi, img); |
||
1283 | |||
1284 | fz_drop_pixmap(img); |
||
1285 | |||
1286 | /* find EI */ |
||
1287 | ch = fz_read_byte(file); |
||
1288 | while (ch != 'E' && ch != EOF) |
||
1289 | ch = fz_read_byte(file); |
||
1290 | ch = fz_read_byte(file); |
||
1291 | if (ch != 'I') |
||
1292 | return fz_rethrow(error, "syntax error after inline image"); |
||
1293 | |||
1294 | return fz_okay; |
||
1295 | } |
||
1296 | |||
1297 | static void pdf_run_B(pdf_csi *csi) |
||
1298 | { |
||
1299 | pdf_show_path(csi, 0, 1, 1, 0); |
||
1300 | } |
||
1301 | |||
1302 | static void pdf_run_BMC(pdf_csi *csi) |
||
1303 | { |
||
1304 | } |
||
1305 | |||
1306 | static void pdf_run_BT(pdf_csi *csi) |
||
1307 | { |
||
1308 | csi->in_text = 1; |
||
1309 | csi->tm = fz_identity; |
||
1310 | csi->tlm = fz_identity; |
||
1311 | } |
||
1312 | |||
1313 | static void pdf_run_BX(pdf_csi *csi) |
||
1314 | { |
||
1315 | csi->xbalance ++; |
||
1316 | } |
||
1317 | |||
1318 | static void pdf_run_Bstar(pdf_csi *csi) |
||
1319 | { |
||
1320 | pdf_show_path(csi, 0, 1, 1, 1); |
||
1321 | } |
||
1322 | |||
1323 | static fz_error pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what) |
||
1324 | { |
||
1325 | fz_colorspace *colorspace; |
||
1326 | fz_obj *obj, *dict; |
||
1327 | fz_error error; |
||
1328 | |||
1329 | if (!strcmp(csi->name, "Pattern")) |
||
1330 | { |
||
1331 | pdf_set_pattern(csi, what, NULL, NULL); |
||
1332 | } |
||
1333 | else |
||
1334 | { |
||
1335 | if (!strcmp(csi->name, "DeviceGray")) |
||
1336 | colorspace = fz_keep_colorspace(fz_device_gray); |
||
1337 | else if (!strcmp(csi->name, "DeviceRGB")) |
||
1338 | colorspace = fz_keep_colorspace(fz_device_rgb); |
||
1339 | else if (!strcmp(csi->name, "DeviceCMYK")) |
||
1340 | colorspace = fz_keep_colorspace(fz_device_cmyk); |
||
1341 | else |
||
1342 | { |
||
1343 | dict = fz_dict_gets(rdb, "ColorSpace"); |
||
1344 | if (!dict) |
||
1345 | return fz_throw("cannot find ColorSpace dictionary"); |
||
1346 | obj = fz_dict_gets(dict, csi->name); |
||
1347 | if (!obj) |
||
1348 | return fz_throw("cannot find colorspace resource '%s'", csi->name); |
||
1349 | error = pdf_load_colorspace(&colorspace, csi->xref, obj); |
||
1350 | if (error) |
||
1351 | return fz_rethrow(error, "cannot load colorspace (%d 0 R)", fz_to_num(obj)); |
||
1352 | } |
||
1353 | |||
1354 | pdf_set_colorspace(csi, what, colorspace); |
||
1355 | |||
1356 | fz_drop_colorspace(colorspace); |
||
1357 | } |
||
1358 | return fz_okay; |
||
1359 | } |
||
1360 | |||
1361 | static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb) |
||
1362 | { |
||
1363 | fz_error error; |
||
1364 | error = pdf_run_cs_imp(csi, rdb, PDF_STROKE); |
||
1365 | if (error) |
||
1366 | fz_catch(error, "cannot set colorspace"); |
||
1367 | } |
||
1368 | |||
1369 | static void pdf_run_cs(pdf_csi *csi, fz_obj *rdb) |
||
1370 | { |
||
1371 | fz_error error; |
||
1372 | error = pdf_run_cs_imp(csi, rdb, PDF_FILL); |
||
1373 | if (error) |
||
1374 | fz_catch(error, "cannot set colorspace"); |
||
1375 | } |
||
1376 | |||
1377 | static void pdf_run_DP(pdf_csi *csi) |
||
1378 | { |
||
1379 | } |
||
1380 | |||
1381 | static fz_error pdf_run_Do(pdf_csi *csi, fz_obj *rdb) |
||
1382 | { |
||
1383 | fz_obj *dict; |
||
1384 | fz_obj *obj; |
||
1385 | fz_obj *subtype; |
||
1386 | fz_error error; |
||
1387 | |||
1388 | dict = fz_dict_gets(rdb, "XObject"); |
||
1389 | if (!dict) |
||
1390 | return fz_throw("cannot find XObject dictionary when looking for: '%s'", csi->name); |
||
1391 | |||
1392 | obj = fz_dict_gets(dict, csi->name); |
||
1393 | if (!obj) |
||
1394 | return fz_throw("cannot find xobject resource: '%s'", csi->name); |
||
1395 | |||
1396 | subtype = fz_dict_gets(obj, "Subtype"); |
||
1397 | if (!fz_is_name(subtype)) |
||
1398 | return fz_throw("no XObject subtype specified"); |
||
1399 | |||
1400 | if (pdf_is_hidden_ocg(obj, csi->target)) |
||
1401 | return fz_okay; |
||
1402 | |||
1403 | if (!strcmp(fz_to_name(subtype), "Form") && fz_dict_gets(obj, "Subtype2")) |
||
1404 | subtype = fz_dict_gets(obj, "Subtype2"); |
||
1405 | |||
1406 | if (!strcmp(fz_to_name(subtype), "Form")) |
||
1407 | { |
||
1408 | pdf_xobject *xobj; |
||
1409 | |||
1410 | error = pdf_load_xobject(&xobj, csi->xref, obj); |
||
1411 | if (error) |
||
1412 | return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); |
||
1413 | |||
1414 | /* Inherit parent resources, in case this one was empty XXX check where it's loaded */ |
||
1415 | if (!xobj->resources) |
||
1416 | xobj->resources = fz_keep_obj(rdb); |
||
1417 | |||
1418 | error = pdf_run_xobject(csi, xobj->resources, xobj, fz_identity); |
||
1419 | if (error) |
||
1420 | return fz_rethrow(error, "cannot draw xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); |
||
1421 | |||
1422 | pdf_drop_xobject(xobj); |
||
1423 | } |
||
1424 | |||
1425 | else if (!strcmp(fz_to_name(subtype), "Image")) |
||
1426 | { |
||
1427 | if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0) |
||
1428 | { |
||
1429 | fz_pixmap *img; |
||
1430 | error = pdf_load_image(&img, csi->xref, obj); |
||
1431 | if (error) |
||
1432 | return fz_rethrow(error, "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); |
||
1433 | pdf_show_image(csi, img); |
||
1434 | fz_drop_pixmap(img); |
||
1435 | } |
||
1436 | } |
||
1437 | |||
1438 | else if (!strcmp(fz_to_name(subtype), "PS")) |
||
1439 | { |
||
1440 | fz_warn("ignoring XObject with subtype PS"); |
||
1441 | } |
||
1442 | |||
1443 | else |
||
1444 | { |
||
1445 | return fz_throw("unknown XObject subtype: '%s'", fz_to_name(subtype)); |
||
1446 | } |
||
1447 | |||
1448 | return fz_okay; |
||
1449 | } |
||
1450 | |||
1451 | static void pdf_run_EMC(pdf_csi *csi) |
||
1452 | { |
||
1453 | } |
||
1454 | |||
1455 | static void pdf_run_ET(pdf_csi *csi) |
||
1456 | { |
||
1457 | pdf_flush_text(csi); |
||
1458 | csi->accumulate = 1; |
||
1459 | csi->in_text = 0; |
||
1460 | } |
||
1461 | |||
1462 | static void pdf_run_EX(pdf_csi *csi) |
||
1463 | { |
||
1464 | csi->xbalance --; |
||
1465 | } |
||
1466 | |||
1467 | static void pdf_run_F(pdf_csi *csi) |
||
1468 | { |
||
1469 | pdf_show_path(csi, 0, 1, 0, 0); |
||
1470 | } |
||
1471 | |||
1472 | static void pdf_run_G(pdf_csi *csi) |
||
1473 | { |
||
1474 | pdf_set_colorspace(csi, PDF_STROKE, fz_device_gray); |
||
1475 | pdf_set_color(csi, PDF_STROKE, csi->stack); |
||
1476 | } |
||
1477 | |||
1478 | static void pdf_run_J(pdf_csi *csi) |
||
1479 | { |
||
1480 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1481 | gstate->stroke_state.start_cap = csi->stack[0]; |
||
1482 | gstate->stroke_state.dash_cap = csi->stack[0]; |
||
1483 | gstate->stroke_state.end_cap = csi->stack[0]; |
||
1484 | } |
||
1485 | |||
1486 | static void pdf_run_K(pdf_csi *csi) |
||
1487 | { |
||
1488 | pdf_set_colorspace(csi, PDF_STROKE, fz_device_cmyk); |
||
1489 | pdf_set_color(csi, PDF_STROKE, csi->stack); |
||
1490 | } |
||
1491 | |||
1492 | static void pdf_run_M(pdf_csi *csi) |
||
1493 | { |
||
1494 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1495 | gstate->stroke_state.miterlimit = csi->stack[0]; |
||
1496 | } |
||
1497 | |||
1498 | static void pdf_run_MP(pdf_csi *csi) |
||
1499 | { |
||
1500 | } |
||
1501 | |||
1502 | static void pdf_run_Q(pdf_csi *csi) |
||
1503 | { |
||
1504 | pdf_grestore(csi); |
||
1505 | } |
||
1506 | |||
1507 | static void pdf_run_RG(pdf_csi *csi) |
||
1508 | { |
||
1509 | pdf_set_colorspace(csi, PDF_STROKE, fz_device_rgb); |
||
1510 | pdf_set_color(csi, PDF_STROKE, csi->stack); |
||
1511 | } |
||
1512 | |||
1513 | static void pdf_run_S(pdf_csi *csi) |
||
1514 | { |
||
1515 | pdf_show_path(csi, 0, 0, 1, 0); |
||
1516 | } |
||
1517 | |||
1518 | static fz_error pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *mat) |
||
1519 | { |
||
1520 | fz_error error; |
||
1521 | fz_obj *patterntype; |
||
1522 | fz_obj *dict; |
||
1523 | fz_obj *obj; |
||
1524 | int kind; |
||
1525 | |||
1526 | kind = mat->kind; |
||
1527 | if (csi->name[0]) |
||
1528 | kind = PDF_MAT_PATTERN; |
||
1529 | |||
1530 | switch (kind) |
||
1531 | { |
||
1532 | case PDF_MAT_NONE: |
||
1533 | return fz_throw("cannot set color in mask objects"); |
||
1534 | |||
1535 | case PDF_MAT_COLOR: |
||
1536 | pdf_set_color(csi, what, csi->stack); |
||
1537 | break; |
||
1538 | |||
1539 | case PDF_MAT_PATTERN: |
||
1540 | dict = fz_dict_gets(rdb, "Pattern"); |
||
1541 | if (!dict) |
||
1542 | return fz_throw("cannot find Pattern dictionary"); |
||
1543 | |||
1544 | obj = fz_dict_gets(dict, csi->name); |
||
1545 | if (!obj) |
||
1546 | return fz_throw("cannot find pattern resource '%s'", csi->name); |
||
1547 | |||
1548 | patterntype = fz_dict_gets(obj, "PatternType"); |
||
1549 | |||
1550 | if (fz_to_int(patterntype) == 1) |
||
1551 | { |
||
1552 | pdf_pattern *pat; |
||
1553 | error = pdf_load_pattern(&pat, csi->xref, obj); |
||
1554 | if (error) |
||
1555 | return fz_rethrow(error, "cannot load pattern (%d 0 R)", fz_to_num(obj)); |
||
1556 | pdf_set_pattern(csi, what, pat, csi->top > 0 ? csi->stack : NULL); |
||
1557 | pdf_drop_pattern(pat); |
||
1558 | } |
||
1559 | else if (fz_to_int(patterntype) == 2) |
||
1560 | { |
||
1561 | fz_shade *shd; |
||
1562 | error = pdf_load_shading(&shd, csi->xref, obj); |
||
1563 | if (error) |
||
1564 | return fz_rethrow(error, "cannot load shading (%d 0 R)", fz_to_num(obj)); |
||
1565 | pdf_set_shade(csi, what, shd); |
||
1566 | fz_drop_shade(shd); |
||
1567 | } |
||
1568 | else |
||
1569 | { |
||
1570 | return fz_throw("unknown pattern type: %d", fz_to_int(patterntype)); |
||
1571 | } |
||
1572 | break; |
||
1573 | |||
1574 | case PDF_MAT_SHADE: |
||
1575 | return fz_throw("cannot set color in shade objects"); |
||
1576 | } |
||
1577 | |||
1578 | return fz_okay; |
||
1579 | } |
||
1580 | |||
1581 | static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb) |
||
1582 | { |
||
1583 | fz_error error; |
||
1584 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1585 | error = pdf_run_SC_imp(csi, rdb, PDF_STROKE, &gstate->stroke); |
||
1586 | if (error) |
||
1587 | fz_catch(error, "cannot set color and colorspace"); |
||
1588 | } |
||
1589 | |||
1590 | static void pdf_run_sc(pdf_csi *csi, fz_obj *rdb) |
||
1591 | { |
||
1592 | fz_error error; |
||
1593 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1594 | error = pdf_run_SC_imp(csi, rdb, PDF_FILL, &gstate->fill); |
||
1595 | if (error) |
||
1596 | fz_catch(error, "cannot set color and colorspace"); |
||
1597 | } |
||
1598 | |||
1599 | static void pdf_run_Tc(pdf_csi *csi) |
||
1600 | { |
||
1601 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1602 | gstate->char_space = csi->stack[0]; |
||
1603 | } |
||
1604 | |||
1605 | static void pdf_run_Tw(pdf_csi *csi) |
||
1606 | { |
||
1607 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1608 | gstate->word_space = csi->stack[0]; |
||
1609 | } |
||
1610 | |||
1611 | static void pdf_run_Tz(pdf_csi *csi) |
||
1612 | { |
||
1613 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1614 | float a = csi->stack[0] / 100; |
||
1615 | pdf_flush_text(csi); |
||
1616 | gstate->scale = a; |
||
1617 | } |
||
1618 | |||
1619 | static void pdf_run_TL(pdf_csi *csi) |
||
1620 | { |
||
1621 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1622 | gstate->leading = csi->stack[0]; |
||
1623 | } |
||
1624 | |||
1625 | static fz_error pdf_run_Tf(pdf_csi *csi, fz_obj *rdb) |
||
1626 | { |
||
1627 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1628 | fz_error error; |
||
1629 | fz_obj *dict; |
||
1630 | fz_obj *obj; |
||
1631 | |||
1632 | gstate->size = csi->stack[0]; |
||
1633 | if (gstate->font) |
||
1634 | pdf_drop_font(gstate->font); |
||
1635 | gstate->font = NULL; |
||
1636 | |||
1637 | dict = fz_dict_gets(rdb, "Font"); |
||
1638 | if (!dict) |
||
1639 | return fz_throw("cannot find Font dictionary"); |
||
1640 | |||
1641 | obj = fz_dict_gets(dict, csi->name); |
||
1642 | if (!obj) |
||
1643 | return fz_throw("cannot find font resource: '%s'", csi->name); |
||
1644 | |||
1645 | error = pdf_load_font(&gstate->font, csi->xref, rdb, obj); |
||
1646 | if (error) |
||
1647 | return fz_rethrow(error, "cannot load font (%d 0 R)", fz_to_num(obj)); |
||
1648 | |||
1649 | return fz_okay; |
||
1650 | } |
||
1651 | |||
1652 | static void pdf_run_Tr(pdf_csi *csi) |
||
1653 | { |
||
1654 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1655 | gstate->render = csi->stack[0]; |
||
1656 | } |
||
1657 | |||
1658 | static void pdf_run_Ts(pdf_csi *csi) |
||
1659 | { |
||
1660 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1661 | gstate->rise = csi->stack[0]; |
||
1662 | } |
||
1663 | |||
1664 | static void pdf_run_Td(pdf_csi *csi) |
||
1665 | { |
||
1666 | fz_matrix m = fz_translate(csi->stack[0], csi->stack[1]); |
||
1667 | csi->tlm = fz_concat(m, csi->tlm); |
||
1668 | csi->tm = csi->tlm; |
||
1669 | } |
||
1670 | |||
1671 | static void pdf_run_TD(pdf_csi *csi) |
||
1672 | { |
||
1673 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1674 | fz_matrix m; |
||
1675 | |||
1676 | gstate->leading = -csi->stack[1]; |
||
1677 | m = fz_translate(csi->stack[0], csi->stack[1]); |
||
1678 | csi->tlm = fz_concat(m, csi->tlm); |
||
1679 | csi->tm = csi->tlm; |
||
1680 | } |
||
1681 | |||
1682 | static void pdf_run_Tm(pdf_csi *csi) |
||
1683 | { |
||
1684 | csi->tm.a = csi->stack[0]; |
||
1685 | csi->tm.b = csi->stack[1]; |
||
1686 | csi->tm.c = csi->stack[2]; |
||
1687 | csi->tm.d = csi->stack[3]; |
||
1688 | csi->tm.e = csi->stack[4]; |
||
1689 | csi->tm.f = csi->stack[5]; |
||
1690 | csi->tlm = csi->tm; |
||
1691 | } |
||
1692 | |||
1693 | static void pdf_run_Tstar(pdf_csi *csi) |
||
1694 | { |
||
1695 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1696 | fz_matrix m = fz_translate(0, -gstate->leading); |
||
1697 | csi->tlm = fz_concat(m, csi->tlm); |
||
1698 | csi->tm = csi->tlm; |
||
1699 | } |
||
1700 | |||
1701 | static void pdf_run_Tj(pdf_csi *csi) |
||
1702 | { |
||
1703 | if (csi->string_len) |
||
1704 | pdf_show_string(csi, csi->string, csi->string_len); |
||
1705 | else |
||
1706 | pdf_show_text(csi, csi->obj); |
||
1707 | } |
||
1708 | |||
1709 | static void pdf_run_TJ(pdf_csi *csi) |
||
1710 | { |
||
1711 | if (csi->string_len) |
||
1712 | pdf_show_string(csi, csi->string, csi->string_len); |
||
1713 | else |
||
1714 | pdf_show_text(csi, csi->obj); |
||
1715 | } |
||
1716 | |||
1717 | static void pdf_run_W(pdf_csi *csi) |
||
1718 | { |
||
1719 | pdf_show_clip(csi, 0); |
||
1720 | } |
||
1721 | |||
1722 | static void pdf_run_Wstar(pdf_csi *csi) |
||
1723 | { |
||
1724 | pdf_show_clip(csi, 1); |
||
1725 | } |
||
1726 | |||
1727 | static void pdf_run_b(pdf_csi *csi) |
||
1728 | { |
||
1729 | pdf_show_path(csi, 1, 1, 1, 0); |
||
1730 | } |
||
1731 | |||
1732 | static void pdf_run_bstar(pdf_csi *csi) |
||
1733 | { |
||
1734 | pdf_show_path(csi, 1, 1, 1, 1); |
||
1735 | } |
||
1736 | |||
1737 | static void pdf_run_c(pdf_csi *csi) |
||
1738 | { |
||
1739 | float a, b, c, d, e, f; |
||
1740 | a = csi->stack[0]; |
||
1741 | b = csi->stack[1]; |
||
1742 | c = csi->stack[2]; |
||
1743 | d = csi->stack[3]; |
||
1744 | e = csi->stack[4]; |
||
1745 | f = csi->stack[5]; |
||
1746 | fz_curveto(csi->path, a, b, c, d, e, f); |
||
1747 | } |
||
1748 | |||
1749 | static void pdf_run_cm(pdf_csi *csi) |
||
1750 | { |
||
1751 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1752 | fz_matrix m; |
||
1753 | |||
1754 | m.a = csi->stack[0]; |
||
1755 | m.b = csi->stack[1]; |
||
1756 | m.c = csi->stack[2]; |
||
1757 | m.d = csi->stack[3]; |
||
1758 | m.e = csi->stack[4]; |
||
1759 | m.f = csi->stack[5]; |
||
1760 | |||
1761 | gstate->ctm = fz_concat(m, gstate->ctm); |
||
1762 | } |
||
1763 | |||
1764 | static void pdf_run_d(pdf_csi *csi) |
||
1765 | { |
||
1766 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1767 | fz_obj *array; |
||
1768 | int i; |
||
1769 | |||
1770 | array = csi->obj; |
||
1771 | gstate->stroke_state.dash_len = MIN(fz_array_len(array), nelem(gstate->stroke_state.dash_list)); |
||
1772 | for (i = 0; i < gstate->stroke_state.dash_len; i++) |
||
1773 | gstate->stroke_state.dash_list[i] = fz_to_real(fz_array_get(array, i)); |
||
1774 | gstate->stroke_state.dash_phase = csi->stack[0]; |
||
1775 | } |
||
1776 | |||
1777 | static void pdf_run_d0(pdf_csi *csi) |
||
1778 | { |
||
1779 | csi->dev->flags |= FZ_CHARPROC_COLOR; |
||
1780 | } |
||
1781 | |||
1782 | static void pdf_run_d1(pdf_csi *csi) |
||
1783 | { |
||
1784 | csi->dev->flags |= FZ_CHARPROC_MASK; |
||
1785 | } |
||
1786 | |||
1787 | static void pdf_run_f(pdf_csi *csi) |
||
1788 | { |
||
1789 | pdf_show_path(csi, 0, 1, 0, 0); |
||
1790 | } |
||
1791 | |||
1792 | static void pdf_run_fstar(pdf_csi *csi) |
||
1793 | { |
||
1794 | pdf_show_path(csi, 0, 1, 0, 1); |
||
1795 | } |
||
1796 | |||
1797 | static void pdf_run_g(pdf_csi *csi) |
||
1798 | { |
||
1799 | pdf_set_colorspace(csi, PDF_FILL, fz_device_gray); |
||
1800 | pdf_set_color(csi, PDF_FILL, csi->stack); |
||
1801 | } |
||
1802 | |||
1803 | static fz_error pdf_run_gs(pdf_csi *csi, fz_obj *rdb) |
||
1804 | { |
||
1805 | fz_error error; |
||
1806 | fz_obj *dict; |
||
1807 | fz_obj *obj; |
||
1808 | |||
1809 | dict = fz_dict_gets(rdb, "ExtGState"); |
||
1810 | if (!dict) |
||
1811 | return fz_throw("cannot find ExtGState dictionary"); |
||
1812 | |||
1813 | obj = fz_dict_gets(dict, csi->name); |
||
1814 | if (!obj) |
||
1815 | return fz_throw("cannot find extgstate resource '%s'", csi->name); |
||
1816 | |||
1817 | error = pdf_run_extgstate(csi, rdb, obj); |
||
1818 | if (error) |
||
1819 | return fz_rethrow(error, "cannot set ExtGState (%d 0 R)", fz_to_num(obj)); |
||
1820 | return fz_okay; |
||
1821 | } |
||
1822 | |||
1823 | static void pdf_run_h(pdf_csi *csi) |
||
1824 | { |
||
1825 | fz_closepath(csi->path); |
||
1826 | } |
||
1827 | |||
1828 | static void pdf_run_i(pdf_csi *csi) |
||
1829 | { |
||
1830 | } |
||
1831 | |||
1832 | static void pdf_run_j(pdf_csi *csi) |
||
1833 | { |
||
1834 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1835 | gstate->stroke_state.linejoin = csi->stack[0]; |
||
1836 | } |
||
1837 | |||
1838 | static void pdf_run_k(pdf_csi *csi) |
||
1839 | { |
||
1840 | pdf_set_colorspace(csi, PDF_FILL, fz_device_cmyk); |
||
1841 | pdf_set_color(csi, PDF_FILL, csi->stack); |
||
1842 | } |
||
1843 | |||
1844 | static void pdf_run_l(pdf_csi *csi) |
||
1845 | { |
||
1846 | float a, b; |
||
1847 | a = csi->stack[0]; |
||
1848 | b = csi->stack[1]; |
||
1849 | fz_lineto(csi->path, a, b); |
||
1850 | } |
||
1851 | |||
1852 | static void pdf_run_m(pdf_csi *csi) |
||
1853 | { |
||
1854 | float a, b; |
||
1855 | a = csi->stack[0]; |
||
1856 | b = csi->stack[1]; |
||
1857 | fz_moveto(csi->path, a, b); |
||
1858 | } |
||
1859 | |||
1860 | static void pdf_run_n(pdf_csi *csi) |
||
1861 | { |
||
1862 | pdf_show_path(csi, 0, 0, 0, 0); |
||
1863 | } |
||
1864 | |||
1865 | static void pdf_run_q(pdf_csi *csi) |
||
1866 | { |
||
1867 | pdf_gsave(csi); |
||
1868 | } |
||
1869 | |||
1870 | static void pdf_run_re(pdf_csi *csi) |
||
1871 | { |
||
1872 | float x, y, w, h; |
||
1873 | |||
1874 | x = csi->stack[0]; |
||
1875 | y = csi->stack[1]; |
||
1876 | w = csi->stack[2]; |
||
1877 | h = csi->stack[3]; |
||
1878 | |||
1879 | fz_moveto(csi->path, x, y); |
||
1880 | fz_lineto(csi->path, x + w, y); |
||
1881 | fz_lineto(csi->path, x + w, y + h); |
||
1882 | fz_lineto(csi->path, x, y + h); |
||
1883 | fz_closepath(csi->path); |
||
1884 | } |
||
1885 | |||
1886 | static void pdf_run_rg(pdf_csi *csi) |
||
1887 | { |
||
1888 | pdf_set_colorspace(csi, PDF_FILL, fz_device_rgb); |
||
1889 | pdf_set_color(csi, PDF_FILL, csi->stack); |
||
1890 | } |
||
1891 | |||
1892 | static void pdf_run_ri(pdf_csi *csi) |
||
1893 | { |
||
1894 | } |
||
1895 | |||
1896 | static void pdf_run(pdf_csi *csi) |
||
1897 | { |
||
1898 | pdf_show_path(csi, 1, 0, 1, 0); |
||
1899 | } |
||
1900 | |||
1901 | static fz_error pdf_run_sh(pdf_csi *csi, fz_obj *rdb) |
||
1902 | { |
||
1903 | fz_obj *dict; |
||
1904 | fz_obj *obj; |
||
1905 | fz_shade *shd; |
||
1906 | fz_error error; |
||
1907 | |||
1908 | dict = fz_dict_gets(rdb, "Shading"); |
||
1909 | if (!dict) |
||
1910 | return fz_throw("cannot find shading dictionary"); |
||
1911 | |||
1912 | obj = fz_dict_gets(dict, csi->name); |
||
1913 | if (!obj) |
||
1914 | return fz_throw("cannot find shading resource: '%s'", csi->name); |
||
1915 | |||
1916 | if ((csi->dev->hints & FZ_IGNORE_SHADE) == 0) |
||
1917 | { |
||
1918 | error = pdf_load_shading(&shd, csi->xref, obj); |
||
1919 | if (error) |
||
1920 | return fz_rethrow(error, "cannot load shading (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); |
||
1921 | pdf_show_shade(csi, shd); |
||
1922 | fz_drop_shade(shd); |
||
1923 | } |
||
1924 | return fz_okay; |
||
1925 | } |
||
1926 | |||
1927 | static void pdf_run_v(pdf_csi *csi) |
||
1928 | { |
||
1929 | float a, b, c, d; |
||
1930 | a = csi->stack[0]; |
||
1931 | b = csi->stack[1]; |
||
1932 | c = csi->stack[2]; |
||
1933 | d = csi->stack[3]; |
||
1934 | fz_curvetov(csi->path, a, b, c, d); |
||
1935 | } |
||
1936 | |||
1937 | static void pdf_run_w(pdf_csi *csi) |
||
1938 | { |
||
1939 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1940 | pdf_flush_text(csi); /* linewidth affects stroked text rendering mode */ |
||
1941 | gstate->stroke_state.linewidth = csi->stack[0]; |
||
1942 | } |
||
1943 | |||
1944 | static void pdf_run_y(pdf_csi *csi) |
||
1945 | { |
||
1946 | float a, b, c, d; |
||
1947 | a = csi->stack[0]; |
||
1948 | b = csi->stack[1]; |
||
1949 | c = csi->stack[2]; |
||
1950 | d = csi->stack[3]; |
||
1951 | fz_curvetoy(csi->path, a, b, c, d); |
||
1952 | } |
||
1953 | |||
1954 | static void pdf_run_squote(pdf_csi *csi) |
||
1955 | { |
||
1956 | fz_matrix m; |
||
1957 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1958 | |||
1959 | m = fz_translate(0, -gstate->leading); |
||
1960 | csi->tlm = fz_concat(m, csi->tlm); |
||
1961 | csi->tm = csi->tlm; |
||
1962 | |||
1963 | if (csi->string_len) |
||
1964 | pdf_show_string(csi, csi->string, csi->string_len); |
||
1965 | else |
||
1966 | pdf_show_text(csi, csi->obj); |
||
1967 | } |
||
1968 | |||
1969 | static void pdf_run_dquote(pdf_csi *csi) |
||
1970 | { |
||
1971 | fz_matrix m; |
||
1972 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
1973 | |||
1974 | gstate->word_space = csi->stack[0]; |
||
1975 | gstate->char_space = csi->stack[1]; |
||
1976 | |||
1977 | m = fz_translate(0, -gstate->leading); |
||
1978 | csi->tlm = fz_concat(m, csi->tlm); |
||
1979 | csi->tm = csi->tlm; |
||
1980 | |||
1981 | if (csi->string_len) |
||
1982 | pdf_show_string(csi, csi->string, csi->string_len); |
||
1983 | else |
||
1984 | pdf_show_text(csi, csi->obj); |
||
1985 | } |
||
1986 | |||
1987 | #define A(a) (a) |
||
1988 | #define B(a,b) (a | b << 8) |
||
1989 | #define C(a,b,c) (a | b << 8 | c << 16) |
||
1990 | |||
1991 | static fz_error |
||
1992 | pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf) |
||
1993 | { |
||
1994 | fz_error error; |
||
1995 | int key; |
||
1996 | |||
1997 | key = buf[0]; |
||
1998 | if (buf[1]) |
||
1999 | { |
||
2000 | key |= buf[1] << 8; |
||
2001 | if (buf[2]) |
||
2002 | { |
||
2003 | key |= buf[2] << 16; |
||
2004 | if (buf[3]) |
||
2005 | key = 0; |
||
2006 | } |
||
2007 | } |
||
2008 | |||
2009 | switch (key) |
||
2010 | { |
||
2011 | case A('"'): pdf_run_dquote(csi); break; |
||
2012 | case A('\''): pdf_run_squote(csi); break; |
||
2013 | case A('B'): pdf_run_B(csi); break; |
||
2014 | case B('B','*'): pdf_run_Bstar(csi); break; |
||
2015 | case C('B','D','C'): pdf_run_BDC(csi); break; |
||
2016 | case B('B','I'): |
||
2017 | error = pdf_run_BI(csi, rdb, file); |
||
2018 | if (error) |
||
2019 | return fz_rethrow(error, "cannot draw inline image"); |
||
2020 | break; |
||
2021 | case C('B','M','C'): pdf_run_BMC(csi); break; |
||
2022 | case B('B','T'): pdf_run_BT(csi); break; |
||
2023 | case B('B','X'): pdf_run_BX(csi); break; |
||
2024 | case B('C','S'): pdf_run_CS(csi, rdb); break; |
||
2025 | case B('D','P'): pdf_run_DP(csi); break; |
||
2026 | case B('D','o'): |
||
2027 | error = pdf_run_Do(csi, rdb); |
||
2028 | if (error) |
||
2029 | fz_catch(error, "cannot draw xobject/image"); |
||
2030 | break; |
||
2031 | case C('E','M','C'): pdf_run_EMC(csi); break; |
||
2032 | case B('E','T'): pdf_run_ET(csi); break; |
||
2033 | case B('E','X'): pdf_run_EX(csi); break; |
||
2034 | case A('F'): pdf_run_F(csi); break; |
||
2035 | case A('G'): pdf_run_G(csi); break; |
||
2036 | case A('J'): pdf_run_J(csi); break; |
||
2037 | case A('K'): pdf_run_K(csi); break; |
||
2038 | case A('M'): pdf_run_M(csi); break; |
||
2039 | case B('M','P'): pdf_run_MP(csi); break; |
||
2040 | case A('Q'): pdf_run_Q(csi); break; |
||
2041 | case B('R','G'): pdf_run_RG(csi); break; |
||
2042 | case A('S'): pdf_run_S(csi); break; |
||
2043 | case B('S','C'): pdf_run_SC(csi, rdb); break; |
||
2044 | case C('S','C','N'): pdf_run_SC(csi, rdb); break; |
||
2045 | case B('T','*'): pdf_run_Tstar(csi); break; |
||
2046 | case B('T','D'): pdf_run_TD(csi); break; |
||
2047 | case B('T','J'): pdf_run_TJ(csi); break; |
||
2048 | case B('T','L'): pdf_run_TL(csi); break; |
||
2049 | case B('T','c'): pdf_run_Tc(csi); break; |
||
2050 | case B('T','d'): pdf_run_Td(csi); break; |
||
2051 | case B('T','f'): |
||
2052 | error = pdf_run_Tf(csi, rdb); |
||
2053 | if (error) |
||
2054 | fz_catch(error, "cannot set font"); |
||
2055 | break; |
||
2056 | case B('T','j'): pdf_run_Tj(csi); break; |
||
2057 | case B('T','m'): pdf_run_Tm(csi); break; |
||
2058 | case B('T','r'): pdf_run_Tr(csi); break; |
||
2059 | case B('T','s'): pdf_run_Ts(csi); break; |
||
2060 | case B('T','w'): pdf_run_Tw(csi); break; |
||
2061 | case B('T','z'): pdf_run_Tz(csi); break; |
||
2062 | case A('W'): pdf_run_W(csi); break; |
||
2063 | case B('W','*'): pdf_run_Wstar(csi); break; |
||
2064 | case A('b'): pdf_run_b(csi); break; |
||
2065 | case B('b','*'): pdf_run_bstar(csi); break; |
||
2066 | case A('c'): pdf_run_c(csi); break; |
||
2067 | case B('c','m'): pdf_run_cm(csi); break; |
||
2068 | case B('c','s'): pdf_run_cs(csi, rdb); break; |
||
2069 | case A('d'): pdf_run_d(csi); break; |
||
2070 | case B('d','0'): pdf_run_d0(csi); break; |
||
2071 | case B('d','1'): pdf_run_d1(csi); break; |
||
2072 | case A('f'): pdf_run_f(csi); break; |
||
2073 | case B('f','*'): pdf_run_fstar(csi); break; |
||
2074 | case A('g'): pdf_run_g(csi); break; |
||
2075 | case B('g','s'): |
||
2076 | error = pdf_run_gs(csi, rdb); |
||
2077 | if (error) |
||
2078 | fz_catch(error, "cannot set graphics state"); |
||
2079 | break; |
||
2080 | case A('h'): pdf_run_h(csi); break; |
||
2081 | case A('i'): pdf_run_i(csi); break; |
||
2082 | case A('j'): pdf_run_j(csi); break; |
||
2083 | case A('k'): pdf_run_k(csi); break; |
||
2084 | case A('l'): pdf_run_l(csi); break; |
||
2085 | case A('m'): pdf_run_m(csi); break; |
||
2086 | case A('n'): pdf_run_n(csi); break; |
||
2087 | case A('q'): pdf_run_q(csi); break; |
||
2088 | case B('r','e'): pdf_run_re(csi); break; |
||
2089 | case B('r','g'): pdf_run_rg(csi); break; |
||
2090 | case B('r','i'): pdf_run_ri(csi); break; |
||
2091 | case A('s'): pdf_run(csi); break; |
||
2092 | case B('s','c'): pdf_run_sc(csi, rdb); break; |
||
2093 | case C('s','c','n'): pdf_run_sc(csi, rdb); break; |
||
2094 | case B('s','h'): |
||
2095 | error = pdf_run_sh(csi, rdb); |
||
2096 | if (error) |
||
2097 | fz_catch(error, "cannot draw shading"); |
||
2098 | break; |
||
2099 | case A('v'): pdf_run_v(csi); break; |
||
2100 | case A('w'): pdf_run_w(csi); break; |
||
2101 | case A('y'): pdf_run_y(csi); break; |
||
2102 | default: |
||
2103 | if (!csi->xbalance) |
||
2104 | fz_warn("unknown keyword: '%s'", buf); |
||
2105 | break; |
||
2106 | } |
||
2107 | |||
2108 | return fz_okay; |
||
2109 | } |
||
2110 | |||
2111 | static fz_error |
||
2112 | pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen) |
||
2113 | { |
||
2114 | fz_error error; |
||
2115 | int tok, len, in_array; |
||
2116 | |||
2117 | /* make sure we have a clean slate if we come here from flush_text */ |
||
2118 | pdf_clear_stack(csi); |
||
2119 | in_array = 0; |
||
2120 | |||
2121 | while (1) |
||
2122 | { |
||
2123 | if (csi->top == nelem(csi->stack) - 1) |
||
2124 | return fz_throw("stack overflow"); |
||
2125 | |||
2126 | error = pdf_lex(&tok, file, buf, buflen, &len); |
||
2127 | if (error) |
||
2128 | return fz_rethrow(error, "lexical error in content stream"); |
||
2129 | |||
2130 | if (in_array) |
||
2131 | { |
||
2132 | if (tok == PDF_TOK_CLOSE_ARRAY) |
||
2133 | { |
||
2134 | in_array = 0; |
||
2135 | } |
||
2136 | else if (tok == PDF_TOK_INT || tok == PDF_TOK_REAL) |
||
2137 | { |
||
2138 | pdf_gstate *gstate = csi->gstate + csi->gtop; |
||
2139 | pdf_show_space(csi, -fz_atof(buf) * gstate->size * 0.001f); |
||
2140 | } |
||
2141 | else if (tok == PDF_TOK_STRING) |
||
2142 | { |
||
2143 | pdf_show_string(csi, (unsigned char *)buf, len); |
||
2144 | } |
||
2145 | else if (tok == PDF_TOK_KEYWORD) |
||
2146 | { |
||
2147 | if (!strcmp(buf, "Tw") || !strcmp(buf, "Tc")) |
||
2148 | fz_warn("ignoring keyword '%s' inside array", buf); |
||
2149 | else |
||
2150 | return fz_throw("syntax error in array"); |
||
2151 | } |
||
2152 | else if (tok == PDF_TOK_EOF) |
||
2153 | return fz_okay; |
||
2154 | else |
||
2155 | return fz_throw("syntax error in array"); |
||
2156 | } |
||
2157 | |||
2158 | else switch (tok) |
||
2159 | { |
||
2160 | case PDF_TOK_ENDSTREAM: |
||
2161 | case PDF_TOK_EOF: |
||
2162 | return fz_okay; |
||
2163 | |||
2164 | case PDF_TOK_OPEN_ARRAY: |
||
2165 | if (!csi->in_text) |
||
2166 | { |
||
2167 | error = pdf_parse_array(&csi->obj, csi->xref, file, buf, buflen); |
||
2168 | if (error) |
||
2169 | return fz_rethrow(error, "cannot parse array"); |
||
2170 | } |
||
2171 | else |
||
2172 | { |
||
2173 | in_array = 1; |
||
2174 | } |
||
2175 | break; |
||
2176 | |||
2177 | case PDF_TOK_OPEN_DICT: |
||
2178 | error = pdf_parse_dict(&csi->obj, csi->xref, file, buf, buflen); |
||
2179 | if (error) |
||
2180 | return fz_rethrow(error, "cannot parse dictionary"); |
||
2181 | break; |
||
2182 | |||
2183 | case PDF_TOK_NAME: |
||
2184 | fz_strlcpy(csi->name, buf, sizeof(csi->name)); |
||
2185 | break; |
||
2186 | |||
2187 | case PDF_TOK_INT: |
||
2188 | csi->stack[csi->top] = atoi(buf); |
||
2189 | csi->top ++; |
||
2190 | break; |
||
2191 | |||
2192 | case PDF_TOK_REAL: |
||
2193 | csi->stack[csi->top] = fz_atof(buf); |
||
2194 | csi->top ++; |
||
2195 | break; |
||
2196 | |||
2197 | case PDF_TOK_STRING: |
||
2198 | if (len <= sizeof(csi->string)) |
||
2199 | { |
||
2200 | memcpy(csi->string, buf, len); |
||
2201 | csi->string_len = len; |
||
2202 | } |
||
2203 | else |
||
2204 | { |
||
2205 | csi->obj = fz_new_string(buf, len); |
||
2206 | } |
||
2207 | break; |
||
2208 | |||
2209 | case PDF_TOK_KEYWORD: |
||
2210 | error = pdf_run_keyword(csi, rdb, file, buf); |
||
2211 | if (error) |
||
2212 | return fz_rethrow(error, "cannot run keyword"); |
||
2213 | pdf_clear_stack(csi); |
||
2214 | break; |
||
2215 | |||
2216 | default: |
||
2217 | return fz_throw("syntax error in content stream"); |
||
2218 | } |
||
2219 | } |
||
2220 | } |
||
2221 | |||
2222 | /* |
||
2223 | * Entry points |
||
2224 | */ |
||
2225 | |||
2226 | static fz_error |
||
2227 | pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents) |
||
2228 | { |
||
2229 | fz_error error; |
||
2230 | int len = sizeof csi->xref->scratch; |
||
2231 | char *buf = fz_malloc(len); /* we must be re-entrant for type3 fonts */ |
||
2232 | fz_stream *file = fz_open_buffer(contents); |
||
2233 | int save_in_text = csi->in_text; |
||
2234 | csi->in_text = 0; |
||
2235 | error = pdf_run_stream(csi, rdb, file, buf, len); |
||
2236 | csi->in_text = save_in_text; |
||
2237 | fz_close(file); |
||
2238 | fz_free(buf); |
||
2239 | if (error) |
||
2240 | return fz_rethrow(error, "cannot parse content stream"); |
||
2241 | return fz_okay; |
||
2242 | } |
||
2243 | |||
2244 | fz_error |
||
2245 | pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target) |
||
2246 | { |
||
2247 | pdf_csi *csi; |
||
2248 | fz_error error; |
||
2249 | pdf_annot *annot; |
||
2250 | int flags; |
||
2251 | |||
2252 | if (page->transparency) |
||
2253 | fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 1, 0, 0, 1); |
||
2254 | |||
2255 | csi = pdf_new_csi(xref, dev, ctm, target); |
||
2256 | error = pdf_run_buffer(csi, page->resources, page->contents); |
||
2257 | pdf_free_csi(csi); |
||
2258 | if (error) |
||
2259 | return fz_rethrow(error, "cannot parse page content stream"); |
||
2260 | |||
2261 | for (annot = page->annots; annot; annot = annot->next) |
||
2262 | { |
||
2263 | flags = fz_to_int(fz_dict_gets(annot->obj, "F")); |
||
2264 | |||
2265 | /* TODO: NoZoom and NoRotate */ |
||
2266 | if (flags & (1 << 0)) /* Invisible */ |
||
2267 | continue; |
||
2268 | if (flags & (1 << 1)) /* Hidden */ |
||
2269 | continue; |
||
2270 | if (flags & (1 << 5)) /* NoView */ |
||
2271 | continue; |
||
2272 | |||
2273 | if (pdf_is_hidden_ocg(annot->obj, target)) |
||
2274 | continue; |
||
2275 | |||
2276 | csi = pdf_new_csi(xref, dev, ctm, target); |
||
2277 | error = pdf_run_xobject(csi, page->resources, annot->ap, annot->matrix); |
||
2278 | pdf_free_csi(csi); |
||
2279 | if (error) |
||
2280 | return fz_rethrow(error, "cannot parse annotation appearance stream"); |
||
2281 | } |
||
2282 | |||
2283 | if (page->transparency) |
||
2284 | fz_end_group(dev); |
||
2285 | |||
2286 | return fz_okay; |
||
2287 | } |
||
2288 | |||
2289 | fz_error |
||
2290 | pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm) |
||
2291 | { |
||
2292 | return pdf_run_page_with_usage(xref, page, dev, ctm, "View"); |
||
2293 | } |
||
2294 | |||
2295 | fz_error |
||
2296 | pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm) |
||
2297 | { |
||
2298 | pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View"); |
||
2299 | fz_error error = pdf_run_buffer(csi, resources, contents); |
||
2300 | pdf_free_csi(csi); |
||
2301 | if (error) |
||
2302 | return fz_rethrow(error, "cannot parse glyph content stream"); |
||
2303 | return fz_okay; |
||
2304 | }><>><>><>=>><>><>><>><>><>>>>>>>>>>>>>>>>>> |