Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
 
3
typedef struct fz_display_node_s fz_display_node;
4
 
5
#define STACK_SIZE 96
6
 
7
typedef enum fz_display_command_e
8
{
9
	FZ_CMD_FILL_PATH,
10
	FZ_CMD_STROKE_PATH,
11
	FZ_CMD_CLIP_PATH,
12
	FZ_CMD_CLIP_STROKE_PATH,
13
	FZ_CMD_FILL_TEXT,
14
	FZ_CMD_STROKE_TEXT,
15
	FZ_CMD_CLIP_TEXT,
16
	FZ_CMD_CLIP_STROKE_TEXT,
17
	FZ_CMD_IGNORE_TEXT,
18
	FZ_CMD_FILL_SHADE,
19
	FZ_CMD_FILL_IMAGE,
20
	FZ_CMD_FILL_IMAGE_MASK,
21
	FZ_CMD_CLIP_IMAGE_MASK,
22
	FZ_CMD_POP_CLIP,
23
	FZ_CMD_BEGIN_MASK,
24
	FZ_CMD_END_MASK,
25
	FZ_CMD_BEGIN_GROUP,
26
	FZ_CMD_END_GROUP,
27
	FZ_CMD_BEGIN_TILE,
28
	FZ_CMD_END_TILE
29
} fz_display_command;
30
 
31
struct fz_display_node_s
32
{
33
	fz_display_command cmd;
34
	fz_display_node *next;
35
	fz_rect rect;
36
	union {
37
		fz_path *path;
38
		fz_text *text;
39
		fz_shade *shade;
40
		fz_pixmap *image;
41
		int blendmode;
42
	} item;
43
	fz_stroke_state *stroke;
44
	int flag; /* even_odd, accumulate, isolated/knockout... */
45
	fz_matrix ctm;
46
	fz_colorspace *colorspace;
47
	float alpha;
48
	float color[FZ_MAX_COLORS];
49
};
50
 
51
struct fz_display_list_s
52
{
53
	fz_display_node *first;
54
	fz_display_node *last;
55
 
56
	int top;
57
	struct {
58
		fz_rect *update;
59
		fz_rect rect;
60
	} stack[STACK_SIZE];
61
	int tiled;
62
};
63
 
64
enum { ISOLATED = 1, KNOCKOUT = 2 };
65
 
66
static fz_display_node *
67
fz_new_display_node(fz_display_command cmd, fz_matrix ctm,
68
	fz_colorspace *colorspace, float *color, float alpha)
69
{
70
	fz_display_node *node;
71
	int i;
72
 
73
	node = fz_malloc(sizeof(fz_display_node));
74
	node->cmd = cmd;
75
	node->next = NULL;
76
	node->rect = fz_empty_rect;
77
	node->item.path = NULL;
78
	node->stroke = NULL;
79
	node->flag = 0;
80
	node->ctm = ctm;
81
	if (colorspace)
82
	{
83
		node->colorspace = fz_keep_colorspace(colorspace);
84
		if (color)
85
		{
86
			for (i = 0; i < node->colorspace->n; i++)
87
				node->color[i] = color[i];
88
		}
89
	}
90
	else
91
	{
92
		node->colorspace = NULL;
93
	}
94
	node->alpha = alpha;
95
 
96
	return node;
97
}
98
 
99
static fz_stroke_state *
100
fz_clone_stroke_state(fz_stroke_state *stroke)
101
{
102
	fz_stroke_state *newstroke = fz_malloc(sizeof(fz_stroke_state));
103
	*newstroke = *stroke;
104
	return newstroke;
105
}
106
 
