1
2
3
4
5
6 package truetype
7
8 import (
9 "reflect"
10 "strings"
11 "testing"
12
13 "golang.org/x/image/math/fixed"
14 )
15
16 func TestBytecode(t *testing.T) {
17 testCases := []struct {
18 desc string
19 prog []byte
20 want []int32
21 errStr string
22 }{
23 {
24 "underflow",
25 []byte{
26 opDUP,
27 },
28 nil,
29 "underflow",
30 },
31 {
32 "infinite loop",
33 []byte{
34 opPUSHW000,
35 0xff,
36 0xff,
37 opDUP,
38 opJMPR,
39 },
40 nil,
41 "too many steps",
42 },
43 {
44 "unbalanced if/else",
45 []byte{
46 opPUSHB000,
47 0,
48 opIF,
49 },
50 nil,
51 "unbalanced",
52 },
53 {
54 "vector set/gets",
55 []byte{
56 opSVTCA1,
57 opGPV,
58 opSVTCA0,
59 opGFV,
60 opNEG,
61 opSPVFS,
62 opSFVTPV,
63 opPUSHB000,
64 1,
65 opGFV,
66 opPUSHB000,
67 2,
68 },
69 []int32{0x4000, 0, 1, 0, -0x4000, 2},
70 "",
71 },
72 {
73 "jumps",
74 []byte{
75 opPUSHB001,
76 10,
77 2,
78 opJMPR,
79 opDUP,
80 opDUP,
81 opPUSHB010,
82 20,
83 2,
84 1,
85 opJROT,
86 opDUP,
87 opDUP,
88 opPUSHB010,
89 30,
90 2,
91 1,
92 opJROF,
93 opDUP,
94 opDUP,
95 },
96 []int32{10, 10, 20, 20, 30, 30, 30},
97 "",
98 },
99 {
100 "stack ops",
101 []byte{
102 opPUSHB010,
103 10,
104 20,
105 30,
106 opCLEAR,
107 opPUSHB010,
108 40,
109 50,
110 60,
111 opSWAP,
112 opDUP,
113 opDUP,
114 opPOP,
115 opDEPTH,
116 opCINDEX,
117 opPUSHB000,
118 4,
119 opMINDEX,
120 },
121 []int32{40, 50, 50, 40, 60},
122 "",
123 },
124 {
125 "push ops",
126 []byte{
127 opPUSHB000,
128 255,
129 opPUSHW001,
130 255,
131 254,
132 0,
133 253,
134 opNPUSHB,
135 2,
136 1,
137 2,
138 opNPUSHW,
139 3,
140 4,
141 5,
142 6,
143 7,
144 8,
145 9,
146 },
147 []int32{255, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809},
148 "",
149 },
150 {
151 "store ops",
152 []byte{
153 opPUSHB011,
154 1,
155 22,
156 3,
157 44,
158 opWS,
159 opWS,
160 opPUSHB000,
161 3,
162 opRS,
163 },
164 []int32{44},
165 "",
166 },
167 {
168 "comparison ops",
169 []byte{
170 opPUSHB001,
171 10,
172 20,
173 opLT,
174 opPUSHB001,
175 10,
176 20,
177 opLTEQ,
178 opPUSHB001,
179 10,
180 20,
181 opGT,
182 opPUSHB001,
183 10,
184 20,
185 opGTEQ,
186 opEQ,
187 opNEQ,
188 },
189 []int32{1, 0},
190 "",
191 },
192 {
193 "odd/even",
194
195 []byte{
196 opPUSHB000,
197 159,
198 opODD,
199 opPUSHB000,
200 160,
201 opODD,
202 opPUSHB000,
203 128,
204 opEVEN,
205 opPUSHB000,
206 64,
207 opEVEN,
208 },
209 []int32{0, 1, 1, 0},
210 "",
211 },
212 {
213 "if true",
214 []byte{
215 opPUSHB001,
216 255,
217 1,
218 opIF,
219 opPUSHB000,
220 2,
221 opEIF,
222 opPUSHB000,
223 254,
224 },
225 []int32{255, 2, 254},
226 "",
227 },
228 {
229 "if false",
230 []byte{
231 opPUSHB001,
232 255,
233 0,
234 opIF,
235 opPUSHB000,
236 2,
237 opEIF,
238 opPUSHB000,
239 254,
240 },
241 []int32{255, 254},
242 "",
243 },
244 {
245 "if/else true",
246 []byte{
247 opPUSHB000,
248 1,
249 opIF,
250 opPUSHB000,
251 2,
252 opELSE,
253 opPUSHB000,
254 3,
255 opEIF,
256 },
257 []int32{2},
258 "",
259 },
260 {
261 "if/else false",
262 []byte{
263 opPUSHB000,
264 0,
265 opIF,
266 opPUSHB000,
267 2,
268 opELSE,
269 opPUSHB000,
270 3,
271 opEIF,
272 },
273 []int32{3},
274 "",
275 },
276 {
277 "if/else true if/else false",
278
279 []byte{
280 opPUSHB010,
281 255,
282 0,
283 1,
284 opIF,
285 opIF,
286 opPUSHB001,
287 0x58,
288 0x58,
289 opELSE,
290 opPUSHW000,
291 0x58,
292 0x58,
293 opEIF,
294 opELSE,
295 opIF,
296 opNPUSHB,
297 3,
298 0x58,
299 0x58,
300 0x58,
301 opELSE,
302 opNPUSHW,
303 2,
304 0x58,
305 0x58,
306 0x58,
307 0x58,
308 opEIF,
309 opEIF,
310 opPUSHB000,
311 254,
312 },
313 []int32{255, 0x5858, 254},
314 "",
315 },
316 {
317 "if/else false if/else true",
318
319 []byte{
320 opPUSHB010,
321 255,
322 1,
323 0,
324 opIF,
325 opIF,
326 opPUSHB001,
327 0x58,
328 0x58,
329 opELSE,
330 opPUSHW000,
331 0x58,
332 0x58,
333 opEIF,
334 opELSE,
335 opIF,
336 opNPUSHB,
337 3,
338 0x58,
339 0x58,
340 0x58,
341 opELSE,
342 opNPUSHW,
343 2,
344 0x58,
345 0x58,
346 0x58,
347 0x58,
348 opEIF,
349 opEIF,
350 opPUSHB000,
351 254,
352 },
353 []int32{255, 0x58, 0x58, 0x58, 254},
354 "",
355 },
356 {
357 "logical ops",
358 []byte{
359 opPUSHB010,
360 0,
361 10,
362 20,
363 opAND,
364 opOR,
365 opNOT,
366 },
367 []int32{0},
368 "",
369 },
370 {
371 "arithmetic ops",
372
373
374 []byte{
375 opPUSHB010,
376 1 << 6,
377 2 << 6,
378 3 << 6,
379 opMUL,
380 opSUB,
381 opNEG,
382 opPUSHB000,
383 2 << 6,
384 opDIV,
385 opPUSHB000,
386 1,
387 opADD,
388 opABS,
389 },
390 []int32{161},
391 "",
392 },
393 {
394 "floor, ceiling",
395 []byte{
396 opPUSHB000,
397 96,
398 opFLOOR,
399 opPUSHB000,
400 96,
401 opCEILING,
402 },
403 []int32{64, 128},
404 "",
405 },
406 {
407 "rounding",
408
409
410 []byte{
411 opROFF,
412 opPUSHB000,
413 90,
414 opROUND00,
415 opRTG,
416 opPUSHB000,
417 90,
418 opROUND00,
419 opRTHG,
420 opPUSHB000,
421 90,
422 opROUND00,
423 opRDTG,
424 opPUSHB000,
425 90,
426 opROUND00,
427 opRUTG,
428 opPUSHB000,
429 90,
430 opROUND00,
431 opRTDG,
432 opPUSHB000,
433 90,
434 opROUND00,
435 },
436 []int32{90, 64, 96, 64, 128, 96},
437 "",
438 },
439 {
440 "super-rounding",
441
442
443 []byte{
444 opPUSHB000,
445 0x58,
446 opSROUND,
447 opPUSHW000,
448 0xff,
449 0xaf,
450 opROUND00,
451 opPUSHW000,
452 0xff,
453 0xb0,
454 opROUND00,
455 opPUSHW000,
456 0xff,
457 0xef,
458 opROUND00,
459 opPUSHW000,
460 0xff,
461 0xf0,
462 opROUND00,
463 opPUSHB000,
464 0,
465 opROUND00,
466 opPUSHB000,
467 16,
468 opROUND00,
469 opPUSHB000,
470 47,
471 opROUND00,
472 opPUSHB000,
473 48,
474 opROUND00,
475 },
476 []int32{-80, -80, -16, -16, 16, 16, 16, 80},
477 "",
478 },
479 {
480 "roll",
481 []byte{
482 opPUSHB010,
483 1,
484 2,
485 3,
486 opROLL,
487 },
488 []int32{2, 3, 1},
489 "",
490 },
491 {
492 "max/min",
493 []byte{
494 opPUSHW001,
495 0xff,
496 0xfe,
497 0xff,
498 0xfd,
499 opMAX,
500 opPUSHW001,
501 0xff,
502 0xfc,
503 0xff,
504 0xfb,
505 opMIN,
506 },
507 []int32{-2, -5},
508 "",
509 },
510 {
511 "functions",
512 []byte{
513 opPUSHB011,
514 3,
515 7,
516 0,
517 3,
518
519 opFDEF,
520 opPUSHB000,
521 98,
522 opENDF,
523
524 opFDEF,
525 opDUP,
526 opADD,
527 opENDF,
528
529 opFDEF,
530 opPUSHB001,
531 10,
532 0,
533 opCALL,
534 opDUP,
535 opENDF,
536
537 opFDEF,
538 opPUSHB000,
539 99,
540 opENDF,
541
542 opPUSHB001,
543 2,
544 0,
545 opCALL,
546 opPUSHB000,
547 3,
548 opLOOPCALL,
549 opPUSHB000,
550 7,
551 opCALL,
552 },
553 []int32{99, 99, 99, 99, 20, 20},
554 "",
555 },
556 }
557
558 for _, tc := range testCases {
559 h := &hinter{}
560 h.init(&Font{
561 maxStorage: 32,
562 maxStackElements: 100,
563 }, 768)
564 err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
565 if err != nil {
566 errStr = err.Error()
567 }
568 if tc.errStr != "" {
569 if errStr == "" {
570 t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
571 } else if !strings.Contains(errStr, tc.errStr) {
572 t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
573 }
574 continue
575 }
576 if errStr != "" {
577 t.Errorf("%s: got error %q, want none", tc.desc, errStr)
578 continue
579 }
580 got := h.stack[:len(tc.want)]
581 if !reflect.DeepEqual(got, tc.want) {
582 t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
583 continue
584 }
585 }
586 }
587
588
589
590 func TestMove(t *testing.T) {
591 h, p := hinter{}, Point{}
592 testCases := []struct {
593 pvX, pvY, fvX, fvY f2dot14
594 wantX, wantY fixed.Int26_6
595 }{
596 {+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
597 {+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
598 {-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
599 {-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
600 {+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
601 {+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
602 {+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
603 {+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
604 {+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
605 {+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
606 {-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
607 {-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
608 {-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
609 {-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
610 {+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
611 {-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
612 {+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
613 {-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
614 {-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
615 {+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
616 {+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
617 }
618 for _, tc := range testCases {
619 p = Point{}
620 h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
621 h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
622 h.move(&p, 1000, true)
623 tx := p.Flags&flagTouchedX != 0
624 ty := p.Flags&flagTouchedY != 0
625 wantTX := tc.fvX != 0
626 wantTY := tc.fvY != 0
627 if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
628 t.Errorf("pv=%v, fv=%v\ngot %d, %d, %t, %t\nwant %d, %d, %t, %t",
629 h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
630 continue
631 }
632
633
634 a := int64(p.X) * int64(tc.fvY)
635 b := int64(p.Y) * int64(tc.fvX)
636 if a != b {
637 t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
638 continue
639 }
640
641
642 dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
643 if dotProd != 1000 {
644 t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
645 continue
646 }
647 }
648 }
649
650
651
652 func TestNormalize(t *testing.T) {
653 testCases := [][2]f2dot14{
654 {-15895, 3974},
655 {-15543, 5181},
656 {-14654, 7327},
657 {-11585, 11585},
658 {0, 16384},
659 {11585, 11585},
660 {14654, 7327},
661 {15543, 5181},
662 {15895, 3974},
663 {16066, 3213},
664 {16161, 2694},
665 {16219, 2317},
666 {16257, 2032},
667 {16284, 1809},
668 }
669 for i, want := range testCases {
670 got := normalize(f2dot14(i)-4, 1)
671 if got != want {
672 t.Errorf("i=%d: got %v, want %v", i, got, want)
673 }
674 }
675 }
676
View as plain text