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
#include "mupdf.h"
3
 
4
#define TILE
5
 
6
typedef struct pdf_material_s pdf_material;
7
typedef struct pdf_gstate_s pdf_gstate;
8
typedef struct pdf_csi_s pdf_csi;
9
 
10
enum
11
{
12
	PDF_FILL,
13
	PDF_STROKE,
14
};
15
 
16
enum
17
{
18
	PDF_MAT_NONE,
19
	PDF_MAT_COLOR,
20
	PDF_MAT_PATTERN,
21
	PDF_MAT_SHADE,
22
};
23
 
24
struct pdf_material_s
25
{
26
	int kind;
27
	fz_colorspace *colorspace;
28
	pdf_pattern *pattern;
29
	fz_shade *shade;
30
	float alpha;
31
	float v[32];
32
};
33
 
34
struct pdf_gstate_s
35
{
36
	fz_matrix ctm;
37
	int clip_depth;
38
 
39
	/* path stroking */
40
	fz_stroke_state stroke_state;
41
 
42
	/* materials */
43
	pdf_material stroke;
44
	pdf_material fill;
45
 
46
	/* text state */
47
	float char_space;
48
	float word_space;
49
	float scale;
50
	float leading;
51
	pdf_font_desc *font;
52
	float size;
53
	int render;
54
	float rise;
55
 
56
	/* transparency */
57
	int blendmode;
58
	pdf_xobject *softmask;
59
	fz_matrix softmask_ctm;
60
	float softmask_bc[FZ_MAX_COLORS];
61
	int luminosity;
62
};
63
 
64
struct pdf_csi_s
65
{
66
	fz_device *dev;
67
	pdf_xref *xref;
68
 
69
	/* usage mode for optional content groups */
70
	char *target; /* "View", "Print", "Export" */
71
 
72
	/* interpreter stack */
73
	fz_obj *obj;
74
	char name[256];
75
	unsigned char string[256];
76
	int string_len;
77
	float stack[32];
78
	int top;
79
 
80
	int xbalance;
81
	int in_text;
82
 
83
	/* path object state */
84
	fz_path *path;
85
 
86
	/* text object state */
87
	fz_text *text;
88
	fz_matrix tlm;
89
	fz_matrix tm;
90
	int text_mode;
91
	int accumulate;
92
 
93
	/* graphics state */
94
	fz_matrix top_ctm;
95
	pdf_gstate gstate[64];
96
	int gtop;
97
};
98
 
99
static fz_error pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents);
100
static fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform);
101
static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what);
102
 
103
 
104
static int
105
pdf_is_hidden_ocg(fz_obj *xobj, char *target)
106
{
107
	char target_state[16];
108
	fz_obj *obj;
109
 
110
	fz_strlcpy(target_state, target, sizeof target_state);
111
	fz_strlcat(target_state, "State", sizeof target_state);
112
 
113
	obj = fz_dict_gets(xobj, "OC");
114
	obj = fz_dict_gets(obj, "OCGs");
115
	if (fz_is_array(obj))
116
		obj = fz_array_get(obj, 0);
117
	obj = fz_dict_gets(obj, "Usage");
118
	obj = fz_dict_gets(obj, target);
119
	obj = fz_dict_gets(obj, target_state);
120
	return !strcmp(fz_to_name(obj), "OFF");
121
}
122
 
123
/*
124
 * Emit graphics calls to device.
125
 */
126
 
127
static void
128
pdf_begin_group(pdf_csi *csi, fz_rect bbox)
129
{
130
	pdf_gstate *gstate = csi->gstate + csi->gtop;
131
	fz_error error;
132
 
133
	if (gstate->softmask)
134
	{
135
		pdf_xobject *softmask = gstate->softmask;
136
		fz_rect bbox = fz_transform_rect(gstate->softmask_ctm, softmask->bbox);
137
		fz_matrix save_ctm = gstate->ctm;
138
 
139
		gstate->softmask = NULL;
140
		gstate->ctm = gstate->softmask_ctm;
141
 
142
		fz_begin_mask(csi->dev, bbox, gstate->luminosity,
143
			softmask->colorspace, gstate->softmask_bc);
144
		error = pdf_run_xobject(csi, NULL, softmask, fz_identity);
145
		if (error)
146
			fz_catch(error, "cannot run softmask");
147
		fz_end_mask(csi->dev);
148
 
149
		gstate->softmask = softmask;
150
		gstate->ctm = save_ctm;
151
	}
152
 
153
	if (gstate->blendmode)
154
		fz_begin_group(csi->dev, bbox, 1, 0, gstate->blendmode, 1);
155
}
156
 
157
static void
158
pdf_end_group(pdf_csi *csi)
159
{
160
	pdf_gstate *gstate = csi->gstate + csi->gtop;
161
 
162
	if (gstate->blendmode)
163
		fz_end_group(csi->dev);
164
 
165
	if (gstate->softmask)
166
		fz_pop_clip(csi->dev);
167
}
168
 
169
static void
170
pdf_show_shade(pdf_csi *csi, fz_shade *shd)
171
{
172
	pdf_gstate *gstate = csi->gstate + csi->gtop;
173
	fz_rect bbox;
174
 
175
	bbox = fz_bound_shade(shd, gstate->ctm);
176
 
177
	pdf_begin_group(csi, bbox);
178
 
179
	fz_fill_shade(csi->dev, shd, gstate->ctm, gstate->fill.alpha);
180
 
181
	pdf_end_group(csi);
182
}
183
 
184
static void
185
pdf_show_image(pdf_csi *csi, fz_pixmap *image)
186
{
187
	pdf_gstate *gstate = csi->gstate + csi->gtop;
188
	fz_rect bbox;
189
 
190
	bbox = fz_transform_rect(gstate->ctm, fz_unit_rect);
191
 
192
	if (image->mask)
193
	{
194
		/* apply blend group even though we skip the softmask */
195
		if (gstate->blendmode)
196
			fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
197
		fz_clip_image_mask(csi->dev, image->mask, &bbox, gstate->ctm);
198
	}
199
	else
200
		pdf_begin_group(csi, bbox);
201
 
202
	if (!image->colorspace)
203
	{
204
 
205
		switch (gstate->fill.kind)
206
		{
207
		case PDF_MAT_NONE:
208
			break;
209
		case PDF_MAT_COLOR:
210
			fz_fill_image_mask(csi->dev, image, gstate->ctm,
211
				gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
212
			break;
213
		case PDF_MAT_PATTERN:
214
			if (gstate->fill.pattern)
215
			{
216
				fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm);
217
				pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
218
				fz_pop_clip(csi->dev);
219
			}
220
			break;
221
		case PDF_MAT_SHADE:
222
			if (gstate->fill.shade)
223
			{
224
				fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm);
225
				fz_fill_shade(csi->dev, gstate->fill.shade, gstate->ctm, gstate->fill.alpha);
226
				fz_pop_clip(csi->dev);
227
			}
228
			break;
229
		}
230
	}
231
	else
232
	{
233
		fz_fill_image(csi->dev, image, gstate->ctm, gstate->fill.alpha);
234
	}
235
 
236
	if (image->mask)
237
	{
238
		fz_pop_clip(csi->dev);
239
		if (gstate->blendmode)
240
			fz_end_group(csi->dev);
241
	}
242
	else
243
		pdf_end_group(csi);
244
}
245
 
246
static void pdf_show_clip(pdf_csi *csi, int even_odd)
247
{
248
	pdf_gstate *gstate = csi->gstate + csi->gtop;
249
 
250
	gstate->clip_depth++;
251
	fz_clip_path(csi->dev, csi->path, NULL, even_odd, gstate->ctm);
252
}
253
 
254
static void
255
pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
256
{
257
	pdf_gstate *gstate = csi->gstate + csi->gtop;
258
	fz_path *path;
259
	fz_rect bbox;
260
 
261
	path = csi->path;
262
	csi->path = fz_new_path();
263
 
264
	if (doclose)
265
		fz_closepath(path);
266
 
267
	if (dostroke)
268
		bbox = fz_bound_path(path, &gstate->stroke_state, gstate->ctm);
269
	else
270
		bbox = fz_bound_path(path, NULL, gstate->ctm);
271
 
272
	if (dofill || dostroke)
273
		pdf_begin_group(csi, bbox);
274
 
275
	if (dofill)
276
	{
277
		switch (gstate->fill.kind)
278
		{
279
		case PDF_MAT_NONE:
280
			break;
281
		case PDF_MAT_COLOR:
282
			fz_fill_path(csi->dev, path, even_odd, gstate->ctm,
283
				gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
284
			break;
285
		case PDF_MAT_PATTERN:
286
			if (gstate->fill.pattern)
287
			{
288
				fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm);
289
				pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
290
				fz_pop_clip(csi->dev);
291
			}
292
			break;
293
		case PDF_MAT_SHADE:
294
			if (gstate->fill.shade)
295
			{
296
				fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm);
297
				fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
298
				fz_pop_clip(csi->dev);
299
			}
300
			break;
301
		}
302
	}
303
 
304
	if (dostroke)
305
	{
306
		switch (gstate->stroke.kind)
307
		{
308
		case PDF_MAT_NONE:
309
			break;
310
		case PDF_MAT_COLOR:
311
			fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm,
312
				gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
313
			break;
314
		case PDF_MAT_PATTERN:
315
			if (gstate->stroke.pattern)
316
			{
317
				fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
318
				pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
319
				fz_pop_clip(csi->dev);
320
			}
321
			break;
322
		case PDF_MAT_SHADE:
323
			if (gstate->stroke.shade)
324
			{
325
				fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
326
				fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
327
				fz_pop_clip(csi->dev);
328
			}
329
			break;
330
		}
331
	}
332
 
333
	if (dofill || dostroke)
334
		pdf_end_group(csi);
335
 
336
	fz_free_path(path);
337
}
338
 
339
/*
340
 * Assemble and emit text
341
 */
342
 