107
static void
108
fz_append_display_node(fz_display_list *list, fz_display_node *node)
109
{
110
	switch (node->cmd)
111
	{
112
	case FZ_CMD_CLIP_PATH:
113
	case FZ_CMD_CLIP_STROKE_PATH:
114
	case FZ_CMD_CLIP_IMAGE_MASK:
115
		if (list->top < STACK_SIZE)
116
		{
117
			list->stack[list->top].update = &node->rect;
118
			list->stack[list->top].rect = fz_empty_rect;
119
		}
120
		list->top++;
121
		break;
122
	case FZ_CMD_END_MASK:
123
	case FZ_CMD_CLIP_TEXT:
124
	case FZ_CMD_CLIP_STROKE_TEXT:
125
		if (list->top < STACK_SIZE)
126
		{
127
			list->stack[list->top].update = NULL;
128
			list->stack[list->top].rect = fz_empty_rect;
129
		}
130
		list->top++;
131
		break;
132
	case FZ_CMD_BEGIN_TILE:
133
		list->tiled++;
134
		if (list->top > 0 && list->top < STACK_SIZE)
135
		{
136
			list->stack[list->top-1].rect = fz_infinite_rect;
137
		}
138
		break;
139
	case FZ_CMD_END_TILE:
140
		list->tiled--;
141
		break;
142
	case FZ_CMD_END_GROUP:
143
		break;
144
	case FZ_CMD_POP_CLIP:
145
		if (list->top > STACK_SIZE)
146
		{
147
			list->top--;
148
			node->rect = fz_infinite_rect;
149
		}
150
		else if (list->top > 0)
151
		{
152
			fz_rect *update;
153
			list->top--;
154
			update = list->stack[list->top].update;
155
			if (list->tiled == 0)
156
			{
157
				if (update != NULL)
158
				{
159
					*update = fz_intersect_rect(*update, list->stack[list->top].rect);
160
					node->rect = *update;
161
				}
162
				else
163
					node->rect = list->stack[list->top].rect;
164
			}
165
			else
166
				node->rect = fz_infinite_rect;
167
		}
168
		/* fallthrough */
169
	default:
170
		if (list->top > 0 && list->tiled == 0 && list->top <= STACK_SIZE)
171
			list->stack[list->top-1].rect = fz_union_rect(list->stack[list->top-1].rect, node->rect);
172
		break;
173
	}
174
	if (!list->first)
175
	{
176
		list->first = node;
177
		list->last = node;
178
	}
179
	else
180
	{
181
		list->last->next = node;
182
		list->last = node;
183
	}
184
}
185
 
186
static void
187
fz_free_display_node(fz_display_node *node)
188
{
189
	switch (node->cmd)
190
	{
191
	case FZ_CMD_FILL_PATH:
192
	case FZ_CMD_STROKE_PATH:
193
	case FZ_CMD_CLIP_PATH:
194
	case FZ_CMD_CLIP_STROKE_PATH:
195
		fz_free_path(node->item.path);
196
		break;
197
	case FZ_CMD_FILL_TEXT:
198
	case FZ_CMD_STROKE_TEXT:
199
	case FZ_CMD_CLIP_TEXT:
200
	case FZ_CMD_CLIP_STROKE_TEXT:
201
	case FZ_CMD_IGNORE_TEXT:
202
		fz_free_text(node->item.text);
203
		break;
204
	case FZ_CMD_FILL_SHADE:
205
		fz_drop_shade(node->item.shade);
206
		break;
207
	case FZ_CMD_FILL_IMAGE:
208
	case FZ_CMD_FILL_IMAGE_MASK:
209
	case FZ_CMD_CLIP_IMAGE_MASK:
210
		fz_drop_pixmap(node->item.image);
211
		break;
212
	case FZ_CMD_POP_CLIP:
213
	case FZ_CMD_BEGIN_MASK:
214
	case FZ_CMD_END_MASK:
215
	case FZ_CMD_BEGIN_GROUP:
216
	case FZ_CMD_END_GROUP:
217
	case FZ_CMD_BEGIN_TILE:
218
	case FZ_CMD_END_TILE:
219
		break;
220
	}
221
	if (node->stroke)
222
		fz_free(node->stroke);
223
	if (node->colorspace)
224
		fz_drop_colorspace(node->colorspace);
225
	fz_free(node);
226
}
227
 
