1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
// Copyright 2019 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
/*
This file contains opt-in tests for kerning in user provided fonts.
Kerning information in kern and GPOS tables can be quite complex. These tests
recursively load all fonts from -bulkFontDirs and try to kern all possible
glyph pairs.
These tests only check if there are no errors during kerning. Tests of actual
kerning values are in proprietary_test.go.
Note: CJK fonts can contain billions of posible kerning pairs. Testing for
these fonts stops after -bulkMaxKernPairs.
To opt-in:
go test golang.org/x/image/font/sfnt -test.run=BulkKern -args -bulk -bulkFontDirs /Library/Fonts:./myfonts
*/
import (
"flag"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"testing"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
var (
bulk = flag.Bool("bulk", false, "")
fontDirs = flag.String(
"bulkFontDirs",
"./",
"separated directories to search for fonts",
)
maxKernPairs = flag.Int(
"bulkMaxKernPairs",
20000000,
"skip testing of kerning after this many tested pairs",
)
)
func TestBulkKern(t *testing.T) {
if !*bulk {
t.Skip("skipping bulk font test")
}
for _, fontDir := range filepath.SplitList(*fontDirs) {
err := filepath.Walk(fontDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if strings.HasSuffix(path, ".ttf") || strings.HasSuffix(path, ".otf") {
t.Run(info.Name(), testFontKerning(filepath.Join(path)))
}
return nil
})
if err != nil {
t.Fatal("error finding fonts", err)
}
}
}
func testFontKerning(fname string) func(*testing.T) {
return func(t *testing.T) {
t.Parallel()
b, err := ioutil.ReadFile(fname)
if err != nil {
t.Fatal(err)
}
fnt, err := Parse(b)
if err != nil {
t.Fatal(err)
}
buf := &Buffer{}
// collect all GlyphIndex
glyphs := make([]GlyphIndex, 1, fnt.NumGlyphs())
glyphs[0] = GlyphIndex(0)
r := rune(0)
for r < 0xffff {
g, err := fnt.GlyphIndex(buf, r)
r++
if g == 0 || err == ErrNotFound {
continue
}
if err != nil {
t.Fatal(err)
}
glyphs = append(glyphs, g)
if len(glyphs) == fnt.NumGlyphs() {
break
}
}
var kerned, tested int
for _, g1 := range glyphs {
for _, g2 := range glyphs {
if tested >= *maxKernPairs {
log.Printf("stop testing after %d or %d kerning pairs (found %d pairs)",
tested, len(glyphs)*len(glyphs), kerned)
return
}
tested++
adv, err := fnt.Kern(buf, g1, g2, fixed.I(20), font.HintingNone)
if err == ErrNotFound {
continue
}
if err != nil {
t.Fatal(err)
}
if adv != 0 {
kerned++
}
}
}
log.Printf("found %d kerning pairs for %d glyphs (%.1f%%) in %q",
kerned,
len(glyphs),
100*float64(kerned)/float64(len(glyphs)*len(glyphs)),
fname,
)
}
}
|