[numberset] Add `wrap_range_prepend'.
[ttfautohint.git] / lib / tafpgm.c
blob1c2081cc66227fcaa42d1487c5db01b017171981
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2017 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
32 GC_orig, \
33 SWAP, \
34 GC_orig, \
35 SWAP, \
36 SUB
38 #define MD_orig_ZP2_0 \
39 MD_orig_fixed
41 #if 0
42 #define MD_orig_ZP2_1 \
43 PUSHB_1, \
44 0, \
45 SZP2, \
46 MD_orig_fixed, \
47 PUSHB_1, \
48 1, \
49 SZP2
50 #endif
54 * Older versions of Monotype's `iType' bytecode interpreter have a serious
55 * bug: The DIV instruction rounds the result, while the correct operation
56 * is truncation. (Note, however, that MUL always rounds the result.)
57 * Since many printers contain this rasterizer without any possibility to
58 * update to a non-buggy version, we have to work around the problem.
60 * DIV and MUL work on 26.6 numbers which means that the numerator gets
61 * multiplied by 64 before the division, and the product gets divided by 64
62 * after the multiplication, respectively. For example, to divide 2 by 3,
63 * you have to write
65 * PUSHB_1,
66 * 2,
67 * 3*64,
68 * DIV
70 * The correct formula to divide two values in 26.6 format with truncation
71 * is
73 * a*64 / b ,
75 * while older `iType' versions incorrectly apply rounding by using
77 * (a*64 + b/2) / b .
79 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
81 * (2*64 + (3*64)/2) / (3*64) = 1
83 * instead of the correct result 0.
85 * The solution to the rounding issue is to use a 26.6 value as an
86 * intermediate result so that we can truncate to the nearest integer (in
87 * 26.6 format) with the FLOOR operator before converting back to a plain
88 * integer (in 32.0 format).
90 * For the common divisions by 2 and 2^10 we define macros.
92 #define DIV_POS_BY_2 \
93 PUSHB_1, \
94 2, \
95 DIV, /* multiply by 64, then divide by 2 */ \
96 FLOOR, \
97 PUSHB_1, \
98 1, \
99 MUL /* multiply by 1, then divide by 64 */
101 #define DIV_BY_2 \
102 PUSHB_1, \
103 2, \
104 DIV, \
105 DUP, \
106 PUSHB_1, \
107 0, \
108 LT, \
109 IF, \
110 PUSHB_1, \
111 64, \
112 ADD, /* add 1 if value is negative */ \
113 EIF, \
114 FLOOR, \
115 PUSHB_1, \
116 1, \
119 #define DIV_BY_1024 \
120 PUSHW_1, \
121 0x04, /* 2^10 */ \
122 0x00, \
123 DIV, \
124 DUP, \
125 PUSHB_1, \
126 0, \
127 LT, \
128 IF, \
129 PUSHB_1, \
130 64, \
131 ADD, \
132 EIF, \
133 FLOOR, \
134 PUSHB_1, \
135 1, \
139 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
140 #define DO_SCALE \
141 DUP, /* s: a a */ \
142 PUSHB_1, \
143 sal_scale, \
144 RS, \
145 MUL, /* delta * 2^10 */ \
146 DIV_BY_1024, /* delta */ \
147 ADD /* a + delta */
150 /* in the comments below, the top of the stack (`s:') */
151 /* is the rightmost element; the stack is shown */
152 /* after the instruction on the same line has been executed */
156 * bci_align_x_height
158 * Optimize the alignment of the top of small letters to the pixel grid.
160 * This function gets used in the `prep' table.
162 * in: blue_idx (CVT index for the style's top of small letters blue zone)
164 * sal: sal_i (CVT index of the style's scaling value;
165 * gets incremented by 1 after execution)
168 static const unsigned char FPGM(bci_align_x_height_a) [] =
171 PUSHB_1,
172 bci_align_x_height,
173 FDEF,
175 /* only get CVT value for non-zero index */
176 DUP,
177 PUSHB_1,
179 NEQ,
181 RCVT,
182 EIF,
183 DUP,
184 DUP, /* s: blue blue blue */
188 /* if (font->increase_x_height) */
189 /* { */
191 static const unsigned char FPGM(bci_align_x_height_b1a) [] =
194 /* apply much `stronger' rounding up of x height for */
195 /* 6 <= PPEM <= increase_x_height */
196 MPPEM,
197 PUSHW_1,
201 /* %d, x height increase limit */
203 static const unsigned char FPGM(bci_align_x_height_b1b) [] =
206 LTEQ,
207 MPPEM,
208 PUSHB_1,
210 GTEQ,
211 AND,
213 PUSHB_1,
214 52, /* threshold = 52 */
216 ELSE,
217 PUSHB_1,
218 40, /* threshold = 40 */
220 EIF,
221 ADD,
222 FLOOR, /* fitted = FLOOR(blue + threshold) */
226 /* } */
228 /* if (!font->increase_x_height) */
229 /* { */
231 static const unsigned char FPGM(bci_align_x_height_b2) [] =
234 PUSHB_1,
236 ADD,
237 FLOOR, /* fitted = FLOOR(blue + 40) */
241 /* } */
243 static const unsigned char FPGM(bci_align_x_height_c) [] =
246 DUP, /* s: blue blue fitted fitted */
247 ROLL,
248 NEQ,
249 IF, /* s: blue fitted */
250 PUSHB_1,
252 CINDEX,
253 SUB, /* s: blue (fitted-blue) */
254 PUSHW_2,
255 0x08, /* 0x800 */
256 0x00,
257 0x08, /* 0x800 */
258 0x00,
259 MUL, /* 0x10000 */
260 MUL, /* (fitted-blue) in 16.16 format */
261 SWAP,
262 DIV, /* factor = ((fitted-blue) / blue) in 16.16 format */
264 ELSE,
265 POP,
266 POP,
267 PUSHB_1,
268 0, /* factor = 0 */
270 EIF,
272 PUSHB_1,
273 sal_i,
274 RS, /* s: factor idx */
275 SWAP,
276 WCVTP,
278 PUSHB_3,
279 sal_i,
281 sal_i,
283 ADD, /* sal_i = sal_i + 1 */
286 ENDF,
292 * bci_round
294 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
295 * engine specific corrections are applied.
297 * in: val
299 * out: ROUND(val)
302 static const unsigned char FPGM(bci_round) [] =
305 PUSHB_1,
306 bci_round,
307 FDEF,
309 PUSHB_1,
311 ADD,
312 FLOOR,
314 ENDF,
320 * bci_smooth_stem_width
322 * This is the equivalent to the following code from function
323 * `ta_latin_compute_stem_width':
325 * dist = |width|
327 * if (stem_is_serif
328 * && dist < 3*64)
329 * || std_width < 40:
330 * return width
331 * else if base_is_round:
332 * if dist < 80:
333 * dist = 64
334 * else if dist < 56:
335 * dist = 56
337 * delta = |dist - std_width|
339 * if delta < 40:
340 * dist = std_width
341 * if dist < 48:
342 * dist = 48
343 * goto End
345 * if dist < 3*64:
346 * delta = dist
347 * dist = FLOOR(dist)
348 * delta = delta - dist
350 * if delta < 10:
351 * dist = dist + delta
352 * else if delta < 32:
353 * dist = dist + 10
354 * else if delta < 54:
355 * dist = dist + 54
356 * else:
357 * dist = dist + delta
358 * else:
359 * bdelta = 0
361 * if width * base_delta > 0:
362 * if ppem < 10:
363 * bdelta = base_delta
364 * else if ppem < 30:
365 * bdelta = (base_delta * (30 - ppem)) / 20
367 * bdelta = |bdelta|
369 * dist = ROUND(dist - bdelta)
371 * End:
372 * if width < 0:
373 * dist = -dist
374 * return dist
376 * If `cvtl_ignore_std_width' is set, we simply set `std_width'
377 * equal to `dist'.
379 * in: width
380 * stem_is_serif
381 * base_is_round
383 * out: new_width
385 * sal: sal_vwidth_data_offset
386 * sal_base_delta
388 * CVT: std_width
389 * cvtl_ignore_std_width
391 * uses: bci_round
394 static const unsigned char FPGM(bci_smooth_stem_width) [] =
397 PUSHB_1,
398 bci_smooth_stem_width,
399 FDEF,
401 DUP,
402 ABS, /* s: base_is_round stem_is_serif width dist */
404 DUP,
405 PUSHB_1,
406 3*64,
407 LT, /* dist < 3*64 */
409 PUSHB_1,
411 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
412 AND, /* stem_is_serif && dist < 3*64 */
414 PUSHB_3,
417 sal_vwidth_data_offset,
419 RCVT, /* first indirection */
420 MUL, /* divide by 64 */
421 RCVT, /* second indirection */
423 PUSHB_1,
424 cvtl_ignore_std_width,
425 RCVT,
427 POP, /* s: ... dist (stem_is_serif && dist < 3*64) 40 */
428 PUSHB_1,
430 CINDEX, /* standard_width = dist */
431 EIF,
433 GT, /* standard_width < 40 */
434 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
436 IF, /* s: base_is_round width dist */
437 POP,
438 SWAP,
439 POP, /* s: width */
441 ELSE,
442 ROLL, /* s: width dist base_is_round */
443 IF, /* s: width dist */
444 DUP,
445 PUSHB_1,
447 LT, /* dist < 80 */
448 IF, /* s: width dist */
449 POP,
450 PUSHB_1,
451 64, /* dist = 64 */
452 EIF,
454 ELSE,
455 DUP,
456 PUSHB_1,
458 LT, /* dist < 56 */
459 IF, /* s: width dist */
460 POP,
461 PUSHB_1,
462 56, /* dist = 56 */
463 EIF,
464 EIF,
466 DUP, /* s: width dist dist */
467 PUSHB_2,
469 sal_vwidth_data_offset,
471 RCVT, /* first indirection */
472 MUL, /* divide by 64 */
473 RCVT, /* second indirection */
474 SUB,
475 ABS, /* s: width dist delta */
477 PUSHB_1,
479 LT, /* delta < 40 */
480 IF, /* s: width dist */
481 POP,
482 PUSHB_2,
484 sal_vwidth_data_offset,
486 RCVT, /* first indirection */
487 MUL, /* divide by 64 */
488 RCVT, /* second indirection; dist = std_width */
489 DUP,
490 PUSHB_1,
492 LT, /* dist < 48 */
494 POP,
495 PUSHB_1,
496 48, /* dist = 48 */
497 EIF,
499 ELSE,
500 DUP, /* s: width dist dist */
501 PUSHB_1,
502 3*64,
503 LT, /* dist < 3*64 */
505 DUP, /* s: width delta dist */
506 FLOOR, /* dist = FLOOR(dist) */
507 DUP, /* s: width delta dist dist */
508 ROLL,
509 ROLL, /* s: width dist delta dist */
510 SUB, /* delta = delta - dist */
512 DUP, /* s: width dist delta delta */
513 PUSHB_1,
515 LT, /* delta < 10 */
516 IF, /* s: width dist delta */
517 ADD, /* dist = dist + delta */
519 ELSE,
520 DUP,
521 PUSHB_1,
523 LT, /* delta < 32 */
525 POP,
526 PUSHB_1,
528 ADD, /* dist = dist + 10 */
530 ELSE,
531 DUP,
532 PUSHB_1,
534 LT, /* delta < 54 */
536 POP,
537 PUSHB_1,
539 ADD, /* dist = dist + 54 */
541 ELSE,
542 ADD, /* dist = dist + delta */
544 EIF,
545 EIF,
546 EIF,
548 ELSE,
549 PUSHB_1,
551 CINDEX, /* s: width dist width */
552 PUSHB_1,
553 sal_base_delta,
555 MUL, /* s: width dist width*base_delta */
556 PUSHB_1,
558 GT, /* width * base_delta > 0 */
560 PUSHB_1,
561 0, /* s: width dist bdelta */
563 MPPEM,
564 PUSHB_1,
566 LT, /* ppem < 10 */
568 POP,
569 PUSHB_1,
570 sal_base_delta,
571 RS, /* bdelta = base_delta */
573 ELSE,
574 MPPEM,
575 PUSHB_1,
577 LT, /* ppem < 30 */
579 POP,
580 PUSHB_1,
582 MPPEM,
583 SUB, /* 30 - ppem */
584 PUSHW_1,
585 0x10, /* 64 * 64 */
586 0x00,
587 MUL, /* (30 - ppem) in 26.6 format */
588 PUSHB_1,
589 sal_base_delta,
591 MUL, /* base_delta * (30 - ppem) */
592 PUSHW_1,
593 0x05, /* 20 * 64 */
594 0x00,
595 DIV, /* bdelta = (base_delta * (30 - ppem)) / 20 */
596 EIF,
597 EIF,
599 ABS, /* bdelta = |bdelta| */
600 SUB, /* dist = dist - bdelta */
601 EIF,
603 PUSHB_1,
604 bci_round,
605 CALL, /* dist = round(dist) */
607 EIF,
608 EIF,
610 SWAP, /* s: dist width */
611 PUSHB_1,
613 LT, /* width < 0 */
615 NEG, /* dist = -dist */
616 EIF,
617 EIF,
619 ENDF,
625 * bci_get_best_width
627 * An auxiliary function for `bci_strong_stem_width'.
629 * in: n (initialized with CVT index for first vertical width)
630 * dist
632 * out: n+1
633 * dist
635 * sal: sal_best
636 * sal_ref
638 * CVT: widths[]
641 static const unsigned char FPGM(bci_get_best_width) [] =
644 PUSHB_1,
645 bci_get_best_width,
646 FDEF,
648 DUP,
649 RCVT, /* s: dist n w */
650 DUP,
651 PUSHB_1,
653 CINDEX, /* s: dist n w w dist */
654 SUB,
655 ABS, /* s: dist n w d */
656 DUP,
657 PUSHB_1,
658 sal_best,
659 RS, /* s: dist n w d d best */
660 LT, /* d < best */
662 PUSHB_1,
663 sal_best,
664 SWAP,
665 WS, /* best = d */
666 PUSHB_1,
667 sal_ref,
668 SWAP,
669 WS, /* reference = w */
671 ELSE,
672 POP,
673 POP,
674 EIF,
676 PUSHB_1,
678 ADD, /* n = n + 1 */
680 ENDF,
686 * bci_strong_stem_width
688 * This is the equivalent to the following code (function
689 * `ta_latin_snap_width' and some lines from
690 * `ta_latin_compute_stem_width'):
692 * best = 64 + 32 + 2
693 * dist = |width|
694 * reference = dist
696 * for n in 0 .. num_widths:
697 * w = widths[n]
698 * d = |dist - w|
700 * if d < best:
701 * best = d
702 * reference = w
704 * if dist >= reference:
705 * if dist < ROUND(reference) + 48:
706 * dist = reference
707 * else:
708 * if dist > ROUND(reference) - 48:
709 * dist = reference
711 * if dist >= 64:
712 * dist = ROUND(dist)
713 * else:
714 * dist = 64
716 * if width < 0:
717 * dist = -dist
718 * return dist
720 * If `cvtl_ignore_std_width' is set, we leave `reference = width'.
722 * in: width
723 * stem_is_serif (unused)
724 * base_is_round (unused)
726 * out: new_width
728 * sal: sal_best
729 * sal_ref
730 * sal_vwidth_data_offset
732 * CVT: widths[]
733 * cvtl_ignore_std_width
735 * uses: bci_get_best_width
736 * bci_round
739 static const unsigned char FPGM(bci_strong_stem_width_a) [] =
742 PUSHB_1,
743 bci_strong_stem_width,
744 FDEF,
746 SWAP,
747 POP,
748 SWAP,
749 POP,
750 DUP,
751 ABS, /* s: width dist */
753 PUSHB_2,
754 sal_best,
755 64 + 32 + 2,
756 WS, /* sal_best = 98 */
758 DUP,
759 PUSHB_1,
760 sal_ref,
761 SWAP,
762 WS, /* sal_ref = width */
764 PUSHB_1,
765 cvtl_ignore_std_width,
766 RCVT,
768 ELSE,
770 /* s: width dist */
771 PUSHB_2,
773 sal_vwidth_data_offset,
775 RCVT,
776 MUL, /* divide by 64; first index of vertical widths */
778 /* s: width dist vw_idx */
779 PUSHB_2,
781 sal_vwidth_data_offset,
783 PUSHB_1,
787 /* %c, number of used styles */
789 static const unsigned char FPGM(bci_strong_stem_width_b) [] =
792 ADD,
793 RCVT, /* number of vertical widths */
794 MUL, /* divide by 64 */
796 /* s: width dist vw_idx loop_count */
797 PUSHB_1,
798 bci_get_best_width,
799 LOOPCALL,
800 /* clean up stack */
801 POP, /* s: width dist */
803 DUP,
804 PUSHB_1,
805 sal_ref,
806 RS, /* s: width dist dist reference */
807 DUP,
808 ROLL,
809 DUP,
810 ROLL,
811 PUSHB_1,
812 bci_round,
813 CALL, /* s: width dist reference dist dist ROUND(reference) */
814 PUSHB_2,
817 CINDEX, /* s: width dist reference dist dist ROUND(reference) 48 reference */
818 PUSHB_1,
820 MINDEX, /* s: width dist reference dist ROUND(reference) 48 reference dist */
822 LTEQ, /* reference <= dist */
823 IF, /* s: width dist reference dist ROUND(reference) 48 */
824 ADD,
825 LT, /* dist < ROUND(reference) + 48 */
827 ELSE,
828 SUB,
829 GT, /* dist > ROUND(reference) - 48 */
830 EIF,
833 SWAP, /* s: width reference=new_dist dist */
834 EIF,
835 POP,
836 EIF, /* !cvtl_ignore_std_width */
838 DUP, /* s: width dist dist */
839 PUSHB_1,
841 GTEQ, /* dist >= 64 */
843 PUSHB_1,
844 bci_round,
845 CALL, /* dist = ROUND(dist) */
847 ELSE,
848 POP,
849 PUSHB_1,
850 64, /* dist = 64 */
851 EIF,
853 SWAP, /* s: dist width */
854 PUSHB_1,
856 LT, /* width < 0 */
858 NEG, /* dist = -dist */
859 EIF,
861 ENDF,
867 * bci_do_loop
869 * An auxiliary function for `bci_loop'.
871 * sal: sal_i (gets incremented by 2 after execution)
872 * sal_func
874 * uses: func[sal_func]
877 static const unsigned char FPGM(bci_loop_do) [] =
880 PUSHB_1,
881 bci_loop_do,
882 FDEF,
884 PUSHB_1,
885 sal_func,
887 CALL,
889 PUSHB_3,
890 sal_i,
892 sal_i,
894 ADD, /* sal_i = sal_i + 2 */
897 ENDF,
903 * bci_loop
905 * Take a range `start'..`end' and a function number and apply the
906 * associated function to the range elements `start', `start+2',
907 * `start+4', ...
909 * in: func_num
910 * end
911 * start
913 * sal: sal_i (counter initialized with `start')
914 * sal_func (`func_num')
916 * uses: bci_loop_do
919 static const unsigned char FPGM(bci_loop) [] =
922 PUSHB_1,
923 bci_loop,
924 FDEF,
926 PUSHB_1,
927 sal_func,
928 SWAP,
929 WS, /* sal_func = func_num */
931 SWAP,
932 DUP,
933 PUSHB_1,
934 sal_i,
935 SWAP,
936 WS, /* sal_i = start */
938 SUB,
939 DIV_POS_BY_2,
940 PUSHB_1,
942 ADD, /* number of loops ((end - start) / 2 + 1) */
944 PUSHB_1,
945 bci_loop_do,
946 LOOPCALL,
948 ENDF,
954 * bci_cvt_rescale
956 * Rescale CVT value by `sal_scale' (in 16.16 format).
958 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
959 * consequently, the calculation `a * b/c' is done as `a + delta' with
960 * `delta = a * (b-c)/c'. This avoids overflow.
962 * in: cvt_idx
964 * out: cvt_idx+1
966 * sal: sal_scale
969 static const unsigned char FPGM(bci_cvt_rescale) [] =
972 PUSHB_1,
973 bci_cvt_rescale,
974 FDEF,
976 DUP,
977 DUP,
978 RCVT,
979 DO_SCALE,
980 WCVTP,
982 PUSHB_1,
984 ADD,
986 ENDF,
992 * bci_cvt_rescale_range
994 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
995 * scaling value.
997 * This function gets used in the `prep' table.
999 * in: num_cvt
1000 * cvt_start_idx
1002 * sal: sal_i (CVT index of the style's scaling value;
1003 * gets incremented by 1 after execution)
1004 * sal_scale
1006 * uses: bci_cvt_rescale
1009 static const unsigned char FPGM(bci_cvt_rescale_range) [] =
1012 PUSHB_1,
1013 bci_cvt_rescale_range,
1014 FDEF,
1016 /* store scaling value in `sal_scale' */
1017 PUSHB_3,
1018 bci_cvt_rescale,
1019 sal_scale,
1020 sal_i,
1022 RCVT,
1023 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
1025 LOOPCALL,
1026 /* clean up stack */
1027 POP,
1029 PUSHB_3,
1030 sal_i,
1032 sal_i,
1034 ADD, /* sal_i = sal_i + 1 */
1037 ENDF,
1043 * bci_vwidth_data_store
1045 * Store a vertical width array value.
1047 * This function gets used in the `prep' table.
1049 * in: value
1051 * sal: sal_i (CVT index of the style's vwidth data;
1052 * gets incremented by 1 after execution)
1055 static const unsigned char FPGM(bci_vwidth_data_store) [] =
1058 PUSHB_1,
1059 bci_vwidth_data_store,
1060 FDEF,
1062 PUSHB_1,
1063 sal_i,
1065 SWAP,
1066 WCVTP,
1068 PUSHB_3,
1069 sal_i,
1071 sal_i,
1073 ADD, /* sal_i = sal_i + 1 */
1076 ENDF,
1082 * bci_smooth_blue_round
1084 * Round a blue ref value and adjust its corresponding shoot value.
1086 * This is the equivalent to the following code (function
1087 * `ta_latin_metrics_scale_dim'):
1089 * delta = dist
1090 * if dist < 0:
1091 * delta = -delta
1093 * if delta < 32:
1094 * delta = 0
1095 * else if delta < 48:
1096 * delta = 32
1097 * else:
1098 * delta = 64
1100 * if dist < 0:
1101 * delta = -delta
1103 * in: ref_idx
1105 * sal: sal_i (number of blue zones)
1107 * out: ref_idx+1
1109 * uses: bci_round
1112 static const unsigned char FPGM(bci_smooth_blue_round) [] =
1115 PUSHB_1,
1116 bci_smooth_blue_round,
1117 FDEF,
1119 DUP,
1120 DUP,
1121 RCVT, /* s: ref_idx ref_idx ref */
1123 DUP,
1124 PUSHB_1,
1125 bci_round,
1126 CALL,
1127 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1129 PUSHB_1,
1130 sal_i,
1132 PUSHB_1,
1134 CINDEX,
1135 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1136 DUP,
1137 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1139 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1140 SWAP,
1141 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1142 DUP,
1143 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1145 DUP,
1146 PUSHB_1,
1148 LT, /* delta < 32 */
1150 POP,
1151 PUSHB_1,
1152 0, /* delta = 0 */
1154 ELSE,
1155 PUSHB_1,
1157 LT, /* delta < 48 */
1159 PUSHB_1,
1160 32, /* delta = 32 */
1162 ELSE,
1163 PUSHB_1,
1164 64, /* delta = 64 */
1165 EIF,
1166 EIF,
1168 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1169 PUSHB_1,
1171 LT, /* dist < 0 */
1173 NEG, /* delta = -delta */
1174 EIF,
1176 PUSHB_1,
1178 CINDEX,
1179 SWAP,
1180 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1182 WCVTP,
1183 WCVTP,
1185 PUSHB_1,
1187 ADD, /* s: (ref_idx + 1) */
1189 ENDF,
1195 * bci_strong_blue_round
1197 * Round a blue ref value and adjust its corresponding shoot value.
1199 * This is the equivalent to the following code:
1201 * delta = dist
1202 * if dist < 0:
1203 * delta = -delta
1205 * if delta < 36:
1206 * delta = 0
1207 * else:
1208 * delta = 64
1210 * if dist < 0:
1211 * delta = -delta
1213 * It doesn't have corresponding code in talatin.c; however, some tests
1214 * have shown that the `smooth' code works just fine for this case also.
1216 * in: ref_idx
1218 * sal: sal_i (number of blue zones)
1220 * out: ref_idx+1
1222 * uses: bci_round
1225 static const unsigned char FPGM(bci_strong_blue_round) [] =
1228 PUSHB_1,
1229 bci_strong_blue_round,
1230 FDEF,
1232 DUP,
1233 DUP,
1234 RCVT, /* s: ref_idx ref_idx ref */
1236 DUP,
1237 PUSHB_1,
1238 bci_round,
1239 CALL,
1240 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1242 PUSHB_1,
1243 sal_i,
1245 PUSHB_1,
1247 CINDEX,
1248 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1249 DUP,
1250 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1252 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1253 SWAP,
1254 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1255 DUP,
1256 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1258 PUSHB_1,
1260 LT, /* delta < 36 */
1262 PUSHB_1,
1263 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1265 ELSE,
1266 PUSHB_1,
1267 64, /* delta = 64 (one pixel unit) */
1268 EIF,
1270 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1271 PUSHB_1,
1273 LT, /* dist < 0 */
1275 NEG, /* delta = -delta */
1276 EIF,
1278 PUSHB_1,
1280 CINDEX,
1281 SWAP,
1282 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1284 WCVTP,
1285 WCVTP,
1287 PUSHB_1,
1289 ADD, /* s: (ref_idx + 1) */
1291 ENDF,
1297 * bci_blue_round_range
1299 * Round a range of blue zones (both reference and shoot values).
1301 * This function gets used in the `prep' table.
1303 * in: num_blue_zones
1304 * blue_ref_idx
1306 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1308 * uses: bci_smooth_blue_round
1309 * bci_strong_blue_round
1312 static const unsigned char FPGM(bci_blue_round_range) [] =
1315 PUSHB_1,
1316 bci_blue_round_range,
1317 FDEF,
1319 DUP,
1320 PUSHB_1,
1321 sal_i,
1322 SWAP,
1325 /* select blue rounding function based on flag in CVT */
1326 PUSHB_3,
1327 bci_strong_blue_round,
1328 bci_smooth_blue_round,
1329 cvtl_use_strong_functions,
1330 RCVT,
1332 POP,
1334 ELSE,
1335 SWAP,
1336 POP,
1338 EIF,
1339 LOOPCALL,
1340 /* clean up stack */
1341 POP,
1343 ENDF,
1349 * bci_decrement_component_counter
1351 * An auxiliary function for composite glyphs.
1353 * CVT: cvtl_is_subglyph
1356 static const unsigned char FPGM(bci_decrement_component_counter) [] =
1359 PUSHB_1,
1360 bci_decrement_component_counter,
1361 FDEF,
1363 /* decrement `cvtl_is_subglyph' counter */
1364 PUSHB_2,
1365 cvtl_is_subglyph,
1366 cvtl_is_subglyph,
1367 RCVT,
1368 PUSHB_1,
1369 100,
1370 SUB,
1371 WCVTP,
1373 ENDF,
1379 * bci_get_point_extrema
1381 * An auxiliary function for `bci_create_segment'.
1383 * in: point-1
1385 * out: point
1387 * sal: sal_point_min
1388 * sal_point_max
1391 static const unsigned char FPGM(bci_get_point_extrema) [] =
1394 PUSHB_1,
1395 bci_get_point_extrema,
1396 FDEF,
1398 PUSHB_1,
1400 ADD, /* s: point */
1401 DUP,
1402 DUP,
1404 /* check whether `point' is a new minimum */
1405 PUSHB_1,
1406 sal_point_min,
1407 RS, /* s: point point point point_min */
1408 MD_orig,
1409 /* if distance is negative, we have a new minimum */
1410 PUSHB_1,
1413 IF, /* s: point point */
1414 DUP,
1415 PUSHB_1,
1416 sal_point_min,
1417 SWAP,
1419 EIF,
1421 /* check whether `point' is a new maximum */
1422 PUSHB_1,
1423 sal_point_max,
1424 RS, /* s: point point point_max */
1425 MD_orig,
1426 /* if distance is positive, we have a new maximum */
1427 PUSHB_1,
1430 IF, /* s: point */
1431 DUP,
1432 PUSHB_1,
1433 sal_point_max,
1434 SWAP,
1436 EIF, /* s: point */
1438 ENDF,
1444 * bci_nibbles
1446 * Pop a byte with two delta arguments in its nibbles and push the
1447 * expanded arguments separately as two bytes.
1449 * in: 16 * (end - start) + (start - base)
1451 * out: start
1452 * end
1454 * sal: sal_base (set to `end' at return)
1458 static const unsigned char FPGM(bci_nibbles) [] =
1460 PUSHB_1,
1461 bci_nibbles,
1462 FDEF,
1464 DUP,
1465 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1467 DIV,
1468 FLOOR,
1469 PUSHB_1,
1471 MUL, /* s: in hnibble */
1472 DUP,
1473 PUSHW_1,
1474 0x04, /* 16*64 */
1475 0x00,
1476 MUL, /* s: in hnibble (hnibble * 16) */
1477 ROLL,
1478 SWAP,
1479 SUB, /* s: hnibble lnibble */
1481 PUSHB_1,
1482 sal_base,
1484 ADD, /* s: hnibble start */
1485 DUP,
1486 ROLL,
1487 ADD, /* s: start end */
1489 DUP,
1490 PUSHB_1,
1491 sal_base,
1492 SWAP,
1493 WS, /* sal_base = end */
1495 SWAP,
1497 ENDF,
1503 * bci_number_set_is_element
1505 * Pop values from stack until it is empty. If one of them is equal to
1506 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1507 * otherwise).
1509 * in: ppem_value_1
1510 * ppem_value_2
1511 * ...
1513 * CVT: cvtl_is_element
1516 static const unsigned char FPGM(bci_number_set_is_element) [] =
1519 PUSHB_1,
1520 bci_number_set_is_element,
1521 FDEF,
1523 /* start_loop: */
1524 MPPEM,
1527 PUSHB_2,
1528 cvtl_is_element,
1529 100,
1530 WCVTP,
1531 EIF,
1533 DEPTH,
1534 PUSHB_1,
1536 NEG,
1537 SWAP,
1538 JROT, /* goto start_loop if stack depth != 0 */
1540 ENDF,
1546 * bci_number_set_is_element2
1548 * Pop value ranges from stack until it is empty. If one of them contains
1549 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1550 * otherwise).
1552 * in: ppem_range_1_start
1553 * ppem_range_1_end
1554 * ppem_range_2_start
1555 * ppem_range_2_end
1556 * ...
1558 * CVT: cvtl_is_element
1561 static const unsigned char FPGM(bci_number_set_is_element2) [] =
1564 PUSHB_1,
1565 bci_number_set_is_element2,
1566 FDEF,
1568 /* start_loop: */
1569 MPPEM,
1570 LTEQ,
1572 MPPEM,
1573 GTEQ,
1575 PUSHB_2,
1576 cvtl_is_element,
1577 100,
1578 WCVTP,
1579 EIF,
1580 ELSE,
1581 POP,
1582 EIF,
1584 DEPTH,
1585 PUSHB_1,
1587 NEG,
1588 SWAP,
1589 JROT, /* goto start_loop if stack depth != 0 */
1591 ENDF,
1597 * bci_create_segment
1599 * Store start and end point of a segment in the storage area,
1600 * then construct a point in the twilight zone to represent it.
1602 * This function is used by `bci_create_segments'.
1604 * in: start
1605 * end
1606 * [last (if wrap-around segment)]
1607 * [first (if wrap-around segment)]
1609 * sal: sal_i (start of current segment)
1610 * sal_j (current twilight point)
1611 * sal_point_min
1612 * sal_point_max
1613 * sal_base
1614 * sal_num_packed_segments
1615 * sal_scale
1617 * CVT: cvtl_temp
1619 * uses: bci_get_point_extrema
1620 * bci_nibbles
1622 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1623 * delta values in nibbles (without a wrap-around segment).
1626 static const unsigned char FPGM(bci_create_segment) [] =
1629 PUSHB_1,
1630 bci_create_segment,
1631 FDEF,
1633 PUSHB_2,
1635 sal_num_packed_segments,
1637 NEQ,
1639 PUSHB_2,
1640 sal_num_packed_segments,
1641 sal_num_packed_segments,
1643 PUSHB_1,
1645 SUB,
1646 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1648 PUSHB_1,
1649 bci_nibbles,
1650 CALL,
1651 EIF,
1653 PUSHB_1,
1654 sal_i,
1656 PUSHB_1,
1658 CINDEX,
1659 WS, /* sal[sal_i] = start */
1661 /* initialize inner loop(s) */
1662 PUSHB_2,
1663 sal_point_min,
1665 CINDEX,
1666 WS, /* sal_point_min = start */
1667 PUSHB_2,
1668 sal_point_max,
1670 CINDEX,
1671 WS, /* sal_point_max = start */
1673 PUSHB_1,
1675 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1677 SWAP,
1678 DUP,
1679 PUSHB_1,
1681 CINDEX, /* s: start end end start */
1682 LT, /* start > end */
1684 /* we have a wrap-around segment with two more arguments */
1685 /* to give the last and first point of the contour, respectively; */
1686 /* our job is to store a segment `start'-`last', */
1687 /* and to get extrema for the two segments */
1688 /* `start'-`last' and `first'-`end' */
1690 /* s: first last start end */
1691 PUSHB_2,
1693 sal_i,
1695 ADD,
1696 PUSHB_1,
1698 CINDEX,
1699 WS, /* sal[sal_i + 1] = last */
1701 ROLL,
1702 ROLL, /* s: first end last start */
1703 DUP,
1704 ROLL,
1705 SWAP, /* s: first end start last start */
1706 SUB, /* s: first end start loop_count */
1708 PUSHB_1,
1709 bci_get_point_extrema,
1710 LOOPCALL,
1711 /* clean up stack */
1712 POP,
1714 SWAP, /* s: end first */
1715 PUSHB_1,
1717 SUB,
1718 DUP,
1719 ROLL, /* s: (first - 1) (first - 1) end */
1720 SWAP,
1721 SUB, /* s: (first - 1) loop_count */
1723 PUSHB_1,
1724 bci_get_point_extrema,
1725 LOOPCALL,
1726 /* clean up stack */
1727 POP,
1729 ELSE, /* s: start end */
1730 PUSHB_2,
1732 sal_i,
1734 ADD,
1735 PUSHB_1,
1737 CINDEX,
1738 WS, /* sal[sal_i + 1] = end */
1740 PUSHB_1,
1742 CINDEX,
1743 SUB, /* s: start loop_count */
1745 PUSHB_1,
1746 bci_get_point_extrema,
1747 LOOPCALL,
1748 /* clean up stack */
1749 POP,
1750 EIF,
1752 /* the twilight point representing a segment */
1753 /* is in the middle between the minimum and maximum */
1754 PUSHB_1,
1755 sal_point_min,
1757 GC_orig,
1758 PUSHB_1,
1759 sal_point_max,
1761 GC_orig,
1762 ADD,
1763 DIV_BY_2, /* s: middle_pos */
1765 DO_SCALE, /* middle_pos = middle_pos * scale */
1767 /* write it to temporary CVT location */
1768 PUSHB_2,
1769 cvtl_temp,
1771 SZP0, /* set zp0 to twilight zone 0 */
1772 SWAP,
1773 WCVTP,
1775 /* create twilight point with index `sal_j' */
1776 PUSHB_1,
1777 sal_j,
1779 PUSHB_1,
1780 cvtl_temp,
1781 MIAP_noround,
1783 PUSHB_3,
1784 sal_j,
1786 sal_j,
1788 ADD, /* twilight_point = twilight_point + 1 */
1791 ENDF,
1797 * bci_create_segments
1799 * This is the top-level entry function.
1801 * It pops point ranges from the stack to define segments, computes
1802 * twilight points to represent segments, and finally calls
1803 * `bci_hint_glyph' to handle the rest.
1805 * The second argument (`data_offset') addresses three CVT arrays in
1806 * parallel:
1808 * CVT(data_offset):
1809 * the current style's scaling value (stored in `sal_scale')
1811 * data_offset + num_used_styles:
1812 * offset to the current style's vwidth index array (this value gets
1813 * stored in `sal_vwidth_data_offset')
1815 * data_offset + 2*num_used_styles:
1816 * offset to the current style's vwidth size
1818 * This addressing scheme ensures that (a) we only need a single argument,
1819 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1820 * which should be sufficient for a long time.
1822 * in: num_packed_segments
1823 * data_offset
1824 * num_segments (N)
1825 * segment_start_0
1826 * segment_end_0
1827 * [contour_last 0 (if wrap-around segment)]
1828 * [contour_first 0 (if wrap-around segment)]
1829 * segment_start_1
1830 * segment_end_1
1831 * [contour_last 0 (if wrap-around segment)]
1832 * [contour_first 0 (if wrap-around segment)]
1833 * ...
1834 * segment_start_(N-1)
1835 * segment_end_(N-1)
1836 * [contour_last (N-1) (if wrap-around segment)]
1837 * [contour_first (N-1) (if wrap-around segment)]
1838 * ... stuff for bci_hint_glyph ...
1840 * sal: sal_i (start of current segment)
1841 * sal_j (current twilight point)
1842 * sal_num_packed_segments
1843 * sal_base (the base for delta values in nibbles)
1844 * sal_vwidth_data_offset
1845 * sal_scale
1847 * CVT: cvtl_is_subglyph
1849 * uses: bci_create_segment
1850 * bci_loop
1851 * bci_hint_glyph
1853 * If `num_packed_segments' is set to p, the first p start/end pairs are
1854 * stored as delta values in nibbles, with the `start' delta in the lower
1855 * nibble (and there are no wrap-around segments). For example, if the
1856 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1857 * stack are 0x21, 0x32, and 0x14.
1861 static const unsigned char FPGM(bci_create_segments_a) [] =
1864 PUSHB_1,
1865 bci_create_segments,
1866 FDEF,
1868 /* all our measurements are taken along the y axis */
1869 SVTCA_y,
1871 /* only do something if we are not a subglyph */
1872 PUSHB_2,
1874 cvtl_is_subglyph,
1875 RCVT,
1878 PUSHB_1,
1879 sal_num_packed_segments,
1880 SWAP,
1883 DUP,
1884 RCVT,
1885 PUSHB_1,
1886 sal_scale, /* sal_scale = CVT(data_offset) */
1887 SWAP,
1890 PUSHB_1,
1891 sal_vwidth_data_offset,
1892 SWAP,
1893 PUSHB_1,
1897 /* %c, number of used styles */
1899 static const unsigned char FPGM(bci_create_segments_b) [] =
1902 ADD,
1903 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1905 DUP,
1906 ADD,
1907 PUSHB_1,
1909 SUB, /* delta = (2*num_segments - 1) */
1911 PUSHB_6,
1912 sal_segment_offset,
1913 sal_segment_offset,
1915 sal_j,
1917 sal_base,
1919 WS, /* sal_base = 0 */
1920 WS, /* sal_j = 0 (point offset) */
1922 ROLL,
1923 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1925 PUSHB_2,
1926 bci_create_segment,
1927 bci_loop,
1928 CALL,
1930 PUSHB_1,
1931 bci_hint_glyph,
1932 CALL,
1936 /* used if we have delta exceptions */
1938 static const unsigned char FPGM(bci_create_segments_c) [] =
1941 PUSHB_1,
1943 SZPS,
1947 static const unsigned char FPGM(bci_create_segments_d) [] =
1950 ELSE,
1951 CLEAR,
1952 EIF,
1954 ENDF,
1960 * bci_create_segments_X
1962 * Top-level routines for calling `bci_create_segments'.
1965 static const unsigned char FPGM(bci_create_segments_0) [] =
1968 PUSHB_1,
1969 bci_create_segments_0,
1970 FDEF,
1972 PUSHB_2,
1974 bci_create_segments,
1975 CALL,
1977 ENDF,
1981 static const unsigned char FPGM(bci_create_segments_1) [] =
1984 PUSHB_1,
1985 bci_create_segments_1,
1986 FDEF,
1988 PUSHB_2,
1990 bci_create_segments,
1991 CALL,
1993 ENDF,
1997 static const unsigned char FPGM(bci_create_segments_2) [] =
2000 PUSHB_1,
2001 bci_create_segments_2,
2002 FDEF,
2004 PUSHB_2,
2006 bci_create_segments,
2007 CALL,
2009 ENDF,
2013 static const unsigned char FPGM(bci_create_segments_3) [] =
2016 PUSHB_1,
2017 bci_create_segments_3,
2018 FDEF,
2020 PUSHB_2,
2022 bci_create_segments,
2023 CALL,
2025 ENDF,
2029 static const unsigned char FPGM(bci_create_segments_4) [] =
2032 PUSHB_1,
2033 bci_create_segments_4,
2034 FDEF,
2036 PUSHB_2,
2038 bci_create_segments,
2039 CALL,
2041 ENDF,
2045 static const unsigned char FPGM(bci_create_segments_5) [] =
2048 PUSHB_1,
2049 bci_create_segments_5,
2050 FDEF,
2052 PUSHB_2,
2054 bci_create_segments,
2055 CALL,
2057 ENDF,
2061 static const unsigned char FPGM(bci_create_segments_6) [] =
2064 PUSHB_1,
2065 bci_create_segments_6,
2066 FDEF,
2068 PUSHB_2,
2070 bci_create_segments,
2071 CALL,
2073 ENDF,
2077 static const unsigned char FPGM(bci_create_segments_7) [] =
2080 PUSHB_1,
2081 bci_create_segments_7,
2082 FDEF,
2084 PUSHB_2,
2086 bci_create_segments,
2087 CALL,
2089 ENDF,
2093 static const unsigned char FPGM(bci_create_segments_8) [] =
2096 PUSHB_1,
2097 bci_create_segments_8,
2098 FDEF,
2100 PUSHB_2,
2102 bci_create_segments,
2103 CALL,
2105 ENDF,
2109 static const unsigned char FPGM(bci_create_segments_9) [] =
2112 PUSHB_1,
2113 bci_create_segments_9,
2114 FDEF,
2116 PUSHB_2,
2118 bci_create_segments,
2119 CALL,
2121 ENDF,
2127 * bci_deltapX
2129 * Wrapper functions around DELTAP[123] that touch the affected points
2130 * before applying the delta. This is necessary for ClearType.
2132 * While DELTAP[123] implicitly do a loop, we have to process the
2133 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2135 * in: point
2136 * arg
2139 static const unsigned char FPGM(bci_deltap1) [] =
2142 PUSHB_1,
2143 bci_deltap1,
2144 FDEF,
2146 SWAP,
2147 DUP, /* s: point arg arg */
2148 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2150 DIV,
2151 FLOOR,
2152 PUSHB_1,
2154 MUL, /* s: point arg hnibble(arg) */
2155 PUSHB_1,
2156 CONTROL_DELTA_PPEM_MIN,
2157 ADD, /* s: point arg ppem(arg) */
2158 MPPEM,
2161 SWAP,
2162 DUP,
2163 MDAP_noround, /* touch `point' */
2165 PUSHB_1,
2167 DELTAP1, /* process one `(point,arg)' pair */
2168 ELSE,
2169 POP,
2170 POP,
2171 EIF,
2173 ENDF,
2177 static const unsigned char FPGM(bci_deltap2) [] =
2180 PUSHB_1,
2181 bci_deltap2,
2182 FDEF,
2184 SWAP,
2185 DUP, /* s: point arg arg */
2186 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2188 DIV,
2189 FLOOR,
2190 PUSHB_1,
2192 MUL, /* s: point arg hnibble(arg) */
2193 PUSHB_1,
2194 CONTROL_DELTA_PPEM_MIN + 16,
2195 ADD, /* s: point arg ppem(arg) */
2196 MPPEM,
2199 SWAP,
2200 DUP,
2201 MDAP_noround, /* touch `point' */
2203 PUSHB_1,
2205 DELTAP2, /* process one `(point,arg)' pair */
2206 ELSE,
2207 POP,
2208 POP,
2209 EIF,
2211 ENDF,
2215 static const unsigned char FPGM(bci_deltap3) [] =
2218 PUSHB_1,
2219 bci_deltap3,
2220 FDEF,
2222 SWAP,
2223 DUP, /* s: point arg arg */
2224 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2226 DIV,
2227 FLOOR,
2228 PUSHB_1,
2230 MUL, /* s: point arg hnibble(arg) */
2231 PUSHB_1,
2232 CONTROL_DELTA_PPEM_MIN + 32,
2233 ADD, /* s: point arg ppem(arg) */
2234 MPPEM,
2237 SWAP,
2238 DUP,
2239 MDAP_noround, /* touch `point' */
2241 PUSHB_1,
2243 DELTAP3, /* process one `(point,arg)' pair */
2244 ELSE,
2245 POP,
2246 POP,
2247 EIF,
2249 ENDF,
2255 * bci_create_segments_composite
2257 * The same as `bci_create_segments'.
2258 * It also decrements the composite component counter.
2260 * sal: sal_num_packed_segments
2261 * sal_segment_offset
2262 * sal_vwidth_data_offset
2264 * CVT: cvtl_is_subglyph
2266 * uses: bci_decrement_component_counter
2267 * bci_create_segment
2268 * bci_loop
2269 * bci_hint_glyph
2272 static const unsigned char FPGM(bci_create_segments_composite_a) [] =
2275 PUSHB_1,
2276 bci_create_segments_composite,
2277 FDEF,
2279 /* all our measurements are taken along the y axis */
2280 SVTCA_y,
2282 PUSHB_1,
2283 bci_decrement_component_counter,
2284 CALL,
2286 /* only do something if we are not a subglyph */
2287 PUSHB_2,
2289 cvtl_is_subglyph,
2290 RCVT,
2293 PUSHB_1,
2294 sal_num_packed_segments,
2295 SWAP,
2298 DUP,
2299 RCVT,
2300 PUSHB_1,
2301 sal_scale, /* sal_scale = CVT(data_offset) */
2302 SWAP,
2305 PUSHB_1,
2306 sal_vwidth_data_offset,
2307 SWAP,
2308 PUSHB_1,
2312 /* %c, number of used styles */
2314 static const unsigned char FPGM(bci_create_segments_composite_b) [] =
2317 ADD,
2318 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2320 DUP,
2321 ADD,
2322 PUSHB_1,
2324 SUB, /* delta = (2*num_segments - 1) */
2326 PUSHB_6,
2327 sal_segment_offset,
2328 sal_segment_offset,
2330 sal_j,
2332 sal_base,
2334 WS, /* sal_base = 0 */
2335 WS, /* sal_j = 0 (point offset) */
2337 ROLL,
2338 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2340 PUSHB_2,
2341 bci_create_segment,
2342 bci_loop,
2343 CALL,
2345 PUSHB_1,
2346 bci_hint_glyph,
2347 CALL,
2351 /* used if we have delta exceptions */
2353 static const unsigned char FPGM(bci_create_segments_composite_c) [] =
2356 PUSHB_1,
2358 SZPS,
2362 static const unsigned char FPGM(bci_create_segments_composite_d) [] =
2365 ELSE,
2366 CLEAR,
2367 EIF,
2369 ENDF,
2375 * bci_create_segments_composite_X
2377 * Top-level routines for calling `bci_create_segments_composite'.
2380 static const unsigned char FPGM(bci_create_segments_composite_0) [] =
2383 PUSHB_1,
2384 bci_create_segments_composite_0,
2385 FDEF,
2387 PUSHB_2,
2389 bci_create_segments_composite,
2390 CALL,
2392 ENDF,
2396 static const unsigned char FPGM(bci_create_segments_composite_1) [] =
2399 PUSHB_1,
2400 bci_create_segments_composite_1,
2401 FDEF,
2403 PUSHB_2,
2405 bci_create_segments_composite,
2406 CALL,
2408 ENDF,
2412 static const unsigned char FPGM(bci_create_segments_composite_2) [] =
2415 PUSHB_1,
2416 bci_create_segments_composite_2,
2417 FDEF,
2419 PUSHB_2,
2421 bci_create_segments_composite,
2422 CALL,
2424 ENDF,
2428 static const unsigned char FPGM(bci_create_segments_composite_3) [] =
2431 PUSHB_1,
2432 bci_create_segments_composite_3,
2433 FDEF,
2435 PUSHB_2,
2437 bci_create_segments_composite,
2438 CALL,
2440 ENDF,
2444 static const unsigned char FPGM(bci_create_segments_composite_4) [] =
2447 PUSHB_1,
2448 bci_create_segments_composite_4,
2449 FDEF,
2451 PUSHB_2,
2453 bci_create_segments_composite,
2454 CALL,
2456 ENDF,
2460 static const unsigned char FPGM(bci_create_segments_composite_5) [] =
2463 PUSHB_1,
2464 bci_create_segments_composite_5,
2465 FDEF,
2467 PUSHB_2,
2469 bci_create_segments_composite,
2470 CALL,
2472 ENDF,
2476 static const unsigned char FPGM(bci_create_segments_composite_6) [] =
2479 PUSHB_1,
2480 bci_create_segments_composite_6,
2481 FDEF,
2483 PUSHB_2,
2485 bci_create_segments_composite,
2486 CALL,
2488 ENDF,
2492 static const unsigned char FPGM(bci_create_segments_composite_7) [] =
2495 PUSHB_1,
2496 bci_create_segments_composite_7,
2497 FDEF,
2499 PUSHB_2,
2501 bci_create_segments_composite,
2502 CALL,
2504 ENDF,
2508 static const unsigned char FPGM(bci_create_segments_composite_8) [] =
2511 PUSHB_1,
2512 bci_create_segments_composite_8,
2513 FDEF,
2515 PUSHB_2,
2517 bci_create_segments_composite,
2518 CALL,
2520 ENDF,
2524 static const unsigned char FPGM(bci_create_segments_composite_9) [] =
2527 PUSHB_1,
2528 bci_create_segments_composite_9,
2529 FDEF,
2531 PUSHB_2,
2533 bci_create_segments_composite,
2534 CALL,
2536 ENDF,
2542 * bci_align_point
2544 * An auxiliary function for `bci_align_segment'.
2546 * in: point
2548 * out: point+1
2551 static const unsigned char FPGM(bci_align_point) [] =
2554 PUSHB_1,
2555 bci_align_point,
2556 FDEF,
2558 DUP,
2559 ALIGNRP, /* align point with rp0 */
2561 PUSHB_1,
2563 ADD,
2565 ENDF,
2571 * bci_align_segment
2573 * Align all points in a segment to the twilight point in rp0.
2574 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2576 * in: segment_index
2578 * sal: sal_segment_offset
2580 * uses: bci_align_point
2583 static const unsigned char FPGM(bci_align_segment) [] =
2586 PUSHB_1,
2587 bci_align_segment,
2588 FDEF,
2590 /* we need the values of `sal_segment_offset + 2*segment_index' */
2591 /* and `sal_segment_offset + 2*segment_index + 1' */
2592 DUP,
2593 ADD,
2594 PUSHB_1,
2595 sal_segment_offset,
2596 ADD,
2597 DUP,
2599 SWAP,
2600 PUSHB_1,
2602 ADD,
2603 RS, /* s: first last */
2605 PUSHB_1,
2607 CINDEX, /* s: first last first */
2608 SUB,
2609 PUSHB_1,
2611 ADD, /* s: first loop_count */
2613 PUSHB_1,
2614 bci_align_point,
2615 LOOPCALL,
2616 /* clean up stack */
2617 POP,
2619 ENDF,
2625 * bci_align_segments
2627 * Align segments to the twilight point in rp0.
2628 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2630 * in: first_segment
2631 * loop_counter (N)
2632 * segment_1
2633 * segment_2
2634 * ...
2635 * segment_N
2637 * uses: bci_align_segment
2640 static const unsigned char FPGM(bci_align_segments) [] =
2643 PUSHB_1,
2644 bci_align_segments,
2645 FDEF,
2647 PUSHB_1,
2648 bci_align_segment,
2649 CALL,
2651 PUSHB_1,
2652 bci_align_segment,
2653 LOOPCALL,
2655 ENDF,
2661 * bci_scale_contour
2663 * Scale a contour using two points giving the maximum and minimum
2664 * coordinates.
2666 * It expects that no point on the contour is touched.
2668 * in: min_point
2669 * max_point
2671 * sal: sal_scale
2674 static const unsigned char FPGM(bci_scale_contour) [] =
2677 PUSHB_1,
2678 bci_scale_contour,
2679 FDEF,
2681 DUP,
2682 DUP,
2683 GC_orig,
2684 DUP,
2685 DO_SCALE, /* min_pos_new = min_pos * scale */
2686 SWAP,
2687 SUB,
2688 SHPIX,
2690 /* don't scale a single-point contour twice */
2691 SWAP,
2692 DUP,
2693 ROLL,
2694 NEQ,
2696 DUP,
2697 GC_orig,
2698 DUP,
2699 DO_SCALE, /* max_pos_new = max_pos * scale */
2700 SWAP,
2701 SUB,
2702 SHPIX,
2704 ELSE,
2705 POP,
2706 EIF,
2708 ENDF,
2714 * bci_scale_glyph
2716 * Scale a glyph using a list of points (two points per contour, giving
2717 * the maximum and mininum coordinates).
2719 * It expects that no point in the glyph is touched.
2721 * Note that the point numbers are sorted in ascending order;
2722 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2723 * contour without specifying which one is the minimum and maximum.
2725 * in: num_contours (N)
2726 * min_point_1
2727 * max_point_1
2728 * min_point_2
2729 * max_point_2
2730 * ...
2731 * min_point_N
2732 * max_point_N
2734 * CVT: cvtl_is_subglyph
2735 * cvtl_do_iup_y
2737 * sal: sal_scale
2739 * uses: bci_scale_contour
2742 static const unsigned char FPGM(bci_scale_glyph_a) [] =
2745 PUSHB_1,
2746 bci_scale_glyph,
2747 FDEF,
2749 /* all our measurements are taken along the y axis */
2750 SVTCA_y,
2752 /* only do something if we are not a subglyph */
2753 PUSHB_2,
2755 cvtl_is_subglyph,
2756 RCVT,
2759 /* use fallback scaling value */
2760 PUSHB_2,
2761 sal_scale,
2765 /* %c, fallback scaling index */
2767 static const unsigned char FPGM(bci_scale_glyph_b) [] =
2770 RCVT,
2773 PUSHB_1,
2775 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2777 PUSHB_1,
2778 bci_scale_contour,
2779 LOOPCALL,
2781 PUSHB_2,
2782 cvtl_do_iup_y,
2784 SZP2, /* set zp2 to normal zone 1 */
2785 RCVT,
2787 IUP_y,
2788 EIF,
2790 ELSE,
2791 CLEAR,
2792 EIF,
2794 ENDF,
2800 * bci_scale_composite_glyph
2802 * The same as `bci_scale_glyph'.
2803 * It also decrements the composite component counter.
2805 * CVT: cvtl_is_subglyph
2806 * cvtl_do_iup_y
2808 * sal: sal_scale
2810 * uses: bci_decrement_component_counter
2811 * bci_scale_contour
2814 static const unsigned char FPGM(bci_scale_composite_glyph_a) [] =
2817 PUSHB_1,
2818 bci_scale_composite_glyph,
2819 FDEF,
2821 /* all our measurements are taken along the y axis */
2822 SVTCA_y,
2824 PUSHB_1,
2825 bci_decrement_component_counter,
2826 CALL,
2828 /* only do something if we are not a subglyph */
2829 PUSHB_2,
2831 cvtl_is_subglyph,
2832 RCVT,
2835 /* use fallback scaling value */
2836 PUSHB_2,
2837 sal_scale,
2841 /* %c, fallback scaling index */
2843 static const unsigned char FPGM(bci_scale_composite_glyph_b) [] =
2846 RCVT,
2849 PUSHB_1,
2851 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2853 PUSHB_1,
2854 bci_scale_contour,
2855 LOOPCALL,
2857 PUSHB_2,
2858 cvtl_do_iup_y,
2860 SZP2, /* set zp2 to normal zone 1 */
2861 RCVT,
2863 IUP_y,
2864 EIF,
2866 ELSE,
2867 CLEAR,
2868 EIF,
2870 ENDF,
2876 * bci_shift_contour
2878 * Shift a contour by a given amount.
2880 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2881 * point to the normal zone 1.
2883 * in: contour
2885 * out: contour+1
2888 static const unsigned char FPGM(bci_shift_contour) [] =
2891 PUSHB_1,
2892 bci_shift_contour,
2893 FDEF,
2895 DUP,
2896 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2898 PUSHB_1,
2900 ADD,
2902 ENDF,
2908 * bci_shift_subglyph
2910 * Shift a subglyph. To be more specific, it corrects the already applied
2911 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2912 * also.
2914 * If this function is called, a point `x' in the subglyph has been scaled
2915 * already (during the hinting of the subglyph itself), and `offset' has
2916 * been applied also:
2918 * x -> x * scale + offset (1)
2920 * However, the offset should be applied first, then the scaling:
2922 * x -> (x + offset) * scale (2)
2924 * Our job is now to transform (1) to (2); a simple calculation shows that
2925 * we have to shift all points of the subglyph by
2927 * offset * scale - offset = offset * (scale - 1)
2929 * Note that `sal_scale' is equal to the above `scale - 1'.
2931 * in: offset (in FUnits)
2932 * num_contours
2933 * first_contour
2935 * CVT: cvtl_funits_to_pixels
2937 * sal: sal_scale
2939 * uses: bci_round
2940 * bci_shift_contour
2943 static const unsigned char FPGM(bci_shift_subglyph_a) [] =
2946 PUSHB_1,
2947 bci_shift_subglyph,
2948 FDEF,
2950 /* all our measurements are taken along the y axis */
2951 SVTCA_y,
2953 /* use fallback scaling value */
2954 PUSHB_2,
2955 sal_scale,
2959 /* %c, fallback scaling index */
2961 static const unsigned char FPGM(bci_shift_subglyph_b) [] =
2964 RCVT,
2967 PUSHB_1,
2968 cvtl_funits_to_pixels,
2969 RCVT, /* scaling factor FUnits -> pixels */
2970 MUL,
2971 DIV_BY_1024,
2973 /* the autohinter always rounds offsets */
2974 PUSHB_1,
2975 bci_round,
2976 CALL, /* offset = round(offset) */
2978 PUSHB_1,
2979 sal_scale,
2981 MUL,
2982 DIV_BY_1024, /* delta = offset * (scale - 1) */
2984 /* and round again */
2985 PUSHB_1,
2986 bci_round,
2987 CALL, /* offset = round(offset) */
2989 PUSHB_1,
2991 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2993 /* we create twilight point 0 as a reference point, */
2994 /* setting the original position to zero (using `cvtl_temp') */
2995 PUSHB_5,
2998 cvtl_temp,
2999 cvtl_temp,
3001 WCVTP,
3002 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
3004 SWAP, /* s: first_contour num_contours 0 delta */
3005 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
3007 PUSHB_2,
3008 bci_shift_contour,
3010 SZP2, /* set zp2 to normal zone 1 */
3011 LOOPCALL,
3012 /* clean up stack */
3013 POP,
3017 /* used if we have delta exceptions */
3019 static const unsigned char FPGM(bci_shift_subglyph_c) [] =
3022 PUSHB_1,
3024 SZPS,
3028 static const unsigned char FPGM(bci_shift_subglyph_d) [] =
3031 ENDF,
3037 * bci_ip_outer_align_point
3039 * Auxiliary function for `bci_action_ip_before' and
3040 * `bci_action_ip_after'.
3042 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3043 * zone, and both zp1 and zp2 set to normal zone.
3045 * in: point
3047 * sal: sal_i (edge_orig_pos)
3048 * sal_scale
3051 static const unsigned char FPGM(bci_ip_outer_align_point) [] =
3054 PUSHB_1,
3055 bci_ip_outer_align_point,
3056 FDEF,
3058 DUP,
3059 ALIGNRP, /* align `point' with `edge' */
3060 DUP,
3061 GC_orig,
3062 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3064 PUSHB_1,
3065 sal_i,
3067 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3068 SHPIX,
3070 ENDF,
3076 * bci_ip_on_align_points
3078 * Auxiliary function for `bci_action_ip_on'.
3080 * in: edge (in twilight zone)
3081 * loop_counter (N)
3082 * point_1
3083 * point_2
3084 * ...
3085 * point_N
3088 static const unsigned char FPGM(bci_ip_on_align_points) [] =
3091 PUSHB_1,
3092 bci_ip_on_align_points,
3093 FDEF,
3095 MDAP_noround, /* set rp0 and rp1 to `edge' */
3097 SLOOP,
3098 ALIGNRP,
3100 ENDF,
3106 * bci_ip_between_align_point
3108 * Auxiliary function for `bci_ip_between_align_points'.
3110 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3111 * zone, and both zp1 and zp2 set to normal zone.
3113 * in: point
3115 * sal: sal_i (edge_orig_pos)
3116 * sal_j (stretch_factor)
3117 * sal_scale
3120 static const unsigned char FPGM(bci_ip_between_align_point) [] =
3123 PUSHB_1,
3124 bci_ip_between_align_point,
3125 FDEF,
3127 DUP,
3128 ALIGNRP, /* align `point' with `edge' */
3129 DUP,
3130 GC_orig,
3131 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3133 PUSHB_1,
3134 sal_i,
3136 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3137 PUSHB_1,
3138 sal_j,
3140 MUL, /* s: point delta */
3141 SHPIX,
3143 ENDF,
3149 * bci_ip_between_align_points
3151 * Auxiliary function for `bci_action_ip_between'.
3153 * in: after_edge (in twilight zone)
3154 * before_edge (in twilight zone)
3155 * loop_counter (N)
3156 * point_1
3157 * point_2
3158 * ...
3159 * point_N
3161 * sal: sal_i (before_orig_pos)
3162 * sal_j (stretch_factor)
3164 * uses: bci_ip_between_align_point
3167 static const unsigned char FPGM(bci_ip_between_align_points) [] =
3170 PUSHB_1,
3171 bci_ip_between_align_points,
3172 FDEF,
3174 PUSHB_2,
3177 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3178 CINDEX,
3179 DUP, /* s: ... before after before before */
3180 MDAP_noround, /* set rp0 and rp1 to `before' */
3181 DUP,
3182 GC_orig, /* s: ... before after before before_orig_pos */
3183 PUSHB_1,
3184 sal_i,
3185 SWAP,
3186 WS, /* sal_i = before_orig_pos */
3187 PUSHB_1,
3189 CINDEX, /* s: ... before after before after */
3190 MD_cur, /* a = after_pos - before_pos */
3191 ROLL,
3192 ROLL,
3193 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
3195 DUP,
3196 IF, /* b != 0 ? */
3197 DIV, /* s: a/b */
3198 ELSE,
3199 POP, /* avoid division by zero */
3200 EIF,
3202 PUSHB_1,
3203 sal_j,
3204 SWAP,
3205 WS, /* sal_j = stretch_factor */
3207 PUSHB_3,
3208 bci_ip_between_align_point,
3211 SZP2, /* set zp2 to normal zone 1 */
3212 SZP1, /* set zp1 to normal zone 1 */
3213 LOOPCALL,
3215 ENDF,
3221 * bci_action_ip_before
3223 * Handle `ip_before' data to align points located before the first edge.
3225 * in: first_edge (in twilight zone)
3226 * loop_counter (N)
3227 * point_1
3228 * point_2
3229 * ...
3230 * point_N
3232 * sal: sal_i (first_edge_orig_pos)
3234 * uses: bci_ip_outer_align_point
3237 static const unsigned char FPGM(bci_action_ip_before) [] =
3240 PUSHB_1,
3241 bci_action_ip_before,
3242 FDEF,
3244 PUSHB_1,
3246 SZP2, /* set zp2 to twilight zone 0 */
3248 DUP,
3249 GC_orig,
3250 PUSHB_1,
3251 sal_i,
3252 SWAP,
3253 WS, /* sal_i = first_edge_orig_pos */
3255 PUSHB_3,
3259 SZP2, /* set zp2 to normal zone 1 */
3260 SZP1, /* set zp1 to normal zone 1 */
3261 SZP0, /* set zp0 to twilight zone 0 */
3263 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
3265 PUSHB_1,
3266 bci_ip_outer_align_point,
3267 LOOPCALL,
3269 ENDF,
3275 * bci_action_ip_after
3277 * Handle `ip_after' data to align points located after the last edge.
3279 * in: last_edge (in twilight zone)
3280 * loop_counter (N)
3281 * point_1
3282 * point_2
3283 * ...
3284 * point_N
3286 * sal: sal_i (last_edge_orig_pos)
3288 * uses: bci_ip_outer_align_point
3291 static const unsigned char FPGM(bci_action_ip_after) [] =
3294 PUSHB_1,
3295 bci_action_ip_after,
3296 FDEF,
3298 PUSHB_1,
3300 SZP2, /* set zp2 to twilight zone 0 */
3302 DUP,
3303 GC_orig,
3304 PUSHB_1,
3305 sal_i,
3306 SWAP,
3307 WS, /* sal_i = last_edge_orig_pos */
3309 PUSHB_3,
3313 SZP2, /* set zp2 to normal zone 1 */
3314 SZP1, /* set zp1 to normal zone 1 */
3315 SZP0, /* set zp0 to twilight zone 0 */
3317 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3319 PUSHB_1,
3320 bci_ip_outer_align_point,
3321 LOOPCALL,
3323 ENDF,
3329 * bci_action_ip_on
3331 * Handle `ip_on' data to align points located on an edge coordinate (but
3332 * not part of an edge).
3334 * in: loop_counter (M)
3335 * edge_1 (in twilight zone)
3336 * loop_counter (N_1)
3337 * point_1
3338 * point_2
3339 * ...
3340 * point_N_1
3341 * edge_2 (in twilight zone)
3342 * loop_counter (N_2)
3343 * point_1
3344 * point_2
3345 * ...
3346 * point_N_2
3347 * ...
3348 * edge_M (in twilight zone)
3349 * loop_counter (N_M)
3350 * point_1
3351 * point_2
3352 * ...
3353 * point_N_M
3355 * uses: bci_ip_on_align_points
3358 static const unsigned char FPGM(bci_action_ip_on) [] =
3361 PUSHB_1,
3362 bci_action_ip_on,
3363 FDEF,
3365 PUSHB_2,
3368 SZP1, /* set zp1 to normal zone 1 */
3369 SZP0, /* set zp0 to twilight zone 0 */
3371 PUSHB_1,
3372 bci_ip_on_align_points,
3373 LOOPCALL,
3375 ENDF,
3381 * bci_action_ip_between
3383 * Handle `ip_between' data to align points located between two edges.
3385 * in: loop_counter (M)
3386 * before_edge_1 (in twilight zone)
3387 * after_edge_1 (in twilight zone)
3388 * loop_counter (N_1)
3389 * point_1
3390 * point_2
3391 * ...
3392 * point_N_1
3393 * before_edge_2 (in twilight zone)
3394 * after_edge_2 (in twilight zone)
3395 * loop_counter (N_2)
3396 * point_1
3397 * point_2
3398 * ...
3399 * point_N_2
3400 * ...
3401 * before_edge_M (in twilight zone)
3402 * after_edge_M (in twilight zone)
3403 * loop_counter (N_M)
3404 * point_1
3405 * point_2
3406 * ...
3407 * point_N_M
3409 * uses: bci_ip_between_align_points
3412 static const unsigned char FPGM(bci_action_ip_between) [] =
3415 PUSHB_1,
3416 bci_action_ip_between,
3417 FDEF,
3419 PUSHB_1,
3420 bci_ip_between_align_points,
3421 LOOPCALL,
3423 ENDF,
3429 * bci_adjust_common
3431 * Common code for bci_action_adjust routines.
3433 * in: top_to_bottom_hinting
3434 * edge2_is_serif
3435 * edge_is_round
3436 * edge
3437 * edge2
3439 * out: edge (adjusted)
3441 * sal: sal_top_to_bottom_hinting
3442 * sal_base_delta
3444 * uses: func[sal_stem_width_function]
3447 static const unsigned char FPGM(bci_adjust_common) [] =
3450 PUSHB_1,
3451 bci_adjust_common,
3452 FDEF,
3454 PUSHB_1,
3456 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3457 PUSHB_1,
3458 sal_top_to_bottom_hinting,
3459 SWAP,
3462 PUSHB_1,
3464 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3465 PUSHB_1,
3467 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3468 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3470 PUSHB_2,
3471 sal_base_delta, /* no base_delta needed here */
3475 PUSHB_1,
3476 sal_stem_width_function,
3478 CALL,
3479 NEG, /* s: [...] edge2 edge -cur_len */
3481 ROLL, /* s: [...] edge -cur_len edge2 */
3482 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3483 SWAP,
3484 DUP,
3485 DUP, /* s: [...] -cur_len edge edge edge */
3486 ALIGNRP, /* align `edge' with `edge2' */
3487 ROLL,
3488 SHPIX, /* shift `edge' by -cur_len */
3490 ENDF,
3496 * bci_adjust_bound
3498 * Handle the ADJUST + BOUND actions to align an edge of a stem if the
3499 * other edge of the stem has already been moved, then moving it again if
3500 * necessary to stay bound.
3502 * in: top_to_bottom_hinting
3503 * edge2_is_serif
3504 * edge_is_round
3505 * edge_point (in twilight zone)
3506 * edge2_point (in twilight zone)
3507 * edge[-1] (in twilight zone)
3508 * ... stuff for bci_align_segments (edge) ...
3510 * sal: sal_top_to_bottom_hinting
3512 * uses: bci_adjust_common
3513 * bci_align_segments
3516 static const unsigned char FPGM(bci_adjust_bound) [] =
3519 PUSHB_1,
3520 bci_adjust_bound,
3521 FDEF,
3523 PUSHB_1,
3524 bci_adjust_common,
3525 CALL,
3527 SWAP, /* s: edge edge[-1] */
3528 DUP,
3529 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3530 GC_cur,
3531 PUSHB_1,
3533 CINDEX,
3534 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3535 PUSHB_1,
3536 sal_top_to_bottom_hinting,
3539 LT, /* edge_pos > edge[-1]_pos */
3540 ELSE,
3541 GT, /* edge_pos < edge[-1]_pos */
3542 EIF,
3544 DUP,
3545 ALIGNRP, /* align `edge' to `edge[-1]' */
3546 EIF,
3548 MDAP_noround, /* set rp0 and rp1 to `edge' */
3550 PUSHB_2,
3551 bci_align_segments,
3553 SZP1, /* set zp1 to normal zone 1 */
3554 CALL,
3556 ENDF,
3562 * bci_action_adjust_bound
3563 * bci_action_adjust_bound_serif
3564 * bci_action_adjust_bound_round
3565 * bci_action_adjust_bound_round_serif
3566 * bci_action_adjust_down_bound
3567 * bci_action_adjust_down_bound_serif
3568 * bci_action_adjust_down_bound_round
3569 * bci_action_adjust_down_bound_round_serif
3571 * Higher-level routines for calling `bci_adjust_bound'.
3574 static const unsigned char FPGM(bci_action_adjust_bound) [] =
3577 PUSHB_1,
3578 bci_action_adjust_bound,
3579 FDEF,
3581 PUSHB_4,
3585 bci_adjust_bound,
3586 CALL,
3588 ENDF,
3592 static const unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3595 PUSHB_1,
3596 bci_action_adjust_bound_serif,
3597 FDEF,
3599 PUSHB_4,
3603 bci_adjust_bound,
3604 CALL,
3606 ENDF,
3610 static const unsigned char FPGM(bci_action_adjust_bound_round) [] =
3613 PUSHB_1,
3614 bci_action_adjust_bound_round,
3615 FDEF,
3617 PUSHB_4,
3621 bci_adjust_bound,
3622 CALL,
3624 ENDF,
3628 static const unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3631 PUSHB_1,
3632 bci_action_adjust_bound_round_serif,
3633 FDEF,
3635 PUSHB_4,
3639 bci_adjust_bound,
3640 CALL,
3642 ENDF,
3646 static const unsigned char FPGM(bci_action_adjust_down_bound) [] =
3649 PUSHB_1,
3650 bci_action_adjust_down_bound,
3651 FDEF,
3653 PUSHB_4,
3657 bci_adjust_bound,
3658 CALL,
3660 ENDF,
3664 static const unsigned char FPGM(bci_action_adjust_down_bound_serif) [] =
3667 PUSHB_1,
3668 bci_action_adjust_down_bound_serif,
3669 FDEF,
3671 PUSHB_4,
3675 bci_adjust_bound,
3676 CALL,
3678 ENDF,
3682 static const unsigned char FPGM(bci_action_adjust_down_bound_round) [] =
3685 PUSHB_1,
3686 bci_action_adjust_down_bound_round,
3687 FDEF,
3689 PUSHB_4,
3693 bci_adjust_bound,
3694 CALL,
3696 ENDF,
3700 static const unsigned char FPGM(bci_action_adjust_down_bound_round_serif) [] =
3703 PUSHB_1,
3704 bci_action_adjust_down_bound_round_serif,
3705 FDEF,
3707 PUSHB_4,
3711 bci_adjust_bound,
3712 CALL,
3714 ENDF,
3720 * bci_adjust
3722 * Handle the ADJUST action to align an edge of a stem if the other edge
3723 * of the stem has already been moved.
3725 * in: edge2_is_serif
3726 * edge_is_round
3727 * edge_point (in twilight zone)
3728 * edge2_point (in twilight zone)
3729 * ... stuff for bci_align_segments (edge) ...
3731 * uses: bci_adjust_common
3732 * bci_align_segments
3735 static const unsigned char FPGM(bci_adjust) [] =
3738 PUSHB_1,
3739 bci_adjust,
3740 FDEF,
3742 PUSHB_2,
3744 bci_adjust_common,
3745 CALL,
3747 MDAP_noround, /* set rp0 and rp1 to `edge' */
3749 PUSHB_2,
3750 bci_align_segments,
3752 SZP1, /* set zp1 to normal zone 1 */
3753 CALL,
3755 ENDF,
3761 * bci_action_adjust
3762 * bci_action_adjust_serif
3763 * bci_action_adjust_round
3764 * bci_action_adjust_round_serif
3766 * Higher-level routines for calling `bci_adjust'.
3769 static const unsigned char FPGM(bci_action_adjust) [] =
3772 PUSHB_1,
3773 bci_action_adjust,
3774 FDEF,
3776 PUSHB_3,
3779 bci_adjust,
3780 CALL,
3782 ENDF,
3786 static const unsigned char FPGM(bci_action_adjust_serif) [] =
3789 PUSHB_1,
3790 bci_action_adjust_serif,
3791 FDEF,
3793 PUSHB_3,
3796 bci_adjust,
3797 CALL,
3799 ENDF,
3803 static const unsigned char FPGM(bci_action_adjust_round) [] =
3806 PUSHB_1,
3807 bci_action_adjust_round,
3808 FDEF,
3810 PUSHB_3,
3813 bci_adjust,
3814 CALL,
3816 ENDF,
3820 static const unsigned char FPGM(bci_action_adjust_round_serif) [] =
3823 PUSHB_1,
3824 bci_action_adjust_round_serif,
3825 FDEF,
3827 PUSHB_3,
3830 bci_adjust,
3831 CALL,
3833 ENDF,
3839 * bci_stem_common
3841 * Common code for bci_action_stem routines.
3843 * in: top_to_bottom_hinting
3844 * edge2_is_serif
3845 * edge_is_round
3846 * edge
3847 * edge2
3849 * out: edge
3850 * cur_len
3851 * edge2
3853 * sal: sal_anchor
3854 * sal_temp1
3855 * sal_temp2
3856 * sal_temp3
3857 * sal_top_to_bottom_hinting
3858 * sal_base_delta
3860 * uses: func[sal_stem_width_function]
3861 * bci_round
3864 #undef sal_u_off
3865 #define sal_u_off sal_temp1
3866 #undef sal_d_off
3867 #define sal_d_off sal_temp2
3868 #undef sal_org_len
3869 #define sal_org_len sal_temp3
3870 #undef sal_edge2
3871 #define sal_edge2 sal_temp3
3873 static const unsigned char FPGM(bci_stem_common) [] =
3876 PUSHB_1,
3877 bci_stem_common,
3878 FDEF,
3880 PUSHB_1,
3882 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3884 PUSHB_1,
3885 sal_top_to_bottom_hinting,
3886 SWAP,
3889 PUSHB_1,
3891 CINDEX,
3892 PUSHB_1,
3894 CINDEX,
3895 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3896 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3898 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3899 DUP,
3900 PUSHB_1,
3901 sal_org_len,
3902 SWAP,
3905 PUSHB_2,
3906 sal_base_delta, /* no base_delta needed here */
3910 PUSHB_1,
3911 sal_stem_width_function,
3913 CALL, /* s: [...] edge2 edge cur_len */
3915 DUP,
3916 PUSHB_1,
3918 LT, /* cur_len < 96 */
3920 DUP,
3921 PUSHB_1,
3923 LTEQ, /* cur_len <= 64 */
3925 PUSHB_4,
3926 sal_u_off,
3928 sal_d_off,
3931 ELSE,
3932 PUSHB_4,
3933 sal_u_off,
3935 sal_d_off,
3937 EIF,
3941 SWAP, /* s: [...] edge2 cur_len edge */
3942 DUP,
3943 PUSHB_1,
3944 sal_anchor,
3946 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3947 ROLL,
3948 SWAP,
3949 MD_orig_ZP2_0,
3950 SWAP,
3951 GC_cur,
3952 ADD, /* s: [...] edge2 cur_len edge org_pos */
3953 PUSHB_1,
3954 sal_org_len,
3956 DIV_BY_2,
3957 ADD, /* s: [...] edge2 cur_len edge org_center */
3959 DUP,
3960 PUSHB_1,
3961 bci_round,
3962 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3964 DUP,
3965 ROLL,
3966 ROLL,
3967 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3969 DUP,
3970 PUSHB_1,
3971 sal_u_off,
3973 ADD,
3974 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3976 SWAP,
3977 PUSHB_1,
3978 sal_d_off,
3980 SUB,
3981 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3983 LT, /* delta1 < delta2 */
3985 PUSHB_1,
3986 sal_u_off,
3988 SUB, /* cur_pos1 = cur_pos1 - u_off */
3990 ELSE,
3991 PUSHB_1,
3992 sal_d_off,
3994 ADD, /* cur_pos1 = cur_pos1 + d_off */
3995 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3997 PUSHB_1,
3999 CINDEX,
4000 DIV_BY_2,
4001 SUB, /* arg = cur_pos1 - cur_len/2 */
4003 SWAP, /* s: [...] edge2 cur_len arg edge */
4004 DUP,
4005 DUP,
4006 PUSHB_1,
4008 MINDEX,
4009 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4010 GC_cur,
4011 SUB,
4012 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4014 ELSE,
4015 SWAP, /* s: [...] edge2 cur_len edge */
4016 PUSHB_1,
4017 sal_anchor,
4019 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
4020 PUSHB_1,
4022 CINDEX,
4023 PUSHB_1,
4024 sal_anchor,
4026 MD_orig_ZP2_0,
4027 ADD, /* s: [...] edge2 cur_len edge org_pos */
4029 DUP,
4030 PUSHB_1,
4031 sal_org_len,
4033 DIV_BY_2,
4034 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
4036 SWAP,
4037 DUP,
4038 PUSHB_1,
4039 bci_round,
4040 CALL, /* cur_pos1 = ROUND(org_pos) */
4041 SWAP,
4042 PUSHB_1,
4043 sal_org_len,
4045 ADD,
4046 PUSHB_1,
4047 bci_round,
4048 CALL,
4049 PUSHB_1,
4051 CINDEX,
4052 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
4054 PUSHB_1,
4056 CINDEX,
4057 DIV_BY_2,
4058 PUSHB_1,
4060 MINDEX,
4061 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
4063 DUP,
4064 PUSHB_1,
4066 CINDEX,
4067 ADD,
4068 ABS, /* delta1 = |cur_pos1 + cur_len / 2 - org_center| */
4069 SWAP,
4070 PUSHB_1,
4072 CINDEX,
4073 ADD,
4074 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
4075 LT, /* delta1 < delta2 */
4077 POP, /* arg = cur_pos1 */
4079 ELSE,
4080 SWAP,
4081 POP, /* arg = cur_pos2 */
4082 EIF, /* s: [...] edge2 cur_len edge arg */
4083 SWAP,
4084 DUP,
4085 DUP,
4086 PUSHB_1,
4088 MINDEX,
4089 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4090 GC_cur,
4091 SUB,
4092 SHPIX, /* edge = arg */
4093 EIF, /* s: [...] edge2 cur_len edge */
4095 ENDF,
4101 * bci_stem_bound
4103 * Handle the STEM action to align two edges of a stem, then moving one
4104 * edge again if necessary to stay bound.
4106 * The code after computing `cur_len' to shift `edge' and `edge2'
4107 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4109 * if cur_len < 96:
4110 * if cur_len < = 64:
4111 * u_off = 32
4112 * d_off = 32
4113 * else:
4114 * u_off = 38
4115 * d_off = 26
4117 * org_pos = anchor + (edge_orig - anchor_orig)
4118 * org_center = org_pos + org_len / 2
4120 * cur_pos1 = ROUND(org_center)
4121 * delta1 = |org_center - (cur_pos1 - u_off)|
4122 * delta2 = |org_center - (cur_pos1 + d_off)|
4123 * if (delta1 < delta2):
4124 * cur_pos1 = cur_pos1 - u_off
4125 * else:
4126 * cur_pos1 = cur_pos1 + d_off
4128 * edge = cur_pos1 - cur_len / 2
4130 * else:
4131 * org_pos = anchor + (edge_orig - anchor_orig)
4132 * org_center = org_pos + org_len / 2
4134 * cur_pos1 = ROUND(org_pos)
4135 * delta1 = |cur_pos1 + cur_len / 2 - org_center|
4136 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
4137 * delta2 = |cur_pos2 + cur_len / 2 - org_center|
4139 * if (delta1 < delta2):
4140 * edge = cur_pos1
4141 * else:
4142 * edge = cur_pos2
4144 * edge2 = edge + cur_len
4146 * in: top_to_bottom_hinting
4147 * edge2_is_serif
4148 * edge_is_round
4149 * edge_point (in twilight zone)
4150 * edge2_point (in twilight zone)
4151 * edge[-1] (in twilight zone)
4152 * ... stuff for bci_align_segments (edge) ...
4153 * ... stuff for bci_align_segments (edge2)...
4155 * sal: sal_anchor
4156 * sal_temp1
4157 * sal_temp2
4158 * sal_temp3
4159 * sal_top_to_bottom_hinting
4161 * uses: bci_stem_common
4162 * bci_align_segments
4165 static const unsigned char FPGM(bci_stem_bound) [] =
4168 PUSHB_1,
4169 bci_stem_bound,
4170 FDEF,
4172 PUSHB_1,
4173 bci_stem_common,
4174 CALL,
4176 ROLL, /* s: edge[-1] cur_len edge edge2 */
4177 DUP,
4178 DUP,
4179 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4180 PUSHB_1,
4181 sal_edge2,
4182 SWAP,
4183 WS, /* s: edge[-1] cur_len edge edge2 */
4184 ROLL,
4185 SHPIX, /* edge2 = edge + cur_len */
4187 SWAP, /* s: edge edge[-1] */
4188 DUP,
4189 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
4190 GC_cur,
4191 PUSHB_1,
4193 CINDEX,
4194 GC_cur, /* s: edge edge[-1]_pos edge_pos */
4195 PUSHB_1,
4196 sal_top_to_bottom_hinting,
4199 LT, /* edge_pos > edge[-1]_pos */
4200 ELSE,
4201 GT, /* edge_pos < edge[-1]_pos */
4202 EIF,
4204 DUP,
4205 ALIGNRP, /* align `edge' to `edge[-1]' */
4206 EIF,
4208 MDAP_noround, /* set rp0 and rp1 to `edge' */
4210 PUSHB_2,
4211 bci_align_segments,
4213 SZP1, /* set zp1 to normal zone 1 */
4214 CALL,
4216 PUSHB_1,
4217 sal_edge2,
4219 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4221 PUSHB_1,
4222 bci_align_segments,
4223 CALL,
4225 ENDF,
4231 * bci_action_stem_bound
4232 * bci_action_stem_bound_serif
4233 * bci_action_stem_bound_round
4234 * bci_action_stem_bound_round_serif
4235 * bci_action_stem_down_bound
4236 * bci_action_stem_down_bound_serif
4237 * bci_action_stem_down_bound_round
4238 * bci_action_stem_down_bound_round_serif
4240 * Higher-level routines for calling `bci_stem_bound'.
4243 static const unsigned char FPGM(bci_action_stem_bound) [] =
4246 PUSHB_1,
4247 bci_action_stem_bound,
4248 FDEF,
4250 PUSHB_4,
4254 bci_stem_bound,
4255 CALL,
4257 ENDF,
4261 static const unsigned char FPGM(bci_action_stem_bound_serif) [] =
4264 PUSHB_1,
4265 bci_action_stem_bound_serif,
4266 FDEF,
4268 PUSHB_4,
4272 bci_stem_bound,
4273 CALL,
4275 ENDF,
4279 static const unsigned char FPGM(bci_action_stem_bound_round) [] =
4282 PUSHB_1,
4283 bci_action_stem_bound_round,
4284 FDEF,
4286 PUSHB_4,
4290 bci_stem_bound,
4291 CALL,
4293 ENDF,
4297 static const unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
4300 PUSHB_1,
4301 bci_action_stem_bound_round_serif,
4302 FDEF,
4304 PUSHB_4,
4308 bci_stem_bound,
4309 CALL,
4311 ENDF,
4315 static const unsigned char FPGM(bci_action_stem_down_bound) [] =
4318 PUSHB_1,
4319 bci_action_stem_down_bound,
4320 FDEF,
4322 PUSHB_4,
4326 bci_stem_bound,
4327 CALL,
4329 ENDF,
4333 static const unsigned char FPGM(bci_action_stem_down_bound_serif) [] =
4336 PUSHB_1,
4337 bci_action_stem_down_bound_serif,
4338 FDEF,
4340 PUSHB_4,
4344 bci_stem_bound,
4345 CALL,
4347 ENDF,
4351 static const unsigned char FPGM(bci_action_stem_down_bound_round) [] =
4354 PUSHB_1,
4355 bci_action_stem_down_bound_round,
4356 FDEF,
4358 PUSHB_4,
4362 bci_stem_bound,
4363 CALL,
4365 ENDF,
4369 static const unsigned char FPGM(bci_action_stem_down_bound_round_serif) [] =
4372 PUSHB_1,
4373 bci_action_stem_down_bound_round_serif,
4374 FDEF,
4376 PUSHB_4,
4380 bci_stem_bound,
4381 CALL,
4383 ENDF,
4389 * bci_stem
4391 * Handle the STEM action to align two edges of a stem.
4393 * See `bci_stem_bound' for more details.
4395 * in: edge2_is_serif
4396 * edge_is_round
4397 * edge_point (in twilight zone)
4398 * edge2_point (in twilight zone)
4399 * ... stuff for bci_align_segments (edge) ...
4400 * ... stuff for bci_align_segments (edge2)...
4402 * sal: sal_anchor
4403 * sal_temp1
4404 * sal_temp2
4405 * sal_temp3
4407 * uses: bci_stem_common
4408 * bci_align_segments
4411 static const unsigned char FPGM(bci_stem) [] =
4414 PUSHB_1,
4415 bci_stem,
4416 FDEF,
4418 PUSHB_2,
4420 bci_stem_common,
4421 CALL,
4423 POP,
4424 SWAP, /* s: cur_len edge2 */
4425 DUP,
4426 DUP,
4427 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4428 PUSHB_1,
4429 sal_edge2,
4430 SWAP,
4431 WS, /* s: cur_len edge2 */
4432 SWAP,
4433 SHPIX, /* edge2 = edge + cur_len */
4435 PUSHB_2,
4436 bci_align_segments,
4438 SZP1, /* set zp1 to normal zone 1 */
4439 CALL,
4441 PUSHB_1,
4442 sal_edge2,
4444 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4446 PUSHB_1,
4447 bci_align_segments,
4448 CALL,
4449 ENDF,
4455 * bci_action_stem
4456 * bci_action_stem_serif
4457 * bci_action_stem_round
4458 * bci_action_stem_round_serif
4460 * Higher-level routines for calling `bci_stem'.
4463 static const unsigned char FPGM(bci_action_stem) [] =
4466 PUSHB_1,
4467 bci_action_stem,
4468 FDEF,
4470 PUSHB_3,
4473 bci_stem,
4474 CALL,
4476 ENDF,
4480 static const unsigned char FPGM(bci_action_stem_serif) [] =
4483 PUSHB_1,
4484 bci_action_stem_serif,
4485 FDEF,
4487 PUSHB_3,
4490 bci_stem,
4491 CALL,
4493 ENDF,
4497 static const unsigned char FPGM(bci_action_stem_round) [] =
4500 PUSHB_1,
4501 bci_action_stem_round,
4502 FDEF,
4504 PUSHB_3,
4507 bci_stem,
4508 CALL,
4510 ENDF,
4514 static const unsigned char FPGM(bci_action_stem_round_serif) [] =
4517 PUSHB_1,
4518 bci_action_stem_round_serif,
4519 FDEF,
4521 PUSHB_3,
4524 bci_stem,
4525 CALL,
4527 ENDF,
4533 * bci_link
4535 * Handle the LINK action to link an edge to another one.
4537 * in: stem_is_serif
4538 * base_is_round
4539 * base_point (in twilight zone)
4540 * stem_point (in twilight zone)
4541 * ... stuff for bci_align_segments (base) ...
4543 * sal: sal_base_delta
4545 * uses: func[sal_stem_width_function]
4546 * bci_align_segments
4549 static const unsigned char FPGM(bci_link) [] =
4552 PUSHB_1,
4553 bci_link,
4554 FDEF,
4556 PUSHB_1,
4558 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4560 PUSHB_1,
4562 CINDEX,
4563 PUSHB_1,
4565 MINDEX,
4566 DUP, /* s: stem is_round is_serif stem base base */
4568 DUP,
4569 DUP,
4570 GC_cur,
4571 SWAP,
4572 GC_orig,
4573 SUB, /* base_delta = base_point_pos - base_point_orig_pos */
4574 PUSHB_1,
4575 sal_base_delta,
4576 SWAP,
4577 WS, /* sal_base_delta = base_delta */
4579 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4581 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4583 PUSHB_1,
4584 sal_stem_width_function,
4586 CALL, /* s: stem new_dist */
4588 SWAP,
4589 DUP,
4590 ALIGNRP, /* align `stem_point' with `base_point' */
4591 DUP,
4592 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4593 SWAP,
4594 SHPIX, /* stem_point = base_point + new_dist */
4596 PUSHB_2,
4597 bci_align_segments,
4599 SZP1, /* set zp1 to normal zone 1 */
4600 CALL,
4602 ENDF,
4608 * bci_action_link
4609 * bci_action_link_serif
4610 * bci_action_link_round
4611 * bci_action_link_round_serif
4613 * Higher-level routines for calling `bci_link'.
4616 static const unsigned char FPGM(bci_action_link) [] =
4619 PUSHB_1,
4620 bci_action_link,
4621 FDEF,
4623 PUSHB_3,
4626 bci_link,
4627 CALL,
4629 ENDF,
4633 static const unsigned char FPGM(bci_action_link_serif) [] =
4636 PUSHB_1,
4637 bci_action_link_serif,
4638 FDEF,
4640 PUSHB_3,
4643 bci_link,
4644 CALL,
4646 ENDF,
4650 static const unsigned char FPGM(bci_action_link_round) [] =
4653 PUSHB_1,
4654 bci_action_link_round,
4655 FDEF,
4657 PUSHB_3,
4660 bci_link,
4661 CALL,
4663 ENDF,
4667 static const unsigned char FPGM(bci_action_link_round_serif) [] =
4670 PUSHB_1,
4671 bci_action_link_round_serif,
4672 FDEF,
4674 PUSHB_3,
4677 bci_link,
4678 CALL,
4680 ENDF,
4686 * bci_anchor
4688 * Handle the ANCHOR action to align two edges
4689 * and to set the edge anchor.
4691 * The code after computing `cur_len' to shift `edge' and `edge2'
4692 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4694 * if cur_len < 96:
4695 * if cur_len < = 64:
4696 * u_off = 32
4697 * d_off = 32
4698 * else:
4699 * u_off = 38
4700 * d_off = 26
4702 * org_center = edge_orig + org_len / 2
4703 * cur_pos1 = ROUND(org_center)
4705 * error1 = |org_center - (cur_pos1 - u_off)|
4706 * error2 = |org_center - (cur_pos1 + d_off)|
4707 * if (error1 < error2):
4708 * cur_pos1 = cur_pos1 - u_off
4709 * else:
4710 * cur_pos1 = cur_pos1 + d_off
4712 * edge = cur_pos1 - cur_len / 2
4713 * edge2 = edge + cur_len
4715 * else:
4716 * edge = ROUND(edge_orig)
4718 * in: edge2_is_serif
4719 * edge_is_round
4720 * edge_point (in twilight zone)
4721 * edge2_point (in twilight zone)
4722 * ... stuff for bci_align_segments (edge) ...
4724 * sal: sal_anchor
4725 * sal_temp1
4726 * sal_temp2
4727 * sal_temp3
4728 * sal_base_delta
4730 * uses: func[sal_stem_width_function]
4731 * bci_round
4732 * bci_align_segments
4735 #undef sal_u_off
4736 #define sal_u_off sal_temp1
4737 #undef sal_d_off
4738 #define sal_d_off sal_temp2
4739 #undef sal_org_len
4740 #define sal_org_len sal_temp3
4742 static const unsigned char FPGM(bci_anchor) [] =
4745 PUSHB_1,
4746 bci_anchor,
4747 FDEF,
4749 /* store anchor point number in `sal_anchor' */
4750 PUSHB_2,
4751 sal_anchor,
4753 CINDEX,
4754 WS, /* sal_anchor = edge_point */
4756 PUSHB_1,
4758 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4760 PUSHB_1,
4762 CINDEX,
4763 PUSHB_1,
4765 CINDEX,
4766 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4767 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4769 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4770 DUP,
4771 PUSHB_1,
4772 sal_org_len,
4773 SWAP,
4776 PUSHB_2,
4777 sal_base_delta, /* no base_delta needed here */
4781 PUSHB_1,
4782 sal_stem_width_function,
4784 CALL, /* s: edge2 edge cur_len */
4786 DUP,
4787 PUSHB_1,
4789 LT, /* cur_len < 96 */
4791 DUP,
4792 PUSHB_1,
4794 LTEQ, /* cur_len <= 64 */
4796 PUSHB_4,
4797 sal_u_off,
4799 sal_d_off,
4802 ELSE,
4803 PUSHB_4,
4804 sal_u_off,
4806 sal_d_off,
4808 EIF,
4812 SWAP, /* s: edge2 cur_len edge */
4813 DUP, /* s: edge2 cur_len edge edge */
4815 GC_orig,
4816 PUSHB_1,
4817 sal_org_len,
4819 DIV_BY_2,
4820 ADD, /* s: edge2 cur_len edge org_center */
4822 DUP,
4823 PUSHB_1,
4824 bci_round,
4825 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4827 DUP,
4828 ROLL,
4829 ROLL,
4830 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4832 DUP,
4833 PUSHB_1,
4834 sal_u_off,
4836 ADD,
4837 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4839 SWAP,
4840 PUSHB_1,
4841 sal_d_off,
4843 SUB,
4844 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4846 LT, /* error1 < error2 */
4848 PUSHB_1,
4849 sal_u_off,
4851 SUB, /* cur_pos1 = cur_pos1 - u_off */
4853 ELSE,
4854 PUSHB_1,
4855 sal_d_off,
4857 ADD, /* cur_pos1 = cur_pos1 + d_off */
4858 EIF, /* s: edge2 cur_len edge cur_pos1 */
4860 PUSHB_1,
4862 CINDEX,
4863 DIV_BY_2,
4864 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4866 PUSHB_1,
4868 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4869 GC_cur,
4870 SUB,
4871 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4873 SWAP, /* s: cur_len edge2 */
4874 DUP,
4875 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4876 SWAP,
4877 SHPIX, /* edge2 = edge1 + cur_len */
4879 ELSE,
4880 POP, /* s: edge2 edge */
4881 DUP,
4882 DUP,
4883 GC_cur,
4884 SWAP,
4885 GC_orig,
4886 PUSHB_1,
4887 bci_round,
4888 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4889 SWAP,
4890 SUB,
4891 SHPIX, /* edge = round(edge_orig) */
4893 /* clean up stack */
4894 POP,
4895 EIF,
4897 PUSHB_2,
4898 bci_align_segments,
4900 SZP1, /* set zp1 to normal zone 1 */
4901 CALL,
4903 ENDF,
4909 * bci_action_anchor
4910 * bci_action_anchor_serif
4911 * bci_action_anchor_round
4912 * bci_action_anchor_round_serif
4914 * Higher-level routines for calling `bci_anchor'.
4917 static const unsigned char FPGM(bci_action_anchor) [] =
4920 PUSHB_1,
4921 bci_action_anchor,
4922 FDEF,
4924 PUSHB_3,
4927 bci_anchor,
4928 CALL,
4930 ENDF,
4934 static const unsigned char FPGM(bci_action_anchor_serif) [] =
4937 PUSHB_1,
4938 bci_action_anchor_serif,
4939 FDEF,
4941 PUSHB_3,
4944 bci_anchor,
4945 CALL,
4947 ENDF,
4951 static const unsigned char FPGM(bci_action_anchor_round) [] =
4954 PUSHB_1,
4955 bci_action_anchor_round,
4956 FDEF,
4958 PUSHB_3,
4961 bci_anchor,
4962 CALL,
4964 ENDF,
4968 static const unsigned char FPGM(bci_action_anchor_round_serif) [] =
4971 PUSHB_1,
4972 bci_action_anchor_round_serif,
4973 FDEF,
4975 PUSHB_3,
4978 bci_anchor,
4979 CALL,
4981 ENDF,
4987 * bci_action_blue_anchor
4989 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4990 * and to set the edge anchor.
4992 * in: anchor_point (in twilight zone)
4993 * blue_cvt_idx
4994 * edge_point (in twilight zone)
4995 * ... stuff for bci_align_segments (edge) ...
4997 * sal: sal_anchor
4999 * uses: bci_action_blue
5002 static const unsigned char FPGM(bci_action_blue_anchor) [] =
5005 PUSHB_1,
5006 bci_action_blue_anchor,
5007 FDEF,
5009 /* store anchor point number in `sal_anchor' */
5010 PUSHB_1,
5011 sal_anchor,
5012 SWAP,
5015 PUSHB_1,
5016 bci_action_blue,
5017 CALL,
5019 ENDF,
5025 * bci_action_blue
5027 * Handle the BLUE action to align an edge with a blue zone.
5029 * in: blue_cvt_idx
5030 * edge_point (in twilight zone)
5031 * ... stuff for bci_align_segments (edge) ...
5033 * uses: bci_align_segments
5036 static const unsigned char FPGM(bci_action_blue) [] =
5039 PUSHB_1,
5040 bci_action_blue,
5041 FDEF,
5043 PUSHB_1,
5045 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5047 /* move `edge_point' to `blue_cvt_idx' position; */
5048 /* note that we can't use MIAP since this would modify */
5049 /* the twilight point's original coordinates also */
5050 RCVT,
5051 SWAP,
5052 DUP,
5053 MDAP_noround, /* set rp0 and rp1 to `edge' */
5054 DUP,
5055 GC_cur, /* s: new_pos edge edge_pos */
5056 ROLL,
5057 SWAP,
5058 SUB, /* s: edge (new_pos - edge_pos) */
5059 SHPIX,
5061 PUSHB_2,
5062 bci_align_segments,
5064 SZP1, /* set zp1 to normal zone 1 */
5065 CALL,
5067 ENDF,
5073 * bci_serif_common
5075 * Common code for bci_action_serif routines.
5077 * in: top_to_bottom_hinting
5078 * serif
5079 * base
5081 * sal: sal_top_to_bottom_hinting
5085 static const unsigned char FPGM(bci_serif_common) [] =
5088 PUSHB_1,
5089 bci_serif_common,
5090 FDEF,
5092 PUSHB_1,
5094 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5096 PUSHB_1,
5097 sal_top_to_bottom_hinting,
5098 SWAP,
5101 DUP,
5102 DUP,
5103 DUP,
5104 PUSHB_1,
5106 MINDEX, /* s: [...] serif serif serif serif base */
5107 DUP,
5108 MDAP_noround, /* set rp0 and rp1 to `base_point' */
5109 MD_orig_ZP2_0,
5110 SWAP,
5111 ALIGNRP, /* align `serif_point' with `base_point' */
5112 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
5114 ENDF,
5120 * bci_lower_bound
5122 * Move an edge if necessary to stay within a lower bound.
5124 * in: edge
5125 * bound
5127 * sal: sal_top_to_bottom_hinting
5129 * uses: bci_align_segments
5132 static const unsigned char FPGM(bci_lower_bound) [] =
5135 PUSHB_1,
5136 bci_lower_bound,
5137 FDEF,
5139 SWAP, /* s: edge bound */
5140 DUP,
5141 MDAP_noround, /* set rp0 and rp1 to `bound' */
5142 GC_cur,
5143 PUSHB_1,
5145 CINDEX,
5146 GC_cur, /* s: edge bound_pos edge_pos */
5147 PUSHB_1,
5148 sal_top_to_bottom_hinting,
5151 LT, /* edge_pos > bound_pos */
5152 ELSE,
5153 GT, /* edge_pos < bound_pos */
5154 EIF,
5156 DUP,
5157 ALIGNRP, /* align `edge' to `bound' */
5158 EIF,
5160 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5162 PUSHB_2,
5163 bci_align_segments,
5165 SZP1, /* set zp1 to normal zone 1 */
5166 CALL,
5168 ENDF,
5174 * bci_upper_bound
5176 * Move an edge if necessary to stay within an upper bound.
5178 * in: edge
5179 * bound
5181 * sal: sal_top_to_bottom_hinting
5183 * uses: bci_align_segments
5186 static const unsigned char FPGM(bci_upper_bound) [] =
5189 PUSHB_1,
5190 bci_upper_bound,
5191 FDEF,
5193 SWAP, /* s: edge bound */
5194 DUP,
5195 MDAP_noround, /* set rp0 and rp1 to `bound' */
5196 GC_cur,
5197 PUSHB_1,
5199 CINDEX,
5200 GC_cur, /* s: edge bound_pos edge_pos */
5201 PUSHB_1,
5202 sal_top_to_bottom_hinting,
5205 GT, /* edge_pos < bound_pos */
5206 ELSE,
5207 LT, /* edge_pos > bound_pos */
5208 EIF,
5210 DUP,
5211 ALIGNRP, /* align `edge' to `bound' */
5212 EIF,
5214 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5216 PUSHB_2,
5217 bci_align_segments,
5219 SZP1, /* set zp1 to normal zone 1 */
5220 CALL,
5222 ENDF,
5228 * bci_upper_lower_bound
5230 * Move an edge if necessary to stay within a lower and lower bound.
5232 * in: edge
5233 * lower
5234 * upper
5236 * sal: sal_top_to_bottom_hinting
5238 * uses: bci_align_segments
5241 static const unsigned char FPGM(bci_upper_lower_bound) [] =
5244 PUSHB_1,
5245 bci_upper_lower_bound,
5246 FDEF,
5248 SWAP, /* s: upper serif lower */
5249 DUP,
5250 MDAP_noround, /* set rp0 and rp1 to `lower' */
5251 GC_cur,
5252 PUSHB_1,
5254 CINDEX,
5255 GC_cur, /* s: upper serif lower_pos serif_pos */
5256 PUSHB_1,
5257 sal_top_to_bottom_hinting,
5260 LT, /* serif_pos > lower_pos */
5261 ELSE,
5262 GT, /* serif_pos < lower_pos */
5263 EIF,
5265 DUP,
5266 ALIGNRP, /* align `serif' to `lower' */
5267 EIF,
5269 SWAP, /* s: serif upper */
5270 DUP,
5271 MDAP_noround, /* set rp0 and rp1 to `upper' */
5272 GC_cur,
5273 PUSHB_1,
5275 CINDEX,
5276 GC_cur, /* s: serif upper_pos serif_pos */
5277 PUSHB_1,
5278 sal_top_to_bottom_hinting,
5281 GT, /* serif_pos < upper_pos */
5282 ELSE,
5283 LT, /* serif_pos > upper_pos */
5284 EIF,
5286 DUP,
5287 ALIGNRP, /* align `serif' to `upper' */
5288 EIF,
5290 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5292 PUSHB_2,
5293 bci_align_segments,
5295 SZP1, /* set zp1 to normal zone 1 */
5296 CALL,
5298 ENDF,
5304 * bci_action_serif
5306 * Handle the SERIF action to align a serif with its base.
5308 * in: serif_point (in twilight zone)
5309 * base_point (in twilight zone)
5310 * ... stuff for bci_align_segments (serif) ...
5312 * uses: bci_serif_common
5313 * bci_align_segments
5316 static const unsigned char FPGM(bci_action_serif) [] =
5319 PUSHB_1,
5320 bci_action_serif,
5321 FDEF,
5323 PUSHB_2,
5325 bci_serif_common,
5326 CALL,
5328 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5330 PUSHB_2,
5331 bci_align_segments,
5333 SZP1, /* set zp1 to normal zone 1 */
5334 CALL,
5336 ENDF,
5342 * bci_action_serif_lower_bound
5344 * Handle the SERIF action to align a serif with its base, then moving it
5345 * again if necessary to stay within a lower bound.
5347 * in: serif_point (in twilight zone)
5348 * base_point (in twilight zone)
5349 * edge[-1] (in twilight zone)
5350 * ... stuff for bci_align_segments (serif) ...
5352 * uses: bci_serif_common
5353 * bci_lower_bound
5356 static const unsigned char FPGM(bci_action_serif_lower_bound) [] =
5359 PUSHB_1,
5360 bci_action_serif_lower_bound,
5361 FDEF,
5363 PUSHB_2,
5365 bci_serif_common,
5366 CALL,
5368 PUSHB_1,
5369 bci_lower_bound,
5370 CALL,
5372 ENDF,
5378 * bci_action_serif_upper_bound
5380 * Handle the SERIF action to align a serif with its base, then moving it
5381 * again if necessary to stay within an upper bound.
5383 * in: serif_point (in twilight zone)
5384 * base_point (in twilight zone)
5385 * edge[1] (in twilight zone)
5386 * ... stuff for bci_align_segments (serif) ...
5388 * uses: bci_serif_common
5389 * bci_upper_bound
5392 static const unsigned char FPGM(bci_action_serif_upper_bound) [] =
5395 PUSHB_1,
5396 bci_action_serif_upper_bound,
5397 FDEF,
5399 PUSHB_2,
5401 bci_serif_common,
5402 CALL,
5404 PUSHB_1,
5405 bci_upper_bound,
5406 CALL,
5408 ENDF,
5414 * bci_action_serif_upper_lower_bound
5416 * Handle the SERIF action to align a serif with its base, then moving it
5417 * again if necessary to stay within a lower and upper bound.
5419 * in: serif_point (in twilight zone)
5420 * base_point (in twilight zone)
5421 * edge[-1] (in twilight zone)
5422 * edge[1] (in twilight zone)
5423 * ... stuff for bci_align_segments (serif) ...
5425 * uses: bci_serif_common
5426 * bci_upper_lower_bound
5429 static const unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
5432 PUSHB_1,
5433 bci_action_serif_upper_lower_bound,
5434 FDEF,
5436 PUSHB_1,
5438 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5440 PUSHB_2,
5442 bci_serif_common,
5443 CALL,
5445 PUSHB_1,
5446 bci_upper_lower_bound,
5447 CALL,
5449 ENDF,
5455 * bci_action_serif_down_lower_bound
5457 * Handle the SERIF action to align a serif with its base, then moving it
5458 * again if necessary to stay within a lower bound. We hint top to
5459 * bottom.
5461 * in: serif_point (in twilight zone)
5462 * base_point (in twilight zone)
5463 * edge[-1] (in twilight zone)
5464 * ... stuff for bci_align_segments (serif) ...
5466 * uses: bci_serif_common
5467 * bci_lower_bound
5470 static const unsigned char FPGM(bci_action_serif_down_lower_bound) [] =
5473 PUSHB_1,
5474 bci_action_serif_down_lower_bound,
5475 FDEF,
5477 PUSHB_2,
5479 bci_serif_common,
5480 CALL,
5482 PUSHB_1,
5483 bci_lower_bound,
5484 CALL,
5486 ENDF,
5492 * bci_action_serif_down_upper_bound
5494 * Handle the SERIF action to align a serif with its base, then moving it
5495 * again if necessary to stay within an upper bound. We hint top to
5496 * bottom.
5498 * in: serif_point (in twilight zone)
5499 * base_point (in twilight zone)
5500 * edge[1] (in twilight zone)
5501 * ... stuff for bci_align_segments (serif) ...
5503 * uses: bci_serif_common
5504 * bci_upper_bound
5507 static const unsigned char FPGM(bci_action_serif_down_upper_bound) [] =
5510 PUSHB_1,
5511 bci_action_serif_down_upper_bound,
5512 FDEF,
5514 PUSHB_2,
5516 bci_serif_common,
5517 CALL,
5519 PUSHB_1,
5520 bci_upper_bound,
5521 CALL,
5523 ENDF,
5529 * bci_action_serif_down_upper_lower_bound
5531 * Handle the SERIF action to align a serif with its base, then moving it
5532 * again if necessary to stay within a lower and upper bound. We hint top
5533 * to bottom.
5535 * in: serif_point (in twilight zone)
5536 * base_point (in twilight zone)
5537 * edge[-1] (in twilight zone)
5538 * edge[1] (in twilight zone)
5539 * ... stuff for bci_align_segments (serif) ...
5541 * uses: bci_serif_common
5542 * bci_upper_lower_bound
5545 static const unsigned char FPGM(bci_action_serif_down_upper_lower_bound) [] =
5548 PUSHB_1,
5549 bci_action_serif_down_upper_lower_bound,
5550 FDEF,
5552 PUSHB_1,
5554 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5556 PUSHB_2,
5558 bci_serif_common,
5559 CALL,
5561 PUSHB_1,
5562 bci_upper_lower_bound,
5563 CALL,
5565 ENDF,
5571 * bci_serif_anchor_common
5573 * Common code for bci_action_serif_anchor routines.
5575 * in: top_to_bottom_hinting
5576 * edge
5578 * out: edge (adjusted)
5580 * sal: sal_anchor
5581 * sal_top_to_bottom_hinting
5583 * uses: bci_round
5586 static const unsigned char FPGM(bci_serif_anchor_common) [] =
5589 PUSHB_1,
5590 bci_serif_anchor_common,
5591 FDEF,
5593 PUSHB_1,
5595 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5597 PUSHB_1,
5598 sal_top_to_bottom_hinting,
5599 SWAP,
5602 DUP,
5603 PUSHB_1,
5604 sal_anchor,
5605 SWAP,
5606 WS, /* sal_anchor = edge_point */
5608 DUP,
5609 DUP,
5610 DUP,
5611 GC_cur,
5612 SWAP,
5613 GC_orig,
5614 PUSHB_1,
5615 bci_round,
5616 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
5617 SWAP,
5618 SUB,
5619 SHPIX, /* edge = round(edge_orig) */
5621 ENDF,
5627 * bci_action_serif_anchor
5629 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5630 * anchor.
5632 * in: edge_point (in twilight zone)
5633 * ... stuff for bci_align_segments (edge) ...
5635 * uses: bci_serif_anchor_common
5636 * bci_align_segments
5639 static const unsigned char FPGM(bci_action_serif_anchor) [] =
5642 PUSHB_1,
5643 bci_action_serif_anchor,
5644 FDEF,
5646 PUSHB_2,
5648 bci_serif_anchor_common,
5649 CALL,
5651 MDAP_noround, /* set rp0 and rp1 to `edge' */
5653 PUSHB_2,
5654 bci_align_segments,
5656 SZP1, /* set zp1 to normal zone 1 */
5657 CALL,
5659 ENDF,
5665 * bci_action_serif_anchor_lower_bound
5667 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5668 * anchor, then moving it again if necessary to stay within a lower
5669 * bound.
5671 * in: edge_point (in twilight zone)
5672 * edge[-1] (in twilight zone)
5673 * ... stuff for bci_align_segments (edge) ...
5675 * uses: bci_serif_anchor_common
5676 * bci_lower_bound
5679 static const unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
5682 PUSHB_1,
5683 bci_action_serif_anchor_lower_bound,
5684 FDEF,
5686 PUSHB_2,
5688 bci_serif_anchor_common,
5689 CALL,
5691 PUSHB_1,
5692 bci_lower_bound,
5693 CALL,
5695 ENDF,
5701 * bci_action_serif_anchor_upper_bound
5703 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5704 * anchor, then moving it again if necessary to stay within an upper
5705 * bound.
5707 * in: edge_point (in twilight zone)
5708 * edge[1] (in twilight zone)
5709 * ... stuff for bci_align_segments (edge) ...
5711 * uses: bci_serif_anchor_common
5712 * bci_upper_bound
5715 static const unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5718 PUSHB_1,
5719 bci_action_serif_anchor_upper_bound,
5720 FDEF,
5722 PUSHB_2,
5724 bci_serif_anchor_common,
5725 CALL,
5727 PUSHB_1,
5728 bci_upper_bound,
5729 CALL,
5731 ENDF,
5737 * bci_action_serif_anchor_upper_lower_bound
5739 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5740 * anchor, then moving it again if necessary to stay within a lower and
5741 * upper bound.
5743 * in: edge_point (in twilight zone)
5744 * edge[-1] (in twilight zone)
5745 * edge[1] (in twilight zone)
5746 * ... stuff for bci_align_segments (edge) ...
5748 * uses: bci_serif_anchor_common
5749 * bci_upper_lower_bound
5752 static const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5755 PUSHB_1,
5756 bci_action_serif_anchor_upper_lower_bound,
5757 FDEF,
5759 PUSHB_2,
5761 bci_serif_anchor_common,
5762 CALL,
5764 PUSHB_1,
5765 bci_upper_lower_bound,
5766 CALL,
5768 ENDF,
5774 * bci_action_serif_anchor_down_lower_bound
5776 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5777 * anchor, then moving it again if necessary to stay within a lower
5778 * bound. We hint top to bottom.
5780 * in: edge_point (in twilight zone)
5781 * edge[-1] (in twilight zone)
5782 * ... stuff for bci_align_segments (edge) ...
5784 * uses: bci_serif_anchor_common
5785 * bci_lower_bound
5788 static const unsigned char FPGM(bci_action_serif_anchor_down_lower_bound) [] =
5791 PUSHB_1,
5792 bci_action_serif_anchor_down_lower_bound,
5793 FDEF,
5795 PUSHB_2,
5797 bci_serif_anchor_common,
5798 CALL,
5800 PUSHB_1,
5801 bci_lower_bound,
5802 CALL,
5804 ENDF,
5810 * bci_action_serif_anchor_down_upper_bound
5812 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5813 * anchor, then moving it again if necessary to stay within an upper
5814 * bound. We hint top to bottom.
5816 * in: edge_point (in twilight zone)
5817 * edge[1] (in twilight zone)
5818 * ... stuff for bci_align_segments (edge) ...
5820 * uses: bci_serif_anchor_common
5821 * bci_upper_bound
5824 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_bound) [] =
5827 PUSHB_1,
5828 bci_action_serif_anchor_down_upper_bound,
5829 FDEF,
5831 PUSHB_2,
5833 bci_serif_anchor_common,
5834 CALL,
5836 PUSHB_1,
5837 bci_upper_bound,
5838 CALL,
5840 ENDF,
5846 * bci_action_serif_anchor_down_upper_lower_bound
5848 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5849 * anchor, then moving it again if necessary to stay within a lower and
5850 * upper bound. We hint top to bottom.
5852 * in: edge_point (in twilight zone)
5853 * edge[-1] (in twilight zone)
5854 * edge[1] (in twilight zone)
5855 * ... stuff for bci_align_segments (edge) ...
5857 * uses: bci_serif_anchor_common
5858 * bci_upper_lower_bound
5861 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_lower_bound) [] =
5864 PUSHB_1,
5865 bci_action_serif_anchor_down_upper_lower_bound,
5866 FDEF,
5868 PUSHB_2,
5870 bci_serif_anchor_common,
5871 CALL,
5873 PUSHB_1,
5874 bci_upper_lower_bound,
5875 CALL,
5877 ENDF,
5883 * bci_serif_link1_common
5885 * Common code for bci_action_serif_link1 routines.
5887 * in: top_to_bottom_hinting
5888 * before
5889 * edge
5890 * after
5892 * out: edge (adjusted)
5894 * sal: sal_top_to_bottom_hinting
5898 static const unsigned char FPGM(bci_serif_link1_common) [] =
5901 PUSHB_1,
5902 bci_serif_link1_common,
5903 FDEF,
5905 PUSHB_1,
5907 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5909 PUSHB_1,
5910 sal_top_to_bottom_hinting,
5911 SWAP,
5914 PUSHB_1,
5916 CINDEX, /* s: [...] after edge before after */
5917 PUSHB_1,
5919 CINDEX, /* s: [...] after edge before after before */
5920 MD_orig_ZP2_0,
5921 PUSHB_1,
5923 EQ, /* after_orig_pos == before_orig_pos */
5924 IF, /* s: [...] after edge before */
5925 MDAP_noround, /* set rp0 and rp1 to `before' */
5926 DUP,
5927 ALIGNRP, /* align `edge' with `before' */
5928 SWAP,
5929 POP,
5931 ELSE,
5932 /* we have to execute `a*b/c', with b/c very near to 1: */
5933 /* to avoid overflow while retaining precision, */
5934 /* we transform this to `a + a * (b-c)/c' */
5936 PUSHB_1,
5938 CINDEX, /* s: [...] after edge before edge */
5939 PUSHB_1,
5941 CINDEX, /* s: [...] after edge before edge before */
5942 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
5944 DUP,
5945 PUSHB_1,
5947 CINDEX, /* s: [...] after edge before a a after */
5948 PUSHB_1,
5950 CINDEX, /* s: [...] after edge before a a after before */
5951 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
5953 PUSHB_1,
5955 CINDEX, /* s: [...] after edge before a a c after */
5956 PUSHB_1,
5958 CINDEX, /* s: [...] after edge before a a c after before */
5959 MD_cur, /* b = after_pos - before_pos */
5961 PUSHB_1,
5963 CINDEX, /* s: [...] after edge before a a c b c */
5964 SUB, /* b-c */
5966 PUSHW_2,
5967 0x08, /* 0x800 */
5968 0x00,
5969 0x08, /* 0x800 */
5970 0x00,
5971 MUL, /* 0x10000 */
5972 MUL, /* (b-c) in 16.16 format */
5973 SWAP,
5975 DUP,
5976 IF, /* c != 0 ? */
5977 DIV, /* s: [...] after edge before a a (b-c)/c */
5978 ELSE,
5979 POP, /* avoid division by zero */
5980 EIF,
5982 MUL, /* a * (b-c)/c * 2^10 */
5983 DIV_BY_1024, /* a * (b-c)/c */
5984 ADD, /* a*b/c */
5986 SWAP,
5987 MDAP_noround, /* set rp0 and rp1 to `before' */
5988 SWAP, /* s: [...] after a*b/c edge */
5989 DUP,
5990 DUP,
5991 ALIGNRP, /* align `edge' with `before' */
5992 ROLL,
5993 SHPIX, /* shift `edge' by `a*b/c' */
5995 SWAP, /* s: [...] edge after */
5996 POP,
5997 EIF,
5999 ENDF,
6005 * bci_action_serif_link1
6007 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6008 * before and after.
6010 * in: before_point (in twilight zone)
6011 * edge_point (in twilight zone)
6012 * after_point (in twilight zone)
6013 * ... stuff for bci_align_segments (edge) ...
6015 * uses: bci_serif_link1_common
6016 * bci_align_segments
6019 static const unsigned char FPGM(bci_action_serif_link1) [] =
6022 PUSHB_1,
6023 bci_action_serif_link1,
6024 FDEF,
6026 PUSHB_2,
6028 bci_serif_link1_common,
6029 CALL,
6031 MDAP_noround, /* set rp0 and rp1 to `edge' */
6033 PUSHB_2,
6034 bci_align_segments,
6036 SZP1, /* set zp1 to normal zone 1 */
6037 CALL,
6039 ENDF,
6045 * bci_action_serif_link1_lower_bound
6047 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6048 * before and after. Additionally, move the serif again if necessary to
6049 * stay within a lower bound.
6051 * in: before_point (in twilight zone)
6052 * edge_point (in twilight zone)
6053 * after_point (in twilight zone)
6054 * edge[-1] (in twilight zone)
6055 * ... stuff for bci_align_segments (edge) ...
6057 * uses: bci_serif_link1_common
6058 * bci_lower_bound
6061 static const unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
6064 PUSHB_1,
6065 bci_action_serif_link1_lower_bound,
6066 FDEF,
6068 PUSHB_2,
6070 bci_serif_link1_common,
6071 CALL,
6073 PUSHB_1,
6074 bci_lower_bound,
6075 CALL,
6077 ENDF,
6083 * bci_action_serif_link1_upper_bound
6085 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6086 * before and after. Additionally, move the serif again if necessary to
6087 * stay within an upper bound.
6089 * in: before_point (in twilight zone)
6090 * edge_point (in twilight zone)
6091 * after_point (in twilight zone)
6092 * edge[1] (in twilight zone)
6093 * ... stuff for bci_align_segments (edge) ...
6095 * uses: bci_serif_link1_common
6096 * bci_upper_bound
6099 static const unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
6102 PUSHB_1,
6103 bci_action_serif_link1_upper_bound,
6104 FDEF,
6106 PUSHB_2,
6108 bci_serif_link1_common,
6109 CALL,
6111 PUSHB_1,
6112 bci_upper_bound,
6113 CALL,
6115 ENDF,
6121 * bci_action_serif_link1_upper_lower_bound
6123 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6124 * before and after. Additionally, move the serif again if necessary to
6125 * stay within a lower and upper bound.
6127 * in: before_point (in twilight zone)
6128 * edge_point (in twilight zone)
6129 * after_point (in twilight zone)
6130 * edge[-1] (in twilight zone)
6131 * edge[1] (in twilight zone)
6132 * ... stuff for bci_align_segments (edge) ...
6134 * uses: bci_serif_link1_common
6135 * bci_upper_lower_bound
6138 static const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
6141 PUSHB_1,
6142 bci_action_serif_link1_upper_lower_bound,
6143 FDEF,
6145 PUSHB_2,
6147 bci_serif_link1_common,
6148 CALL,
6150 PUSHB_1,
6151 bci_upper_lower_bound,
6152 CALL,
6154 ENDF,
6160 * bci_action_serif_link1_down_lower_bound
6162 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6163 * before and after. Additionally, move the serif again if necessary to
6164 * stay within a lower bound. We hint top to bottom.
6166 * in: before_point (in twilight zone)
6167 * edge_point (in twilight zone)
6168 * after_point (in twilight zone)
6169 * edge[-1] (in twilight zone)
6170 * ... stuff for bci_align_segments (edge) ...
6172 * uses: bci_serif_link1_common
6173 * bci_lower_bound
6176 static const unsigned char FPGM(bci_action_serif_link1_down_lower_bound) [] =
6179 PUSHB_1,
6180 bci_action_serif_link1_down_lower_bound,
6181 FDEF,
6183 PUSHB_2,
6185 bci_serif_link1_common,
6186 CALL,
6188 PUSHB_1,
6189 bci_lower_bound,
6190 CALL,
6192 ENDF,
6198 * bci_action_serif_link1_down_upper_bound
6200 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6201 * before and after. Additionally, move the serif again if necessary to
6202 * stay within an upper bound. We hint top to bottom.
6204 * in: before_point (in twilight zone)
6205 * edge_point (in twilight zone)
6206 * after_point (in twilight zone)
6207 * edge[1] (in twilight zone)
6208 * ... stuff for bci_align_segments (edge) ...
6210 * uses: bci_serif_link1_common
6211 * bci_upper_bound
6214 static const unsigned char FPGM(bci_action_serif_link1_down_upper_bound) [] =
6217 PUSHB_1,
6218 bci_action_serif_link1_down_upper_bound,
6219 FDEF,
6221 PUSHB_2,
6223 bci_serif_link1_common,
6224 CALL,
6226 PUSHB_1,
6227 bci_upper_bound,
6228 CALL,
6230 ENDF,
6236 * bci_action_serif_link1_down_upper_lower_bound
6238 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6239 * before and after. Additionally, move the serif again if necessary to
6240 * stay within a lower and upper bound. We hint top to bottom.
6242 * in: before_point (in twilight zone)
6243 * edge_point (in twilight zone)
6244 * after_point (in twilight zone)
6245 * edge[-1] (in twilight zone)
6246 * edge[1] (in twilight zone)
6247 * ... stuff for bci_align_segments (edge) ...
6249 * uses: bci_serif_link1_common
6250 * bci_upper_lower_bound
6253 static const unsigned char FPGM(bci_action_serif_link1_down_upper_lower_bound) [] =
6256 PUSHB_1,
6257 bci_action_serif_link1_down_upper_lower_bound,
6258 FDEF,
6260 PUSHB_2,
6262 bci_serif_link1_common,
6263 CALL,
6265 PUSHB_1,
6266 bci_upper_lower_bound,
6267 CALL,
6269 ENDF,
6275 * bci_serif_link2_common
6277 * Common code for bci_action_serif_link2 routines.
6279 * in: top_to_bottom_hinting
6280 * edge
6282 * out: edge (adjusted)
6284 * sal: sal_anchor
6285 * sal_top_to_bottom_hinting
6289 static const unsigned char FPGM(bci_serif_link2_common) [] =
6292 PUSHB_1,
6293 bci_serif_link2_common,
6294 FDEF,
6296 PUSHB_1,
6298 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6300 PUSHB_1,
6301 sal_top_to_bottom_hinting,
6302 SWAP,
6305 DUP, /* s: [...] edge edge */
6306 PUSHB_1,
6307 sal_anchor,
6309 DUP, /* s: [...] edge edge anchor anchor */
6310 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
6312 MD_orig_ZP2_0,
6313 DUP,
6314 ADD,
6315 PUSHB_1,
6317 ADD,
6318 FLOOR,
6319 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
6321 SWAP,
6322 DUP,
6323 DUP,
6324 ALIGNRP, /* align `edge' with `sal_anchor' */
6325 ROLL,
6326 SHPIX, /* shift `edge' by `delta' */
6328 ENDF,
6334 * bci_action_serif_link2
6336 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6338 * in: edge_point (in twilight zone)
6339 * ... stuff for bci_align_segments (edge) ...
6341 * uses: bci_serif_link2_common
6342 * bci_align_segments
6345 static const unsigned char FPGM(bci_action_serif_link2) [] =
6348 PUSHB_1,
6349 bci_action_serif_link2,
6350 FDEF,
6352 PUSHB_2,
6354 bci_serif_link2_common,
6355 CALL,
6357 MDAP_noround, /* set rp0 and rp1 to `edge' */
6359 PUSHB_2,
6360 bci_align_segments,
6362 SZP1, /* set zp1 to normal zone 1 */
6363 CALL,
6365 ENDF,
6371 * bci_action_serif_link2_lower_bound
6373 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6374 * Additionally, move the serif again if necessary to stay within a lower
6375 * bound.
6377 * in: edge_point (in twilight zone)
6378 * edge[-1] (in twilight zone)
6379 * ... stuff for bci_align_segments (edge) ...
6381 * uses: bci_serif_link2_common
6382 * bci_lower_bound
6385 static const unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
6388 PUSHB_1,
6389 bci_action_serif_link2_lower_bound,
6390 FDEF,
6392 PUSHB_2,
6394 bci_serif_link2_common,
6395 CALL,
6397 PUSHB_1,
6398 bci_lower_bound,
6399 CALL,
6401 ENDF,
6407 * bci_action_serif_link2_upper_bound
6409 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6410 * Additionally, move the serif again if necessary to stay within an upper
6411 * bound.
6413 * in: edge_point (in twilight zone)
6414 * edge[1] (in twilight zone)
6415 * ... stuff for bci_align_segments (edge) ...
6417 * uses: bci_serif_link2_common
6418 * bci_upper_bound
6421 static const unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
6424 PUSHB_1,
6425 bci_action_serif_link2_upper_bound,
6426 FDEF,
6428 PUSHB_2,
6430 bci_serif_link2_common,
6431 CALL,
6433 PUSHB_1,
6434 bci_upper_bound,
6435 CALL,
6437 ENDF,
6443 * bci_action_serif_link2_upper_lower_bound
6445 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6446 * Additionally, move the serif again if necessary to stay within a lower
6447 * and upper bound.
6449 * in: edge_point (in twilight zone)
6450 * edge[-1] (in twilight zone)
6451 * edge[1] (in twilight zone)
6452 * ... stuff for bci_align_segments (edge) ...
6454 * uses: bci_serif_link2_common
6455 * bci_upper_lower_bound
6458 static const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
6461 PUSHB_1,
6462 bci_action_serif_link2_upper_lower_bound,
6463 FDEF,
6465 PUSHB_2,
6467 bci_serif_link2_common,
6468 CALL,
6470 PUSHB_1,
6471 bci_upper_lower_bound,
6472 CALL,
6474 ENDF,
6480 * bci_action_serif_link2_down_lower_bound
6482 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6483 * Additionally, move the serif again if necessary to stay within a lower
6484 * bound. We hint top to bottom.
6486 * in: edge_point (in twilight zone)
6487 * edge[-1] (in twilight zone)
6488 * ... stuff for bci_align_segments (edge) ...
6490 * uses: bci_serif_link2_common
6491 * bci_lower_bound
6494 static const unsigned char FPGM(bci_action_serif_link2_down_lower_bound) [] =
6497 PUSHB_1,
6498 bci_action_serif_link2_down_lower_bound,
6499 FDEF,
6501 PUSHB_2,
6503 bci_serif_link2_common,
6504 CALL,
6506 PUSHB_1,
6507 bci_lower_bound,
6508 CALL,
6510 ENDF,
6516 * bci_action_serif_link2_down_upper_bound
6518 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6519 * Additionally, move the serif again if necessary to stay within an upper
6520 * bound. We hint top to bottom.
6522 * in: edge_point (in twilight zone)
6523 * edge[1] (in twilight zone)
6524 * ... stuff for bci_align_segments (edge) ...
6526 * uses: bci_serif_link2_common
6527 * bci_upper_bound
6530 static const unsigned char FPGM(bci_action_serif_link2_down_upper_bound) [] =
6533 PUSHB_1,
6534 bci_action_serif_link2_down_upper_bound,
6535 FDEF,
6537 PUSHB_2,
6539 bci_serif_link2_common,
6540 CALL,
6542 PUSHB_1,
6543 bci_upper_bound,
6544 CALL,
6546 ENDF,
6552 * bci_action_serif_link2_down_upper_lower_bound
6554 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6555 * Additionally, move the serif again if necessary to stay within a lower
6556 * and upper bound. We hint top to bottom.
6558 * in: edge_point (in twilight zone)
6559 * edge[-1] (in twilight zone)
6560 * edge[1] (in twilight zone)
6561 * ... stuff for bci_align_segments (edge) ...
6563 * uses: bci_serif_link2_common
6564 * bci_upper_lower_bound
6567 static const unsigned char FPGM(bci_action_serif_link2_down_upper_lower_bound) [] =
6570 PUSHB_1,
6571 bci_action_serif_link2_down_upper_lower_bound,
6572 FDEF,
6574 PUSHB_2,
6576 bci_serif_link2_common,
6577 CALL,
6579 PUSHB_1,
6580 bci_upper_lower_bound,
6581 CALL,
6583 ENDF,
6589 * bci_hint_glyph
6591 * This is the top-level glyph hinting function which parses the arguments
6592 * on the stack and calls subroutines.
6594 * in: action_0_func_idx
6595 * ... data ...
6596 * action_1_func_idx
6597 * ... data ...
6598 * ...
6600 * CVT: cvtl_is_subglyph
6601 * cvtl_use_strong_functions
6602 * cvtl_do_iup_y
6604 * sal: sal_stem_width_function
6606 * uses: bci_action_ip_before
6607 * bci_action_ip_after
6608 * bci_action_ip_on
6609 * bci_action_ip_between
6611 * bci_action_adjust_bound
6612 * bci_action_adjust_bound_serif
6613 * bci_action_adjust_bound_round
6614 * bci_action_adjust_bound_round_serif
6616 * bci_action_stem_bound
6617 * bci_action_stem_bound_serif
6618 * bci_action_stem_bound_round
6619 * bci_action_stem_bound_round_serif
6621 * bci_action_link
6622 * bci_action_link_serif
6623 * bci_action_link_round
6624 * bci_action_link_round_serif
6626 * bci_action_anchor
6627 * bci_action_anchor_serif
6628 * bci_action_anchor_round
6629 * bci_action_anchor_round_serif
6631 * bci_action_blue_anchor
6633 * bci_action_adjust
6634 * bci_action_adjust_serif
6635 * bci_action_adjust_round
6636 * bci_action_adjust_round_serif
6638 * bci_action_stem
6639 * bci_action_stem_serif
6640 * bci_action_stem_round
6641 * bci_action_stem_round_serif
6643 * bci_action_blue
6645 * bci_action_serif
6646 * bci_action_serif_lower_bound
6647 * bci_action_serif_upper_bound
6648 * bci_action_serif_upper_lower_bound
6650 * bci_action_serif_anchor
6651 * bci_action_serif_anchor_lower_bound
6652 * bci_action_serif_anchor_upper_bound
6653 * bci_action_serif_anchor_upper_lower_bound
6655 * bci_action_serif_link1
6656 * bci_action_serif_link1_lower_bound
6657 * bci_action_serif_link1_upper_bound
6658 * bci_action_serif_link1_upper_lower_bound
6660 * bci_action_serif_link2
6661 * bci_action_serif_link2_lower_bound
6662 * bci_action_serif_link2_upper_bound
6663 * bci_action_serif_link2_upper_lower_bound
6666 static const unsigned char FPGM(bci_hint_glyph) [] =
6669 PUSHB_1,
6670 bci_hint_glyph,
6671 FDEF,
6673 /* set up stem width function based on flag in CVT */
6674 PUSHB_4,
6675 sal_stem_width_function,
6676 bci_strong_stem_width,
6677 bci_smooth_stem_width,
6678 cvtl_use_strong_functions,
6679 RCVT,
6681 POP,
6683 ELSE,
6684 SWAP,
6685 POP,
6687 EIF,
6690 /* start_loop: */
6691 /* loop until all data on stack is used */
6692 CALL,
6693 PUSHB_1,
6695 NEG,
6696 PUSHB_1,
6698 DEPTH,
6700 JROT, /* goto start_loop */
6702 PUSHB_2,
6703 cvtl_do_iup_y,
6705 SZP2, /* set zp2 to normal zone 1 */
6706 RCVT,
6708 IUP_y,
6709 EIF,
6711 ENDF,
6716 #define COPY_FPGM(func_name) \
6717 do \
6719 memcpy(bufp, fpgm_ ## func_name, \
6720 sizeof (fpgm_ ## func_name)); \
6721 bufp += sizeof (fpgm_ ## func_name); \
6722 } while (0)
6724 static FT_Error
6725 TA_table_build_fpgm(FT_Byte** fpgm,
6726 FT_ULong* fpgm_len,
6727 SFNT* sfnt,
6728 FONT* font)
6730 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6731 glyf_Data* data = (glyf_Data*)glyf_table->data;
6733 unsigned char num_used_styles = (unsigned char)data->num_used_styles;
6734 unsigned char fallback_style =
6735 CVT_SCALING_VALUE_OFFSET(0)
6736 + (unsigned char)data->style_ids[font->fallback_style];
6738 FT_UInt buf_len;
6739 FT_UInt len;
6740 FT_Byte* buf;
6741 FT_Byte* bufp;
6744 /* for compatibility with dumb bytecode interpreters or analyzers, */
6745 /* FDEFs are stored in ascending index order, without holes -- */
6746 /* note that some FDEFs are not always needed */
6747 /* (depending on options of `TTFautohint'), */
6748 /* but implementing dynamic FDEF indices would be a lot of work */
6750 buf_len = sizeof (FPGM(bci_align_x_height_a))
6751 + (font->increase_x_height
6752 ? (sizeof (FPGM(bci_align_x_height_b1a))
6754 + sizeof (FPGM(bci_align_x_height_b1b)))
6755 : sizeof (FPGM(bci_align_x_height_b2)))
6756 + sizeof (FPGM(bci_align_x_height_c))
6757 + sizeof (FPGM(bci_round))
6758 + sizeof (FPGM(bci_smooth_stem_width))
6759 + sizeof (FPGM(bci_get_best_width))
6760 + sizeof (FPGM(bci_strong_stem_width_a))
6762 + sizeof (FPGM(bci_strong_stem_width_b))
6763 + sizeof (FPGM(bci_loop_do))
6764 + sizeof (FPGM(bci_loop))
6765 + sizeof (FPGM(bci_cvt_rescale))
6766 + sizeof (FPGM(bci_cvt_rescale_range))
6767 + sizeof (FPGM(bci_vwidth_data_store))
6768 + sizeof (FPGM(bci_smooth_blue_round))
6769 + sizeof (FPGM(bci_strong_blue_round))
6770 + sizeof (FPGM(bci_blue_round_range))
6771 + sizeof (FPGM(bci_decrement_component_counter))
6772 + sizeof (FPGM(bci_get_point_extrema))
6773 + sizeof (FPGM(bci_nibbles))
6774 + sizeof (FPGM(bci_number_set_is_element))
6775 + sizeof (FPGM(bci_number_set_is_element2))
6777 + sizeof (FPGM(bci_create_segment))
6778 + sizeof (FPGM(bci_create_segments_a))
6780 + sizeof (FPGM(bci_create_segments_b))
6781 + (font->control_data_head != 0
6782 ? sizeof (FPGM(bci_create_segments_c))
6783 : 0)
6784 + sizeof (FPGM(bci_create_segments_d))
6786 + sizeof (FPGM(bci_create_segments_0))
6787 + sizeof (FPGM(bci_create_segments_1))
6788 + sizeof (FPGM(bci_create_segments_2))
6789 + sizeof (FPGM(bci_create_segments_3))
6790 + sizeof (FPGM(bci_create_segments_4))
6791 + sizeof (FPGM(bci_create_segments_5))
6792 + sizeof (FPGM(bci_create_segments_6))
6793 + sizeof (FPGM(bci_create_segments_7))
6794 + sizeof (FPGM(bci_create_segments_8))
6795 + sizeof (FPGM(bci_create_segments_9))
6797 + sizeof (FPGM(bci_deltap1))
6798 + sizeof (FPGM(bci_deltap2))
6799 + sizeof (FPGM(bci_deltap3))
6801 + sizeof (FPGM(bci_create_segments_composite_a))
6803 + sizeof (FPGM(bci_create_segments_composite_b))
6804 + (font->control_data_head != 0
6805 ? sizeof (FPGM(bci_create_segments_composite_c))
6806 : 0)
6807 + sizeof (FPGM(bci_create_segments_composite_d))
6809 + sizeof (FPGM(bci_create_segments_composite_0))
6810 + sizeof (FPGM(bci_create_segments_composite_1))
6811 + sizeof (FPGM(bci_create_segments_composite_2))
6812 + sizeof (FPGM(bci_create_segments_composite_3))
6813 + sizeof (FPGM(bci_create_segments_composite_4))
6814 + sizeof (FPGM(bci_create_segments_composite_5))
6815 + sizeof (FPGM(bci_create_segments_composite_6))
6816 + sizeof (FPGM(bci_create_segments_composite_7))
6817 + sizeof (FPGM(bci_create_segments_composite_8))
6818 + sizeof (FPGM(bci_create_segments_composite_9))
6820 + sizeof (FPGM(bci_align_point))
6821 + sizeof (FPGM(bci_align_segment))
6822 + sizeof (FPGM(bci_align_segments))
6824 + sizeof (FPGM(bci_scale_contour))
6825 + sizeof (FPGM(bci_scale_glyph_a))
6827 + sizeof (FPGM(bci_scale_glyph_b))
6828 + sizeof (FPGM(bci_scale_composite_glyph_a))
6830 + sizeof (FPGM(bci_scale_composite_glyph_b))
6831 + sizeof (FPGM(bci_shift_contour))
6832 + sizeof (FPGM(bci_shift_subglyph_a))
6834 + sizeof (FPGM(bci_shift_subglyph_b))
6835 + (font->control_data_head != 0
6836 ? sizeof (FPGM(bci_shift_subglyph_c))
6837 : 0)
6838 + sizeof (FPGM(bci_shift_subglyph_d))
6840 + sizeof (FPGM(bci_ip_outer_align_point))
6841 + sizeof (FPGM(bci_ip_on_align_points))
6842 + sizeof (FPGM(bci_ip_between_align_point))
6843 + sizeof (FPGM(bci_ip_between_align_points))
6845 + sizeof (FPGM(bci_adjust_common))
6846 + sizeof (FPGM(bci_stem_common))
6847 + sizeof (FPGM(bci_serif_common))
6848 + sizeof (FPGM(bci_serif_anchor_common))
6849 + sizeof (FPGM(bci_serif_link1_common))
6850 + sizeof (FPGM(bci_serif_link2_common))
6852 + sizeof (FPGM(bci_lower_bound))
6853 + sizeof (FPGM(bci_upper_bound))
6854 + sizeof (FPGM(bci_upper_lower_bound))
6856 + sizeof (FPGM(bci_adjust_bound))
6857 + sizeof (FPGM(bci_stem_bound))
6858 + sizeof (FPGM(bci_link))
6859 + sizeof (FPGM(bci_anchor))
6860 + sizeof (FPGM(bci_adjust))
6861 + sizeof (FPGM(bci_stem))
6863 + sizeof (FPGM(bci_action_ip_before))
6864 + sizeof (FPGM(bci_action_ip_after))
6865 + sizeof (FPGM(bci_action_ip_on))
6866 + sizeof (FPGM(bci_action_ip_between))
6868 + sizeof (FPGM(bci_action_blue))
6869 + sizeof (FPGM(bci_action_blue_anchor))
6871 + sizeof (FPGM(bci_action_anchor))
6872 + sizeof (FPGM(bci_action_anchor_serif))
6873 + sizeof (FPGM(bci_action_anchor_round))
6874 + sizeof (FPGM(bci_action_anchor_round_serif))
6876 + sizeof (FPGM(bci_action_adjust))
6877 + sizeof (FPGM(bci_action_adjust_serif))
6878 + sizeof (FPGM(bci_action_adjust_round))
6879 + sizeof (FPGM(bci_action_adjust_round_serif))
6880 + sizeof (FPGM(bci_action_adjust_bound))
6881 + sizeof (FPGM(bci_action_adjust_bound_serif))
6882 + sizeof (FPGM(bci_action_adjust_bound_round))
6883 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
6884 + sizeof (FPGM(bci_action_adjust_down_bound))
6885 + sizeof (FPGM(bci_action_adjust_down_bound_serif))
6886 + sizeof (FPGM(bci_action_adjust_down_bound_round))
6887 + sizeof (FPGM(bci_action_adjust_down_bound_round_serif))
6889 + sizeof (FPGM(bci_action_link))
6890 + sizeof (FPGM(bci_action_link_serif))
6891 + sizeof (FPGM(bci_action_link_round))
6892 + sizeof (FPGM(bci_action_link_round_serif))
6894 + sizeof (FPGM(bci_action_stem))
6895 + sizeof (FPGM(bci_action_stem_serif))
6896 + sizeof (FPGM(bci_action_stem_round))
6897 + sizeof (FPGM(bci_action_stem_round_serif))
6898 + sizeof (FPGM(bci_action_stem_bound))
6899 + sizeof (FPGM(bci_action_stem_bound_serif))
6900 + sizeof (FPGM(bci_action_stem_bound_round))
6901 + sizeof (FPGM(bci_action_stem_bound_round_serif))
6902 + sizeof (FPGM(bci_action_stem_down_bound))
6903 + sizeof (FPGM(bci_action_stem_down_bound_serif))
6904 + sizeof (FPGM(bci_action_stem_down_bound_round))
6905 + sizeof (FPGM(bci_action_stem_down_bound_round_serif))
6907 + sizeof (FPGM(bci_action_serif))
6908 + sizeof (FPGM(bci_action_serif_lower_bound))
6909 + sizeof (FPGM(bci_action_serif_upper_bound))
6910 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
6911 + sizeof (FPGM(bci_action_serif_down_lower_bound))
6912 + sizeof (FPGM(bci_action_serif_down_upper_bound))
6913 + sizeof (FPGM(bci_action_serif_down_upper_lower_bound))
6915 + sizeof (FPGM(bci_action_serif_anchor))
6916 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
6917 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
6918 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
6919 + sizeof (FPGM(bci_action_serif_anchor_down_lower_bound))
6920 + sizeof (FPGM(bci_action_serif_anchor_down_upper_bound))
6921 + sizeof (FPGM(bci_action_serif_anchor_down_upper_lower_bound))
6923 + sizeof (FPGM(bci_action_serif_link1))
6924 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
6925 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
6926 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
6927 + sizeof (FPGM(bci_action_serif_link1_down_lower_bound))
6928 + sizeof (FPGM(bci_action_serif_link1_down_upper_bound))
6929 + sizeof (FPGM(bci_action_serif_link1_down_upper_lower_bound))
6931 + sizeof (FPGM(bci_action_serif_link2))
6932 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
6933 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
6934 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
6935 + sizeof (FPGM(bci_action_serif_link2_down_lower_bound))
6936 + sizeof (FPGM(bci_action_serif_link2_down_upper_bound))
6937 + sizeof (FPGM(bci_action_serif_link2_down_upper_lower_bound))
6939 + sizeof (FPGM(bci_hint_glyph));
6941 /* buffer length must be a multiple of four */
6942 len = (buf_len + 3) & ~3U;
6943 buf = (FT_Byte*)malloc(len);
6944 if (!buf)
6945 return FT_Err_Out_Of_Memory;
6947 /* pad end of buffer with zeros */
6948 buf[len - 1] = 0x00;
6949 buf[len - 2] = 0x00;
6950 buf[len - 3] = 0x00;
6952 /* copy font program into buffer and fill in the missing variables */
6953 bufp = buf;
6955 COPY_FPGM(bci_align_x_height_a);
6956 if (font->increase_x_height)
6958 COPY_FPGM(bci_align_x_height_b1a);
6959 *(bufp++) = HIGH(font->increase_x_height);
6960 *(bufp++) = LOW(font->increase_x_height);
6961 COPY_FPGM(bci_align_x_height_b1b);
6963 else
6964 COPY_FPGM(bci_align_x_height_b2);
6965 COPY_FPGM(bci_align_x_height_c);
6967 COPY_FPGM(bci_round);
6968 COPY_FPGM(bci_smooth_stem_width);
6969 COPY_FPGM(bci_get_best_width);
6970 COPY_FPGM(bci_strong_stem_width_a);
6971 *(bufp++) = num_used_styles;
6972 COPY_FPGM(bci_strong_stem_width_b);
6973 COPY_FPGM(bci_loop_do);
6974 COPY_FPGM(bci_loop);
6975 COPY_FPGM(bci_cvt_rescale);
6976 COPY_FPGM(bci_cvt_rescale_range);
6977 COPY_FPGM(bci_vwidth_data_store);
6978 COPY_FPGM(bci_smooth_blue_round);
6979 COPY_FPGM(bci_strong_blue_round);
6980 COPY_FPGM(bci_blue_round_range);
6981 COPY_FPGM(bci_decrement_component_counter);
6982 COPY_FPGM(bci_get_point_extrema);
6983 COPY_FPGM(bci_nibbles);
6984 COPY_FPGM(bci_number_set_is_element);
6985 COPY_FPGM(bci_number_set_is_element2);
6987 COPY_FPGM(bci_create_segment);
6988 COPY_FPGM(bci_create_segments_a);
6989 *(bufp++) = num_used_styles;
6990 COPY_FPGM(bci_create_segments_b);
6991 if (font->control_data_head)
6992 COPY_FPGM(bci_create_segments_c);
6993 COPY_FPGM(bci_create_segments_d);
6995 COPY_FPGM(bci_create_segments_0);
6996 COPY_FPGM(bci_create_segments_1);
6997 COPY_FPGM(bci_create_segments_2);
6998 COPY_FPGM(bci_create_segments_3);
6999 COPY_FPGM(bci_create_segments_4);
7000 COPY_FPGM(bci_create_segments_5);
7001 COPY_FPGM(bci_create_segments_6);
7002 COPY_FPGM(bci_create_segments_7);
7003 COPY_FPGM(bci_create_segments_8);
7004 COPY_FPGM(bci_create_segments_9);
7006 COPY_FPGM(bci_deltap1);
7007 COPY_FPGM(bci_deltap2);
7008 COPY_FPGM(bci_deltap3);
7010 COPY_FPGM(bci_create_segments_composite_a);
7011 *(bufp++) = num_used_styles;
7012 COPY_FPGM(bci_create_segments_composite_b);
7013 if (font->control_data_head)
7014 COPY_FPGM(bci_create_segments_composite_c);
7015 COPY_FPGM(bci_create_segments_composite_d);
7017 COPY_FPGM(bci_create_segments_composite_0);
7018 COPY_FPGM(bci_create_segments_composite_1);
7019 COPY_FPGM(bci_create_segments_composite_2);
7020 COPY_FPGM(bci_create_segments_composite_3);
7021 COPY_FPGM(bci_create_segments_composite_4);
7022 COPY_FPGM(bci_create_segments_composite_5);
7023 COPY_FPGM(bci_create_segments_composite_6);
7024 COPY_FPGM(bci_create_segments_composite_7);
7025 COPY_FPGM(bci_create_segments_composite_8);
7026 COPY_FPGM(bci_create_segments_composite_9);
7028 COPY_FPGM(bci_align_point);
7029 COPY_FPGM(bci_align_segment);
7030 COPY_FPGM(bci_align_segments);
7032 COPY_FPGM(bci_scale_contour);
7033 COPY_FPGM(bci_scale_glyph_a);
7034 *(bufp++) = fallback_style;
7035 COPY_FPGM(bci_scale_glyph_b);
7036 COPY_FPGM(bci_scale_composite_glyph_a);
7037 *(bufp++) = fallback_style;
7038 COPY_FPGM(bci_scale_composite_glyph_b);
7039 COPY_FPGM(bci_shift_contour);
7040 COPY_FPGM(bci_shift_subglyph_a);
7041 *(bufp++) = fallback_style;
7042 COPY_FPGM(bci_shift_subglyph_b);
7043 if (font->control_data_head)
7044 COPY_FPGM(bci_shift_subglyph_c);
7045 COPY_FPGM(bci_shift_subglyph_d);
7047 COPY_FPGM(bci_ip_outer_align_point);
7048 COPY_FPGM(bci_ip_on_align_points);
7049 COPY_FPGM(bci_ip_between_align_point);
7050 COPY_FPGM(bci_ip_between_align_points);
7052 COPY_FPGM(bci_adjust_common);
7053 COPY_FPGM(bci_stem_common);
7054 COPY_FPGM(bci_serif_common);
7055 COPY_FPGM(bci_serif_anchor_common);
7056 COPY_FPGM(bci_serif_link1_common);
7057 COPY_FPGM(bci_serif_link2_common);
7059 COPY_FPGM(bci_lower_bound);
7060 COPY_FPGM(bci_upper_bound);
7061 COPY_FPGM(bci_upper_lower_bound);
7063 COPY_FPGM(bci_adjust_bound);
7064 COPY_FPGM(bci_stem_bound);
7065 COPY_FPGM(bci_link);
7066 COPY_FPGM(bci_anchor);
7067 COPY_FPGM(bci_adjust);
7068 COPY_FPGM(bci_stem);
7070 COPY_FPGM(bci_action_ip_before);
7071 COPY_FPGM(bci_action_ip_after);
7072 COPY_FPGM(bci_action_ip_on);
7073 COPY_FPGM(bci_action_ip_between);
7075 COPY_FPGM(bci_action_blue);
7076 COPY_FPGM(bci_action_blue_anchor);
7078 COPY_FPGM(bci_action_anchor);
7079 COPY_FPGM(bci_action_anchor_serif);
7080 COPY_FPGM(bci_action_anchor_round);
7081 COPY_FPGM(bci_action_anchor_round_serif);
7083 COPY_FPGM(bci_action_adjust);
7084 COPY_FPGM(bci_action_adjust_serif);
7085 COPY_FPGM(bci_action_adjust_round);
7086 COPY_FPGM(bci_action_adjust_round_serif);
7087 COPY_FPGM(bci_action_adjust_bound);
7088 COPY_FPGM(bci_action_adjust_bound_serif);
7089 COPY_FPGM(bci_action_adjust_bound_round);
7090 COPY_FPGM(bci_action_adjust_bound_round_serif);
7091 COPY_FPGM(bci_action_adjust_down_bound);
7092 COPY_FPGM(bci_action_adjust_down_bound_serif);
7093 COPY_FPGM(bci_action_adjust_down_bound_round);
7094 COPY_FPGM(bci_action_adjust_down_bound_round_serif);
7096 COPY_FPGM(bci_action_link);
7097 COPY_FPGM(bci_action_link_serif);
7098 COPY_FPGM(bci_action_link_round);
7099 COPY_FPGM(bci_action_link_round_serif);
7101 COPY_FPGM(bci_action_stem);
7102 COPY_FPGM(bci_action_stem_serif);
7103 COPY_FPGM(bci_action_stem_round);
7104 COPY_FPGM(bci_action_stem_round_serif);
7105 COPY_FPGM(bci_action_stem_bound);
7106 COPY_FPGM(bci_action_stem_bound_serif);
7107 COPY_FPGM(bci_action_stem_bound_round);
7108 COPY_FPGM(bci_action_stem_bound_round_serif);
7109 COPY_FPGM(bci_action_stem_down_bound);
7110 COPY_FPGM(bci_action_stem_down_bound_serif);
7111 COPY_FPGM(bci_action_stem_down_bound_round);
7112 COPY_FPGM(bci_action_stem_down_bound_round_serif);
7114 COPY_FPGM(bci_action_serif);
7115 COPY_FPGM(bci_action_serif_lower_bound);
7116 COPY_FPGM(bci_action_serif_upper_bound);
7117 COPY_FPGM(bci_action_serif_upper_lower_bound);
7118 COPY_FPGM(bci_action_serif_down_lower_bound);
7119 COPY_FPGM(bci_action_serif_down_upper_bound);
7120 COPY_FPGM(bci_action_serif_down_upper_lower_bound);
7122 COPY_FPGM(bci_action_serif_anchor);
7123 COPY_FPGM(bci_action_serif_anchor_lower_bound);
7124 COPY_FPGM(bci_action_serif_anchor_upper_bound);
7125 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
7126 COPY_FPGM(bci_action_serif_anchor_down_lower_bound);
7127 COPY_FPGM(bci_action_serif_anchor_down_upper_bound);
7128 COPY_FPGM(bci_action_serif_anchor_down_upper_lower_bound);
7130 COPY_FPGM(bci_action_serif_link1);
7131 COPY_FPGM(bci_action_serif_link1_lower_bound);
7132 COPY_FPGM(bci_action_serif_link1_upper_bound);
7133 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
7134 COPY_FPGM(bci_action_serif_link1_down_lower_bound);
7135 COPY_FPGM(bci_action_serif_link1_down_upper_bound);
7136 COPY_FPGM(bci_action_serif_link1_down_upper_lower_bound);
7138 COPY_FPGM(bci_action_serif_link2);
7139 COPY_FPGM(bci_action_serif_link2_lower_bound);
7140 COPY_FPGM(bci_action_serif_link2_upper_bound);
7141 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
7142 COPY_FPGM(bci_action_serif_link2_down_lower_bound);
7143 COPY_FPGM(bci_action_serif_link2_down_upper_bound);
7144 COPY_FPGM(bci_action_serif_link2_down_upper_lower_bound);
7146 COPY_FPGM(bci_hint_glyph);
7148 *fpgm = buf;
7149 *fpgm_len = buf_len;
7151 return FT_Err_Ok;
7155 FT_Error
7156 TA_sfnt_build_fpgm_table(SFNT* sfnt,
7157 FONT* font)
7159 FT_Error error;
7161 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
7162 glyf_Data* data = (glyf_Data*)glyf_table->data;
7164 FT_Byte* fpgm_buf;
7165 FT_ULong fpgm_len;
7168 error = TA_sfnt_add_table_info(sfnt);
7169 if (error)
7170 goto Exit;
7172 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
7173 if (glyf_table->processed)
7175 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
7176 goto Exit;
7179 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
7180 if (error)
7181 goto Exit;
7183 if (fpgm_len > sfnt->max_instructions)
7184 sfnt->max_instructions = (FT_UShort)fpgm_len;
7186 /* in case of success, `fpgm_buf' gets linked */
7187 /* and is eventually freed in `TA_font_unload' */
7188 error = TA_font_add_table(font,
7189 &sfnt->table_infos[sfnt->num_table_infos - 1],
7190 TTAG_fpgm, fpgm_len, fpgm_buf);
7191 if (error)
7192 free(fpgm_buf);
7193 else
7194 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
7196 Exit:
7197 return error;
7200 /* end of tafpgm.c */