228
static void
229
fz_list_fill_path(void *user, fz_path *path, int even_odd, fz_matrix ctm,
230
	fz_colorspace *colorspace, float *color, float alpha)
231
{
232
	fz_display_node *node;
233
	node = fz_new_display_node(FZ_CMD_FILL_PATH, ctm, colorspace, color, alpha);
234
	node->rect = fz_bound_path(path, NULL, ctm);
235
	node->item.path = fz_clone_path(path);
236
	node->flag = even_odd;
237
	fz_append_display_node(user, node);
238
}
239
 
240
static void
241
fz_list_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm,
242
	fz_colorspace *colorspace, float *color, float alpha)
243
{
244
	fz_display_node *node;
245
	node = fz_new_display_node(FZ_CMD_STROKE_PATH, ctm, colorspace, color, alpha);
246
	node->rect = fz_bound_path(path, stroke, ctm);
247
	node->item.path = fz_clone_path(path);
248
	node->stroke = fz_clone_stroke_state(stroke);
249
	fz_append_display_node(user, node);
250
}
251
 
252
static void
253
fz_list_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
254
{
255
	fz_display_node *node;
256
	node = fz_new_display_node(FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0);
257
	node->rect = fz_bound_path(path, NULL, ctm);
258
	if (rect != NULL)
259
		node->rect = fz_intersect_rect(node->rect, *rect);
260
	node->item.path = fz_clone_path(path);
261
	node->flag = even_odd;
262
	fz_append_display_node(user, node);
263
}
264
 
265
static void
266
fz_list_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
267
{
268
	fz_display_node *node;
269
	node = fz_new_display_node(FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0);
270
	node->rect = fz_bound_path(path, stroke, ctm);
271
	if (rect != NULL)
272
		node->rect = fz_intersect_rect(node->rect, *rect);
273
	node->item.path = fz_clone_path(path);
274
	node->stroke = fz_clone_stroke_state(stroke);
275
	fz_append_display_node(user, node);
276
}
277
 
278
static void
279
fz_list_fill_text(void *user, fz_text *text, fz_matrix ctm,
280
	fz_colorspace *colorspace, float *color, float alpha)
281
{
282
	fz_display_node *node;
283
	node = fz_new_display_node(FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha);
284
	node->rect = fz_bound_text(text, ctm);
285
	node->item.text = fz_clone_text(text);
286
	fz_append_display_node(user, node);
287
}
288
 
289
static void
290
fz_list_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm,
291
	fz_colorspace *colorspace, float *color, float alpha)
292
{
293
	fz_display_node *node;
294
	node = fz_new_display_node(FZ_CMD_STROKE_TEXT, ctm, colorspace, color, alpha);
295
	node->rect = fz_bound_text(text, ctm);
296
	node->item.text = fz_clone_text(text);
297
	node->stroke = fz_clone_stroke_state(stroke);
298
	fz_append_display_node(user, node);
299
}
300
 
301
static void
302
fz_list_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate)
303
{
304
	fz_display_node *node;
305
	node = fz_new_display_node(FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0);
306
	node->rect = fz_bound_text(text, ctm);
307
	node->item.text = fz_clone_text(text);
308
	node->flag = accumulate;
309
	/* when accumulating, be conservative about culling */
310
	if (accumulate)
311
		node->rect = fz_infinite_rect;
312
	fz_append_display_node(user, node);
313
}
314
 
315
static void
316
fz_list_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm)
317
{
318
	fz_display_node *node;
319
	node = fz_new_display_node(FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0);
320
	node->rect = fz_bound_text(text, ctm);
321
	node->item.text = fz_clone_text(text);
322
	node->stroke = fz_clone_stroke_state(stroke);
323
	fz_append_display_node(user, node);
324
}
325
 
326
static void
327
fz_list_ignore_text(void *user, fz_text *text, fz_matrix ctm)
328
{
329
	fz_display_node *node;
330
	node = fz_new_display_node(FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0);
331
	node->rect = fz_bound_text(text, ctm);
332
	node->item.text = fz_clone_text(text);
333
	fz_append_display_node(user, node);
334
}
335
 
