summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2011-04-10 03:11:57 +0200
committerTor Andersson <tor.andersson@artifex.com>2011-04-10 03:29:14 +0200
commit4dfa69f388b5eaccc5afe87d368f9b30a8f10475 (patch)
tree758b0596f5b5dd92dfb8abff4dc03cef15f96634
parente51c88f7e0f5e50274bd89fbd52152fd8936ef84 (diff)
downloadmupdf-4dfa69f388b5eaccc5afe87d368f9b30a8f10475.tar.xz
Combine build and interpret to make csi, gstate and material private structs.
-rw-r--r--pdf/mupdf.h116
-rw-r--r--pdf/pdf_build.c720
-rw-r--r--pdf/pdf_interpret.c944
-rw-r--r--win32/libmupdf.vcproj4
4 files changed, 888 insertions, 896 deletions
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index 2a47fd48..428bd7e9 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -480,124 +480,8 @@ void pdf_free_page(pdf_page *page);
* Content stream parsing
*/
-typedef struct pdf_material_s pdf_material;
-typedef struct pdf_gstate_s pdf_gstate;
-typedef struct pdf_csi_s pdf_csi;
-
-enum
-{
- PDF_FILL,
- PDF_STROKE,
-};
-
-enum
-{
- PDF_MAT_NONE,
- PDF_MAT_COLOR,
- PDF_MAT_PATTERN,
- PDF_MAT_SHADE,
-};
-
-struct pdf_material_s
-{
- int kind;
- fz_colorspace *colorspace;
- pdf_pattern *pattern;
- fz_shade *shade;
- float alpha;
- float v[32];
-};
-
-struct pdf_gstate_s
-{
- fz_matrix ctm;
- int clip_depth;
-
- /* path stroking */
- fz_stroke_state stroke_state;
-
- /* materials */
- pdf_material stroke;
- pdf_material fill;
-
- /* text state */
- float char_space;
- float word_space;
- float scale;
- float leading;
- pdf_font_desc *font;
- float size;
- int render;
- float rise;
-
- /* transparency */
- int blendmode;
- pdf_xobject *softmask;
- fz_matrix softmask_ctm;
- float softmask_bc[FZ_MAX_COLORS];
- int luminosity;
-};
-
-struct pdf_csi_s
-{
- fz_device *dev;
- pdf_xref *xref;
-
- /* usage mode for optional content groups */
- char *target; /* "View", "Print", "Export" */
-
- /* interpreter stack */
- fz_obj *obj;
- char name[256];
- unsigned char string[256];
- int string_len;
- float stack[32];
- int top;
-
- int xbalance;
- int in_text;
- int in_array;
-
- /* path object state */
- fz_path *path;
- int clip;
- int clip_even_odd;
-
- /* text object state */
- fz_text *text;
- fz_matrix tlm;
- fz_matrix tm;
- int text_mode;
- int accumulate;
-
- /* graphics state */
- fz_matrix top_ctm;
- pdf_gstate gstate[64];
- int gtop;
-};
-
-void pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm);
-void pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *cs);
-void pdf_set_color(pdf_csi *csi, int what, float *v);
-void pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v);
-void pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade);
-void pdf_show_path(pdf_csi*, int close, int fill, int stroke, int even_odd);
-void pdf_show_space(pdf_csi *csi, float tadj);
-void pdf_show_string(pdf_csi *csi, unsigned char *buf, int len);
-void pdf_show_text(pdf_csi*, fz_obj *text);
-void pdf_flush_text(pdf_csi*);
-void pdf_show_image(pdf_csi*, fz_pixmap *image);
-void pdf_show_shade(pdf_csi*, fz_shade *shade);
-
-void pdf_gsave(pdf_csi *csi);
-void pdf_grestore(pdf_csi *csi);
-fz_error pdf_run_csi_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents);
-fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform);
fz_error pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target);
fz_error pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm);
fz_error pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm);
-pdf_material *pdf_keep_material(pdf_material *mat);
-pdf_material *pdf_drop_material(pdf_material *mat);
-
#endif
diff --git a/pdf/pdf_build.c b/pdf/pdf_build.c
deleted file mode 100644
index e22b50c9..00000000
--- a/pdf/pdf_build.c
+++ /dev/null
@@ -1,720 +0,0 @@
-#include "fitz.h"
-#include "mupdf.h"
-
-#define TILE
-
-void
-pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
-{
- gs->ctm = ctm;
- gs->clip_depth = 0;
-
- gs->stroke_state.linewidth = 1;
- gs->stroke_state.linecap = 0;
- gs->stroke_state.linejoin = 0;
- gs->stroke_state.miterlimit = 10;
- gs->stroke_state.dash_phase = 0;
- gs->stroke_state.dash_len = 0;
- memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list));
-
- gs->stroke.kind = PDF_MAT_COLOR;
- gs->stroke.colorspace = fz_keep_colorspace(fz_device_gray);
- gs->stroke.v[0] = 0;
- gs->stroke.pattern = NULL;
- gs->stroke.shade = NULL;
- gs->stroke.alpha = 1;
-
- gs->fill.kind = PDF_MAT_COLOR;
- gs->fill.colorspace = fz_keep_colorspace(fz_device_gray);
- gs->fill.v[0] = 0;
- gs->fill.pattern = NULL;
- gs->fill.shade = NULL;
- gs->fill.alpha = 1;
-
- gs->char_space = 0;
- gs->word_space = 0;
- gs->scale = 1;
- gs->leading = 0;
- gs->font = NULL;
- gs->size = -1;
- gs->render = 0;
- gs->rise = 0;
-
- gs->blendmode = 0;
- gs->softmask = NULL;
- gs->softmask_ctm = fz_identity;
- gs->luminosity = 0;
-}
-
-void
-pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *colorspace)
-{
- pdf_gstate *gs = csi->gstate + csi->gtop;
- pdf_material *mat;
-
- pdf_flush_text(csi);
-
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
-
- fz_drop_colorspace(mat->colorspace);
-
- mat->kind = PDF_MAT_COLOR;
- mat->colorspace = fz_keep_colorspace(colorspace);
-
- mat->v[0] = 0;
- mat->v[1] = 0;
- mat->v[2] = 0;
- mat->v[3] = 1;
-}
-
-void
-pdf_set_color(pdf_csi *csi, int what, float *v)
-{
- pdf_gstate *gs = csi->gstate + csi->gtop;
- pdf_material *mat;
- int i;
-
- pdf_flush_text(csi);
-
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
-
- switch (mat->kind)
- {
- case PDF_MAT_PATTERN:
- case PDF_MAT_COLOR:
- if (!strcmp(mat->colorspace->name, "Lab"))
- {
- mat->v[0] = v[0] / 100;
- mat->v[1] = (v[1] + 100) / 200;
- mat->v[2] = (v[2] + 100) / 200;
- }
- for (i = 0; i < mat->colorspace->n; i++)
- mat->v[i] = v[i];
- break;
- default:
- fz_warn("color incompatible with material");
- }
-}
-
-static void
-pdf_unset_pattern(pdf_csi *csi, int what)
-{
- pdf_gstate *gs = csi->gstate + csi->gtop;
- pdf_material *mat;
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
- if (mat->kind == PDF_MAT_PATTERN)
- {
- if (mat->pattern)
- pdf_drop_pattern(mat->pattern);
- mat->pattern = NULL;
- mat->kind = PDF_MAT_COLOR;
- }
-}
-
-void
-pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v)
-{
- pdf_gstate *gs = csi->gstate + csi->gtop;
- pdf_material *mat;
-
- pdf_flush_text(csi);
-
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
-
- if (mat->pattern)
- pdf_drop_pattern(mat->pattern);
-
- mat->kind = PDF_MAT_PATTERN;
- if (pat)
- mat->pattern = pdf_keep_pattern(pat);
- else
- mat->pattern = NULL;
-
- if (v)
- pdf_set_color(csi, what, v);
-}
-
-void
-pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade)
-{
- pdf_gstate *gs = csi->gstate + csi->gtop;
- pdf_material *mat;
-
- pdf_flush_text(csi);
-
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
-
- if (mat->shade)
- fz_drop_shade(mat->shade);
-
- mat->kind = PDF_MAT_SHADE;
- mat->shade = fz_keep_shade(shade);
-}
-
-static void
-pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what)
-{
- pdf_gstate *gstate;
- fz_matrix ptm, invptm;
- fz_matrix oldtopctm;
- fz_error error;
- int x0, y0, x1, y1;
- int oldtop;
-
- pdf_gsave(csi);
- gstate = csi->gstate + csi->gtop;
-
- if (pat->ismask)
- {
- pdf_unset_pattern(csi, PDF_FILL);
- pdf_unset_pattern(csi, PDF_STROKE);
- if (what == PDF_FILL)
- {
- pdf_drop_material(&gstate->stroke);
- pdf_keep_material(&gstate->fill);
- gstate->stroke = gstate->fill;
- }
- if (what == PDF_STROKE)
- {
- pdf_drop_material(&gstate->fill);
- pdf_keep_material(&gstate->stroke);
- gstate->fill = gstate->stroke;
- }
- }
- else
- {
- // TODO: unset only the current fill/stroke or both?
- pdf_unset_pattern(csi, what);
- }
-
- /* don't apply softmasks to objects in the pattern as well */
- if (gstate->softmask)
- {
- pdf_drop_xobject(gstate->softmask);
- gstate->softmask = NULL;
- }
-
- ptm = fz_concat(pat->matrix, csi->top_ctm);
- invptm = fz_invert_matrix(ptm);
-
- /* patterns are painted using the ctm in effect at the beginning of the content stream */
- /* get bbox of shape in pattern space for stamping */
- area = fz_transform_rect(invptm, area);
- x0 = floorf(area.x0 / pat->xstep);
- y0 = floorf(area.y0 / pat->ystep);
- x1 = ceilf(area.x1 / pat->xstep);
- y1 = ceilf(area.y1 / pat->ystep);
-
- oldtopctm = csi->top_ctm;
- oldtop = csi->gtop;
-
-#ifdef TILE
- if ((x1 - x0) * (y1 - y0) > 0)
- {
- fz_begin_tile(csi->dev, area, pat->bbox, pat->xstep, pat->ystep, ptm);
- gstate->ctm = ptm;
- csi->top_ctm = gstate->ctm;
- pdf_gsave(csi);
- error = pdf_run_csi_buffer(csi, pat->resources, pat->contents);
- if (error)
- fz_catch(error, "cannot render pattern tile");
- pdf_grestore(csi);
- while (oldtop < csi->gtop)
- pdf_grestore(csi);
- fz_end_tile(csi->dev);
- }
-#else
- {
- int x, y;
- for (y = y0; y < y1; y++)
- {
- for (x = x0; x < x1; x++)
- {
- gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm);
- csi->top_ctm = gstate->ctm;
- error = pdf_run_csi_buffer(csi, pat->resources, pat->contents);
- while (oldtop < csi->gtop)
- pdf_grestore(csi);
- if (error)
- {
- fz_catch(error, "cannot render pattern tile");
- goto cleanup;
- }
- }
- }
- }
-cleanup:
-#endif
-
- csi->top_ctm = oldtopctm;
-
- pdf_grestore(csi);
-}
-
-static void
-pdf_begin_group(pdf_csi *csi, fz_rect bbox)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_error error;
-
- if (gstate->softmask)
- {
- pdf_xobject *softmask = gstate->softmask;
- fz_rect bbox = fz_transform_rect(gstate->ctm, softmask->bbox);
-
- gstate->softmask = NULL;
-
- fz_begin_mask(csi->dev, bbox, gstate->luminosity,
- softmask->colorspace, gstate->softmask_bc);
- error = pdf_run_xobject(csi, NULL, softmask, fz_identity);
- if (error)
- fz_catch(error, "cannot run softmask");
- fz_end_mask(csi->dev);
-
- gstate->softmask = softmask;
- }
-
- if (gstate->blendmode)
- fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
-}
-
-static void
-pdf_end_group(pdf_csi *csi)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
-
- if (gstate->blendmode)
- fz_end_group(csi->dev);
-
- if (gstate->softmask)
- fz_pop_clip(csi->dev);
-}
-
-void
-pdf_show_shade(pdf_csi *csi, fz_shade *shd)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_rect bbox;
-
- bbox = fz_bound_shade(shd, gstate->ctm);
-
- pdf_begin_group(csi, bbox);
-
- fz_fill_shade(csi->dev, shd, gstate->ctm, gstate->fill.alpha);
-
- pdf_end_group(csi);
-}
-
-void
-pdf_show_image(pdf_csi *csi, fz_pixmap *image)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_rect bbox;
-
- bbox = fz_transform_rect(gstate->ctm, fz_unit_rect);
-
- if (image->mask)
- {
- /* apply blend group even though we skip the softmask */
- if (gstate->blendmode)
- fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
- fz_clip_image_mask(csi->dev, image->mask, gstate->ctm);
- }
- else
- pdf_begin_group(csi, bbox);
-
- if (!image->colorspace)
- {
-
- switch (gstate->fill.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_fill_image_mask(csi->dev, image, gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->fill.pattern)
- {
- fz_clip_image_mask(csi->dev, image, gstate->ctm);
- pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
- fz_pop_clip(csi->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->fill.shade)
- {
- fz_clip_image_mask(csi->dev, image, gstate->ctm);
- fz_fill_shade(csi->dev, gstate->fill.shade, gstate->ctm, gstate->fill.alpha);
- fz_pop_clip(csi->dev);
- }
- break;
- }
- }
- else
- {
- fz_fill_image(csi->dev, image, gstate->ctm, gstate->fill.alpha);
- }
-
- if (image->mask)
- {
- fz_pop_clip(csi->dev);
- if (gstate->blendmode)
- fz_end_group(csi->dev);
- }
- else
- pdf_end_group(csi);
-}
-
-void
-pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_path *path;
- fz_rect bbox;
-
- path = csi->path;
- csi->path = fz_new_path();
-
- if (doclose)
- fz_closepath(path);
-
- if (dostroke)
- bbox = fz_bound_path(path, &gstate->stroke_state, gstate->ctm);
- else
- bbox = fz_bound_path(path, NULL, gstate->ctm);
-
- if (csi->clip)
- {
- gstate->clip_depth++;
- fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
- csi->clip = 0;
- }
-
- pdf_begin_group(csi, bbox);
-
- if (dofill)
- {
- switch (gstate->fill.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_fill_path(csi->dev, path, even_odd, gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->fill.pattern)
- {
- fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
- pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
- fz_pop_clip(csi->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->fill.shade)
- {
- fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
- fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
- fz_pop_clip(csi->dev);
- }
- break;
- }
- }
-
- if (dostroke)
- {
- switch (gstate->stroke.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->stroke.pattern)
- {
- fz_clip_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm);
- pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
- fz_pop_clip(csi->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->stroke.shade)
- {
- fz_clip_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm);
- fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
- fz_pop_clip(csi->dev);
- }
- break;
- }
- }
-
- pdf_end_group(csi);
-
- fz_free_path(path);
-}
-
-void
-pdf_flush_text(pdf_csi *csi)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- fz_text *text;
- int dofill = 0;
- int dostroke = 0;
- int doclip = 0;
- int doinvisible = 0;
- fz_rect bbox;
-
- if (!csi->text)
- return;
- text = csi->text;
- csi->text = NULL;
-
- dofill = dostroke = doclip = doinvisible = 0;
- switch (csi->text_mode)
- {
- case 0: dofill = 1; break;
- case 1: dostroke = 1; break;
- case 2: dofill = dostroke = 1; break;
- case 3: doinvisible = 1; break;
- case 4: dofill = doclip = 1; break;
- case 5: dostroke = doclip = 1; break;
- case 6: dofill = dostroke = doclip = 1; break;
- case 7: doclip = 1; break;
- }
-
- bbox = fz_bound_text(text, gstate->ctm);
-
- pdf_begin_group(csi, bbox);
-
- if (doinvisible)
- fz_ignore_text(csi->dev, text, gstate->ctm);
-
- if (doclip)
- {
- if (csi->accumulate < 2)
- gstate->clip_depth++;
- fz_clip_text(csi->dev, text, gstate->ctm, csi->accumulate);
- csi->accumulate = 2;
- }
-
- if (dofill)
- {
- switch (gstate->fill.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_fill_text(csi->dev, text, gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->fill.pattern)
- {
- fz_clip_text(csi->dev, text, gstate->ctm, 0);
- pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
- fz_pop_clip(csi->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->fill.shade)
- {
- fz_clip_text(csi->dev, text, gstate->ctm, 0);
- fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
- fz_pop_clip(csi->dev);
- }
- break;
- }
- }
-
- if (dostroke)
- {
- switch (gstate->stroke.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->stroke.pattern)
- {
- fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
- pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
- fz_pop_clip(csi->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->stroke.shade)
- {
- fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
- fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
- fz_pop_clip(csi->dev);
- }
- break;
- }
- }
-
- pdf_end_group(csi);
-
- fz_free_text(text);
-}
-
-static void
-pdf_show_glyph(pdf_csi *csi, int cid)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- pdf_font_desc *fontdesc = gstate->font;
- fz_matrix tsm, trm;
- float w0, w1, tx, ty;
- pdf_hmtx h;
- pdf_vmtx v;
- int gid;
- int ucsbuf[8];
- int ucslen;
- int i;
-
- tsm.a = gstate->size * gstate->scale;
- tsm.b = 0;
- tsm.c = 0;
- tsm.d = gstate->size;
- tsm.e = 0;
- tsm.f = gstate->rise;
-
- ucslen = 0;
- if (fontdesc->to_unicode)
- ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
- if (ucslen == 0 && cid < fontdesc->cid_to_ucs_len)
- {
- ucsbuf[0] = fontdesc->cid_to_ucs[cid];
- ucslen = 1;
- }
- if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
- {
- ucsbuf[0] = '?';
- ucslen = 1;
- }
-
- gid = pdf_font_cid_to_gid(fontdesc, cid);
-
- if (fontdesc->wmode == 1)
- {
- v = pdf_get_vmtx(fontdesc, cid);
- tsm.e -= v.x * gstate->size * 0.001f;
- tsm.f -= v.y * gstate->size * 0.001f;
- }
-
- trm = fz_concat(tsm, csi->tm);
-
- /* flush buffered text if face or matrix or rendermode has changed */
- if (!csi->text ||
- fontdesc->font != csi->text->font ||
- fontdesc->wmode != csi->text->wmode ||
- fabsf(trm.a - csi->text->trm.a) > FLT_EPSILON ||
- fabsf(trm.b - csi->text->trm.b) > FLT_EPSILON ||
- fabsf(trm.c - csi->text->trm.c) > FLT_EPSILON ||
- fabsf(trm.d - csi->text->trm.d) > FLT_EPSILON ||
- gstate->render != csi->text_mode)
- {
- pdf_flush_text(csi);
-
- csi->text = fz_new_text(fontdesc->font, trm, fontdesc->wmode);
- csi->text->trm.e = 0;
- csi->text->trm.f = 0;
- csi->text_mode = gstate->render;
- }
-
- /* add glyph to textobject */
- fz_add_text(csi->text, gid, ucsbuf[0], trm.e, trm.f);
-
- /* add filler glyphs for one-to-many unicode mapping */
- for (i = 1; i < ucslen; i++)
- fz_add_text(csi->text, -1, ucsbuf[i], trm.e, trm.f);
-
- if (fontdesc->wmode == 0)
- {
- h = pdf_get_hmtx(fontdesc, cid);
- w0 = h.w * 0.001f;
- tx = (w0 * gstate->size + gstate->char_space) * gstate->scale;
- csi->tm = fz_concat(fz_translate(tx, 0), csi->tm);
- }
-
- if (fontdesc->wmode == 1)
- {
- w1 = v.w * 0.001f;
- ty = w1 * gstate->size + gstate->char_space;
- csi->tm = fz_concat(fz_translate(0, ty), csi->tm);
- }
-}
-
-void
-pdf_show_space(pdf_csi *csi, float tadj)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- pdf_font_desc *fontdesc = gstate->font;
-
- if (!fontdesc)
- {
- fz_warn("cannot draw text since font and size not set");
- return;
- }
-
- if (fontdesc->wmode == 0)
- csi->tm = fz_concat(fz_translate(tadj * gstate->scale, 0), csi->tm);
- else
- csi->tm = fz_concat(fz_translate(0, tadj), csi->tm);
-}
-
-void
-pdf_show_string(pdf_csi *csi, unsigned char *buf, int len)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- pdf_font_desc *fontdesc = gstate->font;
- unsigned char *end = buf + len;
- int cpt, cid;
-
- if (!fontdesc)
- {
- fz_warn("cannot draw text since font and size not set");
- return;
- }
-
- while (buf < end)
- {
- buf = pdf_decode_cmap(fontdesc->encoding, buf, &cpt);
- cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
- if (cid >= 0)
- pdf_show_glyph(csi, cid);
- else
- fz_warn("cannot encode character with code point %#x", cpt);
- if (cpt == 32)
- pdf_show_space(csi, gstate->word_space);
- }
-}
-
-void
-pdf_show_text(pdf_csi *csi, fz_obj *text)
-{
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- int i;
-
- if (fz_is_array(text))
- {
- for (i = 0; i < fz_array_len(text); i++)
- {
- fz_obj *item = fz_array_get(text, i);
- if (fz_is_string(item))
- pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item));
- else
- pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f);
- }
- }
- else if (fz_is_string(text))
- {
- pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text));
- }
-}
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index d2f0df1c..d25446d5 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -1,6 +1,651 @@
#include "fitz.h"
#include "mupdf.h"
+#define TILE
+
+typedef struct pdf_material_s pdf_material;
+typedef struct pdf_gstate_s pdf_gstate;
+typedef struct pdf_csi_s pdf_csi;
+
+enum
+{
+ PDF_FILL,
+ PDF_STROKE,
+};
+
+enum
+{
+ PDF_MAT_NONE,
+ PDF_MAT_COLOR,
+ PDF_MAT_PATTERN,
+ PDF_MAT_SHADE,
+};
+
+struct pdf_material_s
+{
+ int kind;
+ fz_colorspace *colorspace;
+ pdf_pattern *pattern;
+ fz_shade *shade;
+ float alpha;
+ float v[32];
+};
+
+struct pdf_gstate_s
+{
+ fz_matrix ctm;
+ int clip_depth;
+
+ /* path stroking */
+ fz_stroke_state stroke_state;
+
+ /* materials */
+ pdf_material stroke;
+ pdf_material fill;
+
+ /* text state */
+ float char_space;
+ float word_space;
+ float scale;
+ float leading;
+ pdf_font_desc *font;
+ float size;
+ int render;
+ float rise;
+
+ /* transparency */
+ int blendmode;
+ pdf_xobject *softmask;
+ fz_matrix softmask_ctm;
+ float softmask_bc[FZ_MAX_COLORS];
+ int luminosity;
+};
+
+struct pdf_csi_s
+{
+ fz_device *dev;
+ pdf_xref *xref;
+
+ /* usage mode for optional content groups */
+ char *target; /* "View", "Print", "Export" */
+
+ /* interpreter stack */
+ fz_obj *obj;
+ char name[256];
+ unsigned char string[256];
+ int string_len;
+ float stack[32];
+ int top;
+
+ int xbalance;
+ int in_text;
+ int in_array;
+
+ /* path object state */
+ fz_path *path;
+ int clip;
+ int clip_even_odd;
+
+ /* text object state */
+ fz_text *text;
+ fz_matrix tlm;
+ fz_matrix tm;
+ int text_mode;
+ int accumulate;
+
+ /* graphics state */
+ fz_matrix top_ctm;
+ pdf_gstate gstate[64];
+ int gtop;
+};
+
+static fz_error pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents);
+static fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform);
+static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what);
+
+
+static int
+pdf_is_hidden_ocg(fz_obj *xobj, char *target)
+{
+ char target_state[16];
+ fz_obj *obj;
+
+ fz_strlcpy(target_state, target, sizeof target_state);
+ fz_strlcat(target_state, "State", sizeof target_state);
+
+ obj = fz_dict_gets(xobj, "OC");
+ obj = fz_dict_gets(obj, "OCGs");
+ if (fz_is_array(obj))
+ obj = fz_array_get(obj, 0);
+ obj = fz_dict_gets(obj, "Usage");
+ obj = fz_dict_gets(obj, target);
+ obj = fz_dict_gets(obj, target_state);
+ return !strcmp(fz_to_name(obj), "OFF");
+}
+
+/*
+ * Emit graphics calls to device.
+ */
+
+static void
+pdf_begin_group(pdf_csi *csi, fz_rect bbox)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_error error;
+
+ if (gstate->softmask)
+ {
+ pdf_xobject *softmask = gstate->softmask;
+ fz_rect bbox = fz_transform_rect(gstate->ctm, softmask->bbox);
+
+ gstate->softmask = NULL;
+
+ fz_begin_mask(csi->dev, bbox, gstate->luminosity,
+ softmask->colorspace, gstate->softmask_bc);
+ error = pdf_run_xobject(csi, NULL, softmask, fz_identity);
+ if (error)
+ fz_catch(error, "cannot run softmask");
+ fz_end_mask(csi->dev);
+
+ gstate->softmask = softmask;
+ }
+
+ if (gstate->blendmode)
+ fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
+}
+
+static void
+pdf_end_group(pdf_csi *csi)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+
+ if (gstate->blendmode)
+ fz_end_group(csi->dev);
+
+ if (gstate->softmask)
+ fz_pop_clip(csi->dev);
+}
+
+static void
+pdf_show_shade(pdf_csi *csi, fz_shade *shd)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_rect bbox;
+
+ bbox = fz_bound_shade(shd, gstate->ctm);
+
+ pdf_begin_group(csi, bbox);
+
+ fz_fill_shade(csi->dev, shd, gstate->ctm, gstate->fill.alpha);
+
+ pdf_end_group(csi);
+}
+
+static void
+pdf_show_image(pdf_csi *csi, fz_pixmap *image)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_rect bbox;
+
+ bbox = fz_transform_rect(gstate->ctm, fz_unit_rect);
+
+ if (image->mask)
+ {
+ /* apply blend group even though we skip the softmask */
+ if (gstate->blendmode)
+ fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
+ fz_clip_image_mask(csi->dev, image->mask, gstate->ctm);
+ }
+ else
+ pdf_begin_group(csi, bbox);
+
+ if (!image->colorspace)
+ {
+
+ switch (gstate->fill.kind)
+ {
+ case PDF_MAT_NONE:
+ break;
+ case PDF_MAT_COLOR:
+ fz_fill_image_mask(csi->dev, image, gstate->ctm,
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ break;
+ case PDF_MAT_PATTERN:
+ if (gstate->fill.pattern)
+ {
+ fz_clip_image_mask(csi->dev, image, gstate->ctm);
+ pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ case PDF_MAT_SHADE:
+ if (gstate->fill.shade)
+ {
+ fz_clip_image_mask(csi->dev, image, gstate->ctm);
+ fz_fill_shade(csi->dev, gstate->fill.shade, gstate->ctm, gstate->fill.alpha);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ }
+ }
+ else
+ {
+ fz_fill_image(csi->dev, image, gstate->ctm, gstate->fill.alpha);
+ }
+
+ if (image->mask)
+ {
+ fz_pop_clip(csi->dev);
+ if (gstate->blendmode)
+ fz_end_group(csi->dev);
+ }
+ else
+ pdf_end_group(csi);
+}
+
+static void
+pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_path *path;
+ fz_rect bbox;
+
+ path = csi->path;
+ csi->path = fz_new_path();
+
+ if (doclose)
+ fz_closepath(path);
+
+ if (dostroke)
+ bbox = fz_bound_path(path, &gstate->stroke_state, gstate->ctm);
+ else
+ bbox = fz_bound_path(path, NULL, gstate->ctm);
+
+ if (csi->clip)
+ {
+ gstate->clip_depth++;
+ fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
+ csi->clip = 0;
+ }
+
+ pdf_begin_group(csi, bbox);
+
+ if (dofill)
+ {
+ switch (gstate->fill.kind)
+ {
+ case PDF_MAT_NONE:
+ break;
+ case PDF_MAT_COLOR:
+ fz_fill_path(csi->dev, path, even_odd, gstate->ctm,
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ break;
+ case PDF_MAT_PATTERN:
+ if (gstate->fill.pattern)
+ {
+ fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
+ pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ case PDF_MAT_SHADE:
+ if (gstate->fill.shade)
+ {
+ fz_clip_path(csi->dev, path, even_odd, gstate->ctm);
+ fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ }
+ }
+
+ if (dostroke)
+ {
+ switch (gstate->stroke.kind)
+ {
+ case PDF_MAT_NONE:
+ break;
+ case PDF_MAT_COLOR:
+ fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm,
+ gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
+ break;
+ case PDF_MAT_PATTERN:
+ if (gstate->stroke.pattern)
+ {
+ fz_clip_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm);
+ pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ case PDF_MAT_SHADE:
+ if (gstate->stroke.shade)
+ {
+ fz_clip_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm);
+ fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ }
+ }
+
+ pdf_end_group(csi);
+
+ fz_free_path(path);
+}
+
+/*
+ * Assemble and emit text
+ */
+
+static void
+pdf_flush_text(pdf_csi *csi)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ fz_text *text;
+ int dofill = 0;
+ int dostroke = 0;
+ int doclip = 0;
+ int doinvisible = 0;
+ fz_rect bbox;
+
+ if (!csi->text)
+ return;
+ text = csi->text;
+ csi->text = NULL;
+
+ dofill = dostroke = doclip = doinvisible = 0;
+ switch (csi->text_mode)
+ {
+ case 0: dofill = 1; break;
+ case 1: dostroke = 1; break;
+ case 2: dofill = dostroke = 1; break;
+ case 3: doinvisible = 1; break;
+ case 4: dofill = doclip = 1; break;
+ case 5: dostroke = doclip = 1; break;
+ case 6: dofill = dostroke = doclip = 1; break;
+ case 7: doclip = 1; break;
+ }
+
+ bbox = fz_bound_text(text, gstate->ctm);
+
+ pdf_begin_group(csi, bbox);
+
+ if (doinvisible)
+ fz_ignore_text(csi->dev, text, gstate->ctm);
+
+ if (doclip)
+ {
+ if (csi->accumulate < 2)
+ gstate->clip_depth++;
+ fz_clip_text(csi->dev, text, gstate->ctm, csi->accumulate);
+ csi->accumulate = 2;
+ }
+
+ if (dofill)
+ {
+ switch (gstate->fill.kind)
+ {
+ case PDF_MAT_NONE:
+ break;
+ case PDF_MAT_COLOR:
+ fz_fill_text(csi->dev, text, gstate->ctm,
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ break;
+ case PDF_MAT_PATTERN:
+ if (gstate->fill.pattern)
+ {
+ fz_clip_text(csi->dev, text, gstate->ctm, 0);
+ pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ case PDF_MAT_SHADE:
+ if (gstate->fill.shade)
+ {
+ fz_clip_text(csi->dev, text, gstate->ctm, 0);
+ fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ }
+ }
+
+ if (dostroke)
+ {
+ switch (gstate->stroke.kind)
+ {
+ case PDF_MAT_NONE:
+ break;
+ case PDF_MAT_COLOR:
+ fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm,
+ gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
+ break;
+ case PDF_MAT_PATTERN:
+ if (gstate->stroke.pattern)
+ {
+ fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
+ pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ case PDF_MAT_SHADE:
+ if (gstate->stroke.shade)
+ {
+ fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
+ fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
+ fz_pop_clip(csi->dev);
+ }
+ break;
+ }
+ }
+
+ pdf_end_group(csi);
+
+ fz_free_text(text);
+}
+
+static void
+pdf_show_glyph(pdf_csi *csi, int cid)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ pdf_font_desc *fontdesc = gstate->font;
+ fz_matrix tsm, trm;
+ float w0, w1, tx, ty;
+ pdf_hmtx h;
+ pdf_vmtx v;
+ int gid;
+ int ucsbuf[8];
+ int ucslen;
+ int i;
+
+ tsm.a = gstate->size * gstate->scale;
+ tsm.b = 0;
+ tsm.c = 0;
+ tsm.d = gstate->size;
+ tsm.e = 0;
+ tsm.f = gstate->rise;
+
+ ucslen = 0;
+ if (fontdesc->to_unicode)
+ ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
+ if (ucslen == 0 && cid < fontdesc->cid_to_ucs_len)
+ {
+ ucsbuf[0] = fontdesc->cid_to_ucs[cid];
+ ucslen = 1;
+ }
+ if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
+ {
+ ucsbuf[0] = '?';
+ ucslen = 1;
+ }
+
+ gid = pdf_font_cid_to_gid(fontdesc, cid);
+
+ if (fontdesc->wmode == 1)
+ {
+ v = pdf_get_vmtx(fontdesc, cid);
+ tsm.e -= v.x * gstate->size * 0.001f;
+ tsm.f -= v.y * gstate->size * 0.001f;
+ }
+
+ trm = fz_concat(tsm, csi->tm);
+
+ /* flush buffered text if face or matrix or rendermode has changed */
+ if (!csi->text ||
+ fontdesc->font != csi->text->font ||
+ fontdesc->wmode != csi->text->wmode ||
+ fabsf(trm.a - csi->text->trm.a) > FLT_EPSILON ||
+ fabsf(trm.b - csi->text->trm.b) > FLT_EPSILON ||
+ fabsf(trm.c - csi->text->trm.c) > FLT_EPSILON ||
+ fabsf(trm.d - csi->text->trm.d) > FLT_EPSILON ||
+ gstate->render != csi->text_mode)
+ {
+ pdf_flush_text(csi);
+
+ csi->text = fz_new_text(fontdesc->font, trm, fontdesc->wmode);
+ csi->text->trm.e = 0;
+ csi->text->trm.f = 0;
+ csi->text_mode = gstate->render;
+ }
+
+ /* add glyph to textobject */
+ fz_add_text(csi->text, gid, ucsbuf[0], trm.e, trm.f);
+
+ /* add filler glyphs for one-to-many unicode mapping */
+ for (i = 1; i < ucslen; i++)
+ fz_add_text(csi->text, -1, ucsbuf[i], trm.e, trm.f);
+
+ if (fontdesc->wmode == 0)
+ {
+ h = pdf_get_hmtx(fontdesc, cid);
+ w0 = h.w * 0.001f;
+ tx = (w0 * gstate->size + gstate->char_space) * gstate->scale;
+ csi->tm = fz_concat(fz_translate(tx, 0), csi->tm);
+ }
+
+ if (fontdesc->wmode == 1)
+ {
+ w1 = v.w * 0.001f;
+ ty = w1 * gstate->size + gstate->char_space;
+ csi->tm = fz_concat(fz_translate(0, ty), csi->tm);
+ }
+}
+
+static void
+pdf_show_space(pdf_csi *csi, float tadj)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ pdf_font_desc *fontdesc = gstate->font;
+
+ if (!fontdesc)
+ {
+ fz_warn("cannot draw text since font and size not set");
+ return;
+ }
+
+ if (fontdesc->wmode == 0)
+ csi->tm = fz_concat(fz_translate(tadj * gstate->scale, 0), csi->tm);
+ else
+ csi->tm = fz_concat(fz_translate(0, tadj), csi->tm);
+}
+
+static void
+pdf_show_string(pdf_csi *csi, unsigned char *buf, int len)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ pdf_font_desc *fontdesc = gstate->font;
+ unsigned char *end = buf + len;
+ int cpt, cid;
+
+ if (!fontdesc)
+ {
+ fz_warn("cannot draw text since font and size not set");
+ return;
+ }
+
+ while (buf < end)
+ {
+ buf = pdf_decode_cmap(fontdesc->encoding, buf, &cpt);
+ cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
+ if (cid >= 0)
+ pdf_show_glyph(csi, cid);
+ else
+ fz_warn("cannot encode character with code point %#x", cpt);
+ if (cpt == 32)
+ pdf_show_space(csi, gstate->word_space);
+ }
+}
+
+static void
+pdf_show_text(pdf_csi *csi, fz_obj *text)
+{
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ int i;
+
+ if (fz_is_array(text))
+ {
+ for (i = 0; i < fz_array_len(text); i++)
+ {
+ fz_obj *item = fz_array_get(text, i);
+ if (fz_is_string(item))
+ pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item));
+ else
+ pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f);
+ }
+ }
+ else if (fz_is_string(text))
+ {
+ pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text));
+ }
+}
+
+/*
+ * Interpreter and graphics state stack.
+ */
+
+static void
+pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
+{
+ gs->ctm = ctm;
+ gs->clip_depth = 0;
+
+ gs->stroke_state.linewidth = 1;
+ gs->stroke_state.linecap = 0;
+ gs->stroke_state.linejoin = 0;
+ gs->stroke_state.miterlimit = 10;
+ gs->stroke_state.dash_phase = 0;
+ gs->stroke_state.dash_len = 0;
+ memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list));
+
+ gs->stroke.kind = PDF_MAT_COLOR;
+ gs->stroke.colorspace = fz_keep_colorspace(fz_device_gray);
+ gs->stroke.v[0] = 0;
+ gs->stroke.pattern = NULL;
+ gs->stroke.shade = NULL;
+ gs->stroke.alpha = 1;
+
+ gs->fill.kind = PDF_MAT_COLOR;
+ gs->fill.colorspace = fz_keep_colorspace(fz_device_gray);
+ gs->fill.v[0] = 0;
+ gs->fill.pattern = NULL;
+ gs->fill.shade = NULL;
+ gs->fill.alpha = 1;
+
+ gs->char_space = 0;
+ gs->word_space = 0;
+ gs->scale = 1;
+ gs->leading = 0;
+ gs->font = NULL;
+ gs->size = -1;
+ gs->render = 0;
+ gs->rise = 0;
+
+ gs->blendmode = 0;
+ gs->softmask = NULL;
+ gs->softmask_ctm = fz_identity;
+ gs->luminosity = 0;
+}
+
static pdf_csi *
pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target)
{
@@ -55,7 +700,7 @@ pdf_clear_stack(pdf_csi *csi)
csi->top = 0;
}
-pdf_material *
+static pdf_material *
pdf_keep_material(pdf_material *mat)
{
if (mat->colorspace)
@@ -67,7 +712,7 @@ pdf_keep_material(pdf_material *mat)
return mat;
}
-pdf_material *
+static pdf_material *
pdf_drop_material(pdf_material *mat)
{
if (mat->colorspace)
@@ -79,7 +724,7 @@ pdf_drop_material(pdf_material *mat)
return mat;
}
-void
+static void
pdf_gsave(pdf_csi *csi)
{
pdf_gstate *gs = csi->gstate + csi->gtop;
@@ -102,7 +747,7 @@ pdf_gsave(pdf_csi *csi)
pdf_keep_xobject(gs->softmask);
}
-void
+static void
pdf_grestore(pdf_csi *csi)
{
pdf_gstate *gs = csi->gstate + csi->gtop;
@@ -155,26 +800,220 @@ pdf_free_csi(pdf_csi *csi)
fz_free(csi);
}
-static int
-pdf_is_hidden_ocg(fz_obj *xobj, char *target)
+/*
+ * Material state
+ */
+
+static void
+pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *colorspace)
{
- char target_state[16];
- fz_obj *obj;
+ pdf_gstate *gs = csi->gstate + csi->gtop;
+ pdf_material *mat;
- fz_strlcpy(target_state, target, sizeof target_state);
- fz_strlcat(target_state, "State", sizeof target_state);
+ pdf_flush_text(csi);
- obj = fz_dict_gets(xobj, "OC");
- obj = fz_dict_gets(obj, "OCGs");
- if (fz_is_array(obj))
- obj = fz_array_get(obj, 0);
- obj = fz_dict_gets(obj, "Usage");
- obj = fz_dict_gets(obj, target);
- obj = fz_dict_gets(obj, target_state);
- return !strcmp(fz_to_name(obj), "OFF");
+ mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
+
+ fz_drop_colorspace(mat->colorspace);
+
+ mat->kind = PDF_MAT_COLOR;
+ mat->colorspace = fz_keep_colorspace(colorspace);
+
+ mat->v[0] = 0;
+ mat->v[1] = 0;
+ mat->v[2] = 0;
+ mat->v[3] = 1;
}
-fz_error
+static void
+pdf_set_color(pdf_csi *csi, int what, float *v)
+{
+ pdf_gstate *gs = csi->gstate + csi->gtop;
+ pdf_material *mat;
+ int i;
+
+ pdf_flush_text(csi);
+
+ mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
+
+ switch (mat->kind)
+ {
+ case PDF_MAT_PATTERN:
+ case PDF_MAT_COLOR:
+ if (!strcmp(mat->colorspace->name, "Lab"))
+ {
+ mat->v[0] = v[0] / 100;
+ mat->v[1] = (v[1] + 100) / 200;
+ mat->v[2] = (v[2] + 100) / 200;
+ }
+ for (i = 0; i < mat->colorspace->n; i++)
+ mat->v[i] = v[i];
+ break;
+ default:
+ fz_warn("color incompatible with material");
+ }
+}
+
+static void
+pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade)
+{
+ pdf_gstate *gs = csi->gstate + csi->gtop;
+ pdf_material *mat;
+
+ pdf_flush_text(csi);
+
+ mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
+
+ if (mat->shade)
+ fz_drop_shade(mat->shade);
+
+ mat->kind = PDF_MAT_SHADE;
+ mat->shade = fz_keep_shade(shade);
+}
+
+static void
+pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v)
+{
+ pdf_gstate *gs = csi->gstate + csi->gtop;
+ pdf_material *mat;
+
+ pdf_flush_text(csi);
+
+ mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
+
+ if (mat->pattern)
+ pdf_drop_pattern(mat->pattern);
+
+ mat->kind = PDF_MAT_PATTERN;
+ if (pat)
+ mat->pattern = pdf_keep_pattern(pat);
+ else
+ mat->pattern = NULL;
+
+ if (v)
+ pdf_set_color(csi, what, v);
+}
+
+static void
+pdf_unset_pattern(pdf_csi *csi, int what)
+{
+ pdf_gstate *gs = csi->gstate + csi->gtop;
+ pdf_material *mat;
+ mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
+ if (mat->kind == PDF_MAT_PATTERN)
+ {
+ if (mat->pattern)
+ pdf_drop_pattern(mat->pattern);
+ mat->pattern = NULL;
+ mat->kind = PDF_MAT_COLOR;
+ }
+}
+
+/*
+ * Patterns, XObjects and ExtGState
+ */
+
+static void
+pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what)
+{
+ pdf_gstate *gstate;
+ fz_matrix ptm, invptm;
+ fz_matrix oldtopctm;
+ fz_error error;
+ int x0, y0, x1, y1;
+ int oldtop;
+
+ pdf_gsave(csi);
+ gstate = csi->gstate + csi->gtop;
+
+ if (pat->ismask)
+ {
+ pdf_unset_pattern(csi, PDF_FILL);
+ pdf_unset_pattern(csi, PDF_STROKE);
+ if (what == PDF_FILL)
+ {
+ pdf_drop_material(&gstate->stroke);
+ pdf_keep_material(&gstate->fill);
+ gstate->stroke = gstate->fill;
+ }
+ if (what == PDF_STROKE)
+ {
+ pdf_drop_material(&gstate->fill);
+ pdf_keep_material(&gstate->stroke);
+ gstate->fill = gstate->stroke;
+ }
+ }
+ else
+ {
+ // TODO: unset only the current fill/stroke or both?
+ pdf_unset_pattern(csi, what);
+ }
+
+ /* don't apply softmasks to objects in the pattern as well */
+ if (gstate->softmask)
+ {
+ pdf_drop_xobject(gstate->softmask);
+ gstate->softmask = NULL;
+ }
+
+ ptm = fz_concat(pat->matrix, csi->top_ctm);
+ invptm = fz_invert_matrix(ptm);
+
+ /* patterns are painted using the ctm in effect at the beginning of the content stream */
+ /* get bbox of shape in pattern space for stamping */
+ area = fz_transform_rect(invptm, area);
+ x0 = floorf(area.x0 / pat->xstep);
+ y0 = floorf(area.y0 / pat->ystep);
+ x1 = ceilf(area.x1 / pat->xstep);
+ y1 = ceilf(area.y1 / pat->ystep);
+
+ oldtopctm = csi->top_ctm;
+ oldtop = csi->gtop;
+
+#ifdef TILE
+ if ((x1 - x0) * (y1 - y0) > 0)
+ {
+ fz_begin_tile(csi->dev, area, pat->bbox, pat->xstep, pat->ystep, ptm);
+ gstate->ctm = ptm;
+ csi->top_ctm = gstate->ctm;
+ pdf_gsave(csi);
+ error = pdf_run_buffer(csi, pat->resources, pat->contents);
+ if (error)
+ fz_catch(error, "cannot render pattern tile");
+ pdf_grestore(csi);
+ while (oldtop < csi->gtop)
+ pdf_grestore(csi);
+ fz_end_tile(csi->dev);
+ }
+#else
+ {
+ int x, y;
+ for (y = y0; y < y1; y++)
+ {
+ for (x = x0; x < x1; x++)
+ {
+ gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm);
+ csi->top_ctm = gstate->ctm;
+ error = pdf_run_csi_buffer(csi, pat->resources, pat->contents);
+ while (oldtop < csi->gtop)
+ pdf_grestore(csi);
+ if (error)
+ {
+ fz_catch(error, "cannot render pattern tile");
+ goto cleanup;
+ }
+ }
+ }
+ }
+cleanup:
+#endif
+
+ csi->top_ctm = oldtopctm;
+
+ pdf_grestore(csi);
+}
+
+static fz_error
pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform)
{
fz_error error;
@@ -241,7 +1080,7 @@ pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix tr
if (xobj->resources)
resources = xobj->resources;
- error = pdf_run_csi_buffer(csi, resources, xobj->contents);
+ error = pdf_run_buffer(csi, resources, xobj->contents);
if (error)
return fz_rethrow(error, "cannot interpret XObject stream");
@@ -265,34 +1104,6 @@ pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix tr
}
static fz_error
-pdf_run_inline_image(pdf_csi *csi, fz_obj *rdb, fz_stream *file, fz_obj *dict)
-{
- fz_error error;
- fz_pixmap *img;
- int ch;
-
- error = pdf_load_inline_image(&img, csi->xref, rdb, dict, file);
- if (error)
- return fz_rethrow(error, "cannot load inline image");
-
- /* find EI */
- ch = fz_read_byte(file);
- while (ch != 'E' && ch != EOF)
- ch = fz_read_byte(file);
- ch = fz_read_byte(file);
- if (ch != 'I')
- {
- fz_drop_pixmap(img);
- return fz_rethrow(error, "syntax error after inline image");
- }
-
- pdf_show_image(csi, img);
-
- fz_drop_pixmap(img);
- return fz_okay;
-}
-
-static fz_error
pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
@@ -430,6 +1241,10 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate)
return fz_okay;
}
+/*
+ * Operators
+ */
+
static void pdf_run_BDC(pdf_csi *csi)
{
}
@@ -440,6 +1255,7 @@ static fz_error pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
fz_error error;
char *buf = csi->xref->scratch;
int buflen = sizeof(csi->xref->scratch);
+ fz_pixmap *img;
fz_obj *obj;
error = pdf_parse_dict(&obj, csi->xref, file, buf, buflen);
@@ -452,10 +1268,22 @@ static fz_error pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
if (fz_peek_byte(file) == '\n')
fz_read_byte(file);
- error = pdf_run_inline_image(csi, rdb, file, obj);
+ error = pdf_load_inline_image(&img, csi->xref, rdb, obj, file);
fz_drop_obj(obj);
if (error)
- return fz_rethrow(error, "cannot parse inline image");
+ return fz_rethrow(error, "cannot load inline image");
+
+ pdf_show_image(csi, img);
+
+ fz_drop_pixmap(img);
+
+ /* find EI */
+ ch = fz_read_byte(file);
+ while (ch != 'E' && ch != EOF)
+ ch = fz_read_byte(file);
+ ch = fz_read_byte(file);
+ if (ch != 'I')
+ return fz_rethrow(error, "syntax error after inline image");
return fz_okay;
}
@@ -1273,7 +2101,7 @@ pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf)
}
static fz_error
-pdf_run_csi_file(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen)
+pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen)
{
fz_error error;
int tok;
@@ -1382,13 +2210,17 @@ pdf_run_csi_file(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int bufl
}
}
-fz_error
-pdf_run_csi_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents)
+/*
+ * Entry points
+ */
+
+static fz_error
+pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents)
{
fz_stream *file;
fz_error error;
file = fz_open_buffer(contents);
- error = pdf_run_csi_file(csi, rdb, file, csi->xref->scratch, sizeof csi->xref->scratch);
+ error = pdf_run_stream(csi, rdb, file, csi->xref->scratch, sizeof csi->xref->scratch);
fz_close(file);
if (error)
return fz_rethrow(error, "cannot parse content stream");
@@ -1407,7 +2239,7 @@ pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matri
fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 0, 0, 0, 1);
csi = pdf_new_csi(xref, dev, ctm, target);
- error = pdf_run_csi_buffer(csi, page->resources, page->contents);
+ error = pdf_run_buffer(csi, page->resources, page->contents);
pdf_free_csi(csi);
if (error)
return fz_rethrow(error, "cannot parse page content stream");
@@ -1450,7 +2282,7 @@ fz_error
pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm)
{
pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View");
- fz_error error = pdf_run_csi_buffer(csi, resources, contents);
+ fz_error error = pdf_run_buffer(csi, resources, contents);
pdf_free_csi(csi);
if (error)
return fz_rethrow(error, "cannot parse glyph content stream");
diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj
index 6bbf11b1..90b8cff2 100644
--- a/win32/libmupdf.vcproj
+++ b/win32/libmupdf.vcproj
@@ -155,10 +155,6 @@
>
</File>
<File
- RelativePath="..\pdf\pdf_build.c"
- >
- </File>
- <File
RelativePath="..\pdf\pdf_cmap.c"
>
</File>