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
This commit is contained in:
Nigel Tao 2013-10-29 20:59:39 +11:00
parent ab80f5823d
commit e849ac9382
5 changed files with 68 additions and 19 deletions

View file

@ -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;

View file

@ -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

View file

@ -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.

View file

@ -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)
}
}
}

View file

@ -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},
}