336
static void
337
fz_list_pop_clip(void *user)
338
{
339
	fz_display_node *node;
340
	node = fz_new_display_node(FZ_CMD_POP_CLIP, fz_identity, NULL, NULL, 0);
341
	fz_append_display_node(user, node);
342
}
343
 
344
static void
345
fz_list_fill_shade(void *user, fz_shade *shade, fz_matrix ctm, float alpha)
346
{
347
	fz_display_node *node;
348
	node = fz_new_display_node(FZ_CMD_FILL_SHADE, ctm, NULL, NULL, alpha);
349
	node->rect = fz_bound_shade(shade, ctm);
350
	node->item.shade = fz_keep_shade(shade);
351
	fz_append_display_node(user, node);
352
}
353
 
354
static void
355
fz_list_fill_image(void *user, fz_pixmap *image, fz_matrix ctm, float alpha)
356
{
357
	fz_display_node *node;
358
	node = fz_new_display_node(FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha);
359
	node->rect = fz_transform_rect(ctm, fz_unit_rect);
360
	node->item.image = fz_keep_pixmap(image);
361
	fz_append_display_node(user, node);
362
}
363
 
364
static void
365
fz_list_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm,
366
	fz_colorspace *colorspace, float *color, float alpha)
367
{
368
	fz_display_node *node;
369
	node = fz_new_display_node(FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha);
370
	node->rect = fz_transform_rect(ctm, fz_unit_rect);
371
	node->item.image = fz_keep_pixmap(image);
372
	fz_append_display_node(user, node);
373
}
374
 
375
static void
376
fz_list_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
377
{
378
	fz_display_node *node;
379
	node = fz_new_display_node(FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
380
	node->rect = fz_transform_rect(ctm, fz_unit_rect);
381
	if (rect != NULL)
382
		node->rect = fz_intersect_rect(node->rect, *rect);
383
	node->item.image = fz_keep_pixmap(image);
384
	fz_append_display_node(user, node);
385
}
386
 
387
static void
388
fz_list_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *color)
389
{
390
	fz_display_node *node;
391
	node = fz_new_display_node(FZ_CMD_BEGIN_MASK, fz_identity, colorspace, color, 0);
392
	node->rect = rect;
393
	node->flag = luminosity;
394
	fz_append_display_node(user, node);
395
}
396
 
397
static void
398
fz_list_end_mask(void *user)
399
{
400
	fz_display_node *node;
401
	node = fz_new_display_node(FZ_CMD_END_MASK, fz_identity, NULL, NULL, 0);
402
	fz_append_display_node(user, node);
403
}
404
 
405
static void
406
fz_list_begin_group(void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha)
407
{
408
	fz_display_node *node;
409
	node = fz_new_display_node(FZ_CMD_BEGIN_GROUP, fz_identity, NULL, NULL, alpha);
410
	node->rect = rect;
411
	node->item.blendmode = blendmode;
412
	node->flag |= isolated ? ISOLATED : 0;
413
	node->flag |= knockout ? KNOCKOUT : 0;
414
	fz_append_display_node(user, node);
415
}
416
 
417
static void
418
fz_list_end_group(void *user)
419
{
420
	fz_display_node *node;
421
	node = fz_new_display_node(FZ_CMD_END_GROUP, fz_identity, NULL, NULL, 0);
422
	fz_append_display_node(user, node);
423
}
424
 
425
static void
426
fz_list_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
427
{
428
	fz_display_node *node;
429
	node = fz_new_display_node(FZ_CMD_BEGIN_TILE, ctm, NULL, NULL, 0);
430
	node->rect = area;
431
	node->color[0] = xstep;
432
	node->color[1] = ystep;
433
	node->color[2] = view.x0;
434
	node->color[3] = view.y0;
435
	node->color[4] = view.x1;
436
	node->color[5] = view.y1;
437
	fz_append_display_node(user, node);
438
}
439
 
