diff options
Diffstat (limited to 'pdf/pdf_interpret.c')
-rw-r--r-- | pdf/pdf_interpret.c | 181 |
1 files changed, 135 insertions, 46 deletions
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 2cfa5d99..7bb2da9c 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -88,6 +88,7 @@ struct pdf_csi_s /* text object state */ fz_text *text; + fz_rect text_bbox; fz_matrix tlm; fz_matrix tm; int text_mode; @@ -432,6 +433,19 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd) fz_path *path; fz_rect bbox; + if (dostroke) { + if (csi->dev->flags & (FZ_DEVFLAG_STROKECOLOR_UNDEFINED | FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED)) + csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; + else if (gstate->stroke_state.dash_len != 0 && csi->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED)) + csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; + else if (gstate->stroke_state.linejoin == FZ_LINEJOIN_MITER && (csi->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED)) + csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; + } + if (dofill) { + if (csi->dev->flags & FZ_DEVFLAG_FILLCOLOR_UNDEFINED) + csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE; + } + path = csi->path; csi->path = fz_new_path(ctx); @@ -540,7 +554,6 @@ pdf_flush_text(pdf_csi *csi) int dostroke = 0; int doclip = 0; int doinvisible = 0; - fz_rect bbox; fz_context *ctx = csi->dev->ctx; if (!csi->text) @@ -566,9 +579,7 @@ pdf_flush_text(pdf_csi *csi) fz_try(ctx) { - bbox = fz_bound_text(ctx, text, gstate->ctm); - - pdf_begin_group(csi, bbox); + pdf_begin_group(csi, csi->text_bbox); if (doinvisible) fz_ignore_text(csi->dev, text, gstate->ctm); @@ -595,7 +606,7 @@ pdf_flush_text(pdf_csi *csi) if (gstate->fill.pattern) { fz_clip_text(csi->dev, text, gstate->ctm, 0); - pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL); + pdf_show_pattern(csi, gstate->fill.pattern, csi->text_bbox, PDF_FILL); fz_pop_clip(csi->dev); } break; @@ -624,7 +635,7 @@ pdf_flush_text(pdf_csi *csi) 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_STROKE); + pdf_show_pattern(csi, gstate->stroke.pattern, csi->text_bbox, PDF_STROKE); fz_pop_clip(csi->dev); } break; @@ -664,6 +675,8 @@ pdf_show_char(pdf_csi *csi, int cid) int ucsbuf[8]; int ucslen; int i; + fz_rect bbox; + int render_direct; tsm.a = gstate->size * gstate->scale; tsm.b = 0; @@ -697,6 +710,15 @@ pdf_show_char(pdf_csi *csi, int cid) trm = fz_concat(tsm, csi->tm); + bbox = fz_bound_glyph(ctx, fontdesc->font, gid, trm); + /* Compensate for the glyph cache limited positioning precision */ + bbox.x0 -= 1; + bbox.y0 -= 1; + bbox.x1 += 1; + bbox.y1 += 1; + + render_direct = !fz_glyph_cacheable(fontdesc->font, gid); + /* flush buffered text if face or matrix or rendermode has changed */ if (!csi->text || fontdesc->font != csi->text->font || @@ -705,7 +727,8 @@ pdf_show_char(pdf_csi *csi, int cid) 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) + gstate->render != csi->text_mode || + render_direct) { pdf_flush_text(csi); @@ -713,14 +736,28 @@ pdf_show_char(pdf_csi *csi, int cid) csi->text->trm.e = 0; csi->text->trm.f = 0; csi->text_mode = gstate->render; + csi->text_bbox = fz_empty_rect; } - /* add glyph to textobject */ - fz_add_text(ctx, csi->text, gid, ucsbuf[0], trm.e, trm.f); + if (render_direct) + { + /* Render the glyph stream direct here (only happens for + * type3 glyphs that seem to inherit current graphics + * attributes) */ + fz_matrix composed = fz_concat(trm, gstate->ctm); + fz_render_t3_glyph_direct(ctx, csi->dev, fontdesc->font, gid, composed, gstate); + } + else + { + csi->text_bbox = fz_union_rect(csi->text_bbox, bbox); + + /* add glyph to textobject */ + fz_add_text(ctx, 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(ctx, csi->text, -1, ucsbuf[i], trm.e, trm.f); + /* add filler glyphs for one-to-many unicode mapping */ + for (i = 1; i < ucslen; i++) + fz_add_text(ctx, csi->text, -1, ucsbuf[i], trm.e, trm.f); + } if (fontdesc->wmode == 0) { @@ -858,8 +895,49 @@ pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm) gs->luminosity = 0; } +static pdf_material * +pdf_keep_material(pdf_material *mat) +{ + if (mat->colorspace) + fz_keep_colorspace(mat->colorspace); + if (mat->pattern) + pdf_keep_pattern(mat->pattern); + if (mat->shade) + fz_keep_shade(mat->shade); + return mat; +} + +static pdf_material * +pdf_drop_material(fz_context *ctx, pdf_material *mat) +{ + if (mat->colorspace) + fz_drop_colorspace(ctx, mat->colorspace); + if (mat->pattern) + pdf_drop_pattern(ctx, mat->pattern); + if (mat->shade) + fz_drop_shade(ctx, mat->shade); + return mat; +} + +static void +copy_state(pdf_gstate *gs, pdf_gstate *old) +{ + gs->stroke = old->stroke; + gs->fill = old->fill; + gs->font = old->font; + gs->softmask = old->softmask; + + pdf_keep_material(&gs->stroke); + pdf_keep_material(&gs->fill); + if (gs->font) + pdf_keep_font(gs->font); + if (gs->softmask) + pdf_keep_xobject(gs->softmask); +} + + static pdf_csi * -pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie) +pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie, pdf_gstate *gstate) { pdf_csi *csi; fz_context *ctx = dev->ctx; @@ -896,6 +974,8 @@ pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *event, fz_cooki csi->top_ctm = ctm; pdf_init_gstate(&csi->gstate[0], ctm); + if (gstate) + copy_state(&csi->gstate[0], gstate); csi->gtop = 0; csi->cookie = cookie; @@ -927,30 +1007,6 @@ pdf_clear_stack(pdf_csi *csi) csi->top = 0; } -static pdf_material * -pdf_keep_material(pdf_material *mat) -{ - if (mat->colorspace) - fz_keep_colorspace(mat->colorspace); - if (mat->pattern) - pdf_keep_pattern(mat->pattern); - if (mat->shade) - fz_keep_shade(mat->shade); - return mat; -} - -static pdf_material * -pdf_drop_material(fz_context *ctx, pdf_material *mat) -{ - if (mat->colorspace) - fz_drop_colorspace(ctx, mat->colorspace); - if (mat->pattern) - pdf_drop_pattern(ctx, mat->pattern); - if (mat->shade) - fz_drop_shade(ctx, mat->shade); - return mat; -} - static void pdf_gsave(pdf_csi *csi) { @@ -962,12 +1018,11 @@ pdf_gsave(pdf_csi *csi) csi->gstate = fz_resize_array(ctx, csi->gstate, csi->gcap*2, sizeof(pdf_gstate)); csi->gcap *= 2; } - gs = csi->gstate + csi->gtop; memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate)); - csi->gtop ++; - + csi->gtop++; + gs = &csi->gstate[csi->gtop]; pdf_keep_material(&gs->stroke); pdf_keep_material(&gs->fill); if (gs->font) @@ -1419,16 +1474,26 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) else if (!strcmp(s, "LC")) { + csi->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); gstate->stroke_state.start_cap = fz_to_int(val); gstate->stroke_state.dash_cap = fz_to_int(val); gstate->stroke_state.end_cap = fz_to_int(val); } else if (!strcmp(s, "LW")) + { + csi->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; gstate->stroke_state.linewidth = fz_to_real(val); + } else if (!strcmp(s, "LJ")) + { + csi->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; gstate->stroke_state.linejoin = fz_to_int(val); + } else if (!strcmp(s, "ML")) + { + csi->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; gstate->stroke_state.miterlimit = fz_to_real(val); + } else if (!strcmp(s, "D")) { @@ -1655,12 +1720,16 @@ static void pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what) static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb) { + csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_run_cs_imp(csi, rdb, PDF_STROKE); /* RJW: "cannot set colorspace" */ } static void pdf_run_cs(pdf_csi *csi, fz_obj *rdb) { + csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; + pdf_run_cs_imp(csi, rdb, PDF_FILL); /* RJW: "cannot set colorspace" */ } @@ -1774,6 +1843,7 @@ static void pdf_run_F(pdf_csi *csi) static void pdf_run_G(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_STROKE, fz_device_gray); pdf_set_color(csi, PDF_STROKE, csi->stack); } @@ -1781,6 +1851,7 @@ static void pdf_run_G(pdf_csi *csi) static void pdf_run_J(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; + csi->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); gstate->stroke_state.start_cap = csi->stack[0]; gstate->stroke_state.dash_cap = csi->stack[0]; gstate->stroke_state.end_cap = csi->stack[0]; @@ -1788,6 +1859,7 @@ static void pdf_run_J(pdf_csi *csi) static void pdf_run_K(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_STROKE, fz_device_cmyk); pdf_set_color(csi, PDF_STROKE, csi->stack); } @@ -1795,6 +1867,7 @@ static void pdf_run_K(pdf_csi *csi) static void pdf_run_M(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; + csi->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; gstate->stroke_state.miterlimit = csi->stack[0]; } @@ -1809,6 +1882,7 @@ static void pdf_run_Q(pdf_csi *csi) static void pdf_run_RG(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_STROKE, fz_device_rgb); pdf_set_color(csi, PDF_STROKE, csi->stack); } @@ -1880,6 +1954,7 @@ static void pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *ma static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb) { pdf_gstate *gstate = csi->gstate + csi->gtop; + csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; pdf_run_SC_imp(csi, rdb, PDF_STROKE, &gstate->stroke); /* RJW: "cannot set color and colorspace" */ } @@ -1887,6 +1962,7 @@ static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb) static void pdf_run_sc(pdf_csi *csi, fz_obj *rdb) { pdf_gstate *gstate = csi->gstate + csi->gtop; + csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; pdf_run_SC_imp(csi, rdb, PDF_FILL, &gstate->fill); /* RJW: "cannot set color and colorspace" */ } @@ -2070,12 +2146,20 @@ static void pdf_run_d(pdf_csi *csi) static void pdf_run_d0(pdf_csi *csi) { - csi->dev->flags |= FZ_CHARPROC_COLOR; + csi->dev->flags |= FZ_DEVFLAG_COLOR; } static void pdf_run_d1(pdf_csi *csi) { - csi->dev->flags |= FZ_CHARPROC_MASK; + csi->dev->flags |= FZ_DEVFLAG_MASK; + csi->dev->flags &= ~(FZ_DEVFLAG_FILLCOLOR_UNDEFINED | + FZ_DEVFLAG_STROKECOLOR_UNDEFINED | + FZ_DEVFLAG_STARTCAP_UNDEFINED | + FZ_DEVFLAG_DASHCAP_UNDEFINED | + FZ_DEVFLAG_ENDCAP_UNDEFINED | + FZ_DEVFLAG_LINEJOIN_UNDEFINED | + FZ_DEVFLAG_MITERLIMIT_UNDEFINED | + FZ_DEVFLAG_LINEWIDTH_UNDEFINED); } static void pdf_run_f(pdf_csi *csi) @@ -2090,6 +2174,7 @@ static void pdf_run_fstar(pdf_csi *csi) static void pdf_run_g(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_FILL, fz_device_gray); pdf_set_color(csi, PDF_FILL, csi->stack); } @@ -2124,11 +2209,13 @@ static void pdf_run_i(pdf_csi *csi) static void pdf_run_j(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; + csi->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; gstate->stroke_state.linejoin = csi->stack[0]; } static void pdf_run_k(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_FILL, fz_device_cmyk); pdf_set_color(csi, PDF_FILL, csi->stack); } @@ -2178,6 +2265,7 @@ static void pdf_run_re(pdf_csi *csi) static void pdf_run_rg(pdf_csi *csi) { + csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; pdf_set_colorspace(csi, PDF_FILL, fz_device_rgb); pdf_set_color(csi, PDF_FILL, csi->stack); } @@ -2237,6 +2325,7 @@ static void pdf_run_w(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; pdf_flush_text(csi); /* linewidth affects stroked text rendering mode */ + csi->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; gstate->stroke_state.linewidth = csi->stack[0]; } @@ -2607,7 +2696,7 @@ pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matri if (page->transparency) fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 1, 0, 0, 1); - csi = pdf_new_csi(xref, dev, ctm, event, cookie); + csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL); fz_try(ctx) { pdf_run_buffer(csi, page->resources, page->contents); @@ -2649,7 +2738,7 @@ pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matri if (!strcmp(event, "View") && (flags & (1 << 5))) /* NoView */ continue; - csi = pdf_new_csi(xref, dev, ctm, event, cookie); + csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL); if (!pdf_is_hidden_ocg(fz_dict_gets(annot->obj, "OC"), csi, page->resources)) { fz_try(ctx) @@ -2676,9 +2765,9 @@ pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_c } void -pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm) +pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) { - pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View", NULL); + pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View", NULL, gstate); fz_context *ctx = xref->ctx; fz_try(ctx) |