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