440
static void
441
fz_list_end_tile(void *user)
442
{
443
	fz_display_node *node;
444
	node = fz_new_display_node(FZ_CMD_END_TILE, fz_identity, NULL, NULL, 0);
445
	fz_append_display_node(user, node);
446
}
447
 
448
fz_device *
449
fz_new_list_device(fz_display_list *list)
450
{
451
	fz_device *dev = fz_new_device(list);
452
 
453
	dev->fill_path = fz_list_fill_path;
454
	dev->stroke_path = fz_list_stroke_path;
455
	dev->clip_path = fz_list_clip_path;
456
	dev->clip_stroke_path = fz_list_clip_stroke_path;
457
 
458
	dev->fill_text = fz_list_fill_text;
459
	dev->stroke_text = fz_list_stroke_text;
460
	dev->clip_text = fz_list_clip_text;
461
	dev->clip_stroke_text = fz_list_clip_stroke_text;
462
	dev->ignore_text = fz_list_ignore_text;
463
 
464
	dev->fill_shade = fz_list_fill_shade;
465
	dev->fill_image = fz_list_fill_image;
466
	dev->fill_image_mask = fz_list_fill_image_mask;
467
	dev->clip_image_mask = fz_list_clip_image_mask;
468
 
469
	dev->pop_clip = fz_list_pop_clip;
470
 
471
	dev->begin_mask = fz_list_begin_mask;
472
	dev->end_mask = fz_list_end_mask;
473
	dev->begin_group = fz_list_begin_group;
474
	dev->end_group = fz_list_end_group;
475
 
476
	dev->begin_tile = fz_list_begin_tile;
477
	dev->end_tile = fz_list_end_tile;
478
 
479
	return dev;
480
}
481
 
482
fz_display_list *
483
fz_new_display_list(void)
484
{
485
	fz_display_list *list = fz_malloc(sizeof(fz_display_list));
486
	list->first = NULL;
487
	list->last = NULL;
488
	list->top = 0;
489
	list->tiled = 0;
490
	return list;
491
}
492
 
493
void
494
fz_free_display_list(fz_display_list *list)
495
{
496
	fz_display_node *node = list->first;
497
	while (node)
498
	{
499
		fz_display_node *next = node->next;
500
		fz_free_display_node(node);
501
		node = next;
502
	}
503
	fz_free(list);
504
}
505
 
