1
2
3
4
5 package sfnt
6
7 import (
8 "bytes"
9 "fmt"
10 "image"
11 "io/ioutil"
12 "path/filepath"
13 "testing"
14
15 "golang.org/x/image/font"
16 "golang.org/x/image/font/gofont/gobold"
17 "golang.org/x/image/font/gofont/gomono"
18 "golang.org/x/image/font/gofont/goregular"
19 "golang.org/x/image/math/fixed"
20 )
21
22 func pt(x, y fixed.Int26_6) fixed.Point26_6 {
23 return fixed.Point26_6{X: x, Y: y}
24 }
25
26 func moveTo(xa, ya fixed.Int26_6) Segment {
27 return Segment{
28 Op: SegmentOpMoveTo,
29 Args: [3]fixed.Point26_6{pt(xa, ya)},
30 }
31 }
32
33 func lineTo(xa, ya fixed.Int26_6) Segment {
34 return Segment{
35 Op: SegmentOpLineTo,
36 Args: [3]fixed.Point26_6{pt(xa, ya)},
37 }
38 }
39
40 func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
41 return Segment{
42 Op: SegmentOpQuadTo,
43 Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb)},
44 }
45 }
46
47 func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
48 return Segment{
49 Op: SegmentOpCubeTo,
50 Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb), pt(xc, yc)},
51 }
52 }
53
54 func translate(dx, dy fixed.Int26_6, s Segment) Segment {
55 translateArgs(&s.Args, dx, dy)
56 return s
57 }
58
59 func transform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, s Segment) Segment {
60 transformArgs(&s.Args, txx, txy, tyx, tyy, dx, dy)
61 return s
62 }
63
64 func checkSegmentsEqual(got, want []Segment) error {
65
66
67
68
69 for i := range got {
70 for j := range got[i].Args {
71 got[i].Args[j].Y *= -1
72 }
73 }
74
75 if len(got) != len(want) {
76 return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
77 len(got), len(want), got, want)
78 }
79 for i, g := range got {
80 if w := want[i]; g != w {
81 return fmt.Errorf("element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v",
82 i, g, w, got, want)
83 }
84 }
85
86
87 if len(got) == 0 {
88 return nil
89 }
90 if got[0].Op != SegmentOpMoveTo {
91 return fmt.Errorf("segments do not start with a moveTo")
92 }
93 var (
94 first, last fixed.Point26_6
95 firstI int
96 )
97 checkClosed := func(lastI int) error {
98 if first != last {
99 return fmt.Errorf("segments[%d:%d] not closed:\nfirst %v\nlast %v", firstI, lastI, first, last)
100 }
101 return nil
102 }
103 for i, g := range got {
104 switch g.Op {
105 case SegmentOpMoveTo:
106 if i != 0 {
107 if err := checkClosed(i); err != nil {
108 return err
109 }
110 }
111 firstI, first, last = i, g.Args[0], g.Args[0]
112 case SegmentOpLineTo:
113 last = g.Args[0]
114 case SegmentOpQuadTo:
115 last = g.Args[1]
116 case SegmentOpCubeTo:
117 last = g.Args[2]
118 }
119 }
120 return checkClosed(len(got))
121 }
122
123 func TestTrueTypeParse(t *testing.T) {
124 f, err := Parse(goregular.TTF)
125 if err != nil {
126 t.Fatalf("Parse: %v", err)
127 }
128 testTrueType(t, f, goregular.TTF)
129 }
130
131 func TestTrueTypeParseReaderAt(t *testing.T) {
132 f, err := ParseReaderAt(bytes.NewReader(goregular.TTF))
133 if err != nil {
134 t.Fatalf("ParseReaderAt: %v", err)
135 }
136 testTrueType(t, f, goregular.TTF)
137 }
138
139 func testTrueType(t *testing.T, f *Font, wantSrc []byte) {
140 if got, want := f.UnitsPerEm(), Units(2048); got != want {
141 t.Errorf("UnitsPerEm: got %d, want %d", got, want)
142 }
143
144
145
146 if got, want := f.NumGlyphs(), 650; got <= want {
147 t.Errorf("NumGlyphs: got %d, want > %d", got, want)
148 }
149
150 buf := &bytes.Buffer{}
151 n, err := f.WriteSourceTo(nil, buf)
152 if err != nil {
153 t.Fatalf("WriteSourceTo: %v", err)
154 }
155
156
157
158 got := (n + 3) &^ 3
159 have := (int64(len(wantSrc)) + 3) &^ 3
160
161 if (n > int64(len(wantSrc))) || (got != have) {
162 t.Fatalf("WriteSourceTo: got %d, want %d (with rounding)", n, len(wantSrc))
163 } else if gotSrc := buf.Bytes(); !bytes.Equal(gotSrc, wantSrc[:n]) {
164 t.Fatalf("WriteSourceTo: contents differ")
165 }
166 }
167
168 func fontData(name string) []byte {
169 switch name {
170 case "gobold":
171 return gobold.TTF
172 case "gomono":
173 return gomono.TTF
174 case "goregular":
175 return goregular.TTF
176 }
177 panic("unreachable")
178 }
179
180 func TestBounds(t *testing.T) {
181 testCases := map[string]fixed.Rectangle26_6{
182 "gobold": {
183 Min: fixed.Point26_6{
184 X: -452,
185 Y: -2291,
186 },
187 Max: fixed.Point26_6{
188 X: 2190,
189 Y: 492,
190 },
191 },
192 "gomono": {
193 Min: fixed.Point26_6{
194 X: 0,
195 Y: -2291,
196 },
197 Max: fixed.Point26_6{
198 X: 1229,
199 Y: 432,
200 },
201 },
202 "goregular": {
203 Min: fixed.Point26_6{
204 X: -440,
205 Y: -2291,
206 },
207 Max: fixed.Point26_6{
208 X: 2160,
209 Y: 543,
210 },
211 },
212 }
213
214 var b Buffer
215 for name, want := range testCases {
216 f, err := Parse(fontData(name))
217 if err != nil {
218 t.Errorf("Parse(%q): %v", name, err)
219 continue
220 }
221 ppem := fixed.Int26_6(f.UnitsPerEm())
222
223 got, err := f.Bounds(&b, ppem, font.HintingNone)
224 if err != nil {
225 t.Errorf("name=%q: Bounds: %v", name, err)
226 continue
227 }
228 if got != want {
229 t.Errorf("name=%q: Bounds: got %v, want %v", name, got, want)
230 continue
231 }
232 }
233 }
234
235 func TestMetrics(t *testing.T) {
236 cmapFont, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
237 if err != nil {
238 t.Fatal(err)
239 }
240 testCases := map[string]struct {
241 font []byte
242 want font.Metrics
243 }{
244 "goregular": {goregular.TTF, font.Metrics{Height: 2367, Ascent: 1935, Descent: 432, XHeight: 1086, CapHeight: 1480,
245 CaretSlope: image.Point{X: 0, Y: 1}}},
246
247 "cmapTest": {cmapFont, font.Metrics{Height: 1549, Ascent: 1365, Descent: 0, XHeight: 800, CapHeight: 800,
248 CaretSlope: image.Point{X: 20, Y: 100}}},
249 }
250 var b Buffer
251 for name, tc := range testCases {
252 f, err := Parse(tc.font)
253 if err != nil {
254 t.Errorf("name=%q: Parse: %v", name, err)
255 continue
256 }
257 ppem := fixed.Int26_6(f.UnitsPerEm())
258
259 got, err := f.Metrics(&b, ppem, font.HintingNone)
260 if err != nil {
261 t.Errorf("name=%q: Metrics: %v", name, err)
262 continue
263 }
264 if got != tc.want {
265 t.Errorf("name=%q: Metrics: got %v, want %v", name, got, tc.want)
266 continue
267 }
268 }
269 }
270
271 func TestGlyphBounds(t *testing.T) {
272 f, err := Parse(goregular.TTF)
273 if err != nil {
274 t.Fatalf("Parse: %v", err)
275 }
276 ppem := fixed.Int26_6(f.UnitsPerEm())
277
278 testCases := []struct {
279 r rune
280 wantBounds fixed.Rectangle26_6
281 wantAdv fixed.Int26_6
282 }{{
283 r: ' ',
284 wantBounds: fixed.Rectangle26_6{
285 Min: fixed.Point26_6{X: 0, Y: 0},
286 Max: fixed.Point26_6{X: 0, Y: 0},
287 },
288 wantAdv: 569,
289 }, {
290 r: 'A',
291 wantBounds: fixed.Rectangle26_6{
292 Min: fixed.Point26_6{X: 19, Y: -1480},
293 Max: fixed.Point26_6{X: 1342, Y: 0},
294 },
295 wantAdv: 1366,
296 }, {
297 r: 'Á',
298 wantBounds: fixed.Rectangle26_6{
299 Min: fixed.Point26_6{X: 19, Y: -1935},
300 Max: fixed.Point26_6{X: 1342, Y: 0},
301 },
302 wantAdv: 1366,
303 }, {
304 r: 'Æ',
305 wantBounds: fixed.Rectangle26_6{
306 Min: fixed.Point26_6{X: 19, Y: -1480},
307 Max: fixed.Point26_6{X: 1990, Y: 0},
308 },
309 wantAdv: 2048,
310 }, {
311 r: 'i',
312 wantBounds: fixed.Rectangle26_6{
313 Min: fixed.Point26_6{X: 144, Y: -1500},
314 Max: fixed.Point26_6{X: 361, Y: 0}},
315 wantAdv: 505,
316 }, {
317 r: 'j',
318 wantBounds: fixed.Rectangle26_6{
319 Min: fixed.Point26_6{X: -84, Y: -1500},
320 Max: fixed.Point26_6{X: 387, Y: 419},
321 },
322 wantAdv: 519,
323 }, {
324 r: 'x',
325 wantBounds: fixed.Rectangle26_6{
326 Min: fixed.Point26_6{X: 28, Y: -1086},
327 Max: fixed.Point26_6{X: 993, Y: 0},
328 },
329 wantAdv: 1024,
330 }}
331
332 var b Buffer
333 for _, tc := range testCases {
334 gi, err := f.GlyphIndex(&b, tc.r)
335 if err != nil {
336 t.Errorf("r=%q: %v", tc.r, err)
337 continue
338 }
339
340 gotBounds, gotAdv, err := f.GlyphBounds(&b, gi, ppem, font.HintingNone)
341 if err != nil {
342 t.Errorf("r=%q: GlyphBounds: %v", tc.r, err)
343 continue
344 }
345 if gotBounds != tc.wantBounds {
346 t.Errorf("r=%q: Bounds: got %#v, want %#v", tc.r, gotBounds, tc.wantBounds)
347 }
348 if gotAdv != tc.wantAdv {
349 t.Errorf("r=%q: Adv: got %#v, want %#v", tc.r, gotAdv, tc.wantAdv)
350 }
351 }
352 }
353
354 func TestGlyphAdvance(t *testing.T) {
355 testCases := map[string][]struct {
356 r rune
357 want fixed.Int26_6
358 }{
359 "gobold": {
360 {' ', 569},
361 {'A', 1479},
362 {'Á', 1479},
363 {'Æ', 2048},
364 {'i', 592},
365 {'x', 1139},
366 },
367 "gomono": {
368 {' ', 1229},
369 {'A', 1229},
370 {'Á', 1229},
371 {'Æ', 1229},
372 {'i', 1229},
373 {'x', 1229},
374 },
375 "goregular": {
376 {' ', 569},
377 {'A', 1366},
378 {'Á', 1366},
379 {'Æ', 2048},
380 {'i', 505},
381 {'x', 1024},
382 },
383 }
384
385 var b Buffer
386 for name, testCases1 := range testCases {
387 f, err := Parse(fontData(name))
388 if err != nil {
389 t.Errorf("Parse(%q): %v", name, err)
390 continue
391 }
392 ppem := fixed.Int26_6(f.UnitsPerEm())
393
394 for _, tc := range testCases1 {
395 x, err := f.GlyphIndex(&b, tc.r)
396 if err != nil {
397 t.Errorf("name=%q, r=%q: GlyphIndex: %v", name, tc.r, err)
398 continue
399 }
400 got, err := f.GlyphAdvance(&b, x, ppem, font.HintingNone)
401 if err != nil {
402 t.Errorf("name=%q, r=%q: GlyphAdvance: %v", name, tc.r, err)
403 continue
404 }
405 if got != tc.want {
406 t.Errorf("name=%q, r=%q: GlyphAdvance: got %d, want %d", name, tc.r, got, tc.want)
407 continue
408 }
409 }
410 }
411 }
412
413 func TestGoRegularGlyphIndex(t *testing.T) {
414 f, err := Parse(goregular.TTF)
415 if err != nil {
416 t.Fatalf("Parse: %v", err)
417 }
418
419 testCases := []struct {
420 r rune
421 want GlyphIndex
422 }{
423
424 {'\u001f', 0},
425 {'\u0200', 0},
426 {'\u2000', 0},
427
428
429
430
431
432
433
434
435
436
437
438 {'\u0020', 3},
439 {'\u0021', 4},
440 {'\u0022', 5},
441 {'\u0023', 6},
442 {'\u0024', 7},
443 {'\u0025', 8},
444 {'\u0026', 9},
445 {'\u0027', 10},
446
447 {'\u03bd', 413},
448 {'\u03be', 414},
449 {'\u03bf', 415},
450 {'\u03c0', 416},
451 {'\u03c1', 417},
452 {'\u03c2', 418},
453 }
454
455 var b Buffer
456 for _, tc := range testCases {
457 got, err := f.GlyphIndex(&b, tc.r)
458 if err != nil {
459 t.Errorf("r=%q: %v", tc.r, err)
460 continue
461 }
462 if got != tc.want {
463 t.Errorf("r=%q: got %d, want %d", tc.r, got, tc.want)
464 continue
465 }
466 }
467 }
468
469 func TestGlyphIndex(t *testing.T) {
470 data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
471 if err != nil {
472 t.Fatal(err)
473 }
474
475 for _, format := range []int{-1, 0, 4, 12} {
476 testGlyphIndex(t, data, format)
477 }
478 }
479
480 func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) {
481 if cmapFormat >= 0 {
482 originalSupportedCmapFormat := supportedCmapFormat
483 defer func() {
484 supportedCmapFormat = originalSupportedCmapFormat
485 }()
486 supportedCmapFormat = func(format, pid, psid uint16) bool {
487 return int(format) == cmapFormat && originalSupportedCmapFormat(format, pid, psid)
488 }
489 }
490
491 f, err := Parse(data)
492 if err != nil {
493 t.Errorf("cmapFormat=%d: %v", cmapFormat, err)
494 return
495 }
496
497 testCases := []struct {
498 r rune
499 want GlyphIndex
500 }{
501
502 {'?', 0},
503 {'\ufffd', 0},
504 {'\U0001f4a9', 0},
505
506
507
508
509
510
511 {'/', 0},
512 {'0', 3},
513 {'1', 4},
514 {'2', 5},
515 {'3', 0},
516
517 {'@', 0},
518 {'A', 6},
519 {'B', 7},
520 {'C', 0},
521
522 {'`', 0},
523 {'a', 8},
524 {'b', 0},
525
526
527
528
529 {'\u00fe', 0},
530 {'\u00ff', 9},
531 {'\u0100', 10},
532 {'\u0101', 11},
533 {'\u0102', 0},
534
535 {'\u4e2c', 0},
536 {'\u4e2d', 12},
537 {'\u4e2e', 0},
538
539 {'\U0001f0a0', 0},
540 {'\U0001f0a1', 13},
541 {'\U0001f0a2', 0},
542
543 {'\U0001f0b0', 0},
544 {'\U0001f0b1', 14},
545 {'\U0001f0b2', 15},
546 {'\U0001f0b3', 0},
547 }
548
549 var b Buffer
550 for _, tc := range testCases {
551 want := tc.want
552 switch {
553 case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff':
554
555
556 want = 0
557 case cmapFormat == 4 && tc.r > '\uffff':
558
559 want = 0
560 }
561
562 got, err := f.GlyphIndex(&b, tc.r)
563 if err != nil {
564 t.Errorf("cmapFormat=%d, r=%q: %v", cmapFormat, tc.r, err)
565 continue
566 }
567 if got != want {
568 t.Errorf("cmapFormat=%d, r=%q: got %d, want %d", cmapFormat, tc.r, got, want)
569 continue
570 }
571 }
572 }
573
574 func TestPostScriptSegments(t *testing.T) {
575
576
577
578
579
580
581
582
583
584
585
586 wants := [][]Segment{{
587
588
589 moveTo(50, 0),
590 lineTo(450, 0),
591 lineTo(450, 533),
592 lineTo(50, 533),
593 lineTo(50, 0),
594
595 moveTo(100, 50),
596 lineTo(100, 483),
597 lineTo(400, 483),
598 lineTo(400, 50),
599 lineTo(100, 50),
600 }, {
601
602
603 moveTo(300, 700),
604 cubeTo(380, 700, 420, 580, 420, 500),
605 cubeTo(420, 350, 390, 100, 300, 100),
606 cubeTo(220, 100, 180, 220, 180, 300),
607 cubeTo(180, 450, 210, 700, 300, 700),
608
609 moveTo(300, 800),
610 cubeTo(200, 800, 100, 580, 100, 400),
611 cubeTo(100, 220, 200, 0, 300, 0),
612 cubeTo(400, 0, 500, 220, 500, 400),
613 cubeTo(500, 580, 400, 800, 300, 800),
614 }, {
615
616
617 moveTo(100, 0),
618 lineTo(300, 0),
619 lineTo(300, 800),
620 lineTo(100, 800),
621 lineTo(100, 0),
622 }, {
623
624
625 moveTo(657, 237),
626 lineTo(289, 387),
627 lineTo(519, 615),
628 lineTo(657, 237),
629
630 moveTo(792, 169),
631 cubeTo(867, 263, 926, 502, 791, 665),
632 cubeTo(645, 840, 380, 831, 228, 673),
633 cubeTo(71, 509, 110, 231, 242, 93),
634 cubeTo(369, -39, 641, 18, 722, 93),
635 lineTo(802, 3),
636 lineTo(864, 83),
637 lineTo(792, 169),
638 }, {
639
640
641 moveTo(141, 520),
642 lineTo(137, 356),
643 lineTo(245, 400),
644 lineTo(331, 26),
645 lineTo(355, 414),
646 lineTo(463, 434),
647 lineTo(453, 620),
648 lineTo(341, 592),
649 lineTo(331, 758),
650 lineTo(243, 752),
651 lineTo(235, 562),
652 lineTo(141, 520),
653 }}
654
655 testSegments(t, "CFFTest.otf", wants)
656 }
657
658 func TestTrueTypeSegments(t *testing.T) {
659
660
661
662
663
664
665
666
667 wants := [][]Segment{{
668
669
670 moveTo(68, 0),
671 lineTo(68, 1365),
672 lineTo(612, 1365),
673 lineTo(612, 0),
674 lineTo(68, 0),
675
676 moveTo(136, 68),
677 lineTo(544, 68),
678 lineTo(544, 1297),
679 lineTo(136, 1297),
680 lineTo(136, 68),
681 }, {
682
683
684 }, {
685
686
687 }, {
688
689
690 moveTo(614, 1434),
691 quadTo(369, 1434, 369, 614),
692 quadTo(369, 471, 435, 338),
693 quadTo(502, 205, 614, 205),
694 quadTo(860, 205, 860, 1024),
695 quadTo(860, 1167, 793, 1300),
696 quadTo(727, 1434, 614, 1434),
697
698 moveTo(614, 1638),
699 quadTo(1024, 1638, 1024, 819),
700 quadTo(1024, 0, 614, 0),
701 quadTo(205, 0, 205, 819),
702 quadTo(205, 1638, 614, 1638),
703 }, {
704
705
706 moveTo(205, 0),
707 lineTo(205, 1638),
708 lineTo(614, 1638),
709 lineTo(614, 0),
710 lineTo(205, 0),
711 }, {
712
713
714 moveTo(0, 0),
715 lineTo(0, 100),
716 lineTo(400, 100),
717 lineTo(400, 0),
718 lineTo(0, 0),
719 }, {
720
721
722 moveTo(0, 0),
723 lineTo(0, 100),
724 lineTo(400, 100),
725 lineTo(400, 0),
726 lineTo(0, 0),
727
728 translate(111, 234, moveTo(205, 0)),
729 translate(111, 234, lineTo(205, 1638)),
730 translate(111, 234, lineTo(614, 1638)),
731 translate(111, 234, lineTo(614, 0)),
732 translate(111, 234, lineTo(205, 0)),
733 }, {
734
735
736 moveTo(0, 0),
737 lineTo(0, 100),
738 lineTo(400, 100),
739 lineTo(400, 0),
740 lineTo(0, 0),
741
742 transform(1<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
743 transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
744 transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
745 transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
746 transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
747 }, {
748
749
750 moveTo(0, 0),
751 lineTo(0, 100),
752 lineTo(400, 100),
753 lineTo(400, 0),
754 lineTo(0, 0),
755
756 transform(3<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
757 transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
758 transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
759 transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
760 transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
761 }, {
762
763
764 moveTo(0, 0),
765 lineTo(0, 100),
766 lineTo(400, 100),
767 lineTo(400, 0),
768 lineTo(0, 0),
769
770 transform(22381, 8192, 5996, 14188, 237, 258, moveTo(205, 0)),
771 transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 1638)),
772 transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 1638)),
773 transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 0)),
774 transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 0)),
775 }}
776
777 testSegments(t, "glyfTest.ttf", wants)
778 }
779
780 func testSegments(t *testing.T, filename string, wants [][]Segment) {
781 data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/" + filename))
782 if err != nil {
783 t.Fatalf("ReadFile: %v", err)
784 }
785 f, err := Parse(data)
786 if err != nil {
787 t.Fatalf("Parse: %v", err)
788 }
789 ppem := fixed.Int26_6(f.UnitsPerEm())
790
791 if ng := f.NumGlyphs(); ng != len(wants) {
792 t.Fatalf("NumGlyphs: got %d, want %d", ng, len(wants))
793 }
794 var b Buffer
795 for i, want := range wants {
796 got, err := f.LoadGlyph(&b, GlyphIndex(i), ppem, nil)
797 if err != nil {
798 t.Errorf("i=%d: LoadGlyph: %v", i, err)
799 continue
800 }
801 if err := checkSegmentsEqual(got, want); err != nil {
802 t.Errorf("i=%d: %v", i, err)
803 continue
804 }
805 }
806 if _, err := f.LoadGlyph(nil, 0xffff, ppem, nil); err != ErrNotFound {
807 t.Errorf("LoadGlyph(..., 0xffff, ...):\ngot %v\nwant %v", err, ErrNotFound)
808 }
809
810 name, err := f.Name(nil, NameIDFamily)
811 if err != nil {
812 t.Errorf("Name: %v", err)
813 } else if want := filename[:len(filename)-len(".ttf")]; name != want {
814 t.Errorf("Name:\ngot %q\nwant %q", name, want)
815 }
816 }
817
818 func TestPPEM(t *testing.T) {
819 data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf"))
820 if err != nil {
821 t.Fatalf("ReadFile: %v", err)
822 }
823 f, err := Parse(data)
824 if err != nil {
825 t.Fatalf("Parse: %v", err)
826 }
827 var b Buffer
828 x, err := f.GlyphIndex(&b, '1')
829 if err != nil {
830 t.Fatalf("GlyphIndex: %v", err)
831 }
832 if x == 0 {
833 t.Fatalf("GlyphIndex: no glyph index found for the rune '1'")
834 }
835
836 testCases := []struct {
837 ppem fixed.Int26_6
838 want []Segment
839 }{{
840 ppem: fixed.Int26_6(12 << 6),
841 want: []Segment{
842 moveTo(77, 0),
843 lineTo(77, 614),
844 lineTo(230, 614),
845 lineTo(230, 0),
846 lineTo(77, 0),
847 },
848 }, {
849 ppem: fixed.Int26_6(2048),
850 want: []Segment{
851 moveTo(205, 0),
852 lineTo(205, 1638),
853 lineTo(614, 1638),
854 lineTo(614, 0),
855 lineTo(205, 0),
856 },
857 }}
858
859 for i, tc := range testCases {
860 got, err := f.LoadGlyph(&b, x, tc.ppem, nil)
861 if err != nil {
862 t.Errorf("i=%d: LoadGlyph: %v", i, err)
863 continue
864 }
865 if err := checkSegmentsEqual(got, tc.want); err != nil {
866 t.Errorf("i=%d: %v", i, err)
867 continue
868 }
869 }
870 }
871
872 func TestPostInfo(t *testing.T) {
873 data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf"))
874 if err != nil {
875 t.Fatalf("ReadFile: %v", err)
876 }
877 f, err := Parse(data)
878 if err != nil {
879 t.Fatalf("Parse: %v", err)
880 }
881 post := f.PostTable()
882 if post.ItalicAngle != -11.25 {
883 t.Error("ItalicAngle:", post.ItalicAngle)
884 }
885 if post.UnderlinePosition != -255 {
886 t.Error("UnderlinePosition:", post.UnderlinePosition)
887 }
888 if post.UnderlineThickness != 102 {
889 t.Error("UnderlineThickness:", post.UnderlineThickness)
890 }
891 if post.IsFixedPitch {
892 t.Error("IsFixedPitch:", post.IsFixedPitch)
893 }
894 }
895
896 func TestGlyphName(t *testing.T) {
897 f, err := Parse(goregular.TTF)
898 if err != nil {
899 t.Fatalf("Parse: %v", err)
900 }
901
902 testCases := []struct {
903 r rune
904 want string
905 }{
906 {'\x00', "uni0000"},
907 {'!', "exclam"},
908 {'A', "A"},
909 {'{', "braceleft"},
910 {'\u00c4', "Adieresis"},
911 {'\u2020', "dagger"},
912 {'\u2660', "spade"},
913 {'\uf800', "gopher"},
914 {'\ufffe', ".notdef"},
915 }
916
917 var b Buffer
918 for _, tc := range testCases {
919 x, err := f.GlyphIndex(&b, tc.r)
920 if err != nil {
921 t.Errorf("r=%q: GlyphIndex: %v", tc.r, err)
922 continue
923 }
924 got, err := f.GlyphName(&b, x)
925 if err != nil {
926 t.Errorf("r=%q: GlyphName: %v", tc.r, err)
927 continue
928 }
929 if got != tc.want {
930 t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want)
931 continue
932 }
933 }
934 }
935
936 func TestBuiltInPostNames(t *testing.T) {
937 testCases := []struct {
938 x GlyphIndex
939 want string
940 }{
941 {0, ".notdef"},
942 {1, ".null"},
943 {2, "nonmarkingreturn"},
944 {13, "asterisk"},
945 {36, "A"},
946 {93, "z"},
947 {123, "ocircumflex"},
948 {202, "Edieresis"},
949 {255, "Ccaron"},
950 {256, "ccaron"},
951 {257, "dcroat"},
952 {258, ""},
953 {999, ""},
954 {0xffff, ""},
955 }
956
957 for _, tc := range testCases {
958 if tc.x >= numBuiltInPostNames {
959 continue
960 }
961 i := builtInPostNamesOffsets[tc.x+0]
962 j := builtInPostNamesOffsets[tc.x+1]
963 got := builtInPostNamesData[i:j]
964 if got != tc.want {
965 t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want)
966 }
967 }
968 }
969
View as plain text