343
static void
344
pdf_flush_text(pdf_csi *csi)
345
{
346
	pdf_gstate *gstate = csi->gstate + csi->gtop;
347
	fz_text *text;
348
	int dofill = 0;
349
	int dostroke = 0;
350
	int doclip = 0;
351
	int doinvisible = 0;
352
	fz_rect bbox;
353
 
354
	if (!csi->text)
355
		return;
356
	text = csi->text;
357
	csi->text = NULL;
358
 
359
	dofill = dostroke = doclip = doinvisible = 0;
360
	switch (csi->text_mode)
361
	{
362
	case 0: dofill = 1; break;
363
	case 1: dostroke = 1; break;
364
	case 2: dofill = dostroke = 1; break;
365
	case 3: doinvisible = 1; break;
366
	case 4: dofill = doclip = 1; break;
367
	case 5: dostroke = doclip = 1; break;
368
	case 6: dofill = dostroke = doclip = 1; break;
369
	case 7: doclip = 1; break;
370
	}
371
 
372
	bbox = fz_bound_text(text, gstate->ctm);
373
 
374
	pdf_begin_group(csi, bbox);
375
 
376
	if (doinvisible)
377
		fz_ignore_text(csi->dev, text, gstate->ctm);
378
 
379
	if (doclip)
380
	{
381
		if (csi->accumulate < 2)
382
			gstate->clip_depth++;
383
		fz_clip_text(csi->dev, text, gstate->ctm, csi->accumulate);
384
		csi->accumulate = 2;
385
	}
386
 
387
	if (dofill)
388
	{
389
		switch (gstate->fill.kind)
390
		{
391
		case PDF_MAT_NONE:
392
			break;
393
		case PDF_MAT_COLOR:
394
			fz_fill_text(csi->dev, text, gstate->ctm,
395
				gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
396
			break;
397
		case PDF_MAT_PATTERN:
398
			if (gstate->fill.pattern)
399
			{
400
				fz_clip_text(csi->dev, text, gstate->ctm, 0);
401
				pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
402
				fz_pop_clip(csi->dev);
403
			}
404
			break;
405
		case PDF_MAT_SHADE:
406
			if (gstate->fill.shade)
407
			{
408
				fz_clip_text(csi->dev, text, gstate->ctm, 0);
409
				fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
410
				fz_pop_clip(csi->dev);
411
			}
412
			break;
413
		}
414
	}
415
 
416
	if (dostroke)
417
	{
418
		switch (gstate->stroke.kind)
419
		{
420
		case PDF_MAT_NONE:
421
			break;
422
		case PDF_MAT_COLOR:
423
			fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm,
424
				gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
425
			break;
426
		case PDF_MAT_PATTERN:
427
			if (gstate->stroke.pattern)
428
			{
429
				fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
430
				pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
431
				fz_pop_clip(csi->dev);
432
			}
433
			break;
434
		case PDF_MAT_SHADE:
435
			if (gstate->stroke.shade)
436
			{
437
				fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
438
				fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
439
				fz_pop_clip(csi->dev);
440
			}
441
			break;
442
		}
443
	}
444
 
445
	pdf_end_group(csi);
446
 
447
	fz_free_text(text);
448
}
449
 
450
static void
451
pdf_show_char(pdf_csi *csi, int cid)
452
{
453
	pdf_gstate *gstate = csi->gstate + csi->gtop;
454
	pdf_font_desc *fontdesc = gstate->font;
455
	fz_matrix tsm, trm;
456
	float w0, w1, tx, ty;
457
	pdf_hmtx h;
458
	pdf_vmtx v;
459
	int gid;
460
	int ucsbuf[8];
461
	int ucslen;
462
	int i;
463
 
464
	tsm.a = gstate->size * gstate->scale;
465
	tsm.b = 0;
466
	tsm.c = 0;
467
	tsm.d = gstate->size;
468
	tsm.e = 0;
469
	tsm.f = gstate->rise;
470
 
471
	ucslen = 0;
472
	if (fontdesc->to_unicode)
473
		ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
474
	if (ucslen == 0 && cid < fontdesc->cid_to_ucs_len)
475
	{
476
		ucsbuf[0] = fontdesc->cid_to_ucs[cid];
477
		ucslen = 1;
478
	}
479
	if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
480
	{
481
		ucsbuf[0] = '?';
482
		ucslen = 1;
483
	}
484
 
485
	gid = pdf_font_cid_to_gid(fontdesc, cid);
486
 
487
	if (fontdesc->wmode == 1)
488
	{
489
		v = pdf_get_vmtx(fontdesc, cid);
490
		tsm.e -= v.x * gstate->size * 0.001f;
491
		tsm.f -= v.y * gstate->size * 0.001f;
492
	}
493
 
494
	trm = fz_concat(tsm, csi->tm);
495
 
496
	/* flush buffered text if face or matrix or rendermode has changed */
497
	if (!csi->text ||
498
		fontdesc->font != csi->text->font ||
499
		fontdesc->wmode != csi->text->wmode ||
500
		fabsf(trm.a - csi->text->trm.a) > FLT_EPSILON ||
501
		fabsf(trm.b - csi->text->trm.b) > FLT_EPSILON ||
502
		fabsf(trm.c - csi->text->trm.c) > FLT_EPSILON ||
503
		fabsf(trm.d - csi->text->trm.d) > FLT_EPSILON ||
504
		gstate->render != csi->text_mode)
505
	{
506
		pdf_flush_text(csi);
507
 
508
		csi->text = fz_new_text(fontdesc->font, trm, fontdesc->wmode);
509
		csi->text->trm.e = 0;
510
		csi->text->trm.f = 0;
511
		csi->text_mode = gstate->render;
512
	}
513
 
514
	/* add glyph to textobject */
515
	fz_add_text(csi->text, gid, ucsbuf[0], trm.e, trm.f);
516
 
517
	/* add filler glyphs for one-to-many unicode mapping */
518
	for (i = 1; i < ucslen; i++)
519
		fz_add_text(csi->text, -1, ucsbuf[i], trm.e, trm.f);
520
 
521
	if (fontdesc->wmode == 0)
522
	{
523
		h = pdf_get_hmtx(fontdesc, cid);
524
		w0 = h.w * 0.001f;
525
		tx = (w0 * gstate->size + gstate->char_space) * gstate->scale;
526
		csi->tm = fz_concat(fz_translate(tx, 0), csi->tm);
527
	}
528
 
529
	if (fontdesc->wmode == 1)
530
	{
531
		w1 = v.w * 0.001f;
532
		ty = w1 * gstate->size + gstate->char_space;
533
		csi->tm = fz_concat(fz_translate(0, ty), csi->tm);
534
	}
535
}
536
 
537
static void
538
pdf_show_space(pdf_csi *csi, float tadj)
539
{
540
	pdf_gstate *gstate = csi->gstate + csi->gtop;
541
	pdf_font_desc *fontdesc = gstate->font;
542
 
543
	if (!fontdesc)
544
	{
545
		fz_warn("cannot draw text since font and size not set");
546
		return;
547
	}
548
 
549
	if (fontdesc->wmode == 0)
550
		csi->tm = fz_concat(fz_translate(tadj * gstate->scale, 0), csi->tm);
551
	else
552
		csi->tm = fz_concat(fz_translate(0, tadj), csi->tm);
553
}
554
 
555
static void
556
pdf_show_string(pdf_csi *csi, unsigned char *buf, int len)
557
{
558
	pdf_gstate *gstate = csi->gstate + csi->gtop;
559
	pdf_font_desc *fontdesc = gstate->font;
560
	unsigned char *end = buf + len;
561
	int cpt, cid;
562
 
563
	if (!fontdesc)
564
	{
565
		fz_warn("cannot draw text since font and size not set");
566
		return;
567
	}
568
 
569
	while (buf < end)
570
	{
571
		buf = pdf_decode_cmap(fontdesc->encoding, buf, &cpt);
572
		cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
573
		if (cid >= 0)
574
			pdf_show_char(csi, cid);
575
		else
576
			fz_warn("cannot encode character with code point %#x", cpt);
577
		if (cpt == 32)
578
			pdf_show_space(csi, gstate->word_space);
579
	}
580
}
581
 
582
static void
583
pdf_show_text(pdf_csi *csi, fz_obj *text)
584
{
585
	pdf_gstate *gstate = csi->gstate + csi->gtop;
586
	int i;
587
 
588
	if (fz_is_array(text))
589
	{
590
		for (i = 0; i < fz_array_len(text); i++)
591
		{
592
			fz_obj *item = fz_array_get(text, i);
593
			if (fz_is_string(item))
594
				pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item));
595
			else
596
				pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f);
597
		}
598
	}
599
	else if (fz_is_string(text))
600
	{
601
		pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text));
602
	}
603
}
604
 
605
/*
606
 * Interpreter and graphics state stack.
607
 */
608
 
609
static void
610
pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
611
{
612
	gs->ctm = ctm;
613
	gs->clip_depth = 0;
614
 
615
	gs->stroke_state.start_cap = 0;
616
	gs->stroke_state.dash_cap = 0;
617
	gs->stroke_state.end_cap = 0;
618
	gs->stroke_state.linejoin = 0;
619
	gs->stroke_state.linewidth = 1;
620
	gs->stroke_state.miterlimit = 10;
621
	gs->stroke_state.dash_phase = 0;
622
	gs->stroke_state.dash_len = 0;
623
	memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list));
624
 
625
	gs->stroke.kind = PDF_MAT_COLOR;
626
	gs->stroke.colorspace = fz_keep_colorspace(fz_device_gray);
627
	gs->stroke.v[0] = 0;
628
	gs->stroke.pattern = NULL;
629
	gs->stroke.shade = NULL;
630
	gs->stroke.alpha = 1;
631
 
632
	gs->fill.kind = PDF_MAT_COLOR;
633
	gs->fill.colorspace = fz_keep_colorspace(fz_device_gray);
634
	gs->fill.v[0] = 0;
635
	gs->fill.pattern = NULL;
636
	gs->fill.shade = NULL;
