| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package sfnt
- import (
- "bytes"
- "fmt"
- "io/ioutil"
- "path/filepath"
- "testing"
- "golang.org/x/image/font"
- "golang.org/x/image/font/gofont/gobold"
- "golang.org/x/image/font/gofont/gomono"
- "golang.org/x/image/font/gofont/goregular"
- "golang.org/x/image/math/fixed"
- )
- func pt(x, y fixed.Int26_6) fixed.Point26_6 {
- return fixed.Point26_6{X: x, Y: y}
- }
- func moveTo(xa, ya fixed.Int26_6) Segment {
- return Segment{
- Op: SegmentOpMoveTo,
- Args: [3]fixed.Point26_6{pt(xa, ya)},
- }
- }
- func lineTo(xa, ya fixed.Int26_6) Segment {
- return Segment{
- Op: SegmentOpLineTo,
- Args: [3]fixed.Point26_6{pt(xa, ya)},
- }
- }
- func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
- return Segment{
- Op: SegmentOpQuadTo,
- Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb)},
- }
- }
- func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
- return Segment{
- Op: SegmentOpCubeTo,
- Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb), pt(xc, yc)},
- }
- }
- func translate(dx, dy fixed.Int26_6, s Segment) Segment {
- translateArgs(&s.Args, dx, dy)
- return s
- }
- func transform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, s Segment) Segment {
- transformArgs(&s.Args, txx, txy, tyx, tyy, dx, dy)
- return s
- }
- func checkSegmentsEqual(got, want []Segment) error {
- // Flip got's Y axis. The test cases' coordinates are given with the Y axis
- // increasing up, as that is what the ttx tool gives, and is the model for
- // the underlying font format. The Go API returns coordinates with the Y
- // axis increasing down, the same as the standard graphics libraries.
- for i := range got {
- for j := range got[i].Args {
- got[i].Args[j].Y *= -1
- }
- }
- if len(got) != len(want) {
- return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
- len(got), len(want), got, want)
- }
- for i, g := range got {
- if w := want[i]; g != w {
- return fmt.Errorf("element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v",
- i, g, w, got, want)
- }
- }
- // Check that every contour is closed.
- if len(got) == 0 {
- return nil
- }
- if got[0].Op != SegmentOpMoveTo {
- return fmt.Errorf("segments do not start with a moveTo")
- }
- var (
- first, last fixed.Point26_6
- firstI int
- )
- checkClosed := func(lastI int) error {
- if first != last {
- return fmt.Errorf("segments[%d:%d] not closed:\nfirst %v\nlast %v", firstI, lastI, first, last)
- }
- return nil
- }
- for i, g := range got {
- switch g.Op {
- case SegmentOpMoveTo:
- if i != 0 {
- if err := checkClosed(i); err != nil {
- return err
- }
- }
- firstI, first, last = i, g.Args[0], g.Args[0]
- case SegmentOpLineTo:
- last = g.Args[0]
- case SegmentOpQuadTo:
- last = g.Args[1]
- case SegmentOpCubeTo:
- last = g.Args[2]
- }
- }
- return checkClosed(len(got))
- }
- func TestTrueTypeParse(t *testing.T) {
- f, err := Parse(goregular.TTF)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
- testTrueType(t, f)
- }
- func TestTrueTypeParseReaderAt(t *testing.T) {
- f, err := ParseReaderAt(bytes.NewReader(goregular.TTF))
- if err != nil {
- t.Fatalf("ParseReaderAt: %v", err)
- }
- testTrueType(t, f)
- }
- func testTrueType(t *testing.T, f *Font) {
- if got, want := f.UnitsPerEm(), Units(2048); got != want {
- t.Errorf("UnitsPerEm: got %d, want %d", got, want)
- }
- // The exact number of glyphs in goregular.TTF can vary, and future
- // versions may add more glyphs, but https://blog.golang.org/go-fonts says
- // that "The WGL4 character set... [has] more than 650 characters in all.
- if got, want := f.NumGlyphs(), 650; got <= want {
- t.Errorf("NumGlyphs: got %d, want > %d", got, want)
- }
- }
- func fontData(name string) []byte {
- switch name {
- case "gobold":
- return gobold.TTF
- case "gomono":
- return gomono.TTF
- case "goregular":
- return goregular.TTF
- }
- panic("unreachable")
- }
- func TestBounds(t *testing.T) {
- testCases := map[string]fixed.Rectangle26_6{
- "gobold": {
- Min: fixed.Point26_6{
- X: -452,
- Y: -2193,
- },
- Max: fixed.Point26_6{
- X: 2190,
- Y: 432,
- },
- },
- "gomono": {
- Min: fixed.Point26_6{
- X: 0,
- Y: -2227,
- },
- Max: fixed.Point26_6{
- X: 1229,
- Y: 432,
- },
- },
- "goregular": {
- Min: fixed.Point26_6{
- X: -440,
- Y: -2118,
- },
- Max: fixed.Point26_6{
- X: 2160,
- Y: 543,
- },
- },
- }
- var b Buffer
- for name, want := range testCases {
- f, err := Parse(fontData(name))
- if err != nil {
- t.Errorf("Parse(%q): %v", name, err)
- continue
- }
- ppem := fixed.Int26_6(f.UnitsPerEm())
- got, err := f.Bounds(&b, ppem, font.HintingNone)
- if err != nil {
- t.Errorf("name=%q: Bounds: %v", name, err)
- continue
- }
- if got != want {
- t.Errorf("name=%q: Bounds: got %v, want %v", name, got, want)
- continue
- }
- }
- }
- func TestGlyphAdvance(t *testing.T) {
- testCases := map[string][]struct {
- r rune
- want fixed.Int26_6
- }{
- "gobold": {
- {' ', 569},
- {'A', 1479},
- {'Á', 1479},
- {'Æ', 2048},
- {'i', 592},
- {'x', 1139},
- },
- "gomono": {
- {' ', 1229},
- {'A', 1229},
- {'Á', 1229},
- {'Æ', 1229},
- {'i', 1229},
- {'x', 1229},
- },
- "goregular": {
- {' ', 569},
- {'A', 1366},
- {'Á', 1366},
- {'Æ', 2048},
- {'i', 505},
- {'x', 1024},
- },
- }
- var b Buffer
- for name, testCases1 := range testCases {
- f, err := Parse(fontData(name))
- if err != nil {
- t.Errorf("Parse(%q): %v", name, err)
- continue
- }
- ppem := fixed.Int26_6(f.UnitsPerEm())
- for _, tc := range testCases1 {
- x, err := f.GlyphIndex(&b, tc.r)
- if err != nil {
- t.Errorf("name=%q, r=%q: GlyphIndex: %v", name, tc.r, err)
- continue
- }
- got, err := f.GlyphAdvance(&b, x, ppem, font.HintingNone)
- if err != nil {
- t.Errorf("name=%q, r=%q: GlyphAdvance: %v", name, tc.r, err)
- continue
- }
- if got != tc.want {
- t.Errorf("name=%q, r=%q: GlyphAdvance: got %d, want %d", name, tc.r, got, tc.want)
- continue
- }
- }
- }
- }
- func TestGoRegularGlyphIndex(t *testing.T) {
- f, err := Parse(goregular.TTF)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
- testCases := []struct {
- r rune
- want GlyphIndex
- }{
- // Glyphs that aren't present in Go Regular.
- {'\u001f', 0}, // U+001F <control>
- {'\u0200', 0}, // U+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
- {'\u2000', 0}, // U+2000 EN QUAD
- // The want values below can be verified by running the ttx tool on
- // Go-Regular.ttf.
- //
- // The actual values are ad hoc, and result from whatever tools the
- // Bigelow & Holmes type foundry used and the order in which they
- // crafted the glyphs. They may change over time as newer versions of
- // the font are released.
- {'\u0020', 3}, // U+0020 SPACE
- {'\u0021', 4}, // U+0021 EXCLAMATION MARK
- {'\u0022', 5}, // U+0022 QUOTATION MARK
- {'\u0023', 6}, // U+0023 NUMBER SIGN
- {'\u0024', 7}, // U+0024 DOLLAR SIGN
- {'\u0025', 8}, // U+0025 PERCENT SIGN
- {'\u0026', 9}, // U+0026 AMPERSAND
- {'\u0027', 10}, // U+0027 APOSTROPHE
- {'\u03bd', 396}, // U+03BD GREEK SMALL LETTER NU
- {'\u03be', 397}, // U+03BE GREEK SMALL LETTER XI
- {'\u03bf', 398}, // U+03BF GREEK SMALL LETTER OMICRON
- {'\u03c0', 399}, // U+03C0 GREEK SMALL LETTER PI
- {'\u03c1', 400}, // U+03C1 GREEK SMALL LETTER RHO
- {'\u03c2', 401}, // U+03C2 GREEK SMALL LETTER FINAL SIGMA
- }
- var b Buffer
- for _, tc := range testCases {
- got, err := f.GlyphIndex(&b, tc.r)
- if err != nil {
- t.Errorf("r=%q: %v", tc.r, err)
- continue
- }
- if got != tc.want {
- t.Errorf("r=%q: got %d, want %d", tc.r, got, tc.want)
- continue
- }
- }
- }
- func TestGlyphIndex(t *testing.T) {
- data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
- if err != nil {
- t.Fatal(err)
- }
- for _, format := range []int{-1, 0, 4, 12} {
- testGlyphIndex(t, data, format)
- }
- }
- func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) {
- if cmapFormat >= 0 {
- originalSupportedCmapFormat := supportedCmapFormat
- defer func() {
- supportedCmapFormat = originalSupportedCmapFormat
- }()
- supportedCmapFormat = func(format, pid, psid uint16) bool {
- return int(format) == cmapFormat && originalSupportedCmapFormat(format, pid, psid)
- }
- }
- f, err := Parse(data)
- if err != nil {
- t.Errorf("cmapFormat=%d: %v", cmapFormat, err)
- return
- }
- testCases := []struct {
- r rune
- want GlyphIndex
- }{
- // Glyphs that aren't present in cmapTest.ttf.
- {'?', 0},
- {'\ufffd', 0},
- {'\U0001f4a9', 0},
- // For a .TTF file, FontForge maps:
- // - ".notdef" to glyph index 0.
- // - ".null" to glyph index 1.
- // - "nonmarkingreturn" to glyph index 2.
- {'/', 0},
- {'0', 3},
- {'1', 4},
- {'2', 5},
- {'3', 0},
- {'@', 0},
- {'A', 6},
- {'B', 7},
- {'C', 0},
- {'`', 0},
- {'a', 8},
- {'b', 0},
- // Of the remaining runes, only U+00FF LATIN SMALL LETTER Y WITH
- // DIAERESIS is in both the Mac Roman encoding and the cmapTest.ttf
- // font file.
- {'\u00fe', 0},
- {'\u00ff', 9},
- {'\u0100', 10},
- {'\u0101', 11},
- {'\u0102', 0},
- {'\u4e2c', 0},
- {'\u4e2d', 12},
- {'\u4e2e', 0},
- {'\U0001f0a0', 0},
- {'\U0001f0a1', 13},
- {'\U0001f0a2', 0},
- {'\U0001f0b0', 0},
- {'\U0001f0b1', 14},
- {'\U0001f0b2', 15},
- {'\U0001f0b3', 0},
- }
- var b Buffer
- for _, tc := range testCases {
- want := tc.want
- switch {
- case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff':
- // cmap format 0, with the Macintosh Roman encoding, can only
- // represent a limited set of non-ASCII runes, e.g. U+00FF.
- want = 0
- case cmapFormat == 4 && tc.r > '\uffff':
- // cmap format 4 only supports the Basic Multilingual Plane (BMP).
- want = 0
- }
- got, err := f.GlyphIndex(&b, tc.r)
- if err != nil {
- t.Errorf("cmapFormat=%d, r=%q: %v", cmapFormat, tc.r, err)
- continue
- }
- if got != want {
- t.Errorf("cmapFormat=%d, r=%q: got %d, want %d", cmapFormat, tc.r, got, want)
- continue
- }
- }
- }
- func TestPostScriptSegments(t *testing.T) {
- // wants' vectors correspond 1-to-1 to what's in the CFFTest.sfd file,
- // although OpenType/CFF and FontForge's SFD have reversed orders.
- // https://fontforge.github.io/validation.html says that "All paths must be
- // drawn in a consistent direction. Clockwise for external paths,
- // anti-clockwise for internal paths. (Actually PostScript requires the
- // exact opposite, but FontForge reverses PostScript contours when it loads
- // them so that everything is consistant internally -- and reverses them
- // again when it saves them, of course)."
- //
- // The .notdef glyph isn't explicitly in the SFD file, but for some unknown
- // reason, FontForge generates it in the OpenType/CFF file.
- wants := [][]Segment{{
- // .notdef
- // - contour #0
- moveTo(50, 0),
- lineTo(450, 0),
- lineTo(450, 533),
- lineTo(50, 533),
- lineTo(50, 0),
- // - contour #1
- moveTo(100, 50),
- lineTo(100, 483),
- lineTo(400, 483),
- lineTo(400, 50),
- lineTo(100, 50),
- }, {
- // zero
- // - contour #0
- moveTo(300, 700),
- cubeTo(380, 700, 420, 580, 420, 500),
- cubeTo(420, 350, 390, 100, 300, 100),
- cubeTo(220, 100, 180, 220, 180, 300),
- cubeTo(180, 450, 210, 700, 300, 700),
- // - contour #1
- moveTo(300, 800),
- cubeTo(200, 800, 100, 580, 100, 400),
- cubeTo(100, 220, 200, 0, 300, 0),
- cubeTo(400, 0, 500, 220, 500, 400),
- cubeTo(500, 580, 400, 800, 300, 800),
- }, {
- // one
- // - contour #0
- moveTo(100, 0),
- lineTo(300, 0),
- lineTo(300, 800),
- lineTo(100, 800),
- lineTo(100, 0),
- }, {
- // Q
- // - contour #0
- moveTo(657, 237),
- lineTo(289, 387),
- lineTo(519, 615),
- lineTo(657, 237),
- // - contour #1
- moveTo(792, 169),
- cubeTo(867, 263, 926, 502, 791, 665),
- cubeTo(645, 840, 380, 831, 228, 673),
- cubeTo(71, 509, 110, 231, 242, 93),
- cubeTo(369, -39, 641, 18, 722, 93),
- lineTo(802, 3),
- lineTo(864, 83),
- lineTo(792, 169),
- }, {
- // uni4E2D
- // - contour #0
- moveTo(141, 520),
- lineTo(137, 356),
- lineTo(245, 400),
- lineTo(331, 26),
- lineTo(355, 414),
- lineTo(463, 434),
- lineTo(453, 620),
- lineTo(341, 592),
- lineTo(331, 758),
- lineTo(243, 752),
- lineTo(235, 562),
- lineTo(141, 520),
- }}
- testSegments(t, "CFFTest.otf", wants)
- }
- func TestTrueTypeSegments(t *testing.T) {
- // wants' vectors correspond 1-to-1 to what's in the glyfTest.sfd file,
- // although FontForge's SFD format stores quadratic Bézier curves as cubics
- // with duplicated off-curve points. quadTo(bx, by, cx, cy) is stored as
- // "bx by bx by cx cy".
- //
- // The .notdef, .null and nonmarkingreturn glyphs aren't explicitly in the
- // SFD file, but for some unknown reason, FontForge generates them in the
- // TrueType file.
- wants := [][]Segment{{
- // .notdef
- // - contour #0
- moveTo(68, 0),
- lineTo(68, 1365),
- lineTo(612, 1365),
- lineTo(612, 0),
- lineTo(68, 0),
- // - contour #1
- moveTo(136, 68),
- lineTo(544, 68),
- lineTo(544, 1297),
- lineTo(136, 1297),
- lineTo(136, 68),
- }, {
- // .null
- // Empty glyph.
- }, {
- // nonmarkingreturn
- // Empty glyph.
- }, {
- // zero
- // - contour #0
- moveTo(614, 1434),
- quadTo(369, 1434, 369, 614),
- quadTo(369, 471, 435, 338),
- quadTo(502, 205, 614, 205),
- quadTo(860, 205, 860, 1024),
- quadTo(860, 1167, 793, 1300),
- quadTo(727, 1434, 614, 1434),
- // - contour #1
- moveTo(614, 1638),
- quadTo(1024, 1638, 1024, 819),
- quadTo(1024, 0, 614, 0),
- quadTo(205, 0, 205, 819),
- quadTo(205, 1638, 614, 1638),
- }, {
- // one
- // - contour #0
- moveTo(205, 0),
- lineTo(205, 1638),
- lineTo(614, 1638),
- lineTo(614, 0),
- lineTo(205, 0),
- }, {
- // five
- // - contour #0
- moveTo(0, 0),
- lineTo(0, 100),
- lineTo(400, 100),
- lineTo(400, 0),
- lineTo(0, 0),
- }, {
- // six
- // - contour #0
- moveTo(0, 0),
- lineTo(0, 100),
- lineTo(400, 100),
- lineTo(400, 0),
- lineTo(0, 0),
- // - contour #1
- translate(111, 234, moveTo(205, 0)),
- translate(111, 234, lineTo(205, 1638)),
- translate(111, 234, lineTo(614, 1638)),
- translate(111, 234, lineTo(614, 0)),
- translate(111, 234, lineTo(205, 0)),
- }, {
- // seven
- // - contour #0
- moveTo(0, 0),
- lineTo(0, 100),
- lineTo(400, 100),
- lineTo(400, 0),
- lineTo(0, 0),
- // - contour #1
- transform(1<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
- transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
- transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
- transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
- transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
- }, {
- // eight
- // - contour #0
- moveTo(0, 0),
- lineTo(0, 100),
- lineTo(400, 100),
- lineTo(400, 0),
- lineTo(0, 0),
- // - contour #1
- transform(3<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
- transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
- transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
- transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
- transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
- }, {
- // nine
- // - contour #0
- moveTo(0, 0),
- lineTo(0, 100),
- lineTo(400, 100),
- lineTo(400, 0),
- lineTo(0, 0),
- // - contour #1
- transform(22381, 8192, 5996, 14188, 237, 258, moveTo(205, 0)),
- transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 1638)),
- transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 1638)),
- transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 0)),
- transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 0)),
- }}
- testSegments(t, "glyfTest.ttf", wants)
- }
- func testSegments(t *testing.T, filename string, wants [][]Segment) {
- data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/" + filename))
- if err != nil {
- t.Fatalf("ReadFile: %v", err)
- }
- f, err := Parse(data)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
- ppem := fixed.Int26_6(f.UnitsPerEm())
- if ng := f.NumGlyphs(); ng != len(wants) {
- t.Fatalf("NumGlyphs: got %d, want %d", ng, len(wants))
- }
- var b Buffer
- for i, want := range wants {
- got, err := f.LoadGlyph(&b, GlyphIndex(i), ppem, nil)
- if err != nil {
- t.Errorf("i=%d: LoadGlyph: %v", i, err)
- continue
- }
- if err := checkSegmentsEqual(got, want); err != nil {
- t.Errorf("i=%d: %v", i, err)
- continue
- }
- }
- if _, err := f.LoadGlyph(nil, 0xffff, ppem, nil); err != ErrNotFound {
- t.Errorf("LoadGlyph(..., 0xffff, ...):\ngot %v\nwant %v", err, ErrNotFound)
- }
- name, err := f.Name(nil, NameIDFamily)
- if err != nil {
- t.Errorf("Name: %v", err)
- } else if want := filename[:len(filename)-len(".ttf")]; name != want {
- t.Errorf("Name:\ngot %q\nwant %q", name, want)
- }
- }
- func TestPPEM(t *testing.T) {
- data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf"))
- if err != nil {
- t.Fatalf("ReadFile: %v", err)
- }
- f, err := Parse(data)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
- var b Buffer
- x, err := f.GlyphIndex(&b, '1')
- if err != nil {
- t.Fatalf("GlyphIndex: %v", err)
- }
- if x == 0 {
- t.Fatalf("GlyphIndex: no glyph index found for the rune '1'")
- }
- testCases := []struct {
- ppem fixed.Int26_6
- want []Segment
- }{{
- ppem: fixed.Int26_6(12 << 6),
- want: []Segment{
- moveTo(77, 0),
- lineTo(77, 614),
- lineTo(230, 614),
- lineTo(230, 0),
- lineTo(77, 0),
- },
- }, {
- ppem: fixed.Int26_6(2048),
- want: []Segment{
- moveTo(205, 0),
- lineTo(205, 1638),
- lineTo(614, 1638),
- lineTo(614, 0),
- lineTo(205, 0),
- },
- }}
- for i, tc := range testCases {
- got, err := f.LoadGlyph(&b, x, tc.ppem, nil)
- if err != nil {
- t.Errorf("i=%d: LoadGlyph: %v", i, err)
- continue
- }
- if err := checkSegmentsEqual(got, tc.want); err != nil {
- t.Errorf("i=%d: %v", i, err)
- continue
- }
- }
- }
- func TestGlyphName(t *testing.T) {
- f, err := Parse(goregular.TTF)
- if err != nil {
- t.Fatalf("Parse: %v", err)
- }
- testCases := []struct {
- r rune
- want string
- }{
- {'\x00', "uni0000"},
- {'!', "exclam"},
- {'A', "A"},
- {'{', "braceleft"},
- {'\u00c4', "Adieresis"}, // U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
- {'\u2020', "dagger"}, // U+2020 DAGGER
- {'\u2660', "spade"}, // U+2660 BLACK SPADE SUIT
- {'\uf800', "gopher"}, // U+F800 <Private Use>
- {'\ufffe', ".notdef"}, // Not in the Go Regular font, so GlyphIndex returns (0, nil).
- }
- var b Buffer
- for _, tc := range testCases {
- x, err := f.GlyphIndex(&b, tc.r)
- if err != nil {
- t.Errorf("r=%q: GlyphIndex: %v", tc.r, err)
- continue
- }
- got, err := f.GlyphName(&b, x)
- if err != nil {
- t.Errorf("r=%q: GlyphName: %v", tc.r, err)
- continue
- }
- if got != tc.want {
- t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want)
- continue
- }
- }
- }
- func TestBuiltInPostNames(t *testing.T) {
- testCases := []struct {
- x GlyphIndex
- want string
- }{
- {0, ".notdef"},
- {1, ".null"},
- {2, "nonmarkingreturn"},
- {13, "asterisk"},
- {36, "A"},
- {93, "z"},
- {123, "ocircumflex"},
- {202, "Edieresis"},
- {255, "Ccaron"},
- {256, "ccaron"},
- {257, "dcroat"},
- {258, ""},
- {999, ""},
- {0xffff, ""},
- }
- for _, tc := range testCases {
- if tc.x >= numBuiltInPostNames {
- continue
- }
- i := builtInPostNamesOffsets[tc.x+0]
- j := builtInPostNamesOffsets[tc.x+1]
- got := builtInPostNamesData[i:j]
- if got != tc.want {
- t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want)
- }
- }
- }
|