comparison mupdf-source/source/fitz/list-device.c @ 2:b50eed0cc0ef upstream

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