637
	gs->fill.alpha = 1;
638
 
639
	gs->char_space = 0;
640
	gs->word_space = 0;
641
	gs->scale = 1;
642
	gs->leading = 0;
643
	gs->font = NULL;
644
	gs->size = -1;
645
	gs->render = 0;
646
	gs->rise = 0;
647
 
648
	gs->blendmode = 0;
649
	gs->softmask = NULL;
650
	gs->softmask_ctm = fz_identity;
651
	gs->luminosity = 0;
652
}
653
 
654
static pdf_csi *
655
pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target)
656
{
657
	pdf_csi *csi;
658
 
659
	csi = fz_malloc(sizeof(pdf_csi));
660
	csi->xref = xref;
661
	csi->dev = dev;
662
	csi->target = target;
663
 
664
	csi->top = 0;
665
	csi->obj = NULL;
666
	csi->name[0] = 0;
667
	csi->string_len = 0;
668
	memset(csi->stack, 0, sizeof csi->stack);
669
 
670
	csi->xbalance = 0;
671
	csi->in_text = 0;
672
 
673
	csi->path = fz_new_path();
674
 
675
	csi->text = NULL;
676
	csi->tlm = fz_identity;
677
	csi->tm = fz_identity;
678
	csi->text_mode = 0;
679
	csi->accumulate = 1;
680
 
681
	csi->top_ctm = ctm;
682
	pdf_init_gstate(&csi->gstate[0], ctm);
683
	csi->gtop = 0;
684
 
685
	return csi;
686
}
687
 
688
static void
689
pdf_clear_stack(pdf_csi *csi)
690
{
691
	int i;
692
 
693
	if (csi->obj)
694
		fz_drop_obj(csi->obj);
695
	csi->obj = NULL;
696
 
697
	csi->name[0] = 0;
698
	csi->string_len = 0;
699
	for (i = 0; i < csi->top; i++)
700
		csi->stack[i] = 0;
701
 
702
	csi->top = 0;
703
}
704
 
705
static pdf_material *
706
pdf_keep_material(pdf_material *mat)
707
{
708
	if (mat->colorspace)
709
		fz_keep_colorspace(mat->colorspace);
710
	if (mat->pattern)
711
		pdf_keep_pattern(mat->pattern);
712
	if (mat->shade)
713
		fz_keep_shade(mat->shade);
714
	return mat;
715
}
716
 
717
static pdf_material *
718
pdf_drop_material(pdf_material *mat)
719
{
720
	if (mat->colorspace)
721
		fz_drop_colorspace(mat->colorspace);
722
	if (mat->pattern)
723
		pdf_drop_pattern(mat->pattern);
724
	if (mat->shade)
725
		fz_drop_shade(mat->shade);
726
	return mat;
727
}
728
 
729
static void
730
pdf_gsave(pdf_csi *csi)
731
{
732
	pdf_gstate *gs = csi->gstate + csi->gtop;
733
 
734
	if (csi->gtop == nelem(csi->gstate) - 1)
735
	{
736
		fz_warn("gstate overflow in content stream");
737
		return;
738
	}
739
 
740
	memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate));
741
 
742
	csi->gtop ++;
743
 
744
	pdf_keep_material(&gs->stroke);
745
	pdf_keep_material(&gs->fill);
746
	if (gs->font)
747
		pdf_keep_font(gs->font);
748
	if (gs->softmask)
749
		pdf_keep_xobject(gs->softmask);
750
}
751
 
752
static void
753
pdf_grestore(pdf_csi *csi)
754
{
755
	pdf_gstate *gs = csi->gstate + csi->gtop;
756
	int clip_depth = gs->clip_depth;
757
 
758
	if (csi->gtop == 0)
759
	{
760
		fz_warn("gstate underflow in content stream");
761
		return;
762
	}
763
 
764
	pdf_drop_material(&gs->stroke);
765
	pdf_drop_material(&gs->fill);
766
	if (gs->font)
767
		pdf_drop_font(gs->font);
768
	if (gs->softmask)
769
		pdf_drop_xobject(gs->softmask);
770
 
771
	csi->gtop --;
772
 
773
	gs = csi->gstate + csi->gtop;
774
	while (clip_depth > gs->clip_depth)
775
	{
776
		fz_pop_clip(csi->dev);
777
		clip_depth--;
778
	}
779
}
780
 
781
static void
782
pdf_free_csi(pdf_csi *csi)
783
{
784
	while (csi->gtop)
785
		pdf_grestore(csi);
786
 
787
	pdf_drop_material(&csi->gstate[0].fill);
788
	pdf_drop_material(&csi->gstate[0].stroke);
789
	if (csi->gstate[0].font)
790
		pdf_drop_font(csi->gstate[0].font);
791
	if (csi->gstate[0].softmask)
792
		pdf_drop_xobject(csi->gstate[0].softmask);
793
 
794
	while (csi->gstate[0].clip_depth--)
795
		fz_pop_clip(csi->dev);
796
 
797
	if (csi->path) fz_free_path(csi->path);
798
	if (csi->text) fz_free_text(csi->text);
799
 
800
	pdf_clear_stack(csi);
801
 
802
	fz_free(csi);
803
}
804
 
805
/*
806
 * Material state
807
 */
808
 
809
static void
810
pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *colorspace)
811
{
812
	pdf_gstate *gs = csi->gstate + csi->gtop;
813
	pdf_material *mat;
814
 
815
	pdf_flush_text(csi);
816
 
817
	mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
818
 
819
	fz_drop_colorspace(mat->colorspace);
820
 
821
	mat->kind = PDF_MAT_COLOR;
822
	mat->colorspace = fz_keep_colorspace(colorspace);
823
 
824
	mat->v[0] = 0;
825
	mat->v[1] = 0;
826
	mat->v[2] = 0;
827
	mat->v[3] = 1;
828
}
829
 
830
static void
831
pdf_set_color(pdf_csi *csi, int what, float *v)
832
{
833
	pdf_gstate *gs = csi->gstate + csi->gtop;
834
	pdf_material *mat;
835
	int i;
836
 
837
	pdf_flush_text(csi);
838
 
839
	mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
840
 
841
	switch (mat->kind)
842
	{
843
	case PDF_MAT_PATTERN:
844
	case PDF_MAT_COLOR:
845
		if (!strcmp(mat->colorspace->name, "Lab"))
846
		{
847
			mat->v[0] = v[0] / 100;
848
			mat->v[1] = (v[1] + 100) / 200;
849
			mat->v[2] = (v[2] + 100) / 200;
850
		}
851
		for (i = 0; i < mat->colorspace->n; i++)
852
			mat->v[i] = v[i];
853
		break;
854
	default:
855
		fz_warn("color incompatible with material");
856
	}
857
}
858
 
859
static void
860
pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade)
861
{
862
	pdf_gstate *gs = csi->gstate + csi->gtop;
863
	pdf_material *mat;
864
 
865
	pdf_flush_text(csi);
866
 
867
	mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
868
 
869
	if (mat->shade)
870
		fz_drop_shade(mat->shade);
871
 
872
	mat->kind = PDF_MAT_SHADE;
873
	mat->shade = fz_keep_shade(shade);
874
}
875
 
876
static void
877
pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v)
878
{
879
	pdf_gstate *gs = csi->gstate + csi->gtop;
880
	pdf_material *mat;
881
 
882
	pdf_flush_text(csi);
883
 
884
	mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
885
 
886
	if (mat->pattern)
887
		pdf_drop_pattern(mat->pattern);
888
 
889
	mat->kind = PDF_MAT_PATTERN;
890
	if (pat)
891
		mat->pattern = pdf_keep_pattern(pat);
892
	else
893
		mat->pattern = NULL;
894
 
895
	if (v)
896
		pdf_set_color(csi, what, v);
897
}
898
 
899
static void
900
pdf_unset_pattern(pdf_csi *csi, int what)
901
{
902
	pdf_gstate *gs = csi->gstate + csi->gtop;
903
	pdf_material *mat;
904
	mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
905
	if (mat->kind == PDF_MAT_PATTERN)
906
	{
907
		if (mat->pattern)
908
			pdf_drop_pattern(mat->pattern);
909
		mat->pattern = NULL;
910
		mat->kind = PDF_MAT_COLOR;
911
	}
912
}
913
 
914
/*
915
 * Patterns, XObjects and ExtGState
916
 */
917
 
918
static void
919
pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what)
920
{
921
	pdf_gstate *gstate;
922
	fz_matrix ptm, invptm;
923
	fz_matrix oldtopctm;
924
	fz_error error;
925
	int x0, y0, x1, y1;
926
	int oldtop;
927
 
928
	pdf_gsave(csi);
929
	gstate = csi->gstate + csi->gtop;
930
 
931
	if (pat->ismask)
932
	{
933
		pdf_unset_pattern(csi, PDF_FILL);
934
		pdf_unset_pattern(csi, PDF_STROKE);
935
		if (what == PDF_FILL)
936
		{
937
			pdf_drop_material(&gstate->stroke);
938
			pdf_keep_material(&gstate->fill);
939
			gstate->stroke = gstate->fill;
940
		}
941
		if (what == PDF_STROKE)
942
		{
943
			pdf_drop_material(&gstate->fill);
944
			pdf_keep_material(&gstate->stroke);
945
			gstate->fill = gstate->stroke;
946
		}
947
	}
948
	else
949
	{
950
		// TODO: unset only the current fill/stroke or both?
951
		pdf_unset_pattern(csi, what);
952
	}
953
 
954
	/* don't apply softmasks to objects in the pattern as well */
955
	if (gstate->softmask)
956
	{
957
		pdf_drop_xobject(gstate->softmask);
958
		gstate->softmask = NULL;
959
	}
960
 
961
	ptm = fz_concat(pat->matrix, csi->top_ctm);
962
	invptm = fz_invert_matrix(ptm);
963
 
964
	/* patterns are painted using the ctm in effect at the beginning of the content stream */
965
	/* get bbox of shape in pattern space for stamping */
966
	area = fz_transform_rect(invptm, area);
967
	x0 = floorf(area.x0 / pat->xstep);
968
	y0 = floorf(area.y0 / pat->ystep);
969
	x1 = ceilf(area.x1 / pat->xstep);
970
	y1 = ceilf(area.y1 / pat->ystep);
971
 
972
	oldtopctm = csi->top_ctm;
973
	oldtop = csi->gtop;
974
 
975
#ifdef TILE
976
	if ((x1 - x0) * (y1 - y0) > 0)
977
	{
978
		fz_begin_tile(csi->dev, area, pat->bbox, pat->xstep, pat->ystep, ptm);
979
		gstate->ctm = ptm;
980
		csi->top_ctm = gstate->ctm;
981
		pdf_gsave(csi);
982
		error = pdf_run_buffer(csi, pat->resources, pat->contents);
983
		if (error)
984
			fz_catch(error, "cannot render pattern tile");
985
		pdf_grestore(csi);
986
		while (oldtop < csi->gtop)
987
			pdf_grestore(csi);
988
		fz_end_tile(csi->dev);
989
	}
990
#else
991
	{
992
		int x, y;
993
		for (y = y0; y < y1; y++)
994
		{
995
			for (x = x0; x < x1; x++)
996
			{
997
				gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm);
998
				csi->top_ctm = gstate->ctm;
999
				error = pdf_run_csi_buffer(csi, pat->resources, pat->contents);
1000
				while (oldtop < csi->gtop)
1001
					pdf_grestore(csi);
1002
				if (error)
1003
				{
1004
					fz_catch(error, "cannot render pattern tile");
1005
					goto cleanup;
1006
				}
1007
			}
1008
		}
1009
	}
