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:
parent
ab80f5823d
commit
e849ac9382
|
@ -7,7 +7,7 @@ gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxi
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
void usage(char** argv) {
|
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) {
|
int main(int argc, char** argv) {
|
||||||
|
@ -15,6 +15,7 @@ int main(int argc, char** argv) {
|
||||||
FT_Library library;
|
FT_Library library;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
FT_Outline* o;
|
FT_Outline* o;
|
||||||
|
FT_Int major, minor, patch;
|
||||||
int i, j, font_size, no_hinting;
|
int i, j, font_size, no_hinting;
|
||||||
|
|
||||||
if (argc != 4) {
|
if (argc != 4) {
|
||||||
|
@ -23,7 +24,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
font_size = atoi(argv[1]);
|
font_size = atoi(argv[1]);
|
||||||
if (font_size <= 0) {
|
if (font_size <= 0) {
|
||||||
printf("invalid font_size\n");
|
fprintf(stderr, "invalid font_size\n");
|
||||||
usage(argv);
|
usage(argv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -32,33 +33,40 @@ int main(int argc, char** argv) {
|
||||||
} else if (!strcmp(argv[3], "sans_hinting")) {
|
} else if (!strcmp(argv[3], "sans_hinting")) {
|
||||||
no_hinting = 1;
|
no_hinting = 1;
|
||||||
} else {
|
} else {
|
||||||
printf("neither \"with_hinting\" nor \"sans_hinting\"\n");
|
fprintf(stderr, "neither \"with_hinting\" nor \"sans_hinting\"\n");
|
||||||
usage(argv);
|
usage(argv);
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
error = FT_Init_FreeType(&library);
|
error = FT_Init_FreeType(&library);
|
||||||
if (error) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
error = FT_New_Face(library, argv[2], 0, &face);
|
error = FT_New_Face(library, argv[2], 0, &face);
|
||||||
if (error) {
|
if (error) {
|
||||||
printf("FT_New_Face: error #%d\n", error);
|
fprintf(stderr, "FT_New_Face: error #%d\n", error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0);
|
error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0);
|
||||||
if (error) {
|
if (error) {
|
||||||
printf("FT_Set_Char_Size: error #%d\n", error);
|
fprintf(stderr, "FT_Set_Char_Size: error #%d\n", error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
for (i = 0; i < face->num_glyphs; i++) {
|
for (i = 0; i < face->num_glyphs; i++) {
|
||||||
error = FT_Load_Glyph(face, i, no_hinting ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT);
|
error = FT_Load_Glyph(face, i, no_hinting ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT);
|
||||||
if (error) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
o = &face->glyph->outline;
|
o = &face->glyph->outline;
|
||||||
|
|
|
@ -171,6 +171,11 @@ func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error)
|
||||||
if g.hinter != nil {
|
if g.hinter != nil {
|
||||||
g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4]
|
g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4]
|
||||||
g.Unhinted = g.Unhinted[:len(g.Unhinted)-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 {
|
if np0 != 0 {
|
||||||
// The hinting program expects the []End values to be indexed relative
|
// The hinting program expects the []End values to be indexed relative
|
||||||
|
|
|
@ -989,11 +989,11 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set-RP0 bit.
|
// Set-RP0 bit.
|
||||||
|
h.gs.rp[1] = h.gs.rp[0]
|
||||||
|
h.gs.rp[2] = i
|
||||||
if opcode&0x10 != 0 {
|
if opcode&0x10 != 0 {
|
||||||
h.gs.rp[0] = i
|
h.gs.rp[0] = i
|
||||||
}
|
}
|
||||||
h.gs.rp[1] = h.gs.rp[0]
|
|
||||||
h.gs.rp[2] = i
|
|
||||||
|
|
||||||
// Move the point.
|
// Move the point.
|
||||||
oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv)
|
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.
|
// Set-RP0 bit.
|
||||||
|
h.gs.rp[1] = h.gs.rp[0]
|
||||||
|
h.gs.rp[2] = i
|
||||||
if opcode&0x10 != 0 {
|
if opcode&0x10 != 0 {
|
||||||
h.gs.rp[0] = i
|
h.gs.rp[0] = i
|
||||||
}
|
}
|
||||||
h.gs.rp[1] = h.gs.rp[0]
|
|
||||||
h.gs.rp[2] = i
|
|
||||||
|
|
||||||
// Move the point.
|
// Move the point.
|
||||||
h.move(p, distance-curDist, true)
|
h.move(p, distance-curDist, true)
|
||||||
|
@ -1438,13 +1438,20 @@ type f2dot14 int16
|
||||||
|
|
||||||
func normalize(x, y f2dot14) [2]f2dot14 {
|
func normalize(x, y f2dot14) [2]f2dot14 {
|
||||||
fx, fy := float64(x), float64(y)
|
fx, fy := float64(x), float64(y)
|
||||||
l := math.Hypot(fx, fy)
|
l := 0x4000 / math.Hypot(fx, fy)
|
||||||
fx /= l
|
fx *= l
|
||||||
fy /= l
|
if fx >= 0 {
|
||||||
return [2]f2dot14{
|
fx += 0.5
|
||||||
f2dot14(fx * 0x4000),
|
} else {
|
||||||
f2dot14(fy * 0x4000),
|
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.
|
// f26dot6 is a 26.6 fixed point number.
|
||||||
|
|
|
@ -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) {
|
func TestMove(t *testing.T) {
|
||||||
h, p := Hinter{}, Point{}
|
h, p := Hinter{}, Point{}
|
||||||
testCases := []struct {
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -253,7 +253,7 @@ var scalingTestCases = []struct {
|
||||||
}{
|
}{
|
||||||
{"luxisr", 12, -1},
|
{"luxisr", 12, -1},
|
||||||
{"x-arial-bold", 11, 0},
|
{"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-droid-sans-japanese", 9, 0},
|
||||||
{"x-times-new-roman", 13, 0},
|
{"x-times-new-roman", 13, 0},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue