diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-12-18 19:37:50 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-12-19 15:20:26 +0000 |
commit | d4d3b774f21f3a8a238a4f67bc01132119c97a94 (patch) | |
tree | 9de55d45d277129228febcfedcc620805822d2a9 /pdf | |
parent | 956945485624f0df0ffdfbd471a4ec095bd145c9 (diff) | |
download | mupdf-d4d3b774f21f3a8a238a4f67bc01132119c97a94.tar.xz |
Bug 693503: 'Flatten' display list for all type3 glyphs.
It is perfectly allowable to have type3 glyphs that refer to
other type3 glyphs in the same font (and in theory it's probably
even possible to have type3 glyphs that refer back and forth
between 2 or more type3 fonts).
The old code used to cope with this just fine, but with the change
to 'early loading' of the glyphs to display lists at interpret time
a problem has crept in. When we load the type 3 font, we load
each glyph in turn. If glyph 1 tries to use glyph 2, then we look
up the font, only to find that that the font has not been installed
yet, so we reload the entire font. This gets us into an infinite
loop.
As a fix for this, we split the loading of the type3 font into 2; we
load the font as normal, then allow the font to be inserted into
the list of current fonts. Then we run through the glyphs in the
font 'preparing' them (turning them into display lists).
This solves the infinite loop issue, but causes another problem;
recursive references (such as a font holding a display list that
contains a text node that contains a reference to the original font)
result in us never being able to free the structures.
To avoid this, we insist on never allowing type3 glyphs to be referenced
within a type3 display list. The display lists for all type3 glyphs
are therefore 'flat'. We achieve this by adding a 'nested' flag to
the pdf command stream interpreter structure, and setting this in the
case where we are running a glyph stream. We check for that flag in the
type3 glyph render function, and if present, we force the 'render_direct'
path to be used.
Finally, we ensure that fz_text groups are not needlessly created with
no contents.
Problem found in 2923.pdf.asan.22.2139, a test file supplied by
Mateusz "j00ru" Jurczyk and Gynvael Coldwind of the Google Security
Team using Address Sanitizer. Many thanks!
Diffstat (limited to 'pdf')
-rw-r--r-- | pdf/mupdf-internal.h | 5 | ||||
-rw-r--r-- | pdf/pdf_font.c | 10 | ||||
-rw-r--r-- | pdf/pdf_form.c | 2 | ||||
-rw-r--r-- | pdf/pdf_interpret.c | 36 | ||||
-rw-r--r-- | pdf/pdf_type3.c | 27 |
5 files changed, 63 insertions, 17 deletions
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h index 839f30f4..a9ee53e3 100644 --- a/pdf/mupdf-internal.h +++ b/pdf/mupdf-internal.h @@ -474,7 +474,8 @@ unsigned char *pdf_lookup_substitute_font(int mono, int serif, int bold, int ita unsigned char *pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len); pdf_font_desc *pdf_load_type3_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *obj); -pdf_font_desc *pdf_load_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *obj); +void pdf_load_type3_glyphs(pdf_document *doc, pdf_font_desc *fontdesc, int nestedDepth); +pdf_font_desc *pdf_load_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *obj, int nestedDepth); pdf_font_desc *pdf_new_font_desc(fz_context *ctx); pdf_font_desc *pdf_keep_font(fz_context *ctx, pdf_font_desc *fontdesc); @@ -554,7 +555,7 @@ struct pdf_page_s * Content stream parsing */ -void pdf_run_glyph(pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); +void pdf_run_glyph(pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, int nestedDepth); /* * PDF interface to store diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index 34199e06..ebb157b5 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -1098,13 +1098,14 @@ pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc) } pdf_font_desc * -pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) +pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, int nested_depth) { char *subtype; pdf_obj *dfonts; pdf_obj *charprocs; fz_context *ctx = xref->ctx; pdf_font_desc *fontdesc; + int type3 = 0; if ((fontdesc = pdf_find_item(ctx, pdf_free_font_imp, dict))) { @@ -1124,11 +1125,15 @@ pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) else if (subtype && !strcmp(subtype, "TrueType")) fontdesc = pdf_load_simple_font(xref, dict); else if (subtype && !strcmp(subtype, "Type3")) + { fontdesc = pdf_load_type3_font(xref, rdb, dict); + type3 = 1; + } else if (charprocs) { fz_warn(ctx, "unknown font format, guessing type3."); fontdesc = pdf_load_type3_font(xref, rdb, dict); + type3 = 1; } else if (dfonts) { @@ -1147,6 +1152,9 @@ pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) pdf_store_item(ctx, dict, fontdesc, fontdesc->size); + if (type3) + pdf_load_type3_glyphs(xref, fontdesc, nested_depth); + return fontdesc; } diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c index 871c9a55..1a8dd268 100644 --- a/pdf/pdf_form.c +++ b/pdf/pdf_form.c @@ -371,7 +371,7 @@ static void get_font_info(pdf_document *doc, pdf_obj *dr, char *da, font_info *f parse_da(ctx, da, &font_rec->da_rec); if (font_rec->da_rec.font_name == NULL) fz_throw(ctx, "No font name in default appearance"); - font_rec->font = pdf_load_font(doc, dr, pdf_dict_gets(pdf_dict_gets(dr, "Font"), font_rec->da_rec.font_name)); + font_rec->font = pdf_load_font(doc, dr, pdf_dict_gets(pdf_dict_gets(dr, "Font"), font_rec->da_rec.font_name), 0); } static void font_info_fin(fz_context *ctx, font_info *font_rec) diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index e655cc87..05b7b1c4 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -66,6 +66,8 @@ struct pdf_csi_s fz_device *dev; pdf_document *xref; + int nested_depth; + /* usage mode for optional content groups */ char *event; /* "View", "Print", "Export" */ @@ -600,6 +602,11 @@ pdf_flush_text(pdf_csi *csi) fz_try(ctx) { fz_rect tb = fz_transform_rect(gstate->ctm, csi->text_bbox); + + /* Don't bother sending a text group with nothing in it */ + if (text->len == 0) + break; + pdf_begin_group(csi, tb); if (doinvisible) @@ -739,7 +746,9 @@ pdf_show_char(pdf_csi *csi, int cid) bbox.x1 += 1; bbox.y1 += 1; - render_direct = !fz_glyph_cacheable(ctx, fontdesc->font, gid); + /* If we are a type3 font within a type 3 font, or are otherwise + * uncachable, then render direct. */ + render_direct = (!fontdesc->font->ft_face && csi->nested_depth > 0) || !fz_glyph_cacheable(ctx, fontdesc->font, gid); /* flush buffered text if face or matrix or rendermode has changed */ if (!csi->text || @@ -765,9 +774,9 @@ pdf_show_char(pdf_csi *csi, int cid) { /* Render the glyph stream direct here (only happens for * type3 glyphs that seem to inherit current graphics - * attributes) */ + * attributes, or type 3 glyphs within type3 glyphs). */ fz_matrix composed = fz_concat(trm, gstate->ctm); - fz_render_t3_glyph_direct(ctx, csi->dev, fontdesc->font, gid, composed, gstate); + fz_render_t3_glyph_direct(ctx, csi->dev, fontdesc->font, gid, composed, gstate, csi->nested_depth); } else { @@ -956,7 +965,7 @@ copy_state(fz_context *ctx, pdf_gstate *gs, pdf_gstate *old) static pdf_csi * -pdf_new_csi(pdf_document *xref, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie, pdf_gstate *gstate) +pdf_new_csi(pdf_document *xref, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie, pdf_gstate *gstate, int nested) { pdf_csi *csi; fz_context *ctx = dev->ctx; @@ -992,6 +1001,7 @@ pdf_new_csi(pdf_document *xref, fz_device *dev, fz_matrix ctm, char *event, fz_c csi->gstate = fz_malloc_array(ctx, csi->gcap, sizeof(pdf_gstate)); csi->top_ctm = ctm; + csi->nested_depth = nested; pdf_init_gstate(ctx, &csi->gstate[0], ctm); if (gstate) copy_state(ctx, &csi->gstate[0], gstate); @@ -1493,7 +1503,7 @@ pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate) gstate->font = NULL; } - gstate->font = pdf_load_font(csi->xref, rdb, font); + gstate->font = pdf_load_font(csi->xref, rdb, font, csi->nested_depth); if (!gstate->font) fz_throw(ctx, "cannot find font in store"); gstate->size = pdf_to_real(pdf_array_get(val, 1)); @@ -2062,7 +2072,7 @@ static void pdf_run_Tf(pdf_csi *csi, pdf_obj *rdb) if (!obj) fz_throw(ctx, "cannot find font resource: '%s'", csi->name); - gstate->font = pdf_load_font(csi->xref, rdb, obj); + gstate->font = pdf_load_font(csi->xref, rdb, obj, csi->nested_depth); } static void pdf_run_Tr(pdf_csi *csi) @@ -2197,11 +2207,15 @@ static void pdf_run_d(pdf_csi *csi) static void pdf_run_d0(pdf_csi *csi) { + if (csi->nested_depth > 1) + return; csi->dev->flags |= FZ_DEVFLAG_COLOR; } static void pdf_run_d1(pdf_csi *csi) { + if (csi->nested_depth > 1) + return; csi->dev->flags |= FZ_DEVFLAG_MASK; csi->dev->flags &= ~(FZ_DEVFLAG_FILLCOLOR_UNDEFINED | FZ_DEVFLAG_STROKECOLOR_UNDEFINED | @@ -2828,7 +2842,7 @@ static void pdf_run_page_contents_with_usage(pdf_document *xref, pdf_page *page, 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, NULL); + csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL, 0); fz_try(ctx) { pdf_run_contents_object(csi, page->resources, page->contents); @@ -2871,7 +2885,7 @@ static void pdf_run_annot_with_usage(pdf_document *xref, pdf_page *page, pdf_ann if (!strcmp(event, "View") && (flags & (1 << 5))) /* NoView */ return; - csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL); + csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL, 0); if (!pdf_is_hidden_ocg(pdf_dict_gets(annot->obj, "OC"), csi, page->resources)) { fz_try(ctx) @@ -2932,13 +2946,15 @@ pdf_run_page(pdf_document *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, } void -pdf_run_glyph(pdf_document *xref, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) +pdf_run_glyph(pdf_document *xref, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, int nested_depth) { - pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View", NULL, gstate); + pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View", NULL, gstate, nested_depth+1); fz_context *ctx = xref->ctx; fz_try(ctx) { + if (nested_depth > 10) + fz_throw(ctx, "Too many nestings of Type3 glyphs"); pdf_run_contents_buffer(csi, resources, contents); } fz_always(ctx) diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c index 7b4e9f07..d96a160a 100644 --- a/pdf/pdf_type3.c +++ b/pdf/pdf_type3.c @@ -2,9 +2,9 @@ #include "mupdf-internal.h" static void -pdf_run_glyph_func(void *doc, void *rdb, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) +pdf_run_glyph_func(void *doc, void *rdb, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate, int nested_depth) { - pdf_run_glyph(doc, (pdf_obj *)rdb, contents, dev, ctm, gstate); + pdf_run_glyph(doc, (pdf_obj *)rdb, contents, dev, ctm, gstate, nested_depth); } static void @@ -155,7 +155,6 @@ pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) { fontdesc->font->t3procs[i] = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; - fz_prepare_t3_glyph(ctx, fontdesc->font, i); fontdesc->size += 0; // TODO: display list size calculation } } @@ -169,3 +168,25 @@ pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) } return fontdesc; } + +void pdf_load_type3_glyphs(pdf_document *xref, pdf_font_desc *fontdesc, int nested_depth) +{ + int i; + fz_context *ctx = xref->ctx; + + fz_try(ctx) + { + for (i = 0; i < 256; i++) + { + if (fontdesc->font->t3procs[i]) + { + fz_prepare_t3_glyph(ctx, fontdesc->font, i, nested_depth); + fontdesc->size += 0; // TODO: display list size calculation + } + } + } + fz_catch(ctx) + { + fz_warn(ctx, "Type3 glyph load failed: %s", fz_caught(ctx)); + } +} |