1010
cleanup:
1011
#endif
1012
 
1013
	csi->top_ctm = oldtopctm;
1014
 
1015
	pdf_grestore(csi);
1016
}
1017
 
1018
static fz_error
1019
pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform)
1020
{
1021
	fz_error error;
1022
	pdf_gstate *gstate;
1023
	fz_matrix oldtopctm;
1024
	int oldtop;
1025
	int popmask;
1026
 
1027
	pdf_gsave(csi);
1028
 
1029
	gstate = csi->gstate + csi->gtop;
1030
	oldtop = csi->gtop;
1031
	popmask = 0;
1032
 
1033
	/* apply xobject's transform matrix */
1034
	transform = fz_concat(xobj->matrix, transform);
1035
	gstate->ctm = fz_concat(transform, gstate->ctm);
1036
 
1037
	/* apply soft mask, create transparency group and reset state */
1038
	if (xobj->transparency)
1039
	{
1040
		if (gstate->softmask)
1041
		{
1042
			pdf_xobject *softmask = gstate->softmask;
1043
			fz_rect bbox = fz_transform_rect(gstate->ctm, xobj->bbox);
1044
 
1045
			gstate->softmask = NULL;
1046
			popmask = 1;
1047
 
1048
			fz_begin_mask(csi->dev, bbox, gstate->luminosity,
1049
				softmask->colorspace, gstate->softmask_bc);
1050
			error = pdf_run_xobject(csi, resources, softmask, fz_identity);
1051
			if (error)
1052
				return fz_rethrow(error, "cannot run softmask");
1053
			fz_end_mask(csi->dev);
1054
 
1055
			pdf_drop_xobject(softmask);
1056
		}
1057
 
1058
		fz_begin_group(csi->dev,
1059
			fz_transform_rect(gstate->ctm, xobj->bbox),
1060
			xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha);
1061
 
1062
		gstate->blendmode = 0;
1063
		gstate->stroke.alpha = 1;
1064
		gstate->fill.alpha = 1;
1065
	}
1066
 
1067
	/* clip to the bounds */
1068
 
1069
	fz_moveto(csi->path, xobj->bbox.x0, xobj->bbox.y0);
1070
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y0);
1071
	fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y1);
1072
	fz_lineto(csi->path, xobj->bbox.x0, xobj->bbox.y1);
1073
	fz_closepath(csi->path);
1074
	pdf_show_clip(csi, 0);
1075
	pdf_show_path(csi, 0, 0, 0, 0);
1076
 
1077
	/* run contents */
1078
 
1079
	oldtopctm = csi->top_ctm;
1080
	csi->top_ctm = gstate->ctm;
1081
 
1082
	if (xobj->resources)
1083
		resources = xobj->resources;
1084
 
1085
	error = pdf_run_buffer(csi, resources, xobj->contents);
1086
	if (error)
1087
		fz_catch(error, "cannot interpret XObject stream");
1088
 
1089
	csi->top_ctm = oldtopctm;
1090
 
1091
	while (oldtop < csi->gtop)
1092
		pdf_grestore(csi);
1093
 
1094
	pdf_grestore(csi);
1095
 
1096
	/* wrap up transparency stacks */
1097
 
1098
	if (xobj->transparency)
1099
	{
1100
		fz_end_group(csi->dev);
1101
		if (popmask)
1102
			fz_pop_clip(csi->dev);
1103
	}
1104
 
1105
	return fz_okay;
1106
}
1107
 
1108
static fz_error
1109
pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate)
1110
{
1111
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1112
	fz_colorspace *colorspace;
1113
	int i, k;
1114
 
1115
	pdf_flush_text(csi);
1116
 
1117
	for (i = 0; i < fz_dict_len(extgstate); i++)
1118
	{
1119
		fz_obj *key = fz_dict_get_key(extgstate, i);
1120
		fz_obj *val = fz_dict_get_val(extgstate, i);
1121
		char *s = fz_to_name(key);
1122
 
1123
		if (!strcmp(s, "Font"))
1124
		{
1125
			if (fz_is_array(val) && fz_array_len(val) == 2)
1126
			{
1127
				fz_error error;
1128
				fz_obj *font = fz_array_get(val, 0);
1129
 
1130
				if (gstate->font)
1131
				{
1132
					pdf_drop_font(gstate->font);
1133
					gstate->font = NULL;
1134
				}
1135
 
1136
				error = pdf_load_font(&gstate->font, csi->xref, rdb, font);
1137
				if (error)
1138
					return fz_rethrow(error, "cannot load font (%d %d R)", fz_to_num(font), fz_to_gen(font));
1139
				if (!gstate->font)
1140
					return fz_throw("cannot find font in store");
1141
				gstate->size = fz_to_real(fz_array_get(val, 1));
1142
			}
1143
			else
1144
				return fz_throw("malformed /Font dictionary");
1145
		}
1146
 
1147
		else if (!strcmp(s, "LC"))
1148
		{
1149
			gstate->stroke_state.start_cap = fz_to_int(val);
1150
			gstate->stroke_state.dash_cap = fz_to_int(val);
1151
			gstate->stroke_state.end_cap = fz_to_int(val);
1152
		}
1153
		else if (!strcmp(s, "LW"))
1154
			gstate->stroke_state.linewidth = fz_to_real(val);
1155
		else if (!strcmp(s, "LJ"))
1156
			gstate->stroke_state.linejoin = fz_to_int(val);
1157
		else if (!strcmp(s, "ML"))
1158
			gstate->stroke_state.miterlimit = fz_to_real(val);
1159
 
1160
		else if (!strcmp(s, "D"))
1161
		{
1162
			if (fz_is_array(val) && fz_array_len(val) == 2)
1163
			{
1164
				fz_obj *dashes = fz_array_get(val, 0);
1165
				gstate->stroke_state.dash_len = MAX(fz_array_len(dashes), 32);
1166
				for (k = 0; k < gstate->stroke_state.dash_len; k++)
1167
					gstate->stroke_state.dash_list[k] = fz_to_real(fz_array_get(dashes, k));
1168
				gstate->stroke_state.dash_phase = fz_to_real(fz_array_get(val, 1));
1169
			}
1170
			else
1171
				return fz_throw("malformed /D");
1172
		}
1173
 
1174
		else if (!strcmp(s, "CA"))
1175
			gstate->stroke.alpha = fz_to_real(val);
1176
 
1177
		else if (!strcmp(s, "ca"))
1178
			gstate->fill.alpha = fz_to_real(val);
1179
 
1180
		else if (!strcmp(s, "BM"))
1181
		{
1182
			if (fz_is_array(val))
1183
				val = fz_array_get(val, 0);
1184
			gstate->blendmode = fz_find_blendmode(fz_to_name(val));
1185
		}
1186
 
1187
		else if (!strcmp(s, "SMask"))
1188
		{
1189
			if (fz_is_dict(val))
1190
			{
1191
				fz_error error;
1192
				pdf_xobject *xobj;
1193
				fz_obj *group, *luminosity, *bc;
1194
 
1195
				if (gstate->softmask)
1196
				{
1197
					pdf_drop_xobject(gstate->softmask);
1198
					gstate->softmask = NULL;
1199
				}
1200
 
1201
				group = fz_dict_gets(val, "G");
1202
				if (!group)
1203
					return fz_throw("cannot load softmask xobject (%d %d R)", fz_to_num(val), fz_to_gen(val));
1204
				error = pdf_load_xobject(&xobj, csi->xref, group);
1205
				if (error)
1206
					return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(val), fz_to_gen(val));
1207
 
1208
				colorspace = xobj->colorspace;
1209
				if (!colorspace)
1210
					colorspace = fz_device_gray;
1211
 
1212
				gstate->softmask_ctm = fz_concat(xobj->matrix, gstate->ctm);
1213
				gstate->softmask = xobj;
1214
				for (k = 0; k < colorspace->n; k++)
1215
					gstate->softmask_bc[k] = 0;
1216
 
1217
				bc = fz_dict_gets(val, "BC");
1218
				if (fz_is_array(bc))
1219
				{
1220
					for (k = 0; k < colorspace->n; k++)
1221
						gstate->softmask_bc[k] = fz_to_real(fz_array_get(bc, k));
1222
				}
1223
 
1224
				luminosity = fz_dict_gets(val, "S");
1225
				if (fz_is_name(luminosity) && !strcmp(fz_to_name(luminosity), "Luminosity"))
1226
					gstate->luminosity = 1;
1227
				else
1228
					gstate->luminosity = 0;
1229
			}
1230
			else if (fz_is_name(val) && !strcmp(fz_to_name(val), "None"))
1231
			{
1232
				if (gstate->softmask)
1233
				{
1234
					pdf_drop_xobject(gstate->softmask);
1235
					gstate->softmask = NULL;
1236
				}
1237
			}
1238
		}
1239
 
1240
		else if (!strcmp(s, "TR"))
1241
		{
1242
			if (fz_is_name(val) && strcmp(fz_to_name(val), "Identity"))
1243
				fz_warn("ignoring transfer function");
1244
		}
1245
	}
