summaryrefslogtreecommitdiff
path: root/source/fitz/font.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2014-02-04 10:33:14 +0000
committerRobin Watts <robin.watts@artifex.com>2014-02-04 14:06:52 +0000
commite80425cb7049c5c097d965e2236cfa751be6d522 (patch)
treec361cd816b4cfd9150eda133b0440909e973e526 /source/fitz/font.c
parent210ae39dfb7c6793482d92af5b88d335e4ef5f31 (diff)
downloadmupdf-e80425cb7049c5c097d965e2236cfa751be6d522.tar.xz
Improve glyph bounding, outlining and SVG output text.
Luiz Henrique de Figueiredo reports that glyphs output from the SVG device contain 'lumpy' outlines. Investigation reveals that this is because the current code extracts the outlines from freetype at unit scale, and then relies on SVG to scale them up. Unfortunately, freetype insists on working in integer maths, so any sort of scaling runs the risk of distorting the outlines. The fix is to change the way we call freetype; we now request an 'UNSCALED' char, and set the required size to be the design size. We then transform the results in the floating point domain ourself. This cures the lumpy outlines, but reveals a second problem, namely that the bbox given for characters is inaccurate (and sometimes too small). Investigation shows that this is again caused by freetypes scaling, so we apply the same trick; ask for the glyph without scaling (as far as possible), and then scale the results down. We also take care to spot the 'ft_hint' flag in the font. If set this indicates that hinting must be performed to ensure that the returned outlines are sane. We therefore take note of this when calculating both bbox and outlines. This means that 'tricky' fonts such as dynalab ones now render correctly. This produces many changes in the bitmaps, the vast majority of which are neutral. The ones that aren't are all progressions.
Diffstat (limited to 'source/fitz/font.c')
-rw-r--r--source/fitz/font.c182
1 files changed, 110 insertions, 72 deletions
diff --git a/source/fitz/font.c b/source/fitz/font.c
index 6027164c..e8c6fa00 100644
--- a/source/fitz/font.c
+++ b/source/fitz/font.c
@@ -790,39 +790,54 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat
}
static fz_rect *
-fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_rect *bounds)
+fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_rect *bounds)
{
FT_Face face = font->ft_face;
FT_Error fterr;
FT_BBox cbox;
FT_Matrix m;
FT_Vector v;
+ int ft_flags;
// TODO: refactor loading into fz_load_ft_glyph
// TODO: cache results
- float strength = fz_matrix_expansion(trm) * 0.02f;
- fz_matrix local_trm = *trm;
+ const int scale = face->units_per_EM;
+ const float recip = 1 / (float)scale;
+ const float strength = 0.02f;
+ fz_matrix local_trm = fz_identity;
fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm);
if (font->ft_italic)
fz_pre_shear(&local_trm, SHEAR, 0);
- m.xx = local_trm.a * 64; /* should be 65536 */
- m.yx = local_trm.b * 64;
- m.xy = local_trm.c * 64;
- m.yy = local_trm.d * 64;
- v.x = local_trm.e * 64;
- v.y = local_trm.f * 64;
+ m.xx = local_trm.a * 65536;
+ m.yx = local_trm.b * 65536;
+ m.xy = local_trm.c * 65536;
+ m.yy = local_trm.d * 65536;
+ v.x = local_trm.e * 65536;
+ v.y = local_trm.f * 65536;
+
+ if (font->ft_hint)
+ {
+ ft_flags = FT_LOAD_NO_BITMAP;
+ }
+ else
+ {
+ ft_flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
+ }
fz_lock(ctx, FZ_LOCK_FREETYPE);
- fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
+ /* Set the char size to scale=face->units_per_EM to effectively give
+ * us unscaled results. This avoids quantisation. We then apply the
+ * scale ourselves below. */
+ fterr = FT_Set_Char_Size(face, scale, scale, 72, 72);
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);
+ fterr = FT_Load_Glyph(face, gid, ft_flags);
if (fterr)
{
fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr));
@@ -834,16 +849,16 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm,
if (font->ft_bold)
{
- FT_Outline_Embolden(&face->glyph->outline, strength * 64);
- FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32);
+ FT_Outline_Embolden(&face->glyph->outline, strength * scale);
+ FT_Outline_Translate(&face->glyph->outline, -strength * 0.5 * scale, -strength * 0.5 * scale);
}
FT_Outline_Get_CBox(&face->glyph->outline, &cbox);
fz_unlock(ctx, FZ_LOCK_FREETYPE);
- bounds->x0 = cbox.xMin / 64.0f;
- bounds->y0 = cbox.yMin / 64.0f;
- bounds->x1 = cbox.xMax / 64.0f;
- bounds->y1 = cbox.yMax / 64.0f;
+ bounds->x0 = cbox.xMin * recip;
+ bounds->y0 = cbox.yMin * recip;
+ bounds->x1 = cbox.xMax * recip;
+ bounds->y1 = cbox.yMax * recip;
if (fz_is_empty_rect(bounds))
{
@@ -859,57 +874,80 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm,
struct closure {
fz_context *ctx;
fz_path *path;
- float x, y;
+ fz_matrix trm;
};
-static int move_to(const FT_Vector *p, void *cc)
+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);
+ struct closure *cc = (struct closure *)cc_;
+ fz_context *ctx = cc->ctx;
+ fz_path *path = cc->path;
+ fz_point pt;
+
+ pt.x = p->x;
+ pt.y = p->y;
+ fz_transform_point(&pt, &cc->trm);
+ fz_moveto(ctx, path, pt.x, pt.y);
return 0;
}
-static int line_to(const FT_Vector *p, void *cc)
+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);
+ struct closure *cc = (struct closure *)cc_;
+ fz_context *ctx = cc->ctx;
+ fz_path *path = cc->path;
+ fz_point pt;
+
+ pt.x = p->x;
+ pt.y = p->y;
+ fz_transform_point(&pt, &cc->trm);
+ fz_lineto(ctx, path, pt.x, pt.y);
return 0;
}
-static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc)
+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;
+ struct closure *cc = (struct closure *)cc_;
+ fz_context *ctx = cc->ctx;
+ fz_path *path = cc->path;
+ fz_point ct, pt;
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;
+
+ ct.x = c->x;
+ ct.y = c->y;
+ fz_transform_point(&ct, &cc->trm);
+ pt.x = p->x;
+ pt.y = p->y;
+ fz_transform_point(&pt, &cc->trm);
+
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);
+ c1.x = (s.x + ct.x * 2) / 3;
+ c1.y = (s.y + ct.y * 2) / 3;
+ c2.x = (pt.x + ct.x * 2) / 3;
+ c2.y = (pt.y + ct.y * 2) / 3;
+
+ fz_curveto(ctx, path, c1.x, c1.y, c2.x, c2.y, pt.x, pt.y);
return 0;
}
-static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc)
+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);
+ struct closure *cc = (struct closure *)cc_;
+ fz_context *ctx = cc->ctx;
+ fz_path *path = cc->path;
+ fz_point c1t, c2t, pt;
+
+ c1t.x = c1->x;
+ c1t.y = c1->y;
+ fz_transform_point(&c1t, &cc->trm);
+ c2t.x = c2->x;
+ c2t.y = c2->y;
+ fz_transform_point(&c2t, &cc->trm);
+ pt.x = p->x;
+ pt.y = p->y;
+ fz_transform_point(&pt, &cc->trm);
+
+ fz_curveto(ctx, path, c1t.x, c1t.y, c2t.x, c2t.y, pt.x, pt.y);
return 0;
}
@@ -922,33 +960,34 @@ fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *tr
{
struct closure cc;
FT_Face face = font->ft_face;
- FT_Matrix m;
- FT_Vector v;
int fterr;
fz_matrix local_trm = *trm;
+ int ft_flags;
- float strength = fz_matrix_expansion(trm) * 0.02f;
+ const int scale = face->units_per_EM;
+ const float recip = 1 / (float)scale;
+ const float strength = 0.02f;
fz_adjust_ft_glyph_width(ctx, font, gid, &local_trm);
if (font->ft_italic)
fz_pre_shear(&local_trm, SHEAR, 0);
- m.xx = local_trm.a * 64; /* should be 65536 */
- m.yx = local_trm.b * 64;
- m.xy = local_trm.c * 64;
- m.yy = local_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);
+ if (font->ft_hint)
+ {
+ ft_flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM;
+ fterr = FT_Set_Char_Size(face, scale, scale, 72, 72);
+ if (fterr)
+ fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr));
+ }
+ else
+ {
+ ft_flags = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
+ }
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
+ fterr = FT_Load_Glyph(face, gid, ft_flags);
if (fterr)
{
fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr));
@@ -958,8 +997,8 @@ fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *tr
if (font->ft_bold)
{
- FT_Outline_Embolden(&face->glyph->outline, strength * 64);
- FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32);
+ FT_Outline_Embolden(&face->glyph->outline, strength * scale);
+ FT_Outline_Translate(&face->glyph->outline, -strength * 0.5 * scale, -strength * 0.5 * scale);
}
cc.path = NULL;
@@ -967,9 +1006,8 @@ fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *tr
{
cc.ctx = ctx;
cc.path = fz_new_path(ctx);
- cc.x = local_trm.e;
- cc.y = local_trm.f;
- fz_moveto(ctx, cc.path, cc.x, cc.y);
+ fz_concat(&cc.trm, fz_scale(&cc.trm, recip, recip), &local_trm);
+ fz_moveto(ctx, cc.path, cc.trm.e, cc.trm.f);
FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc);
fz_closepath(ctx, cc.path);
}
@@ -1239,7 +1277,7 @@ fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz
if (fz_is_infinite_rect(&font->bbox_table[gid]))
{
if (font->ft_face)
- fz_bound_ft_glyph(ctx, font, gid, &fz_identity, &font->bbox_table[gid]);
+ fz_bound_ft_glyph(ctx, font, gid, &font->bbox_table[gid]);
else if (font->t3lists)
fz_bound_t3_glyph(ctx, font, gid, &fz_identity, &font->bbox_table[gid]);
else