diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2012-08-01 15:10:40 +0100 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2012-08-01 15:10:40 +0100 |
commit | c8b8bbc851ae2089f515b5e65780198ad024c5cb (patch) | |
tree | b1702dda67a2a6026e8870ec1a89d70545f69f2f | |
parent | 55743b7682129deb6cc03e90ebde1b0e6e62d3b4 (diff) | |
parent | 4d36e9613da5190aba2c0c6c8281e5d35cf9758c (diff) | |
download | mupdf-c8b8bbc851ae2089f515b5e65780198ad024c5cb.tar.xz |
Merge branch 'master' into forms
Conflicts:
pdf/mupdf-internal.h
pdf/pdf_font.c
-rw-r--r-- | apps/mudraw.c | 1 | ||||
-rw-r--r-- | apps/mupdfinfo.c | 4 | ||||
-rw-r--r-- | apps/mupdfshow.c | 6 | ||||
-rw-r--r-- | apps/x11_main.c | 4 | ||||
-rw-r--r-- | draw/draw_device.c | 68 | ||||
-rw-r--r-- | draw/draw_edge.c | 12 | ||||
-rw-r--r-- | draw/draw_glyph.c | 48 | ||||
-rw-r--r-- | draw/draw_path.c | 4 | ||||
-rw-r--r-- | fitz/base_hash.c | 2 | ||||
-rw-r--r-- | fitz/fitz-internal.h | 48 | ||||
-rw-r--r-- | fitz/fitz.h | 24 | ||||
-rw-r--r-- | fitz/res_font.c | 179 | ||||
-rw-r--r-- | fitz/res_path.c | 36 | ||||
-rw-r--r-- | fitz/res_shade.c | 2 | ||||
-rw-r--r-- | fitz/res_store.c | 2 | ||||
-rw-r--r-- | pdf/mupdf-internal.h | 15 | ||||
-rw-r--r-- | pdf/mupdf.h | 3 | ||||
-rw-r--r-- | pdf/pdf_cmap.c | 2 | ||||
-rw-r--r-- | pdf/pdf_colorspace.c | 2 | ||||
-rw-r--r-- | pdf/pdf_crypt.c | 180 | ||||
-rw-r--r-- | pdf/pdf_font.c | 135 | ||||
-rw-r--r-- | pdf/pdf_function.c | 237 | ||||
-rw-r--r-- | pdf/pdf_image.c | 16 | ||||
-rw-r--r-- | pdf/pdf_object.c | 2 | ||||
-rw-r--r-- | pdf/pdf_page.c | 2 | ||||
-rw-r--r-- | pdf/pdf_shade.c | 18 | ||||
-rw-r--r-- | pdf/pdf_store.c | 4 | ||||
-rw-r--r-- | pdf/pdf_stream.c | 8 | ||||
-rw-r--r-- | pdf/pdf_type3.c | 6 | ||||
-rw-r--r-- | pdf/pdf_write.c | 7 | ||||
-rw-r--r-- | pdf/pdf_xref.c | 30 | ||||
-rw-r--r-- | xps/xps_glyphs.c | 5 | ||||
-rw-r--r-- | xps/xps_path.c | 62 |
33 files changed, 783 insertions, 391 deletions
diff --git a/apps/mudraw.c b/apps/mudraw.c index 24e8a36e..a67ba8e8 100644 --- a/apps/mudraw.c +++ b/apps/mudraw.c @@ -546,6 +546,7 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) if (diff > timing.max) { timing.max = diff; + timing.maxpage = pagenum; timing.maxfilename = filename; } timing.total += diff; diff --git a/apps/mupdfinfo.c b/apps/mupdfinfo.c index 5bdf760e..279298c2 100644 --- a/apps/mupdfinfo.c +++ b/apps/mupdfinfo.c @@ -176,14 +176,14 @@ showglobalinfo(void) if (obj) { printf("Info object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); - pdf_print_obj(pdf_resolve_indirect(obj)); + pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0); } obj = pdf_dict_gets(xref->trailer, "Encrypt"); if (obj) { printf("\nEncryption object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); - pdf_print_obj(pdf_resolve_indirect(obj)); + pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0); } printf("\nPages: %d\n\n", pagecount); diff --git a/apps/mupdfshow.c b/apps/mupdfshow.c index 8e8425b0..f534a5c7 100644 --- a/apps/mupdfshow.c +++ b/apps/mupdfshow.c @@ -24,7 +24,7 @@ static void showtrailer(void) if (!doc) fz_throw(ctx, "no file specified"); printf("trailer\n"); - pdf_print_obj(doc->trailer); + pdf_fprint_obj(stdout, doc->trailer, 0); printf("\n"); } @@ -122,7 +122,7 @@ static void showobject(int num, int gen) else { printf("%d %d obj\n", num, gen); - pdf_print_obj(obj); + pdf_fprint_obj(stdout, obj, 0); printf("stream\n"); showstream(num, gen); printf("endstream\n"); @@ -132,7 +132,7 @@ static void showobject(int num, int gen) else { printf("%d %d obj\n", num, gen); - pdf_print_obj(obj); + pdf_fprint_obj(stdout, obj, 0); printf("endobj\n\n"); } diff --git a/apps/x11_main.c b/apps/x11_main.c index d19b4f8c..ec78695d 100644 --- a/apps/x11_main.c +++ b/apps/x11_main.c @@ -583,7 +583,11 @@ void winopenuri(pdfapp_t *app, char *buf) #endif } if (fork() == 0) + { execlp(browser, browser, buf, (char*)0); + fprintf(stderr, "cannot exec '%s'\n", browser); + exit(0); + } } static void onkey(int c) diff --git a/draw/draw_device.c b/draw/draw_device.c index 6f74eabf..b4cc606e 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -463,11 +463,12 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, fz_matrix ctm, unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; - fz_matrix tm, trm; + fz_matrix tm, trm, trunc_trm; fz_pixmap *glyph; int i, x, y, gid; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; + fz_bbox scissor = state->scissor; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); @@ -491,10 +492,15 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, fz_matrix ctm, trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); - trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); - trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); - glyph = fz_render_glyph(dev->ctx, text->font, gid, trm, model); + trunc_trm = trm; + trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); + trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); + + scissor.x0 -= x; scissor.x1 -= x; + scissor.y0 -= y; scissor.y1 -= y; + + glyph = fz_render_glyph(dev->ctx, text->font, gid, trunc_trm, model, scissor); if (glyph) { if (glyph->n == 1) @@ -510,6 +516,19 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, fz_matrix ctm, } fz_drop_pixmap(dev->ctx, glyph); } + else + { + fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm); + if (path) + { + fz_draw_fill_path(devp, path, 0, fz_identity, colorspace, color, alpha); + fz_free_path(dev->ctx, path); + } + else + { + fz_warn(dev->ctx, "cannot render glyph"); + } + } } if (state->blendmode & FZ_BLEND_KNOCKOUT) @@ -523,11 +542,12 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_ fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; - fz_matrix tm, trm; + fz_matrix tm, trm, trunc_trm; fz_pixmap *glyph; int i, x, y, gid; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; + fz_bbox scissor = state->scissor; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); @@ -550,10 +570,15 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_ trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); - trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); - trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); - glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trm, ctm, stroke); + trunc_trm = trm; + trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); + trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); + + scissor.x0 -= x; scissor.x1 -= x; + scissor.y0 -= y; scissor.y1 -= y; + + glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trunc_trm, ctm, stroke, scissor); if (glyph) { draw_glyph(colorbv, state->dest, glyph, x, y, state->scissor); @@ -561,6 +586,19 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_ draw_glyph(colorbv, state->shape, glyph, x, y, state->scissor); fz_drop_pixmap(dev->ctx, glyph); } + else + { + fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm); + if (path) + { + fz_draw_stroke_path(devp, path, stroke, fz_identity, colorspace, color, alpha); + fz_free_path(dev->ctx, path); + } + else + { + fz_warn(dev->ctx, "cannot render glyph"); + } + } } if (state->blendmode & FZ_BLEND_KNOCKOUT) @@ -645,7 +683,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, fz_matrix ctm, int accumulate) trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); - glyph = fz_render_glyph(dev->ctx, text->font, gid, trm, model); + glyph = fz_render_glyph(dev->ctx, text->font, gid, trm, model, bbox); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); @@ -653,6 +691,11 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, fz_matrix ctm, int accumulate) draw_glyph(NULL, state[1].shape, glyph, x, y, bbox); fz_drop_pixmap(dev->ctx, glyph); } + else + { + fz_warn(dev->ctx, "cannot draw glyph for clipping (unimplemented case)"); + // TODO: outline/non-cached case + } } } } @@ -712,7 +755,7 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); - glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trm, ctm, stroke); + glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trm, ctm, stroke, bbox); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); @@ -720,6 +763,11 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke draw_glyph(NULL, shape, glyph, x, y, bbox); fz_drop_pixmap(dev->ctx, glyph); } + else + { + fz_warn(dev->ctx, "cannot draw glyph for clipping (unimplemented case)"); + // TODO: outline/non-cached case + } } } } diff --git a/draw/draw_edge.c b/draw/draw_edge.c index 48496acd..ff5dcdfc 100644 --- a/draw/draw_edge.c +++ b/draw/draw_edge.c @@ -356,10 +356,14 @@ fz_insert_gel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) fy0 = floorf(fy0 * fz_aa_vscale); fy1 = floorf(fy1 * fz_aa_vscale); - x0 = fz_clampi(fx0, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); - y0 = fz_clampi(fy0, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); - x1 = fz_clampi(fx1, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); - y1 = fz_clampi(fy1, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); + /* Call fz_clamp so that clamping is done in the float domain, THEN + * cast down to an int. Calling fz_clampi causes problems due to the + * implicit cast down from float to int of the first argument + * over/underflowing and flipping sign at extreme values. */ + x0 = (int)fz_clamp(fx0, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); + y0 = (int)fz_clamp(fy0, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); + x1 = (int)fz_clamp(fx1, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); + y1 = (int)fz_clamp(fy1, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); d = clip_lerp_y(gel->clip.y0, 0, x0, y0, x1, y1, &v); if (d == OUTSIDE) return; diff --git a/draw/draw_glyph.c b/draw/draw_glyph.c index cef9d7fa..de2f47c2 100644 --- a/draw/draw_glyph.c +++ b/draw/draw_glyph.c @@ -1,6 +1,5 @@ #include "fitz-internal.h" -#define MAX_FONT_SIZE 1000 #define MAX_GLYPH_SIZE 256 #define MAX_CACHE_SIZE (1024*1024) @@ -96,29 +95,48 @@ fz_keep_glyph_cache(fz_context *ctx) } fz_pixmap * -fz_render_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *stroke) +fz_render_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *stroke, fz_bbox scissor) { if (font->ft_face) + { + if (stroke->dash_len > 0) + return NULL; return fz_render_ft_stroked_glyph(ctx, font, gid, trm, ctm, stroke); - return fz_render_glyph(ctx, font, gid, trm, NULL); + } + return fz_render_glyph(ctx, font, gid, trm, NULL, scissor); } +/* + Render a glyph and return a bitmap. + If the glyph is too large to fit the cache we have two choices: + 1) Return NULL so the caller can draw the glyph using an outline. + Only supported for freetype fonts. + 2) Render a clipped glyph by using the scissor rectangle. + Only supported for type 3 fonts. + This must not be inserted into the cache. + */ fz_pixmap * -fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_colorspace *model) +fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_colorspace *model, fz_bbox scissor) { fz_glyph_cache *cache; fz_glyph_key key; fz_pixmap *val; float size = fz_matrix_expansion(ctm); + int do_cache; - cache = ctx->glyph_cache; - - if (size > MAX_FONT_SIZE) + if (size <= MAX_GLYPH_SIZE) { - /* TODO: this case should be handled by rendering glyph as a path fill */ - fz_warn(ctx, "font size too large (%g), not rendering glyph", size); - return NULL; + scissor = fz_infinite_bbox; + do_cache = 1; } + else + { + if (font->ft_face) + return NULL; + do_cache = 0; + } + + cache = ctx->glyph_cache; memset(&key, 0, sizeof key); key.font = font; @@ -131,6 +149,9 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color key.f = (ctm.f - floorf(ctm.f)) * 256; key.aa = fz_aa_level(ctx); + ctm.e = floorf(ctm.e) + key.e / 256.0f; + ctm.f = floorf(ctm.f) + key.f / 256.0f; + fz_lock(ctx, FZ_LOCK_GLYPHCACHE); val = fz_hash_find(ctx, cache->hash, &key); if (val) @@ -140,9 +161,6 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color return val; } - ctm.e = floorf(ctm.e) + key.e / 256.0f; - ctm.f = floorf(ctm.f) + key.f / 256.0f; - fz_try(ctx) { if (font->ft_face) @@ -161,7 +179,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color * abandon ours, and use the one there already. */ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); - val = fz_render_t3_glyph(ctx, font, gid, ctm, model); + val = fz_render_t3_glyph(ctx, font, gid, ctm, model, scissor); fz_lock(ctx, FZ_LOCK_GLYPHCACHE); } else @@ -176,7 +194,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color fz_rethrow(ctx); } - if (val) + if (val && do_cache) { if (val->w < MAX_GLYPH_SIZE && val->h < MAX_GLYPH_SIZE) { diff --git a/draw/draw_path.c b/draw/draw_path.c index b0889279..9996c182 100644 --- a/draw/draw_path.c +++ b/draw/draw_path.c @@ -82,7 +82,7 @@ fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness) { case FZ_MOVETO: /* implicit closepath before moveto */ - if (i && (cx != bx || cy != by)) + if (cx != bx || cy != by) line(gel, &ctm, cx, cy, bx, by); x1 = path->items[i++].v; y1 = path->items[i++].v; @@ -118,7 +118,7 @@ fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness) } } - if (i && (cx != bx || cy != by)) + if (cx != bx || cy != by) line(gel, &ctm, cx, cy, bx, by); } diff --git a/fitz/base_hash.c b/fitz/base_hash.c index ccdffe63..76d7f870 100644 --- a/fitz/base_hash.c +++ b/fitz/base_hash.c @@ -267,6 +267,7 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key) } } +#ifndef NDEBUG void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) { @@ -287,3 +288,4 @@ fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) } } } +#endif diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index e719e78d..02d452f4 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -71,7 +71,6 @@ float fz_atof(const char *s); typedef struct fz_hash_table_s fz_hash_table; fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock); -void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table); void fz_empty_hash(fz_context *ctx, fz_hash_table *table); void fz_free_hash(fz_context *ctx, fz_hash_table *table); @@ -83,6 +82,10 @@ int fz_hash_len(fz_context *ctx, fz_hash_table *table); void *fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx); void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx); +#ifndef NDEBUG +void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table); +#endif + /* * Math and geometry */ @@ -270,7 +273,9 @@ struct fz_store_type_s void *(*keep_key)(fz_context *,void *); void (*drop_key)(fz_context *,void *); int (*cmp_key)(void *, void *); +#ifndef NDEBUG void (*debug)(void *); +#endif }; /* @@ -292,11 +297,6 @@ void fz_drop_store_context(fz_context *ctx); fz_store *fz_keep_store_context(fz_context *ctx); /* - fz_print_store: Dump the contents of the store for debugging. -*/ -void fz_print_store(fz_context *ctx, FILE *out); - -/* fz_store_item: Add an item to the store. Add an item into the store, returning NULL for success. If an item @@ -364,6 +364,13 @@ void fz_empty_store(fz_context *ctx); */ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase); +/* + fz_print_store: Dump the contents of the store for debugging. +*/ +#ifndef NDEBUG +void fz_print_store(fz_context *ctx, FILE *out); +#endif + struct fz_buffer_s { int refs; @@ -742,18 +749,20 @@ void fz_drop_font_context(fz_context *ctx); fz_font *fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix); -fz_font *fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox); -fz_font *fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox); +fz_font *fz_new_font_from_memory(fz_context *ctx, char *name, unsigned char *data, int len, int index, int use_glyph_bbox); +fz_font *fz_new_font_from_file(fz_context *ctx, char *name, char *path, int index, int use_glyph_bbox); fz_font *fz_keep_font(fz_context *ctx, fz_font *font); void fz_drop_font(fz_context *ctx, fz_font *font); -void fz_print_font(fz_context *ctx, FILE *out, fz_font *font); - void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax); fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid); +#ifndef NDEBUG +void fz_print_font(fz_context *ctx, FILE *out, fz_font *font); +#endif + /* * Vector path buffer. * It can be stroked and dashed, or be filled. @@ -818,6 +827,7 @@ struct fz_stroke_state_s }; fz_path *fz_new_path(fz_context *ctx); +fz_point fz_currentpoint(fz_context *ctx, fz_path *path); void fz_moveto(fz_context*, fz_path*, float x, float y); void fz_lineto(fz_context*, fz_path*, float x, float y); void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float); @@ -832,7 +842,6 @@ fz_path *fz_clone_path(fz_context *ctx, fz_path *old); fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm); void fz_adjust_rect_for_stroke(fz_rect *r, fz_stroke_state *stroke, fz_matrix *ctm); -void fz_print_path(fz_context *ctx, FILE *out, fz_path *, int indent); fz_stroke_state *fz_new_stroke_state(fz_context *ctx); fz_stroke_state *fz_new_stroke_state_with_len(fz_context *ctx, int len); @@ -841,6 +850,10 @@ void fz_drop_stroke_state(fz_context *ctx, fz_stroke_state *stroke); fz_stroke_state *fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared); fz_stroke_state *fz_unshare_stroke_state_with_len(fz_context *ctx, fz_stroke_state *shared, int len); +#ifndef NDEBUG +void fz_print_path(fz_context *ctx, FILE *out, fz_path *, int indent); +#endif + /* * Glyph cache */ @@ -850,11 +863,13 @@ fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx); void fz_drop_glyph_cache_context(fz_context *ctx); void fz_purge_glyph_cache(fz_context *ctx); +fz_path *fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); +fz_path *fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm); fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, int aa); -fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model); +fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model, fz_bbox scissor); fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state); -fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model); -fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke); +fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model, fz_bbox scissor); +fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke, fz_bbox scissor); void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate); /* @@ -933,11 +948,14 @@ struct fz_shade_s fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade); void fz_drop_shade(fz_context *ctx, fz_shade *shade); void fz_free_shade_imp(fz_context *ctx, fz_storable *shade); -void fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade); fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm); void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox); +#ifndef NDEBUG +void fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade); +#endif + /* * Scan converter */ diff --git a/fitz/fitz.h b/fitz/fitz.h index fa07360b..595dc2e4 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1631,7 +1631,7 @@ typedef struct fz_text_page_s fz_text_page; /* fz_text_sheet: A text sheet contains a list of distinct text styles used on a page (or a series of pages). -*/ +*/ struct fz_text_sheet_s { int maxid; @@ -1641,7 +1641,7 @@ struct fz_text_sheet_s /* fz_text_style: A text style contains details of a distinct text style used on a page. -*/ +*/ struct fz_text_style_s { fz_text_style *next; @@ -1656,7 +1656,7 @@ struct fz_text_style_s /* fz_text_page: A text page is a list of blocks of text, together with an overall bounding box. -*/ +*/ struct fz_text_page_s { fz_rect mediabox; @@ -1668,7 +1668,7 @@ struct fz_text_page_s fz_text_block: A text block is a list of lines of text. In typical cases this may correspond to a paragraph or a column of text. A collection of blocks makes up a page. -*/ +*/ struct fz_text_block_s { fz_rect bbox; @@ -1681,7 +1681,7 @@ struct fz_text_block_s (or very similar) baseline. In typical cases this should correspond (as expected) to complete lines of text. A collection of lines makes up a block. -*/ +*/ struct fz_text_line_s { fz_rect bbox; @@ -1696,7 +1696,7 @@ struct fz_text_line_s enough to represent a complete line. In cases where multiple font styles are used (for example italics), then a line will be broken down into a series of spans. -*/ +*/ struct fz_text_span_s { fz_rect bbox; @@ -1708,7 +1708,7 @@ struct fz_text_span_s /* fz_text_char: A text char is a unicode character and the bounding box with which it appears on the page. -*/ +*/ struct fz_text_char_s { fz_rect bbox; @@ -1755,22 +1755,22 @@ void fz_free_text_page(fz_context *ctx, fz_text_page *page); /* fz_print_text_sheet: Output a text sheet to a file as CSS. -*/ +*/ void fz_print_text_sheet(fz_context *ctx, FILE *out, fz_text_sheet *sheet); /* fz_print_text_page_html: Output a page to a file in HTML format. -*/ +*/ void fz_print_text_page_html(fz_context *ctx, FILE *out, fz_text_page *page); /* fz_print_text_page_xml: Output a page to a file in XML format. -*/ +*/ void fz_print_text_page_xml(fz_context *ctx, FILE *out, fz_text_page *page); /* fz_print_text_page: Output a page to a file in UTF-8 format. -*/ +*/ void fz_print_text_page(fz_context *ctx, FILE *out, fz_text_page *page); /* @@ -1965,7 +1965,7 @@ enum { gotor.new_window: If true, the destination should open in a new window. - For FZ_LINK_URI: + For FZ_LINK_URI: uri.uri: A UTF-8 encoded URI to launch. diff --git a/fitz/res_font.c b/fitz/res_font.c index 25939d02..a68a1ff1 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -6,6 +6,9 @@ #define MAX_BBOX_TABLE_SIZE 4096 +/* 20 degrees */ +#define SHEAR 0.36397f + static void fz_drop_freetype(fz_context *ctx); static fz_font * @@ -251,7 +254,7 @@ fz_drop_freetype(fz_context *ctx) } fz_font * -fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox) +fz_new_font_from_file(fz_context *ctx, char *name, char *path, int index, int use_glyph_bbox) { FT_Face face; fz_font *font; @@ -268,7 +271,10 @@ fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox fz_throw(ctx, "freetype: cannot load font: %s", ft_error_string(fterr)); } - font = fz_new_font(ctx, face->family_name, use_glyph_bbox, face->num_glyphs); + if (!name) + name = face->family_name; + + font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs); font->ft_face = face; font->bbox.x0 = (float) face->bbox.xMin / face->units_per_EM; font->bbox.y0 = (float) face->bbox.yMin / face->units_per_EM; @@ -279,7 +285,7 @@ fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox } fz_font * -fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox) +fz_new_font_from_memory(fz_context *ctx, char *name, unsigned char *data, int len, int index, int use_glyph_bbox) { FT_Face face; fz_font *font; @@ -296,7 +302,10 @@ fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index fz_throw(ctx, "freetype: cannot load font: %s", ft_error_string(fterr)); } - font = fz_new_font(ctx, face->family_name, use_glyph_bbox, face->num_glyphs); + if (!name) + name = face->family_name; + + font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs); font->ft_face = face; font->bbox.x0 = (float) face->bbox.xMin / face->units_per_EM; font->bbox.y0 = (float) face->bbox.yMin / face->units_per_EM; @@ -377,7 +386,7 @@ fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) for (y = 0; y < pixmap->h; y++) { memcpy(pixmap->samples + (unsigned int)(y * pixmap->w), - bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch), + bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch), pixmap->w); } } @@ -395,10 +404,12 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int a FT_Error fterr; fz_pixmap *result; + float strength = fz_matrix_expansion(trm) * 0.02f; + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); if (font->ft_italic) - trm = fz_concat(fz_shear(0.3f, 0), trm); + trm = fz_concat(fz_shear(SHEAR, 0), trm); /* Freetype mutilates complex glyphs if they are loaded @@ -471,7 +482,6 @@ retry_unhinted: if (font->ft_bold) { - float strength = fz_matrix_expansion(trm) * 0.04f; FT_Outline_Embolden(&face->glyph->outline, strength * 64); FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); } @@ -507,7 +517,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); if (font->ft_italic) - trm = fz_concat(fz_shear(0.3f, 0), trm); + trm = fz_concat(fz_shear(SHEAR, 0), trm); m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; @@ -611,10 +621,12 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) // TODO: refactor loading into fz_load_ft_glyph // TODO: cache results + float strength = fz_matrix_expansion(trm) * 0.02f; + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); if (font->ft_italic) - trm = fz_concat(fz_shear(0.3f, 0), trm); + trm = fz_concat(fz_shear(SHEAR, 0), trm); m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; @@ -641,7 +653,6 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) if (font->ft_bold) { - float strength = fz_matrix_expansion(trm) * 0.04f; FT_Outline_Embolden(&face->glyph->outline, strength * 64); FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); } @@ -662,6 +673,136 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) return bounds; } +/* Turn FT_Outline into a fz_path */ + +struct closure { + fz_context *ctx; + fz_path *path; + float x, y; +}; + +static int move_to(const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_moveto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); + return 0; +} + +static int line_to(const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_lineto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); + return 0; +} + +static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_point s, c1, c2; + float cx = tx + c->x / 64.0f, cy = ty + c->y / 64.0f; + float px = tx + p->x / 64.0f, py = ty + p->y / 64.0f; + s = fz_currentpoint(ctx, path); + c1.x = (s.x + cx * 2) / 3; + c1.y = (s.y + cy * 2) / 3; + c2.x = (px + cx * 2) / 3; + c2.y = (py + cy * 2) / 3; + fz_curveto(ctx, path, c1.x, c1.y, c2.x, c2.y, px, py); + return 0; +} + +static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_curveto(ctx, path, + tx + c1->x/64.0f, ty + c1->y/64.0f, + tx + c2->x/64.0f, ty + c2->y/64.0f, + tx + p->x/64.0f, ty + p->y/64.0f); + return 0; +} + +static const FT_Outline_Funcs outline_funcs = { + move_to, line_to, conic_to, cubic_to, 0, 0 +}; + +fz_path * +fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) +{ + struct closure cc; + FT_Face face = font->ft_face; + FT_Matrix m; + FT_Vector v; + int fterr; + + float strength = fz_matrix_expansion(trm) * 0.02f; + + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); + + if (font->ft_italic) + trm = fz_concat(fz_shear(SHEAR, 0), trm); + + m.xx = trm.a * 64; /* should be 65536 */ + m.yx = trm.b * 64; + m.xy = trm.c * 64; + m.yy = trm.d * 64; + v.x = 0; + v.y = 0; + + fz_lock(ctx, FZ_LOCK_FREETYPE); + + fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ + if (fterr) + fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); + FT_Set_Transform(face, &m, &v); + + fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); + if (fterr) + { + fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + if (font->ft_bold) + { + FT_Outline_Embolden(&face->glyph->outline, strength * 64); + FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); + } + + fz_try(ctx) + { + cc.ctx = ctx; + cc.path = fz_new_path(ctx); + cc.x = trm.e; + cc.y = trm.f; + fz_moveto(ctx, cc.path, cc.x, cc.y); + FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc); + fz_closepath(ctx, cc.path); + } + fz_catch(ctx) + { + fz_warn(ctx, "freetype cannot decompose outline"); + fz_free(ctx, cc.path); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + fz_unlock(ctx, FZ_LOCK_FREETYPE); + + return cc.path; +} + /* * Type 3 fonts... */ @@ -723,7 +864,7 @@ fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) } fz_pixmap * -fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model) +fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, fz_bbox scissor) { fz_matrix ctm; void *contents; @@ -762,6 +903,8 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_co bbox.x1++; bbox.y1++; + bbox = fz_intersect_bbox(bbox, scissor); + glyph = fz_new_pixmap_with_bbox(ctx, model ? model : fz_device_gray, bbox); fz_clear_pixmap(ctx, glyph); @@ -813,6 +956,7 @@ fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gi /* RJW: "cannot draw type3 glyph" */ } +#ifndef NDEBUG void fz_print_font(fz_context *ctx, FILE *out, fz_font *font) { @@ -838,6 +982,7 @@ fz_print_font(fz_context *ctx, FILE *out, fz_font *font) fprintf(out, "}\n"); } +#endif fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) @@ -860,6 +1005,18 @@ fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) return fz_transform_rect(trm, font->bbox); } +fz_path * +fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm) +{ + if (!font->ft_face) + { + fz_warn(ctx, "cannot convert type3 glyph to path"); + return NULL; + } + + return fz_outline_ft_glyph(ctx, font, gid, ctm); +} + int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid) { if (!font->t3procs || !font->t3flags || gid < 0 || gid >= font->bbox_count) diff --git a/fitz/res_path.c b/fitz/res_path.c index b8a6a1a2..d02ea560 100644 --- a/fitz/res_path.c +++ b/fitz/res_path.c @@ -63,6 +63,40 @@ grow_path(fz_context *ctx, fz_path *path, int n) path->last = path->len; } +fz_point +fz_currentpoint(fz_context *ctx, fz_path *path) +{ + fz_point c, m; + int i; + + c.x = c.y = m.x = m.y = 0; + i = 0; + + while (i < path->len) + { + switch (path->items[i++].k) + { + case FZ_MOVETO: + m.x = c.x = path->items[i++].v; + m.y = c.y = path->items[i++].v; + break; + case FZ_LINETO: + c.x = path->items[i++].v; + c.y = path->items[i++].v; + break; + case FZ_CURVETO: + i += 4; + c.x = path->items[i++].v; + c.y = path->items[i++].v; + break; + case FZ_CLOSE_PATH: + c = m; + } + } + + return c; +} + void fz_moveto(fz_context *ctx, fz_path *path, float x, float y) { @@ -336,6 +370,7 @@ fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix ctm) } } +#ifndef NDEBUG void fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent) { @@ -375,6 +410,7 @@ fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent) } } } +#endif fz_stroke_state * fz_keep_stroke_state(fz_context *ctx, fz_stroke_state *stroke) diff --git a/fitz/res_shade.c b/fitz/res_shade.c index d2b2f44b..9ebdd51e 100644 --- a/fitz/res_shade.c +++ b/fitz/res_shade.c @@ -67,6 +67,7 @@ fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm) return fz_intersect_rect(s, r); } +#ifndef NDEBUG void fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade) { @@ -130,3 +131,4 @@ fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade) fprintf(out, "}\n"); } +#endif diff --git a/fitz/res_store.c b/fitz/res_store.c index 8e5375d6..a76cfbb0 100644 --- a/fitz/res_store.c +++ b/fitz/res_store.c @@ -452,6 +452,7 @@ fz_drop_store_context(fz_context *ctx) ctx->store = NULL; } +#ifndef NDEBUG void fz_print_store(fz_context *ctx, FILE *out) { @@ -476,6 +477,7 @@ fz_print_store(fz_context *ctx, FILE *out) } fz_unlock(ctx, FZ_LOCK_ALLOC); } +#endif /* This is now an n^2 algorithm - not ideal, but it'll only be bad if we are * actually managing to scavenge lots of blocks back. */ diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h index eb423abb..62747538 100644 --- a/pdf/mupdf-internal.h +++ b/pdf/mupdf-internal.h @@ -245,10 +245,11 @@ fz_stream *pdf_open_raw_renumbered_stream(pdf_document *doc, int num, int gen, i void pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf); void pdf_repair_obj_stms(pdf_document *doc); -void pdf_print_xref(pdf_document *); void pdf_resize_xref(pdf_document *doc, int newcap); pdf_obj *pdf_new_ref(pdf_document *doc, pdf_obj *obj); +void pdf_print_xref(pdf_document *); + /* * Encryption */ @@ -266,7 +267,9 @@ char *pdf_crypt_method(pdf_document *doc); int pdf_crypt_length(pdf_document *doc); unsigned char *pdf_crypt_key(pdf_document *doc); +#ifndef NDEBUG void pdf_print_crypt(pdf_crypt *crypt); +#endif /* * Functions, Colorspaces, Shadings and Images @@ -274,7 +277,7 @@ void pdf_print_crypt(pdf_crypt *crypt); typedef struct pdf_function_s pdf_function; -pdf_function *pdf_load_function(pdf_document *doc, pdf_obj *ref); +pdf_function *pdf_load_function(pdf_document *doc, pdf_obj *ref, int in, int out); void pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, float *out, int outlen); pdf_function *pdf_keep_function(fz_context *ctx, pdf_function *func); void pdf_drop_function(fz_context *ctx, pdf_function *func); @@ -388,7 +391,6 @@ void pdf_drop_cmap(fz_context *ctx, pdf_cmap *cmap); void pdf_free_cmap_imp(fz_context *ctx, fz_storable *cmap); unsigned int pdf_cmap_size(fz_context *ctx, pdf_cmap *cmap); -void pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap); int pdf_cmap_wmode(fz_context *ctx, pdf_cmap *cmap); void pdf_set_cmap_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode); void pdf_set_usecmap(fz_context *ctx, pdf_cmap *cmap, pdf_cmap *usecmap); @@ -409,6 +411,10 @@ pdf_cmap *pdf_load_system_cmap(fz_context *ctx, char *name); pdf_cmap *pdf_load_builtin_cmap(fz_context *ctx, char *name); pdf_cmap *pdf_load_embedded_cmap(pdf_document *doc, pdf_obj *ref); +#ifndef NDEBUG +void pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap); +#endif + /* * Font */ @@ -524,7 +530,10 @@ pdf_font_desc *pdf_new_font_desc(fz_context *ctx); pdf_font_desc *pdf_keep_font(fz_context *ctx, pdf_font_desc *fontdesc); void pdf_drop_font(fz_context *ctx, pdf_font_desc *font); +#ifndef NDEBUG void pdf_print_font(fz_context *ctx, pdf_font_desc *fontdesc); +#endif + fz_rect pdf_measure_text(fz_context *ctx, pdf_font_desc *fontdesc, unsigned char *buf, int len); float pdf_text_stride(fz_context *ctx, pdf_font_desc *fontdesc, float fontsize, unsigned char *buf, int len, float room, int *count); diff --git a/pdf/mupdf.h b/pdf/mupdf.h index f3821efd..f2d235b9 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -82,8 +82,11 @@ void pdf_dict_dels(pdf_obj *dict, char *key); void pdf_sort_dict(pdf_obj *dict); int pdf_fprint_obj(FILE *fp, pdf_obj *obj, int tight); + +#ifndef NDEBUG void pdf_print_obj(pdf_obj *obj); void pdf_print_ref(pdf_obj *obj); +#endif char *pdf_to_utf8(pdf_document *xref, pdf_obj *src); unsigned short *pdf_to_ucs2(pdf_document *xref, pdf_obj *src); /* sumatrapdf */ diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c index 1f1117fe..cd0d6385 100644 --- a/pdf/pdf_cmap.c +++ b/pdf/pdf_cmap.c @@ -109,6 +109,7 @@ pdf_set_cmap_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode) cmap->wmode = wmode; } +#ifndef NDEBUG void pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap) { @@ -155,6 +156,7 @@ pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap) } printf("\t}\n}\n"); } +#endif /* * Add a codespacerange section. diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c index 13323ce3..7a3835dd 100644 --- a/pdf/pdf_colorspace.c +++ b/pdf/pdf_colorspace.c @@ -119,7 +119,7 @@ load_separation(pdf_document *xref, pdf_obj *array) fz_try(ctx) { - tint = pdf_load_function(xref, tintobj); + tint = pdf_load_function(xref, tintobj, n, base->n); /* RJW: fz_drop_colorspace(ctx, base); * "cannot load tint function (%d %d R)", pdf_to_num(tintobj), pdf_to_gen(tintobj) */ diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index b65786d9..a8f92823 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -40,7 +40,7 @@ struct pdf_crypt_s fz_context *ctx; }; -static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *dict, char *name, int defaultlength); +static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_crypt *crypt, char *name); /* * Create crypt object for decrypting strings and streams @@ -79,80 +79,6 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) fz_throw(ctx, "unknown encryption version"); } - crypt->length = 40; - if (crypt->v == 2 || crypt->v == 4) - { - obj = pdf_dict_gets(dict, "Length"); - if (pdf_is_int(obj)) - crypt->length = pdf_to_int(obj); - - /* work-around for pdf generators that assume length is in bytes */ - if (crypt->length < 40) - crypt->length = crypt->length * 8; - - if (crypt->length % 8 != 0) - { - pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "invalid encryption key length"); - } - if (crypt->length > 256) - { - pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "invalid encryption key length"); - } - } - - if (crypt->v == 5) - crypt->length = 256; - - if (crypt->v == 1 || crypt->v == 2) - { - crypt->stmf.method = PDF_CRYPT_RC4; - crypt->stmf.length = crypt->length; - - crypt->strf.method = PDF_CRYPT_RC4; - crypt->strf.length = crypt->length; - } - - if (crypt->v == 4 || crypt->v == 5) - { - crypt->stmf.method = PDF_CRYPT_NONE; - crypt->stmf.length = crypt->length; - - crypt->strf.method = PDF_CRYPT_NONE; - crypt->strf.length = crypt->length; - - obj = pdf_dict_gets(dict, "CF"); - if (pdf_is_dict(obj)) - { - crypt->cf = pdf_keep_obj(obj); - } - else - { - crypt->cf = NULL; - } - - fz_try(ctx) - { - obj = pdf_dict_gets(dict, "StmF"); - if (pdf_is_name(obj)) - pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt->cf, pdf_to_name(obj), crypt->length); - - obj = pdf_dict_gets(dict, "StrF"); - if (pdf_is_name(obj)) - pdf_parse_crypt_filter(ctx, &crypt->strf, crypt->cf, pdf_to_name(obj), crypt->length); - } - fz_catch(ctx) - { - pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); - } - - /* in crypt revision 4, the crypt filter determines the key length */ - if (crypt->strf.method != PDF_CRYPT_NONE) - crypt->length = crypt->stmf.length; - } - /* Standard security handler (PDF 1.7 table 3.19) */ obj = pdf_dict_gets(dict, "R"); @@ -163,7 +89,7 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) fz_warn(ctx, "encryption dictionary missing revision value, guessing..."); if (crypt->v < 2) crypt->r = 2; - else if (crypt->v == 2 || crypt->v == 3) + else if (crypt->v == 2) crypt->r = 3; else if (crypt->v == 4) crypt->r = 4; @@ -189,7 +115,8 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) obj = pdf_dict_gets(dict, "U"); if (pdf_is_string(obj) && pdf_to_str_len(obj) == 32) memcpy(crypt->u, pdf_to_str_buf(obj), 32); - else if (pdf_is_string(obj) && pdf_to_str_len(obj) >= 48 && crypt->r == 5) + /* /O and /U are supposed to be 48 bytes long for revision 5, they're often longer, though */ + else if (crypt->r == 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) memcpy(crypt->u, pdf_to_str_buf(obj), 48); else if (pdf_is_string(obj) && pdf_to_str_len(obj) < 32) { @@ -246,6 +173,82 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) else fz_warn(ctx, "missing file identifier, may not be able to do decryption"); + /* Determine encryption key length */ + + crypt->length = 40; + if (crypt->v == 2 || crypt->v == 4) + { + obj = pdf_dict_gets(dict, "Length"); + if (pdf_is_int(obj)) + crypt->length = pdf_to_int(obj); + + /* work-around for pdf generators that assume length is in bytes */ + if (crypt->length < 40) + crypt->length = crypt->length * 8; + + if (crypt->length % 8 != 0) + { + pdf_free_crypt(ctx, crypt); + fz_throw(ctx, "invalid encryption key length"); + } + if (crypt->length < 0 || crypt->length > 256) + { + pdf_free_crypt(ctx, crypt); + fz_throw(ctx, "invalid encryption key length"); + } + } + + if (crypt->v == 5) + crypt->length = 256; + + if (crypt->v == 1 || crypt->v == 2) + { + crypt->stmf.method = PDF_CRYPT_RC4; + crypt->stmf.length = crypt->length; + + crypt->strf.method = PDF_CRYPT_RC4; + crypt->strf.length = crypt->length; + } + + if (crypt->v == 4 || crypt->v == 5) + { + crypt->stmf.method = PDF_CRYPT_NONE; + crypt->stmf.length = crypt->length; + + crypt->strf.method = PDF_CRYPT_NONE; + crypt->strf.length = crypt->length; + + obj = pdf_dict_gets(dict, "CF"); + if (pdf_is_dict(obj)) + { + crypt->cf = pdf_keep_obj(obj); + } + else + { + crypt->cf = NULL; + } + + fz_try(ctx) + { + obj = pdf_dict_gets(dict, "StmF"); + if (pdf_is_name(obj)) + pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt, pdf_to_name(obj)); + + obj = pdf_dict_gets(dict, "StrF"); + if (pdf_is_name(obj)) + pdf_parse_crypt_filter(ctx, &crypt->strf, crypt, pdf_to_name(obj)); + } + fz_catch(ctx) + { + pdf_free_crypt(ctx, crypt); + fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); + } + + /* in crypt revision 4, the crypt filter determines the key length */ + if (crypt->strf.method != PDF_CRYPT_NONE) + crypt->length = crypt->stmf.length; + } + return crypt; } @@ -262,7 +265,7 @@ pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt) */ static void -pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *cf_obj, char *name, int defaultlength) +pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_crypt *crypt, char *name) { pdf_obj *obj; pdf_obj *dict; @@ -270,20 +273,20 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *cf_obj, c int is_stdcf = (!is_identity && (strcmp(name, "StdCF") == 0)); if (!is_identity && !is_stdcf) - fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj)); + fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", pdf_to_num(crypt->cf), pdf_to_gen(crypt->cf)); cf->method = PDF_CRYPT_NONE; - cf->length = defaultlength; + cf->length = crypt->length; - if (!cf_obj) + if (!crypt->cf) { cf->method = (is_identity ? PDF_CRYPT_NONE : PDF_CRYPT_RC4); return; } - dict = pdf_dict_gets(cf_obj, name); + dict = pdf_dict_gets(crypt->cf, name); if (!pdf_is_dict(dict)) - fz_throw(ctx, "cannot parse crypt filter (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj)); + fz_throw(ctx, "cannot parse crypt filter (%d %d R)", pdf_to_num(crypt->cf), pdf_to_gen(crypt->cf)); obj = pdf_dict_gets(dict, "CFM"); if (pdf_is_name(obj)) @@ -310,6 +313,13 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *cf_obj, c if ((cf->length % 8) != 0) fz_throw(ctx, "invalid key length: %d", cf->length); + + if ((crypt->r == 1 || crypt->r == 2 || crypt->r == 4) && + (cf->length < 0 || cf->length > 256)) + fz_throw(ctx, "invalid key length: %d", cf->length); + if (crypt->r == 5 && + (cf->length != 128 && cf->length != 192 && cf->length == 256)) + fz_throw(ctx, "invalid key length: %d", cf->length); } /* @@ -816,12 +826,13 @@ pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int n if (strcmp(name, "Identity")) { pdf_crypt_filter cf; - pdf_parse_crypt_filter(chain->ctx, &cf, crypt->cf, name, crypt->length); + pdf_parse_crypt_filter(chain->ctx, &cf, crypt, name); return pdf_open_crypt_imp(chain, crypt, &cf, num, gen); } return chain; } +#ifndef NDEBUG void pdf_print_crypt(pdf_crypt *crypt) { int i; @@ -845,3 +856,4 @@ void pdf_print_crypt(pdf_crypt *crypt) printf("}\n"); } +#endif diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index 904094a2..1a0177b6 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -7,7 +7,7 @@ static void pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *dict, char *collection, char *basefont); -static char *base_font_names[14][7] = +static char *base_font_names[][10] = { { "Courier", "CourierNew", "CourierNewPSMT", NULL }, { "Courier-Bold", "CourierNew,Bold", "Courier,Bold", @@ -33,7 +33,8 @@ static char *base_font_names[14][7] = { "Times-BoldItalic", "TimesNewRomanPS-BoldItalicMT", "TimesNewRoman,BoldItalic", "TimesNewRomanPS-BoldItalic", "TimesNewRoman-BoldItalic", NULL }, - { "Symbol", NULL }, + { "Symbol", "Symbol,Italic", "Symbol,Bold", "Symbol,BoldItalic", + "SymbolMT", "SymbolMT,Italic", "SymbolMT,Bold", "SymbolMT,BoldItalic", NULL }, { "ZapfDingbats", NULL } }; @@ -72,7 +73,7 @@ static int strcmp_ignore_space(char *a, char *b) static char *clean_font_name(char *fontname) { int i, k; - for (i = 0; i < 14; i++) + for (i = 0; i < nelem(base_font_names); i++) for (k = 0; base_font_names[i][k]; k++) if (!strcmp_ignore_space(base_font_names[i][k], fontname)) return base_font_names[i][0]; @@ -175,40 +176,24 @@ static int lookup_mre_code(char *name) static void pdf_load_builtin_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname) { - char buf[256], *comma = NULL; unsigned char *data; unsigned int len; - if (strchr(fontname, ',')) - { - fz_strlcpy(buf, fontname, sizeof buf); - comma = strchr(buf, ','); - if (comma) - *comma++ = 0; - fontname = buf; - } + fontname = clean_font_name(fontname); data = pdf_lookup_builtin_font(fontname, &len); if (!data) fz_throw(ctx, "cannot find builtin font: '%s'", fontname); - fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 1); + fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1); /* RJW: "cannot load freetype font from memory" */ if (!strcmp(fontname, "Symbol") || !strcmp(fontname, "ZapfDingbats")) fontdesc->flags |= PDF_FD_SYMBOLIC; - - if (comma) - { - if (strstr(comma, "Italic")) - fontdesc->font->ft_italic = 1; - if (strstr(comma, "Bold")) - fontdesc->font->ft_bold = 1; - } } static void -pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int serif, int bold, int italic) +pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname, int mono, int serif, int bold, int italic) { unsigned char *data; unsigned int len; @@ -217,7 +202,7 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int if (!data) fz_throw(ctx, "cannot find substitute font"); - fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 1); + fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1); /* RJW: "cannot load freetype font from memory" */ fontdesc->font->ft_substitute = 1; @@ -226,7 +211,7 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int } static void -pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, int ros, int serif) +pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname, int ros, int serif) { unsigned char *data; unsigned int len; @@ -236,7 +221,7 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, int ros, fz_throw(ctx, "cannot find builtin CJK font"); /* a glyph bbox cache is too big for droid sans fallback (51k glyphs!) */ - fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 0); + fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 0); /* RJW: "cannot load builtin CJK font" */ fontdesc->font->ft_substitute = 1; @@ -269,24 +254,27 @@ pdf_load_system_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname, c if (collection) { if (!strcmp(collection, "Adobe-CNS1")) - pdf_load_substitute_cjk_font(ctx, fontdesc, PDF_ROS_CNS, serif); + pdf_load_substitute_cjk_font(ctx, fontdesc, fontname, PDF_ROS_CNS, serif); else if (!strcmp(collection, "Adobe-GB1")) - pdf_load_substitute_cjk_font(ctx, fontdesc, PDF_ROS_GB, serif); + pdf_load_substitute_cjk_font(ctx, fontdesc, fontname, PDF_ROS_GB, serif); else if (!strcmp(collection, "Adobe-Japan1")) - pdf_load_substitute_cjk_font(ctx, fontdesc, PDF_ROS_JAPAN, serif); + pdf_load_substitute_cjk_font(ctx, fontdesc, fontname, PDF_ROS_JAPAN, serif); else if (!strcmp(collection, "Adobe-Korea1")) - pdf_load_substitute_cjk_font(ctx, fontdesc, PDF_ROS_KOREA, serif); + pdf_load_substitute_cjk_font(ctx, fontdesc, fontname, PDF_ROS_KOREA, serif); else - fz_throw(ctx, "unknown cid collection: %s", collection); - return; + { + fz_warn(ctx, "unknown cid collection: %s", collection); + pdf_load_substitute_font(ctx, fontdesc, fontname, mono, serif, bold, italic); + } + } + else + { + pdf_load_substitute_font(ctx, fontdesc, fontname, mono, serif, bold, italic); } - - pdf_load_substitute_font(ctx, fontdesc, mono, serif, bold, italic); - /* RJW: "cannot load substitute font" */ } static void -pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *stmref) +pdf_load_embedded_font(pdf_document *xref, pdf_font_desc *fontdesc, char *fontname, pdf_obj *stmref) { fz_buffer *buf; fz_context *ctx = xref->ctx; @@ -302,7 +290,7 @@ pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *stm fz_try(ctx) { - fontdesc->font = fz_new_font_from_memory(ctx, buf->data, buf->len, 0, 1); + fontdesc->font = fz_new_font_from_memory(ctx, fontname, buf->data, buf->len, 0, 1); } fz_catch(ctx) { @@ -419,13 +407,13 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) pdf_obj *widths; unsigned short *etable = NULL; pdf_font_desc *fontdesc = NULL; + char *subtype; FT_Face face; FT_CharMap cmap; int symbolic; int kind; char *basefont; - char *fontname; char *estrings[256]; char ebuffer[256][32]; int i, k, n; @@ -436,7 +424,6 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) fz_var(etable); basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); - fontname = clean_font_name(basefont); /* Load font file */ fz_try(ctx) @@ -447,15 +434,14 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) if (descriptor) pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont); else - pdf_load_builtin_font(ctx, fontdesc, fontname); + pdf_load_builtin_font(ctx, fontdesc, basefont); /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */ - if (!*fontdesc->font->name && + if (descriptor && pdf_is_string(pdf_dict_gets(descriptor, "FontName")) && !pdf_dict_gets(dict, "ToUnicode") && !strcmp(pdf_to_name(pdf_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && pdf_to_int(pdf_dict_gets(descriptor, "Flags")) == 4) { - /* note: without the comma, pdf_load_font_descriptor would prefer /FontName over /BaseFont */ char *cp936fonts[] = { "\xCB\xCE\xCC\xE5", "SimSun,Regular", "\xBA\xDA\xCC\xE5", "SimHei,Regular", @@ -512,6 +498,8 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) cmap = test; if (test->platform_id == 3 && test->encoding_id == 1) cmap = test; + if (symbolic && test->platform_id == 3 && test->encoding_id == 0) + cmap = test; } } @@ -558,10 +546,8 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); - if (pdf_is_name(item)) + if (pdf_is_name(item) && k >= 0 && k < 256) estrings[k++] = pdf_to_name(item); - if (k < 0) k = 0; - if (k > 255) k = 255; } } } @@ -571,8 +557,22 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) for (i = 0; i < 256; i++) etable[i] = ft_char_index(face, i); - /* encode by glyph name where we can */ fz_lock(ctx, FZ_LOCK_FREETYPE); + + /* built-in and substitute fonts may be a different type than what the document expects */ + subtype = pdf_to_name(pdf_dict_gets(dict, "Subtype")); + if (!strcmp(subtype, "Type1")) + kind = TYPE1; + else if (!strcmp(subtype, "MMType1")) + kind = TYPE1; + else if (!strcmp(subtype, "TrueType")) + kind = TRUETYPE; + else if (!strcmp(subtype, "CIDFontType0")) + kind = TYPE1; + else if (!strcmp(subtype, "CIDFontType2")) + kind = TRUETYPE; + + /* encode by glyph name where we can */ if (kind == TYPE1) { for (i = 0; i < 256; i++) @@ -632,7 +632,7 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) } /* Symbolic cmap */ - else + else if (!face->charmap || face->charmap->encoding != FT_ENCODING_MS_SYMBOL) { for (i = 0; i < 256; i++) { @@ -665,6 +665,15 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) } } } + + /* symbolic Type 1 fonts with an implicit encoding and non-standard glyph names */ + if (kind == TYPE1 && symbolic) + { + for (i = 0; i < 256; i++) + if (etable[i] && estrings[i] && !pdf_lookup_agl(estrings[i])) + estrings[i] = (char*) pdf_standard[i]; + } + fz_unlock(ctx, FZ_LOCK_FREETYPE); fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); @@ -672,8 +681,14 @@ pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; - pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); - /* RJW: "cannot load to_unicode" */ + fz_try(ctx) + { + pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); + } + fz_catch(ctx) + { + fz_warn(ctx, "cannot load ToUnicode CMap"); + } skip_encoding: @@ -732,7 +747,7 @@ load_cid_font(pdf_document *xref, pdf_obj *dict, pdf_obj *encoding, pdf_obj *to_ { pdf_obj *widths; pdf_obj *descriptor; - pdf_font_desc *fontdesc; + pdf_font_desc *fontdesc = NULL; FT_Face face; int kind; char collection[256]; @@ -996,15 +1011,14 @@ static void pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *dict, char *collection, char *basefont) { pdf_obj *obj1, *obj2, *obj3, *obj; - char *fontname; - char *origname; + char *fontname, *origname; FT_Face face; fz_context *ctx = xref->ctx; - if (!strchr(basefont, ',') || strchr(basefont, '+')) - origname = pdf_to_name(pdf_dict_gets(dict, "FontName")); - else - origname = basefont; + /* Prefer BaseFont; don't bother with FontName */ + origname = basefont; + + /* Look through list of alternate names for built in fonts */ fontname = clean_font_name(origname); fontdesc->flags = pdf_to_int(pdf_dict_gets(dict, "Flags")); @@ -1024,7 +1038,7 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *d { fz_try(ctx) { - pdf_load_embedded_font(fontdesc, xref, obj); + pdf_load_embedded_font(xref, fontdesc, fontname, obj); } fz_catch(ctx) { @@ -1033,7 +1047,6 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *d pdf_load_builtin_font(ctx, fontdesc, fontname); else pdf_load_system_font(ctx, fontdesc, fontname, collection); - /* RJW: "cannot load font descriptor (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ } } else @@ -1042,11 +1055,8 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *d pdf_load_builtin_font(ctx, fontdesc, fontname); else pdf_load_system_font(ctx, fontdesc, fontname, collection); - /* RJW: "cannot load font descriptor (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ } - fz_strlcpy(fontdesc->font->name, fontname, sizeof fontdesc->font->name); - /* Check for DynaLab fonts that must use hinting */ face = fontdesc->font->ft_face; if (ft_kind(face) == TRUETYPE) @@ -1076,6 +1086,7 @@ pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc) font->width_count = n + 1; font->width_table = fz_malloc_array(ctx, font->width_count, sizeof(int)); + memset(font->width_table, 0, font->width_count * sizeof(int)); fontdesc->size += font->width_count * sizeof(int); for (i = 0; i < fontdesc->hmtx_len; i++) @@ -1085,7 +1096,7 @@ pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc) cid = pdf_lookup_cmap(fontdesc->encoding, k); gid = pdf_font_cid_to_gid(ctx, fontdesc, cid); if (gid >= 0 && gid < font->width_count) - font->width_table[gid] = fontdesc->hmtx[i].w; + font->width_table[gid] = fz_maxi(fontdesc->hmtx[i].w, font->width_table[gid]); } } } @@ -1144,6 +1155,7 @@ pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) return fontdesc; } +#ifndef NDEBUG void pdf_print_font(fz_context *ctx, pdf_font_desc *fontdesc) { @@ -1175,6 +1187,7 @@ pdf_print_font(fz_context *ctx, pdf_font_desc *fontdesc) printf("\t}\n"); } } +#endif fz_rect pdf_measure_text(fz_context *ctx, pdf_font_desc *fontdesc, unsigned char *buf, int len) { diff --git a/pdf/pdf_function.c b/pdf/pdf_function.c index 7c123476..eab7bedf 100644 --- a/pdf/pdf_function.c +++ b/pdf/pdf_function.c @@ -117,6 +117,7 @@ struct ps_stack_s int sp; }; +#ifndef NDEBUG void pdf_debug_ps_stack(ps_stack *st) { @@ -147,6 +148,7 @@ pdf_debug_ps_stack(ps_stack *st) printf("\n"); } +#endif static void ps_init_stack(ps_stack *st) @@ -914,6 +916,8 @@ eval_postscript_func(fz_context *ctx, pdf_function *func, float *in, float *out) * Sample function */ +#define MAX_SAMPLE_FUNCTION_SIZE (100 << 20) + static void load_sample_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, int gen) { @@ -927,59 +931,68 @@ load_sample_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, func->u.sa.samples = NULL; obj = pdf_dict_gets(dict, "Size"); - if (!pdf_is_array(obj) || pdf_array_len(obj) != func->m) - fz_throw(ctx, "malformed /Size"); + if (pdf_array_len(obj) < func->m) + fz_throw(ctx, "too few sample function dimension sizes"); + if (pdf_array_len(obj) > func->m) + fz_warn(ctx, "too many sample function dimension sizes"); for (i = 0; i < func->m; i++) + { func->u.sa.size[i] = pdf_to_int(pdf_array_get(obj, i)); + if (func->u.sa.size[i] < 0) + { + fz_warn(ctx, "negative sample function dimension size"); + func->u.sa.size[i] = 1; + } + } obj = pdf_dict_gets(dict, "BitsPerSample"); - if (!pdf_is_int(obj)) - fz_throw(ctx, "malformed /BitsPerSample"); func->u.sa.bps = bps = pdf_to_int(obj); + for (i = 0; i < func->m; i++) + { + func->u.sa.encode[i][0] = 0; + func->u.sa.encode[i][1] = func->u.sa.size[i] - 1; + } obj = pdf_dict_gets(dict, "Encode"); if (pdf_is_array(obj)) { - if (pdf_array_len(obj) != func->m * 2) - fz_throw(ctx, "malformed /Encode"); - for (i = 0; i < func->m; i++) + int ranges = fz_mini(func->m, pdf_array_len(obj) / 2); + if (ranges != func->m) + fz_warn(ctx, "too few/many sample function input mappings"); + + for (i = 0; i < ranges; i++) { - func->u.sa.encode[i][0] = pdf_to_real(pdf_array_get(obj, i*2+0)); - func->u.sa.encode[i][1] = pdf_to_real(pdf_array_get(obj, i*2+1)); + func->u.sa.encode[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); + func->u.sa.encode[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1)); } } - else + + for (i = 0; i < func->n; i++) { - for (i = 0; i < func->m; i++) - { - func->u.sa.encode[i][0] = 0; - func->u.sa.encode[i][1] = func->u.sa.size[i] - 1; - } + func->u.sa.decode[i][0] = func->range[i][0]; + func->u.sa.decode[i][1] = func->range[i][1]; } obj = pdf_dict_gets(dict, "Decode"); if (pdf_is_array(obj)) { - if (pdf_array_len(obj) != func->n * 2) - fz_throw(ctx, "malformed /Decode"); - for (i = 0; i < func->n; i++) - { - func->u.sa.decode[i][0] = pdf_to_real(pdf_array_get(obj, i*2+0)); - func->u.sa.decode[i][1] = pdf_to_real(pdf_array_get(obj, i*2+1)); - } - } - else - { - for (i = 0; i < func->n; i++) + int ranges = fz_mini(func->n, pdf_array_len(obj) / 2); + if (ranges != func->n) + fz_warn(ctx, "too few/many sample function output mappings"); + + for (i = 0; i < ranges; i++) { - func->u.sa.decode[i][0] = func->range[i][0]; - func->u.sa.decode[i][1] = func->range[i][1]; + func->u.sa.decode[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); + func->u.sa.decode[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1)); } } for (i = 0, samplecount = func->n; i < func->m; i++) samplecount *= func->u.sa.size[i]; + if (samplecount > MAX_SAMPLE_FUNCTION_SIZE) + fz_throw(ctx, "sample function too large"); + func->u.sa.samples = fz_malloc_array(ctx, samplecount, sizeof(float)); func->size += samplecount * sizeof(float); @@ -995,7 +1008,7 @@ load_sample_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, if (fz_is_eof_bits(stream)) { fz_close(stream); - fz_throw(ctx, "truncated sample stream"); + fz_throw(ctx, "truncated sample function stream"); } switch (bps) @@ -1131,43 +1144,57 @@ load_exponential_func(fz_context *ctx, pdf_function *func, pdf_obj *dict) pdf_obj *obj; int i; - if (func->m != 1) - fz_throw(ctx, "/Domain must be one dimension (%d)", func->m); + if (func->m > 1) + fz_warn(ctx, "exponential functions have at most one input"); + func->m = 1; obj = pdf_dict_gets(dict, "N"); - if (!pdf_is_int(obj) && !pdf_is_real(obj)) - fz_throw(ctx, "malformed /N"); func->u.e.n = pdf_to_real(obj); + /* See exponential functions (PDF 1.7 section 3.9.2) */ + if (func->u.e.n != (int) func->u.e.n) + { + /* If N is non-integer, input values may never be negative */ + for (i = 0; i < func->m; i++) + if (func->domain[i][0] < 0 || func->domain[i][1] < 0) + fz_warn(ctx, "exponential function input domain includes illegal negative input values"); + } + else if (func->u.e.n < 0) + { + /* if N is negative, input values may never be zero */ + for (i = 0; i < func->m; i++) + if (func->domain[i][0] == 0 || func->domain[i][1] == 0 || + (func->domain[i][0] < 0 && func->domain[i][1] > 0)) + fz_warn(ctx, "exponential function input domain includes illegal input value zero"); + } + + for (i = 0; i < func->n; i++) + { + func->u.e.c0[i] = 0; + func->u.e.c1[i] = 1; + } + obj = pdf_dict_gets(dict, "C0"); if (pdf_is_array(obj)) { - func->n = pdf_array_len(obj); - if (func->n >= MAXN) - fz_throw(ctx, "exponential function result array out of range"); - for (i = 0; i < func->n; i++) + int ranges = fz_mini(func->n, pdf_array_len(obj)); + if (ranges != func->n) + fz_warn(ctx, "too few/many C0 constants for exponential function"); + + for (i = 0; i < ranges; i++) func->u.e.c0[i] = pdf_to_real(pdf_array_get(obj, i)); } - else - { - func->n = 1; - func->u.e.c0[0] = 0; - } obj = pdf_dict_gets(dict, "C1"); if (pdf_is_array(obj)) { - if (pdf_array_len(obj) != func->n) - fz_throw(ctx, "/C1 must match /C0 length"); - for (i = 0; i < func->n; i++) + int ranges = fz_mini(func->n, pdf_array_len(obj)); + if (ranges != func->n) + fz_warn(ctx, "too few/many C1 constants for exponential function"); + + for (i = 0; i < ranges; i++) func->u.e.c1[i] = pdf_to_real(pdf_array_get(obj, i)); } - else - { - if (func->n != 1) - fz_throw(ctx, "/C1 must match /C0 length"); - func->u.e.c1[0] = 1; - } } static void @@ -1179,12 +1206,9 @@ eval_exponential_func(fz_context *ctx, pdf_function *func, float in, float *out) x = fz_clamp(x, func->domain[0][0], func->domain[0][1]); - /* constraint */ + /* Default output is zero, which is suitable for violated constraints */ if ((func->u.e.n != (int)func->u.e.n && x < 0) || (func->u.e.n < 0 && x == 0)) - { - fz_warn(ctx, "constraint error"); return; - } tmp = powf(x, func->u.e.n); for (i = 0; i < func->n; i++) @@ -1212,8 +1236,9 @@ load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict) func->u.st.k = 0; - if (func->m != 1) - fz_throw(ctx, "/Domain must be one dimension (%d)", func->m); + if (func->m > 1) + fz_warn(ctx, "stitching functions have at most one input"); + func->m = 1; obj = pdf_dict_gets(dict, "Functions"); if (!pdf_is_array(obj)) @@ -1229,7 +1254,7 @@ load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict) for (i = 0; i < k; i++) { sub = pdf_array_get(obj, i); - funcs[i] = pdf_load_function(xref, sub); + funcs[i] = pdf_load_function(xref, sub, 1, func->n); /* RJW: "cannot load sub function %d (%d %d R)", i, pdf_to_num(sub), pdf_to_gen(sub) */ if (funcs[i]->m != 1 || funcs[i]->n != funcs[0]->n) fz_throw(ctx, "sub function %d /Domain or /Range mismatch", i); @@ -1237,9 +1262,7 @@ load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict) func->u.st.k ++; } - if (!func->n) - func->n = funcs[0]->n; - else if (func->n != funcs[0]->n) + if (func->n != funcs[0]->n) fz_throw(ctx, "sub function /Domain or /Range mismatch"); } @@ -1247,34 +1270,41 @@ load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict) if (!pdf_is_array(obj)) fz_throw(ctx, "stitching function has no bounds"); { - if (pdf_array_len(obj) != k - 1) - fz_throw(ctx, "malformed /Bounds (wrong length)"); + if (pdf_array_len(obj) < k - 1) + fz_throw(ctx, "too few subfunction boundaries"); + if (pdf_array_len(obj) > k) + fz_warn(ctx, "too many subfunction boundaries"); - for (i = 0; i < k-1; i++) + for (i = 0; i < k - 1; i++) { num = pdf_array_get(obj, i); - if (!pdf_is_int(num) && !pdf_is_real(num)) - fz_throw(ctx, "malformed /Bounds (item not real)"); func->u.st.bounds[i] = pdf_to_real(num); - if (i && func->u.st.bounds[i-1] > func->u.st.bounds[i]) - fz_throw(ctx, "malformed /Bounds (item not monotonic)"); + if (i && func->u.st.bounds[i - 1] > func->u.st.bounds[i]) + fz_throw(ctx, "subfunction %d boundary out of range", i); } - if (k != 1 && (func->domain[0][0] > func->u.st.bounds[0] || - func->domain[0][1] < func->u.st.bounds[k-2])) - fz_warn(ctx, "malformed shading function bounds (domain mismatch), proceeding anyway."); + if (k > 1 && (func->domain[0][0] > func->u.st.bounds[0] || + func->domain[0][1] < func->u.st.bounds[k - 2])) + fz_warn(ctx, "subfunction boundaries outside of input mapping"); + } + + for (i = 0; i < k; i++) + { + func->u.st.encode[i * 2 + 0] = 0; + func->u.st.encode[i * 2 + 1] = 0; } obj = pdf_dict_gets(dict, "Encode"); - if (!pdf_is_array(obj)) - fz_throw(ctx, "stitching function is missing encoding"); + if (pdf_is_array(obj)) { - if (pdf_array_len(obj) != k * 2) - fz_throw(ctx, "malformed /Encode"); - for (i = 0; i < k; i++) + int ranges = fz_mini(k, pdf_array_len(obj) / 2); + if (ranges != k) + fz_warn(ctx, "too few/many stitching function input mappings"); + + for (i = 0; i < ranges; i++) { - func->u.st.encode[i*2+0] = pdf_to_real(pdf_array_get(obj, i*2+0)); - func->u.st.encode[i*2+1] = pdf_to_real(pdf_array_get(obj, i*2+1)); + func->u.st.encode[i * 2 + 0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); + func->u.st.encode[i * 2 + 1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1)); } } } @@ -1307,16 +1337,16 @@ eval_stitching_func(fz_context *ctx, pdf_function *func, float in, float *out) } else if (i == k - 1) { - low = bounds[k-2]; + low = bounds[k - 2]; high = func->domain[0][1]; } else { - low = bounds[i-1]; + low = bounds[i - 1]; high = bounds[i]; } - in = lerp(in, low, high, func->u.st.encode[i*2+0], func->u.st.encode[i*2+1]); + in = lerp(in, low, high, func->u.st.encode[i * 2 + 0], func->u.st.encode[i * 2 + 1]); pdf_eval_function(ctx, func->u.st.funcs[i], &in, 1, out, func->n); } @@ -1371,7 +1401,7 @@ pdf_function_size(pdf_function *func) } pdf_function * -pdf_load_function(pdf_document *xref, pdf_obj *dict) +pdf_load_function(pdf_document *xref, pdf_obj *dict, int in, int out) { fz_context *ctx = xref->ctx; pdf_function *func; @@ -1392,7 +1422,7 @@ pdf_load_function(pdf_document *xref, pdf_obj *dict) /* required for all */ obj = pdf_dict_gets(dict, "Domain"); - func->m = pdf_array_len(obj) / 2; + func->m = fz_clampi(pdf_array_len(obj) / 2, 1, MAXN); for (i = 0; i < func->m; i++) { func->domain[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); @@ -1404,7 +1434,7 @@ pdf_load_function(pdf_document *xref, pdf_obj *dict) if (pdf_is_array(obj)) { func->has_range = 1; - func->n = pdf_array_len(obj) / 2; + func->n = fz_clampi(pdf_array_len(obj) / 2, 1, MAXN); for (i = 0; i < func->n; i++) { func->range[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); @@ -1414,14 +1444,13 @@ pdf_load_function(pdf_document *xref, pdf_obj *dict) else { func->has_range = 0; - func->n = 0; + func->n = out; } - if (func->m >= MAXM || func->n >= MAXN) - { - fz_free(ctx, func); - fz_throw(ctx, "assert: /Domain or /Range too big"); - } + if (func->m != in) + fz_warn(ctx, "too few/many function inputs"); + if (func->n != out) + fz_warn(ctx, "too few/many function outputs"); fz_try(ctx) { @@ -1467,20 +1496,27 @@ pdf_load_function(pdf_document *xref, pdf_obj *dict) } void -pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, float *out, int outlen) +pdf_eval_function(fz_context *ctx, pdf_function *func, float *in_, int inlen, float *out_, int outlen) { - memset(out, 0, sizeof(float) * outlen); + float fakein[MAXN]; + float fakeout[MAXN]; + float *in = in_; + float *out = out_; - if (inlen != func->m) + if (inlen < func->m) { - fz_warn(ctx, "tried to evaluate function with wrong number of inputs"); - return; + in = fakein; + memset(in, 0, sizeof(float) * func->m); + memcpy(in, in_, sizeof(float) * inlen); } - if (func->n != outlen) + + if (outlen < func->n) { - fz_warn(ctx, "tried to evaluate function with wrong number of outputs"); - return; + out = fakeout; + memset(out, 0, sizeof(float) * func->n); } + else + memset(out, 0, sizeof(float) * outlen); switch(func->type) { @@ -1489,12 +1525,16 @@ pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, flo case STITCHING: eval_stitching_func(ctx, func, *in, out); break; case POSTSCRIPT: eval_postscript_func(ctx, func, in, out); break; } + + if (outlen < func->n) + memcpy(out_, out, sizeof(float) * outlen); } /* * Debugging prints */ +#ifndef NDEBUG static void pdf_debug_indent(char *prefix, int level, char *suffix) { @@ -1710,3 +1750,4 @@ pdf_debug_function(pdf_function *func) { pdf_debug_function_imp(func, 0); } +#endif diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index b4571bbe..58a17ed0 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -77,6 +77,7 @@ pdf_cmp_image_key(void *k0_, void *k1_) return k0->image == k1->image && k0->factor == k1->factor; } +#ifndef NDEBUG static void pdf_debug_image(void *key_) { @@ -84,6 +85,7 @@ pdf_debug_image(void *key_) printf("(image %d x %d sf=%d) ", key->image->w, key->image->h, key->factor); } +#endif static fz_store_type pdf_image_store_type = { @@ -91,7 +93,9 @@ static fz_store_type pdf_image_store_type = pdf_keep_image_key, pdf_drop_image_key, pdf_cmp_image_key, +#ifndef NDEBUG pdf_debug_image +#endif }; static fz_pixmap * @@ -339,12 +343,12 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c if (imagemask) bpc = 1; - if (w == 0) - fz_throw(ctx, "image width is zero"); - if (h == 0) - fz_throw(ctx, "image height is zero"); - if (bpc == 0) - fz_throw(ctx, "image depth is zero"); + if (w <= 0) + fz_throw(ctx, "image width is zero (or less)"); + if (h <= 0) + fz_throw(ctx, "image height is zero (or less)"); + if (bpc <= 0) + fz_throw(ctx, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, "image depth is too large: %d", bpc); if (w > (1 << 16)) diff --git a/pdf/pdf_object.c b/pdf/pdf_object.c index 531eb8eb..7021fa5d 100644 --- a/pdf/pdf_object.c +++ b/pdf/pdf_object.c @@ -1452,6 +1452,7 @@ pdf_fprint_obj(FILE *fp, pdf_obj *obj, int tight) return n; } +#ifndef NDEBUG void pdf_print_obj(pdf_obj *obj) { @@ -1463,3 +1464,4 @@ pdf_print_ref(pdf_obj *ref) { pdf_print_obj(pdf_resolve_indirect(ref)); } +#endif diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c index c094e830..c1d454f0 100644 --- a/pdf/pdf_page.c +++ b/pdf/pdf_page.c @@ -161,7 +161,7 @@ pdf_load_page_tree(pdf_document *xref) if (!pdf_is_dict(pages)) fz_throw(ctx, "missing page tree"); - if (!pdf_is_int(count)) + if (!pdf_is_int(count) || pdf_to_int(count) < 0) fz_throw(ctx, "missing page count"); xref->page_cap = pdf_to_int(count); diff --git a/pdf/pdf_shade.c b/pdf/pdf_shade.c index 2d9e74b8..9e056c14 100644 --- a/pdf/pdf_shade.c +++ b/pdf/pdf_shade.c @@ -984,7 +984,7 @@ pdf_load_shading_dict(pdf_document *xref, pdf_obj *dict, fz_matrix transform) pdf_obj *obj; int funcs = 0; int type = 0; - int i; + int i, in, out; fz_context *ctx = xref->ctx; fz_var(shade); @@ -1040,7 +1040,13 @@ pdf_load_shading_dict(pdf_document *xref, pdf_obj *dict, fz_matrix transform) { funcs = 1; - func[0] = pdf_load_function(xref, obj); + if (type == 1) + in = 2; + else + in = 1; + out = shade->colorspace->n; + + func[0] = pdf_load_function(xref, obj, in, out); if (!func[0]) fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } @@ -1050,9 +1056,15 @@ pdf_load_shading_dict(pdf_document *xref, pdf_obj *dict, fz_matrix transform) if (funcs != 1 && funcs != shade->colorspace->n) fz_throw(ctx, "incorrect number of shading functions"); + if (type == 1) + in = 2; + else + in = 1; + out = 1; + for (i = 0; i < funcs; i++) { - func[i] = pdf_load_function(xref, pdf_array_get(obj, i)); + func[i] = pdf_load_function(xref, pdf_array_get(obj, i), in, out); if (!func[i]) fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } diff --git a/pdf/pdf_store.c b/pdf/pdf_store.c index 2a3b8b07..2b20fca1 100644 --- a/pdf/pdf_store.c +++ b/pdf/pdf_store.c @@ -31,6 +31,7 @@ pdf_cmp_key(void *k0, void *k1) return pdf_objcmp((pdf_obj *)k0, (pdf_obj *)k1); } +#ifndef NDEBUG static void pdf_debug_key(void *key_) { @@ -42,6 +43,7 @@ pdf_debug_key(void *key_) } else pdf_print_obj(key); } +#endif static fz_store_type pdf_obj_store_type = { @@ -49,7 +51,9 @@ static fz_store_type pdf_obj_store_type = pdf_keep_key, pdf_drop_key, pdf_cmp_key, +#ifndef NDEBUG pdf_debug_key +#endif }; void diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c index 829210ea..a4af8e39 100644 --- a/pdf/pdf_stream.c +++ b/pdf/pdf_stream.c @@ -59,10 +59,10 @@ build_filter(fz_stream *chain, pdf_document * xref, pdf_obj * f, pdf_obj * p, in int colors = pdf_to_int(pdf_dict_gets(p, "Colors")); int bpc = pdf_to_int(pdf_dict_gets(p, "BitsPerComponent")); - if (predictor == 0) predictor = 1; - if (columns == 0) columns = 1; - if (colors == 0) colors = 1; - if (bpc == 0) bpc = 8; + if (predictor <= 0) predictor = 1; + if (columns <= 0) columns = 1; + if (colors <= 0) colors = 1; + if (bpc <= 0) bpc = 8; if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx")) return fz_open_ahxd(chain); diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c index 4df46ce3..bd60216d 100644 --- a/pdf/pdf_type3.c +++ b/pdf/pdf_type3.c @@ -89,8 +89,7 @@ pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) k = pdf_to_int(item); if (pdf_is_name(item)) estrings[k++] = pdf_to_name(item); - if (k < 0) k = 0; - if (k > 255) k = 255; + k = fz_clampi(k, 0, 255); } } } @@ -107,6 +106,9 @@ pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); + if (first < 0 || last > 255 || first > last) + first = last = 0; + widths = pdf_dict_gets(dict, "Widths"); if (!widths) { diff --git a/pdf/pdf_write.c b/pdf/pdf_write.c index 3527961f..76f19748 100644 --- a/pdf/pdf_write.c +++ b/pdf/pdf_write.c @@ -616,7 +616,7 @@ static void compactxref(pdf_document *xref, pdf_write_options *opts) for (num = 1; num < xref->len; num++) { /* If it's not used, map it to zero */ - if (!opts->use_list[num]) + if (!opts->use_list[opts->renumber_map[num]]) { opts->renumber_map[num] = 0; } @@ -731,7 +731,7 @@ static void renumberobjs(pdf_document *xref, pdf_write_options *opts) if (newlen < opts->renumber_map[num]) newlen = opts->renumber_map[num]; xref->table[opts->renumber_map[num]] = oldxref[num]; - new_use_list[opts->renumber_map[num]] = opts->use_list[num]; + new_use_list[opts->renumber_map[num]] = 1; } else { @@ -2120,6 +2120,9 @@ void pdf_write_document(pdf_document *xref, char *filename, fz_write_options *fz /* Sweep & mark objects from the trailer */ if (opts.do_garbage >= 1) sweepobj(xref, &opts, xref->trailer); + else + for (num = 0; num < xref->len; num++) + opts.use_list[num] = 1; /* Coalesce and renumber duplicate objects */ if (opts.do_garbage >= 3) diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c index 4a03751c..ab8a3364 100644 --- a/pdf/pdf_xref.c +++ b/pdf/pdf_xref.c @@ -273,7 +273,9 @@ pdf_read_new_xref_section(pdf_document *xref, fz_stream *stm, int i0, int i1, in { int i, n; - if (i0 < 0 || i0 + i1 > xref->len) + if (i0 < 0 || i1 < 0) + fz_throw(xref->ctx, "negative xref stream entry index"); + if (i0 + i1 > xref->len) fz_throw(xref->ctx, "xref stream has too many entries"); for (i = i0; i < i0 + i1; i++) @@ -347,6 +349,17 @@ pdf_read_new_xref(pdf_document *xref, pdf_lexbuf *buf) w1 = pdf_to_int(pdf_array_get(obj, 1)); w2 = pdf_to_int(pdf_array_get(obj, 2)); + if (w0 < 0) + fz_warn(ctx, "xref stream objects have corrupt type"); + if (w1 < 0) + fz_warn(ctx, "xref stream objects have corrupt offset"); + if (w2 < 0) + fz_warn(ctx, "xref stream objects have corrupt generation"); + + w0 = w0 < 0 ? 0 : w0; + w1 = w1 < 0 ? 0 : w1; + w2 = w2 < 0 ? 0 : w2; + index = pdf_dict_gets(trailer, "Index"); stm = pdf_open_stream_with_offset(xref, num, gen, trailer, stm_ofs); @@ -434,12 +447,17 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf) xrefstmofs = pdf_to_int(pdf_dict_gets(trailer, "XRefStm")); prevofs = pdf_to_int(pdf_dict_gets(trailer, "Prev")); + if (xrefstmofs < 0) + fz_throw(ctx, "negative xref stream offset"); + if (prevofs < 0) + fz_throw(ctx, "negative xref stream offset for previous xref stream"); + /* We only recurse if we have both xrefstm and prev. * Hopefully this happens infrequently. */ if (xrefstmofs && prevofs) pdf_read_xref_sections(xref, xrefstmofs, buf); if (prevofs) - ofs = prevofs; + ofs = prevofs; else if (xrefstmofs) ofs = xrefstmofs; pdf_drop_obj(trailer); @@ -477,7 +495,8 @@ pdf_load_xref(pdf_document *xref, pdf_lexbuf *buf) if (!size) fz_throw(ctx, "trailer missing Size entry"); - pdf_resize_xref(xref, size); + if (size > xref->len) + pdf_resize_xref(xref, size); pdf_read_xref_sections(xref, xref->startxref, buf); @@ -892,6 +911,11 @@ pdf_load_obj_stm(pdf_document *xref, int num, int gen, pdf_lexbuf *buf) count = pdf_to_int(pdf_dict_gets(objstm, "N")); first = pdf_to_int(pdf_dict_gets(objstm, "First")); + if (count < 0) + fz_throw(ctx, "negative number of objects in object stream"); + if (first < 0) + fz_throw(ctx, "first object in object stream resides outside stream"); + numbuf = fz_calloc(ctx, count, sizeof(int)); ofsbuf = fz_calloc(ctx, count, sizeof(int)); diff --git a/xps/xps_glyphs.c b/xps/xps_glyphs.c index f75815f0..6a7a1dcc 100644 --- a/xps/xps_glyphs.c +++ b/xps/xps_glyphs.c @@ -332,6 +332,9 @@ xps_parse_glyphs_imp(xps_document *doc, fz_matrix ctm, else advance = mtx.hadv * 100; + if (font->ft_bold) + advance *= 1.02f; + if (is && *is) { is = xps_parse_glyph_metrics(is, &advance, &u_offset, &v_offset); @@ -517,7 +520,7 @@ xps_parse_glyphs(xps_document *doc, fz_matrix ctm, fz_try(doc->ctx) { - font = fz_new_font_from_memory(doc->ctx, part->data, part->size, subfontid, 1); + font = fz_new_font_from_memory(doc->ctx, NULL, part->data, part->size, subfontid, 1); } fz_catch(doc->ctx) { diff --git a/xps/xps_path.c b/xps/xps_path.c index 696a78b9..8650fbb8 100644 --- a/xps/xps_path.c +++ b/xps/xps_path.c @@ -35,40 +35,6 @@ xps_parse_point(char *s_in, float *x, float *y) return s_out; } -static fz_point -fz_currentpoint(fz_path *path) -{ - fz_point c, m; - int i; - - c.x = c.y = m.x = m.y = 0; - i = 0; - - while (i < path->len) - { - switch (path->items[i++].k) - { - case FZ_MOVETO: - m.x = c.x = path->items[i++].v; - m.y = c.y = path->items[i++].v; - break; - case FZ_LINETO: - c.x = path->items[i++].v; - c.y = path->items[i++].v; - break; - case FZ_CURVETO: - i += 4; - c.x = path->items[i++].v; - c.y = path->items[i++].v; - break; - case FZ_CLOSE_PATH: - c = m; - } - } - - return c; -} - /* Draw an arc segment transformed by the matrix, we approximate with straight * line segments. We cannot use the fz_arc function because they only draw * circular arcs, we need to transform the line to make them elliptical but @@ -160,7 +126,7 @@ xps_draw_arc(fz_context *doc, fz_path *path, float sign; float th1, dth; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc, path); x1 = pt.x; y1 = pt.y; x2 = point_x; @@ -334,7 +300,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) break; case 'm': if (i + 1 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_moveto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y + fz_atof(args[i+1])); i += 2; break; @@ -346,33 +312,33 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) break; case 'l': if (i + 1 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y + fz_atof(args[i+1])); i += 2; break; case 'H': if (i >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, fz_atof(args[i]), pt.y); i += 1; break; case 'h': if (i >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y); i += 1; break; case 'V': if (i >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x, fz_atof(args[i])); i += 1; break; case 'v': if (i >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x, pt.y + fz_atof(args[i])); i += 1; break; @@ -394,7 +360,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) case 'c': if (i + 5 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; y1 = fz_atof(args[i+1]) + pt.y; x2 = fz_atof(args[i+2]) + pt.x; @@ -410,7 +376,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) case 'S': if (i + 3 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]); y1 = fz_atof(args[i+1]); x2 = fz_atof(args[i+2]); @@ -424,7 +390,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) case 's': if (i + 3 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; y1 = fz_atof(args[i+1]) + pt.y; x2 = fz_atof(args[i+2]) + pt.x; @@ -438,7 +404,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) case 'Q': if (i + 3 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]); y1 = fz_atof(args[i+1]); x2 = fz_atof(args[i+2]); @@ -451,7 +417,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) break; case 'q': if (i + 3 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; y1 = fz_atof(args[i+1]) + pt.y; x2 = fz_atof(args[i+2]) + pt.x; @@ -473,7 +439,7 @@ xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) break; case 'a': if (i + 6 >= n) break; - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc->ctx, path); xps_draw_arc(doc->ctx, path, fz_atof(args[i+0]), fz_atof(args[i+1]), fz_atof(args[i+2]), atoi(args[i+3]), atoi(args[i+4]), @@ -587,7 +553,7 @@ xps_parse_poly_quadratic_bezier_segment(fz_context *doc, fz_path *path, xml_elem } else { - pt = fz_currentpoint(path); + pt = fz_currentpoint(doc, path); fz_curveto(doc, path, (pt.x + 2 * x[0]) / 3, (pt.y + 2 * y[0]) / 3, (x[1] + 2 * x[0]) / 3, (y[1] + 2 * y[0]) / 3, |