1246
 
1247
	return fz_okay;
1248
}
1249
 
1250
/*
1251
 * Operators
1252
 */
1253
 
1254
static void pdf_run_BDC(pdf_csi *csi)
1255
{
1256
}
1257
 
1258
static fz_error pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
1259
{
1260
	int ch;
1261
	fz_error error;
1262
	char *buf = csi->xref->scratch;
1263
	int buflen = sizeof(csi->xref->scratch);
1264
	fz_pixmap *img;
1265
	fz_obj *obj;
1266
 
1267
	error = pdf_parse_dict(&obj, csi->xref, file, buf, buflen);
1268
	if (error)
1269
		return fz_rethrow(error, "cannot parse inline image dictionary");
1270
 
1271
	/* read whitespace after ID keyword */
1272
	ch = fz_read_byte(file);
1273
	if (ch == '\r')
1274
		if (fz_peek_byte(file) == '\n')
1275
			fz_read_byte(file);
1276
 
1277
	error = pdf_load_inline_image(&img, csi->xref, rdb, obj, file);
1278
	fz_drop_obj(obj);
1279
	if (error)
1280
		return fz_rethrow(error, "cannot load inline image");
1281
 
1282
	pdf_show_image(csi, img);
1283
 
1284
	fz_drop_pixmap(img);
1285
 
1286
	/* find EI */
1287
	ch = fz_read_byte(file);
1288
	while (ch != 'E' && ch != EOF)
1289
		ch = fz_read_byte(file);
1290
	ch = fz_read_byte(file);
1291
	if (ch != 'I')
1292
		return fz_rethrow(error, "syntax error after inline image");
1293
 
1294
	return fz_okay;
1295
}
1296
 
1297
static void pdf_run_B(pdf_csi *csi)
1298
{
1299
	pdf_show_path(csi, 0, 1, 1, 0);
1300
}
1301
 
1302
static void pdf_run_BMC(pdf_csi *csi)
1303
{
1304
}
1305
 
1306
static void pdf_run_BT(pdf_csi *csi)
1307
{
1308
	csi->in_text = 1;
1309
	csi->tm = fz_identity;
1310
	csi->tlm = fz_identity;
1311
}
1312
 
1313
static void pdf_run_BX(pdf_csi *csi)
1314
{
1315
	csi->xbalance ++;
1316
}
1317
 
1318
static void pdf_run_Bstar(pdf_csi *csi)
1319
{
1320
	pdf_show_path(csi, 0, 1, 1, 1);
1321
}
1322
 
1323
static fz_error pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what)
1324
{
1325
	fz_colorspace *colorspace;
1326
	fz_obj *obj, *dict;
1327
	fz_error error;
1328
 
1329
	if (!strcmp(csi->name, "Pattern"))
1330
	{
1331
		pdf_set_pattern(csi, what, NULL, NULL);
1332
	}
1333
	else
1334
	{
1335
		if (!strcmp(csi->name, "DeviceGray"))
1336
			colorspace = fz_keep_colorspace(fz_device_gray);
1337
		else if (!strcmp(csi->name, "DeviceRGB"))
1338
			colorspace = fz_keep_colorspace(fz_device_rgb);
1339
		else if (!strcmp(csi->name, "DeviceCMYK"))
1340
			colorspace = fz_keep_colorspace(fz_device_cmyk);
1341
		else
1342
		{
1343
			dict = fz_dict_gets(rdb, "ColorSpace");
1344
			if (!dict)
1345
				return fz_throw("cannot find ColorSpace dictionary");
1346
			obj = fz_dict_gets(dict, csi->name);
1347
			if (!obj)
1348
				return fz_throw("cannot find colorspace resource '%s'", csi->name);
1349
			error = pdf_load_colorspace(&colorspace, csi->xref, obj);
1350
			if (error)
1351
				return fz_rethrow(error, "cannot load colorspace (%d 0 R)", fz_to_num(obj));
1352
		}
1353
 
1354
		pdf_set_colorspace(csi, what, colorspace);
1355
 
1356
		fz_drop_colorspace(colorspace);
1357
	}
1358
	return fz_okay;
1359
}
1360
 
1361
static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb)
1362
{
1363
	fz_error error;
1364
	error = pdf_run_cs_imp(csi, rdb, PDF_STROKE);
1365
	if (error)
1366
		fz_catch(error, "cannot set colorspace");
1367
}
1368
 
1369
static void pdf_run_cs(pdf_csi *csi, fz_obj *rdb)
1370
{
1371
	fz_error error;
1372
	error = pdf_run_cs_imp(csi, rdb, PDF_FILL);
1373
	if (error)
1374
		fz_catch(error, "cannot set colorspace");
1375
}
1376
 
1377
static void pdf_run_DP(pdf_csi *csi)
1378
{
1379
}
1380
 
1381
static fz_error pdf_run_Do(pdf_csi *csi, fz_obj *rdb)
1382
{
1383
	fz_obj *dict;
1384
	fz_obj *obj;
1385
	fz_obj *subtype;
1386
	fz_error error;
1387
 
1388
	dict = fz_dict_gets(rdb, "XObject");
1389
	if (!dict)
1390
		return fz_throw("cannot find XObject dictionary when looking for: '%s'", csi->name);
1391
 
1392
	obj = fz_dict_gets(dict, csi->name);
1393
	if (!obj)
1394
		return fz_throw("cannot find xobject resource: '%s'", csi->name);
1395
 
1396
	subtype = fz_dict_gets(obj, "Subtype");
1397
	if (!fz_is_name(subtype))
1398
		return fz_throw("no XObject subtype specified");
1399
 
1400
	if (pdf_is_hidden_ocg(obj, csi->target))
1401
		return fz_okay;
1402
 
1403
	if (!strcmp(fz_to_name(subtype), "Form") && fz_dict_gets(obj, "Subtype2"))
1404
		subtype = fz_dict_gets(obj, "Subtype2");
1405
 
1406
	if (!strcmp(fz_to_name(subtype), "Form"))
1407
	{
1408
		pdf_xobject *xobj;
1409
 
1410
		error = pdf_load_xobject(&xobj, csi->xref, obj);
1411
		if (error)
1412
			return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
1413
 
1414
		/* Inherit parent resources, in case this one was empty XXX check where it's loaded */
1415
		if (!xobj->resources)
1416
			xobj->resources = fz_keep_obj(rdb);
1417
 
1418
		error = pdf_run_xobject(csi, xobj->resources, xobj, fz_identity);
1419
		if (error)
1420
			return fz_rethrow(error, "cannot draw xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
1421
 
1422
		pdf_drop_xobject(xobj);
1423
	}
1424
 
1425
	else if (!strcmp(fz_to_name(subtype), "Image"))
1426
	{
1427
		if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0)
1428
		{
1429
			fz_pixmap *img;
1430
			error = pdf_load_image(&img, csi->xref, obj);
1431
			if (error)
1432
				return fz_rethrow(error, "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
1433
			pdf_show_image(csi, img);
1434
			fz_drop_pixmap(img);
1435
		}
1436
	}
1437
 
1438
	else if (!strcmp(fz_to_name(subtype), "PS"))
1439
	{
1440
		fz_warn("ignoring XObject with subtype PS");
1441
	}
1442
 
1443
	else
1444
	{
1445
		return fz_throw("unknown XObject subtype: '%s'", fz_to_name(subtype));
1446
	}
1447
 
1448
	return fz_okay;
1449
}
1450
 
1451
static void pdf_run_EMC(pdf_csi *csi)
1452
{
1453
}
1454
 
1455
static void pdf_run_ET(pdf_csi *csi)
1456
{
1457
	pdf_flush_text(csi);
1458
	csi->accumulate = 1;
1459
	csi->in_text = 0;
1460
}
1461
 
1462
static void pdf_run_EX(pdf_csi *csi)
1463
{
1464
	csi->xbalance --;
1465
}
1466
 
1467
static void pdf_run_F(pdf_csi *csi)
1468
{
1469
	pdf_show_path(csi, 0, 1, 0, 0);
1470
}
1471
 
1472
static void pdf_run_G(pdf_csi *csi)
1473
{
1474
	pdf_set_colorspace(csi, PDF_STROKE, fz_device_gray);
1475
	pdf_set_color(csi, PDF_STROKE, csi->stack);
1476
}
1477
 
1478
static void pdf_run_J(pdf_csi *csi)
1479
{
1480
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1481
	gstate->stroke_state.start_cap = csi->stack[0];
1482
	gstate->stroke_state.dash_cap = csi->stack[0];
1483
	gstate->stroke_state.end_cap = csi->stack[0];
1484
}
1485
 
1486
static void pdf_run_K(pdf_csi *csi)
1487
{
1488
	pdf_set_colorspace(csi, PDF_STROKE, fz_device_cmyk);
1489
	pdf_set_color(csi, PDF_STROKE, csi->stack);
1490
}
1491
 
1492
static void pdf_run_M(pdf_csi *csi)
1493
{
1494
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1495
	gstate->stroke_state.miterlimit = csi->stack[0];
1496
}
1497
 
1498
static void pdf_run_MP(pdf_csi *csi)
1499
{
1500
}
1501
 
1502
static void pdf_run_Q(pdf_csi *csi)
1503
{
1504
	pdf_grestore(csi);
1505
}
1506
 
1507
static void pdf_run_RG(pdf_csi *csi)
1508
{
1509
	pdf_set_colorspace(csi, PDF_STROKE, fz_device_rgb);
1510
	pdf_set_color(csi, PDF_STROKE, csi->stack);
1511
}
1512
 
1513
static void pdf_run_S(pdf_csi *csi)
1514
{
1515
	pdf_show_path(csi, 0, 0, 1, 0);
1516
}
1517
 
1518
static fz_error pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *mat)
1519
{
1520
	fz_error error;
1521
	fz_obj *patterntype;
1522
	fz_obj *dict;
1523
	fz_obj *obj;
1524
	int kind;
1525
 
1526
	kind = mat->kind;
1527
	if (csi->name[0])
1528
		kind = PDF_MAT_PATTERN;
1529
 
1530
	switch (kind)
1531
	{
1532
	case PDF_MAT_NONE:
1533
		return fz_throw("cannot set color in mask objects");
1534
 
1535
	case PDF_MAT_COLOR:
1536
		pdf_set_color(csi, what, csi->stack);
1537
		break;
1538
 
1539
	case PDF_MAT_PATTERN:
1540
		dict = fz_dict_gets(rdb, "Pattern");
1541
		if (!dict)
1542
			return fz_throw("cannot find Pattern dictionary");
1543
 
1544
		obj = fz_dict_gets(dict, csi->name);
1545
		if (!obj)
1546
			return fz_throw("cannot find pattern resource '%s'", csi->name);
1547
 
1548
		patterntype = fz_dict_gets(obj, "PatternType");
1549
 
1550
		if (fz_to_int(patterntype) == 1)
1551
		{
1552
			pdf_pattern *pat;
1553
			error = pdf_load_pattern(&pat, csi->xref, obj);
1554
			if (error)
1555
				return fz_rethrow(error, "cannot load pattern (%d 0 R)", fz_to_num(obj));
1556
			pdf_set_pattern(csi, what, pat, csi->top > 0 ? csi->stack : NULL);
1557
			pdf_drop_pattern(pat);
1558
		}
1559
		else if (fz_to_int(patterntype) == 2)
1560
		{
1561
			fz_shade *shd;
1562
			error = pdf_load_shading(&shd, csi->xref, obj);
1563
			if (error)
1564
				return fz_rethrow(error, "cannot load shading (%d 0 R)", fz_to_num(obj));
1565
			pdf_set_shade(csi, what, shd);
1566
			fz_drop_shade(shd);
1567
		}
1568
		else
1569
		{
1570
			return fz_throw("unknown pattern type: %d", fz_to_int(patterntype));
1571
		}
1572
		break;
1573
 
1574
	case PDF_MAT_SHADE:
1575
		return fz_throw("cannot set color in shade objects");
1576
	}
1577
 
1578
	return fz_okay;
1579
}
1580
 
