1 #include "mupdf/fitz.h"
2
3 #include <assert.h>
4 #include <string.h>
5
6 #define STACK_SIZE 96
7
8 typedef enum
9 {
10 FZ_CMD_FILL_PATH,
11 FZ_CMD_STROKE_PATH,
12 FZ_CMD_CLIP_PATH,
13 FZ_CMD_CLIP_STROKE_PATH,
14 FZ_CMD_FILL_TEXT,
15 FZ_CMD_STROKE_TEXT,
16 FZ_CMD_CLIP_TEXT,
17 FZ_CMD_CLIP_STROKE_TEXT,
18 FZ_CMD_IGNORE_TEXT,
19 FZ_CMD_FILL_SHADE,
20 FZ_CMD_FILL_IMAGE,
21 FZ_CMD_FILL_IMAGE_MASK,
22 FZ_CMD_CLIP_IMAGE_MASK,
23 FZ_CMD_POP_CLIP,
24 FZ_CMD_BEGIN_MASK,
25 FZ_CMD_END_MASK,
26 FZ_CMD_BEGIN_GROUP,
27 FZ_CMD_END_GROUP,
28 FZ_CMD_BEGIN_TILE,
29 FZ_CMD_END_TILE,
30 FZ_CMD_RENDER_FLAGS,
31 FZ_CMD_DEFAULT_COLORSPACES,
32 FZ_CMD_BEGIN_LAYER,
33 FZ_CMD_END_LAYER
34 } fz_display_command;
35
36 /* The display list is a list of nodes.
37 * Each node is a structure consisting of a bitfield (that packs into a
38 * 32 bit word).
39 * The different fields in the bitfield identify what information is
40 * present in the node.
41 *
42 * cmd: What type of node this is.
43 *
44 * size: The number of sizeof(fz_display_node) bytes that this node's
45 * data occupies. (i.e. &node[node->size] = the next node in the
46 * chain; 0 for end of list).
47 *
48 * rect: 0 for unchanged, 1 for present.
49 *
50 * path: 0 for unchanged, 1 for present.
51 *
52 * cs: 0 for unchanged
53 * 1 for devicegray (color defaults to 0)
54 * 2 for devicegray (color defaults to 1)
55 * 3 for devicergb (color defaults to 0,0,0)
56 * 4 for devicergb (color defaults to 1,1,1)
57 * 5 for devicecmyk (color defaults to 0,0,0,0)
58 * 6 for devicecmyk (color defaults to 0,0,0,1)
59 * 7 for present (color defaults to 0)
60 *
61 * color: 0 for unchanged color, 1 for present.
62 *
63 * alpha: 0 for unchanged, 1 for solid, 2 for transparent, 3
64 * for alpha value present.
65 *
66 * ctm: 0 for unchanged,
67 * 1 for change ad
68 * 2 for change bc
69 * 4 for change ef.
70 *
71 * stroke: 0 for unchanged, 1 for present.
72 *
73 * flags: Flags (node specific meanings)
74 *
75 * Nodes are packed in the order:
76 * header, rect, colorspace, color, alpha, ctm, stroke_state, path, private data.
77 */
78 typedef struct
79 {
80 unsigned int cmd : 5;
81 unsigned int size : 9;
82 unsigned int rect : 1;
83 unsigned int path : 1;
84 unsigned int cs : 3;
85 unsigned int color : 1;
86 unsigned int alpha : 2;
87 unsigned int ctm : 3;
88 unsigned int stroke : 1;
89 unsigned int flags : 6;
90 } fz_display_node;
91
92 enum {
93 CS_UNCHANGED = 0,
94 CS_GRAY_0 = 1,
95 CS_GRAY_1 = 2,
96 CS_RGB_0 = 3,
97 CS_RGB_1 = 4,
98 CS_CMYK_0 = 5,
99 CS_CMYK_1 = 6,
100 CS_OTHER_0 = 7,
101
102 ALPHA_UNCHANGED = 0,
103 ALPHA_1 = 1,
104 ALPHA_0 = 2,
105 ALPHA_PRESENT = 3,
106
107 CTM_UNCHANGED = 0,
108 CTM_CHANGE_AD = 1,
109 CTM_CHANGE_BC = 2,
110 CTM_CHANGE_EF = 4,
111
112 MAX_NODE_SIZE = (1<<9)-sizeof(fz_display_node)
113 };
114
115 struct fz_display_list
116 {
117 fz_storable storable;
118 fz_display_node *list;
119 fz_rect mediabox;
120 size_t max;
121 size_t len;
122 };
123
124 typedef struct
125 {
126 fz_device super;
127
128 fz_display_list *list;
129
130 fz_path *path;
131 float alpha;
132 fz_matrix ctm;
133 fz_stroke_state *stroke;
134 fz_colorspace *colorspace;
135 fz_color_params *color_params;
136 float color[FZ_MAX_COLORS];
137 fz_rect rect;
138
139 int top;
140 struct {
141 fz_rect *update;
142 fz_rect rect;
143 } stack[STACK_SIZE];
144 int tiled;
145 } fz_list_device;
146
147 enum { ISOLATED = 1, KNOCKOUT = 2 };
148 enum { OPM = 1, OP = 2, BP = 3, RI = 4};
149
150 #define SIZE_IN_NODES(t) \
151 ((t + sizeof(fz_display_node) - 1) / sizeof(fz_display_node))
152
153 static void
fz_append_display_node(fz_context * ctx,fz_device * dev,fz_display_command cmd,int flags,const fz_rect * rect,const fz_path * path,const float * color,fz_colorspace * colorspace,const float * alpha,const fz_matrix * ctm,const fz_stroke_state * stroke,const void * private_data,size_t private_data_len)154 fz_append_display_node(
155 fz_context *ctx,
156 fz_device *dev,
157 fz_display_command cmd,
158 int flags,
159 const fz_rect *rect,
160 const fz_path *path,
161 const float *color,
162 fz_colorspace *colorspace,
163 const float *alpha,
164 const fz_matrix *ctm,
165 const fz_stroke_state *stroke,
166 const void *private_data,
167 size_t private_data_len)
168 {
169 fz_display_node node = { 0 };
170 fz_display_node *node_ptr;
171 fz_list_device *writer = (fz_list_device *)dev;
172 fz_display_list *list = writer->list;
173 size_t size;
174 size_t rect_off = 0;
175 size_t path_off = 0;
176 size_t color_off = 0;
177 size_t colorspace_off = 0;
178 size_t alpha_off = 0;
179 size_t ctm_off = 0;
180 size_t stroke_off = 0;
181 int rect_for_updates = 0;
182 size_t private_off = 0;
183 fz_path *my_path = NULL;
184 fz_stroke_state *my_stroke = NULL;
185 fz_rect local_rect;
186 size_t path_size = 0;
187
188 switch (cmd)
189 {
190 case FZ_CMD_CLIP_PATH:
191 case FZ_CMD_CLIP_STROKE_PATH:
192 case FZ_CMD_CLIP_TEXT:
193 case FZ_CMD_CLIP_STROKE_TEXT:
194 case FZ_CMD_CLIP_IMAGE_MASK:
195 if (writer->top < STACK_SIZE)
196 {
197 rect_for_updates = 1;
198 writer->stack[writer->top].rect = fz_empty_rect;
199 }
200 writer->top++;
201 break;
202 case FZ_CMD_END_MASK:
203 if (writer->top < STACK_SIZE)
204 {
205 writer->stack[writer->top].update = NULL;
206 writer->stack[writer->top].rect = fz_empty_rect;
207 }
208 writer->top++;
209 break;
210 case FZ_CMD_BEGIN_TILE:
211 writer->tiled++;
212 if (writer->top > 0 && writer->top <= STACK_SIZE)
213 {
214 writer->stack[writer->top-1].rect = fz_infinite_rect;
215 }
216 break;
217 case FZ_CMD_END_TILE:
218 writer->tiled--;
219 break;
220 case FZ_CMD_END_GROUP:
221 break;
222 case FZ_CMD_POP_CLIP:
223 if (writer->top > STACK_SIZE)
224 {
225 writer->top--;
226 rect = &fz_infinite_rect;
227 }
228 else if (writer->top > 0)
229 {
230 fz_rect *update;
231 writer->top--;
232 update = writer->stack[writer->top].update;
233 if (writer->tiled == 0)
234 {
235 if (update)
236 {
237 *update = fz_intersect_rect(*update, writer->stack[writer->top].rect);
238 local_rect = *update;
239 rect = &local_rect;
240 }
241 else
242 rect = &writer->stack[writer->top].rect;
243 }
244 else
245 rect = &fz_infinite_rect;
246 }
247 /* fallthrough */
248 default:
249 if (writer->top > 0 && writer->tiled == 0 && writer->top <= STACK_SIZE && rect)
250 writer->stack[writer->top-1].rect = fz_union_rect(writer->stack[writer->top-1].rect, *rect);
251 break;
252 }
253
254 size = 1; /* 1 for the fz_display_node */
255 node.cmd = cmd;
256
257 /* Figure out what we need to write, and the offsets at which we will
258 * write it. */
259 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)))
260 {
261 node.rect = 1;
262 rect_off = size;
263 size += SIZE_IN_NODES(sizeof(fz_rect));
264 }
265 if (color || colorspace)
266 {
267 if (colorspace != writer->colorspace)
268 {
269 assert(color);
270 if (colorspace == fz_device_gray(ctx))
271 {
272 if (color[0] == 0.0f)
273 node.cs = CS_GRAY_0, color = NULL;
274 else
275 {
276 node.cs = CS_GRAY_1;
277 if (color[0] == 1.0f)
278 color = NULL;
279 }
280 }
281 else if (colorspace == fz_device_rgb(ctx))
282 {
283 if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f)
284 node.cs = CS_RGB_0, color = NULL;
285 else
286 {
287 node.cs = CS_RGB_1;
288 if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f)
289 color = NULL;
290 }
291 }
292 else if (colorspace == fz_device_cmyk(ctx))
293 {
294 node.cs = CS_CMYK_0;
295 if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f)
296 {
297 if (color[3] == 0.0f)
298 color = NULL;
299 else
300 {
301 node.cs = CS_CMYK_1;
302 if (color[3] == 1.0f)
303 color = NULL;
304 }
305 }
306 }
307 else
308 {
309 int i;
310 int n = fz_colorspace_n(ctx, colorspace);
311
312 colorspace_off = size;
313 size += SIZE_IN_NODES(sizeof(fz_colorspace *));
314 node.cs = CS_OTHER_0;
315 for (i = 0; i < n; i++)
316 if (color[i] != 0.0f)
317 break;
318 if (i == n)
319 color = NULL;
320 memset(writer->color, 0, sizeof(float)*n);
321 }
322 }
323 else
324 {
325 /* Colorspace is unchanged, but color may have changed
326 * to something best coded as a colorspace change */
327 if (colorspace == fz_device_gray(ctx))
328 {
329 if (writer->color[0] != color[0])
330 {
331 if (color[0] == 0.0f)
332 {
333 node.cs = CS_GRAY_0;
334 color = NULL;
335 }
336 else if (color[0] == 1.0f)
337 {
338 node.cs = CS_GRAY_1;
339 color = NULL;
340 }
341 }
342 }
343 else if (colorspace == fz_device_rgb(ctx))
344 {
345 if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2])
346 {
347 if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f)
348 {
349 node.cs = CS_RGB_0;
350 color = NULL;
351 }
352 else if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f)
353 {
354 node.cs = CS_RGB_1;
355 color = NULL;
356 }
357 }
358 }
359 else if (colorspace == fz_device_cmyk(ctx))
360 {
361 if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2] || writer->color[3] != color[3])
362 {
363 if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f)
364 {
365 if (color[3] == 0.0f)
366 {
367 node.cs = CS_CMYK_0;
368 color = NULL;
369 }
370 else if (color[3] == 1.0f)
371 {
372 node.cs = CS_CMYK_1;
373 color = NULL;
374 }
375 }
376 }
377 }
378 else
379 {
380 int i;
381 int n = fz_colorspace_n(ctx, colorspace);
382 for (i=0; i < n; i++)
383 if (color[i] != 0.0f)
384 break;
385 if (i == n)
386 {
387 node.cs = CS_OTHER_0;
388 colorspace_off = size;
389 size += SIZE_IN_NODES(sizeof(fz_colorspace *));
390 color = NULL;
391 }
392 }
393 }
394 }
395 if (color)
396 {
397 int i, n;
398 const float *wc = &writer->color[0];
399
400 assert(colorspace != NULL);
401 n = fz_colorspace_n(ctx, colorspace);
402 i = 0;
403 /* Only check colors if the colorspace is unchanged. If the
404 * colorspace *has* changed and the colors are implicit then
405 * this will have been caught above. */
406 if (colorspace == writer->colorspace)
407 for (; i < n; i++)
408 if (color[i] != wc[i])
409 break;
410
411 if (i != n)
412 {
413 node.color = 1;
414 color_off = size;
415 size += n * SIZE_IN_NODES(sizeof(float));
416 }
417 }
418 if (alpha && (*alpha != writer->alpha))
419 {
420 if (*alpha >= 1.0f)
421 node.alpha = ALPHA_1;
422 else if (*alpha <= 0.0f)
423 node.alpha = ALPHA_0;
424 else
425 {
426 alpha_off = size;
427 size += SIZE_IN_NODES(sizeof(float));
428 node.alpha = ALPHA_PRESENT;
429 }
430 }
431 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))
432 {
433 int ctm_flags;
434
435 ctm_off = size;
436 ctm_flags = CTM_UNCHANGED;
437 if (ctm->a != writer->ctm.a || ctm->d != writer->ctm.d)
438 ctm_flags = CTM_CHANGE_AD, size += SIZE_IN_NODES(2*sizeof(float));
439 if (ctm->b != writer->ctm.b || ctm->c != writer->ctm.c)
440 ctm_flags |= CTM_CHANGE_BC, size += SIZE_IN_NODES(2*sizeof(float));
441 if (ctm->e != writer->ctm.e || ctm->f != writer->ctm.f)
442 ctm_flags |= CTM_CHANGE_EF, size += SIZE_IN_NODES(2*sizeof(float));
443 node.ctm = ctm_flags;
444 }
445 if (stroke && (writer->stroke == NULL || stroke != writer->stroke))
446 {
447 stroke_off = size;
448 size += SIZE_IN_NODES(sizeof(fz_stroke_state *));
449 node.stroke = 1;
450 }
451 if (path && (writer->path == NULL || path != writer->path))
452 {
453 size_t max = SIZE_IN_NODES(MAX_NODE_SIZE) - size - SIZE_IN_NODES(private_data_len);
454 path_size = SIZE_IN_NODES(fz_pack_path(ctx, NULL, max, path));
455 node.path = 1;
456 path_off = size;
457
458 size += path_size;
459 }
460 if (private_data != NULL)
461 {
462 size_t max = SIZE_IN_NODES(MAX_NODE_SIZE) - size;
463 if (SIZE_IN_NODES(private_data_len) > max)
464 fz_throw(ctx, FZ_ERROR_GENERIC, "Private data too large to pack into display list node");
465 private_off = size;
466 size += SIZE_IN_NODES(private_data_len);
467 }
468
469 while (list->len + size > list->max)
470 {
471 size_t newsize = list->max * 2;
472 fz_display_node *old = list->list;
473 ptrdiff_t diff;
474 int i, n;
475
476 if (newsize < 256)
477 newsize = 256;
478 list->list = fz_realloc_array(ctx, list->list, newsize, fz_display_node);
479 list->max = newsize;
480 diff = (char *)(list->list) - (char *)old;
481 n = (writer->top < STACK_SIZE ? writer->top : STACK_SIZE);
482 for (i = 0; i < n; i++)
483 {
484 if (writer->stack[i].update != NULL)
485 writer->stack[i].update = (fz_rect *)(((char *)writer->stack[i].update) + diff);
486 }
487 if (writer->path)
488 writer->path = (fz_path *)(((char *)writer->path) + diff);
489 }
490
491 if ((unsigned int)size != size)
492 fz_throw(ctx, FZ_ERROR_GENERIC, "Display list node too large");
493
494 /* Write the node to the list */
495 node.size = (unsigned int)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
fz_pack_color_params(fz_color_params color_params)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
fz_unpack_color_params(fz_color_params * color_params,int flags)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
fz_list_fill_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_list_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_list_clip_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_rect scissor)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
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)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
fz_list_fill_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_list_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_list_clip_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_rect scissor)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
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)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
fz_list_ignore_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm)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
fz_list_pop_clip(fz_context * ctx,fz_device * dev)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
fz_list_fill_shade(fz_context * ctx,fz_device * dev,fz_shade * shade,fz_matrix ctm,float alpha,fz_color_params color_params)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
fz_list_fill_image(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,float alpha,fz_color_params color_params)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
fz_list_fill_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_list_clip_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_rect scissor)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
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)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
fz_list_end_mask(fz_context * ctx,fz_device * dev)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
fz_list_begin_group(fz_context * ctx,fz_device * dev,fz_rect rect,fz_colorspace * colorspace,int isolated,int knockout,int blendmode,float alpha)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
fz_list_end_group(fz_context * ctx,fz_device * dev)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
1127 {
1128 float xstep;
1129 float ystep;
1130 fz_rect view;
1131 int id;
1132 } fz_list_tile_data;
1133
1134 static int
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)1135 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)
1136 {
1137 fz_list_tile_data tile;
1138
1139 tile.xstep = xstep;
1140 tile.ystep = ystep;
1141 tile.view = view;
1142 tile.id = id;
1143 fz_append_display_node(
1144 ctx,
1145 dev,
1146 FZ_CMD_BEGIN_TILE,
1147 0, /* flags */
1148 &area,
1149 NULL, /* path */
1150 NULL, /* color */
1151 NULL, /* colorspace */
1152 NULL, /* alpha */
1153 &ctm, /* ctm */
1154 NULL, /* stroke */
1155 &tile, /* private_data */
1156 sizeof(tile)); /* private_data_len */
1157
1158 return 0;
1159 }
1160
1161 static void
fz_list_end_tile(fz_context * ctx,fz_device * dev)1162 fz_list_end_tile(fz_context *ctx, fz_device *dev)
1163 {
1164 fz_append_display_node(
1165 ctx,
1166 dev,
1167 FZ_CMD_END_TILE,
1168 0, /* flags */
1169 NULL,
1170 NULL, /* path */
1171 NULL, /* color */
1172 NULL, /* colorspace */
1173 NULL, /* alpha */
1174 NULL, /* ctm */
1175 NULL, /* stroke */
1176 NULL, /* private_data */
1177 0); /* private_data_len */
1178 }
1179
1180 static void
fz_list_render_flags(fz_context * ctx,fz_device * dev,int set,int clear)1181 fz_list_render_flags(fz_context *ctx, fz_device *dev, int set, int clear)
1182 {
1183 int flags;
1184
1185 /* Pack the options down */
1186 if (set == FZ_DEVFLAG_GRIDFIT_AS_TILED && clear == 0)
1187 flags = 1;
1188 else if (set == 0 && clear == FZ_DEVFLAG_GRIDFIT_AS_TILED)
1189 flags = 0;
1190 else
1191 {
1192 assert("Unsupported flags combination" == NULL);
1193 return;
1194 }
1195 fz_append_display_node(
1196 ctx,
1197 dev,
1198 FZ_CMD_RENDER_FLAGS,
1199 flags, /* flags */
1200 NULL,
1201 NULL, /* path */
1202 NULL, /* color */
1203 NULL, /* colorspace */
1204 NULL, /* alpha */
1205 NULL, /* ctm */
1206 NULL, /* stroke */
1207 NULL, /* private_data */
1208 0); /* private_data_len */
1209 }
1210
1211 static void
fz_list_set_default_colorspaces(fz_context * ctx,fz_device * dev,fz_default_colorspaces * default_cs)1212 fz_list_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs)
1213 {
1214 fz_default_colorspaces *default_cs2 = fz_keep_default_colorspaces(ctx, default_cs);
1215
1216 fz_try(ctx)
1217 {
1218 fz_append_display_node(
1219 ctx,
1220 dev,
1221 FZ_CMD_DEFAULT_COLORSPACES,
1222 0, /* flags */
1223 NULL,
1224 NULL, /* path */
1225 NULL, /* color */
1226 NULL, /* colorspace */
1227 NULL, /* alpha */
1228 NULL, /* ctm */
1229 NULL, /* stroke */
1230 &default_cs2, /* private_data */
1231 sizeof(default_cs2)); /* private_data_len */
1232 }
1233 fz_catch(ctx)
1234 {
1235 fz_drop_default_colorspaces(ctx, default_cs2);
1236 fz_rethrow(ctx);
1237 }
1238 }
1239
1240 static void
fz_list_begin_layer(fz_context * ctx,fz_device * dev,const char * layer_name)1241 fz_list_begin_layer(fz_context *ctx, fz_device *dev, const char *layer_name)
1242 {
1243 fz_append_display_node(
1244 ctx,
1245 dev,
1246 FZ_CMD_BEGIN_LAYER,
1247 0, /* flags */
1248 NULL,
1249 NULL, /* path */
1250 NULL, /* color */
1251 NULL, /* colorspace */
1252 NULL, /* alpha */
1253 NULL,
1254 NULL, /* stroke */
1255 layer_name, /* private_data */
1256 1+strlen(layer_name)); /* private_data_len */
1257 }
1258
1259 static void
fz_list_end_layer(fz_context * ctx,fz_device * dev)1260 fz_list_end_layer(fz_context *ctx, fz_device *dev)
1261 {
1262 fz_append_display_node(
1263 ctx,
1264 dev,
1265 FZ_CMD_END_LAYER,
1266 0, /* flags */
1267 NULL,
1268 NULL, /* path */
1269 NULL, /* color */
1270 NULL, /* colorspace */
1271 NULL, /* alpha */
1272 NULL, /* ctm */
1273 NULL, /* stroke */
1274 NULL, /* private_data */
1275 0); /* private_data_len */
1276 }
1277
1278 static void
fz_list_drop_device(fz_context * ctx,fz_device * dev)1279 fz_list_drop_device(fz_context *ctx, fz_device *dev)
1280 {
1281 fz_list_device *writer = (fz_list_device *)dev;
1282
1283 fz_drop_colorspace(ctx, writer->colorspace);
1284 fz_drop_stroke_state(ctx, writer->stroke);
1285 fz_drop_path(ctx, writer->path);
1286 fz_drop_display_list(ctx, writer->list);
1287 }
1288
1289 fz_device *
fz_new_list_device(fz_context * ctx,fz_display_list * list)1290 fz_new_list_device(fz_context *ctx, fz_display_list *list)
1291 {
1292 fz_list_device *dev;
1293
1294 dev = fz_new_derived_device(ctx, fz_list_device);
1295
1296 dev->super.fill_path = fz_list_fill_path;
1297 dev->super.stroke_path = fz_list_stroke_path;
1298 dev->super.clip_path = fz_list_clip_path;
1299 dev->super.clip_stroke_path = fz_list_clip_stroke_path;
1300
1301 dev->super.fill_text = fz_list_fill_text;
1302 dev->super.stroke_text = fz_list_stroke_text;
1303 dev->super.clip_text = fz_list_clip_text;
1304 dev->super.clip_stroke_text = fz_list_clip_stroke_text;
1305 dev->super.ignore_text = fz_list_ignore_text;
1306
1307 dev->super.fill_shade = fz_list_fill_shade;
1308 dev->super.fill_image = fz_list_fill_image;
1309 dev->super.fill_image_mask = fz_list_fill_image_mask;
1310 dev->super.clip_image_mask = fz_list_clip_image_mask;
1311
1312 dev->super.pop_clip = fz_list_pop_clip;
1313
1314 dev->super.begin_mask = fz_list_begin_mask;
1315 dev->super.end_mask = fz_list_end_mask;
1316 dev->super.begin_group = fz_list_begin_group;
1317 dev->super.end_group = fz_list_end_group;
1318
1319 dev->super.begin_tile = fz_list_begin_tile;
1320 dev->super.end_tile = fz_list_end_tile;
1321
1322 dev->super.render_flags = fz_list_render_flags;
1323 dev->super.set_default_colorspaces = fz_list_set_default_colorspaces;
1324
1325 dev->super.begin_layer = fz_list_begin_layer;
1326 dev->super.end_layer = fz_list_end_layer;
1327
1328 dev->super.drop_device = fz_list_drop_device;
1329
1330 dev->list = fz_keep_display_list(ctx, list);
1331 dev->path = NULL;
1332 dev->alpha = 1.0f;
1333 dev->ctm = fz_identity;
1334 dev->stroke = NULL;
1335 dev->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
1336 memset(dev->color, 0, sizeof(float)*FZ_MAX_COLORS);
1337 dev->top = 0;
1338 dev->tiled = 0;
1339
1340 return &dev->super;
1341 }
1342
1343 static void
fz_drop_display_list_imp(fz_context * ctx,fz_storable * list_)1344 fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_)
1345 {
1346 fz_display_list *list = (fz_display_list *)list_;
1347 fz_display_node *node = list->list;
1348 fz_display_node *node_end = list->list + list->len;
1349 int cs_n = 1;
1350 fz_colorspace *cs;
1351
1352 while (node != node_end)
1353 {
1354 fz_display_node n = *node;
1355 fz_display_node *next = node + n.size;
1356
1357 node++;
1358 if (n.rect)
1359 {
1360 node += SIZE_IN_NODES(sizeof(fz_rect));
1361 }
1362 switch (n.cs)
1363 {
1364 default:
1365 case CS_UNCHANGED:
1366 break;
1367 case CS_GRAY_0:
1368 case CS_GRAY_1:
1369 cs_n = 1;
1370 break;
1371 case CS_RGB_0:
1372 case CS_RGB_1:
1373 cs_n = 3;
1374 break;
1375 case CS_CMYK_0:
1376 case CS_CMYK_1:
1377 cs_n = 4;
1378 break;
1379 case CS_OTHER_0:
1380 cs = *(fz_colorspace **)node;
1381 cs_n = fz_colorspace_n(ctx, cs);
1382 fz_drop_colorspace(ctx, cs);
1383 node += SIZE_IN_NODES(sizeof(fz_colorspace *));
1384 break;
1385 }
1386 if (n.color)
1387 {
1388 node += SIZE_IN_NODES(cs_n * sizeof(float));
1389 }
1390 if (n.alpha == ALPHA_PRESENT)
1391 {
1392 node += SIZE_IN_NODES(sizeof(float));
1393 }
1394 if (n.ctm & CTM_CHANGE_AD)
1395 node += SIZE_IN_NODES(2*sizeof(float));
1396 if (n.ctm & CTM_CHANGE_BC)
1397 node += SIZE_IN_NODES(2*sizeof(float));
1398 if (n.ctm & CTM_CHANGE_EF)
1399 node += SIZE_IN_NODES(2*sizeof(float));
1400 if (n.stroke)
1401 {
1402 fz_drop_stroke_state(ctx, *(fz_stroke_state **)node);
1403 node += SIZE_IN_NODES(sizeof(fz_stroke_state *));
1404 }
1405 if (n.path)
1406 {
1407 int path_size = fz_packed_path_size((fz_path *)node);
1408 fz_drop_path(ctx, (fz_path *)node);
1409 node += SIZE_IN_NODES(path_size);
1410 }
1411 switch(n.cmd)
1412 {
1413 case FZ_CMD_FILL_TEXT:
1414 case FZ_CMD_STROKE_TEXT:
1415 case FZ_CMD_CLIP_TEXT:
1416 case FZ_CMD_CLIP_STROKE_TEXT:
1417 case FZ_CMD_IGNORE_TEXT:
1418 fz_drop_text(ctx, *(fz_text **)node);
1419 break;
1420 case FZ_CMD_FILL_SHADE:
1421 fz_drop_shade(ctx, *(fz_shade **)node);
1422 break;
1423 case FZ_CMD_FILL_IMAGE:
1424 case FZ_CMD_FILL_IMAGE_MASK:
1425 case FZ_CMD_CLIP_IMAGE_MASK:
1426 fz_drop_image(ctx, *(fz_image **)node);
1427 break;
1428 case FZ_CMD_BEGIN_GROUP:
1429 fz_drop_colorspace(ctx, *(fz_colorspace **)node);
1430 break;
1431 case FZ_CMD_DEFAULT_COLORSPACES:
1432 fz_drop_default_colorspaces(ctx, *(fz_default_colorspaces **)node);
1433 break;
1434 }
1435 node = next;
1436 }
1437 fz_free(ctx, list->list);
1438 fz_free(ctx, list);
1439 }
1440
1441 fz_display_list *
fz_new_display_list(fz_context * ctx,fz_rect mediabox)1442 fz_new_display_list(fz_context *ctx, fz_rect mediabox)
1443 {
1444 fz_display_list *list = fz_malloc_struct(ctx, fz_display_list);
1445 FZ_INIT_STORABLE(list, 1, fz_drop_display_list_imp);
1446 list->list = NULL;
1447 list->mediabox = mediabox;
1448 list->max = 0;
1449 list->len = 0;
1450 return list;
1451 }
1452
1453 fz_display_list *
fz_keep_display_list(fz_context * ctx,fz_display_list * list)1454 fz_keep_display_list(fz_context *ctx, fz_display_list *list)
1455 {
1456 return fz_keep_storable(ctx, &list->storable);
1457 }
1458
1459 void
fz_drop_display_list(fz_context * ctx,fz_display_list * list)1460 fz_drop_display_list(fz_context *ctx, fz_display_list *list)
1461 {
1462 fz_defer_reap_start(ctx);
1463 fz_drop_storable(ctx, &list->storable);
1464 fz_defer_reap_end(ctx);
1465 }
1466
1467 fz_rect
fz_bound_display_list(fz_context * ctx,fz_display_list * list)1468 fz_bound_display_list(fz_context *ctx, fz_display_list *list)
1469 {
1470 return list->mediabox;
1471 }
1472
fz_display_list_is_empty(fz_context * ctx,const fz_display_list * list)1473 int fz_display_list_is_empty(fz_context *ctx, const fz_display_list *list)
1474 {
1475 return !list || list->len == 0;
1476 }
1477
1478 void
fz_run_display_list(fz_context * ctx,fz_display_list * list,fz_device * dev,fz_matrix top_ctm,fz_rect scissor,fz_cookie * cookie)1479 fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_rect scissor, fz_cookie *cookie)
1480 {
1481 fz_display_node *node;
1482 fz_display_node *node_end;
1483 fz_display_node *next_node;
1484 int clipped = 0;
1485 int tiled = 0;
1486 int progress = 0;
1487
1488 /* Current graphics state as unpacked from list */
1489 fz_path *path = NULL;
1490 float alpha = 1.0f;
1491 fz_matrix ctm = fz_identity;
1492 fz_stroke_state *stroke = NULL;
1493 float color[FZ_MAX_COLORS] = { 0 };
1494 fz_colorspace *colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
1495 fz_color_params color_params;
1496 fz_rect rect = { 0 };
1497
1498 /* Transformed versions of graphic state entries */
1499 fz_rect trans_rect;
1500 fz_matrix trans_ctm;
1501 int tile_skip_depth = 0;
1502
1503 if (cookie)
1504 {
1505 cookie->progress_max = list->len;
1506 cookie->progress = 0;
1507 }
1508
1509 color_params = fz_default_color_params;
1510
1511 node = list->list;
1512 node_end = &list->list[list->len];
1513 for (; node != node_end ; node = next_node)
1514 {
1515 int empty;
1516 fz_display_node n = *node;
1517
1518 next_node = node + n.size;
1519
1520 /* Check the cookie for aborting */
1521 if (cookie)
1522 {
1523 if (cookie->abort)
1524 break;
1525 cookie->progress = progress;
1526 progress += n.size;
1527 }
1528
1529 node++;
1530 if (n.rect)
1531 {
1532 rect = *(fz_rect *)node;
1533 node += SIZE_IN_NODES(sizeof(fz_rect));
1534 }
1535 if (n.cs)
1536 {
1537 int i, en;
1538
1539 fz_drop_colorspace(ctx, colorspace);
1540 switch (n.cs)
1541 {
1542 default:
1543 case CS_GRAY_0:
1544 colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
1545 color[0] = 0.0f;
1546 break;
1547 case CS_GRAY_1:
1548 colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
1549 color[0] = 1.0f;
1550 break;
1551 case CS_RGB_0:
1552 colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
1553 color[0] = 0.0f;
1554 color[1] = 0.0f;
1555 color[2] = 0.0f;
1556 break;
1557 case CS_RGB_1:
1558 colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
1559 color[0] = 1.0f;
1560 color[1] = 1.0f;
1561 color[2] = 1.0f;
1562 break;
1563 case CS_CMYK_0:
1564 colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
1565 color[0] = 0.0f;
1566 color[1] = 0.0f;
1567 color[2] = 0.0f;
1568 color[3] = 0.0f;
1569 break;
1570 case CS_CMYK_1:
1571 colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
1572 color[0] = 0.0f;
1573 color[1] = 0.0f;
1574 color[2] = 0.0f;
1575 color[3] = 1.0f;
1576 break;
1577 case CS_OTHER_0:
1578 colorspace = fz_keep_colorspace(ctx, *(fz_colorspace **)(node));
1579 node += SIZE_IN_NODES(sizeof(fz_colorspace *));
1580 en = fz_colorspace_n(ctx, colorspace);
1581 for (i = 0; i < en; i++)
1582 color[i] = 0.0f;
1583 break;
1584 }
1585 }
1586 if (n.color)
1587 {
1588 int nc = fz_colorspace_n(ctx, colorspace);
1589 memcpy(color, (float *)node, nc * sizeof(float));
1590 node += SIZE_IN_NODES(nc * sizeof(float));
1591 }
1592 if (n.alpha)
1593 {
1594 switch(n.alpha)
1595 {
1596 default:
1597 case ALPHA_0:
1598 alpha = 0.0f;
1599 break;
1600 case ALPHA_1:
1601 alpha = 1.0f;
1602 break;
1603 case ALPHA_PRESENT:
1604 alpha = *(float *)node;
1605 node += SIZE_IN_NODES(sizeof(float));
1606 break;
1607 }
1608 }
1609 if (n.ctm != 0)
1610 {
1611 float *packed_ctm = (float *)node;
1612 if (n.ctm & CTM_CHANGE_AD)
1613 {
1614 ctm.a = *packed_ctm++;
1615 ctm.d = *packed_ctm++;
1616 node += SIZE_IN_NODES(2*sizeof(float));
1617 }
1618 if (n.ctm & CTM_CHANGE_BC)
1619 {
1620 ctm.b = *packed_ctm++;
1621 ctm.c = *packed_ctm++;
1622 node += SIZE_IN_NODES(2*sizeof(float));
1623 }
1624 if (n.ctm & CTM_CHANGE_EF)
1625 {
1626 ctm.e = *packed_ctm++;
1627 ctm.f = *packed_ctm;
1628 node += SIZE_IN_NODES(2*sizeof(float));
1629 }
1630 }
1631 if (n.stroke)
1632 {
1633 fz_drop_stroke_state(ctx, stroke);
1634 stroke = fz_keep_stroke_state(ctx, *(fz_stroke_state **)node);
1635 node += SIZE_IN_NODES(sizeof(fz_stroke_state *));
1636 }
1637 if (n.path)
1638 {
1639 fz_drop_path(ctx, path);
1640 path = fz_keep_path(ctx, (fz_path *)node);
1641 node += SIZE_IN_NODES(fz_packed_path_size(path));
1642 }
1643
1644 if (tile_skip_depth > 0)
1645 {
1646 if (n.cmd == FZ_CMD_BEGIN_TILE)
1647 tile_skip_depth++;
1648 else if (n.cmd == FZ_CMD_END_TILE)
1649 tile_skip_depth--;
1650 if (tile_skip_depth > 0)
1651 continue;
1652 }
1653
1654 trans_rect = fz_transform_rect(rect, top_ctm);
1655
1656 /* cull objects to draw using a quick visibility test */
1657
1658 if (tiled ||
1659 n.cmd == FZ_CMD_BEGIN_TILE || n.cmd == FZ_CMD_END_TILE ||
1660 n.cmd == FZ_CMD_RENDER_FLAGS || n.cmd == FZ_CMD_DEFAULT_COLORSPACES ||
1661 n.cmd == FZ_CMD_BEGIN_LAYER || n.cmd == FZ_CMD_END_LAYER)
1662 {
1663 empty = 0;
1664 }
1665 else
1666 {
1667 empty = fz_is_empty_rect(fz_intersect_rect(trans_rect, scissor));
1668 }
1669
1670 if (clipped || empty)
1671 {
1672 switch (n.cmd)
1673 {
1674 case FZ_CMD_CLIP_PATH:
1675 case FZ_CMD_CLIP_STROKE_PATH:
1676 case FZ_CMD_CLIP_TEXT:
1677 case FZ_CMD_CLIP_STROKE_TEXT:
1678 case FZ_CMD_CLIP_IMAGE_MASK:
1679 case FZ_CMD_BEGIN_MASK:
1680 case FZ_CMD_BEGIN_GROUP:
1681 clipped++;
1682 continue;
1683 case FZ_CMD_POP_CLIP:
1684 case FZ_CMD_END_GROUP:
1685 if (!clipped)
1686 goto visible;
1687 clipped--;
1688 continue;
1689 case FZ_CMD_END_MASK:
1690 if (!clipped)
1691 goto visible;
1692 continue;
1693 default:
1694 continue;
1695 }
1696 }
1697
1698 visible:
1699 trans_ctm = fz_concat(ctm, top_ctm);
1700
1701 fz_try(ctx)
1702 {
1703 switch (n.cmd)
1704 {
1705 case FZ_CMD_FILL_PATH:
1706 fz_unpack_color_params(&color_params, n.flags);
1707 fz_fill_path(ctx, dev, path, n.flags & 1, trans_ctm, colorspace, color, alpha, color_params);
1708 break;
1709 case FZ_CMD_STROKE_PATH:
1710 fz_unpack_color_params(&color_params, n.flags);
1711 fz_stroke_path(ctx, dev, path, stroke, trans_ctm, colorspace, color, alpha, color_params);
1712 break;
1713 case FZ_CMD_CLIP_PATH:
1714 fz_clip_path(ctx, dev, path, n.flags, trans_ctm, trans_rect);
1715 break;
1716 case FZ_CMD_CLIP_STROKE_PATH:
1717 fz_clip_stroke_path(ctx, dev, path, stroke, trans_ctm, trans_rect);
1718 break;
1719 case FZ_CMD_FILL_TEXT:
1720 fz_unpack_color_params(&color_params, n.flags);
1721 fz_fill_text(ctx, dev, *(fz_text **)node, trans_ctm, colorspace, color, alpha, color_params);
1722 break;
1723 case FZ_CMD_STROKE_TEXT:
1724 fz_unpack_color_params(&color_params, n.flags);
1725 fz_stroke_text(ctx, dev, *(fz_text **)node, stroke, trans_ctm, colorspace, color, alpha, color_params);
1726 break;
1727 case FZ_CMD_CLIP_TEXT:
1728 fz_clip_text(ctx, dev, *(fz_text **)node, trans_ctm, trans_rect);
1729 break;
1730 case FZ_CMD_CLIP_STROKE_TEXT:
1731 fz_clip_stroke_text(ctx, dev, *(fz_text **)node, stroke, trans_ctm, trans_rect);
1732 break;
1733 case FZ_CMD_IGNORE_TEXT:
1734 fz_ignore_text(ctx, dev, *(fz_text **)node, trans_ctm);
1735 break;
1736 case FZ_CMD_FILL_SHADE:
1737 fz_unpack_color_params(&color_params, n.flags);
1738 fz_fill_shade(ctx, dev, *(fz_shade **)node, trans_ctm, alpha, color_params);
1739 break;
1740 case FZ_CMD_FILL_IMAGE:
1741 fz_unpack_color_params(&color_params, n.flags);
1742 fz_fill_image(ctx, dev, *(fz_image **)node, trans_ctm, alpha, color_params);
1743 break;
1744 case FZ_CMD_FILL_IMAGE_MASK:
1745 fz_unpack_color_params(&color_params, n.flags);
1746 fz_fill_image_mask(ctx, dev, *(fz_image **)node, trans_ctm, colorspace, color, alpha, color_params);
1747 break;
1748 case FZ_CMD_CLIP_IMAGE_MASK:
1749 fz_clip_image_mask(ctx, dev, *(fz_image **)node, trans_ctm, trans_rect);
1750 break;
1751 case FZ_CMD_POP_CLIP:
1752 fz_pop_clip(ctx, dev);
1753 break;
1754 case FZ_CMD_BEGIN_MASK:
1755 fz_unpack_color_params(&color_params, n.flags);
1756 fz_begin_mask(ctx, dev, trans_rect, n.flags & 1, colorspace, color, color_params);
1757 break;
1758 case FZ_CMD_END_MASK:
1759 fz_end_mask(ctx, dev);
1760 break;
1761 case FZ_CMD_BEGIN_GROUP:
1762 fz_begin_group(ctx, dev, trans_rect, *(fz_colorspace **)node, (n.flags & ISOLATED) != 0, (n.flags & KNOCKOUT) != 0, (n.flags>>2), alpha);
1763 break;
1764 case FZ_CMD_END_GROUP:
1765 fz_end_group(ctx, dev);
1766 break;
1767 case FZ_CMD_BEGIN_TILE:
1768 {
1769 int cached;
1770 fz_list_tile_data *data = (fz_list_tile_data *)node;
1771 fz_rect tile_rect;
1772 tiled++;
1773 tile_rect = data->view;
1774 cached = fz_begin_tile_id(ctx, dev, rect, tile_rect, data->xstep, data->ystep, trans_ctm, data->id);
1775 if (cached)
1776 tile_skip_depth = 1;
1777 break;
1778 }
1779 case FZ_CMD_END_TILE:
1780 tiled--;
1781 fz_end_tile(ctx, dev);
1782 break;
1783 case FZ_CMD_RENDER_FLAGS:
1784 if (n.flags == 0)
1785 fz_render_flags(ctx, dev, 0, FZ_DEVFLAG_GRIDFIT_AS_TILED);
1786 else if (n.flags == 1)
1787 fz_render_flags(ctx, dev, FZ_DEVFLAG_GRIDFIT_AS_TILED, 0);
1788 break;
1789 case FZ_CMD_DEFAULT_COLORSPACES:
1790 fz_set_default_colorspaces(ctx, dev, *(fz_default_colorspaces **)node);
1791 break;
1792 case FZ_CMD_BEGIN_LAYER:
1793 fz_begin_layer(ctx, dev, (const char *)node);
1794 break;
1795 case FZ_CMD_END_LAYER:
1796 fz_end_layer(ctx, dev);
1797 break;
1798 }
1799 }
1800 fz_catch(ctx)
1801 {
1802 /* Swallow the error */
1803 if (cookie)
1804 cookie->errors++;
1805 if (fz_caught(ctx) == FZ_ERROR_ABORT)
1806 break;
1807 fz_warn(ctx, "Ignoring error during interpretation");
1808 }
1809 }
1810 fz_drop_colorspace(ctx, colorspace);
1811 fz_drop_stroke_state(ctx, stroke);
1812 fz_drop_path(ctx, path);
1813 if (cookie)
1814 cookie->progress = progress;
1815 }
1816