summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2012-01-11 16:02:18 +0100
committerTor Andersson <tor.andersson@artifex.com>2012-01-11 16:02:18 +0100
commit177346693da57e72d1e6c01edbdf7ce75e010a3f (patch)
tree7cfa2037949f22b7263f05e0ca95820dc4b4fe2e
parent220b6f3565b8ec6da406acc08e8f09128b7c7346 (diff)
downloadmupdf-177346693da57e72d1e6c01edbdf7ce75e010a3f.tar.xz
Calculate accurate per-glyph bounding boxes for fz_bound_text.
-rw-r--r--draw/draw_device.c4
-rw-r--r--fitz/dev_bbox.c4
-rw-r--r--fitz/dev_list.c10
-rw-r--r--fitz/fitz.h11
-rw-r--r--fitz/res_font.c109
-rw-r--r--fitz/res_text.c63
-rw-r--r--pdf/pdf_font.c24
-rw-r--r--pdf/pdf_interpret.c2
-rw-r--r--pdf/pdf_type3.c4
-rw-r--r--xps/xps_glyphs.c2
10 files changed, 155 insertions, 78 deletions
diff --git a/draw/draw_device.c b/draw/draw_device.c
index f07ad681..07a2bb82 100644
--- a/draw/draw_device.c
+++ b/draw/draw_device.c
@@ -589,7 +589,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, fz_matrix ctm, int accumulate)
if (accumulate == 0)
{
/* make the mask the exact size needed */
- bbox = fz_round_rect(fz_bound_text(text, ctm));
+ bbox = fz_round_rect(fz_bound_text(dev->ctx, text, ctm));
bbox = fz_intersect_bbox(bbox, state->scissor);
}
else
@@ -670,7 +670,7 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke
fz_colorspace *model = state->dest->colorspace;
/* make the mask the exact size needed */
- bbox = fz_round_rect(fz_bound_text(text, ctm));
+ bbox = fz_round_rect(fz_bound_text(dev->ctx, text, ctm));
bbox = fz_intersect_bbox(bbox, state->scissor);
mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox);
diff --git a/fitz/dev_bbox.c b/fitz/dev_bbox.c
index 766adefa..9165407f 100644
--- a/fitz/dev_bbox.c
+++ b/fitz/dev_bbox.c
@@ -25,7 +25,7 @@ fz_bbox_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_bbox *result = dev->user;
- fz_bbox bbox = fz_round_rect(fz_bound_text(text, ctm));
+ fz_bbox bbox = fz_round_rect(fz_bound_text(dev->ctx, text, ctm));
*result = fz_union_bbox(*result, bbox);
}
@@ -34,7 +34,7 @@ fz_bbox_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_m
fz_colorspace *colorspace, float *color, float alpha)
{
fz_bbox *result = dev->user;
- fz_bbox bbox = fz_round_rect(fz_bound_text(text, ctm));
+ fz_bbox bbox = fz_round_rect(fz_bound_text(dev->ctx, text, ctm));
*result = fz_union_bbox(*result, bbox);
}
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index b77cb9e4..c1822227 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -320,7 +320,7 @@ fz_list_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm,
node = fz_new_display_node(ctx, FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha);
fz_try(ctx)
{
- node->rect = fz_bound_text(text, ctm);
+ node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
}
fz_catch(ctx)
@@ -341,7 +341,7 @@ fz_list_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_m
node->item.text = NULL;
fz_try(ctx)
{
- node->rect = fz_bound_text(text, ctm);
+ node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
}
@@ -361,7 +361,7 @@ fz_list_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate)
node = fz_new_display_node(ctx, FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0);
fz_try(ctx)
{
- node->rect = fz_bound_text(text, ctm);
+ node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
node->flag = accumulate;
/* when accumulating, be conservative about culling */
@@ -384,7 +384,7 @@ fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke,
node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0);
fz_try(ctx)
{
- node->rect = fz_bound_text(text, ctm);
+ node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
}
@@ -404,7 +404,7 @@ fz_list_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
node = fz_new_display_node(ctx, FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0);
fz_try(ctx)
{
- node->rect = fz_bound_text(text, ctm);
+ node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
}
fz_catch(ctx)
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 73017e2f..ddaa6fe3 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -1042,11 +1042,10 @@ struct fz_font_s
void (*t3run)(void *xref, fz_obj *resources, fz_buffer *contents,
struct fz_device_s *dev, fz_matrix ctm);
- fz_rect bbox;
+ fz_rect bbox; /* font bbox is used only for t3 fonts */
- /* substitute metrics */
int width_count;
- int *width_table;
+ int *width_table; /* substitute metrics */
};
void fz_new_font_context(fz_context *ctx);
@@ -1061,7 +1060,9 @@ fz_font *fz_keep_font(fz_font *font);
void fz_drop_font(fz_context *ctx, fz_font *font);
void fz_debug_font(fz_font *font);
+
void fz_set_font_bbox(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);
/*
* Vector path buffer.
@@ -1158,9 +1159,9 @@ struct fz_text_s
fz_text *fz_new_text(fz_context *ctx, fz_font *face, fz_matrix trm, int wmode);
void fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y);
void fz_free_text(fz_context *ctx, fz_text *text);
-void fz_debug_text(fz_text*, int indent);
-fz_rect fz_bound_text(fz_text *text, fz_matrix ctm);
+fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm);
fz_text *fz_clone_text(fz_context *ctx, fz_text *old);
+void fz_debug_text(fz_text*, int indent);
/*
* The shading code uses gouraud shaded triangle meshes.
diff --git a/fitz/res_font.c b/fitz/res_font.c
index 053b2a04..b224e7ac 100644
--- a/fitz/res_font.c
+++ b/fitz/res_font.c
@@ -38,8 +38,8 @@ fz_new_font(fz_context *ctx, char *name)
font->bbox.x0 = 0;
font->bbox.y0 = 0;
- font->bbox.x1 = 1000;
- font->bbox.y1 = 1000;
+ font->bbox.x1 = 1;
+ font->bbox.y1 = 1;
font->width_count = 0;
font->width_table = NULL;
@@ -216,10 +216,10 @@ fz_new_font_from_file(fz_context *ctx, char *path, int index)
font = fz_new_font(ctx, face->family_name);
font->ft_face = face;
- font->bbox.x0 = face->bbox.xMin * 1000 / face->units_per_EM;
- font->bbox.y0 = face->bbox.yMin * 1000 / face->units_per_EM;
- font->bbox.x1 = face->bbox.xMax * 1000 / face->units_per_EM;
- font->bbox.y1 = face->bbox.yMax * 1000 / face->units_per_EM;
+ font->bbox.x0 = (float) face->bbox.xMin / face->units_per_EM;
+ font->bbox.y0 = (float) face->bbox.yMin / face->units_per_EM;
+ font->bbox.x1 = (float) face->bbox.xMax / face->units_per_EM;
+ font->bbox.y1 = (float) face->bbox.yMax / face->units_per_EM;
return font;
}
@@ -242,10 +242,10 @@ fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index
font = fz_new_font(ctx, face->family_name);
font->ft_face = face;
- font->bbox.x0 = face->bbox.xMin * 1000 / face->units_per_EM;
- font->bbox.y0 = face->bbox.yMin * 1000 / face->units_per_EM;
- font->bbox.x1 = face->bbox.xMax * 1000 / face->units_per_EM;
- font->bbox.y1 = face->bbox.yMax * 1000 / face->units_per_EM;
+ font->bbox.x0 = (float) face->bbox.xMin / face->units_per_EM;
+ font->bbox.y0 = (float) face->bbox.yMin / face->units_per_EM;
+ font->bbox.x1 = (float) face->bbox.xMax / face->units_per_EM;
+ font->bbox.y1 = (float) face->bbox.yMax / face->units_per_EM;
return font;
}
@@ -254,7 +254,7 @@ static fz_matrix
fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
{
/* Fudge the font matrix to stretch the glyph if we've substituted the font. */
- if (font->ft_substitute && gid < font->width_count)
+ if (font->ft_substitute && font->width_table && gid < font->width_count)
{
FT_Error fterr;
int subw;
@@ -504,6 +504,68 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr
return pixmap;
}
+static fz_rect
+fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
+{
+ FT_Face face = font->ft_face;
+ FT_Error fterr;
+ FT_BBox cbox;
+ FT_Matrix m;
+ FT_Vector v;
+ fz_rect bounds;
+
+ // TODO: stroke state
+ // TODO: refactor loading into fz_load_ft_glyph
+ // TODO: cache results
+
+ trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm);
+
+ if (font->ft_italic)
+ trm = fz_concat(fz_shear(0.3f, 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 = trm.e * 64;
+ v.y = trm.f * 64;
+
+ 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));
+ bounds.x0 = bounds.x1 = trm.e;
+ bounds.y0 = bounds.y1 = trm.f;
+ return bounds;
+ }
+
+ 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);
+ }
+
+ FT_Outline_Get_CBox(&face->glyph->outline, &cbox);
+ bounds.x0 = cbox.xMin / 64.0f;
+ bounds.y0 = cbox.yMin / 64.0f;
+ bounds.x1 = cbox.xMax / 64.0f;
+ bounds.y1 = cbox.yMax / 64.0f;
+
+ if (fz_is_empty_rect(bounds))
+ {
+ bounds.x0 = bounds.x1 = trm.e;
+ bounds.y0 = bounds.y1 = trm.f;
+ }
+
+ return bounds;
+}
+
/*
* Type 3 fonts...
*/
@@ -528,6 +590,13 @@ fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix)
return font;
}
+static fz_rect
+fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
+{
+ trm = fz_concat(font->t3matrix, trm);
+ return fz_transform_rect(trm, font->bbox);
+}
+
fz_pixmap *
fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model)
{
@@ -613,11 +682,21 @@ fz_debug_font(fz_font *font)
printf("\ttype3 matrix [%g %g %g %g]\n",
font->t3matrix.a, font->t3matrix.b,
font->t3matrix.c, font->t3matrix.d);
- }
- printf("\tbbox [%g %g %g %g]\n",
- font->bbox.x0, font->bbox.y0,
- font->bbox.x1, font->bbox.y1);
+ printf("\ttype3 bbox [%g %g %g %g]\n",
+ font->bbox.x0, font->bbox.y0,
+ font->bbox.x1, font->bbox.y1);
+ }
printf("}\n");
}
+
+fz_rect
+fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
+{
+ if (font->ft_face)
+ return fz_bound_ft_glyph(ctx, font, gid, trm);
+ if (font->t3procs)
+ return fz_bound_t3_glyph(ctx, font, gid, trm);
+ return fz_empty_rect;
+}
diff --git a/fitz/res_text.c b/fitz/res_text.c
index fae2606b..79a07e86 100644
--- a/fitz/res_text.c
+++ b/fitz/res_text.c
@@ -53,57 +53,44 @@ fz_clone_text(fz_context *ctx, fz_text *old)
}
fz_rect
-fz_bound_text(fz_text *text, fz_matrix ctm)
+fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm)
{
- fz_matrix trm;
+ fz_matrix tm, trm;
fz_rect bbox;
- fz_rect fbox;
+ fz_rect gbox;
int i;
if (text->len == 0)
return fz_empty_rect;
- /* find bbox of glyph origins in ctm space */
+ tm = text->trm;
- bbox.x0 = bbox.x1 = text->items[0].x;
- bbox.y0 = bbox.y1 = text->items[0].y;
+ tm.e = text->items[0].x;
+ tm.f = text->items[0].y;
+ trm = fz_concat(tm, ctm);
+ bbox = fz_bound_glyph(ctx, text->font, text->items[0].gid, trm);
for (i = 1; i < text->len; i++)
{
- bbox.x0 = MIN(bbox.x0, text->items[i].x);
- bbox.y0 = MIN(bbox.y0, text->items[i].y);
- bbox.x1 = MAX(bbox.x1, text->items[i].x);
- bbox.y1 = MAX(bbox.y1, text->items[i].y);
+ if (text->items[i].gid >= 0)
+ {
+ tm.e = text->items[i].x;
+ tm.f = text->items[i].y;
+ trm = fz_concat(tm, ctm);
+ gbox = fz_bound_glyph(ctx, text->font, text->items[i].gid, trm);
+
+ bbox.x0 = MIN(bbox.x0, gbox.x0);
+ bbox.y0 = MIN(bbox.y0, gbox.y0);
+ bbox.x1 = MAX(bbox.x1, gbox.x1);
+ bbox.y1 = MAX(bbox.y1, gbox.y1);
+ }
}
- bbox = fz_transform_rect(ctm, bbox);
-
- /* find bbox of font in trm * ctm space */
-
- trm = fz_concat(text->trm, ctm);
- trm.e = 0;
- trm.f = 0;
-
- fbox.x0 = text->font->bbox.x0 * 0.001f;
- fbox.y0 = text->font->bbox.y0 * 0.001f;
- fbox.x1 = text->font->bbox.x1 * 0.001f;
- fbox.y1 = text->font->bbox.y1 * 0.001f;
-
- fbox = fz_transform_rect(trm, fbox);
-
- /* expand glyph origin bbox by font bbox */
-
- bbox.x0 += fbox.x0;
- bbox.y0 += fbox.y0;
- bbox.x1 += fbox.x1;
- bbox.y1 += fbox.y1;
-
- /* add some fuzz at the edges, as font bbox is often not accurate.
- * Better to localise this fuzz in just this one place than have it
- * everywhere that looks at these results. If we ever change to using
- * freetype to exactly bound text, we can remove this. */
- bbox.x0 -= 20; bbox.y0 -= 20;
- bbox.x1 += 20; bbox.y1 += 20;
+ /* Compensate for the glyph cache limited positioning precision */
+ bbox.x0 -= 1;
+ bbox.y0 -= 1;
+ bbox.x1 += 1;
+ bbox.y1 += 1;
return bbox;
}
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index 16223be7..76d4632a 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -1031,25 +1031,31 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *dict,
}
}
-static void
-pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc)
+static int
+pdf_count_font_glyphs(fz_context *ctx, pdf_font_desc *fontdesc)
{
- fz_font *font = fontdesc->font;
- int i, k, cid, gid;
-
- font->width_count = 0;
+ int i, k, n, cid, gid;
+ n = 0;
for (i = 0; i < fontdesc->hmtx_len; i++)
{
for (k = fontdesc->hmtx[i].lo; k <= fontdesc->hmtx[i].hi; k++)
{
cid = pdf_lookup_cmap(fontdesc->encoding, k);
gid = pdf_font_cid_to_gid(fontdesc, cid);
- if (gid > font->width_count)
- font->width_count = gid;
+ if (gid > n)
+ n = gid;
}
}
- font->width_count ++;
+ return n + 1;
+}
+
+static void
+pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc)
+{
+ fz_font *font = fontdesc->font;
+ int i, k, cid, gid;
+ font->width_count = pdf_count_font_glyphs(ctx, fontdesc);
font->width_table = fz_malloc_array(ctx, font->width_count, sizeof(int));
fontdesc->size += font->width_count * sizeof(int);
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index 2172eb89..c8b65dd6 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -565,7 +565,7 @@ pdf_flush_text(pdf_csi *csi)
fz_try(ctx)
{
- bbox = fz_bound_text(text, gstate->ctm);
+ bbox = fz_bound_text(ctx, text, gstate->ctm);
pdf_begin_group(csi, bbox);
diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c
index 730a2754..98ebe934 100644
--- a/pdf/pdf_type3.c
+++ b/pdf/pdf_type3.c
@@ -40,6 +40,10 @@ pdf_load_type3_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict)
obj = fz_dict_gets(dict, "FontBBox");
bbox = pdf_to_rect(ctx, obj);
+ bbox.x0 *= 0.001;
+ bbox.y0 *= 0.001;
+ bbox.x1 *= 0.001;
+ bbox.y1 *= 0.001;
fontdesc->font = fz_new_type3_font(ctx, buf, matrix);
fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float));
diff --git a/xps/xps_glyphs.c b/xps/xps_glyphs.c
index 030ca0e5..51cdaa77 100644
--- a/xps/xps_glyphs.c
+++ b/xps/xps_glyphs.c
@@ -544,7 +544,7 @@ xps_parse_glyphs(xps_document *doc, fz_matrix ctm,
fz_atof(origin_x_att), fz_atof(origin_y_att),
is_sideways, bidi_level, indices_att, unicode_att);
- area = fz_bound_text(text, ctm);
+ area = fz_bound_text(doc->ctx, text, ctm);
xps_begin_opacity(doc, ctm, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);