1581
static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb)
1582
{
1583
	fz_error error;
1584
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1585
	error = pdf_run_SC_imp(csi, rdb, PDF_STROKE, &gstate->stroke);
1586
	if (error)
1587
		fz_catch(error, "cannot set color and colorspace");
1588
}
1589
 
1590
static void pdf_run_sc(pdf_csi *csi, fz_obj *rdb)
1591
{
1592
	fz_error error;
1593
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1594
	error = pdf_run_SC_imp(csi, rdb, PDF_FILL, &gstate->fill);
1595
	if (error)
1596
		fz_catch(error, "cannot set color and colorspace");
1597
}
1598
 
1599
static void pdf_run_Tc(pdf_csi *csi)
1600
{
1601
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1602
	gstate->char_space = csi->stack[0];
1603
}
1604
 
1605
static void pdf_run_Tw(pdf_csi *csi)
1606
{
1607
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1608
	gstate->word_space = csi->stack[0];
1609
}
1610
 
1611
static void pdf_run_Tz(pdf_csi *csi)
1612
{
1613
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1614
	float a = csi->stack[0] / 100;
1615
	pdf_flush_text(csi);
1616
	gstate->scale = a;
1617
}
1618
 
1619
static void pdf_run_TL(pdf_csi *csi)
1620
{
1621
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1622
	gstate->leading = csi->stack[0];
1623
}
1624
 
1625
static fz_error pdf_run_Tf(pdf_csi *csi, fz_obj *rdb)
1626
{
1627
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1628
	fz_error error;
1629
	fz_obj *dict;
1630
	fz_obj *obj;
1631
 
1632
	gstate->size = csi->stack[0];
1633
	if (gstate->font)
1634
		pdf_drop_font(gstate->font);
1635
	gstate->font = NULL;
1636
 
1637
	dict = fz_dict_gets(rdb, "Font");
1638
	if (!dict)
1639
		return fz_throw("cannot find Font dictionary");
1640
 
1641
	obj = fz_dict_gets(dict, csi->name);
1642
	if (!obj)
1643
		return fz_throw("cannot find font resource: '%s'", csi->name);
1644
 
1645
	error = pdf_load_font(&gstate->font, csi->xref, rdb, obj);
1646
	if (error)
1647
		return fz_rethrow(error, "cannot load font (%d 0 R)", fz_to_num(obj));
1648
 
1649
	return fz_okay;
1650
}
1651
 
1652
static void pdf_run_Tr(pdf_csi *csi)
1653
{
1654
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1655
	gstate->render = csi->stack[0];
1656
}
1657
 
1658
static void pdf_run_Ts(pdf_csi *csi)
1659
{
1660
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1661
	gstate->rise = csi->stack[0];
1662
}
1663
 
1664
static void pdf_run_Td(pdf_csi *csi)
1665
{
1666
	fz_matrix m = fz_translate(csi->stack[0], csi->stack[1]);
1667
	csi->tlm = fz_concat(m, csi->tlm);
1668
	csi->tm = csi->tlm;
1669
}
1670
 
1671
static void pdf_run_TD(pdf_csi *csi)
1672
{
1673
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1674
	fz_matrix m;
1675
 
1676
	gstate->leading = -csi->stack[1];
1677
	m = fz_translate(csi->stack[0], csi->stack[1]);
1678
	csi->tlm = fz_concat(m, csi->tlm);
1679
	csi->tm = csi->tlm;
1680
}
1681
 
1682
static void pdf_run_Tm(pdf_csi *csi)
1683
{
1684
	csi->tm.a = csi->stack[0];
1685
	csi->tm.b = csi->stack[1];
1686
	csi->tm.c = csi->stack[2];
1687
	csi->tm.d = csi->stack[3];
1688
	csi->tm.e = csi->stack[4];
1689
	csi->tm.f = csi->stack[5];
1690
	csi->tlm = csi->tm;
1691
}
1692
 
1693
static void pdf_run_Tstar(pdf_csi *csi)
1694
{
1695
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1696
	fz_matrix m = fz_translate(0, -gstate->leading);
1697
	csi->tlm = fz_concat(m, csi->tlm);
1698
	csi->tm = csi->tlm;
1699
}
1700
 
1701
static void pdf_run_Tj(pdf_csi *csi)
1702
{
1703
	if (csi->string_len)
1704
		pdf_show_string(csi, csi->string, csi->string_len);
1705
	else
1706
		pdf_show_text(csi, csi->obj);
1707
}
1708
 
1709
static void pdf_run_TJ(pdf_csi *csi)
1710
{
1711
	if (csi->string_len)
1712
		pdf_show_string(csi, csi->string, csi->string_len);
1713
	else
1714
		pdf_show_text(csi, csi->obj);
1715
}
1716
 
1717
static void pdf_run_W(pdf_csi *csi)
1718
{
1719
	pdf_show_clip(csi, 0);
1720
}
1721
 
1722
static void pdf_run_Wstar(pdf_csi *csi)
1723
{
1724
	pdf_show_clip(csi, 1);
1725
}
1726
 
1727
static void pdf_run_b(pdf_csi *csi)
1728
{
1729
	pdf_show_path(csi, 1, 1, 1, 0);
1730
}
1731
 
1732
static void pdf_run_bstar(pdf_csi *csi)
1733
{
1734
	pdf_show_path(csi, 1, 1, 1, 1);
1735
}
1736
 
1737
static void pdf_run_c(pdf_csi *csi)
1738
{
1739
	float a, b, c, d, e, f;
1740
	a = csi->stack[0];
1741
	b = csi->stack[1];
1742
	c = csi->stack[2];
1743
	d = csi->stack[3];
1744
	e = csi->stack[4];
1745
	f = csi->stack[5];
1746
	fz_curveto(csi->path, a, b, c, d, e, f);
1747
}
1748
 
1749
static void pdf_run_cm(pdf_csi *csi)
1750
{
1751
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1752
	fz_matrix m;
1753
 
1754
	m.a = csi->stack[0];
1755
	m.b = csi->stack[1];
1756
	m.c = csi->stack[2];
1757
	m.d = csi->stack[3];
1758
	m.e = csi->stack[4];
1759
	m.f = csi->stack[5];
1760
 
1761
	gstate->ctm = fz_concat(m, gstate->ctm);
1762
}
1763
 
1764
static void pdf_run_d(pdf_csi *csi)
1765
{
1766
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1767
	fz_obj *array;
1768
	int i;
1769
 
1770
	array = csi->obj;
1771
	gstate->stroke_state.dash_len = MIN(fz_array_len(array), nelem(gstate->stroke_state.dash_list));
1772
	for (i = 0; i < gstate->stroke_state.dash_len; i++)
1773
		gstate->stroke_state.dash_list[i] = fz_to_real(fz_array_get(array, i));
1774
	gstate->stroke_state.dash_phase = csi->stack[0];
1775
}
1776
 
1777
static void pdf_run_d0(pdf_csi *csi)
1778
{
1779
	csi->dev->flags |= FZ_CHARPROC_COLOR;
1780
}
1781
 
1782
static void pdf_run_d1(pdf_csi *csi)
1783
{
1784
	csi->dev->flags |= FZ_CHARPROC_MASK;
1785
}
1786
 
