...

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

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

     1  // Copyright 2017 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 popular, high quality, proprietary fonts,
     9  made by companies such as Adobe and Microsoft. These fonts are generally
    10  available, but copies are not explicitly included in this repository due to
    11  licensing differences or file size concerns. To opt-in, run:
    12  
    13  go test golang.org/x/image/font/sfnt -args -proprietary
    14  
    15  Not all tests pass out-of-the-box on all systems. For example, the Microsoft
    16  Times New Roman font is downloadable gratis even on non-Windows systems, but as
    17  per the ttf-mscorefonts-installer Debian package, this requires accepting an
    18  End User License Agreement (EULA) and a CAB format decoder. These tests assume
    19  that such fonts have already been installed. You may need to specify the
    20  directories for these fonts:
    21  
    22  go test golang.org/x/image/font/sfnt -args -proprietary \
    23  	-adobeDir=$HOME/fonts/adobe \
    24  	-appleDir=$HOME/fonts/apple \
    25  	-dejavuDir=$HOME/fonts/dejavu \
    26  	-microsoftDir=$HOME/fonts/microsoft \
    27  	-notoDir=$HOME/fonts/noto
    28  
    29  To only run those tests for the Microsoft fonts:
    30  
    31  go test golang.org/x/image/font/sfnt -test.run=ProprietaryMicrosoft -args -proprietary etc
    32  */
    33  
    34  // TODO: enable Apple/Microsoft tests by default on Darwin/Windows?
    35  
    36  import (
    37  	"errors"
    38  	"flag"
    39  	"io/ioutil"
    40  	"path/filepath"
    41  	"strconv"
    42  	"strings"
    43  	"testing"
    44  
    45  	"golang.org/x/image/font"
    46  	"golang.org/x/image/math/fixed"
    47  )
    48  
    49  var (
    50  	proprietary = flag.Bool("proprietary", false, "test proprietary fonts not included in this repository")
    51  
    52  	adobeDir = flag.String(
    53  		"adobeDir",
    54  		// This needs to be set explicitly. There is no default dir on Debian:
    55  		// https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=736680
    56  		//
    57  		// Get the fonts from https://github.com/adobe-fonts, e.g.:
    58  		//	- https://github.com/adobe-fonts/source-code-pro/releases/latest
    59  		//	- https://github.com/adobe-fonts/source-han-sans/releases/latest
    60  		//	- https://github.com/adobe-fonts/source-sans-pro/releases/latest
    61  		//
    62  		// Copy all of the TTF and OTF files to the one directory, such as
    63  		// $HOME/adobe-fonts, and pass that as the -adobeDir flag here.
    64  		"",
    65  		"directory name for the Adobe proprietary fonts",
    66  	)
    67  
    68  	appleDir = flag.String(
    69  		"appleDir",
    70  		// This needs to be set explicitly. These fonts come with macOS, which
    71  		// is widely available but not freely available.
    72  		//
    73  		// On a Mac, set this to "/System/Library/Fonts/".
    74  		"",
    75  		"directory name for the Apple proprietary fonts",
    76  	)
    77  
    78  	dejavuDir = flag.String(
    79  		"dejavuDir",
    80  		// Get the fonts from https://dejavu-fonts.github.io/
    81  		"",
    82  		"directory name for the DejaVu proprietary fonts",
    83  	)
    84  
    85  	microsoftDir = flag.String(
    86  		"microsoftDir",
    87  		"/usr/share/fonts/truetype/msttcorefonts",
    88  		"directory name for the Microsoft proprietary fonts",
    89  	)
    90  
    91  	notoDir = flag.String(
    92  		"notoDir",
    93  		// Get the fonts from https://www.google.com/get/noto/
    94  		"",
    95  		"directory name for the Noto proprietary fonts",
    96  	)
    97  )
    98  
    99  func TestProprietaryAdobeSourceCodeProRegularOTF(t *testing.T) {
   100  	testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, -1)
   101  }
   102  
   103  func TestProprietaryAdobeSourceCodeProRegularTTF(t *testing.T) {
   104  	testProprietary(t, "adobe", "SourceCodePro-Regular.ttf", 1500, -1)
   105  }
   106  
   107  func TestProprietaryAdobeSourceHanSansSCRegularOTF(t *testing.T) {
   108  	testProprietary(t, "adobe", "SourceHanSansSC-Regular.otf", 65535, -1)
   109  }
   110  
   111  func TestProprietaryAdobeSourceSansProBlackOTF(t *testing.T) {
   112  	testProprietary(t, "adobe", "SourceSansPro-Black.otf", 1900, -1)
   113  }
   114  
   115  func TestProprietaryAdobeSourceSansProBlackTTF(t *testing.T) {
   116  	testProprietary(t, "adobe", "SourceSansPro-Black.ttf", 1900, -1)
   117  }
   118  
   119  func TestProprietaryAdobeSourceSansProRegularOTF(t *testing.T) {
   120  	testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1900, -1)
   121  }
   122  
   123  func TestProprietaryAdobeSourceSansProRegularTTF(t *testing.T) {
   124  	testProprietary(t, "adobe", "SourceSansPro-Regular.ttf", 1900, -1)
   125  }
   126  
   127  func TestProprietaryAppleAppleSymbols(t *testing.T) {
   128  	testProprietary(t, "apple", "Apple Symbols.ttf", 4600, -1)
   129  }
   130  
   131  func TestProprietaryAppleGeezaPro0(t *testing.T) {
   132  	testProprietary(t, "apple", "GeezaPro.ttc?0", 1700, -1)
   133  }
   134  
   135  func TestProprietaryAppleGeezaPro1(t *testing.T) {
   136  	testProprietary(t, "apple", "GeezaPro.ttc?1", 1700, -1)
   137  }
   138  
   139  func TestProprietaryAppleHelvetica0(t *testing.T) {
   140  	testProprietary(t, "apple", "Helvetica.dfont?0", 2100, -1)
   141  }
   142  
   143  func TestProprietaryAppleHelvetica1(t *testing.T) {
   144  	testProprietary(t, "apple", "Helvetica.dfont?1", 2100, -1)
   145  }
   146  
   147  func TestProprietaryAppleHelvetica2(t *testing.T) {
   148  	testProprietary(t, "apple", "Helvetica.dfont?2", 2100, -1)
   149  }
   150  
   151  func TestProprietaryAppleHelvetica3(t *testing.T) {
   152  	testProprietary(t, "apple", "Helvetica.dfont?3", 2100, -1)
   153  }
   154  
   155  func TestProprietaryAppleHelvetica4(t *testing.T) {
   156  	testProprietary(t, "apple", "Helvetica.dfont?4", 1300, -1)
   157  }
   158  
   159  func TestProprietaryAppleHelvetica5(t *testing.T) {
   160  	testProprietary(t, "apple", "Helvetica.dfont?5", 1300, -1)
   161  }
   162  
   163  func TestProprietaryAppleHiragino0(t *testing.T) {
   164  	testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?0", 9000, -1)
   165  }
   166  
   167  func TestProprietaryAppleHiragino1(t *testing.T) {
   168  	testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?1", 9000, -1)
   169  }
   170  
   171  func TestProprietaryDejaVuSans(t *testing.T) {
   172  	testProprietary(t, "dejavu", "DejaVuSans.ttf", 3300, -1)
   173  }
   174  
   175  func TestProprietaryDejaVuSansExtraLight(t *testing.T) {
   176  	testProprietary(t, "dejavu", "DejaVuSans-ExtraLight.ttf", 2000, -1)
   177  }
   178  
   179  func TestProprietaryDejaVuSansMono(t *testing.T) {
   180  	testProprietary(t, "dejavu", "DejaVuSansMono.ttf", 3300, -1)
   181  }
   182  
   183  func TestProprietaryDejaVuSerif(t *testing.T) {
   184  	testProprietary(t, "dejavu", "DejaVuSerif.ttf", 3500, -1)
   185  }
   186  
   187  func TestProprietaryMicrosoftArial(t *testing.T) {
   188  	testProprietary(t, "microsoft", "Arial.ttf", 1200, -1)
   189  }
   190  
   191  func TestProprietaryMicrosoftArialAsACollection(t *testing.T) {
   192  	testProprietary(t, "microsoft", "Arial.ttf?0", 1200, -1)
   193  }
   194  
   195  func TestProprietaryMicrosoftComicSansMS(t *testing.T) {
   196  	testProprietary(t, "microsoft", "Comic_Sans_MS.ttf", 550, -1)
   197  }
   198  
   199  func TestProprietaryMicrosoftTimesNewRoman(t *testing.T) {
   200  	testProprietary(t, "microsoft", "Times_New_Roman.ttf", 1200, -1)
   201  }
   202  
   203  func TestProprietaryMicrosoftWebdings(t *testing.T) {
   204  	testProprietary(t, "microsoft", "Webdings.ttf", 200, -1)
   205  }
   206  
   207  func TestProprietaryNotoColorEmoji(t *testing.T) {
   208  	testProprietary(t, "noto", "NotoColorEmoji.ttf", 2300, -1)
   209  }
   210  
   211  func TestProprietaryNotoSansRegular(t *testing.T) {
   212  	testProprietary(t, "noto", "NotoSans-Regular.ttf", 2400, -1)
   213  }
   214  
   215  // testProprietary tests that we can load every glyph in the named font.
   216  //
   217  // The exact number of glyphs in the font can differ across its various
   218  // versions, but as a sanity check, there should be at least minNumGlyphs.
   219  //
   220  // While this package is a work-in-progress, not every glyph can be loaded. The
   221  // firstUnsupportedGlyph argument, if non-negative, is the index of the first
   222  // unsupported glyph in the font. This number should increase over time (or set
   223  // negative), as the TODO's in this package are done.
   224  func testProprietary(t *testing.T, proprietor, filename string, minNumGlyphs, firstUnsupportedGlyph int) {
   225  	if !*proprietary {
   226  		t.Skip("skipping proprietary font test")
   227  	}
   228  
   229  	basename, fontIndex, err := filename, -1, error(nil)
   230  	if i := strings.IndexByte(filename, '?'); i >= 0 {
   231  		fontIndex, err = strconv.Atoi(filename[i+1:])
   232  		if err != nil {
   233  			t.Fatalf("could not parse collection font index from filename %q", filename)
   234  		}
   235  		basename = filename[:i]
   236  	}
   237  
   238  	dir := ""
   239  	switch proprietor {
   240  	case "adobe":
   241  		dir = *adobeDir
   242  	case "apple":
   243  		dir = *appleDir
   244  	case "dejavu":
   245  		dir = *dejavuDir
   246  	case "microsoft":
   247  		dir = *microsoftDir
   248  	case "noto":
   249  		dir = *notoDir
   250  	default:
   251  		panic("unreachable")
   252  	}
   253  	file, err := ioutil.ReadFile(filepath.Join(dir, basename))
   254  	if err != nil {
   255  		t.Fatalf("%v\nPerhaps you need to set the -%sDir flag?", err, proprietor)
   256  	}
   257  	qualifiedFilename := proprietor + "/" + filename
   258  
   259  	f := (*Font)(nil)
   260  	if fontIndex >= 0 {
   261  		c, err := ParseCollection(file)
   262  		if err != nil {
   263  			t.Fatalf("ParseCollection: %v", err)
   264  		}
   265  		if want, ok := proprietaryNumFonts[qualifiedFilename]; ok {
   266  			if got := c.NumFonts(); got != want {
   267  				t.Fatalf("NumFonts: got %d, want %d", got, want)
   268  			}
   269  		}
   270  		f, err = c.Font(fontIndex)
   271  		if err != nil {
   272  			t.Fatalf("Font: %v", err)
   273  		}
   274  	} else {
   275  		f, err = Parse(file)
   276  		if err != nil {
   277  			t.Fatalf("Parse: %v", err)
   278  		}
   279  	}
   280  
   281  	ppem := fixed.Int26_6(f.UnitsPerEm())
   282  	var buf Buffer
   283  
   284  	// Some of the tests below, such as which glyph index a particular rune
   285  	// maps to, can depend on the specific version of the proprietary font. If
   286  	// tested against a different version of that font, the test might (but not
   287  	// necessarily will) fail, even though the Go code is good. If so, log a
   288  	// message, but don't automatically fail (i.e. dont' call t.Fatalf).
   289  	gotVersion, err := f.Name(&buf, NameIDVersion)
   290  	if err != nil {
   291  		t.Fatalf("Name(Version): %v", err)
   292  	}
   293  	wantVersion := proprietaryVersions[qualifiedFilename]
   294  	if gotVersion != wantVersion {
   295  		t.Logf("font version provided differs from the one the tests were written against:"+
   296  			"\ngot  %q\nwant %q", gotVersion, wantVersion)
   297  	}
   298  
   299  	gotFull, err := f.Name(&buf, NameIDFull)
   300  	if err != nil {
   301  		t.Fatalf("Name(Full): %v", err)
   302  	}
   303  	wantFull := proprietaryFullNames[qualifiedFilename]
   304  	if gotFull != wantFull {
   305  		t.Fatalf("Name(Full):\ngot  %q\nwant %q", gotFull, wantFull)
   306  	}
   307  
   308  	numGlyphs := f.NumGlyphs()
   309  	if numGlyphs < minNumGlyphs {
   310  		t.Fatalf("NumGlyphs: got %d, want at least %d", numGlyphs, minNumGlyphs)
   311  	}
   312  
   313  	iMax := numGlyphs
   314  	if firstUnsupportedGlyph >= 0 {
   315  		iMax = firstUnsupportedGlyph
   316  	}
   317  	for i, numErrors := 0, 0; i < iMax; i++ {
   318  		if _, err := f.LoadGlyph(&buf, GlyphIndex(i), ppem, nil); err != nil && err != ErrColoredGlyph {
   319  			t.Errorf("LoadGlyph(%d): %v", i, err)
   320  			numErrors++
   321  		}
   322  		if numErrors == 10 {
   323  			t.Fatal("LoadGlyph: too many errors")
   324  		}
   325  	}
   326  
   327  	for r, want := range proprietaryGlyphIndexTestCases[qualifiedFilename] {
   328  		got, err := f.GlyphIndex(&buf, r)
   329  		if err != nil {
   330  			t.Errorf("GlyphIndex(%q): %v", r, err)
   331  			continue
   332  		}
   333  		if got != want {
   334  			t.Errorf("GlyphIndex(%q): got %d, want %d", r, got, want)
   335  			continue
   336  		}
   337  	}
   338  
   339  	for r, want := range proprietaryGlyphTestCases[qualifiedFilename] {
   340  		x, err := f.GlyphIndex(&buf, r)
   341  		if err != nil {
   342  			t.Errorf("GlyphIndex(%q): %v", r, err)
   343  			continue
   344  		}
   345  		got, err := f.LoadGlyph(&buf, x, ppem, nil)
   346  		if err != nil {
   347  			t.Errorf("LoadGlyph(%q): %v", r, err)
   348  			continue
   349  		}
   350  		if err := checkSegmentsEqual(got, want); err != nil {
   351  			t.Errorf("LoadGlyph(%q): %v", r, err)
   352  			continue
   353  		}
   354  	}
   355  
   356  	for r, tc := range proprietaryGlyphBoundsTestCases[qualifiedFilename] {
   357  		ppem := fixed.Int26_6(f.UnitsPerEm())
   358  		x, err := f.GlyphIndex(&buf, r)
   359  		if err != nil {
   360  			t.Errorf("GlyphIndex(%q): %v", r, err)
   361  			continue
   362  		}
   363  		gotBounds, gotAdv, err := f.GlyphBounds(&buf, x, ppem, font.HintingNone)
   364  		if err != nil {
   365  			t.Errorf("GlyphBounds(%q): %v", r, err)
   366  			continue
   367  		}
   368  		if gotBounds != tc.wantBounds {
   369  			t.Errorf("GlyphBounds(%q): got %#v, want %#v", r, gotBounds, tc.wantBounds)
   370  		}
   371  		if gotAdv != tc.wantAdv {
   372  			t.Errorf("GlyphBounds(%q): got %#v, want %#v", r, gotAdv, tc.wantAdv)
   373  		}
   374  	}
   375  
   376  kernLoop:
   377  	for _, tc := range proprietaryKernTestCases[qualifiedFilename] {
   378  		var indexes [2]GlyphIndex
   379  		for i := range indexes {
   380  			x, err := f.GlyphIndex(&buf, tc.runes[i])
   381  			if x == 0 && err == nil {
   382  				err = errors.New("no glyph index found")
   383  			}
   384  			if err != nil {
   385  				t.Errorf("GlyphIndex(%q): %v", tc.runes[0], err)
   386  				continue kernLoop
   387  			}
   388  			indexes[i] = x
   389  		}
   390  		kern, err := f.Kern(&buf, indexes[0], indexes[1], tc.ppem, tc.hinting)
   391  		if err != nil {
   392  			t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): %v",
   393  				tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, err)
   394  			continue
   395  		}
   396  		if got := Units(kern); got != tc.want {
   397  			t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): got %d, want %d",
   398  				tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, got, tc.want)
   399  			continue
   400  		}
   401  	}
   402  
   403  	for x, want := range proprietaryFDSelectTestCases[qualifiedFilename] {
   404  		got, err := f.cached.glyphData.fdSelect.lookup(f, &buf, x)
   405  		if err != nil {
   406  			t.Errorf("fdSelect.lookup(%d): %v", x, err)
   407  			continue
   408  		}
   409  		if got != want {
   410  			t.Errorf("fdSelect.lookup(%d): got %d, want %d", x, got, want)
   411  			continue
   412  		}
   413  	}
   414  }
   415  
   416  // proprietaryNumFonts holds the expected number of fonts in each collection,
   417  // or 1 for a single font. It is not necessarily an exhaustive list of all
   418  // proprietary fonts tested.
   419  var proprietaryNumFonts = map[string]int{
   420  	"apple/Helvetica.dfont?0":    6,
   421  	"apple/ヒラギノ角ゴシック W0.ttc?0": 2,
   422  	"microsoft/Arial.ttf?0":      1,
   423  }
   424  
   425  // proprietaryVersions holds the expected version string of each proprietary
   426  // font tested. If third parties such as Adobe or Microsoft update their fonts,
   427  // and the tests subsequently fail, these versions should be updated too.
   428  //
   429  // Updates are expected to be infrequent. For example, as of 2017, the fonts
   430  // installed by the Debian ttf-mscorefonts-installer package have last modified
   431  // times no later than 2001.
   432  var proprietaryVersions = map[string]string{
   433  	"adobe/SourceCodePro-Regular.otf":   "Version 2.030;PS 1.0;hotconv 16.6.51;makeotf.lib2.5.65220",
   434  	"adobe/SourceCodePro-Regular.ttf":   "Version 2.030;PS 1.000;hotconv 16.6.51;makeotf.lib2.5.65220",
   435  	"adobe/SourceHanSansSC-Regular.otf": "Version 1.004;PS 1.004;hotconv 1.0.82;makeotf.lib2.5.63406",
   436  	"adobe/SourceSansPro-Black.otf":     "Version 2.020;PS 2.0;hotconv 1.0.86;makeotf.lib2.5.63406",
   437  	"adobe/SourceSansPro-Black.ttf":     "Version 2.020;PS 2.000;hotconv 1.0.86;makeotf.lib2.5.63406",
   438  	"adobe/SourceSansPro-Regular.otf":   "Version 2.020;PS 2.0;hotconv 1.0.86;makeotf.lib2.5.63406",
   439  	"adobe/SourceSansPro-Regular.ttf":   "Version 2.020;PS 2.000;hotconv 1.0.86;makeotf.lib2.5.63406",
   440  
   441  	"apple/Apple Symbols.ttf":    "12.0d3e10",
   442  	"apple/GeezaPro.ttc?0":       "12.0d1e3",
   443  	"apple/GeezaPro.ttc?1":       "12.0d1e3",
   444  	"apple/Helvetica.dfont?0":    "12.0d1e3",
   445  	"apple/Helvetica.dfont?1":    "12.0d1e3",
   446  	"apple/Helvetica.dfont?2":    "12.0d1e3",
   447  	"apple/Helvetica.dfont?3":    "12.0d1e3",
   448  	"apple/Helvetica.dfont?4":    "12.0d1e3",
   449  	"apple/Helvetica.dfont?5":    "12.0d1e3",
   450  	"apple/ヒラギノ角ゴシック W0.ttc?0": "11.0d7e1",
   451  	"apple/ヒラギノ角ゴシック W0.ttc?1": "11.0d7e1",
   452  
   453  	"dejavu/DejaVuSans-ExtraLight.ttf": "Version 2.37",
   454  	"dejavu/DejaVuSans.ttf":            "Version 2.37",
   455  	"dejavu/DejaVuSansMono.ttf":        "Version 2.37",
   456  	"dejavu/DejaVuSerif.ttf":           "Version 2.37",
   457  
   458  	"microsoft/Arial.ttf":           "Version 2.82",
   459  	"microsoft/Arial.ttf?0":         "Version 2.82",
   460  	"microsoft/Comic_Sans_MS.ttf":   "Version 2.10",
   461  	"microsoft/Times_New_Roman.ttf": "Version 2.82",
   462  	"microsoft/Webdings.ttf":        "Version 1.03",
   463  
   464  	"noto/NotoColorEmoji.ttf":   "Version 1.33",
   465  	"noto/NotoSans-Regular.ttf": "Version 1.06",
   466  }
   467  
   468  // proprietaryFullNames holds the expected full name of each proprietary font
   469  // tested.
   470  var proprietaryFullNames = map[string]string{
   471  	"adobe/SourceCodePro-Regular.otf":   "Source Code Pro",
   472  	"adobe/SourceCodePro-Regular.ttf":   "Source Code Pro",
   473  	"adobe/SourceHanSansSC-Regular.otf": "Source Han Sans SC Regular",
   474  	"adobe/SourceSansPro-Black.otf":     "Source Sans Pro Black",
   475  	"adobe/SourceSansPro-Black.ttf":     "Source Sans Pro Black",
   476  	"adobe/SourceSansPro-Regular.otf":   "Source Sans Pro",
   477  	"adobe/SourceSansPro-Regular.ttf":   "Source Sans Pro",
   478  
   479  	"apple/Apple Symbols.ttf":    "Apple Symbols",
   480  	"apple/GeezaPro.ttc?0":       "Geeza Pro Regular",
   481  	"apple/GeezaPro.ttc?1":       "Geeza Pro Bold",
   482  	"apple/Helvetica.dfont?0":    "Helvetica",
   483  	"apple/Helvetica.dfont?1":    "Helvetica Bold",
   484  	"apple/Helvetica.dfont?2":    "Helvetica Oblique",
   485  	"apple/Helvetica.dfont?3":    "Helvetica Bold Oblique",
   486  	"apple/Helvetica.dfont?4":    "Helvetica Light",
   487  	"apple/Helvetica.dfont?5":    "Helvetica Light Oblique",
   488  	"apple/ヒラギノ角ゴシック W0.ttc?0": "Hiragino Sans W0",
   489  	"apple/ヒラギノ角ゴシック W0.ttc?1": ".Hiragino Kaku Gothic Interface W0",
   490  
   491  	"dejavu/DejaVuSans-ExtraLight.ttf": "DejaVu Sans ExtraLight",
   492  	"dejavu/DejaVuSans.ttf":            "DejaVu Sans",
   493  	"dejavu/DejaVuSansMono.ttf":        "DejaVu Sans Mono",
   494  	"dejavu/DejaVuSerif.ttf":           "DejaVu Serif",
   495  
   496  	"microsoft/Arial.ttf":           "Arial",
   497  	"microsoft/Arial.ttf?0":         "Arial",
   498  	"microsoft/Comic_Sans_MS.ttf":   "Comic Sans MS",
   499  	"microsoft/Times_New_Roman.ttf": "Times New Roman",
   500  	"microsoft/Webdings.ttf":        "Webdings",
   501  
   502  	"noto/NotoColorEmoji.ttf":   "Noto Color Emoji",
   503  	"noto/NotoSans-Regular.ttf": "Noto Sans",
   504  }
   505  
   506  // proprietaryGlyphIndexTestCases hold a sample of each font's rune to glyph
   507  // index cmap. The numerical values can be verified by running the ttx tool.
   508  var proprietaryGlyphIndexTestCases = map[string]map[rune]GlyphIndex{
   509  	"adobe/SourceCodePro-Regular.otf": {
   510  		'\u0030':     877,  // U+0030 DIGIT ZERO
   511  		'\u0041':     2,    // U+0041 LATIN CAPITAL LETTER A
   512  		'\u0061':     28,   // U+0061 LATIN SMALL LETTER A
   513  		'\u0104':     64,   // U+0104 LATIN CAPITAL LETTER A WITH OGONEK
   514  		'\u0125':     323,  // U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX
   515  		'\u01f4':     111,  // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE
   516  		'\u03a3':     623,  // U+03A3 GREEK CAPITAL LETTER SIGMA
   517  		'\u2569':     1500, // U+2569 BOX DRAWINGS DOUBLE UP AND HORIZONTAL
   518  		'\U0001f100': 0,    // U+0001F100 DIGIT ZERO FULL STOP
   519  	},
   520  	"adobe/SourceCodePro-Regular.ttf": {
   521  		'\u0030': 877, // U+0030 DIGIT ZERO
   522  		'\u0041': 2,   // U+0041 LATIN CAPITAL LETTER A
   523  		'\u01f4': 111, // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE
   524  	},
   525  	"adobe/SourceHanSansSC-Regular.otf": {
   526  		'\u0030':     17,    // U+0030 DIGIT ZERO
   527  		'\u0041':     34,    // U+0041 LATIN CAPITAL LETTER A
   528  		'\u00d7':     150,   // U+00D7 MULTIPLICATION SIGN
   529  		'\u1100':     365,   // U+1100 HANGUL CHOSEONG KIYEOK
   530  		'\u25ca':     1254,  // U+25CA LOZENGE
   531  		'\u2e9c':     1359,  // U+2E9C CJK RADICAL SUN
   532  		'\u304b':     1463,  // U+304B HIRAGANA LETTER KA
   533  		'\u4e2d':     9893,  // U+4E2D <CJK Ideograph>, 中
   534  		'\ua960':     47537, // U+A960 HANGUL CHOSEONG TIKEUT-MIEUM
   535  		'\ufb00':     58919, // U+FB00 LATIN SMALL LIGATURE FF
   536  		'\uffee':     59213, // U+FFEE HALFWIDTH WHITE CIRCLE
   537  		'\U0001f100': 59214, // U+0001F100 DIGIT ZERO FULL STOP
   538  		'\U0001f248': 59449, // U+0001F248 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
   539  		'\U0002f9f4': 61768, // U+0002F9F4 CJK COMPATIBILITY IDEOGRAPH-2F9F4
   540  	},
   541  	"adobe/SourceSansPro-Regular.otf": {
   542  		'\u0041': 2,    // U+0041 LATIN CAPITAL LETTER A
   543  		'\u03a3': 592,  // U+03A3 GREEK CAPITAL LETTER SIGMA
   544  		'\u0435': 999,  // U+0435 CYRILLIC SMALL LETTER IE
   545  		'\u2030': 1728, // U+2030 PER MILLE SIGN
   546  	},
   547  	"adobe/SourceSansPro-Regular.ttf": {
   548  		'\u0041': 2,    // U+0041 LATIN CAPITAL LETTER A
   549  		'\u03a3': 592,  // U+03A3 GREEK CAPITAL LETTER SIGMA
   550  		'\u0435': 999,  // U+0435 CYRILLIC SMALL LETTER IE
   551  		'\u2030': 1728, // U+2030 PER MILLE SIGN
   552  	},
   553  
   554  	"apple/Helvetica.dfont?0": {
   555  		'\u0041':     36,   // U+0041 LATIN CAPITAL LETTER A
   556  		'\u00f1':     120,  // U+00F1 LATIN SMALL LETTER N WITH TILDE
   557  		'\u0401':     473,  // U+0401 CYRILLIC CAPITAL LETTER IO
   558  		'\u200d':     611,  // U+200D ZERO WIDTH JOINER
   559  		'\u20ab':     1743, // U+20AB DONG SIGN
   560  		'\u2229':     0,    // U+2229 INTERSECTION
   561  		'\u04e9':     1208, // U+04E9 CYRILLIC SMALL LETTER BARRED O
   562  		'\U0001f100': 0,    // U+0001F100 DIGIT ZERO FULL STOP
   563  	},
   564  
   565  	"dejavu/DejaVuSerif.ttf": {
   566  		'\u0041': 36,   // U+0041 LATIN CAPITAL LETTER A
   567  		'\u1e00': 1418, // U+1E00 LATIN CAPITAL LETTER A WITH RING BELOW
   568  	},
   569  
   570  	"microsoft/Arial.ttf": {
   571  		'\u0041':     36,   // U+0041 LATIN CAPITAL LETTER A
   572  		'\u00f1':     120,  // U+00F1 LATIN SMALL LETTER N WITH TILDE
   573  		'\u0401':     556,  // U+0401 CYRILLIC CAPITAL LETTER IO
   574  		'\u200d':     745,  // U+200D ZERO WIDTH JOINER
   575  		'\u20ab':     1150, // U+20AB DONG SIGN
   576  		'\u2229':     320,  // U+2229 INTERSECTION
   577  		'\u04e9':     1319, // U+04E9 CYRILLIC SMALL LETTER BARRED O
   578  		'\U0001f100': 0,    // U+0001F100 DIGIT ZERO FULL STOP
   579  	},
   580  	"microsoft/Comic_Sans_MS.ttf": {
   581  		'\u0041': 36,  // U+0041 LATIN CAPITAL LETTER A
   582  		'\u03af': 573, // U+03AF GREEK SMALL LETTER IOTA WITH TONOS
   583  	},
   584  	"microsoft/Times_New_Roman.ttf": {
   585  		'\u0041': 36,  // U+0041 LATIN CAPITAL LETTER A
   586  		'\u0042': 37,  // U+0041 LATIN CAPITAL LETTER B
   587  		'\u266a': 392, // U+266A EIGHTH NOTE
   588  		'\uf041': 0,   // PRIVATE USE AREA
   589  		'\uf042': 0,   // PRIVATE USE AREA
   590  	},
   591  	"microsoft/Webdings.ttf": {
   592  		'\u0041': 0,  // U+0041 LATIN CAPITAL LETTER A
   593  		'\u0042': 0,  // U+0041 LATIN CAPITAL LETTER B
   594  		'\u266a': 0,  // U+266A EIGHTH NOTE
   595  		'\uf041': 36, // PRIVATE USE AREA
   596  		'\uf042': 37, // PRIVATE USE AREA
   597  	},
   598  }
   599  
   600  // proprietaryGlyphTestCases hold a sample of each font's glyph vectors. The
   601  // numerical values can be verified by running the ttx tool, remembering that:
   602  //   - for PostScript glyphs, ttx coordinates are relative.
   603  //   - for TrueType glyphs, ttx coordinates are absolute, and consecutive
   604  //     off-curve points implies an on-curve point at the midpoint.
   605  var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
   606  	"adobe/SourceHanSansSC-Regular.otf": {
   607  		'!': {
   608  			// -312 123 callsubr # 123 + bias = 230
   609  			// :	# Arg stack is [-312].
   610  			// :	-13 140 -119 -21 return
   611  			// :	# Arg stack is [-312 -13 140 -119 -21].
   612  			// 120 callsubr # 120 + bias = 227
   613  			// :	# Arg stack is [-312 -13 140 -119 -21].
   614  			// :	hstemhm
   615  			// :	95 132 -103 75 return
   616  			// :	# Arg stack is [95 132 -103 75].
   617  			// hintmask 01010000
   618  			// 8 callsubr # 8 + bias = 115
   619  			// :	# Arg stack is [].
   620  			// :	130 221 rmoveto
   621  			moveTo(130, 221),
   622  			// :	63 hlineto
   623  			lineTo(193, 221),
   624  			// :	12 424 3 -735 callgsubr # -735 + bias = 396
   625  			// :	:	# Arg stack is [12 424 3].
   626  			// :	:	104 rlineto
   627  			lineTo(205, 645),
   628  			lineTo(208, 749),
   629  			// :	:	-93 hlineto
   630  			lineTo(115, 749),
   631  			// :	:	3 -104 rlineto
   632  			lineTo(118, 645),
   633  			// :	:	return
   634  			// :	:	# Arg stack is [].
   635  			// :	return
   636  			// :	# Arg stack is [].
   637  			// hintmask 01100000
   638  			// 106 callsubr # 106 + bias = 213
   639  			// :	# Arg stack is [].
   640  			// :	43 -658 rmoveto
   641  			lineTo(130, 221),
   642  			moveTo(161, -13),
   643  			// :	37 29 28 41 return
   644  			// :	# Arg stack is [37 29 28 41].
   645  			// hvcurveto
   646  			cubeTo(198, -13, 227, 15, 227, 56),
   647  			// hintmask 10100000
   648  			// 41 -29 30 -37 -36 -30 -30 -41 vhcurveto
   649  			cubeTo(227, 97, 198, 127, 161, 127),
   650  			cubeTo(125, 127, 95, 97, 95, 56),
   651  			// hintmask 01100000
   652  			// 111 callsubr # 111 + bias = 218
   653  			// :	# Arg stack is [].
   654  			// :	-41 30 -28 36 vhcurveto
   655  			cubeTo(95, 15, 125, -13, 161, -13),
   656  			// :	endchar
   657  		},
   658  
   659  		'二': { // U+4E8C <CJK Ideograph> "two; twice"
   660  			// 23 81 510 79 hstem
   661  			// 60 881 cntrmask 11000000
   662  			// 144 693 rmoveto
   663  			moveTo(144, 693),
   664  			// -79 713 79 vlineto
   665  			lineTo(144, 614),
   666  			lineTo(857, 614),
   667  			lineTo(857, 693),
   668  			// -797 -589 rmoveto
   669  			lineTo(144, 693),
   670  			moveTo(60, 104),
   671  			// -81 881 81 vlineto
   672  			lineTo(60, 23),
   673  			lineTo(941, 23),
   674  			lineTo(941, 104),
   675  			// endchar
   676  			lineTo(60, 104),
   677  		},
   678  	},
   679  
   680  	"adobe/SourceSansPro-Black.otf": {
   681  		'¤': { // U+00A4 CURRENCY SIGN
   682  			// -45 147 99 168 98 hstem
   683  			// 44 152 148 152 vstem
   684  			// 102 76 rmoveto
   685  			moveTo(102, 76),
   686  			// 71 71 rlineto
   687  			lineTo(173, 147),
   688  			// 31 -13 33 -6 33 32 34 6 31 hflex1
   689  			cubeTo(204, 134, 237, 128, 270, 128),
   690  			cubeTo(302, 128, 336, 134, 367, 147),
   691  			// 71 -71 85 85 -61 60 rlineto
   692  			lineTo(438, 76),
   693  			lineTo(523, 161),
   694  			lineTo(462, 221),
   695  			// 21 30 13 36 43 vvcurveto
   696  			cubeTo(483, 251, 496, 287, 496, 330),
   697  			// 42 -12 36 -21 29 vhcurveto
   698  			cubeTo(496, 372, 484, 408, 463, 437),
   699  			// 60 60 -85 85 -70 -70 rlineto
   700  			lineTo(523, 497),
   701  			lineTo(438, 582),
   702  			lineTo(368, 512),
   703  			// -31 13 -34 7 -33 -33 -34 -7 -31 hflex1
   704  			cubeTo(337, 525, 303, 532, 270, 532),
   705  			cubeTo(237, 532, 203, 525, 172, 512),
   706  			// -70 70 -85 -85 59 -60 rlineto
   707  			lineTo(102, 582),
   708  			lineTo(17, 497),
   709  			lineTo(76, 437),
   710  			// -20 -29 -12 -36 -42 vvcurveto
   711  			cubeTo(56, 408, 44, 372, 44, 330),
   712  			// -43 12 -36 21 -30 vhcurveto
   713  			cubeTo(44, 287, 56, 251, 77, 221),
   714  			// -60 -60 rlineto
   715  			lineTo(17, 161),
   716  			// 253 85 rmoveto
   717  			lineTo(102, 76),
   718  			moveTo(270, 246),
   719  			// -42 -32 32 52 52 32 32 42 42 32 -32 -52 -52 -32 -32 -42 hvcurveto
   720  			cubeTo(228, 246, 196, 278, 196, 330),
   721  			cubeTo(196, 382, 228, 414, 270, 414),
   722  			cubeTo(312, 414, 344, 382, 344, 330),
   723  			cubeTo(344, 278, 312, 246, 270, 246),
   724  			// endchar
   725  		},
   726  	},
   727  
   728  	"adobe/SourceSansPro-Regular.otf": {
   729  		',': {
   730  			// -309 -1 115 hstem
   731  			// 137 61 vstem
   732  			// 67 -170 rmoveto
   733  			moveTo(67, -170),
   734  			// 81 34 50 67 86 vvcurveto
   735  			cubeTo(148, -136, 198, -69, 198, 17),
   736  			// 60 -26 37 -43 -33 -28 -22 -36 -37 27 -20 32 3 4 0 1 3 vhcurveto
   737  			cubeTo(198, 77, 172, 114, 129, 114),
   738  			cubeTo(96, 114, 68, 92, 68, 56),
   739  			cubeTo(68, 19, 95, -1, 127, -1),
   740  			cubeTo(130, -1, 134, -1, 137, 0),
   741  			// 1 -53 -34 -44 -57 -25 rrcurveto
   742  			cubeTo(138, -53, 104, -97, 47, -122),
   743  			// endchar
   744  			lineTo(67, -170),
   745  		},
   746  
   747  		'Q': {
   748  			// 106 -165 70 87 65 538 73 hstem
   749  			// 52 86 388 87 vstem
   750  			// 332 57 rmoveto
   751  			moveTo(332, 57),
   752  			// -117 -77 106 168 163 77 101 117 117 77 -101 -163 -168 -77 -106 -117 hvcurveto
   753  			cubeTo(215, 57, 138, 163, 138, 331),
   754  			cubeTo(138, 494, 215, 595, 332, 595),
   755  			cubeTo(449, 595, 526, 494, 526, 331),
   756  			cubeTo(526, 163, 449, 57, 332, 57),
   757  			// 201 -222 rmoveto
   758  			moveTo(533, -165),
   759  			// 39 35 7 8 20 hvcurveto
   760  			cubeTo(572, -165, 607, -158, 627, -150),
   761  			// -16 64 rlineto
   762  			lineTo(611, -86),
   763  			// -5 -18 -22 -4 -29 hhcurveto
   764  			cubeTo(593, -91, 571, -95, 542, -95),
   765  			// -71 -60 29 58 -30 hvcurveto
   766  			cubeTo(471, -95, 411, -66, 381, -8),
   767  			// 139 24 93 126 189 vvcurveto
   768  			cubeTo(520, 16, 613, 142, 613, 331),
   769  			// 209 -116 128 -165 -165 -115 -127 -210 -193 96 -127 143 -20 vhcurveto
   770  			cubeTo(613, 540, 497, 668, 332, 668),
   771  			cubeTo(167, 668, 52, 541, 52, 331),
   772  			cubeTo(52, 138, 148, 11, 291, -9),
   773  			// -90 38 83 -66 121 hhcurveto
   774  			cubeTo(329, -99, 412, -165, 533, -165),
   775  			// endchar
   776  		},
   777  
   778  		'ĩ': { // U+0129 LATIN SMALL LETTER I WITH TILDE
   779  			// 92 callgsubr # 92 + bias = 199.
   780  			// :	# Arg stack is [].
   781  			// :	-312 21 85 callgsubr # 85 + bias = 192.
   782  			// :	:	# Arg stack is [-312 21].
   783  			// :	:	-21 486 -20 return
   784  			// :	:	# Arg stack is [-312 21 -21 486 -20].
   785  			// :	return
   786  			// :	# Arg stack is [-312 21 -21 486 -20].
   787  			// 111 45 callsubr # 45 + bias = 152
   788  			// :	# Arg stack is [-312 21 -21 486 -20 111].
   789  			// :	60 24 60 -9 216 callgsubr # 216 + bias = 323
   790  			// :	:	# Arg stack is [-312 21 -21 486 -20 111 60 24 60 -9].
   791  			// :	:	-20 24 -20 hstemhm
   792  			// :	:	return
   793  			// :	:	# Arg stack is [].
   794  			// :	return
   795  			// :	# Arg stack is [].
   796  			// -50 55 77 82 77 55 hintmask 1101000100000000
   797  			// 134 callsubr # 134 + bias = 241
   798  			// :	# Arg stack is [].
   799  			// :	82 hmoveto
   800  			moveTo(82, 0),
   801  			// :	82 127 callsubr # 127 + bias = 234
   802  			// :	:	# Arg stack is [82].
   803  			// :	:	486 -82 hlineto
   804  			lineTo(164, 0),
   805  			lineTo(164, 486),
   806  			lineTo(82, 486),
   807  			// :	:	return
   808  			// :	:	# Arg stack is [].
   809  			// :	return
   810  			// :	# Arg stack is [].
   811  			// hintmask 1110100110000000
   812  			// 113 91 15 callgsubr # 15 + bias = 122
   813  			// :	# Arg stack is [113 91].
   814  			// :	rmoveto
   815  			lineTo(82, 0),
   816  			moveTo(195, 577),
   817  			// :	69 29 58 77 3 hvcurveto
   818  			cubeTo(264, 577, 293, 635, 296, 712),
   819  			// :	return
   820  			// :	# Arg stack is [].
   821  			// hintmask 1110010110000000
   822  			// -58 callsubr # -58 + bias = 49
   823  			// :	# Arg stack is [].
   824  			// :	-55 4 rlineto
   825  			lineTo(241, 716),
   826  			// :	-46 -3 -14 -33 -29 -47 -26 84 -71 hhcurveto
   827  			cubeTo(238, 670, 224, 637, 195, 637),
   828  			cubeTo(148, 637, 122, 721, 51, 721),
   829  			// :	return
   830  			// :	# Arg stack is [].
   831  			// hintmask 1101001100000000
   832  			// -70 callgsubr # -70 + bias = 37
   833  			// :	# Arg stack is [].
   834  			// :	-69 -29 -58 -78 -3 hvcurveto
   835  			cubeTo(-18, 721, -47, 663, -50, 585),
   836  			// :	55 -3 rlineto
   837  			lineTo(5, 582),
   838  			// :	47 3 14 32 30 hhcurveto
   839  			cubeTo(8, 629, 22, 661, 52, 661),
   840  			// :	return
   841  			// :	# Arg stack is [].
   842  			// hintmask 1110100110000000
   843  			// 51 callsubr # 51 + bias = 158
   844  			// :	# Arg stack is [].
   845  			// :	46 26 -84 71 hhcurveto
   846  			cubeTo(98, 661, 124, 577, 195, 577),
   847  			// :	endchar
   848  		},
   849  
   850  		'ī': { // U+012B LATIN SMALL LETTER I WITH MACRON
   851  			// 92 callgsubr # 92 + bias = 199.
   852  			// :	# Arg stack is [].
   853  			// :	-312 21 85 callgsubr # 85 + bias = 192.
   854  			// :	:	# Arg stack is [-312 21].
   855  			// :	:	-21 486 -20 return
   856  			// :	:	# Arg stack is [-312 21 -21 486 -20].
   857  			// :	return
   858  			// :	# Arg stack is [-312 21 -21 486 -20].
   859  			// 135 57 112 callgsubr # 112 + bias = 219
   860  			// :	# Arg stack is [-312 21 -21 486 -20 135 57].
   861  			// :	hstem
   862  			// :	82 82 vstem
   863  			// :	134 callsubr # 134 + bias = 241
   864  			// :	:	# Arg stack is [].
   865  			// :	:	82 hmoveto
   866  			moveTo(82, 0),
   867  			// :	:	82 127 callsubr # 127 + bias = 234
   868  			// :	:	:	# Arg stack is [82].
   869  			// :	:	:	486 -82 hlineto
   870  			lineTo(164, 0),
   871  			lineTo(164, 486),
   872  			lineTo(82, 486),
   873  			// :	:	:	return
   874  			// :	:	:	# Arg stack is [].
   875  			// :	:	return
   876  			// :	:	# Arg stack is [].
   877  			// :	return
   878  			// :	# Arg stack is [].
   879  			// -92 115 -60 callgsubr # -60 + bias = 47
   880  			// :	# Arg stack is [-92 115].
   881  			// :	rmoveto
   882  			lineTo(82, 0),
   883  			moveTo(-10, 601),
   884  			// :	266 57 -266 hlineto
   885  			lineTo(256, 601),
   886  			lineTo(256, 658),
   887  			lineTo(-10, 658),
   888  			// :	endchar
   889  			lineTo(-10, 601),
   890  		},
   891  
   892  		'ĭ': { // U+012D LATIN SMALL LETTER I WITH BREVE
   893  			// 92 callgsubr # 92 + bias = 199.
   894  			// :	# Arg stack is [].
   895  			// :	-312 21 85 callgsubr # 85 + bias = 192.
   896  			// :	:	# Arg stack is [-312 21].
   897  			// :	:	-21 486 -20 return
   898  			// :	:	# Arg stack is [-312 21 -21 486 -20].
   899  			// :	return
   900  			// :	# Arg stack is [-312 21 -21 486 -20].
   901  			// 105 55 96 -20 hstem
   902  			// -32 51 63 82 65 51 vstem
   903  			// 134 callsubr # 134 + bias = 241
   904  			// :	# Arg stack is [].
   905  			// :	82 hmoveto
   906  			moveTo(82, 0),
   907  			// :	82 127 callsubr # 127 + bias = 234
   908  			// :	:	# Arg stack is [82].
   909  			// :	:	486 -82 hlineto
   910  			lineTo(164, 0),
   911  			lineTo(164, 486),
   912  			lineTo(82, 486),
   913  			// :	:	return
   914  			// :	:	# Arg stack is [].
   915  			// :	return
   916  			// :	# Arg stack is [].
   917  			// 42 85 143 callsubr # 143 + bias = 250
   918  			// :	# Arg stack is [42 85].
   919  			// :	rmoveto
   920  			lineTo(82, 0),
   921  			moveTo(124, 571),
   922  			// :	-84 callsubr # -84 + bias = 23
   923  			// :	:	# Arg stack is [].
   924  			// :	:	107 44 77 74 5 hvcurveto
   925  			cubeTo(231, 571, 275, 648, 280, 722),
   926  			// :	:	-51 8 rlineto
   927  			lineTo(229, 730),
   928  			// :	:	-51 -8 -32 -53 -65 hhcurveto
   929  			cubeTo(221, 679, 189, 626, 124, 626),
   930  			// :	:	-65 -32 53 51 -8 hvcurveto
   931  			cubeTo(59, 626, 27, 679, 19, 730),
   932  			// :	:	-51 -22 callsubr # -22 + bias = 85
   933  			// :	:	:	# Arg stack is [-51].
   934  			// :	:	:	-8 rlineto
   935  			lineTo(-32, 722),
   936  			// :	:	:	-74 5 44 -77 107 hhcurveto
   937  			cubeTo(-27, 648, 17, 571, 124, 571),
   938  			// :	:	:	return
   939  			// :	:	:	# Arg stack is [].
   940  			// :	:	return
   941  			// :	:	# Arg stack is [].
   942  			// :	return
   943  			// :	# Arg stack is [].
   944  			// endchar
   945  		},
   946  
   947  		'Λ': { // U+039B GREEK CAPITAL LETTER LAMDA
   948  			// -43 21 -21 572 84 hstem
   949  			// 0 515 vstem
   950  			// 0 vmoveto
   951  			moveTo(0, 0),
   952  			// 85 hlineto
   953  			lineTo(85, 0),
   954  			// 105 355 23 77 16 63 24 77 rlinecurve
   955  			lineTo(190, 355),
   956  			cubeTo(213, 432, 229, 495, 253, 572),
   957  			// 4 hlineto
   958  			lineTo(257, 572),
   959  			// 25 -77 16 -63 23 -77 106 -355 rcurveline
   960  			cubeTo(282, 495, 298, 432, 321, 355),
   961  			lineTo(427, 0),
   962  			// 88 hlineto
   963  			lineTo(515, 0),
   964  			// -210 656 rlineto
   965  			lineTo(305, 656),
   966  			// -96 hlineto
   967  			lineTo(209, 656),
   968  			// endchar
   969  			lineTo(0, 0),
   970  		},
   971  
   972  		'Ḫ': { // U+1E2A LATIN CAPITAL LETTER H WITH BREVE BELOW
   973  			// 94 -231 55 197 157 callgsubr # 157 + bias = 264
   974  			// :	# Arg stack is [94 -231 55 197].
   975  			// :	-21 309 72 return
   976  			// :	# Arg stack is [94 -231 55 197 -21 309 72].
   977  			// 275 254 callgsubr # 254 + bias = 361
   978  			// :	# Arg stack is [94 -231 55 197 -21 309 72 275].
   979  			// :	-20 hstemhm
   980  			// :	90 83 return
   981  			// :	# Arg stack is [90 83].
   982  			// -4 352 callsubr # 352 + bias = 459
   983  			// :	# Arg stack is [90 83 -4].
   984  			// :	51 210 51 return
   985  			// :	# Arg stack is [90 83 -4 51 210 51].
   986  			// -3 84 hintmask 11111001
   987  			// 90 -40 callsubr # -40 + bias = 67
   988  			// :	# Arg stack is [90].
   989  			// :	-27 callgsubr # -27 + bias = 80
   990  			// :	:	# Arg stack is [90].
   991  			// :	:	hmoveto
   992  			moveTo(90, 0),
   993  			// :	:	83 309 305 -309 84 return
   994  			// :	:	# Arg stack is [83 309 305 -309 84].
   995  			// :	-41 callgsubr # -41 + bias = 66
   996  			// :	:	# Arg stack is [83 309 305 -309 84].
   997  			// :	:	656 -84 -275 -305 275 -83 return
   998  			// :	:	# Arg stack is [83 309 305 -309 84 656 -84 -275 -305 275 -83].
   999  			// :	hlineto
  1000  			lineTo(173, 0),
  1001  			lineTo(173, 309),
  1002  			lineTo(478, 309),
  1003  			lineTo(478, 0),
  1004  			lineTo(562, 0),
  1005  			lineTo(562, 656),
  1006  			lineTo(478, 656),
  1007  			lineTo(478, 381),
  1008  			lineTo(173, 381),
  1009  			lineTo(173, 656),
  1010  			lineTo(90, 656),
  1011  			// :	return
  1012  			// :	# Arg stack is [].
  1013  			// hintmask 11110110
  1014  			// 235 -887 143 callsubr # 143 + bias = 250
  1015  			// :	# Arg stack is [235 -887].
  1016  			// :	rmoveto
  1017  			lineTo(90, 0),
  1018  			moveTo(325, -231),
  1019  			// :	-84 callsubr # -84 + bias = 23
  1020  			// :	:	# Arg stack is [].
  1021  			// :	:	107 44 77 74 5 hvcurveto
  1022  			cubeTo(432, -231, 476, -154, 481, -80),
  1023  			// :	:	-51 8 rlineto
  1024  			lineTo(430, -72),
  1025  			// :	:	-51 -8 -32 -53 -65 hhcurveto
  1026  			cubeTo(422, -123, 390, -176, 325, -176),
  1027  			// :	:	-65 -32 53 51 -8 hvcurveto
  1028  			cubeTo(260, -176, 228, -123, 220, -72),
  1029  			// :	:	-51 -22 callsubr # -22 + bias = 85
  1030  			// :	:	:	# Arg stack is [-51].
  1031  			// :	:	:	-8 rlineto
  1032  			lineTo(169, -80),
  1033  			// :	:	:	-74 5 44 -77 107 hhcurveto
  1034  			cubeTo(174, -154, 218, -231, 325, -231),
  1035  			// :	:	:	return
  1036  			// :	:	:	# Arg stack is [].
  1037  			// :	:	return
  1038  			// :	:	# Arg stack is [].
  1039  			// :	return
  1040  			// :	# Arg stack is [].
  1041  			// endchar
  1042  		},
  1043  	},
  1044  
  1045  	"apple/Helvetica.dfont?0": {
  1046  		'i': {
  1047  			// - contour #0
  1048  			moveTo(132, 1066),
  1049  			lineTo(315, 1066),
  1050  			lineTo(315, 0),
  1051  			lineTo(132, 0),
  1052  			lineTo(132, 1066),
  1053  			// - contour #1
  1054  			moveTo(132, 1469),
  1055  			lineTo(315, 1469),
  1056  			lineTo(315, 1265),
  1057  			lineTo(132, 1265),
  1058  			lineTo(132, 1469),
  1059  		},
  1060  	},
  1061  
  1062  	"apple/Helvetica.dfont?1": {
  1063  		'i': {
  1064  			// - contour #0
  1065  			moveTo(426, 1220),
  1066  			lineTo(137, 1220),
  1067  			lineTo(137, 1483),
  1068  			lineTo(426, 1483),
  1069  			lineTo(426, 1220),
  1070  			// - contour #1
  1071  			moveTo(137, 1090),
  1072  			lineTo(426, 1090),
  1073  			lineTo(426, 0),
  1074  			lineTo(137, 0),
  1075  			lineTo(137, 1090),
  1076  		},
  1077  	},
  1078  
  1079  	"dejavu/DejaVuSans-ExtraLight.ttf": {
  1080  		'i': {
  1081  			// - contour #0
  1082  			moveTo(230, 1120),
  1083  			lineTo(322, 1120),
  1084  			lineTo(322, 0),
  1085  			lineTo(230, 0),
  1086  			lineTo(230, 1120),
  1087  			// - contour #1
  1088  			moveTo(230, 1556),
  1089  			lineTo(322, 1556),
  1090  			lineTo(322, 1430),
  1091  			lineTo(230, 1430),
  1092  			lineTo(230, 1556),
  1093  		},
  1094  	},
  1095  
  1096  	"microsoft/Arial.ttf": {
  1097  		',': {
  1098  			// - contour #0
  1099  			moveTo(182, 0),
  1100  			lineTo(182, 205),
  1101  			lineTo(387, 205),
  1102  			lineTo(387, 0),
  1103  			quadTo(387, -113, 347, -182),
  1104  			quadTo(307, -252, 220, -290),
  1105  			lineTo(170, -213),
  1106  			quadTo(227, -188, 254, -139),
  1107  			quadTo(281, -91, 284, 0),
  1108  			lineTo(182, 0),
  1109  		},
  1110  
  1111  		'i': {
  1112  			// - contour #0
  1113  			moveTo(136, 1259),
  1114  			lineTo(136, 1466),
  1115  			lineTo(316, 1466),
  1116  			lineTo(316, 1259),
  1117  			lineTo(136, 1259),
  1118  			// - contour #1
  1119  			moveTo(136, 0),
  1120  			lineTo(136, 1062),
  1121  			lineTo(316, 1062),
  1122  			lineTo(316, 0),
  1123  			lineTo(136, 0),
  1124  		},
  1125  
  1126  		'o': {
  1127  			// - contour #0
  1128  			moveTo(68, 531),
  1129  			quadTo(68, 826, 232, 968),
  1130  			quadTo(369, 1086, 566, 1086),
  1131  			quadTo(785, 1086, 924, 942),
  1132  			quadTo(1063, 799, 1063, 546),
  1133  			quadTo(1063, 341, 1001, 223),
  1134  			quadTo(940, 106, 822, 41),
  1135  			quadTo(705, -24, 566, -24),
  1136  			quadTo(343, -24, 205, 119),
  1137  			quadTo(68, 262, 68, 531),
  1138  			// - contour #1
  1139  			moveTo(253, 531),
  1140  			quadTo(253, 327, 342, 225),
  1141  			quadTo(431, 124, 566, 124),
  1142  			quadTo(700, 124, 789, 226),
  1143  			quadTo(878, 328, 878, 537),
  1144  			quadTo(878, 734, 788, 835),
  1145  			quadTo(699, 937, 566, 937),
  1146  			quadTo(431, 937, 342, 836),
  1147  			quadTo(253, 735, 253, 531),
  1148  		},
  1149  
  1150  		'í': { // U+00ED LATIN SMALL LETTER I WITH ACUTE
  1151  			// - contour #0
  1152  			translate(0, 0, moveTo(198, 0)),
  1153  			translate(0, 0, lineTo(198, 1062)),
  1154  			translate(0, 0, lineTo(378, 1062)),
  1155  			translate(0, 0, lineTo(378, 0)),
  1156  			translate(0, 0, lineTo(198, 0)),
  1157  			// - contour #1
  1158  			translate(-33, 0, moveTo(222, 1194)),
  1159  			translate(-33, 0, lineTo(355, 1474)),
  1160  			translate(-33, 0, lineTo(591, 1474)),
  1161  			translate(-33, 0, lineTo(371, 1194)),
  1162  			translate(-33, 0, lineTo(222, 1194)),
  1163  		},
  1164  
  1165  		'Ī': { // U+012A LATIN CAPITAL LETTER I WITH MACRON
  1166  			// - contour #0
  1167  			translate(0, 0, moveTo(191, 0)),
  1168  			translate(0, 0, lineTo(191, 1466)),
  1169  			translate(0, 0, lineTo(385, 1466)),
  1170  			translate(0, 0, lineTo(385, 0)),
  1171  			translate(0, 0, lineTo(191, 0)),
  1172  			// - contour #1
  1173  			translate(-57, 336, moveTo(29, 1227)),
  1174  			translate(-57, 336, lineTo(29, 1375)),
  1175  			translate(-57, 336, lineTo(653, 1375)),
  1176  			translate(-57, 336, lineTo(653, 1227)),
  1177  			translate(-57, 336, lineTo(29, 1227)),
  1178  		},
  1179  
  1180  		// Ǻ is a compound glyph whose elements are also compound glyphs.
  1181  		'Ǻ': { // U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
  1182  			// - contour #0
  1183  			translate(0, 0, moveTo(-3, 0)),
  1184  			translate(0, 0, lineTo(560, 1466)),
  1185  			translate(0, 0, lineTo(769, 1466)),
  1186  			translate(0, 0, lineTo(1369, 0)),
  1187  			translate(0, 0, lineTo(1148, 0)),
  1188  			translate(0, 0, lineTo(977, 444)),
  1189  			translate(0, 0, lineTo(364, 444)),
  1190  			translate(0, 0, lineTo(203, 0)),
  1191  			translate(0, 0, lineTo(-3, 0)),
  1192  			// - contour #1
  1193  			translate(0, 0, moveTo(420, 602)),
  1194  			translate(0, 0, lineTo(917, 602)),
  1195  			translate(0, 0, lineTo(764, 1008)),
  1196  			translate(0, 0, quadTo(694, 1193, 660, 1312)),
  1197  			translate(0, 0, quadTo(632, 1171, 581, 1032)),
  1198  			translate(0, 0, lineTo(420, 602)),
  1199  			// - contour #2
  1200  			translate(319, 263, moveTo(162, 1338)),
  1201  			translate(319, 263, quadTo(162, 1411, 215, 1464)),
  1202  			translate(319, 263, quadTo(269, 1517, 342, 1517)),
  1203  			translate(319, 263, quadTo(416, 1517, 469, 1463)),
  1204  			translate(319, 263, quadTo(522, 1410, 522, 1334)),
  1205  			translate(319, 263, quadTo(522, 1257, 469, 1204)),
  1206  			translate(319, 263, quadTo(416, 1151, 343, 1151)),
  1207  			translate(319, 263, quadTo(268, 1151, 215, 1204)),
  1208  			translate(319, 263, quadTo(162, 1258, 162, 1338)),
  1209  			// - contour #3
  1210  			translate(319, 263, moveTo(238, 1337)),
  1211  			translate(319, 263, quadTo(238, 1290, 269, 1258)),
  1212  			translate(319, 263, quadTo(301, 1226, 344, 1226)),
  1213  			translate(319, 263, quadTo(387, 1226, 418, 1258)),
  1214  			translate(319, 263, quadTo(450, 1290, 450, 1335)),
  1215  			translate(319, 263, quadTo(450, 1380, 419, 1412)),
  1216  			translate(319, 263, quadTo(388, 1444, 344, 1444)),
  1217  			translate(319, 263, quadTo(301, 1444, 269, 1412)),
  1218  			translate(319, 263, quadTo(238, 1381, 238, 1337)),
  1219  			// - contour #4
  1220  			translate(339, 650, moveTo(222, 1194)),
  1221  			translate(339, 650, lineTo(355, 1474)),
  1222  			translate(339, 650, lineTo(591, 1474)),
  1223  			translate(339, 650, lineTo(371, 1194)),
  1224  			translate(339, 650, lineTo(222, 1194)),
  1225  		},
  1226  
  1227  		'﴾': { // U+FD3E ORNATE LEFT PARENTHESIS.
  1228  			// - contour #0
  1229  			moveTo(560, -384),
  1230  			lineTo(516, -429),
  1231  			quadTo(412, -304, 361, -226),
  1232  			quadTo(258, -68, 201, 106),
  1233  			quadTo(127, 334, 127, 595),
  1234  			quadTo(127, 845, 201, 1069),
  1235  			quadTo(259, 1246, 361, 1404),
  1236  			quadTo(414, 1487, 514, 1608),
  1237  			lineTo(560, 1566),
  1238  			quadTo(452, 1328, 396, 1094),
  1239  			quadTo(336, 845, 336, 603),
  1240  			quadTo(336, 359, 370, 165),
  1241  			quadTo(398, 8, 454, -142),
  1242  			quadTo(482, -217, 560, -384),
  1243  		},
  1244  
  1245  		'﴿': { // U+FD3F ORNATE RIGHT PARENTHESIS
  1246  			// - contour #0
  1247  			transform(-1<<14, 0, 0, +1<<14, 653, 0, moveTo(560, -384)),
  1248  			transform(-1<<14, 0, 0, +1<<14, 653, 0, lineTo(516, -429)),
  1249  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(412, -304, 361, -226)),
  1250  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(258, -68, 201, 106)),
  1251  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(127, 334, 127, 595)),
  1252  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(127, 845, 201, 1069)),
  1253  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(259, 1246, 361, 1404)),
  1254  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(414, 1487, 514, 1608)),
  1255  			transform(-1<<14, 0, 0, +1<<14, 653, 0, lineTo(560, 1566)),
  1256  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(452, 1328, 396, 1094)),
  1257  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(336, 845, 336, 603)),
  1258  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(336, 359, 370, 165)),
  1259  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(398, 8, 454, -142)),
  1260  			transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(482, -217, 560, -384)),
  1261  		},
  1262  	},
  1263  
  1264  	"noto/NotoSans-Regular.ttf": {
  1265  		'i': {
  1266  			// - contour #0
  1267  			moveTo(354, 0),
  1268  			lineTo(174, 0),
  1269  			lineTo(174, 1098),
  1270  			lineTo(354, 1098),
  1271  			lineTo(354, 0),
  1272  			// - contour #1
  1273  			moveTo(160, 1395),
  1274  			quadTo(160, 1455, 190, 1482),
  1275  			quadTo(221, 1509, 266, 1509),
  1276  			quadTo(308, 1509, 339, 1482),
  1277  			quadTo(371, 1455, 371, 1395),
  1278  			quadTo(371, 1336, 339, 1308),
  1279  			quadTo(308, 1280, 266, 1280),
  1280  			quadTo(221, 1280, 190, 1308),
  1281  			quadTo(160, 1336, 160, 1395),
  1282  		},
  1283  	},
  1284  }
  1285  
  1286  type boundsTestCase struct {
  1287  	wantBounds fixed.Rectangle26_6
  1288  	wantAdv    fixed.Int26_6
  1289  }
  1290  
  1291  // proprietaryGlyphBoundsTestCases hold expected GlyphBounds. The
  1292  // numerical values can be verified by running the ttx tool.
  1293  // - Advance from hmtx width
  1294  // - Bounds from TTGlyph (with flipped Y axis)
  1295  var proprietaryGlyphBoundsTestCases = map[string]map[rune]boundsTestCase{
  1296  	"adobe/SourceHanSansSC-Regular.otf": {
  1297  		'!': {
  1298  			wantBounds: fixed.Rectangle26_6{
  1299  				Min: fixed.Point26_6{X: 95, Y: -749},
  1300  				Max: fixed.Point26_6{X: 227, Y: 13},
  1301  			},
  1302  			wantAdv: 323,
  1303  		},
  1304  	},
  1305  	"apple/Helvetica.dfont?0": {
  1306  		'i': {
  1307  			wantBounds: fixed.Rectangle26_6{
  1308  				Min: fixed.Point26_6{X: 132, Y: -1469},
  1309  				Max: fixed.Point26_6{X: 315, Y: 0},
  1310  			},
  1311  			wantAdv: 455,
  1312  		},
  1313  	},
  1314  	"microsoft/Arial.ttf": {
  1315  		'A': {
  1316  			wantBounds: fixed.Rectangle26_6{
  1317  				Min: fixed.Point26_6{X: -3, Y: -1466},
  1318  				Max: fixed.Point26_6{X: 1369, Y: 0},
  1319  			},
  1320  			wantAdv: 1366,
  1321  		},
  1322  		// U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE is a
  1323  		// compound glyph whose elements are also compound glyphs.
  1324  		'Ǻ': {
  1325  			wantBounds: fixed.Rectangle26_6{
  1326  				Min: fixed.Point26_6{X: -3, Y: -2124},
  1327  				Max: fixed.Point26_6{X: 1369, Y: 0},
  1328  			},
  1329  			wantAdv: 1366,
  1330  		},
  1331  		// U+FD3E ORNATE LEFT PARENTHESIS.
  1332  		'﴾': {
  1333  			wantBounds: fixed.Rectangle26_6{
  1334  				Min: fixed.Point26_6{X: 127, Y: -1608},
  1335  				Max: fixed.Point26_6{X: 560, Y: 429},
  1336  			},
  1337  			wantAdv: 653,
  1338  		},
  1339  		// U+FD3F ORNATE RIGHT PARENTHESIS is a transformed version of left parenthesis
  1340  		'﴿': {
  1341  			wantBounds: fixed.Rectangle26_6{
  1342  				Min: fixed.Point26_6{X: 93, Y: -1608},
  1343  				Max: fixed.Point26_6{X: 526, Y: 429},
  1344  			},
  1345  			wantAdv: 653,
  1346  		},
  1347  	},
  1348  	"noto/NotoSans-Regular.ttf": {
  1349  		'i': {
  1350  			wantBounds: fixed.Rectangle26_6{
  1351  				Min: fixed.Point26_6{X: 160, Y: -1509},
  1352  				Max: fixed.Point26_6{X: 371, Y: 0},
  1353  			},
  1354  			wantAdv: 528,
  1355  		},
  1356  	},
  1357  }
  1358  
  1359  type kernTestCase struct {
  1360  	ppem    fixed.Int26_6
  1361  	hinting font.Hinting
  1362  	runes   [2]rune
  1363  	want    Units
  1364  }
  1365  
  1366  // proprietaryKernTestCases hold a sample of each font's kerning pairs. The
  1367  // numerical values can be verified by running the ttx tool.
  1368  var proprietaryKernTestCases = map[string][]kernTestCase{
  1369  	"adobe/SourceSansPro-Regular.otf": {
  1370  		{1000, font.HintingNone, [2]rune{'A', 'V'}, -14},
  1371  		{1000, font.HintingNone, [2]rune{'F', '\u0129'}, 36},
  1372  	},
  1373  	"adobe/SourceHanSansSC-Regular.otf": {
  1374  		// U+3043 HIRAGANA LETTER SMALL I
  1375  		// U+3067 HIRAGANA LETTER DE
  1376  		{1000, font.HintingNone, [2]rune{'\u3043', '\u3067'}, -20},
  1377  	},
  1378  	"dejavu/DejaVuSans-ExtraLight.ttf": {
  1379  		{2048, font.HintingNone, [2]rune{'A', 'A'}, 57},
  1380  		{2048, font.HintingNone, [2]rune{'W', 'A'}, -112},
  1381  		// U+00C1 LATIN CAPITAL LETTER A WITH ACUTE
  1382  		// U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
  1383  		// U+1E82 LATIN CAPITAL LETTER W WITH ACUTE
  1384  		{2048, font.HintingNone, [2]rune{'\u00c1', 'A'}, 57},
  1385  		{2048, font.HintingNone, [2]rune{'\u01fa', 'A'}, 57},
  1386  		{2048, font.HintingNone, [2]rune{'\u1e82', 'A'}, -112},
  1387  	},
  1388  	"dejavu/DejaVuSans.ttf": {
  1389  		// U+EF13 + U+EF19 are private use codes, but DejaVuSans has these
  1390  		// codes in a rarely used ClassDef format 1
  1391  		{2048, font.HintingNone, [2]rune{'\uef13', '\uef19'}, -40},
  1392  		{2048, font.HintingNone, [2]rune{'\uef13', '\uef13'}, 0},
  1393  		// Use U+EF13 to trigger default class in ClassDef format 2
  1394  		{2048, font.HintingNone, [2]rune{'A', '\uef13'}, 0},
  1395  	},
  1396  	"microsoft/Arial.ttf": {
  1397  		{2048, font.HintingNone, [2]rune{'A', 'V'}, -152},
  1398  		// U+03B8 GREEK SMALL LETTER THETA
  1399  		// U+03BB GREEK SMALL LETTER LAMDA
  1400  		{2048, font.HintingNone, [2]rune{'\u03b8', '\u03bb'}, -39},
  1401  		{2048, font.HintingNone, [2]rune{'\u03bb', '\u03b8'}, -0},
  1402  	},
  1403  	"microsoft/Comic_Sans_MS.ttf": {
  1404  		{2048, font.HintingNone, [2]rune{'A', 'V'}, 0},
  1405  	},
  1406  	"microsoft/Times_New_Roman.ttf": {
  1407  		{768, font.HintingNone, [2]rune{'A', 'V'}, -99},
  1408  		{768, font.HintingFull, [2]rune{'A', 'V'}, -128},
  1409  		{2048, font.HintingNone, [2]rune{'A', 'A'}, 0},
  1410  		{2048, font.HintingNone, [2]rune{'A', 'T'}, -227},
  1411  		{2048, font.HintingNone, [2]rune{'A', 'V'}, -264},
  1412  		{2048, font.HintingNone, [2]rune{'T', 'A'}, -164},
  1413  		{2048, font.HintingNone, [2]rune{'T', 'T'}, 0},
  1414  		{2048, font.HintingNone, [2]rune{'T', 'V'}, 0},
  1415  		{2048, font.HintingNone, [2]rune{'V', 'A'}, -264},
  1416  		{2048, font.HintingNone, [2]rune{'V', 'T'}, 0},
  1417  		{2048, font.HintingNone, [2]rune{'V', 'V'}, 0},
  1418  		// U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
  1419  		// U+0393 GREEK CAPITAL LETTER GAMMA
  1420  		{2048, font.HintingNone, [2]rune{'\u0390', '\u0393'}, 0},
  1421  		{2048, font.HintingNone, [2]rune{'\u0393', '\u0390'}, 76},
  1422  	},
  1423  	"microsoft/Webdings.ttf": {
  1424  		{2048, font.HintingNone, [2]rune{'\uf041', '\uf042'}, 0},
  1425  	},
  1426  	"noto/NotoSans-Regular.ttf": {
  1427  		{2048, font.HintingNone, [2]rune{'A', 'V'}, -40},
  1428  		{2048, font.HintingNone, [2]rune{'A', 'W'}, -40},
  1429  		{2048, font.HintingNone, [2]rune{'A', 'T'}, -70},
  1430  		{2048, font.HintingNone, [2]rune{'V', 'A'}, -40},
  1431  		{2048, font.HintingNone, [2]rune{'W', 'A'}, -40},
  1432  		{2048, font.HintingNone, [2]rune{'T', 'A'}, -70},
  1433  		// U+00C1 LATIN CAPITAL LETTER A WITH ACUTE
  1434  		// U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
  1435  		// U+1E82 LATIN CAPITAL LETTER W WITH ACUTE
  1436  		{2048, font.HintingNone, [2]rune{'\u00c1', 'T'}, -70},
  1437  		{2048, font.HintingNone, [2]rune{'\u01fa', 'T'}, -70},
  1438  		{2048, font.HintingNone, [2]rune{'\u1e82', 'A'}, -40},
  1439  
  1440  		// NotoSans-Regular.ttf uses two PairPos format=1 tables (with ExtensionPos).
  1441  		// Test first and last pairs in both tables.
  1442  		// First pair in first table
  1443  		{2048, font.HintingNone, [2]rune{'F', '?'}, 20},
  1444  		// U+04c3 CYRILLIC CAPITAL LETTER KA WITH HOOK
  1445  		// U+0424 CYRILLIC CAPITAL LETTER EF
  1446  		// Last pair in first table
  1447  		{2048, font.HintingNone, [2]rune{'\u04c3', '\u0424'}, -20},
  1448  		// First pair in second table
  1449  		{2048, font.HintingNone, [2]rune{'"', 'A'}, -70},
  1450  		// <!-- GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -->
  1451  		// <!-- GREEK UPSILON WITH HOOK SYMBOL -->
  1452  		// Last pair in second table
  1453  		{2048, font.HintingNone, [2]rune{'\u1f4d', '\u03d2'}, -10},
  1454  	},
  1455  }
  1456  
  1457  // proprietaryFDSelectTestCases hold a sample of each font's Font Dict Select
  1458  // (FDSelect) map. The numerical values can be verified by grepping the output
  1459  // of the ttx tool:
  1460  //
  1461  //	grep CharString.*fdSelectIndex SourceHanSansSC-Regular.ttx
  1462  //
  1463  // will print lines like this:
  1464  //
  1465  //	<CharString name="cid00100" fdSelectIndex="15">
  1466  //	<CharString name="cid00101" fdSelectIndex="15">
  1467  //	<CharString name="cid00102" fdSelectIndex="3">
  1468  //	<CharString name="cid00103" fdSelectIndex="15">
  1469  //
  1470  // As for what the values like 3 or 15 actually mean, grepping that ttx file
  1471  // for "FontName" gives this list:
  1472  //
  1473  //	0:	<FontName value="SourceHanSansSC-Regular-Alphabetic"/>
  1474  //	1:	<FontName value="SourceHanSansSC-Regular-AlphabeticDigits"/>
  1475  //	2:	<FontName value="SourceHanSansSC-Regular-Bopomofo"/>
  1476  //	3:	<FontName value="SourceHanSansSC-Regular-Dingbats"/>
  1477  //	4:	<FontName value="SourceHanSansSC-Regular-DingbatsDigits"/>
  1478  //	5:	<FontName value="SourceHanSansSC-Regular-Generic"/>
  1479  //	6:	<FontName value="SourceHanSansSC-Regular-HDingbats"/>
  1480  //	7:	<FontName value="SourceHanSansSC-Regular-HHangul"/>
  1481  //	8:	<FontName value="SourceHanSansSC-Regular-HKana"/>
  1482  //	9:	<FontName value="SourceHanSansSC-Regular-HWidth"/>
  1483  //	10:	<FontName value="SourceHanSansSC-Regular-HWidthCJK"/>
  1484  //	11:	<FontName value="SourceHanSansSC-Regular-HWidthDigits"/>
  1485  //	12:	<FontName value="SourceHanSansSC-Regular-Hangul"/>
  1486  //	13:	<FontName value="SourceHanSansSC-Regular-Ideographs"/>
  1487  //	14:	<FontName value="SourceHanSansSC-Regular-Kana"/>
  1488  //	15:	<FontName value="SourceHanSansSC-Regular-Proportional"/>
  1489  //	16:	<FontName value="SourceHanSansSC-Regular-ProportionalCJK"/>
  1490  //	17:	<FontName value="SourceHanSansSC-Regular-ProportionalDigits"/>
  1491  //	18:	<FontName value="SourceHanSansSC-Regular-VKana"/>
  1492  //
  1493  // As a sanity check, the cmap table maps U+3127 BOPOMOFO LETTER I to the glyph
  1494  // named "cid65353", proprietaryFDSelectTestCases here maps 65353 to Font Dict
  1495  // 2, and the list immediately above maps 2 to "Bopomofo".
  1496  var proprietaryFDSelectTestCases = map[string]map[GlyphIndex]int{
  1497  	"adobe/SourceHanSansSC-Regular.otf": {
  1498  		0:     5,
  1499  		1:     15,
  1500  		2:     15,
  1501  		16:    15,
  1502  		17:    17,
  1503  		26:    17,
  1504  		27:    15,
  1505  		100:   15,
  1506  		101:   15,
  1507  		102:   3,
  1508  		103:   15,
  1509  		777:   4,
  1510  		1000:  3,
  1511  		2000:  3,
  1512  		3000:  13,
  1513  		4000:  13,
  1514  		20000: 13,
  1515  		48000: 12,
  1516  		59007: 1,
  1517  		59024: 0,
  1518  		59087: 8,
  1519  		59200: 7,
  1520  		59211: 6,
  1521  		60000: 13,
  1522  		63000: 16,
  1523  		63039: 9,
  1524  		63060: 11,
  1525  		63137: 10,
  1526  		65353: 2,
  1527  		65486: 14,
  1528  		65505: 18,
  1529  		65506: 5,
  1530  		65533: 5,
  1531  		65534: 5,
  1532  	},
  1533  }
  1534  

View as plain text