From b76427be4766888670756221f8b156c18c4ea5e5 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Wed, 9 Oct 2013 20:07:32 +1100 Subject: [PATCH] freetype: add script to create more hinting tests. R=bsiegert, r CC=golang-dev https://codereview.appspot.com/14414044 --- cmd/print-glyph-points/main.c | 31 +++++-- freetype/truetype/truetype_test.go | 133 ++++++++++++++++++---------- testdata/README | 4 +- testdata/make-other-hinting-txts.sh | 30 +++++++ 4 files changed, 146 insertions(+), 52 deletions(-) create mode 100755 testdata/make-other-hinting-txts.sh diff --git a/cmd/print-glyph-points/main.c b/cmd/print-glyph-points/main.c index b63dc3c..bb8a326 100644 --- a/cmd/print-glyph-points/main.c +++ b/cmd/print-glyph-points/main.c @@ -1,27 +1,47 @@ /* -gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out +gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxisr.ttf with_hinting */ #include #include #include FT_FREETYPE_H -static int font_size = 12; -static int no_hinting = 0; +void usage(char** argv) { + printf("usage: %s font_size font_file [with_hinting|sans_hinting]\n", argv[0]); +} int main(int argc, char** argv) { FT_Error error; FT_Library library; FT_Face face; FT_Outline* o; - int i, j; + int i, j, font_size, no_hinting; + if (argc != 4) { + usage(argv); + return 1; + } + font_size = atoi(argv[1]); + if (font_size <= 0) { + printf("invalid font_size\n"); + usage(argv); + return 1; + } + if (!strcmp(argv[3], "with_hinting")) { + no_hinting = 0; + } else if (!strcmp(argv[3], "sans_hinting")) { + no_hinting = 1; + } else { + printf("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); return 1; } - error = FT_New_Face(library, "../../testdata/luxisr.ttf", 0, &face); + error = FT_New_Face(library, argv[2], 0, &face); if (error) { printf("FT_New_Face: error #%d\n", error); return 1; @@ -50,4 +70,5 @@ int main(int argc, char** argv) { } printf("\n"); } + return 0; } diff --git a/freetype/truetype/truetype_test.go b/freetype/truetype/truetype_test.go index 294d0b0..d64c421 100644 --- a/freetype/truetype/truetype_test.go +++ b/freetype/truetype/truetype_test.go @@ -74,63 +74,106 @@ func TestParse(t *testing.T) { } } -func testScaling(t *testing.T, filename string, hinter *Hinter) { - b, err := ioutil.ReadFile("../../testdata/luxisr.ttf") - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - font, err := Parse(b) - if err != nil { - t.Fatalf("Parse: %v", err) - } - f, err := os.Open("../../testdata/" + filename) - if err != nil { - t.Fatalf("Open: %v", err) - } - defer f.Close() +var scalingTestCases = []struct { + name string + size int32 + // hintingBrokenAt, if non-negative, is the glyph index n for which + // only the first n glyphs are known to be correctly hinted. + // TODO: remove this field, when hinting is completely implemented. + hintingBrokenAt int +}{ + {"luxisr", 12, -1}, + // TODO: uncomment the fonts below, once they get past Parse and + // GlyphBuf.Load, and the unhinted values match C Freetype. + //{"x-arial-bold", 11, 0}, + //{"x-deja-vu-sans-oblique", 17, 0}, + //{"x-droid-sans-japanese", 9, 0}, + //{"x-inconsolata", 10, 0}, + //{"x-times-new-roman", 13, 0}, +} - wants := [][]Point{} - scanner := bufio.NewScanner(f) - for scanner.Scan() { - text := scanner.Text() - if text == "" { - wants = append(wants, []Point{}) - continue - } - ss := strings.Split(text, ",") - points := make([]Point, len(ss)) - for i, s := range ss { - p := &points[i] - if _, err := fmt.Sscanf(s, "%d %d %d", &p.X, &p.Y, &p.Flags); err != nil { - t.Fatalf("Sscanf: %v", err) +func testScaling(t *testing.T, hinter *Hinter) { +loop: + for _, tc := range scalingTestCases { + b, err := ioutil.ReadFile(fmt.Sprintf("../../testdata/%s.ttf", tc.name)) + if err != nil { + // The "x-foo" fonts are optional tests, as they are not checked + // in for copyright or file size reasons. + if strings.HasPrefix(tc.name, "x-") { + t.Logf("%s: ReadFile: %v", tc.name, err) + } else { + t.Errorf("%s: ReadFile: %v", tc.name, err) } + continue loop } - wants = append(wants, points) - } - if err := scanner.Err(); err != nil && err != io.EOF { - t.Fatalf("Scanner: %v", err) - } + font, err := Parse(b) + if err != nil { + t.Errorf("%s: Parse: %v", tc.name, err) + continue loop + } + hinting := "sans" + if hinter != nil { + hinting = "with" + } + f, err := os.Open(fmt.Sprintf( + "../../testdata/%s-%dpt-%s-hinting.txt", tc.name, tc.size, hinting)) + if err != nil { + t.Errorf("%s: Open: %v", tc.name, err) + continue loop + } + defer f.Close() - const fontSize = 12 - glyphBuf := NewGlyphBuf() - for i, want := range wants { - if err = glyphBuf.Load(font, fontSize*64, Index(i), hinter); err != nil { - t.Fatalf("Load: %v", err) + wants := [][]Point{} + scanner := bufio.NewScanner(f) + for scanner.Scan() { + text := scanner.Text() + if text == "" { + wants = append(wants, []Point{}) + continue + } + ss := strings.Split(text, ",") + points := make([]Point, len(ss)) + for i, s := range ss { + p := &points[i] + if _, err := fmt.Sscanf(s, "%d %d %d", &p.X, &p.Y, &p.Flags); err != nil { + t.Errorf("%s: Sscanf: %v", tc.name, err) + continue loop + } + } + wants = append(wants, points) } - got := glyphBuf.Point - for i := range got { - got[i].Flags &= 0x01 + if err := scanner.Err(); err != nil && err != io.EOF { + t.Errorf("%s: Scanner: %v", tc.name, err) + continue loop } - if !reflect.DeepEqual(got, want) { - t.Errorf("glyph #%d:\ngot %v\nwant %v\n", i, got, want) + + glyphBuf := NewGlyphBuf() + for i, want := range wants { + // TODO: completely implement hinting. For now, only the first + // tc.hintingBrokenAt glyphs of the test case's font are correctly hinted. + if hinter != nil && i == tc.hintingBrokenAt { + break + } + + if err = glyphBuf.Load(font, tc.size*64, Index(i), hinter); err != nil { + t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err) + continue loop + } + got := glyphBuf.Point + for i := range got { + got[i].Flags &= 0x01 + } + if !reflect.DeepEqual(got, want) { + t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\n", tc.name, i, got, want) + } } } } func TestScalingSansHinting(t *testing.T) { - testScaling(t, "luxisr-12pt-sans-hinting.txt", nil) + testScaling(t, nil) } func TestScalingWithHinting(t *testing.T) { - testScaling(t, "luxisr-12pt-with-hinting.txt", &Hinter{}) + testScaling(t, &Hinter{}) } diff --git a/testdata/README b/testdata/README index c290524..bae4382 100644 --- a/testdata/README +++ b/testdata/README @@ -1,8 +1,8 @@ -The *.ttf and COPYING files in this directory were copied from the X.org +The luxi*.ttf and COPYING files in this directory were copied from the X.org project, specifically http://xorg.freedesktop.org/releases/individual/font/font-bh-ttf-1.0.0.tar.bz2 -There are three fonts: sans (s), serif (r) and monospaced (m). For example, +There are three Luxi fonts: sans (s), serif (r) and monospaced (m). For example, luxisr.ttf is Luxi Sans. The 'r' here means regular, as opposed to bold. The *.ttx files in this directory were generated from the *.ttf files diff --git a/testdata/make-other-hinting-txts.sh b/testdata/make-other-hinting-txts.sh new file mode 100755 index 0000000..6af1465 --- /dev/null +++ b/testdata/make-other-hinting-txts.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# +# This script creates the optional x-*-hinting.txt files from fonts that are +# not checked in for copyright or file size reasons. +# +# Run it from this directory (testdata). +# +# It has only been tested on an Ubuntu 12.04 system. + +set -e + +: ${FONTDIR:=/usr/share/fonts/truetype} + +ln -sf $FONTDIR/droid/DroidSansJapanese.ttf x-droid-sans-japanese.ttf +ln -sf $FONTDIR/msttcorefonts/Arial_Bold.ttf x-arial-bold.ttf +ln -sf $FONTDIR/msttcorefonts/Times_New_Roman.ttf x-times-new-roman.ttf +ln -sf $FONTDIR/ttf-dejavu/DejaVuSans-Oblique.ttf x-deja-vu-sans-oblique.ttf + +${CC:=gcc} ../cmd/print-glyph-points/main.c $(pkg-config --cflags --libs freetype2) -o print-glyph-points + +./print-glyph-points 9 x-droid-sans-japanese.ttf sans_hinting > x-droid-sans-japanese-9pt-sans-hinting.txt +./print-glyph-points 9 x-droid-sans-japanese.ttf with_hinting > x-droid-sans-japanese-9pt-with-hinting.txt +./print-glyph-points 11 x-arial-bold.ttf sans_hinting > x-arial-bold-11pt-sans-hinting.txt +./print-glyph-points 11 x-arial-bold.ttf with_hinting > x-arial-bold-11pt-with-hinting.txt +./print-glyph-points 13 x-times-new-roman.ttf sans_hinting > x-times-new-roman-13pt-sans-hinting.txt +./print-glyph-points 13 x-times-new-roman.ttf with_hinting > x-times-new-roman-13pt-with-hinting.txt +./print-glyph-points 17 x-deja-vu-sans-oblique.ttf sans_hinting > x-deja-vu-sans-oblique-17pt-sans-hinting.txt +./print-glyph-points 17 x-deja-vu-sans-oblique.ttf with_hinting > x-deja-vu-sans-oblique-17pt-with-hinting.txt + +rm print-glyph-points