1787
static void pdf_run_f(pdf_csi *csi)
1788
{
1789
	pdf_show_path(csi, 0, 1, 0, 0);
1790
}
1791
 
1792
static void pdf_run_fstar(pdf_csi *csi)
1793
{
1794
	pdf_show_path(csi, 0, 1, 0, 1);
1795
}
1796
 
1797
static void pdf_run_g(pdf_csi *csi)
1798
{
1799
	pdf_set_colorspace(csi, PDF_FILL, fz_device_gray);
1800
	pdf_set_color(csi, PDF_FILL, csi->stack);
1801
}
1802
 
1803
static fz_error pdf_run_gs(pdf_csi *csi, fz_obj *rdb)
1804
{
1805
	fz_error error;
1806
	fz_obj *dict;
1807
	fz_obj *obj;
1808
 
1809
	dict = fz_dict_gets(rdb, "ExtGState");
1810
	if (!dict)
1811
		return fz_throw("cannot find ExtGState dictionary");
1812
 
1813
	obj = fz_dict_gets(dict, csi->name);
1814
	if (!obj)
1815
		return fz_throw("cannot find extgstate resource '%s'", csi->name);
1816
 
1817
	error = pdf_run_extgstate(csi, rdb, obj);
1818
	if (error)
1819
		return fz_rethrow(error, "cannot set ExtGState (%d 0 R)", fz_to_num(obj));
1820
	return fz_okay;
1821
}
1822
 
1823
static void pdf_run_h(pdf_csi *csi)
1824
{
1825
	fz_closepath(csi->path);
1826
}
1827
 
1828
static void pdf_run_i(pdf_csi *csi)
1829
{
1830
}
1831
 
1832
static void pdf_run_j(pdf_csi *csi)
1833
{
1834
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1835
	gstate->stroke_state.linejoin = csi->stack[0];
1836
}
1837
 
1838
static void pdf_run_k(pdf_csi *csi)
1839
{
1840
	pdf_set_colorspace(csi, PDF_FILL, fz_device_cmyk);
1841
	pdf_set_color(csi, PDF_FILL, csi->stack);
1842
}
1843
 
1844
static void pdf_run_l(pdf_csi *csi)
1845
{
1846
	float a, b;
1847
	a = csi->stack[0];
1848
	b = csi->stack[1];
1849
	fz_lineto(csi->path, a, b);
1850
}
1851
 
1852
static void pdf_run_m(pdf_csi *csi)
1853
{
1854
	float a, b;
1855
	a = csi->stack[0];
1856
	b = csi->stack[1];
1857
	fz_moveto(csi->path, a, b);
1858
}
1859
 
1860
static void pdf_run_n(pdf_csi *csi)
1861
{
1862
	pdf_show_path(csi, 0, 0, 0, 0);
1863
}
1864
 
1865
static void pdf_run_q(pdf_csi *csi)
1866
{
1867
	pdf_gsave(csi);
1868
}
1869
 
1870
static void pdf_run_re(pdf_csi *csi)
1871
{
1872
	float x, y, w, h;
1873
 
1874
	x = csi->stack[0];
1875
	y = csi->stack[1];
1876
	w = csi->stack[2];
1877
	h = csi->stack[3];
1878
 
1879
	fz_moveto(csi->path, x, y);
1880
	fz_lineto(csi->path, x + w, y);
1881
	fz_lineto(csi->path, x + w, y + h);
1882
	fz_lineto(csi->path, x, y + h);
1883
	fz_closepath(csi->path);
1884
}
1885
 
1886
static void pdf_run_rg(pdf_csi *csi)
1887
{
1888
	pdf_set_colorspace(csi, PDF_FILL, fz_device_rgb);
1889
	pdf_set_color(csi, PDF_FILL, csi->stack);
1890
}
1891
 
1892
static void pdf_run_ri(pdf_csi *csi)
1893
{
1894
}
1895
 
1896
static void pdf_run(pdf_csi *csi)
1897
{
1898
	pdf_show_path(csi, 1, 0, 1, 0);
1899
}
1900
 
1901
static fz_error pdf_run_sh(pdf_csi *csi, fz_obj *rdb)
1902
{
1903
	fz_obj *dict;
1904
	fz_obj *obj;
1905
	fz_shade *shd;
1906
	fz_error error;
1907
 
1908
	dict = fz_dict_gets(rdb, "Shading");
1909
	if (!dict)
1910
		return fz_throw("cannot find shading dictionary");
1911
 
1912
	obj = fz_dict_gets(dict, csi->name);
1913
	if (!obj)
1914
		return fz_throw("cannot find shading resource: '%s'", csi->name);
1915
 
1916
	if ((csi->dev->hints & FZ_IGNORE_SHADE) == 0)
1917
	{
1918
		error = pdf_load_shading(&shd, csi->xref, obj);
1919
		if (error)
1920
			return fz_rethrow(error, "cannot load shading (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
1921
		pdf_show_shade(csi, shd);
1922
		fz_drop_shade(shd);
1923
	}
1924
	return fz_okay;
1925
}
1926
 
1927
static void pdf_run_v(pdf_csi *csi)
1928
{
1929
	float a, b, c, d;
1930
	a = csi->stack[0];
1931
	b = csi->stack[1];
1932
	c = csi->stack[2];
1933
	d = csi->stack[3];
1934
	fz_curvetov(csi->path, a, b, c, d);
1935
}
1936
 
1937
static void pdf_run_w(pdf_csi *csi)
1938
{
1939
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1940
	pdf_flush_text(csi); /* linewidth affects stroked text rendering mode */
1941
	gstate->stroke_state.linewidth = csi->stack[0];
1942
}
1943
 
1944
static void pdf_run_y(pdf_csi *csi)
1945
{
1946
	float a, b, c, d;
1947
	a = csi->stack[0];
1948
	b = csi->stack[1];
1949
	c = csi->stack[2];
1950
	d = csi->stack[3];
1951
	fz_curvetoy(csi->path, a, b, c, d);
1952
}
1953
 
1954
static void pdf_run_squote(pdf_csi *csi)
1955
{
1956
	fz_matrix m;
1957
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1958
 
1959
	m = fz_translate(0, -gstate->leading);
1960
	csi->tlm = fz_concat(m, csi->tlm);
1961
	csi->tm = csi->tlm;
1962
 
1963
	if (csi->string_len)
1964
		pdf_show_string(csi, csi->string, csi->string_len);
1965
	else
1966
		pdf_show_text(csi, csi->obj);
1967
}
1968
 
1969
static void pdf_run_dquote(pdf_csi *csi)
1970
{
1971
	fz_matrix m;
1972
	pdf_gstate *gstate = csi->gstate + csi->gtop;
1973
 
1974
	gstate->word_space = csi->stack[0];
1975
	gstate->char_space = csi->stack[1];
1976
 
1977
	m = fz_translate(0, -gstate->leading);
1978
	csi->tlm = fz_concat(m, csi->tlm);
1979
	csi->tm = csi->tlm;
1980
 
1981
	if (csi->string_len)
1982
		pdf_show_string(csi, csi->string, csi->string_len);
1983
	else
1984
		pdf_show_text(csi, csi->obj);
1985
}
1986
 
1987
#define A(a) (a)
1988
#define B(a,b) (a | b << 8)
1989
#define C(a,b,c) (a | b << 8 | c << 16)
1990
 
1991
static fz_error
1992
pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf)
1993
{
1994
	fz_error error;
1995
	int key;
1996
 
1997
	key = buf[0];
1998
	if (buf[1])
1999
	{
2000
		key |= buf[1] << 8;
2001
		if (buf[2])
2002
		{
2003
			key |= buf[2] << 16;
2004
			if (buf[3])
2005
				key = 0;
2006
		}
2007
	}
2008
 
2009
	switch (key)
2010
	{
2011
	case A('"'): pdf_run_dquote(csi); break;
2012
	case A('\''): pdf_run_squote(csi); break;
2013
	case A('B'): pdf_run_B(csi); break;
2014
	case B('B','*'): pdf_run_Bstar(csi); break;
2015
	case C('B','D','C'): pdf_run_BDC(csi); break;
2016
	case B('B','I'):
2017
		error = pdf_run_BI(csi, rdb, file);
2018
		if (error)
2019
			return fz_rethrow(error, "cannot draw inline image");
2020
		break;
2021
	case C('B','M','C'): pdf_run_BMC(csi); break;
2022
	case B('B','T'): pdf_run_BT(csi); break;
2023
	case B('B','X'): pdf_run_BX(csi); break;
2024
	case B('C','S'): pdf_run_CS(csi, rdb); break;
2025
	case B('D','P'): pdf_run_DP(csi); break;
2026
	case B('D','o'):
2027
		error = pdf_run_Do(csi, rdb);
2028
		if (error)
2029
			fz_catch(error, "cannot draw xobject/image");
2030
		break;
2031
	case C('E','M','C'): pdf_run_EMC(csi); break;
2032
	case B('E','T'): pdf_run_ET(csi); break;
2033
	case B('E','X'): pdf_run_EX(csi); break;
2034
	case A('F'): pdf_run_F(csi); break;
2035
	case A('G'): pdf_run_G(csi); break;
2036
	case A('J'): pdf_run_J(csi); break;
2037
	case A('K'): pdf_run_K(csi); break;
2038
	case A('M'): pdf_run_M(csi); break;
2039
	case B('M','P'): pdf_run_MP(csi); break;
2040
	case A('Q'): pdf_run_Q(csi); break;
2041
	case B('R','G'): pdf_run_RG(csi); break;
2042
	case A('S'): pdf_run_S(csi); break;
2043
	case B('S','C'): pdf_run_SC(csi, rdb); break;
2044
	case C('S','C','N'): pdf_run_SC(csi, rdb); break;
2045
	case B('T','*'): pdf_run_Tstar(csi); break;
2046
	case B('T','D'): pdf_run_TD(csi); break;
2047
	case B('T','J'): pdf_run_TJ(csi); break;
2048
	case B('T','L'): pdf_run_TL(csi); break;
2049
	case B('T','c'): pdf_run_Tc(csi); break;
2050
	case B('T','d'): pdf_run_Td(csi); break;
2051
	case B('T','f'):
2052
		error = pdf_run_Tf(csi, rdb);
2053
		if (error)
2054
			fz_catch(error, "cannot set font");
2055
		break;
2056
	case B('T','j'): pdf_run_Tj(csi); break;
2057
	case B('T','m'): pdf_run_Tm(csi); break;
2058
	case B('T','r'): pdf_run_Tr(csi); break;
2059
	case B('T','s'): pdf_run_Ts(csi); break;
2060
	case B('T','w'): pdf_run_Tw(csi); break;
2061
	case B('T','z'): pdf_run_Tz(csi); break;
2062
	case A('W'): pdf_run_W(csi); break;
2063
	case B('W','*'): pdf_run_Wstar(csi); break;
2064
	case A('b'): pdf_run_b(csi); break;
2065
	case B('b','*'): pdf_run_bstar(csi); break;
2066
	case A('c'): pdf_run_c(csi); break;
2067
	case B('c','m'): pdf_run_cm(csi); break;
2068
	case B('c','s'): pdf_run_cs(csi, rdb); break;
2069
	case A('d'): pdf_run_d(csi); break;
2070
	case B('d','0'): pdf_run_d0(csi); break;
2071
	case B('d','1'): pdf_run_d1(csi); break;
2072
	case A('f'): pdf_run_f(csi); break;
2073
	case B('f','*'): pdf_run_fstar(csi); break;
2074
	case A('g'): pdf_run_g(csi); break;
2075
	case B('g','s'):
2076
		error = pdf_run_gs(csi, rdb);
2077
		if (error)
2078
			fz_catch(error, "cannot set graphics state");
2079
		break;
2080
	case A('h'): pdf_run_h(csi); break;
2081
	case A('i'): pdf_run_i(csi); break;
2082
	case A('j'): pdf_run_j(csi); break;
2083
	case A('k'): pdf_run_k(csi); break;
2084
	case A('l'): pdf_run_l(csi); break;
2085
	case A('m'): pdf_run_m(csi); break;
2086
	case A('n'): pdf_run_n(csi); break;
2087
	case A('q'): pdf_run_q(csi); break;
2088
	case B('r','e'): pdf_run_re(csi); break;
2089
	case B('r','g'): pdf_run_rg(csi); break;
2090
	case B('r','i'): pdf_run_ri(csi); break;
2091
	case A('s'): pdf_run(csi); break;
2092
	case B('s','c'): pdf_run_sc(csi, rdb); break;
2093
	case C('s','c','n'): pdf_run_sc(csi, rdb); break;
2094
	case B('s','h'):
2095
		error = pdf_run_sh(csi, rdb);
2096
		if (error)
2097
			fz_catch(error, "cannot draw shading");
2098
		break;
2099
	case A('v'): pdf_run_v(csi); break;
2100
	case A('w'): pdf_run_w(csi); break;
2101
	case A('y'): pdf_run_y(csi); break;
2102
	default:
2103
		if (!csi->xbalance)
2104
			fz_warn("unknown keyword: '%s'", buf);
2105
		break;
2106
	}
2107
 
2108
	return fz_okay;
2109
}
2110
 
