1
2
3
4
5 package sfnt
6
7
33
34
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
55
56
57
58
59
60
61
62
63
64 "",
65 "directory name for the Adobe proprietary fonts",
66 )
67
68 appleDir = flag.String(
69 "appleDir",
70
71
72
73
74 "",
75 "directory name for the Apple proprietary fonts",
76 )
77
78 dejavuDir = flag.String(
79 "dejavuDir",
80
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
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
216
217
218
219
220
221
222
223
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
285
286
287
288
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
417
418
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
426
427
428
429
430
431
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
469
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
507
508 var proprietaryGlyphIndexTestCases = map[string]map[rune]GlyphIndex{
509 "adobe/SourceCodePro-Regular.otf": {
510 '\u0030': 877,
511 '\u0041': 2,
512 '\u0061': 28,
513 '\u0104': 64,
514 '\u0125': 323,
515 '\u01f4': 111,
516 '\u03a3': 623,
517 '\u2569': 1500,
518 '\U0001f100': 0,
519 },
520 "adobe/SourceCodePro-Regular.ttf": {
521 '\u0030': 877,
522 '\u0041': 2,
523 '\u01f4': 111,
524 },
525 "adobe/SourceHanSansSC-Regular.otf": {
526 '\u0030': 17,
527 '\u0041': 34,
528 '\u00d7': 150,
529 '\u1100': 365,
530 '\u25ca': 1254,
531 '\u2e9c': 1359,
532 '\u304b': 1463,
533 '\u4e2d': 9893,
534 '\ua960': 47537,
535 '\ufb00': 58919,
536 '\uffee': 59213,
537 '\U0001f100': 59214,
538 '\U0001f248': 59449,
539 '\U0002f9f4': 61768,
540 },
541 "adobe/SourceSansPro-Regular.otf": {
542 '\u0041': 2,
543 '\u03a3': 592,
544 '\u0435': 999,
545 '\u2030': 1728,
546 },
547 "adobe/SourceSansPro-Regular.ttf": {
548 '\u0041': 2,
549 '\u03a3': 592,
550 '\u0435': 999,
551 '\u2030': 1728,
552 },
553
554 "apple/Helvetica.dfont?0": {
555 '\u0041': 36,
556 '\u00f1': 120,
557 '\u0401': 473,
558 '\u200d': 611,
559 '\u20ab': 1743,
560 '\u2229': 0,
561 '\u04e9': 1208,
562 '\U0001f100': 0,
563 },
564
565 "dejavu/DejaVuSerif.ttf": {
566 '\u0041': 36,
567 '\u1e00': 1418,
568 },
569
570 "microsoft/Arial.ttf": {
571 '\u0041': 36,
572 '\u00f1': 120,
573 '\u0401': 556,
574 '\u200d': 745,
575 '\u20ab': 1150,
576 '\u2229': 320,
577 '\u04e9': 1319,
578 '\U0001f100': 0,
579 },
580 "microsoft/Comic_Sans_MS.ttf": {
581 '\u0041': 36,
582 '\u03af': 573,
583 },
584 "microsoft/Times_New_Roman.ttf": {
585 '\u0041': 36,
586 '\u0042': 37,
587 '\u266a': 392,
588 '\uf041': 0,
589 '\uf042': 0,
590 },
591 "microsoft/Webdings.ttf": {
592 '\u0041': 0,
593 '\u0042': 0,
594 '\u266a': 0,
595 '\uf041': 36,
596 '\uf042': 37,
597 },
598 }
599
600
601
602
603
604
605 var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
606 "adobe/SourceHanSansSC-Regular.otf": {
607 '!': {
608
609
610
611
612
613
614
615
616
617
618
619
620
621 moveTo(130, 221),
622
623 lineTo(193, 221),
624
625
626
627 lineTo(205, 645),
628 lineTo(208, 749),
629
630 lineTo(115, 749),
631
632 lineTo(118, 645),
633
634
635
636
637
638
639
640
641 lineTo(130, 221),
642 moveTo(161, -13),
643
644
645
646 cubeTo(198, -13, 227, 15, 227, 56),
647
648
649 cubeTo(227, 97, 198, 127, 161, 127),
650 cubeTo(125, 127, 95, 97, 95, 56),
651
652
653
654
655 cubeTo(95, 15, 125, -13, 161, -13),
656
657 },
658
659 '二': {
660
661
662
663 moveTo(144, 693),
664
665 lineTo(144, 614),
666 lineTo(857, 614),
667 lineTo(857, 693),
668
669 lineTo(144, 693),
670 moveTo(60, 104),
671
672 lineTo(60, 23),
673 lineTo(941, 23),
674 lineTo(941, 104),
675
676 lineTo(60, 104),
677 },
678 },
679
680 "adobe/SourceSansPro-Black.otf": {
681 '¤': {
682
683
684
685 moveTo(102, 76),
686
687 lineTo(173, 147),
688
689 cubeTo(204, 134, 237, 128, 270, 128),
690 cubeTo(302, 128, 336, 134, 367, 147),
691
692 lineTo(438, 76),
693 lineTo(523, 161),
694 lineTo(462, 221),
695
696 cubeTo(483, 251, 496, 287, 496, 330),
697
698 cubeTo(496, 372, 484, 408, 463, 437),
699
700 lineTo(523, 497),
701 lineTo(438, 582),
702 lineTo(368, 512),
703
704 cubeTo(337, 525, 303, 532, 270, 532),
705 cubeTo(237, 532, 203, 525, 172, 512),
706
707 lineTo(102, 582),
708 lineTo(17, 497),
709 lineTo(76, 437),
710
711 cubeTo(56, 408, 44, 372, 44, 330),
712
713 cubeTo(44, 287, 56, 251, 77, 221),
714
715 lineTo(17, 161),
716
717 lineTo(102, 76),
718 moveTo(270, 246),
719
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
725 },
726 },
727
728 "adobe/SourceSansPro-Regular.otf": {
729 ',': {
730
731
732
733 moveTo(67, -170),
734
735 cubeTo(148, -136, 198, -69, 198, 17),
736
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
742 cubeTo(138, -53, 104, -97, 47, -122),
743
744 lineTo(67, -170),
745 },
746
747 'Q': {
748
749
750
751 moveTo(332, 57),
752
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
758 moveTo(533, -165),
759
760 cubeTo(572, -165, 607, -158, 627, -150),
761
762 lineTo(611, -86),
763
764 cubeTo(593, -91, 571, -95, 542, -95),
765
766 cubeTo(471, -95, 411, -66, 381, -8),
767
768 cubeTo(520, 16, 613, 142, 613, 331),
769
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
774 cubeTo(329, -99, 412, -165, 533, -165),
775
776 },
777
778 'ĩ': {
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800 moveTo(82, 0),
801
802
803
804 lineTo(164, 0),
805 lineTo(164, 486),
806 lineTo(82, 486),
807
808
809
810
811
812
813
814
815 lineTo(82, 0),
816 moveTo(195, 577),
817
818 cubeTo(264, 577, 293, 635, 296, 712),
819
820
821
822
823
824
825 lineTo(241, 716),
826
827 cubeTo(238, 670, 224, 637, 195, 637),
828 cubeTo(148, 637, 122, 721, 51, 721),
829
830
831
832
833
834
835 cubeTo(-18, 721, -47, 663, -50, 585),
836
837 lineTo(5, 582),
838
839 cubeTo(8, 629, 22, 661, 52, 661),
840
841
842
843
844
845
846 cubeTo(98, 661, 124, 577, 195, 577),
847
848 },
849
850 'ī': {
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866 moveTo(82, 0),
867
868
869
870 lineTo(164, 0),
871 lineTo(164, 486),
872 lineTo(82, 486),
873
874
875
876
877
878
879
880
881
882 lineTo(82, 0),
883 moveTo(-10, 601),
884
885 lineTo(256, 601),
886 lineTo(256, 658),
887 lineTo(-10, 658),
888
889 lineTo(-10, 601),
890 },
891
892 'ĭ': {
893
894
895
896
897
898
899
900
901
902
903
904
905
906 moveTo(82, 0),
907
908
909
910 lineTo(164, 0),
911 lineTo(164, 486),
912 lineTo(82, 486),
913
914
915
916
917
918
919
920 lineTo(82, 0),
921 moveTo(124, 571),
922
923
924
925 cubeTo(231, 571, 275, 648, 280, 722),
926
927 lineTo(229, 730),
928
929 cubeTo(221, 679, 189, 626, 124, 626),
930
931 cubeTo(59, 626, 27, 679, 19, 730),
932
933
934
935 lineTo(-32, 722),
936
937 cubeTo(-27, 648, 17, 571, 124, 571),
938
939
940
941
942
943
944
945 },
946
947 'Λ': {
948
949
950
951 moveTo(0, 0),
952
953 lineTo(85, 0),
954
955 lineTo(190, 355),
956 cubeTo(213, 432, 229, 495, 253, 572),
957
958 lineTo(257, 572),
959
960 cubeTo(282, 495, 298, 432, 321, 355),
961 lineTo(427, 0),
962
963 lineTo(515, 0),
964
965 lineTo(305, 656),
966
967 lineTo(209, 656),
968
969 lineTo(0, 0),
970 },
971
972 'Ḫ': {
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992 moveTo(90, 0),
993
994
995
996
997
998
999
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
1012
1013
1014
1015
1016
1017 lineTo(90, 0),
1018 moveTo(325, -231),
1019
1020
1021
1022 cubeTo(432, -231, 476, -154, 481, -80),
1023
1024 lineTo(430, -72),
1025
1026 cubeTo(422, -123, 390, -176, 325, -176),
1027
1028 cubeTo(260, -176, 228, -123, 220, -72),
1029
1030
1031
1032 lineTo(169, -80),
1033
1034 cubeTo(174, -154, 218, -231, 325, -231),
1035
1036
1037
1038
1039
1040
1041
1042 },
1043 },
1044
1045 "apple/Helvetica.dfont?0": {
1046 'i': {
1047
1048 moveTo(132, 1066),
1049 lineTo(315, 1066),
1050 lineTo(315, 0),
1051 lineTo(132, 0),
1052 lineTo(132, 1066),
1053
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
1065 moveTo(426, 1220),
1066 lineTo(137, 1220),
1067 lineTo(137, 1483),
1068 lineTo(426, 1483),
1069 lineTo(426, 1220),
1070
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
1082 moveTo(230, 1120),
1083 lineTo(322, 1120),
1084 lineTo(322, 0),
1085 lineTo(230, 0),
1086 lineTo(230, 1120),
1087
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
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
1113 moveTo(136, 1259),
1114 lineTo(136, 1466),
1115 lineTo(316, 1466),
1116 lineTo(316, 1259),
1117 lineTo(136, 1259),
1118
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
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
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 'í': {
1151
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
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 'Ī': {
1166
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
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
1181 'Ǻ': {
1182
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
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
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
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
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 '﴾': {
1228
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 '﴿': {
1246
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
1267 moveTo(354, 0),
1268 lineTo(174, 0),
1269 lineTo(174, 1098),
1270 lineTo(354, 1098),
1271 lineTo(354, 0),
1272
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
1292
1293
1294
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
1323
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
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
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
1367
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
1375
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
1382
1383
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
1390
1391 {2048, font.HintingNone, [2]rune{'\uef13', '\uef19'}, -40},
1392 {2048, font.HintingNone, [2]rune{'\uef13', '\uef13'}, 0},
1393
1394 {2048, font.HintingNone, [2]rune{'A', '\uef13'}, 0},
1395 },
1396 "microsoft/Arial.ttf": {
1397 {2048, font.HintingNone, [2]rune{'A', 'V'}, -152},
1398
1399
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
1419
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
1434
1435
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
1441
1442
1443 {2048, font.HintingNone, [2]rune{'F', '?'}, 20},
1444
1445
1446
1447 {2048, font.HintingNone, [2]rune{'\u04c3', '\u0424'}, -20},
1448
1449 {2048, font.HintingNone, [2]rune{'"', 'A'}, -70},
1450
1451
1452
1453 {2048, font.HintingNone, [2]rune{'\u1f4d', '\u03d2'}, -10},
1454 },
1455 }
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
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