summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2012-08-01 15:10:40 +0100
committerPaul Gardiner <paulg.artifex@glidos.net>2012-08-01 15:10:40 +0100
commitc8b8bbc851ae2089f515b5e65780198ad024c5cb (patch)
treeb1702dda67a2a6026e8870ec1a89d70545f69f2f
parent55743b7682129deb6cc03e90ebde1b0e6e62d3b4 (diff)
parent4d36e9613da5190aba2c0c6c8281e5d35cf9758c (diff)
downloadmupdf-c8b8bbc851ae2089f515b5e65780198ad024c5cb.tar.xz
Merge branch 'master' into forms
Conflicts: pdf/mupdf-internal.h pdf/pdf_font.c
-rw-r--r--apps/mudraw.c1
-rw-r--r--apps/mupdfinfo.c4
-rw-r--r--apps/mupdfshow.c6
-rw-r--r--apps/x11_main.c4
-rw-r--r--draw/draw_device.c68
-rw-r--r--draw/draw_edge.c12
-rw-r--r--draw/draw_glyph.c48
-rw-r--r--draw/draw_path.c4
-rw-r--r--fitz/base_hash.c2
-rw-r--r--fitz/fitz-internal.h48
-rw-r--r--fitz/fitz.h24
-rw-r--r--fitz/res_font.c179
-rw-r--r--fitz/res_path.c36
-rw-r--r--fitz/res_shade.c2
-rw-r--r--fitz/res_store.c2
-rw-r--r--pdf/mupdf-internal.h15
-rw-r--r--pdf/mupdf.h3
-rw-r--r--pdf/pdf_cmap.c2
-rw-r--r--pdf/pdf_colorspace.c2
-rw-r--r--pdf/pdf_crypt.c180
-rw-r--r--pdf/pdf_font.c135
-rw-r--r--pdf/pdf_function.c237
-rw-r--r--pdf/pdf_image.c16
-rw-r--r--pdf/pdf_object.c2
-rw-r--r--pdf/pdf_page.c2
-rw-r--r--pdf/pdf_shade.c18
-rw-r--r--pdf/pdf_store.c4
-rw-r--r--pdf/pdf_stream.c8
-rw-r--r--pdf/pdf_type3.c6
-rw-r--r--pdf/pdf_write.c7
-rw-r--r--pdf/pdf_xref.c30
-rw-r--r--xps/xps_glyphs.c5
-rw-r--r--xps/xps_path.c62
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,