2111
static fz_error
2112
pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen)
2113
{
2114
	fz_error error;
2115
	int tok, len, in_array;
2116
 
2117
	/* make sure we have a clean slate if we come here from flush_text */
2118
	pdf_clear_stack(csi);
2119
	in_array = 0;
2120
 
2121
	while (1)
2122
	{
2123
		if (csi->top == nelem(csi->stack) - 1)
2124
			return fz_throw("stack overflow");
2125
 
2126
		error = pdf_lex(&tok, file, buf, buflen, &len);
2127
		if (error)
2128
			return fz_rethrow(error, "lexical error in content stream");
2129
 
2130
		if (in_array)
2131
		{
2132
			if (tok == PDF_TOK_CLOSE_ARRAY)
2133
			{
2134
				in_array = 0;
2135
			}
2136
			else if (tok == PDF_TOK_INT || tok == PDF_TOK_REAL)
2137
			{
2138
				pdf_gstate *gstate = csi->gstate + csi->gtop;
2139
				pdf_show_space(csi, -fz_atof(buf) * gstate->size * 0.001f);
2140
			}
2141
			else if (tok == PDF_TOK_STRING)
2142
			{
2143
				pdf_show_string(csi, (unsigned char *)buf, len);
2144
			}
2145
			else if (tok == PDF_TOK_KEYWORD)
2146
			{
2147
				if (!strcmp(buf, "Tw") || !strcmp(buf, "Tc"))
2148
					fz_warn("ignoring keyword '%s' inside array", buf);
2149
				else
2150
					return fz_throw("syntax error in array");
2151
			}
2152
			else if (tok == PDF_TOK_EOF)
2153
				return fz_okay;
2154
			else
2155
				return fz_throw("syntax error in array");
2156
		}
2157
 
2158
		else switch (tok)
2159
		{
2160
		case PDF_TOK_ENDSTREAM:
2161
		case PDF_TOK_EOF:
2162
			return fz_okay;
2163
 
2164
		case PDF_TOK_OPEN_ARRAY:
2165
			if (!csi->in_text)
2166
			{
2167
				error = pdf_parse_array(&csi->obj, csi->xref, file, buf, buflen);
2168
				if (error)
2169
					return fz_rethrow(error, "cannot parse array");
2170
			}
2171
			else
2172
			{
2173
				in_array = 1;
2174
			}
2175
			break;
2176
 
2177
		case PDF_TOK_OPEN_DICT:
2178
			error = pdf_parse_dict(&csi->obj, csi->xref, file, buf, buflen);
2179
			if (error)
2180
				return fz_rethrow(error, "cannot parse dictionary");
2181
			break;
2182
 
2183
		case PDF_TOK_NAME:
2184
			fz_strlcpy(csi->name, buf, sizeof(csi->name));
2185
			break;
2186
 
2187
		case PDF_TOK_INT:
2188
			csi->stack[csi->top] = atoi(buf);
2189
			csi->top ++;
2190
			break;
2191
 
2192
		case PDF_TOK_REAL:
2193
			csi->stack[csi->top] = fz_atof(buf);
2194
			csi->top ++;
2195
			break;
2196
 
2197
		case PDF_TOK_STRING:
2198
			if (len <= sizeof(csi->string))
2199
			{
2200
				memcpy(csi->string, buf, len);
2201
				csi->string_len = len;
2202
			}
2203
			else
2204
			{
2205
				csi->obj = fz_new_string(buf, len);
2206
			}
2207
			break;
2208
 
2209
		case PDF_TOK_KEYWORD:
2210
			error = pdf_run_keyword(csi, rdb, file, buf);
2211
			if (error)
2212
				return fz_rethrow(error, "cannot run keyword");
2213
			pdf_clear_stack(csi);
2214
			break;
2215
 
2216
		default:
2217
			return fz_throw("syntax error in content stream");
2218
		}
2219
	}
2220
}
2221
 
2222
/*
2223
 * Entry points
2224
 */
2225
 
2226
static fz_error
2227
pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents)
2228
{
2229
	fz_error error;
2230
	int len = sizeof csi->xref->scratch;
2231
	char *buf = fz_malloc(len); /* we must be re-entrant for type3 fonts */
2232
	fz_stream *file = fz_open_buffer(contents);
2233
	int save_in_text = csi->in_text;
2234
	csi->in_text = 0;
2235
	error = pdf_run_stream(csi, rdb, file, buf, len);
2236
	csi->in_text = save_in_text;
2237
	fz_close(file);
2238
	fz_free(buf);
2239
	if (error)
2240
		return fz_rethrow(error, "cannot parse content stream");
2241
	return fz_okay;
2242
}
2243
 
2244
fz_error
2245
pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target)
2246
{
2247
	pdf_csi *csi;
2248
	fz_error error;
2249
	pdf_annot *annot;
2250
	int flags;
2251
 
2252
	if (page->transparency)
2253
		fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 1, 0, 0, 1);
2254
 
2255
	csi = pdf_new_csi(xref, dev, ctm, target);
2256
	error = pdf_run_buffer(csi, page->resources, page->contents);
2257
	pdf_free_csi(csi);
2258
	if (error)
2259
		return fz_rethrow(error, "cannot parse page content stream");
2260
 
2261
	for (annot = page->annots; annot; annot = annot->next)
2262
	{
2263
		flags = fz_to_int(fz_dict_gets(annot->obj, "F"));
2264
 
2265
		/* TODO: NoZoom and NoRotate */
2266
		if (flags & (1 << 0)) /* Invisible */
2267
			continue;
2268
		if (flags & (1 << 1)) /* Hidden */
2269
			continue;
2270
		if (flags & (1 << 5)) /* NoView */
2271
			continue;
2272
 
2273
		if (pdf_is_hidden_ocg(annot->obj, target))
2274
			continue;
2275
 
2276
		csi = pdf_new_csi(xref, dev, ctm, target);
2277
		error = pdf_run_xobject(csi, page->resources, annot->ap, annot->matrix);
2278
		pdf_free_csi(csi);
2279
		if (error)
2280
			return fz_rethrow(error, "cannot parse annotation appearance stream");
2281
	}
2282
 
2283
	if (page->transparency)
2284
		fz_end_group(dev);
2285
 
2286
	return fz_okay;
2287
}
2288
 
2289
fz_error
2290
pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm)
2291
{
2292
	return pdf_run_page_with_usage(xref, page, dev, ctm, "View");
2293
}
2294
 
2295
fz_error
2296
pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm)
2297
{
2298
	pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View");
2299
	fz_error error = pdf_run_buffer(csi, resources, contents);
2300
	pdf_free_csi(csi);
2301
	if (error)
2302
		return fz_rethrow(error, "cannot parse glyph content stream");
2303
	return fz_okay;
2304
}