proprietary_test.go 44 KB

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