...

Source file src/golang.org/x/image/font/sfnt/kern_test.go

Documentation: golang.org/x/image/font/sfnt

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

View as plain text