506
void
507
fz_execute_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_bbox scissor)
508
{
509
	fz_display_node *node;
510
	fz_matrix ctm;
511
	fz_rect rect;
512
	fz_bbox bbox;
513
	int clipped = 0;
514
	int tiled = 0;
515
	int empty;
516
 
517
	if (!fz_is_infinite_bbox(scissor))
518
	{
519
		/* add some fuzz at the edges, as especially glyph rects
520
		 * are sometimes not actually completely bounding the glyph */
521
		scissor.x0 -= 20; scissor.y0 -= 20;
522
		scissor.x1 += 20; scissor.y1 += 20;
523
	}
524
 
525
	for (node = list->first; node; node = node->next)
526
	{
527
		/* cull objects to draw using a quick visibility test */
528
 
529
		if (tiled || node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE)
530
		{
531
			empty = 0;
532
		}
533
		else
534
		{
535
			bbox = fz_round_rect(fz_transform_rect(top_ctm, node->rect));
536
			bbox = fz_intersect_bbox(bbox, scissor);
537
			empty = fz_is_empty_bbox(bbox);
538
		}
539
 
540
		if (clipped || empty)
541
		{
542
			switch (node->cmd)
543
			{
544
			case FZ_CMD_CLIP_PATH:
545
			case FZ_CMD_CLIP_STROKE_PATH:
546
			case FZ_CMD_CLIP_TEXT:
547
			case FZ_CMD_CLIP_STROKE_TEXT:
548
			case FZ_CMD_CLIP_IMAGE_MASK:
549
			case FZ_CMD_BEGIN_MASK:
550
			case FZ_CMD_BEGIN_GROUP:
551
				clipped++;
552
				continue;
553
			case FZ_CMD_POP_CLIP:
554
			case FZ_CMD_END_GROUP:
555
				if (!clipped)
556
					goto visible;
557
				clipped--;
558
				continue;
559
			case FZ_CMD_END_MASK:
560
				if (!clipped)
561
					goto visible;
562
				continue;
563
			default:
564
				continue;
565
			}
566
		}
567
 
568
visible:
569
		ctm = fz_concat(node->ctm, top_ctm);
570
 
571
		switch (node->cmd)
572
		{
573
		case FZ_CMD_FILL_PATH:
574
			fz_fill_path(dev, node->item.path, node->flag, ctm,
575
				node->colorspace, node->color, node->alpha);
576
			break;
577
		case FZ_CMD_STROKE_PATH:
578
			fz_stroke_path(dev, node->item.path, node->stroke, ctm,
579
				node->colorspace, node->color, node->alpha);
580
			break;
581
		case FZ_CMD_CLIP_PATH:
582
		{
583
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
584
			fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
585
			break;
586
		}
587
		case FZ_CMD_CLIP_STROKE_PATH:
588
		{
589
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
590
			fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
591
			break;
592
		}
593
		case FZ_CMD_FILL_TEXT:
594
			fz_fill_text(dev, node->item.text, ctm,
595
				node->colorspace, node->color, node->alpha);
596
			break;
597
		case FZ_CMD_STROKE_TEXT:
598
			fz_stroke_text(dev, node->item.text, node->stroke, ctm,
599
				node->colorspace, node->color, node->alpha);
600
			break;
601
		case FZ_CMD_CLIP_TEXT:
602
			fz_clip_text(dev, node->item.text, ctm, node->flag);
603
			break;
604
		case FZ_CMD_CLIP_STROKE_TEXT:
605
			fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
606
			break;
607
		case FZ_CMD_IGNORE_TEXT:
608
			fz_ignore_text(dev, node->item.text, ctm);
609
			break;
610
		case FZ_CMD_FILL_SHADE:
611
			fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
612
			break;
613
		case FZ_CMD_FILL_IMAGE:
614
			fz_fill_image(dev, node->item.image, ctm, node->alpha);
615
			break;
616
		case FZ_CMD_FILL_IMAGE_MASK:
617
			fz_fill_image_mask(dev, node->item.image, ctm,
618
				node->colorspace, node->color, node->alpha);
619
			break;
620
		case FZ_CMD_CLIP_IMAGE_MASK:
621
		{
622
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
623
			fz_clip_image_mask(dev, node->item.image, &trect, ctm);
624
			break;
625
		}
626
		case FZ_CMD_POP_CLIP:
627
			fz_pop_clip(dev);
628
			break;
629
		case FZ_CMD_BEGIN_MASK:
630
			rect = fz_transform_rect(top_ctm, node->rect);
631
			fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
632
			break;
633
		case FZ_CMD_END_MASK:
634
			fz_end_mask(dev);
635
			break;
636
		case FZ_CMD_BEGIN_GROUP:
637
			rect = fz_transform_rect(top_ctm, node->rect);
638
			fz_begin_group(dev, rect,
639
				(node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
640
				node->item.blendmode, node->alpha);
641
			break;
642
		case FZ_CMD_END_GROUP:
643
			fz_end_group(dev);
644
			break;
645
		case FZ_CMD_BEGIN_TILE:
646
			tiled++;
647
			rect.x0 = node->color[2];
648
			rect.y0 = node->color[3];
649
			rect.x1 = node->color[4];
650
			rect.y1 = node->color[5];
651
			fz_begin_tile(dev, node->rect, rect,
652
				node->color[0], node->color[1], ctm);
653
			break;
654
		case FZ_CMD_END_TILE:
655
			tiled--;
656
			fz_end_tile(dev);
657
			break;
658
		}
659
	}
660
}