diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2012-01-11 16:02:18 +0100 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2012-01-11 16:02:18 +0100 |
commit | 177346693da57e72d1e6c01edbdf7ce75e010a3f (patch) | |
tree | 7cfa2037949f22b7263f05e0ca95820dc4b4fe2e | |
parent | 220b6f3565b8ec6da406acc08e8f09128b7c7346 (diff) | |
download | mupdf-177346693da57e72d1e6c01edbdf7ce75e010a3f.tar.xz |
Calculate accurate per-glyph bounding boxes for fz_bound_text.
-rw-r--r-- | draw/draw_device.c | 4 | ||||
-rw-r--r-- | fitz/dev_bbox.c | 4 | ||||
-rw-r--r-- | fitz/dev_list.c | 10 | ||||
-rw-r--r-- | fitz/fitz.h | 11 | ||||
-rw-r--r-- | fitz/res_font.c | 109 | ||||
-rw-r--r-- | fitz/res_text.c | 63 | ||||
-rw-r--r-- | pdf/pdf_font.c | 24 | ||||
-rw-r--r-- | pdf/pdf_interpret.c | 2 | ||||
-rw-r--r-- | pdf/pdf_type3.c | 4 | ||||
-rw-r--r-- | xps/xps_glyphs.c | 2 |
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); |