From e849ac9382647d7ebdab3b1531ff7a6012b40483 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 29 Oct 2013 20:59:39 +1100 Subject: [PATCH] freetype: fix MDRP/MIRP Set-RP0 bit and fix normalize rounding. Also make phantom point delta-X adjustment. Also make print-glyph-points require Freetype version >= 2.5, which is the latest version, at the time of writing. R=bsiegert CC=golang-dev, remyoudompheng https://codereview.appspot.com/18370043 --- cmd/print-glyph-points/main.c | 24 ++++++++++++++++-------- freetype/truetype/glyph.go | 5 +++++ freetype/truetype/hint.go | 27 +++++++++++++++++---------- freetype/truetype/hint_test.go | 29 +++++++++++++++++++++++++++++ freetype/truetype/truetype_test.go | 2 +- 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/cmd/print-glyph-points/main.c b/cmd/print-glyph-points/main.c index bb8a326..24d7308 100644 --- a/cmd/print-glyph-points/main.c +++ b/cmd/print-glyph-points/main.c @@ -7,7 +7,7 @@ gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxi #include FT_FREETYPE_H void usage(char** argv) { - printf("usage: %s font_size font_file [with_hinting|sans_hinting]\n", argv[0]); + fprintf(stderr, "usage: %s font_size font_file [with_hinting|sans_hinting]\n", argv[0]); } int main(int argc, char** argv) { @@ -15,6 +15,7 @@ int main(int argc, char** argv) { FT_Library library; FT_Face face; FT_Outline* o; + FT_Int major, minor, patch; int i, j, font_size, no_hinting; if (argc != 4) { @@ -23,7 +24,7 @@ int main(int argc, char** argv) { } font_size = atoi(argv[1]); if (font_size <= 0) { - printf("invalid font_size\n"); + fprintf(stderr, "invalid font_size\n"); usage(argv); return 1; } @@ -32,33 +33,40 @@ int main(int argc, char** argv) { } else if (!strcmp(argv[3], "sans_hinting")) { no_hinting = 1; } else { - printf("neither \"with_hinting\" nor \"sans_hinting\"\n"); + fprintf(stderr, "neither \"with_hinting\" nor \"sans_hinting\"\n"); usage(argv); return 1; }; error = FT_Init_FreeType(&library); if (error) { - printf("FT_Init_FreeType: error #%d\n", error); + fprintf(stderr, "FT_Init_FreeType: error #%d\n", error); + return 1; + } + FT_Library_Version(library, &major, &minor, &patch); + if ((major < 2) || ((major == 2) && (minor < 5))) { + fprintf(stderr, "%s needs freetype version >= 2.5.\n" + "Try setting LD_LIBRARY_PATH=/path/to/freetype_built_from_src/objs/.libs/\n", + argv[0]); return 1; } error = FT_New_Face(library, argv[2], 0, &face); if (error) { - printf("FT_New_Face: error #%d\n", error); + fprintf(stderr, "FT_New_Face: error #%d\n", error); return 1; } error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0); if (error) { - printf("FT_Set_Char_Size: error #%d\n", error); + fprintf(stderr, "FT_Set_Char_Size: error #%d\n", error); return 1; } for (i = 0; i < face->num_glyphs; i++) { error = FT_Load_Glyph(face, i, no_hinting ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT); if (error) { - printf("FT_Load_Glyph: glyph %d: error #%d\n", i, error); + fprintf(stderr, "FT_Load_Glyph: glyph %d: error #%d\n", i, error); return 1; } if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { - printf("glyph format for glyph %d is not FT_GLYPH_FORMAT_OUTLINE\n", i); + fprintf(stderr, "glyph format for glyph %d is not FT_GLYPH_FORMAT_OUTLINE\n", i); return 1; } o = &face->glyph->outline; diff --git a/freetype/truetype/glyph.go b/freetype/truetype/glyph.go index 90f40b4..8dcb336 100644 --- a/freetype/truetype/glyph.go +++ b/freetype/truetype/glyph.go @@ -171,6 +171,11 @@ func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) if g.hinter != nil { g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4] g.Unhinted = g.Unhinted[:len(g.Unhinted)-4] + if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 { + for i := np0; i < len(g.Point); i++ { + g.Point[i].X += dx + } + } } if np0 != 0 { // The hinting program expects the []End values to be indexed relative diff --git a/freetype/truetype/hint.go b/freetype/truetype/hint.go index 1817958..28de384 100644 --- a/freetype/truetype/hint.go +++ b/freetype/truetype/hint.go @@ -989,11 +989,11 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, } // Set-RP0 bit. + h.gs.rp[1] = h.gs.rp[0] + h.gs.rp[2] = i if opcode&0x10 != 0 { h.gs.rp[0] = i } - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i // Move the point. oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv) @@ -1068,11 +1068,11 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, } // Set-RP0 bit. + h.gs.rp[1] = h.gs.rp[0] + h.gs.rp[2] = i if opcode&0x10 != 0 { h.gs.rp[0] = i } - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i // Move the point. h.move(p, distance-curDist, true) @@ -1438,13 +1438,20 @@ type f2dot14 int16 func normalize(x, y f2dot14) [2]f2dot14 { fx, fy := float64(x), float64(y) - l := math.Hypot(fx, fy) - fx /= l - fy /= l - return [2]f2dot14{ - f2dot14(fx * 0x4000), - f2dot14(fy * 0x4000), + l := 0x4000 / math.Hypot(fx, fy) + fx *= l + if fx >= 0 { + fx += 0.5 + } else { + fx -= 0.5 } + fy *= l + if fy >= 0 { + fy += 0.5 + } else { + fy -= 0.5 + } + return [2]f2dot14{f2dot14(fx), f2dot14(fy)} } // f26dot6 is a 26.6 fixed point number. diff --git a/freetype/truetype/hint_test.go b/freetype/truetype/hint_test.go index 98d9453..ee4f716 100644 --- a/freetype/truetype/hint_test.go +++ b/freetype/truetype/hint_test.go @@ -583,6 +583,8 @@ func TestBytecode(t *testing.T) { } } +// TestMove tests that the Hinter.move method matches the output of the C +// Freetype implementation. func TestMove(t *testing.T) { h, p := Hinter{}, Point{} testCases := []struct { @@ -642,3 +644,30 @@ func TestMove(t *testing.T) { } } } + +// TestNormalize tests that the normalize function matches the output of the C +// Freetype implementation. +func TestNormalize(t *testing.T) { + testCases := [][2]f2dot14{ + {-15895, 3974}, + {-15543, 5181}, + {-14654, 7327}, + {-11585, 11585}, + {0, 16384}, + {11585, 11585}, + {14654, 7327}, + {15543, 5181}, + {15895, 3974}, + {16066, 3213}, + {16161, 2694}, + {16219, 2317}, + {16257, 2032}, + {16284, 1809}, + } + for i, want := range testCases { + got := normalize(f2dot14(i)-4, 1) + if got != want { + t.Errorf("i=%d: got %v, want %v", i, got, want) + } + } +} diff --git a/freetype/truetype/truetype_test.go b/freetype/truetype/truetype_test.go index 80b0b00..d5ded68 100644 --- a/freetype/truetype/truetype_test.go +++ b/freetype/truetype/truetype_test.go @@ -253,7 +253,7 @@ var scalingTestCases = []struct { }{ {"luxisr", 12, -1}, {"x-arial-bold", 11, 0}, - {"x-deja-vu-sans-oblique", 17, 14}, + {"x-deja-vu-sans-oblique", 17, 229}, {"x-droid-sans-japanese", 9, 0}, {"x-times-new-roman", 13, 0}, }