1 | #include "mupdf/fitz.h" |
2 | |
3 | #include <assert.h> |
4 | #include <string.h> |
5 | |
6 | typedef struct fz_display_node_s fz_display_node; |
7 | typedef struct fz_list_device_s fz_list_device; |
8 | |
9 | #define STACK_SIZE 96 |
10 | |
11 | typedef enum fz_display_command_e |
12 | { |
13 | FZ_CMD_FILL_PATH, |
14 | FZ_CMD_STROKE_PATH, |
15 | FZ_CMD_CLIP_PATH, |
16 | FZ_CMD_CLIP_STROKE_PATH, |
17 | FZ_CMD_FILL_TEXT, |
18 | FZ_CMD_STROKE_TEXT, |
19 | FZ_CMD_CLIP_TEXT, |
20 | FZ_CMD_CLIP_STROKE_TEXT, |
21 | FZ_CMD_IGNORE_TEXT, |
22 | FZ_CMD_FILL_SHADE, |
23 | FZ_CMD_FILL_IMAGE, |
24 | FZ_CMD_FILL_IMAGE_MASK, |
25 | FZ_CMD_CLIP_IMAGE_MASK, |
26 | FZ_CMD_POP_CLIP, |
27 | FZ_CMD_BEGIN_MASK, |
28 | FZ_CMD_END_MASK, |
29 | FZ_CMD_BEGIN_GROUP, |
30 | FZ_CMD_END_GROUP, |
31 | FZ_CMD_BEGIN_TILE, |
32 | FZ_CMD_END_TILE, |
33 | FZ_CMD_RENDER_FLAGS, |
34 | FZ_CMD_DEFAULT_COLORSPACES, |
35 | FZ_CMD_BEGIN_LAYER, |
36 | FZ_CMD_END_LAYER |
37 | } fz_display_command; |
38 | |
39 | /* The display list is a list of nodes. |
40 | * Each node is a structure consisting of a bitfield (that packs into a |
41 | * 32 bit word). |
42 | * The different fields in the bitfield identify what information is |
43 | * present in the node. |
44 | * |
45 | * cmd: What type of node this is. |
46 | * |
47 | * size: The number of sizeof(fz_display_node) bytes that this node's |
48 | * data occupies. (i.e. &node[node->size] = the next node in the |
49 | * chain; 0 for end of list). |
50 | * |
51 | * rect: 0 for unchanged, 1 for present. |
52 | * |
53 | * path: 0 for unchanged, 1 for present. |
54 | * |
55 | * cs: 0 for unchanged |
56 | * 1 for devicegray (color defaults to 0) |
57 | * 2 for devicegray (color defaults to 1) |
58 | * 3 for devicergb (color defaults to 0,0,0) |
59 | * 4 for devicergb (color defaults to 1,1,1) |
60 | * 5 for devicecmyk (color defaults to 0,0,0,0) |
61 | * 6 for devicecmyk (color defaults to 0,0,0,1) |
62 | * 7 for present (color defaults to 0) |
63 | * |
64 | * color: 0 for unchanged color, 1 for present. |
65 | * |
66 | * alpha: 0 for unchanged, 1 for solid, 2 for transparent, 3 |
67 | * for alpha value present. |
68 | * |
69 | * ctm: 0 for unchanged, |
70 | * 1 for change ad |
71 | * 2 for change bc |
72 | * 4 for change ef. |
73 | * |
74 | * stroke: 0 for unchanged, 1 for present. |
75 | * |
76 | * flags: Flags (node specific meanings) |
77 | * |
78 | * Nodes are packed in the order: |
79 | * header, rect, colorspace, color, alpha, ctm, stroke_state, path, private data. |
80 | */ |
81 | struct fz_display_node_s |
82 | { |
83 | unsigned int cmd : 5; |
84 | unsigned int size : 9; |
85 | unsigned int rect : 1; |
86 | unsigned int path : 1; |
87 | unsigned int cs : 3; |
88 | unsigned int color : 1; |
89 | unsigned int alpha : 2; |
90 | unsigned int ctm : 3; |
91 | unsigned int stroke : 1; |
92 | unsigned int flags : 6; |
93 | }; |
94 | |
95 | enum { |
96 | CS_UNCHANGED = 0, |
97 | CS_GRAY_0 = 1, |
98 | CS_GRAY_1 = 2, |
99 | CS_RGB_0 = 3, |
100 | CS_RGB_1 = 4, |
101 | CS_CMYK_0 = 5, |
102 | CS_CMYK_1 = 6, |
103 | CS_OTHER_0 = 7, |
104 | |
105 | ALPHA_UNCHANGED = 0, |
106 | ALPHA_1 = 1, |
107 | ALPHA_0 = 2, |
108 | ALPHA_PRESENT = 3, |
109 | |
110 | CTM_UNCHANGED = 0, |
111 | CTM_CHANGE_AD = 1, |
112 | CTM_CHANGE_BC = 2, |
113 | CTM_CHANGE_EF = 4, |
114 | |
115 | MAX_NODE_SIZE = (1<<9)-sizeof(fz_display_node) |
116 | }; |
117 | |
118 | struct fz_display_list_s |
119 | { |
120 | fz_storable storable; |
121 | fz_display_node *list; |
122 | fz_rect mediabox; |
123 | int max; |
124 | int len; |
125 | }; |
126 | |
127 | struct fz_list_device_s |
128 | { |
129 | fz_device super; |
130 | |
131 | fz_display_list *list; |
132 | |
133 | fz_path *path; |
134 | float alpha; |
135 | fz_matrix ctm; |
136 | fz_stroke_state *stroke; |
137 | fz_colorspace *colorspace; |
138 | fz_color_params *color_params; |
139 | float color[FZ_MAX_COLORS]; |
140 | fz_rect rect; |
141 | |
142 | int top; |
143 | struct { |
144 | fz_rect *update; |
145 | fz_rect rect; |
146 | } stack[STACK_SIZE]; |
147 | int tiled; |
148 | }; |
149 | |
150 | enum { ISOLATED = 1, KNOCKOUT = 2 }; |
151 | enum { OPM = 1, OP = 2, BP = 3, RI = 4}; |
152 | |
153 | #define SIZE_IN_NODES(t) \ |
154 | ((t + sizeof(fz_display_node) - 1) / sizeof(fz_display_node)) |
155 | |
156 | static void |
157 | fz_append_display_node( |
158 | fz_context *ctx, |
159 | fz_device *dev, |
160 | fz_display_command cmd, |
161 | int flags, |
162 | const fz_rect *rect, |
163 | const fz_path *path, |
164 | const float *color, |
165 | fz_colorspace *colorspace, |
166 | const float *alpha, |
167 | const fz_matrix *ctm, |
168 | const fz_stroke_state *stroke, |
169 | const void *private_data, |
170 | int private_data_len) |
171 | { |
172 | fz_display_node node = { 0 }; |
173 | fz_display_node *node_ptr; |
174 | fz_list_device *writer = (fz_list_device *)dev; |
175 | fz_display_list *list = writer->list; |
176 | int size; |
177 | int rect_off = 0; |
178 | int path_off = 0; |
179 | int color_off = 0; |
180 | int colorspace_off = 0; |
181 | int alpha_off = 0; |
182 | int ctm_off = 0; |
183 | int stroke_off = 0; |
184 | int rect_for_updates = 0; |
185 | int private_off = 0; |
186 | fz_path *my_path = NULL; |
187 | fz_stroke_state *my_stroke = NULL; |
188 | fz_rect local_rect; |
189 | int path_size = 0; |
190 | |
191 | switch (cmd) |
192 | { |
193 | case FZ_CMD_CLIP_PATH: |
194 | case FZ_CMD_CLIP_STROKE_PATH: |
195 | case FZ_CMD_CLIP_TEXT: |
196 | case FZ_CMD_CLIP_STROKE_TEXT: |
197 | case FZ_CMD_CLIP_IMAGE_MASK: |
198 | if (writer->top < STACK_SIZE) |
199 | { |
200 | rect_for_updates = 1; |
201 | writer->stack[writer->top].rect = fz_empty_rect; |
202 | } |
203 | writer->top++; |
204 | break; |
205 | case FZ_CMD_END_MASK: |
206 | if (writer->top < STACK_SIZE) |
207 | { |
208 | writer->stack[writer->top].update = NULL; |
209 | writer->stack[writer->top].rect = fz_empty_rect; |
210 | } |
211 | writer->top++; |
212 | break; |
213 | case FZ_CMD_BEGIN_TILE: |
214 | writer->tiled++; |
215 | if (writer->top > 0 && writer->top <= STACK_SIZE) |
216 | { |
217 | writer->stack[writer->top-1].rect = fz_infinite_rect; |
218 | } |
219 | break; |
220 | case FZ_CMD_END_TILE: |
221 | writer->tiled--; |
222 | break; |
223 | case FZ_CMD_END_GROUP: |
224 | break; |
225 | case FZ_CMD_POP_CLIP: |
226 | if (writer->top > STACK_SIZE) |
227 | { |
228 | writer->top--; |
229 | rect = &fz_infinite_rect; |
230 | } |
231 | else if (writer->top > 0) |
232 | { |
233 | fz_rect *update; |
234 | writer->top--; |
235 | update = writer->stack[writer->top].update; |
236 | if (writer->tiled == 0) |
237 | { |
238 | if (update) |
239 | { |
240 | *update = fz_intersect_rect(*update, writer->stack[writer->top].rect); |
241 | local_rect = *update; |
242 | rect = &local_rect; |
243 | } |
244 | else |
245 | rect = &writer->stack[writer->top].rect; |
246 | } |
247 | else |
248 | rect = &fz_infinite_rect; |
249 | } |
250 | /* fallthrough */ |
251 | default: |
252 | if (writer->top > 0 && writer->tiled == 0 && writer->top <= STACK_SIZE && rect) |
253 | writer->stack[writer->top-1].rect = fz_union_rect(writer->stack[writer->top-1].rect, *rect); |
254 | break; |
255 | } |
256 | |
257 | size = 1; /* 1 for the fz_display_node */ |
258 | node.cmd = cmd; |
259 | |
260 | /* Figure out what we need to write, and the offsets at which we will |
261 | * write it. */ |
262 | if (rect_for_updates || (rect != NULL && (writer->rect.x0 != rect->x0 || writer->rect.y0 != rect->y0 || writer->rect.x1 != rect->x1 || writer->rect.y1 != rect->y1))) |
263 | { |
264 | node.rect = 1; |
265 | rect_off = size; |
266 | size += SIZE_IN_NODES(sizeof(fz_rect)); |
267 | } |
268 | if (color || colorspace) |
269 | { |
270 | if (colorspace != writer->colorspace) |
271 | { |
272 | assert(color); |
273 | if (colorspace == fz_device_gray(ctx)) |
274 | { |
275 | if (color[0] == 0.0f) |
276 | node.cs = CS_GRAY_0, color = NULL; |
277 | else |
278 | { |
279 | node.cs = CS_GRAY_1; |
280 | if (color[0] == 1.0f) |
281 | color = NULL; |
282 | } |
283 | } |
284 | else if (colorspace == fz_device_rgb(ctx)) |
285 | { |
286 | if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) |
287 | node.cs = CS_RGB_0, color = NULL; |
288 | else |
289 | { |
290 | node.cs = CS_RGB_1; |
291 | if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f) |
292 | color = NULL; |
293 | } |
294 | } |
295 | else if (colorspace == fz_device_cmyk(ctx)) |
296 | { |
297 | node.cs = CS_CMYK_0; |
298 | if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) |
299 | { |
300 | if (color[3] == 0.0f) |
301 | color = NULL; |
302 | else |
303 | { |
304 | node.cs = CS_CMYK_1; |
305 | if (color[3] == 1.0f) |
306 | color = NULL; |
307 | } |
308 | } |
309 | } |
310 | else |
311 | { |
312 | int i; |
313 | int n = fz_colorspace_n(ctx, colorspace); |
314 | |
315 | colorspace_off = size; |
316 | size += SIZE_IN_NODES(sizeof(fz_colorspace *)); |
317 | node.cs = CS_OTHER_0; |
318 | for (i = 0; i < n; i++) |
319 | if (color[i] != 0.0f) |
320 | break; |
321 | if (i == n) |
322 | color = NULL; |
323 | memset(writer->color, 0, sizeof(float)*n); |
324 | } |
325 | } |
326 | else |
327 | { |
328 | /* Colorspace is unchanged, but color may have changed |
329 | * to something best coded as a colorspace change */ |
330 | if (colorspace == fz_device_gray(ctx)) |
331 | { |
332 | if (writer->color[0] != color[0]) |
333 | { |
334 | if (color[0] == 0.0f) |
335 | { |
336 | node.cs = CS_GRAY_0; |
337 | color = NULL; |
338 | } |
339 | else if (color[0] == 1.0f) |
340 | { |
341 | node.cs = CS_GRAY_1; |
342 | color = NULL; |
343 | } |
344 | } |
345 | } |
346 | else if (colorspace == fz_device_rgb(ctx)) |
347 | { |
348 | if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2]) |
349 | { |
350 | if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) |
351 | { |
352 | node.cs = CS_RGB_0; |
353 | color = NULL; |
354 | } |
355 | else if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f) |
356 | { |
357 | node.cs = CS_RGB_1; |
358 | color = NULL; |
359 | } |
360 | } |
361 | } |
362 | else if (colorspace == fz_device_cmyk(ctx)) |
363 | { |
364 | if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2] || writer->color[3] != color[3]) |
365 | { |
366 | if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) |
367 | { |
368 | if (color[3] == 0.0f) |
369 | { |
370 | node.cs = CS_CMYK_0; |
371 | color = NULL; |
372 | } |
373 | else if (color[3] == 1.0f) |
374 | { |
375 | node.cs = CS_CMYK_1; |
376 | color = NULL; |
377 | } |
378 | } |
379 | } |
380 | } |
381 | else |
382 | { |
383 | int i; |
384 | int n = fz_colorspace_n(ctx, colorspace); |
385 | for (i=0; i < n; i++) |
386 | if (color[i] != 0.0f) |
387 | break; |
388 | if (i == n) |
389 | { |
390 | node.cs = CS_OTHER_0; |
391 | colorspace_off = size; |
392 | size += SIZE_IN_NODES(sizeof(fz_colorspace *)); |
393 | color = NULL; |
394 | } |
395 | } |
396 | } |
397 | } |
398 | if (color) |
399 | { |
400 | int i, n; |
401 | const float *wc = &writer->color[0]; |
402 | |
403 | assert(colorspace != NULL); |
404 | n = fz_colorspace_n(ctx, colorspace); |
405 | i = 0; |
406 | /* Only check colors if the colorspace is unchanged. If the |
407 | * colorspace *has* changed and the colors are implicit then |
408 | * this will have been caught above. */ |
409 | if (colorspace == writer->colorspace) |
410 | for (; i < n; i++) |
411 | if (color[i] != wc[i]) |
412 | break; |
413 | |
414 | if (i != n) |
415 | { |
416 | node.color = 1; |
417 | color_off = size; |
418 | size += n * SIZE_IN_NODES(sizeof(float)); |
419 | } |
420 | } |
421 | if (alpha && (*alpha != writer->alpha)) |
422 | { |
423 | if (*alpha >= 1.0f) |
424 | node.alpha = ALPHA_1; |
425 | else if (*alpha <= 0.0f) |
426 | node.alpha = ALPHA_0; |
427 | else |
428 | { |
429 | alpha_off = size; |
430 | size += SIZE_IN_NODES(sizeof(float)); |
431 | node.alpha = ALPHA_PRESENT; |
432 | } |
433 | } |
434 | if (ctm && (ctm->a != writer->ctm.a || ctm->b != writer->ctm.b || ctm->c != writer->ctm.c || ctm->d != writer->ctm.d || ctm->e != writer->ctm.e || ctm->f != writer->ctm.f)) |
435 | { |
436 | int ctm_flags; |
437 | |
438 | ctm_off = size; |
439 | ctm_flags = CTM_UNCHANGED; |
440 | if (ctm->a != writer->ctm.a || ctm->d != writer->ctm.d) |
441 | ctm_flags = CTM_CHANGE_AD, size += SIZE_IN_NODES(2*sizeof(float)); |
442 | if (ctm->b != writer->ctm.b || ctm->c != writer->ctm.c) |
443 | ctm_flags |= CTM_CHANGE_BC, size += SIZE_IN_NODES(2*sizeof(float)); |
444 | if (ctm->e != writer->ctm.e || ctm->f != writer->ctm.f) |
445 | ctm_flags |= CTM_CHANGE_EF, size += SIZE_IN_NODES(2*sizeof(float)); |
446 | node.ctm = ctm_flags; |
447 | } |
448 | if (stroke && (writer->stroke == NULL || stroke != writer->stroke)) |
449 | { |
450 | stroke_off = size; |
451 | size += SIZE_IN_NODES(sizeof(fz_stroke_state *)); |
452 | node.stroke = 1; |
453 | } |
454 | if (path && (writer->path == NULL || path != writer->path)) |
455 | { |
456 | int max = SIZE_IN_NODES(MAX_NODE_SIZE) - size - SIZE_IN_NODES(private_data_len); |
457 | path_size = SIZE_IN_NODES(fz_pack_path(ctx, NULL, max, path)); |
458 | node.path = 1; |
459 | path_off = size; |
460 | |
461 | size += path_size; |
462 | } |
463 | if (private_data != NULL) |
464 | { |
465 | int max = SIZE_IN_NODES(MAX_NODE_SIZE) - size; |
466 | if (SIZE_IN_NODES(private_data_len) > max) |
467 | fz_throw(ctx, FZ_ERROR_GENERIC, "Private data too large to pack into display list node" ); |
468 | private_off = size; |
469 | size += SIZE_IN_NODES(private_data_len); |
470 | } |
471 | |
472 | while (list->len + size > list->max) |
473 | { |
474 | int newsize = list->max * 2; |
475 | fz_display_node *old = list->list; |
476 | ptrdiff_t diff; |
477 | int i, n; |
478 | |
479 | if (newsize < 256) |
480 | newsize = 256; |
481 | list->list = fz_realloc_array(ctx, list->list, newsize, fz_display_node); |
482 | list->max = newsize; |
483 | diff = (char *)(list->list) - (char *)old; |
484 | n = (writer->top < STACK_SIZE ? writer->top : STACK_SIZE); |
485 | for (i = 0; i < n; i++) |
486 | { |
487 | if (writer->stack[i].update != NULL) |
488 | writer->stack[i].update = (fz_rect *)(((char *)writer->stack[i].update) + diff); |
489 | } |
490 | if (writer->path) |
491 | writer->path = (fz_path *)(((char *)writer->path) + diff); |
492 | } |
493 | |
494 | /* Write the node to the list */ |
495 | node.size = size; |
496 | node.flags = flags; |
497 | assert(size < (1<<9)); |
498 | node_ptr = &list->list[list->len]; |
499 | *node_ptr = node; |
500 | |
501 | /* Path is the most frequent one, so try to avoid the try/catch in |
502 | * this case */ |
503 | if (path_off) |
504 | { |
505 | my_path = (void *)(&node_ptr[path_off]); |
506 | (void)fz_pack_path(ctx, (void *)my_path, path_size * sizeof(fz_display_node), path); |
507 | } |
508 | |
509 | if (stroke_off) |
510 | { |
511 | fz_try(ctx) |
512 | { |
513 | my_stroke = fz_keep_stroke_state(ctx, stroke); |
514 | } |
515 | fz_catch(ctx) |
516 | { |
517 | fz_drop_path(ctx, my_path); |
518 | fz_rethrow(ctx); |
519 | } |
520 | } |
521 | |
522 | if (rect_off) |
523 | { |
524 | fz_rect *out_rect = (fz_rect *)(void *)(&node_ptr[rect_off]); |
525 | writer->rect = *rect; |
526 | *out_rect = *rect; |
527 | if (rect_for_updates) |
528 | writer->stack[writer->top-1].update = out_rect; |
529 | } |
530 | if (path_off) |
531 | { |
532 | fz_drop_path(ctx, writer->path); |
533 | writer->path = fz_keep_path(ctx, my_path); /* Can never fail */ |
534 | } |
535 | if (node.cs) |
536 | { |
537 | fz_drop_colorspace(ctx, writer->colorspace); |
538 | switch(node.cs) |
539 | { |
540 | case CS_GRAY_0: |
541 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
542 | writer->color[0] = 0; |
543 | break; |
544 | case CS_GRAY_1: |
545 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
546 | writer->color[0] = 1; |
547 | break; |
548 | case CS_RGB_0: |
549 | writer->color[0] = 0; |
550 | writer->color[1] = 0; |
551 | writer->color[2] = 0; |
552 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
553 | break; |
554 | case CS_RGB_1: |
555 | writer->color[0] = 1; |
556 | writer->color[1] = 1; |
557 | writer->color[2] = 1; |
558 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
559 | break; |
560 | case CS_CMYK_0: |
561 | writer->color[0] = 0; |
562 | writer->color[1] = 0; |
563 | writer->color[2] = 0; |
564 | writer->color[3] = 0; |
565 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); |
566 | break; |
567 | case CS_CMYK_1: |
568 | writer->color[0] = 0; |
569 | writer->color[1] = 0; |
570 | writer->color[2] = 0; |
571 | writer->color[3] = 1; |
572 | writer->colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); |
573 | break; |
574 | default: |
575 | { |
576 | fz_colorspace **out_colorspace = (fz_colorspace **)(void *)(&node_ptr[colorspace_off]); |
577 | int i, n; |
578 | n = fz_colorspace_n(ctx, colorspace); |
579 | *out_colorspace = fz_keep_colorspace(ctx, colorspace); |
580 | |
581 | writer->colorspace = fz_keep_colorspace(ctx, colorspace); |
582 | for (i = 0; i < n; i++) |
583 | writer->color[i] = 0; |
584 | break; |
585 | } |
586 | } |
587 | } |
588 | if (color_off) |
589 | { |
590 | int n = fz_colorspace_n(ctx, colorspace); |
591 | float *out_color = (float *)(void *)(&node_ptr[color_off]); |
592 | memcpy(writer->color, color, n * sizeof(float)); |
593 | memcpy(out_color, color, n * sizeof(float)); |
594 | } |
595 | if (node.alpha) |
596 | { |
597 | writer->alpha = *alpha; |
598 | if (alpha_off) |
599 | { |
600 | float *out_alpha = (float *)(void *)(&node_ptr[alpha_off]); |
601 | *out_alpha = *alpha; |
602 | } |
603 | } |
604 | if (ctm_off) |
605 | { |
606 | float *out_ctm = (float *)(void *)(&node_ptr[ctm_off]); |
607 | if (node.ctm & CTM_CHANGE_AD) |
608 | { |
609 | writer->ctm.a = *out_ctm++ = ctm->a; |
610 | writer->ctm.d = *out_ctm++ = ctm->d; |
611 | } |
612 | if (node.ctm & CTM_CHANGE_BC) |
613 | { |
614 | writer->ctm.b = *out_ctm++ = ctm->b; |
615 | writer->ctm.c = *out_ctm++ = ctm->c; |
616 | } |
617 | if (node.ctm & CTM_CHANGE_EF) |
618 | { |
619 | writer->ctm.e = *out_ctm++ = ctm->e; |
620 | writer->ctm.f = *out_ctm = ctm->f; |
621 | } |
622 | } |
623 | if (stroke_off) |
624 | { |
625 | fz_stroke_state **out_stroke = (fz_stroke_state **)(void *)(&node_ptr[stroke_off]); |
626 | *out_stroke = my_stroke; |
627 | fz_drop_stroke_state(ctx, writer->stroke); |
628 | /* Can never fail as my_stroke was kept above */ |
629 | writer->stroke = fz_keep_stroke_state(ctx, my_stroke); |
630 | } |
631 | if (private_off) |
632 | { |
633 | char *out_private = (char *)(void *)(&node_ptr[private_off]); |
634 | memcpy(out_private, private_data, private_data_len); |
635 | } |
636 | list->len += size; |
637 | } |
638 | |
639 | /* Pack ri, op, opm, bp into flags upper bits, even/odd in lower bit */ |
640 | static int |
641 | fz_pack_color_params(fz_color_params color_params) |
642 | { |
643 | int flags = 0; |
644 | flags |= color_params.ri << RI; /* 2 bits */ |
645 | flags |= color_params.bp << BP; |
646 | flags |= color_params.op << OP; |
647 | flags |= color_params.opm << OPM; |
648 | return flags; |
649 | } |
650 | |
651 | /* unpack ri, op, opm, bp from flags, even/odd in lower bit */ |
652 | static void |
653 | fz_unpack_color_params(fz_color_params *color_params, int flags) |
654 | { |
655 | color_params->ri = (flags >> RI) & 3; |
656 | color_params->bp = (flags >> BP) & 1; |
657 | color_params->op = (flags >> OP) & 1; |
658 | color_params->opm = (flags >> OPM) & 1; |
659 | } |
660 | |
661 | static void |
662 | fz_list_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, |
663 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
664 | { |
665 | fz_rect rect = fz_bound_path(ctx, path, NULL, ctm); |
666 | fz_append_display_node( |
667 | ctx, |
668 | dev, |
669 | FZ_CMD_FILL_PATH, |
670 | even_odd | fz_pack_color_params(color_params), /* flags */ |
671 | &rect, |
672 | path, /* path */ |
673 | color, |
674 | colorspace, |
675 | &alpha, /* alpha */ |
676 | &ctm, |
677 | NULL, /* stroke_state */ |
678 | NULL, /* private_data */ |
679 | 0); /* private_data_len */ |
680 | } |
681 | |
682 | static void |
683 | fz_list_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, |
684 | fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
685 | { |
686 | fz_rect rect = fz_bound_path(ctx, path, stroke, ctm); |
687 | fz_append_display_node( |
688 | ctx, |
689 | dev, |
690 | FZ_CMD_STROKE_PATH, |
691 | fz_pack_color_params(color_params), /* flags */ |
692 | &rect, |
693 | path, /* path */ |
694 | color, |
695 | colorspace, |
696 | &alpha, /* alpha */ |
697 | &ctm, /* ctm */ |
698 | stroke, |
699 | NULL, /* private_data */ |
700 | 0); /* private_data_len */ |
701 | } |
702 | |
703 | static void |
704 | fz_list_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor) |
705 | { |
706 | fz_rect rect = fz_bound_path(ctx, path, NULL, ctm); |
707 | rect = fz_intersect_rect(rect, scissor); |
708 | fz_append_display_node( |
709 | ctx, |
710 | dev, |
711 | FZ_CMD_CLIP_PATH, |
712 | even_odd, /* flags */ |
713 | &rect, |
714 | path, /* path */ |
715 | NULL, /* color */ |
716 | NULL, /* colorspace */ |
717 | NULL, /* alpha */ |
718 | &ctm, /* ctm */ |
719 | NULL, /* stroke */ |
720 | NULL, /* private_data */ |
721 | 0); /* private_data_len */ |
722 | } |
723 | |
724 | static void |
725 | fz_list_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor) |
726 | { |
727 | fz_rect rect = fz_bound_path(ctx, path, stroke, ctm); |
728 | rect = fz_intersect_rect(rect, scissor); |
729 | fz_append_display_node( |
730 | ctx, |
731 | dev, |
732 | FZ_CMD_CLIP_STROKE_PATH, |
733 | 0, /* flags */ |
734 | &rect, |
735 | path, /* path */ |
736 | NULL, /* color */ |
737 | NULL, /* colorspace */ |
738 | NULL, /* alpha */ |
739 | &ctm, /* ctm */ |
740 | stroke, /* stroke */ |
741 | NULL, /* private_data */ |
742 | 0); /* private_data_len */ |
743 | } |
744 | |
745 | static void |
746 | fz_list_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, |
747 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
748 | { |
749 | fz_text *cloned_text = fz_keep_text(ctx, text); |
750 | fz_try(ctx) |
751 | { |
752 | fz_rect rect = fz_bound_text(ctx, text, NULL, ctm); |
753 | fz_append_display_node( |
754 | ctx, |
755 | dev, |
756 | FZ_CMD_FILL_TEXT, |
757 | fz_pack_color_params(color_params), /* flags */ |
758 | &rect, |
759 | NULL, /* path */ |
760 | color, /* color */ |
761 | colorspace, /* colorspace */ |
762 | &alpha, /* alpha */ |
763 | &ctm, /* ctm */ |
764 | NULL, /* stroke */ |
765 | &cloned_text, /* private_data */ |
766 | sizeof(cloned_text)); /* private_data_len */ |
767 | } |
768 | fz_catch(ctx) |
769 | { |
770 | fz_drop_text(ctx, cloned_text); |
771 | fz_rethrow(ctx); |
772 | } |
773 | } |
774 | |
775 | static void |
776 | fz_list_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, |
777 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
778 | { |
779 | fz_text *cloned_text = fz_keep_text(ctx, text); |
780 | fz_try(ctx) |
781 | { |
782 | fz_rect rect = fz_bound_text(ctx, text, stroke, ctm); |
783 | fz_append_display_node( |
784 | ctx, |
785 | dev, |
786 | FZ_CMD_STROKE_TEXT, |
787 | fz_pack_color_params(color_params), /* flags */ |
788 | &rect, |
789 | NULL, /* path */ |
790 | color, /* color */ |
791 | colorspace, /* colorspace */ |
792 | &alpha, /* alpha */ |
793 | &ctm, /* ctm */ |
794 | stroke, |
795 | &cloned_text, /* private_data */ |
796 | sizeof(cloned_text)); /* private_data_len */ |
797 | } |
798 | fz_catch(ctx) |
799 | { |
800 | fz_drop_text(ctx, cloned_text); |
801 | fz_rethrow(ctx); |
802 | } |
803 | } |
804 | |
805 | static void |
806 | fz_list_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor) |
807 | { |
808 | fz_text *cloned_text = fz_keep_text(ctx, text); |
809 | fz_try(ctx) |
810 | { |
811 | fz_rect rect = fz_bound_text(ctx, text, NULL, ctm); |
812 | rect = fz_intersect_rect(rect, scissor); |
813 | fz_append_display_node( |
814 | ctx, |
815 | dev, |
816 | FZ_CMD_CLIP_TEXT, |
817 | 0, /* flags */ |
818 | &rect, |
819 | NULL, /* path */ |
820 | NULL, /* color */ |
821 | NULL, /* colorspace */ |
822 | NULL, /* alpha */ |
823 | &ctm, /* ctm */ |
824 | NULL, /* stroke */ |
825 | &cloned_text, /* private_data */ |
826 | sizeof(cloned_text)); /* private_data_len */ |
827 | } |
828 | fz_catch(ctx) |
829 | { |
830 | fz_drop_text(ctx, cloned_text); |
831 | fz_rethrow(ctx); |
832 | } |
833 | } |
834 | |
835 | static void |
836 | fz_list_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor) |
837 | { |
838 | fz_text *cloned_text = fz_keep_text(ctx, text); |
839 | fz_try(ctx) |
840 | { |
841 | fz_rect rect = fz_bound_text(ctx, text, stroke, ctm); |
842 | rect = fz_intersect_rect(rect, scissor); |
843 | fz_append_display_node( |
844 | ctx, |
845 | dev, |
846 | FZ_CMD_CLIP_STROKE_TEXT, |
847 | 0, /* flags */ |
848 | &rect, |
849 | NULL, /* path */ |
850 | NULL, /* color */ |
851 | NULL, /* colorspace */ |
852 | NULL, /* alpha */ |
853 | &ctm, /* ctm */ |
854 | stroke, /* stroke */ |
855 | &cloned_text, /* private_data */ |
856 | sizeof(cloned_text)); /* private_data_len */ |
857 | } |
858 | fz_catch(ctx) |
859 | { |
860 | fz_drop_text(ctx, cloned_text); |
861 | fz_rethrow(ctx); |
862 | } |
863 | } |
864 | |
865 | static void |
866 | fz_list_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm) |
867 | { |
868 | fz_text *cloned_text = fz_keep_text(ctx, text); |
869 | fz_try(ctx) |
870 | { |
871 | fz_rect rect = fz_bound_text(ctx, text, NULL, ctm); |
872 | fz_append_display_node( |
873 | ctx, |
874 | dev, |
875 | FZ_CMD_IGNORE_TEXT, |
876 | 0, /* flags */ |
877 | &rect, |
878 | NULL, /* path */ |
879 | NULL, /* color */ |
880 | NULL, /* colorspace */ |
881 | NULL, /* alpha */ |
882 | &ctm, /* ctm */ |
883 | NULL, /* stroke */ |
884 | &cloned_text, /* private_data */ |
885 | sizeof(cloned_text)); /* private_data_len */ |
886 | } |
887 | fz_catch(ctx) |
888 | { |
889 | fz_drop_text(ctx, cloned_text); |
890 | fz_rethrow(ctx); |
891 | } |
892 | } |
893 | |
894 | static void |
895 | fz_list_pop_clip(fz_context *ctx, fz_device *dev) |
896 | { |
897 | fz_append_display_node( |
898 | ctx, |
899 | dev, |
900 | FZ_CMD_POP_CLIP, |
901 | 0, /* flags */ |
902 | NULL, /* rect */ |
903 | NULL, /* path */ |
904 | NULL, /* color */ |
905 | NULL, /* colorspace */ |
906 | NULL, /* alpha */ |
907 | NULL, /* ctm */ |
908 | NULL, /* stroke */ |
909 | NULL, /* private_data */ |
910 | 0); /* private_data_len */ |
911 | } |
912 | |
913 | static void |
914 | fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params) |
915 | { |
916 | fz_shade *shade2 = fz_keep_shade(ctx, shade); |
917 | fz_try(ctx) |
918 | { |
919 | fz_rect rect = fz_bound_shade(ctx, shade, ctm); |
920 | fz_append_display_node( |
921 | ctx, |
922 | dev, |
923 | FZ_CMD_FILL_SHADE, |
924 | fz_pack_color_params(color_params), /* flags */ |
925 | &rect, |
926 | NULL, /* path */ |
927 | NULL, /* color */ |
928 | NULL, /* colorspace */ |
929 | &alpha, /* alpha */ |
930 | &ctm, /* ctm */ |
931 | NULL, /* stroke */ |
932 | &shade2, /* private_data */ |
933 | sizeof(shade2)); /* private_data_len */ |
934 | } |
935 | fz_catch(ctx) |
936 | { |
937 | fz_drop_shade(ctx, shade2); |
938 | fz_rethrow(ctx); |
939 | } |
940 | } |
941 | |
942 | static void |
943 | fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params) |
944 | { |
945 | fz_image *image2 = fz_keep_image(ctx, image); |
946 | fz_try(ctx) |
947 | { |
948 | fz_rect rect = fz_transform_rect(fz_unit_rect, ctm); |
949 | fz_append_display_node( |
950 | ctx, |
951 | dev, |
952 | FZ_CMD_FILL_IMAGE, |
953 | fz_pack_color_params(color_params), /* flags */ |
954 | &rect, |
955 | NULL, /* path */ |
956 | NULL, /* color */ |
957 | NULL, /* colorspace */ |
958 | &alpha, /* alpha */ |
959 | &ctm, /* ctm */ |
960 | NULL, /* stroke */ |
961 | &image2, /* private_data */ |
962 | sizeof(image2)); /* private_data_len */ |
963 | } |
964 | fz_catch(ctx) |
965 | { |
966 | fz_drop_image(ctx, image2); |
967 | fz_rethrow(ctx); |
968 | } |
969 | } |
970 | |
971 | static void |
972 | fz_list_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, |
973 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
974 | { |
975 | fz_image *image2 = fz_keep_image(ctx, image); |
976 | |
977 | fz_try(ctx) |
978 | { |
979 | fz_rect rect = fz_transform_rect(fz_unit_rect, ctm); |
980 | fz_append_display_node( |
981 | ctx, |
982 | dev, |
983 | FZ_CMD_FILL_IMAGE_MASK, |
984 | fz_pack_color_params(color_params), /* flags */ |
985 | &rect, |
986 | NULL, /* path */ |
987 | color, |
988 | colorspace, |
989 | &alpha, /* alpha */ |
990 | &ctm, /* ctm */ |
991 | NULL, /* stroke */ |
992 | &image2, /* private_data */ |
993 | sizeof(image2)); /* private_data_len */ |
994 | } |
995 | fz_catch(ctx) |
996 | { |
997 | fz_drop_image(ctx, image2); |
998 | fz_rethrow(ctx); |
999 | } |
1000 | } |
1001 | |
1002 | static void |
1003 | fz_list_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor) |
1004 | { |
1005 | fz_image *image2 = fz_keep_image(ctx, image); |
1006 | fz_try(ctx) |
1007 | { |
1008 | fz_rect rect = fz_transform_rect(fz_unit_rect, ctm); |
1009 | rect = fz_intersect_rect(rect, scissor); |
1010 | fz_append_display_node( |
1011 | ctx, |
1012 | dev, |
1013 | FZ_CMD_CLIP_IMAGE_MASK, |
1014 | 0, /* flags */ |
1015 | &rect, |
1016 | NULL, /* path */ |
1017 | NULL, /* color */ |
1018 | NULL, /* colorspace */ |
1019 | NULL, /* alpha */ |
1020 | &ctm, /* ctm */ |
1021 | NULL, /* stroke */ |
1022 | &image2, /* private_data */ |
1023 | sizeof(image2)); /* private_data_len */ |
1024 | } |
1025 | fz_catch(ctx) |
1026 | { |
1027 | fz_drop_image(ctx, image2); |
1028 | fz_rethrow(ctx); |
1029 | } |
1030 | } |
1031 | |
1032 | static void |
1033 | fz_list_begin_mask(fz_context *ctx, fz_device *dev, fz_rect rect, int luminosity, fz_colorspace *colorspace, const float *color, fz_color_params color_params) |
1034 | { |
1035 | fz_append_display_node( |
1036 | ctx, |
1037 | dev, |
1038 | FZ_CMD_BEGIN_MASK, |
1039 | (!!luminosity) | fz_pack_color_params(color_params), /* flags */ |
1040 | &rect, |
1041 | NULL, /* path */ |
1042 | color, |
1043 | colorspace, |
1044 | NULL, /* alpha */ |
1045 | NULL, /* ctm */ |
1046 | NULL, /* stroke */ |
1047 | NULL, /* private_data */ |
1048 | 0); /* private_data_len */ |
1049 | } |
1050 | |
1051 | static void |
1052 | fz_list_end_mask(fz_context *ctx, fz_device *dev) |
1053 | { |
1054 | fz_append_display_node( |
1055 | ctx, |
1056 | dev, |
1057 | FZ_CMD_END_MASK, |
1058 | 0, /* flags */ |
1059 | NULL, /* rect */ |
1060 | NULL, /* path */ |
1061 | NULL, /* color */ |
1062 | NULL, /* colorspace */ |
1063 | NULL, /* alpha */ |
1064 | NULL, /* ctm */ |
1065 | NULL, /* stroke */ |
1066 | NULL, /* private_data */ |
1067 | 0); /* private_data_len */ |
1068 | } |
1069 | |
1070 | static void |
1071 | fz_list_begin_group(fz_context *ctx, fz_device *dev, fz_rect rect, fz_colorspace *colorspace, int isolated, int knockout, int blendmode, float alpha) |
1072 | { |
1073 | int flags; |
1074 | |
1075 | colorspace = fz_keep_colorspace(ctx, colorspace); |
1076 | |
1077 | flags = (blendmode<<2); |
1078 | if (isolated) |
1079 | flags |= ISOLATED; |
1080 | if (knockout) |
1081 | flags |= KNOCKOUT; |
1082 | |
1083 | fz_try(ctx) |
1084 | { |
1085 | fz_append_display_node( |
1086 | ctx, |
1087 | dev, |
1088 | FZ_CMD_BEGIN_GROUP, |
1089 | flags, |
1090 | &rect, |
1091 | NULL, /* path */ |
1092 | NULL, /* color */ |
1093 | NULL, /* colorspace */ |
1094 | &alpha, /* alpha */ |
1095 | NULL, /* ctm */ |
1096 | NULL, /* stroke */ |
1097 | &colorspace, /* private_data */ |
1098 | sizeof(colorspace)); /* private_data_len */ |
1099 | } |
1100 | fz_catch(ctx) |
1101 | { |
1102 | fz_drop_colorspace(ctx, colorspace); |
1103 | fz_rethrow(ctx); |
1104 | } |
1105 | } |
1106 | |
1107 | static void |
1108 | fz_list_end_group(fz_context *ctx, fz_device *dev) |
1109 | { |
1110 | fz_append_display_node( |
1111 | ctx, |
1112 | dev, |
1113 | FZ_CMD_END_GROUP, |
1114 | 0, /* flags */ |
1115 | NULL, /* rect */ |
1116 | NULL, /* path */ |
1117 | NULL, /* color */ |
1118 | NULL, /* colorspace */ |
1119 | NULL, /* alpha */ |
1120 | NULL, /* ctm */ |
1121 | NULL, /* stroke */ |
1122 | NULL, /* private_data */ |
1123 | 0); /* private_data_len */ |
1124 | } |
1125 | |
1126 | typedef struct fz_list_tile_data_s fz_list_tile_data; |
1127 | |
1128 | struct fz_list_tile_data_s |
1129 | { |
1130 | float xstep; |
1131 | float ystep; |
1132 | fz_rect view; |
1133 | int id; |
1134 | }; |
1135 | |
1136 | static int |
1137 | fz_list_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id) |
1138 | { |
1139 | fz_list_tile_data tile; |
1140 | |
1141 | tile.xstep = xstep; |
1142 | tile.ystep = ystep; |
1143 | tile.view = view; |
1144 | tile.id = id; |
1145 | fz_append_display_node( |
1146 | ctx, |
1147 | dev, |
1148 | FZ_CMD_BEGIN_TILE, |
1149 | 0, /* flags */ |
1150 | &area, |
1151 | NULL, /* path */ |
1152 | NULL, /* color */ |
1153 | NULL, /* colorspace */ |
1154 | NULL, /* alpha */ |
1155 | &ctm, /* ctm */ |
1156 | NULL, /* stroke */ |
1157 | &tile, /* private_data */ |
1158 | sizeof(tile)); /* private_data_len */ |
1159 | |
1160 | return 0; |
1161 | } |
1162 | |
1163 | static void |
1164 | fz_list_end_tile(fz_context *ctx, fz_device *dev) |
1165 | { |
1166 | fz_append_display_node( |
1167 | ctx, |
1168 | dev, |
1169 | FZ_CMD_END_TILE, |
1170 | 0, /* flags */ |
1171 | NULL, |
1172 | NULL, /* path */ |
1173 | NULL, /* color */ |
1174 | NULL, /* colorspace */ |
1175 | NULL, /* alpha */ |
1176 | NULL, /* ctm */ |
1177 | NULL, /* stroke */ |
1178 | NULL, /* private_data */ |
1179 | 0); /* private_data_len */ |
1180 | } |
1181 | |
1182 | static void |
1183 | fz_list_render_flags(fz_context *ctx, fz_device *dev, int set, int clear) |
1184 | { |
1185 | int flags; |
1186 | |
1187 | /* Pack the options down */ |
1188 | if (set == FZ_DEVFLAG_GRIDFIT_AS_TILED && clear == 0) |
1189 | flags = 1; |
1190 | else if (set == 0 && clear == FZ_DEVFLAG_GRIDFIT_AS_TILED) |
1191 | flags = 0; |
1192 | else |
1193 | { |
1194 | assert("Unsupported flags combination" == NULL); |
1195 | return; |
1196 | } |
1197 | fz_append_display_node( |
1198 | ctx, |
1199 | dev, |
1200 | FZ_CMD_RENDER_FLAGS, |
1201 | flags, /* flags */ |
1202 | NULL, |
1203 | NULL, /* path */ |
1204 | NULL, /* color */ |
1205 | NULL, /* colorspace */ |
1206 | NULL, /* alpha */ |
1207 | NULL, /* ctm */ |
1208 | NULL, /* stroke */ |
1209 | NULL, /* private_data */ |
1210 | 0); /* private_data_len */ |
1211 | } |
1212 | |
1213 | static void |
1214 | fz_list_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs) |
1215 | { |
1216 | fz_default_colorspaces *default_cs2 = fz_keep_default_colorspaces(ctx, default_cs); |
1217 | |
1218 | fz_try(ctx) |
1219 | { |
1220 | fz_append_display_node( |
1221 | ctx, |
1222 | dev, |
1223 | FZ_CMD_DEFAULT_COLORSPACES, |
1224 | 0, /* flags */ |
1225 | NULL, |
1226 | NULL, /* path */ |
1227 | NULL, /* color */ |
1228 | NULL, /* colorspace */ |
1229 | NULL, /* alpha */ |
1230 | NULL, /* ctm */ |
1231 | NULL, /* stroke */ |
1232 | &default_cs2, /* private_data */ |
1233 | sizeof(default_cs2)); /* private_data_len */ |
1234 | } |
1235 | fz_catch(ctx) |
1236 | { |
1237 | fz_drop_default_colorspaces(ctx, default_cs2); |
1238 | fz_rethrow(ctx); |
1239 | } |
1240 | } |
1241 | |
1242 | static void |
1243 | fz_list_begin_layer(fz_context *ctx, fz_device *dev, const char *layer_name) |
1244 | { |
1245 | fz_append_display_node( |
1246 | ctx, |
1247 | dev, |
1248 | FZ_CMD_BEGIN_LAYER, |
1249 | 0, /* flags */ |
1250 | NULL, |
1251 | NULL, /* path */ |
1252 | NULL, /* color */ |
1253 | NULL, /* colorspace */ |
1254 | NULL, /* alpha */ |
1255 | NULL, |
1256 | NULL, /* stroke */ |
1257 | layer_name, /* private_data */ |
1258 | 1+strlen(layer_name)); /* private_data_len */ |
1259 | } |
1260 | |
1261 | static void |
1262 | fz_list_end_layer(fz_context *ctx, fz_device *dev) |
1263 | { |
1264 | fz_append_display_node( |
1265 | ctx, |
1266 | dev, |
1267 | FZ_CMD_END_LAYER, |
1268 | 0, /* flags */ |
1269 | NULL, |
1270 | NULL, /* path */ |
1271 | NULL, /* color */ |
1272 | NULL, /* colorspace */ |
1273 | NULL, /* alpha */ |
1274 | NULL, /* ctm */ |
1275 | NULL, /* stroke */ |
1276 | NULL, /* private_data */ |
1277 | 0); /* private_data_len */ |
1278 | } |
1279 | |
1280 | static void |
1281 | fz_list_drop_device(fz_context *ctx, fz_device *dev) |
1282 | { |
1283 | fz_list_device *writer = (fz_list_device *)dev; |
1284 | |
1285 | fz_drop_colorspace(ctx, writer->colorspace); |
1286 | fz_drop_stroke_state(ctx, writer->stroke); |
1287 | fz_drop_path(ctx, writer->path); |
1288 | } |
1289 | |
1290 | /* |
1291 | Create a rendering device for a display list. |
1292 | |
1293 | When the device is rendering a page it will populate the |
1294 | display list with drawing commands (text, images, etc.). The |
1295 | display list can later be reused to render a page many times |
1296 | without having to re-interpret the page from the document file |
1297 | for each rendering. Once the device is no longer needed, free |
1298 | it with fz_drop_device. |
1299 | |
1300 | list: A display list that the list device takes ownership of. |
1301 | */ |
1302 | fz_device * |
1303 | fz_new_list_device(fz_context *ctx, fz_display_list *list) |
1304 | { |
1305 | fz_list_device *dev; |
1306 | |
1307 | dev = fz_new_derived_device(ctx, fz_list_device); |
1308 | |
1309 | dev->super.fill_path = fz_list_fill_path; |
1310 | dev->super.stroke_path = fz_list_stroke_path; |
1311 | dev->super.clip_path = fz_list_clip_path; |
1312 | dev->super.clip_stroke_path = fz_list_clip_stroke_path; |
1313 | |
1314 | dev->super.fill_text = fz_list_fill_text; |
1315 | dev->super.stroke_text = fz_list_stroke_text; |
1316 | dev->super.clip_text = fz_list_clip_text; |
1317 | dev->super.clip_stroke_text = fz_list_clip_stroke_text; |
1318 | dev->super.ignore_text = fz_list_ignore_text; |
1319 | |
1320 | dev->super.fill_shade = fz_list_fill_shade; |
1321 | dev->super.fill_image = fz_list_fill_image; |
1322 | dev->super.fill_image_mask = fz_list_fill_image_mask; |
1323 | dev->super.clip_image_mask = fz_list_clip_image_mask; |
1324 | |
1325 | dev->super.pop_clip = fz_list_pop_clip; |
1326 | |
1327 | dev->super.begin_mask = fz_list_begin_mask; |
1328 | dev->super.end_mask = fz_list_end_mask; |
1329 | dev->super.begin_group = fz_list_begin_group; |
1330 | dev->super.end_group = fz_list_end_group; |
1331 | |
1332 | dev->super.begin_tile = fz_list_begin_tile; |
1333 | dev->super.end_tile = fz_list_end_tile; |
1334 | |
1335 | dev->super.render_flags = fz_list_render_flags; |
1336 | dev->super.set_default_colorspaces = fz_list_set_default_colorspaces; |
1337 | |
1338 | dev->super.begin_layer = fz_list_begin_layer; |
1339 | dev->super.end_layer = fz_list_end_layer; |
1340 | |
1341 | dev->super.drop_device = fz_list_drop_device; |
1342 | |
1343 | dev->list = list; |
1344 | dev->path = NULL; |
1345 | dev->alpha = 1.0f; |
1346 | dev->ctm = fz_identity; |
1347 | dev->stroke = NULL; |
1348 | dev->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
1349 | memset(dev->color, 0, sizeof(float)*FZ_MAX_COLORS); |
1350 | dev->top = 0; |
1351 | dev->tiled = 0; |
1352 | |
1353 | return &dev->super; |
1354 | } |
1355 | |
1356 | static void |
1357 | fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_) |
1358 | { |
1359 | fz_display_list *list = (fz_display_list *)list_; |
1360 | fz_display_node *node = list->list; |
1361 | fz_display_node *node_end = list->list + list->len; |
1362 | int cs_n = 1; |
1363 | fz_colorspace *cs; |
1364 | |
1365 | while (node != node_end) |
1366 | { |
1367 | fz_display_node n = *node; |
1368 | fz_display_node *next = node + n.size; |
1369 | |
1370 | node++; |
1371 | if (n.rect) |
1372 | { |
1373 | node += SIZE_IN_NODES(sizeof(fz_rect)); |
1374 | } |
1375 | switch (n.cs) |
1376 | { |
1377 | default: |
1378 | case CS_UNCHANGED: |
1379 | break; |
1380 | case CS_GRAY_0: |
1381 | case CS_GRAY_1: |
1382 | cs_n = 1; |
1383 | break; |
1384 | case CS_RGB_0: |
1385 | case CS_RGB_1: |
1386 | cs_n = 3; |
1387 | break; |
1388 | case CS_CMYK_0: |
1389 | case CS_CMYK_1: |
1390 | cs_n = 4; |
1391 | break; |
1392 | case CS_OTHER_0: |
1393 | cs = *(fz_colorspace **)node; |
1394 | cs_n = fz_colorspace_n(ctx, cs); |
1395 | fz_drop_colorspace(ctx, cs); |
1396 | node += SIZE_IN_NODES(sizeof(fz_colorspace *)); |
1397 | break; |
1398 | } |
1399 | if (n.color) |
1400 | { |
1401 | node += SIZE_IN_NODES(cs_n * sizeof(float)); |
1402 | } |
1403 | if (n.alpha == ALPHA_PRESENT) |
1404 | { |
1405 | node += SIZE_IN_NODES(sizeof(float)); |
1406 | } |
1407 | if (n.ctm & CTM_CHANGE_AD) |
1408 | node += SIZE_IN_NODES(2*sizeof(float)); |
1409 | if (n.ctm & CTM_CHANGE_BC) |
1410 | node += SIZE_IN_NODES(2*sizeof(float)); |
1411 | if (n.ctm & CTM_CHANGE_EF) |
1412 | node += SIZE_IN_NODES(2*sizeof(float)); |
1413 | if (n.stroke) |
1414 | { |
1415 | fz_drop_stroke_state(ctx, *(fz_stroke_state **)node); |
1416 | node += SIZE_IN_NODES(sizeof(fz_stroke_state *)); |
1417 | } |
1418 | if (n.path) |
1419 | { |
1420 | int path_size = fz_packed_path_size((fz_path *)node); |
1421 | fz_drop_path(ctx, (fz_path *)node); |
1422 | node += SIZE_IN_NODES(path_size); |
1423 | } |
1424 | switch(n.cmd) |
1425 | { |
1426 | case FZ_CMD_FILL_TEXT: |
1427 | case FZ_CMD_STROKE_TEXT: |
1428 | case FZ_CMD_CLIP_TEXT: |
1429 | case FZ_CMD_CLIP_STROKE_TEXT: |
1430 | case FZ_CMD_IGNORE_TEXT: |
1431 | fz_drop_text(ctx, *(fz_text **)node); |
1432 | break; |
1433 | case FZ_CMD_FILL_SHADE: |
1434 | fz_drop_shade(ctx, *(fz_shade **)node); |
1435 | break; |
1436 | case FZ_CMD_FILL_IMAGE: |
1437 | case FZ_CMD_FILL_IMAGE_MASK: |
1438 | case FZ_CMD_CLIP_IMAGE_MASK: |
1439 | fz_drop_image(ctx, *(fz_image **)node); |
1440 | break; |
1441 | case FZ_CMD_BEGIN_GROUP: |
1442 | fz_drop_colorspace(ctx, *(fz_colorspace **)node); |
1443 | break; |
1444 | case FZ_CMD_DEFAULT_COLORSPACES: |
1445 | fz_drop_default_colorspaces(ctx, *(fz_default_colorspaces **)node); |
1446 | break; |
1447 | } |
1448 | node = next; |
1449 | } |
1450 | fz_free(ctx, list->list); |
1451 | fz_free(ctx, list); |
1452 | } |
1453 | |
1454 | /* |
1455 | Create an empty display list. |
1456 | |
1457 | A display list contains drawing commands (text, images, etc.). |
1458 | Use fz_new_list_device for populating the list. |
1459 | |
1460 | mediabox: Bounds of the page (in points) represented by the display list. |
1461 | */ |
1462 | fz_display_list * |
1463 | fz_new_display_list(fz_context *ctx, fz_rect mediabox) |
1464 | { |
1465 | fz_display_list *list = fz_malloc_struct(ctx, fz_display_list); |
1466 | FZ_INIT_STORABLE(list, 1, fz_drop_display_list_imp); |
1467 | list->list = NULL; |
1468 | list->mediabox = mediabox; |
1469 | list->max = 0; |
1470 | list->len = 0; |
1471 | return list; |
1472 | } |
1473 | |
1474 | fz_display_list * |
1475 | fz_keep_display_list(fz_context *ctx, fz_display_list *list) |
1476 | { |
1477 | return fz_keep_storable(ctx, &list->storable); |
1478 | } |
1479 | |
1480 | void |
1481 | fz_drop_display_list(fz_context *ctx, fz_display_list *list) |
1482 | { |
1483 | fz_defer_reap_start(ctx); |
1484 | fz_drop_storable(ctx, &list->storable); |
1485 | fz_defer_reap_end(ctx); |
1486 | } |
1487 | |
1488 | /* |
1489 | Return the bounding box of the page recorded in a display list. |
1490 | */ |
1491 | fz_rect |
1492 | fz_bound_display_list(fz_context *ctx, fz_display_list *list) |
1493 | { |
1494 | return list->mediabox; |
1495 | } |
1496 | |
1497 | /* |
1498 | Check for a display list being empty |
1499 | |
1500 | list: The list to check. |
1501 | |
1502 | Returns true if empty, false otherwise. |
1503 | */ |
1504 | int fz_display_list_is_empty(fz_context *ctx, const fz_display_list *list) |
1505 | { |
1506 | return !list || list->len == 0; |
1507 | } |
1508 | |
1509 | /* |
1510 | (Re)-run a display list through a device. |
1511 | |
1512 | list: A display list, created by fz_new_display_list and |
1513 | populated with objects from a page by running fz_run_page on a |
1514 | device obtained from fz_new_list_device. |
1515 | |
1516 | ctm: Transform to apply to display list contents. May include |
1517 | for example scaling and rotation, see fz_scale, fz_rotate and |
1518 | fz_concat. Set to fz_identity if no transformation is desired. |
1519 | |
1520 | scissor: Only the part of the contents of the display list |
1521 | visible within this area will be considered when the list is |
1522 | run through the device. This does not imply for tile objects |
1523 | contained in the display list. |
1524 | |
1525 | cookie: Communication mechanism between caller and library |
1526 | running the page. Intended for multi-threaded applications, |
1527 | while single-threaded applications set cookie to NULL. The |
1528 | caller may abort an ongoing page run. Cookie also communicates |
1529 | progress information back to the caller. The fields inside |
1530 | cookie are continually updated while the page is being run. |
1531 | */ |
1532 | void |
1533 | fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_rect scissor, fz_cookie *cookie) |
1534 | { |
1535 | fz_display_node *node; |
1536 | fz_display_node *node_end; |
1537 | fz_display_node *next_node; |
1538 | int clipped = 0; |
1539 | int tiled = 0; |
1540 | int progress = 0; |
1541 | |
1542 | /* Current graphics state as unpacked from list */ |
1543 | fz_path *path = NULL; |
1544 | float alpha = 1.0f; |
1545 | fz_matrix ctm = fz_identity; |
1546 | fz_stroke_state *stroke = NULL; |
1547 | float color[FZ_MAX_COLORS] = { 0 }; |
1548 | fz_colorspace *colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
1549 | fz_color_params color_params; |
1550 | fz_rect rect = { 0 }; |
1551 | |
1552 | /* Transformed versions of graphic state entries */ |
1553 | fz_rect trans_rect; |
1554 | fz_matrix trans_ctm; |
1555 | int tile_skip_depth = 0; |
1556 | |
1557 | if (cookie) |
1558 | { |
1559 | cookie->progress_max = list->len; |
1560 | cookie->progress = 0; |
1561 | } |
1562 | |
1563 | color_params = fz_default_color_params; |
1564 | |
1565 | node = list->list; |
1566 | node_end = &list->list[list->len]; |
1567 | for (; node != node_end ; node = next_node) |
1568 | { |
1569 | int empty; |
1570 | fz_display_node n = *node; |
1571 | |
1572 | next_node = node + n.size; |
1573 | |
1574 | /* Check the cookie for aborting */ |
1575 | if (cookie) |
1576 | { |
1577 | if (cookie->abort) |
1578 | break; |
1579 | cookie->progress = progress; |
1580 | progress += n.size; |
1581 | } |
1582 | |
1583 | node++; |
1584 | if (n.rect) |
1585 | { |
1586 | rect = *(fz_rect *)node; |
1587 | node += SIZE_IN_NODES(sizeof(fz_rect)); |
1588 | } |
1589 | if (n.cs) |
1590 | { |
1591 | int i, en; |
1592 | |
1593 | fz_drop_colorspace(ctx, colorspace); |
1594 | switch (n.cs) |
1595 | { |
1596 | default: |
1597 | case CS_GRAY_0: |
1598 | colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
1599 | color[0] = 0.0f; |
1600 | break; |
1601 | case CS_GRAY_1: |
1602 | colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx)); |
1603 | color[0] = 1.0f; |
1604 | break; |
1605 | case CS_RGB_0: |
1606 | colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
1607 | color[0] = 0.0f; |
1608 | color[1] = 0.0f; |
1609 | color[2] = 0.0f; |
1610 | break; |
1611 | case CS_RGB_1: |
1612 | colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
1613 | color[0] = 1.0f; |
1614 | color[1] = 1.0f; |
1615 | color[2] = 1.0f; |
1616 | break; |
1617 | case CS_CMYK_0: |
1618 | colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); |
1619 | color[0] = 0.0f; |
1620 | color[1] = 0.0f; |
1621 | color[2] = 0.0f; |
1622 | color[3] = 0.0f; |
1623 | break; |
1624 | case CS_CMYK_1: |
1625 | colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); |
1626 | color[0] = 0.0f; |
1627 | color[1] = 0.0f; |
1628 | color[2] = 0.0f; |
1629 | color[3] = 1.0f; |
1630 | break; |
1631 | case CS_OTHER_0: |
1632 | colorspace = fz_keep_colorspace(ctx, *(fz_colorspace **)(node)); |
1633 | node += SIZE_IN_NODES(sizeof(fz_colorspace *)); |
1634 | en = fz_colorspace_n(ctx, colorspace); |
1635 | for (i = 0; i < en; i++) |
1636 | color[i] = 0.0f; |
1637 | break; |
1638 | } |
1639 | } |
1640 | if (n.color) |
1641 | { |
1642 | int nc = fz_colorspace_n(ctx, colorspace); |
1643 | memcpy(color, (float *)node, nc * sizeof(float)); |
1644 | node += SIZE_IN_NODES(nc * sizeof(float)); |
1645 | } |
1646 | if (n.alpha) |
1647 | { |
1648 | switch(n.alpha) |
1649 | { |
1650 | default: |
1651 | case ALPHA_0: |
1652 | alpha = 0.0f; |
1653 | break; |
1654 | case ALPHA_1: |
1655 | alpha = 1.0f; |
1656 | break; |
1657 | case ALPHA_PRESENT: |
1658 | alpha = *(float *)node; |
1659 | node += SIZE_IN_NODES(sizeof(float)); |
1660 | break; |
1661 | } |
1662 | } |
1663 | if (n.ctm != 0) |
1664 | { |
1665 | float *packed_ctm = (float *)node; |
1666 | if (n.ctm & CTM_CHANGE_AD) |
1667 | { |
1668 | ctm.a = *packed_ctm++; |
1669 | ctm.d = *packed_ctm++; |
1670 | node += SIZE_IN_NODES(2*sizeof(float)); |
1671 | } |
1672 | if (n.ctm & CTM_CHANGE_BC) |
1673 | { |
1674 | ctm.b = *packed_ctm++; |
1675 | ctm.c = *packed_ctm++; |
1676 | node += SIZE_IN_NODES(2*sizeof(float)); |
1677 | } |
1678 | if (n.ctm & CTM_CHANGE_EF) |
1679 | { |
1680 | ctm.e = *packed_ctm++; |
1681 | ctm.f = *packed_ctm; |
1682 | node += SIZE_IN_NODES(2*sizeof(float)); |
1683 | } |
1684 | } |
1685 | if (n.stroke) |
1686 | { |
1687 | fz_drop_stroke_state(ctx, stroke); |
1688 | stroke = fz_keep_stroke_state(ctx, *(fz_stroke_state **)node); |
1689 | node += SIZE_IN_NODES(sizeof(fz_stroke_state *)); |
1690 | } |
1691 | if (n.path) |
1692 | { |
1693 | fz_drop_path(ctx, path); |
1694 | path = fz_keep_path(ctx, (fz_path *)node); |
1695 | node += SIZE_IN_NODES(fz_packed_path_size(path)); |
1696 | } |
1697 | |
1698 | if (tile_skip_depth > 0) |
1699 | { |
1700 | if (n.cmd == FZ_CMD_BEGIN_TILE) |
1701 | tile_skip_depth++; |
1702 | else if (n.cmd == FZ_CMD_END_TILE) |
1703 | tile_skip_depth--; |
1704 | if (tile_skip_depth > 0) |
1705 | continue; |
1706 | } |
1707 | |
1708 | trans_rect = fz_transform_rect(rect, top_ctm); |
1709 | |
1710 | /* cull objects to draw using a quick visibility test */ |
1711 | |
1712 | if (tiled || |
1713 | n.cmd == FZ_CMD_BEGIN_TILE || n.cmd == FZ_CMD_END_TILE || |
1714 | n.cmd == FZ_CMD_RENDER_FLAGS || n.cmd == FZ_CMD_DEFAULT_COLORSPACES || |
1715 | n.cmd == FZ_CMD_BEGIN_LAYER || n.cmd == FZ_CMD_END_LAYER) |
1716 | { |
1717 | empty = 0; |
1718 | } |
1719 | else |
1720 | { |
1721 | empty = fz_is_empty_rect(fz_intersect_rect(trans_rect, scissor)); |
1722 | } |
1723 | |
1724 | if (clipped || empty) |
1725 | { |
1726 | switch (n.cmd) |
1727 | { |
1728 | case FZ_CMD_CLIP_PATH: |
1729 | case FZ_CMD_CLIP_STROKE_PATH: |
1730 | case FZ_CMD_CLIP_TEXT: |
1731 | case FZ_CMD_CLIP_STROKE_TEXT: |
1732 | case FZ_CMD_CLIP_IMAGE_MASK: |
1733 | case FZ_CMD_BEGIN_MASK: |
1734 | case FZ_CMD_BEGIN_GROUP: |
1735 | clipped++; |
1736 | continue; |
1737 | case FZ_CMD_POP_CLIP: |
1738 | case FZ_CMD_END_GROUP: |
1739 | if (!clipped) |
1740 | goto visible; |
1741 | clipped--; |
1742 | continue; |
1743 | case FZ_CMD_END_MASK: |
1744 | if (!clipped) |
1745 | goto visible; |
1746 | continue; |
1747 | default: |
1748 | continue; |
1749 | } |
1750 | } |
1751 | |
1752 | visible: |
1753 | trans_ctm = fz_concat(ctm, top_ctm); |
1754 | |
1755 | fz_try(ctx) |
1756 | { |
1757 | switch (n.cmd) |
1758 | { |
1759 | case FZ_CMD_FILL_PATH: |
1760 | fz_unpack_color_params(&color_params, n.flags); |
1761 | fz_fill_path(ctx, dev, path, n.flags & 1, trans_ctm, colorspace, color, alpha, color_params); |
1762 | break; |
1763 | case FZ_CMD_STROKE_PATH: |
1764 | fz_unpack_color_params(&color_params, n.flags); |
1765 | fz_stroke_path(ctx, dev, path, stroke, trans_ctm, colorspace, color, alpha, color_params); |
1766 | break; |
1767 | case FZ_CMD_CLIP_PATH: |
1768 | fz_clip_path(ctx, dev, path, n.flags, trans_ctm, trans_rect); |
1769 | break; |
1770 | case FZ_CMD_CLIP_STROKE_PATH: |
1771 | fz_clip_stroke_path(ctx, dev, path, stroke, trans_ctm, trans_rect); |
1772 | break; |
1773 | case FZ_CMD_FILL_TEXT: |
1774 | fz_unpack_color_params(&color_params, n.flags); |
1775 | fz_fill_text(ctx, dev, *(fz_text **)node, trans_ctm, colorspace, color, alpha, color_params); |
1776 | break; |
1777 | case FZ_CMD_STROKE_TEXT: |
1778 | fz_unpack_color_params(&color_params, n.flags); |
1779 | fz_stroke_text(ctx, dev, *(fz_text **)node, stroke, trans_ctm, colorspace, color, alpha, color_params); |
1780 | break; |
1781 | case FZ_CMD_CLIP_TEXT: |
1782 | fz_clip_text(ctx, dev, *(fz_text **)node, trans_ctm, trans_rect); |
1783 | break; |
1784 | case FZ_CMD_CLIP_STROKE_TEXT: |
1785 | fz_clip_stroke_text(ctx, dev, *(fz_text **)node, stroke, trans_ctm, trans_rect); |
1786 | break; |
1787 | case FZ_CMD_IGNORE_TEXT: |
1788 | fz_ignore_text(ctx, dev, *(fz_text **)node, trans_ctm); |
1789 | break; |
1790 | case FZ_CMD_FILL_SHADE: |
1791 | fz_unpack_color_params(&color_params, n.flags); |
1792 | fz_fill_shade(ctx, dev, *(fz_shade **)node, trans_ctm, alpha, color_params); |
1793 | break; |
1794 | case FZ_CMD_FILL_IMAGE: |
1795 | fz_unpack_color_params(&color_params, n.flags); |
1796 | fz_fill_image(ctx, dev, *(fz_image **)node, trans_ctm, alpha, color_params); |
1797 | break; |
1798 | case FZ_CMD_FILL_IMAGE_MASK: |
1799 | fz_unpack_color_params(&color_params, n.flags); |
1800 | fz_fill_image_mask(ctx, dev, *(fz_image **)node, trans_ctm, colorspace, color, alpha, color_params); |
1801 | break; |
1802 | case FZ_CMD_CLIP_IMAGE_MASK: |
1803 | fz_clip_image_mask(ctx, dev, *(fz_image **)node, trans_ctm, trans_rect); |
1804 | break; |
1805 | case FZ_CMD_POP_CLIP: |
1806 | fz_pop_clip(ctx, dev); |
1807 | break; |
1808 | case FZ_CMD_BEGIN_MASK: |
1809 | fz_unpack_color_params(&color_params, n.flags); |
1810 | fz_begin_mask(ctx, dev, trans_rect, n.flags & 1, colorspace, color, color_params); |
1811 | break; |
1812 | case FZ_CMD_END_MASK: |
1813 | fz_end_mask(ctx, dev); |
1814 | break; |
1815 | case FZ_CMD_BEGIN_GROUP: |
1816 | fz_begin_group(ctx, dev, trans_rect, *(fz_colorspace **)node, (n.flags & ISOLATED) != 0, (n.flags & KNOCKOUT) != 0, (n.flags>>2), alpha); |
1817 | break; |
1818 | case FZ_CMD_END_GROUP: |
1819 | fz_end_group(ctx, dev); |
1820 | break; |
1821 | case FZ_CMD_BEGIN_TILE: |
1822 | { |
1823 | int cached; |
1824 | fz_list_tile_data *data = (fz_list_tile_data *)node; |
1825 | fz_rect tile_rect; |
1826 | tiled++; |
1827 | tile_rect = data->view; |
1828 | cached = fz_begin_tile_id(ctx, dev, rect, tile_rect, data->xstep, data->ystep, trans_ctm, data->id); |
1829 | if (cached) |
1830 | tile_skip_depth = 1; |
1831 | break; |
1832 | } |
1833 | case FZ_CMD_END_TILE: |
1834 | tiled--; |
1835 | fz_end_tile(ctx, dev); |
1836 | break; |
1837 | case FZ_CMD_RENDER_FLAGS: |
1838 | if (n.flags == 0) |
1839 | fz_render_flags(ctx, dev, 0, FZ_DEVFLAG_GRIDFIT_AS_TILED); |
1840 | else if (n.flags == 1) |
1841 | fz_render_flags(ctx, dev, FZ_DEVFLAG_GRIDFIT_AS_TILED, 0); |
1842 | break; |
1843 | case FZ_CMD_DEFAULT_COLORSPACES: |
1844 | fz_set_default_colorspaces(ctx, dev, *(fz_default_colorspaces **)node); |
1845 | break; |
1846 | case FZ_CMD_BEGIN_LAYER: |
1847 | fz_begin_layer(ctx, dev, (const char *)node); |
1848 | break; |
1849 | case FZ_CMD_END_LAYER: |
1850 | fz_end_layer(ctx, dev); |
1851 | break; |
1852 | } |
1853 | } |
1854 | fz_catch(ctx) |
1855 | { |
1856 | /* Swallow the error */ |
1857 | if (cookie) |
1858 | cookie->errors++; |
1859 | if (fz_caught(ctx) == FZ_ERROR_ABORT) |
1860 | break; |
1861 | fz_warn(ctx, "Ignoring error during interpretation" ); |
1862 | } |
1863 | } |
1864 | fz_drop_colorspace(ctx, colorspace); |
1865 | fz_drop_stroke_state(ctx, stroke); |
1866 | fz_drop_path(ctx, path); |
1867 | if (cookie) |
1868 | cookie->progress = progress; |
1869 | } |
1870 | |