Rename `deltas exceptions' to `control instructions'.
[ttfautohint.git] / lib / tafpgm.c
blob8a3203550ef544aabb6e46d66586e562d20b0aa7
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2014 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 #define MD_orig_ZP2_1 \
42 PUSHB_1, \
43 0, \
44 SZP2, \
45 MD_orig_fixed, \
46 PUSHB_1, \
47 1, \
48 SZP2
52 * Older versions of Monotype's `iType' bytecode interpreter have a serious
53 * bug: The DIV instruction rounds the result, while the correct operation
54 * is truncation. (Note, however, that MUL always rounds the result.)
55 * Since many printers contain this rasterizer without any possibility to
56 * update to a non-buggy version, we have to work around the problem.
58 * DIV and MUL work on 26.6 numbers which means that the numerator gets
59 * multiplied by 64 before the division, and the product gets divided by 64
60 * after the multiplication, respectively. For example, to divide 2 by 3,
61 * you have to write
63 * PUSHB_1,
64 * 2,
65 * 3*64,
66 * DIV
68 * The correct formula to divide two values in 26.6 format with truncation
69 * is
71 * a*64 / b ,
73 * while older `iType' versions incorrectly apply rounding by using
75 * (a*64 + b/2) / b .
77 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
79 * (2*64 + (3*64)/2) / (3*64) = 1
81 * instead of the correct result 0.
83 * The solution to the rounding issue is to use a 26.6 value as an
84 * intermediate result so that we can truncate to the nearest integer (in
85 * 26.6 format) with the FLOOR operator before converting back to a plain
86 * integer (in 32.0 format).
88 * For the common divisions by 2 and 2^10 we define macros.
90 #define DIV_POS_BY_2 \
91 PUSHB_1, \
92 2, \
93 DIV, /* multiply by 64, then divide by 2 */ \
94 FLOOR, \
95 PUSHB_1, \
96 1, \
97 MUL /* multiply by 1, then divide by 64 */
99 #define DIV_BY_2 \
100 PUSHB_1, \
101 2, \
102 DIV, \
103 DUP, \
104 PUSHB_1, \
105 0, \
106 LT, \
107 IF, \
108 PUSHB_1, \
109 64, \
110 ADD, /* add 1 if value is negative */ \
111 EIF, \
112 FLOOR, \
113 PUSHB_1, \
114 1, \
117 #define DIV_BY_1024 \
118 PUSHW_1, \
119 0x04, /* 2^10 */ \
120 0x00, \
121 DIV, \
122 DUP, \
123 PUSHB_1, \
124 0, \
125 LT, \
126 IF, \
127 PUSHB_1, \
128 64, \
129 ADD, \
130 EIF, \
131 FLOOR, \
132 PUSHB_1, \
133 1, \
137 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
138 #define DO_SCALE \
139 DUP, /* s: a a */ \
140 PUSHB_1, \
141 sal_scale, \
142 RS, \
143 MUL, /* delta * 2^10 */ \
144 DIV_BY_1024, /* delta */ \
145 ADD /* a + delta */
148 /* in the comments below, the top of the stack (`s:') */
149 /* is the rightmost element; the stack is shown */
150 /* after the instruction on the same line has been executed */
154 * bci_align_top
156 * Optimize the alignment of the top of small letters to the pixel grid.
158 * This function gets used in the `prep' table.
160 * in: blue_idx (CVT index for the style's top of small letters blue zone)
162 * sal: sal_i (CVT index of the style's scaling value;
163 * gets incremented by 1 after execution)
166 unsigned char FPGM(bci_align_top_a) [] =
169 PUSHB_1,
170 bci_align_top,
171 FDEF,
173 /* only get CVT value for non-zero index */
174 DUP,
175 PUSHB_1,
177 NEQ,
179 RCVT,
180 EIF,
181 DUP,
182 DUP, /* s: blue blue blue */
186 /* if (font->increase_x_height) */
187 /* { */
189 unsigned char FPGM(bci_align_top_b1a) [] =
192 /* apply much `stronger' rounding up of x height for */
193 /* 6 <= PPEM <= increase_x_height */
194 MPPEM,
195 PUSHW_1,
199 /* %d, x height increase limit */
201 unsigned char FPGM(bci_align_top_b1b) [] =
204 LTEQ,
205 MPPEM,
206 PUSHB_1,
208 GTEQ,
209 AND,
211 PUSHB_1,
212 52, /* threshold = 52 */
214 ELSE,
215 PUSHB_1,
216 40, /* threshold = 40 */
218 EIF,
219 ADD,
220 FLOOR, /* fitted = FLOOR(blue + threshold) */
224 /* } */
226 /* if (!font->increase_x_height) */
227 /* { */
229 unsigned char FPGM(bci_align_top_b2) [] =
232 PUSHB_1,
234 ADD,
235 FLOOR, /* fitted = FLOOR(blue + 40) */
239 /* } */
241 unsigned char FPGM(bci_align_top_c) [] =
244 DUP, /* s: blue blue fitted fitted */
245 ROLL,
246 NEQ,
247 IF, /* s: blue fitted */
248 PUSHB_1,
250 CINDEX,
251 SUB, /* s: blue (fitted-blue) */
252 PUSHW_2,
253 0x08, /* 0x800 */
254 0x00,
255 0x08, /* 0x800 */
256 0x00,
257 MUL, /* 0x10000 */
258 MUL, /* (fitted-blue) in 16.16 format */
259 SWAP,
260 DIV, /* factor = ((fitted-blue) / blue) in 16.16 format */
262 ELSE,
263 POP,
264 POP,
265 PUSHB_1,
266 0, /* factor = 0 */
268 EIF,
270 PUSHB_1,
271 sal_i,
272 RS, /* s: factor idx */
273 SWAP,
274 WCVTP,
276 PUSHB_3,
277 sal_i,
279 sal_i,
281 ADD, /* sal_i = sal_i + 1 */
284 ENDF,
290 * bci_round
292 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
293 * engine specific corrections are applied.
295 * in: val
297 * out: ROUND(val)
300 unsigned char FPGM(bci_round) [] =
303 PUSHB_1,
304 bci_round,
305 FDEF,
307 PUSHB_1,
309 ADD,
310 FLOOR,
312 ENDF,
318 * bci_smooth_stem_width
320 * This is the equivalent to the following code from function
321 * `ta_latin_compute_stem_width':
323 * dist = ABS(width)
325 * if (stem_is_serif
326 * && dist < 3*64)
327 * || std_width < 40:
328 * return width
329 * else if base_is_round:
330 * if dist < 80:
331 * dist = 64
332 * else if dist < 56:
333 * dist = 56
335 * delta = ABS(dist - std_width)
337 * if delta < 40:
338 * dist = std_width
339 * if dist < 48:
340 * dist = 48
341 * goto End
343 * if dist < 3*64:
344 * delta = dist
345 * dist = FLOOR(dist)
346 * delta = delta - dist
348 * if delta < 10:
349 * dist = dist + delta
350 * else if delta < 32:
351 * dist = dist + 10
352 * else if delta < 54:
353 * dist = dist + 54
354 * else:
355 * dist = dist + delta
356 * else:
357 * dist = ROUND(dist)
359 * End:
360 * if width < 0:
361 * dist = -dist
362 * return dist
364 * in: width
365 * stem_is_serif
366 * base_is_round
368 * out: new_width
370 * sal: sal_vwidth_data_offset
372 * CVT: std_width
374 * uses: bci_round
377 unsigned char FPGM(bci_smooth_stem_width) [] =
380 PUSHB_1,
381 bci_smooth_stem_width,
382 FDEF,
384 DUP,
385 ABS, /* s: base_is_round stem_is_serif width dist */
387 DUP,
388 PUSHB_1,
389 3*64,
390 LT, /* dist < 3*64 */
392 PUSHB_1,
394 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
395 AND, /* stem_is_serif && dist < 3*64 */
397 PUSHB_3,
400 sal_vwidth_data_offset,
402 RCVT, /* first indirection */
403 MUL, /* divide by 64 */
404 RCVT, /* second indirection */
405 GT, /* standard_width < 40 */
406 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
408 IF, /* s: base_is_round width dist */
409 POP,
410 SWAP,
411 POP, /* s: width */
413 ELSE,
414 ROLL, /* s: width dist base_is_round */
415 IF, /* s: width dist */
416 DUP,
417 PUSHB_1,
419 LT, /* dist < 80 */
420 IF, /* s: width dist */
421 POP,
422 PUSHB_1,
423 64, /* dist = 64 */
424 EIF,
426 ELSE,
427 DUP,
428 PUSHB_1,
430 LT, /* dist < 56 */
431 IF, /* s: width dist */
432 POP,
433 PUSHB_1,
434 56, /* dist = 56 */
435 EIF,
436 EIF,
438 DUP, /* s: width dist dist */
439 PUSHB_2,
441 sal_vwidth_data_offset,
443 RCVT, /* first indirection */
444 MUL, /* divide by 64 */
445 RCVT, /* second indirection */
446 SUB,
447 ABS, /* s: width dist delta */
449 PUSHB_1,
451 LT, /* delta < 40 */
452 IF, /* s: width dist */
453 POP,
454 PUSHB_2,
456 sal_vwidth_data_offset,
458 RCVT, /* first indirection */
459 MUL, /* divide by 64 */
460 RCVT, /* second indirection; dist = std_width */
461 DUP,
462 PUSHB_1,
464 LT, /* dist < 48 */
466 POP,
467 PUSHB_1,
468 48, /* dist = 48 */
469 EIF,
471 ELSE,
472 DUP, /* s: width dist dist */
473 PUSHB_1,
474 3*64,
475 LT, /* dist < 3*64 */
477 DUP, /* s: width delta dist */
478 FLOOR, /* dist = FLOOR(dist) */
479 DUP, /* s: width delta dist dist */
480 ROLL,
481 ROLL, /* s: width dist delta dist */
482 SUB, /* delta = delta - dist */
484 DUP, /* s: width dist delta delta */
485 PUSHB_1,
487 LT, /* delta < 10 */
488 IF, /* s: width dist delta */
489 ADD, /* dist = dist + delta */
491 ELSE,
492 DUP,
493 PUSHB_1,
495 LT, /* delta < 32 */
497 POP,
498 PUSHB_1,
500 ADD, /* dist = dist + 10 */
502 ELSE,
503 DUP,
504 PUSHB_1,
506 LT, /* delta < 54 */
508 POP,
509 PUSHB_1,
511 ADD, /* dist = dist + 54 */
513 ELSE,
514 ADD, /* dist = dist + delta */
516 EIF,
517 EIF,
518 EIF,
520 ELSE,
521 PUSHB_1,
522 bci_round,
523 CALL, /* dist = round(dist) */
525 EIF,
526 EIF,
528 SWAP, /* s: dist width */
529 PUSHB_1,
531 LT, /* width < 0 */
533 NEG, /* dist = -dist */
534 EIF,
535 EIF,
537 ENDF,
543 * bci_get_best_width
545 * An auxiliary function for `bci_strong_stem_width'.
547 * in: n (initialized with CVT index for first vertical width)
548 * dist
550 * out: n+1
551 * dist
553 * sal: sal_best
554 * sal_ref
556 * CVT: widths[]
559 unsigned char FPGM(bci_get_best_width) [] =
562 PUSHB_1,
563 bci_get_best_width,
564 FDEF,
566 DUP,
567 RCVT, /* s: dist n w */
568 DUP,
569 PUSHB_1,
571 CINDEX, /* s: dist n w w dist */
572 SUB,
573 ABS, /* s: dist n w d */
574 DUP,
575 PUSHB_1,
576 sal_best,
577 RS, /* s: dist n w d d best */
578 LT, /* d < best */
580 PUSHB_1,
581 sal_best,
582 SWAP,
583 WS, /* best = d */
584 PUSHB_1,
585 sal_ref,
586 SWAP,
587 WS, /* reference = w */
589 ELSE,
590 POP,
591 POP,
592 EIF,
594 PUSHB_1,
596 ADD, /* n = n + 1 */
598 ENDF,
604 * bci_strong_stem_width
606 * This is the equivalent to the following code (function
607 * `ta_latin_snap_width' and some lines from
608 * `ta_latin_compute_stem_width'):
610 * best = 64 + 32 + 2
611 * reference = width
612 * dist = ABS(width)
614 * for n in 0 .. num_widths:
615 * w = widths[n]
616 * d = ABS(dist - w)
618 * if d < best:
619 * best = d
620 * reference = w
622 * if dist >= reference:
623 * if dist < ROUND(reference) + 48:
624 * dist = reference
625 * else:
626 * if dist > ROUND(reference) - 48:
627 * dist = reference
629 * if dist >= 64:
630 * dist = ROUND(dist)
631 * else:
632 * dist = 64
634 * if width < 0:
635 * dist = -dist
636 * return dist
638 * in: width
639 * stem_is_serif (unused)
640 * base_is_round (unused)
642 * out: new_width
644 * sal: sal_best
645 * sal_ref
646 * sal_vwidth_data_offset
648 * CVT: widths[]
650 * uses: bci_get_best_width
651 * bci_round
654 unsigned char FPGM(bci_strong_stem_width_a) [] =
657 PUSHB_1,
658 bci_strong_stem_width,
659 FDEF,
661 SWAP,
662 POP,
663 SWAP,
664 POP,
665 DUP,
666 ABS, /* s: width dist */
668 PUSHB_2,
669 sal_best,
670 64 + 32 + 2,
671 WS, /* sal_best = 98 */
673 DUP,
674 PUSHB_1,
675 sal_ref,
676 SWAP,
677 WS, /* sal_ref = width */
679 PUSHB_2,
681 sal_vwidth_data_offset,
683 RCVT,
684 MUL, /* divide by 64; first index of vertical widths */
686 PUSHB_2,
688 sal_vwidth_data_offset,
690 PUSHB_1,
694 /* %c, number of used styles */
696 unsigned char FPGM(bci_strong_stem_width_b) [] =
699 ADD,
700 RCVT, /* number of vertical widths */
701 MUL, /* divide by 64 */
703 PUSHB_1,
704 bci_get_best_width,
705 LOOPCALL,
707 POP, /* s: width dist */
708 DUP,
709 PUSHB_1,
710 sal_ref,
711 RS, /* s: width dist dist reference */
712 DUP,
713 ROLL,
714 DUP,
715 ROLL,
716 PUSHB_1,
717 bci_round,
718 CALL, /* s: width dist reference dist dist ROUND(reference) */
719 PUSHB_2,
722 CINDEX, /* s: width dist reference dist dist ROUND(reference) 48 reference */
723 PUSHB_1,
725 MINDEX, /* s: width dist reference dist ROUND(reference) 48 reference dist */
727 LTEQ, /* dist >= reference */
728 IF, /* s: width dist reference dist ROUND(reference) 48 */
729 ADD,
730 LT, /* dist < ROUND(reference) + 48 */
732 ELSE,
733 SUB,
734 GT, /* dist > ROUND(reference) - 48 */
735 EIF,
738 SWAP, /* s: width reference dist */
739 EIF,
740 POP,
742 DUP,
743 PUSHB_1,
745 GTEQ, /* dist >= 64 */
747 PUSHB_1,
748 bci_round,
749 CALL, /* dist = ROUND(dist) */
751 ELSE,
752 POP,
753 PUSHB_1,
754 64, /* dist = 64 */
755 EIF,
757 SWAP, /* s: dist width */
758 PUSHB_1,
760 LT, /* width < 0 */
762 NEG, /* dist = -dist */
763 EIF,
765 ENDF,
771 * bci_do_loop
773 * An auxiliary function for `bci_loop'.
775 * sal: sal_i (gets incremented by 2 after execution)
776 * sal_func
778 * uses: func[sal_func]
781 unsigned char FPGM(bci_loop_do) [] =
784 PUSHB_1,
785 bci_loop_do,
786 FDEF,
788 PUSHB_1,
789 sal_func,
791 CALL,
793 PUSHB_3,
794 sal_i,
796 sal_i,
798 ADD, /* sal_i = sal_i + 2 */
801 ENDF,
807 * bci_loop
809 * Take a range `start'..`end' and a function number and apply the
810 * associated function to the range elements `start', `start+2',
811 * `start+4', ...
813 * in: func_num
814 * end
815 * start
817 * sal: sal_i (counter initialized with `start')
818 * sal_func (`func_num')
820 * uses: bci_loop_do
823 unsigned char FPGM(bci_loop) [] =
826 PUSHB_1,
827 bci_loop,
828 FDEF,
830 PUSHB_1,
831 sal_func,
832 SWAP,
833 WS, /* sal_func = func_num */
835 SWAP,
836 DUP,
837 PUSHB_1,
838 sal_i,
839 SWAP,
840 WS, /* sal_i = start */
842 SUB,
843 DIV_POS_BY_2,
844 PUSHB_1,
846 ADD, /* number of loops ((end - start) / 2 + 1) */
848 PUSHB_1,
849 bci_loop_do,
850 LOOPCALL,
852 ENDF,
858 * bci_cvt_rescale
860 * Rescale CVT value by `sal_scale' (in 16.16 format).
862 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
863 * consequently, the calculation `a * b/c' is done as `a + delta' with
864 * `delta = a * (b-c)/c'. This avoids overflow.
866 * in: cvt_idx
868 * out: cvt_idx+1
870 * sal: sal_scale
873 unsigned char FPGM(bci_cvt_rescale) [] =
876 PUSHB_1,
877 bci_cvt_rescale,
878 FDEF,
880 DUP,
881 DUP,
882 RCVT,
883 DO_SCALE,
884 WCVTP,
886 PUSHB_1,
888 ADD,
890 ENDF,
896 * bci_cvt_rescale_range
898 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
899 * scaling value.
901 * This function gets used in the `prep' table.
903 * in: num_cvt
904 * cvt_start_idx
906 * sal: sal_i (CVT index of the style's scaling value;
907 * gets incremented by 1 after execution)
908 * sal_scale
910 * uses: bci_cvt_rescale
913 unsigned char FPGM(bci_cvt_rescale_range) [] =
916 PUSHB_1,
917 bci_cvt_rescale_range,
918 FDEF,
920 /* store scaling value in `sal_scale' */
921 PUSHB_3,
922 bci_cvt_rescale,
923 sal_scale,
924 sal_i,
926 RCVT,
927 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
929 LOOPCALL,
930 POP,
932 PUSHB_3,
933 sal_i,
935 sal_i,
937 ADD, /* sal_i = sal_i + 1 */
940 ENDF,
946 * bci_vwidth_data_store
948 * Store a vertical width array value.
950 * This function gets used in the `prep' table.
952 * in: value
954 * sal: sal_i (CVT index of the style's vwidth data;
955 * gets incremented by 1 after execution)
958 unsigned char FPGM(bci_vwidth_data_store) [] =
961 PUSHB_1,
962 bci_vwidth_data_store,
963 FDEF,
965 PUSHB_1,
966 sal_i,
968 SWAP,
969 WCVTP,
971 PUSHB_3,
972 sal_i,
974 sal_i,
976 ADD, /* sal_i = sal_i + 1 */
979 ENDF,
985 * bci_smooth_blue_round
987 * Round a blue ref value and adjust its corresponding shoot value.
989 * This is the equivalent to the following code (function
990 * `ta_latin_metrics_scale_dim':
992 * delta = dist
993 * if dist < 0:
994 * delta = -delta
996 * if delta < 32:
997 * delta = 0
998 * else if delta < 48:
999 * delta = 32
1000 * else:
1001 * delta = 64
1003 * if dist < 0:
1004 * delta = -delta
1006 * in: ref_idx
1008 * sal: sal_i (number of blue zones)
1010 * out: ref_idx+1
1012 * uses: bci_round
1015 unsigned char FPGM(bci_smooth_blue_round) [] =
1018 PUSHB_1,
1019 bci_smooth_blue_round,
1020 FDEF,
1022 DUP,
1023 DUP,
1024 RCVT, /* s: ref_idx ref_idx ref */
1026 DUP,
1027 PUSHB_1,
1028 bci_round,
1029 CALL,
1030 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1032 PUSHB_1,
1033 sal_i,
1035 PUSHB_1,
1037 CINDEX,
1038 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1039 DUP,
1040 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1042 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1043 SWAP,
1044 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1045 DUP,
1046 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1048 DUP,
1049 PUSHB_1,
1051 LT, /* delta < 32 */
1053 POP,
1054 PUSHB_1,
1055 0, /* delta = 0 */
1057 ELSE,
1058 PUSHB_1,
1060 LT, /* delta < 48 */
1062 PUSHB_1,
1063 32, /* delta = 32 */
1065 ELSE,
1066 PUSHB_1,
1067 64, /* delta = 64 */
1068 EIF,
1069 EIF,
1071 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1072 PUSHB_1,
1074 LT, /* dist < 0 */
1076 NEG, /* delta = -delta */
1077 EIF,
1079 PUSHB_1,
1081 CINDEX,
1082 SWAP,
1083 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1085 WCVTP,
1086 WCVTP,
1088 PUSHB_1,
1090 ADD, /* s: (ref_idx + 1) */
1092 ENDF,
1098 * bci_strong_blue_round
1100 * Round a blue ref value and adjust its corresponding shoot value.
1102 * This is the equivalent to the following code:
1104 * delta = dist
1105 * if dist < 0:
1106 * delta = -delta
1108 * if delta < 36:
1109 * delta = 0
1110 * else:
1111 * delta = 64
1113 * if dist < 0:
1114 * delta = -delta
1116 * It doesn't have corresponding code in talatin.c; however, some tests
1117 * have shown that the `smooth' code works just fine for this case also.
1119 * in: ref_idx
1121 * sal: sal_i (number of blue zones)
1123 * out: ref_idx+1
1125 * uses: bci_round
1128 unsigned char FPGM(bci_strong_blue_round) [] =
1131 PUSHB_1,
1132 bci_strong_blue_round,
1133 FDEF,
1135 DUP,
1136 DUP,
1137 RCVT, /* s: ref_idx ref_idx ref */
1139 DUP,
1140 PUSHB_1,
1141 bci_round,
1142 CALL,
1143 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1145 PUSHB_1,
1146 sal_i,
1148 PUSHB_1,
1150 CINDEX,
1151 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1152 DUP,
1153 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1155 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1156 SWAP,
1157 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1158 DUP,
1159 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1161 PUSHB_1,
1163 LT, /* delta < 36 */
1165 PUSHB_1,
1166 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1168 ELSE,
1169 PUSHB_1,
1170 64, /* delta = 64 (one pixel unit) */
1171 EIF,
1173 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1174 PUSHB_1,
1176 LT, /* dist < 0 */
1178 NEG, /* delta = -delta */
1179 EIF,
1181 PUSHB_1,
1183 CINDEX,
1184 SWAP,
1185 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1187 WCVTP,
1188 WCVTP,
1190 PUSHB_1,
1192 ADD, /* s: (ref_idx + 1) */
1194 ENDF,
1200 * bci_blue_round_range
1202 * Round a range of blue zones (both reference and shoot values).
1204 * This function gets used in the `prep' table.
1206 * in: num_blue_zones
1207 * blue_ref_idx
1209 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1211 * uses: bci_smooth_blue_round
1212 * bci_strong_blue_round
1215 unsigned char FPGM(bci_blue_round_range) [] =
1218 PUSHB_1,
1219 bci_blue_round_range,
1220 FDEF,
1222 DUP,
1223 PUSHB_1,
1224 sal_i,
1225 SWAP,
1228 /* select blue rounding function based on flag in CVT */
1229 PUSHB_3,
1230 bci_strong_blue_round,
1231 bci_smooth_blue_round,
1232 cvtl_use_strong_functions,
1233 RCVT,
1235 POP,
1237 ELSE,
1238 SWAP,
1239 POP,
1241 EIF,
1242 LOOPCALL,
1243 POP,
1245 ENDF,
1251 * bci_decrement_component_counter
1253 * An auxiliary function for composite glyphs.
1255 * CVT: cvtl_is_subglyph
1258 unsigned char FPGM(bci_decrement_component_counter) [] =
1261 PUSHB_1,
1262 bci_decrement_component_counter,
1263 FDEF,
1265 /* decrement `cvtl_is_subglyph' counter */
1266 PUSHB_2,
1267 cvtl_is_subglyph,
1268 cvtl_is_subglyph,
1269 RCVT,
1270 PUSHB_1,
1271 100,
1272 SUB,
1273 WCVTP,
1275 ENDF,
1281 * bci_get_point_extrema
1283 * An auxiliary function for `bci_create_segment'.
1285 * in: point-1
1287 * out: point
1289 * sal: sal_point_min
1290 * sal_point_max
1293 unsigned char FPGM(bci_get_point_extrema) [] =
1296 PUSHB_1,
1297 bci_get_point_extrema,
1298 FDEF,
1300 PUSHB_1,
1302 ADD, /* s: point */
1303 DUP,
1304 DUP,
1306 /* check whether `point' is a new minimum */
1307 PUSHB_1,
1308 sal_point_min,
1309 RS, /* s: point point point point_min */
1310 MD_orig,
1311 /* if distance is negative, we have a new minimum */
1312 PUSHB_1,
1315 IF, /* s: point point */
1316 DUP,
1317 PUSHB_1,
1318 sal_point_min,
1319 SWAP,
1321 EIF,
1323 /* check whether `point' is a new maximum */
1324 PUSHB_1,
1325 sal_point_max,
1326 RS, /* s: point point point_max */
1327 MD_orig,
1328 /* if distance is positive, we have a new maximum */
1329 PUSHB_1,
1332 IF, /* s: point */
1333 DUP,
1334 PUSHB_1,
1335 sal_point_max,
1336 SWAP,
1338 EIF, /* s: point */
1340 ENDF,
1346 * bci_nibbles
1348 * Pop a byte with two delta arguments in its nibbles and push the
1349 * expanded arguments separately as two bytes.
1351 * in: 16 * (end - start) + (start - base)
1353 * out: start
1354 * end
1356 * sal: sal_base (set to `end' at return)
1360 unsigned char FPGM(bci_nibbles) [] =
1362 PUSHB_1,
1363 bci_nibbles,
1364 FDEF,
1366 DUP,
1367 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1369 DIV,
1370 FLOOR,
1371 PUSHB_1,
1373 MUL, /* s: in hnibble */
1374 DUP,
1375 PUSHW_1,
1376 0x04, /* 16*64 */
1377 0x00,
1378 MUL, /* s: in hnibble (hnibble * 16) */
1379 ROLL,
1380 SWAP,
1381 SUB, /* s: hnibble lnibble */
1383 PUSHB_1,
1384 sal_base,
1386 ADD, /* s: hnibble start */
1387 DUP,
1388 ROLL,
1389 ADD, /* s: start end */
1391 DUP,
1392 PUSHB_1,
1393 sal_base,
1394 SWAP,
1395 WS, /* sal_base = end */
1397 SWAP,
1399 ENDF,
1405 * bci_number_set_is_element
1407 * Pop values from stack until it is empty. If one of them is equal to
1408 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1409 * otherwise).
1411 * in: ppem_value_1
1412 * ppem_value_2
1413 * ...
1415 * CVT: cvtl_is_element
1418 unsigned char FPGM(bci_number_set_is_element) [] =
1421 PUSHB_1,
1422 bci_number_set_is_element,
1423 FDEF,
1425 /* start_loop: */
1426 MPPEM,
1429 PUSHB_2,
1430 cvtl_is_element,
1431 100,
1432 WCVTP,
1433 EIF,
1435 DEPTH,
1436 PUSHB_1,
1438 NEG,
1439 SWAP,
1440 JROT, /* goto start_loop if stack depth != 0 */
1442 ENDF,
1448 * bci_number_set_is_element2
1450 * Pop value ranges from stack until it is empty. If one of them contains
1451 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1452 * otherwise).
1454 * in: ppem_range_1_start
1455 * ppem_range_1_end
1456 * ppem_range_2_start
1457 * ppem_range_2_end
1458 * ...
1460 * CVT: cvtl_is_element
1463 unsigned char FPGM(bci_number_set_is_element2) [] =
1466 PUSHB_1,
1467 bci_number_set_is_element2,
1468 FDEF,
1470 /* start_loop: */
1471 MPPEM,
1472 LTEQ,
1474 MPPEM,
1475 GTEQ,
1477 PUSHB_2,
1478 cvtl_is_element,
1479 100,
1480 WCVTP,
1481 EIF,
1482 ELSE,
1483 POP,
1484 EIF,
1486 DEPTH,
1487 PUSHB_1,
1489 NEG,
1490 SWAP,
1491 JROT, /* goto start_loop if stack depth != 0 */
1493 ENDF,
1499 * bci_create_segment
1501 * Store start and end point of a segment in the storage area,
1502 * then construct a point in the twilight zone to represent it.
1504 * This function is used by `bci_create_segments'.
1506 * in: start
1507 * end
1508 * [last (if wrap-around segment)]
1509 * [first (if wrap-around segment)]
1511 * sal: sal_i (start of current segment)
1512 * sal_j (current twilight point)
1513 * sal_point_min
1514 * sal_point_max
1515 * sal_base
1516 * sal_num_packed_segments
1517 * sal_scale
1519 * CVT: cvtl_temp
1521 * uses: bci_get_point_extrema
1522 * bci_nibbles
1524 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1525 * delta values in nibbles (without a wrap-around segment).
1528 unsigned char FPGM(bci_create_segment) [] =
1531 PUSHB_1,
1532 bci_create_segment,
1533 FDEF,
1535 PUSHB_2,
1537 sal_num_packed_segments,
1539 NEQ,
1541 PUSHB_2,
1542 sal_num_packed_segments,
1543 sal_num_packed_segments,
1545 PUSHB_1,
1547 SUB,
1548 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1550 PUSHB_1,
1551 bci_nibbles,
1552 CALL,
1553 EIF,
1555 PUSHB_1,
1556 sal_i,
1558 PUSHB_1,
1560 CINDEX,
1561 WS, /* sal[sal_i] = start */
1563 /* initialize inner loop(s) */
1564 PUSHB_2,
1565 sal_point_min,
1567 CINDEX,
1568 WS, /* sal_point_min = start */
1569 PUSHB_2,
1570 sal_point_max,
1572 CINDEX,
1573 WS, /* sal_point_max = start */
1575 PUSHB_1,
1577 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1579 SWAP,
1580 DUP,
1581 PUSHB_1,
1583 CINDEX, /* s: start end end start */
1584 LT, /* start > end */
1586 /* we have a wrap-around segment with two more arguments */
1587 /* to give the last and first point of the contour, respectively; */
1588 /* our job is to store a segment `start'-`last', */
1589 /* and to get extrema for the two segments */
1590 /* `start'-`last' and `first'-`end' */
1592 /* s: first last start end */
1593 PUSHB_2,
1595 sal_i,
1597 ADD,
1598 PUSHB_1,
1600 CINDEX,
1601 WS, /* sal[sal_i + 1] = last */
1603 ROLL,
1604 ROLL, /* s: first end last start */
1605 DUP,
1606 ROLL,
1607 SWAP, /* s: first end start last start */
1608 SUB, /* s: first end start loop_count */
1610 PUSHB_1,
1611 bci_get_point_extrema,
1612 LOOPCALL,
1613 /* clean up stack */
1614 POP,
1616 SWAP, /* s: end first */
1617 PUSHB_1,
1619 SUB,
1620 DUP,
1621 ROLL, /* s: (first - 1) (first - 1) end */
1622 SWAP,
1623 SUB, /* s: (first - 1) loop_count */
1625 PUSHB_1,
1626 bci_get_point_extrema,
1627 LOOPCALL,
1628 /* clean up stack */
1629 POP,
1631 ELSE, /* s: start end */
1632 PUSHB_2,
1634 sal_i,
1636 ADD,
1637 PUSHB_1,
1639 CINDEX,
1640 WS, /* sal[sal_i + 1] = end */
1642 PUSHB_1,
1644 CINDEX,
1645 SUB, /* s: start loop_count */
1647 PUSHB_1,
1648 bci_get_point_extrema,
1649 LOOPCALL,
1650 /* clean up stack */
1651 POP,
1652 EIF,
1654 /* the twilight point representing a segment */
1655 /* is in the middle between the minimum and maximum */
1656 PUSHB_1,
1657 sal_point_min,
1659 GC_orig,
1660 PUSHB_1,
1661 sal_point_max,
1663 GC_orig,
1664 ADD,
1665 DIV_BY_2, /* s: middle_pos */
1667 DO_SCALE, /* middle_pos = middle_pos * scale */
1669 /* write it to temporary CVT location */
1670 PUSHB_2,
1671 cvtl_temp,
1673 SZP0, /* set zp0 to twilight zone 0 */
1674 SWAP,
1675 WCVTP,
1677 /* create twilight point with index `sal_j' */
1678 PUSHB_1,
1679 sal_j,
1681 PUSHB_1,
1682 cvtl_temp,
1683 MIAP_noround,
1685 PUSHB_3,
1686 sal_j,
1688 sal_j,
1690 ADD, /* twilight_point = twilight_point + 1 */
1693 ENDF,
1699 * bci_create_segments
1701 * This is the top-level entry function.
1703 * It pops point ranges from the stack to define segments, computes
1704 * twilight points to represent segments, and finally calls
1705 * `bci_hint_glyph' to handle the rest.
1707 * The second argument (`data_offset') addresses three CVT arrays in
1708 * parallel:
1710 * CVT(data_offset):
1711 * the current style's scaling value (stored in `sal_scale')
1713 * data_offset + num_used_styles:
1714 * offset to the current style's vwidth index array (this value gets
1715 * stored in `sal_vwidth_data_offset')
1717 * data_offset + 2*num_used_styles:
1718 * offset to the current style's vwidth size
1720 * This addressing scheme ensures that (a) we only need a single argument,
1721 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1722 * which should be sufficient for a long time.
1724 * in: num_packed_segments
1725 * data_offset
1726 * num_segments (N)
1727 * segment_start_0
1728 * segment_end_0
1729 * [contour_last 0 (if wrap-around segment)]
1730 * [contour_first 0 (if wrap-around segment)]
1731 * segment_start_1
1732 * segment_end_1
1733 * [contour_last 0 (if wrap-around segment)]
1734 * [contour_first 0 (if wrap-around segment)]
1735 * ...
1736 * segment_start_(N-1)
1737 * segment_end_(N-1)
1738 * [contour_last (N-1) (if wrap-around segment)]
1739 * [contour_first (N-1) (if wrap-around segment)]
1740 * ... stuff for bci_hint_glyph ...
1742 * sal: sal_i (start of current segment)
1743 * sal_j (current twilight point)
1744 * sal_num_packed_segments
1745 * sal_base (the base for delta values in nibbles)
1746 * sal_vwidth_data_offset
1747 * sal_scale
1749 * CVT: cvtl_is_subglyph
1751 * uses: bci_create_segment
1752 * bci_loop
1753 * bci_hint_glyph
1755 * If `num_packed_segments' is set to p, the first p start/end pairs are
1756 * stored as delta values in nibbles, with the `start' delta in the lower
1757 * nibble (and there are no wrap-around segments). For example, if the
1758 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1759 * stack are 0x21, 0x32, and 0x14.
1763 unsigned char FPGM(bci_create_segments_a) [] =
1766 PUSHB_1,
1767 bci_create_segments,
1768 FDEF,
1770 /* all our measurements are taken along the y axis */
1771 SVTCA_y,
1773 /* only do something if we are not a subglyph */
1774 PUSHB_2,
1776 cvtl_is_subglyph,
1777 RCVT,
1780 PUSHB_1,
1781 sal_num_packed_segments,
1782 SWAP,
1785 DUP,
1786 RCVT,
1787 PUSHB_1,
1788 sal_scale, /* sal_scale = CVT(data_offset) */
1789 SWAP,
1792 PUSHB_1,
1793 sal_vwidth_data_offset,
1794 SWAP,
1795 PUSHB_1,
1799 /* %c, number of used styles */
1801 unsigned char FPGM(bci_create_segments_b) [] =
1804 ADD,
1805 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1807 DUP,
1808 ADD,
1809 PUSHB_1,
1811 SUB, /* delta = (2*num_segments - 1) */
1813 PUSHB_6,
1814 sal_segment_offset,
1815 sal_segment_offset,
1817 sal_j,
1819 sal_base,
1821 WS, /* sal_base = 0 */
1822 WS, /* sal_j = 0 (point offset) */
1824 ROLL,
1825 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1827 PUSHB_2,
1828 bci_create_segment,
1829 bci_loop,
1830 CALL,
1832 PUSHB_1,
1833 bci_hint_glyph,
1834 CALL,
1838 /* used if we have delta exceptions */
1840 unsigned char FPGM(bci_create_segments_c) [] =
1843 PUSHB_1,
1845 SZPS,
1849 unsigned char FPGM(bci_create_segments_d) [] =
1852 ELSE,
1853 CLEAR,
1854 EIF,
1856 ENDF,
1862 * bci_create_segments_X
1864 * Top-level routines for calling `bci_create_segments'.
1867 unsigned char FPGM(bci_create_segments_0) [] =
1870 PUSHB_1,
1871 bci_create_segments_0,
1872 FDEF,
1874 PUSHB_2,
1876 bci_create_segments,
1877 CALL,
1879 ENDF,
1883 unsigned char FPGM(bci_create_segments_1) [] =
1886 PUSHB_1,
1887 bci_create_segments_1,
1888 FDEF,
1890 PUSHB_2,
1892 bci_create_segments,
1893 CALL,
1895 ENDF,
1899 unsigned char FPGM(bci_create_segments_2) [] =
1902 PUSHB_1,
1903 bci_create_segments_2,
1904 FDEF,
1906 PUSHB_2,
1908 bci_create_segments,
1909 CALL,
1911 ENDF,
1915 unsigned char FPGM(bci_create_segments_3) [] =
1918 PUSHB_1,
1919 bci_create_segments_3,
1920 FDEF,
1922 PUSHB_2,
1924 bci_create_segments,
1925 CALL,
1927 ENDF,
1931 unsigned char FPGM(bci_create_segments_4) [] =
1934 PUSHB_1,
1935 bci_create_segments_4,
1936 FDEF,
1938 PUSHB_2,
1940 bci_create_segments,
1941 CALL,
1943 ENDF,
1947 unsigned char FPGM(bci_create_segments_5) [] =
1950 PUSHB_1,
1951 bci_create_segments_5,
1952 FDEF,
1954 PUSHB_2,
1956 bci_create_segments,
1957 CALL,
1959 ENDF,
1963 unsigned char FPGM(bci_create_segments_6) [] =
1966 PUSHB_1,
1967 bci_create_segments_6,
1968 FDEF,
1970 PUSHB_2,
1972 bci_create_segments,
1973 CALL,
1975 ENDF,
1979 unsigned char FPGM(bci_create_segments_7) [] =
1982 PUSHB_1,
1983 bci_create_segments_7,
1984 FDEF,
1986 PUSHB_2,
1988 bci_create_segments,
1989 CALL,
1991 ENDF,
1995 unsigned char FPGM(bci_create_segments_8) [] =
1998 PUSHB_1,
1999 bci_create_segments_8,
2000 FDEF,
2002 PUSHB_2,
2004 bci_create_segments,
2005 CALL,
2007 ENDF,
2011 unsigned char FPGM(bci_create_segments_9) [] =
2014 PUSHB_1,
2015 bci_create_segments_9,
2016 FDEF,
2018 PUSHB_2,
2020 bci_create_segments,
2021 CALL,
2023 ENDF,
2029 * bci_create_segments_composite
2031 * The same as `bci_create_segments'.
2032 * It also decrements the composite component counter.
2034 * sal: sal_num_packed_segments
2035 * sal_segment_offset
2036 * sal_vwidth_data_offset
2038 * CVT: cvtl_is_subglyph
2040 * uses: bci_decrement_component_counter
2041 * bci_create_segment
2042 * bci_loop
2043 * bci_hint_glyph
2046 unsigned char FPGM(bci_create_segments_composite_a) [] =
2049 PUSHB_1,
2050 bci_create_segments_composite,
2051 FDEF,
2053 /* all our measurements are taken along the y axis */
2054 SVTCA_y,
2056 PUSHB_1,
2057 bci_decrement_component_counter,
2058 CALL,
2060 /* only do something if we are not a subglyph */
2061 PUSHB_2,
2063 cvtl_is_subglyph,
2064 RCVT,
2067 PUSHB_1,
2068 sal_num_packed_segments,
2069 SWAP,
2072 DUP,
2073 RCVT,
2074 PUSHB_1,
2075 sal_scale, /* sal_scale = CVT(data_offset) */
2076 SWAP,
2079 PUSHB_1,
2080 sal_vwidth_data_offset,
2081 SWAP,
2082 PUSHB_1,
2086 /* %c, number of used styles */
2088 unsigned char FPGM(bci_create_segments_composite_b) [] =
2091 ADD,
2092 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2094 DUP,
2095 ADD,
2096 PUSHB_1,
2098 SUB, /* delta = (2*num_segments - 1) */
2100 PUSHB_6,
2101 sal_segment_offset,
2102 sal_segment_offset,
2104 sal_j,
2106 sal_base,
2108 WS, /* sal_base = 0 */
2109 WS, /* sal_j = 0 (point offset) */
2111 ROLL,
2112 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2114 PUSHB_2,
2115 bci_create_segment,
2116 bci_loop,
2117 CALL,
2119 PUSHB_1,
2120 bci_hint_glyph,
2121 CALL,
2125 /* used if we have delta exceptions */
2127 unsigned char FPGM(bci_create_segments_composite_c) [] =
2130 PUSHB_1,
2132 SZPS,
2136 unsigned char FPGM(bci_create_segments_composite_d) [] =
2139 ELSE,
2140 CLEAR,
2141 EIF,
2143 ENDF,
2149 * bci_create_segments_composite_X
2151 * Top-level routines for calling `bci_create_segments_composite'.
2154 unsigned char FPGM(bci_create_segments_composite_0) [] =
2157 PUSHB_1,
2158 bci_create_segments_composite_0,
2159 FDEF,
2161 PUSHB_2,
2163 bci_create_segments_composite,
2164 CALL,
2166 ENDF,
2170 unsigned char FPGM(bci_create_segments_composite_1) [] =
2173 PUSHB_1,
2174 bci_create_segments_composite_1,
2175 FDEF,
2177 PUSHB_2,
2179 bci_create_segments_composite,
2180 CALL,
2182 ENDF,
2186 unsigned char FPGM(bci_create_segments_composite_2) [] =
2189 PUSHB_1,
2190 bci_create_segments_composite_2,
2191 FDEF,
2193 PUSHB_2,
2195 bci_create_segments_composite,
2196 CALL,
2198 ENDF,
2202 unsigned char FPGM(bci_create_segments_composite_3) [] =
2205 PUSHB_1,
2206 bci_create_segments_composite_3,
2207 FDEF,
2209 PUSHB_2,
2211 bci_create_segments_composite,
2212 CALL,
2214 ENDF,
2218 unsigned char FPGM(bci_create_segments_composite_4) [] =
2221 PUSHB_1,
2222 bci_create_segments_composite_4,
2223 FDEF,
2225 PUSHB_2,
2227 bci_create_segments_composite,
2228 CALL,
2230 ENDF,
2234 unsigned char FPGM(bci_create_segments_composite_5) [] =
2237 PUSHB_1,
2238 bci_create_segments_composite_5,
2239 FDEF,
2241 PUSHB_2,
2243 bci_create_segments_composite,
2244 CALL,
2246 ENDF,
2250 unsigned char FPGM(bci_create_segments_composite_6) [] =
2253 PUSHB_1,
2254 bci_create_segments_composite_6,
2255 FDEF,
2257 PUSHB_2,
2259 bci_create_segments_composite,
2260 CALL,
2262 ENDF,
2266 unsigned char FPGM(bci_create_segments_composite_7) [] =
2269 PUSHB_1,
2270 bci_create_segments_composite_7,
2271 FDEF,
2273 PUSHB_2,
2275 bci_create_segments_composite,
2276 CALL,
2278 ENDF,
2282 unsigned char FPGM(bci_create_segments_composite_8) [] =
2285 PUSHB_1,
2286 bci_create_segments_composite_8,
2287 FDEF,
2289 PUSHB_2,
2291 bci_create_segments_composite,
2292 CALL,
2294 ENDF,
2298 unsigned char FPGM(bci_create_segments_composite_9) [] =
2301 PUSHB_1,
2302 bci_create_segments_composite_9,
2303 FDEF,
2305 PUSHB_2,
2307 bci_create_segments_composite,
2308 CALL,
2310 ENDF,
2316 * bci_align_point
2318 * An auxiliary function for `bci_align_segment'.
2320 * in: point
2322 * out: point+1
2325 unsigned char FPGM(bci_align_point) [] =
2328 PUSHB_1,
2329 bci_align_point,
2330 FDEF,
2332 DUP,
2333 ALIGNRP, /* align point with rp0 */
2335 PUSHB_1,
2337 ADD,
2339 ENDF,
2345 * bci_align_segment
2347 * Align all points in a segment to the twilight point in rp0.
2348 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2350 * in: segment_index
2352 * sal: sal_segment_offset
2354 * uses: bci_align_point
2357 unsigned char FPGM(bci_align_segment) [] =
2360 PUSHB_1,
2361 bci_align_segment,
2362 FDEF,
2364 /* we need the values of `sal_segment_offset + 2*segment_index' */
2365 /* and `sal_segment_offset + 2*segment_index + 1' */
2366 DUP,
2367 ADD,
2368 PUSHB_1,
2369 sal_segment_offset,
2370 ADD,
2371 DUP,
2373 SWAP,
2374 PUSHB_1,
2376 ADD,
2377 RS, /* s: first last */
2379 PUSHB_1,
2381 CINDEX, /* s: first last first */
2382 SUB,
2383 PUSHB_1,
2385 ADD, /* s: first loop_count */
2387 PUSHB_1,
2388 bci_align_point,
2389 LOOPCALL,
2390 /* clean up stack */
2391 POP,
2393 ENDF,
2399 * bci_align_segments
2401 * Align segments to the twilight point in rp0.
2402 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2404 * in: first_segment
2405 * loop_counter (N)
2406 * segment_1
2407 * segment_2
2408 * ...
2409 * segment_N
2411 * uses: bci_align_segment
2414 unsigned char FPGM(bci_align_segments) [] =
2417 PUSHB_1,
2418 bci_align_segments,
2419 FDEF,
2421 PUSHB_1,
2422 bci_align_segment,
2423 CALL,
2425 PUSHB_1,
2426 bci_align_segment,
2427 LOOPCALL,
2429 ENDF,
2435 * bci_scale_contour
2437 * Scale a contour using two points giving the maximum and minimum
2438 * coordinates.
2440 * It expects that no point on the contour is touched.
2442 * in: min_point
2443 * max_point
2445 * sal: sal_scale
2448 unsigned char FPGM(bci_scale_contour) [] =
2451 PUSHB_1,
2452 bci_scale_contour,
2453 FDEF,
2455 DUP,
2456 DUP,
2457 GC_orig,
2458 DUP,
2459 DO_SCALE, /* min_pos_new = min_pos * scale */
2460 SWAP,
2461 SUB,
2462 SHPIX,
2464 /* don't scale a single-point contour twice */
2465 SWAP,
2466 DUP,
2467 ROLL,
2468 NEQ,
2470 DUP,
2471 GC_orig,
2472 DUP,
2473 DO_SCALE, /* max_pos_new = max_pos * scale */
2474 SWAP,
2475 SUB,
2476 SHPIX,
2478 ELSE,
2479 POP,
2480 EIF,
2482 ENDF,
2488 * bci_scale_glyph
2490 * Scale a glyph using a list of points (two points per contour, giving
2491 * the maximum and mininum coordinates).
2493 * It expects that no point in the glyph is touched.
2495 * Note that the point numbers are sorted in ascending order;
2496 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2497 * contour without specifying which one is the minimum and maximum.
2499 * in: num_contours (N)
2500 * min_point_1
2501 * max_point_1
2502 * min_point_2
2503 * max_point_2
2504 * ...
2505 * min_point_N
2506 * max_point_N
2508 * CVT: cvtl_is_subglyph
2510 * uses: bci_scale_contour
2513 unsigned char FPGM(bci_scale_glyph) [] =
2516 PUSHB_1,
2517 bci_scale_glyph,
2518 FDEF,
2520 /* all our measurements are taken along the y axis */
2521 SVTCA_y,
2523 /* only do something if we are not a subglyph */
2524 PUSHB_2,
2526 cvtl_is_subglyph,
2527 RCVT,
2530 PUSHB_1,
2532 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2534 PUSHB_1,
2535 bci_scale_contour,
2536 LOOPCALL,
2538 PUSHB_1,
2540 SZP2, /* set zp2 to normal zone 1 */
2541 IUP_y,
2543 ELSE,
2544 CLEAR,
2545 EIF,
2547 ENDF,
2553 * bci_scale_composite_glyph
2555 * The same as `bci_scale_glyph'.
2556 * It also decrements the composite component counter.
2558 * CVT: cvtl_is_subglyph
2560 * uses: bci_decrement_component_counter
2561 * bci_scale_contour
2564 unsigned char FPGM(bci_scale_composite_glyph) [] =
2567 PUSHB_1,
2568 bci_scale_composite_glyph,
2569 FDEF,
2571 /* all our measurements are taken along the y axis */
2572 SVTCA_y,
2574 PUSHB_1,
2575 bci_decrement_component_counter,
2576 CALL,
2578 /* only do something if we are not a subglyph */
2579 PUSHB_2,
2581 cvtl_is_subglyph,
2582 RCVT,
2585 PUSHB_1,
2587 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2589 PUSHB_1,
2590 bci_scale_contour,
2591 LOOPCALL,
2593 PUSHB_1,
2595 SZP2, /* set zp2 to normal zone 1 */
2596 IUP_y,
2598 ELSE,
2599 CLEAR,
2600 EIF,
2602 ENDF,
2608 * bci_shift_contour
2610 * Shift a contour by a given amount.
2612 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2613 * point to the normal zone 1.
2615 * in: contour
2617 * out: contour+1
2620 unsigned char FPGM(bci_shift_contour) [] =
2623 PUSHB_1,
2624 bci_shift_contour,
2625 FDEF,
2627 DUP,
2628 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2630 PUSHB_1,
2632 ADD,
2634 ENDF,
2640 * bci_shift_subglyph
2642 * Shift a subglyph. To be more specific, it corrects the already applied
2643 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2644 * also.
2646 * If this function is called, a point `x' in the subglyph has been scaled
2647 * already (during the hinting of the subglyph itself), and `offset' has
2648 * been applied also:
2650 * x -> x * scale + offset (1)
2652 * However, the offset should be applied first, then the scaling:
2654 * x -> (x + offset) * scale (2)
2656 * Our job is now to transform (1) to (2); a simple calculation shows that
2657 * we have to shift all points of the subglyph by
2659 * offset * scale - offset = offset * (scale - 1)
2661 * Note that `sal_scale' is equal to the above `scale - 1'.
2663 * in: offset (in FUnits)
2664 * num_contours
2665 * first_contour
2667 * CVT: cvtl_funits_to_pixels
2669 * sal: sal_scale
2671 * uses: bci_round
2672 * bci_shift_contour
2675 unsigned char FPGM(bci_shift_subglyph_a) [] =
2678 PUSHB_1,
2679 bci_shift_subglyph,
2680 FDEF,
2682 /* all our measurements are taken along the y axis */
2683 SVTCA_y,
2685 PUSHB_1,
2686 cvtl_funits_to_pixels,
2687 RCVT, /* scaling factor FUnits -> pixels */
2688 MUL,
2689 DIV_BY_1024,
2691 /* the autohinter always rounds offsets */
2692 PUSHB_1,
2693 bci_round,
2694 CALL, /* offset = round(offset) */
2696 PUSHB_1,
2697 sal_scale,
2699 MUL,
2700 DIV_BY_1024, /* delta = offset * (scale - 1) */
2702 /* and round again */
2703 PUSHB_1,
2704 bci_round,
2705 CALL, /* offset = round(offset) */
2707 PUSHB_1,
2709 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2711 /* we create twilight point 0 as a reference point, */
2712 /* setting the original position to zero (using `cvtl_temp') */
2713 PUSHB_5,
2716 cvtl_temp,
2717 cvtl_temp,
2719 WCVTP,
2720 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2722 SWAP, /* s: first_contour num_contours 0 delta */
2723 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2725 PUSHB_2,
2726 bci_shift_contour,
2728 SZP2, /* set zp2 to normal zone 1 */
2729 LOOPCALL,
2733 /* used if we have delta exceptions */
2735 unsigned char FPGM(bci_shift_subglyph_b) [] =
2738 PUSHB_1,
2740 SZPS,
2744 unsigned char FPGM(bci_shift_subglyph_c) [] =
2747 ENDF,
2753 * bci_ip_outer_align_point
2755 * Auxiliary function for `bci_action_ip_before' and
2756 * `bci_action_ip_after'.
2758 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2759 * zone, and both zp1 and zp2 set to normal zone.
2761 * in: point
2763 * sal: sal_i (edge_orig_pos)
2764 * sal_scale
2767 unsigned char FPGM(bci_ip_outer_align_point) [] =
2770 PUSHB_1,
2771 bci_ip_outer_align_point,
2772 FDEF,
2774 DUP,
2775 ALIGNRP, /* align `point' with `edge' */
2776 DUP,
2777 GC_orig,
2778 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2780 PUSHB_1,
2781 sal_i,
2783 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2784 SHPIX,
2786 ENDF,
2792 * bci_ip_on_align_points
2794 * Auxiliary function for `bci_action_ip_on'.
2796 * in: edge (in twilight zone)
2797 * loop_counter (N)
2798 * point_1
2799 * point_2
2800 * ...
2801 * point_N
2804 unsigned char FPGM(bci_ip_on_align_points) [] =
2807 PUSHB_1,
2808 bci_ip_on_align_points,
2809 FDEF,
2811 MDAP_noround, /* set rp0 and rp1 to `edge' */
2813 SLOOP,
2814 ALIGNRP,
2816 ENDF,
2822 * bci_ip_between_align_point
2824 * Auxiliary function for `bci_ip_between_align_points'.
2826 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2827 * zone, and both zp1 and zp2 set to normal zone.
2829 * in: point
2831 * sal: sal_i (edge_orig_pos)
2832 * sal_j (stretch_factor)
2833 * sal_scale
2836 unsigned char FPGM(bci_ip_between_align_point) [] =
2839 PUSHB_1,
2840 bci_ip_between_align_point,
2841 FDEF,
2843 DUP,
2844 ALIGNRP, /* align `point' with `edge' */
2845 DUP,
2846 GC_orig,
2847 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2849 PUSHB_1,
2850 sal_i,
2852 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2853 PUSHB_1,
2854 sal_j,
2856 MUL, /* s: point delta */
2857 SHPIX,
2859 ENDF,
2865 * bci_ip_between_align_points
2867 * Auxiliary function for `bci_action_ip_between'.
2869 * in: after_edge (in twilight zone)
2870 * before_edge (in twilight zone)
2871 * loop_counter (N)
2872 * point_1
2873 * point_2
2874 * ...
2875 * point_N
2877 * sal: sal_i (before_orig_pos)
2878 * sal_j (stretch_factor)
2880 * uses: bci_ip_between_align_point
2883 unsigned char FPGM(bci_ip_between_align_points) [] =
2886 PUSHB_1,
2887 bci_ip_between_align_points,
2888 FDEF,
2890 PUSHB_2,
2893 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2894 CINDEX,
2895 DUP, /* s: ... before after before before */
2896 MDAP_noround, /* set rp0 and rp1 to `before' */
2897 DUP,
2898 GC_orig, /* s: ... before after before before_orig_pos */
2899 PUSHB_1,
2900 sal_i,
2901 SWAP,
2902 WS, /* sal_i = before_orig_pos */
2903 PUSHB_1,
2905 CINDEX, /* s: ... before after before after */
2906 MD_cur, /* a = after_pos - before_pos */
2907 ROLL,
2908 ROLL,
2909 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2911 DUP,
2912 IF, /* b != 0 ? */
2913 DIV, /* s: a/b */
2914 ELSE,
2915 POP, /* avoid division by zero */
2916 EIF,
2918 PUSHB_1,
2919 sal_j,
2920 SWAP,
2921 WS, /* sal_j = stretch_factor */
2923 PUSHB_3,
2924 bci_ip_between_align_point,
2927 SZP2, /* set zp2 to normal zone 1 */
2928 SZP1, /* set zp1 to normal zone 1 */
2929 LOOPCALL,
2931 ENDF,
2937 * bci_action_ip_before
2939 * Handle `ip_before' data to align points located before the first edge.
2941 * in: first_edge (in twilight zone)
2942 * loop_counter (N)
2943 * point_1
2944 * point_2
2945 * ...
2946 * point_N
2948 * sal: sal_i (first_edge_orig_pos)
2950 * uses: bci_ip_outer_align_point
2953 unsigned char FPGM(bci_action_ip_before) [] =
2956 PUSHB_1,
2957 bci_action_ip_before,
2958 FDEF,
2960 PUSHB_1,
2962 SZP2, /* set zp2 to twilight zone 0 */
2964 DUP,
2965 GC_orig,
2966 PUSHB_1,
2967 sal_i,
2968 SWAP,
2969 WS, /* sal_i = first_edge_orig_pos */
2971 PUSHB_3,
2975 SZP2, /* set zp2 to normal zone 1 */
2976 SZP1, /* set zp1 to normal zone 1 */
2977 SZP0, /* set zp0 to twilight zone 0 */
2979 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2981 PUSHB_1,
2982 bci_ip_outer_align_point,
2983 LOOPCALL,
2985 ENDF,
2991 * bci_action_ip_after
2993 * Handle `ip_after' data to align points located after the last edge.
2995 * in: last_edge (in twilight zone)
2996 * loop_counter (N)
2997 * point_1
2998 * point_2
2999 * ...
3000 * point_N
3002 * sal: sal_i (last_edge_orig_pos)
3004 * uses: bci_ip_outer_align_point
3007 unsigned char FPGM(bci_action_ip_after) [] =
3010 PUSHB_1,
3011 bci_action_ip_after,
3012 FDEF,
3014 PUSHB_1,
3016 SZP2, /* set zp2 to twilight zone 0 */
3018 DUP,
3019 GC_orig,
3020 PUSHB_1,
3021 sal_i,
3022 SWAP,
3023 WS, /* sal_i = last_edge_orig_pos */
3025 PUSHB_3,
3029 SZP2, /* set zp2 to normal zone 1 */
3030 SZP1, /* set zp1 to normal zone 1 */
3031 SZP0, /* set zp0 to twilight zone 0 */
3033 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3035 PUSHB_1,
3036 bci_ip_outer_align_point,
3037 LOOPCALL,
3039 ENDF,
3045 * bci_action_ip_on
3047 * Handle `ip_on' data to align points located on an edge coordinate (but
3048 * not part of an edge).
3050 * in: loop_counter (M)
3051 * edge_1 (in twilight zone)
3052 * loop_counter (N_1)
3053 * point_1
3054 * point_2
3055 * ...
3056 * point_N_1
3057 * edge_2 (in twilight zone)
3058 * loop_counter (N_2)
3059 * point_1
3060 * point_2
3061 * ...
3062 * point_N_2
3063 * ...
3064 * edge_M (in twilight zone)
3065 * loop_counter (N_M)
3066 * point_1
3067 * point_2
3068 * ...
3069 * point_N_M
3071 * uses: bci_ip_on_align_points
3074 unsigned char FPGM(bci_action_ip_on) [] =
3077 PUSHB_1,
3078 bci_action_ip_on,
3079 FDEF,
3081 PUSHB_2,
3084 SZP1, /* set zp1 to normal zone 1 */
3085 SZP0, /* set zp0 to twilight zone 0 */
3087 PUSHB_1,
3088 bci_ip_on_align_points,
3089 LOOPCALL,
3091 ENDF,
3097 * bci_action_ip_between
3099 * Handle `ip_between' data to align points located between two edges.
3101 * in: loop_counter (M)
3102 * before_edge_1 (in twilight zone)
3103 * after_edge_1 (in twilight zone)
3104 * loop_counter (N_1)
3105 * point_1
3106 * point_2
3107 * ...
3108 * point_N_1
3109 * before_edge_2 (in twilight zone)
3110 * after_edge_2 (in twilight zone)
3111 * loop_counter (N_2)
3112 * point_1
3113 * point_2
3114 * ...
3115 * point_N_2
3116 * ...
3117 * before_edge_M (in twilight zone)
3118 * after_edge_M (in twilight zone)
3119 * loop_counter (N_M)
3120 * point_1
3121 * point_2
3122 * ...
3123 * point_N_M
3125 * uses: bci_ip_between_align_points
3128 unsigned char FPGM(bci_action_ip_between) [] =
3131 PUSHB_1,
3132 bci_action_ip_between,
3133 FDEF,
3135 PUSHB_1,
3136 bci_ip_between_align_points,
3137 LOOPCALL,
3139 ENDF,
3145 * bci_adjust_common
3147 * Common code for bci_action_adjust routines.
3149 * uses: func[sal_stem_width_function]
3152 unsigned char FPGM(bci_adjust_common) [] =
3155 PUSHB_1,
3156 bci_adjust_common,
3157 FDEF,
3159 PUSHB_1,
3161 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3163 PUSHB_1,
3165 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3166 PUSHB_1,
3168 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3169 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3171 PUSHB_1,
3172 sal_stem_width_function,
3174 CALL,
3175 NEG, /* s: [...] edge2 edge -cur_len */
3177 ROLL, /* s: [...] edge -cur_len edge2 */
3178 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3179 SWAP,
3180 DUP,
3181 DUP, /* s: [...] -cur_len edge edge edge */
3182 ALIGNRP, /* align `edge' with `edge2' */
3183 ROLL,
3184 SHPIX, /* shift `edge' by -cur_len */
3186 ENDF,
3192 * bci_adjust_bound
3194 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3195 * edge of the stem has already been moved, then moving it again if
3196 * necessary to stay bound.
3198 * in: edge2_is_serif
3199 * edge_is_round
3200 * edge_point (in twilight zone)
3201 * edge2_point (in twilight zone)
3202 * edge[-1] (in twilight zone)
3203 * ... stuff for bci_align_segments (edge) ...
3205 * uses: bci_adjust_common
3206 * bci_align_segments
3209 unsigned char FPGM(bci_adjust_bound) [] =
3212 PUSHB_1,
3213 bci_adjust_bound,
3214 FDEF,
3216 PUSHB_1,
3217 bci_adjust_common,
3218 CALL,
3220 SWAP, /* s: edge edge[-1] */
3221 DUP,
3222 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3223 GC_cur,
3224 PUSHB_1,
3226 CINDEX,
3227 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3228 GT, /* edge_pos < edge[-1]_pos */
3230 DUP,
3231 ALIGNRP, /* align `edge' to `edge[-1]' */
3232 EIF,
3234 MDAP_noround, /* set rp0 and rp1 to `edge' */
3236 PUSHB_2,
3237 bci_align_segments,
3239 SZP1, /* set zp1 to normal zone 1 */
3240 CALL,
3242 ENDF,
3248 * bci_action_adjust_bound
3249 * bci_action_adjust_bound_serif
3250 * bci_action_adjust_bound_round
3251 * bci_action_adjust_bound_round_serif
3253 * Higher-level routines for calling `bci_adjust_bound'.
3256 unsigned char FPGM(bci_action_adjust_bound) [] =
3259 PUSHB_1,
3260 bci_action_adjust_bound,
3261 FDEF,
3263 PUSHB_3,
3266 bci_adjust_bound,
3267 CALL,
3269 ENDF,
3273 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3276 PUSHB_1,
3277 bci_action_adjust_bound_serif,
3278 FDEF,
3280 PUSHB_3,
3283 bci_adjust_bound,
3284 CALL,
3286 ENDF,
3290 unsigned char FPGM(bci_action_adjust_bound_round) [] =
3293 PUSHB_1,
3294 bci_action_adjust_bound_round,
3295 FDEF,
3297 PUSHB_3,
3300 bci_adjust_bound,
3301 CALL,
3303 ENDF,
3307 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3310 PUSHB_1,
3311 bci_action_adjust_bound_round_serif,
3312 FDEF,
3314 PUSHB_3,
3317 bci_adjust_bound,
3318 CALL,
3320 ENDF,
3326 * bci_adjust
3328 * Handle the ADJUST action to align an edge of a stem if the other edge
3329 * of the stem has already been moved.
3331 * in: edge2_is_serif
3332 * edge_is_round
3333 * edge_point (in twilight zone)
3334 * edge2_point (in twilight zone)
3335 * ... stuff for bci_align_segments (edge) ...
3337 * uses: bci_adjust_common
3338 * bci_align_segments
3341 unsigned char FPGM(bci_adjust) [] =
3344 PUSHB_1,
3345 bci_adjust,
3346 FDEF,
3348 PUSHB_1,
3349 bci_adjust_common,
3350 CALL,
3352 MDAP_noround, /* set rp0 and rp1 to `edge' */
3354 PUSHB_2,
3355 bci_align_segments,
3357 SZP1, /* set zp1 to normal zone 1 */
3358 CALL,
3360 ENDF,
3366 * bci_action_adjust
3367 * bci_action_adjust_serif
3368 * bci_action_adjust_round
3369 * bci_action_adjust_round_serif
3371 * Higher-level routines for calling `bci_adjust'.
3374 unsigned char FPGM(bci_action_adjust) [] =
3377 PUSHB_1,
3378 bci_action_adjust,
3379 FDEF,
3381 PUSHB_3,
3384 bci_adjust,
3385 CALL,
3387 ENDF,
3391 unsigned char FPGM(bci_action_adjust_serif) [] =
3394 PUSHB_1,
3395 bci_action_adjust_serif,
3396 FDEF,
3398 PUSHB_3,
3401 bci_adjust,
3402 CALL,
3404 ENDF,
3408 unsigned char FPGM(bci_action_adjust_round) [] =
3411 PUSHB_1,
3412 bci_action_adjust_round,
3413 FDEF,
3415 PUSHB_3,
3418 bci_adjust,
3419 CALL,
3421 ENDF,
3425 unsigned char FPGM(bci_action_adjust_round_serif) [] =
3428 PUSHB_1,
3429 bci_action_adjust_round_serif,
3430 FDEF,
3432 PUSHB_3,
3435 bci_adjust,
3436 CALL,
3438 ENDF,
3444 * bci_stem_common
3446 * Common code for bci_action_stem routines.
3448 * sal: sal_anchor
3449 * sal_temp1
3450 * sal_temp2
3451 * sal_temp3
3453 * uses: func[sal_stem_width_function]
3454 * bci_round
3457 #undef sal_u_off
3458 #define sal_u_off sal_temp1
3459 #undef sal_d_off
3460 #define sal_d_off sal_temp2
3461 #undef sal_org_len
3462 #define sal_org_len sal_temp3
3463 #undef sal_edge2
3464 #define sal_edge2 sal_temp3
3466 unsigned char FPGM(bci_stem_common) [] =
3469 PUSHB_1,
3470 bci_stem_common,
3471 FDEF,
3473 PUSHB_1,
3475 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3477 PUSHB_1,
3479 CINDEX,
3480 PUSHB_1,
3482 CINDEX,
3483 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3484 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3486 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3487 DUP,
3488 PUSHB_1,
3489 sal_org_len,
3490 SWAP,
3493 PUSHB_1,
3494 sal_stem_width_function,
3496 CALL, /* s: [...] edge2 edge cur_len */
3498 DUP,
3499 PUSHB_1,
3501 LT, /* cur_len < 96 */
3503 DUP,
3504 PUSHB_1,
3506 LTEQ, /* cur_len <= 64 */
3508 PUSHB_4,
3509 sal_u_off,
3511 sal_d_off,
3514 ELSE,
3515 PUSHB_4,
3516 sal_u_off,
3518 sal_d_off,
3520 EIF,
3524 SWAP, /* s: [...] edge2 cur_len edge */
3525 DUP,
3526 PUSHB_1,
3527 sal_anchor,
3529 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3530 ROLL,
3531 SWAP,
3532 MD_orig_ZP2_0,
3533 SWAP,
3534 GC_cur,
3535 ADD, /* s: [...] edge2 cur_len edge org_pos */
3536 PUSHB_1,
3537 sal_org_len,
3539 DIV_BY_2,
3540 ADD, /* s: [...] edge2 cur_len edge org_center */
3542 DUP,
3543 PUSHB_1,
3544 bci_round,
3545 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3547 DUP,
3548 ROLL,
3549 ROLL,
3550 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3552 DUP,
3553 PUSHB_1,
3554 sal_u_off,
3556 ADD,
3557 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3559 SWAP,
3560 PUSHB_1,
3561 sal_d_off,
3563 SUB,
3564 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3566 LT, /* delta1 < delta2 */
3568 PUSHB_1,
3569 sal_u_off,
3571 SUB, /* cur_pos1 = cur_pos1 - u_off */
3573 ELSE,
3574 PUSHB_1,
3575 sal_d_off,
3577 ADD, /* cur_pos1 = cur_pos1 + d_off */
3578 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3580 PUSHB_1,
3582 CINDEX,
3583 DIV_BY_2,
3584 SUB, /* arg = cur_pos1 - cur_len/2 */
3586 SWAP, /* s: [...] edge2 cur_len arg edge */
3587 DUP,
3588 DUP,
3589 PUSHB_1,
3591 MINDEX,
3592 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3593 GC_cur,
3594 SUB,
3595 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3597 ELSE,
3598 SWAP, /* s: [...] edge2 cur_len edge */
3599 PUSHB_1,
3600 sal_anchor,
3602 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3603 PUSHB_1,
3605 CINDEX,
3606 PUSHB_1,
3607 sal_anchor,
3609 MD_orig_ZP2_0,
3610 ADD, /* s: [...] edge2 cur_len edge org_pos */
3612 DUP,
3613 PUSHB_1,
3614 sal_org_len,
3616 DIV_BY_2,
3617 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3619 SWAP,
3620 DUP,
3621 PUSHB_1,
3622 bci_round,
3623 CALL, /* cur_pos1 = ROUND(org_pos) */
3624 SWAP,
3625 PUSHB_1,
3626 sal_org_len,
3628 ADD,
3629 PUSHB_1,
3630 bci_round,
3631 CALL,
3632 PUSHB_1,
3634 CINDEX,
3635 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3637 PUSHB_1,
3639 CINDEX,
3640 DIV_BY_2,
3641 PUSHB_1,
3643 MINDEX,
3644 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3646 DUP,
3647 PUSHB_1,
3649 CINDEX,
3650 ADD,
3651 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3652 SWAP,
3653 PUSHB_1,
3655 CINDEX,
3656 ADD,
3657 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3658 LT, /* delta1 < delta2 */
3660 POP, /* arg = cur_pos1 */
3662 ELSE,
3663 SWAP,
3664 POP, /* arg = cur_pos2 */
3665 EIF, /* s: [...] edge2 cur_len edge arg */
3666 SWAP,
3667 DUP,
3668 DUP,
3669 PUSHB_1,
3671 MINDEX,
3672 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3673 GC_cur,
3674 SUB,
3675 SHPIX, /* edge = arg */
3676 EIF, /* s: [...] edge2 cur_len edge */
3678 ENDF,
3684 * bci_stem_bound
3686 * Handle the STEM action to align two edges of a stem, then moving one
3687 * edge again if necessary to stay bound.
3689 * The code after computing `cur_len' to shift `edge' and `edge2'
3690 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3692 * if cur_len < 96:
3693 * if cur_len < = 64:
3694 * u_off = 32
3695 * d_off = 32
3696 * else:
3697 * u_off = 38
3698 * d_off = 26
3700 * org_pos = anchor + (edge_orig - anchor_orig)
3701 * org_center = org_pos + org_len / 2
3703 * cur_pos1 = ROUND(org_center)
3704 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3705 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3706 * if (delta1 < delta2):
3707 * cur_pos1 = cur_pos1 - u_off
3708 * else:
3709 * cur_pos1 = cur_pos1 + d_off
3711 * edge = cur_pos1 - cur_len / 2
3713 * else:
3714 * org_pos = anchor + (edge_orig - anchor_orig)
3715 * org_center = org_pos + org_len / 2
3717 * cur_pos1 = ROUND(org_pos)
3718 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3719 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3720 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3722 * if (delta1 < delta2):
3723 * edge = cur_pos1
3724 * else:
3725 * edge = cur_pos2
3727 * edge2 = edge + cur_len
3729 * in: edge2_is_serif
3730 * edge_is_round
3731 * edge_point (in twilight zone)
3732 * edge2_point (in twilight zone)
3733 * edge[-1] (in twilight zone)
3734 * ... stuff for bci_align_segments (edge) ...
3735 * ... stuff for bci_align_segments (edge2)...
3737 * sal: sal_anchor
3738 * sal_temp1
3739 * sal_temp2
3740 * sal_temp3
3742 * uses: bci_stem_common
3743 * bci_align_segments
3746 unsigned char FPGM(bci_stem_bound) [] =
3749 PUSHB_1,
3750 bci_stem_bound,
3751 FDEF,
3753 PUSHB_1,
3754 bci_stem_common,
3755 CALL,
3757 ROLL, /* s: edge[-1] cur_len edge edge2 */
3758 DUP,
3759 DUP,
3760 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3761 PUSHB_1,
3762 sal_edge2,
3763 SWAP,
3764 WS, /* s: edge[-1] cur_len edge edge2 */
3765 ROLL,
3766 SHPIX, /* edge2 = edge + cur_len */
3768 SWAP, /* s: edge edge[-1] */
3769 DUP,
3770 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3771 GC_cur,
3772 PUSHB_1,
3774 CINDEX,
3775 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3776 GT, /* edge_pos < edge[-1]_pos */
3778 DUP,
3779 ALIGNRP, /* align `edge' to `edge[-1]' */
3780 EIF,
3782 MDAP_noround, /* set rp0 and rp1 to `edge' */
3784 PUSHB_2,
3785 bci_align_segments,
3787 SZP1, /* set zp1 to normal zone 1 */
3788 CALL,
3790 PUSHB_1,
3791 sal_edge2,
3793 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3795 PUSHB_1,
3796 bci_align_segments,
3797 CALL,
3799 ENDF,
3805 * bci_action_stem_bound
3806 * bci_action_stem_bound_serif
3807 * bci_action_stem_bound_round
3808 * bci_action_stem_bound_round_serif
3810 * Higher-level routines for calling `bci_stem_bound'.
3813 unsigned char FPGM(bci_action_stem_bound) [] =
3816 PUSHB_1,
3817 bci_action_stem_bound,
3818 FDEF,
3820 PUSHB_3,
3823 bci_stem_bound,
3824 CALL,
3826 ENDF,
3830 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3833 PUSHB_1,
3834 bci_action_stem_bound_serif,
3835 FDEF,
3837 PUSHB_3,
3840 bci_stem_bound,
3841 CALL,
3843 ENDF,
3847 unsigned char FPGM(bci_action_stem_bound_round) [] =
3850 PUSHB_1,
3851 bci_action_stem_bound_round,
3852 FDEF,
3854 PUSHB_3,
3857 bci_stem_bound,
3858 CALL,
3860 ENDF,
3864 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3867 PUSHB_1,
3868 bci_action_stem_bound_round_serif,
3869 FDEF,
3871 PUSHB_3,
3874 bci_stem_bound,
3875 CALL,
3877 ENDF,
3883 * bci_stem
3885 * Handle the STEM action to align two edges of a stem.
3887 * See `bci_stem_bound' for more details.
3889 * in: edge2_is_serif
3890 * edge_is_round
3891 * edge_point (in twilight zone)
3892 * edge2_point (in twilight zone)
3893 * ... stuff for bci_align_segments (edge) ...
3894 * ... stuff for bci_align_segments (edge2)...
3896 * sal: sal_anchor
3897 * sal_temp1
3898 * sal_temp2
3899 * sal_temp3
3901 * uses: bci_stem_common
3902 * bci_align_segments
3905 unsigned char FPGM(bci_stem) [] =
3908 PUSHB_1,
3909 bci_stem,
3910 FDEF,
3912 PUSHB_1,
3913 bci_stem_common,
3914 CALL,
3916 POP,
3917 SWAP, /* s: cur_len edge2 */
3918 DUP,
3919 DUP,
3920 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3921 PUSHB_1,
3922 sal_edge2,
3923 SWAP,
3924 WS, /* s: cur_len edge2 */
3925 SWAP,
3926 SHPIX, /* edge2 = edge + cur_len */
3928 PUSHB_2,
3929 bci_align_segments,
3931 SZP1, /* set zp1 to normal zone 1 */
3932 CALL,
3934 PUSHB_1,
3935 sal_edge2,
3937 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3939 PUSHB_1,
3940 bci_align_segments,
3941 CALL,
3942 ENDF,
3948 * bci_action_stem
3949 * bci_action_stem_serif
3950 * bci_action_stem_round
3951 * bci_action_stem_round_serif
3953 * Higher-level routines for calling `bci_stem'.
3956 unsigned char FPGM(bci_action_stem) [] =
3959 PUSHB_1,
3960 bci_action_stem,
3961 FDEF,
3963 PUSHB_3,
3966 bci_stem,
3967 CALL,
3969 ENDF,
3973 unsigned char FPGM(bci_action_stem_serif) [] =
3976 PUSHB_1,
3977 bci_action_stem_serif,
3978 FDEF,
3980 PUSHB_3,
3983 bci_stem,
3984 CALL,
3986 ENDF,
3990 unsigned char FPGM(bci_action_stem_round) [] =
3993 PUSHB_1,
3994 bci_action_stem_round,
3995 FDEF,
3997 PUSHB_3,
4000 bci_stem,
4001 CALL,
4003 ENDF,
4007 unsigned char FPGM(bci_action_stem_round_serif) [] =
4010 PUSHB_1,
4011 bci_action_stem_round_serif,
4012 FDEF,
4014 PUSHB_3,
4017 bci_stem,
4018 CALL,
4020 ENDF,
4026 * bci_link
4028 * Handle the LINK action to link an edge to another one.
4030 * in: stem_is_serif
4031 * base_is_round
4032 * base_point (in twilight zone)
4033 * stem_point (in twilight zone)
4034 * ... stuff for bci_align_segments (base) ...
4036 * uses: func[sal_stem_width_function]
4037 * bci_align_segments
4040 unsigned char FPGM(bci_link) [] =
4043 PUSHB_1,
4044 bci_link,
4045 FDEF,
4047 PUSHB_1,
4049 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4051 PUSHB_1,
4053 CINDEX,
4054 PUSHB_1,
4056 MINDEX,
4057 DUP, /* s: stem is_round is_serif stem base base */
4058 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4060 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4062 PUSHB_1,
4063 sal_stem_width_function,
4065 CALL, /* s: stem new_dist */
4067 SWAP,
4068 DUP,
4069 ALIGNRP, /* align `stem_point' with `base_point' */
4070 DUP,
4071 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4072 SWAP,
4073 SHPIX, /* stem_point = base_point + new_dist */
4075 PUSHB_2,
4076 bci_align_segments,
4078 SZP1, /* set zp1 to normal zone 1 */
4079 CALL,
4081 ENDF,
4087 * bci_action_link
4088 * bci_action_link_serif
4089 * bci_action_link_round
4090 * bci_action_link_round_serif
4092 * Higher-level routines for calling `bci_link'.
4095 unsigned char FPGM(bci_action_link) [] =
4098 PUSHB_1,
4099 bci_action_link,
4100 FDEF,
4102 PUSHB_3,
4105 bci_link,
4106 CALL,
4108 ENDF,
4112 unsigned char FPGM(bci_action_link_serif) [] =
4115 PUSHB_1,
4116 bci_action_link_serif,
4117 FDEF,
4119 PUSHB_3,
4122 bci_link,
4123 CALL,
4125 ENDF,
4129 unsigned char FPGM(bci_action_link_round) [] =
4132 PUSHB_1,
4133 bci_action_link_round,
4134 FDEF,
4136 PUSHB_3,
4139 bci_link,
4140 CALL,
4142 ENDF,
4146 unsigned char FPGM(bci_action_link_round_serif) [] =
4149 PUSHB_1,
4150 bci_action_link_round_serif,
4151 FDEF,
4153 PUSHB_3,
4156 bci_link,
4157 CALL,
4159 ENDF,
4165 * bci_anchor
4167 * Handle the ANCHOR action to align two edges
4168 * and to set the edge anchor.
4170 * The code after computing `cur_len' to shift `edge' and `edge2'
4171 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4173 * if cur_len < 96:
4174 * if cur_len < = 64:
4175 * u_off = 32
4176 * d_off = 32
4177 * else:
4178 * u_off = 38
4179 * d_off = 26
4181 * org_center = edge_orig + org_len / 2
4182 * cur_pos1 = ROUND(org_center)
4184 * error1 = ABS(org_center - (cur_pos1 - u_off))
4185 * error2 = ABS(org_center - (cur_pos1 + d_off))
4186 * if (error1 < error2):
4187 * cur_pos1 = cur_pos1 - u_off
4188 * else:
4189 * cur_pos1 = cur_pos1 + d_off
4191 * edge = cur_pos1 - cur_len / 2
4192 * edge2 = edge + cur_len
4194 * else:
4195 * edge = ROUND(edge_orig)
4197 * in: edge2_is_serif
4198 * edge_is_round
4199 * edge_point (in twilight zone)
4200 * edge2_point (in twilight zone)
4201 * ... stuff for bci_align_segments (edge) ...
4203 * sal: sal_anchor
4204 * sal_temp1
4205 * sal_temp2
4206 * sal_temp3
4208 * uses: func[sal_stem_width_function]
4209 * bci_round
4210 * bci_align_segments
4213 #undef sal_u_off
4214 #define sal_u_off sal_temp1
4215 #undef sal_d_off
4216 #define sal_d_off sal_temp2
4217 #undef sal_org_len
4218 #define sal_org_len sal_temp3
4220 unsigned char FPGM(bci_anchor) [] =
4223 PUSHB_1,
4224 bci_anchor,
4225 FDEF,
4227 /* store anchor point number in `sal_anchor' */
4228 PUSHB_2,
4229 sal_anchor,
4231 CINDEX,
4232 WS, /* sal_anchor = edge_point */
4234 PUSHB_1,
4236 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4238 PUSHB_1,
4240 CINDEX,
4241 PUSHB_1,
4243 CINDEX,
4244 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4245 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4247 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4248 DUP,
4249 PUSHB_1,
4250 sal_org_len,
4251 SWAP,
4254 PUSHB_1,
4255 sal_stem_width_function,
4257 CALL, /* s: edge2 edge cur_len */
4259 DUP,
4260 PUSHB_1,
4262 LT, /* cur_len < 96 */
4264 DUP,
4265 PUSHB_1,
4267 LTEQ, /* cur_len <= 64 */
4269 PUSHB_4,
4270 sal_u_off,
4272 sal_d_off,
4275 ELSE,
4276 PUSHB_4,
4277 sal_u_off,
4279 sal_d_off,
4281 EIF,
4285 SWAP, /* s: edge2 cur_len edge */
4286 DUP, /* s: edge2 cur_len edge edge */
4288 GC_orig,
4289 PUSHB_1,
4290 sal_org_len,
4292 DIV_BY_2,
4293 ADD, /* s: edge2 cur_len edge org_center */
4295 DUP,
4296 PUSHB_1,
4297 bci_round,
4298 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4300 DUP,
4301 ROLL,
4302 ROLL,
4303 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4305 DUP,
4306 PUSHB_1,
4307 sal_u_off,
4309 ADD,
4310 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4312 SWAP,
4313 PUSHB_1,
4314 sal_d_off,
4316 SUB,
4317 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4319 LT, /* error1 < error2 */
4321 PUSHB_1,
4322 sal_u_off,
4324 SUB, /* cur_pos1 = cur_pos1 - u_off */
4326 ELSE,
4327 PUSHB_1,
4328 sal_d_off,
4330 ADD, /* cur_pos1 = cur_pos1 + d_off */
4331 EIF, /* s: edge2 cur_len edge cur_pos1 */
4333 PUSHB_1,
4335 CINDEX,
4336 DIV_BY_2,
4337 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4339 PUSHB_1,
4341 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4342 GC_cur,
4343 SUB,
4344 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4346 SWAP, /* s: cur_len edge2 */
4347 DUP,
4348 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4349 SWAP,
4350 SHPIX, /* edge2 = edge1 + cur_len */
4352 ELSE,
4353 POP, /* s: edge2 edge */
4354 DUP,
4355 DUP,
4356 GC_cur,
4357 SWAP,
4358 GC_orig,
4359 PUSHB_1,
4360 bci_round,
4361 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4362 SWAP,
4363 SUB,
4364 SHPIX, /* edge = round(edge_orig) */
4366 /* clean up stack */
4367 POP,
4368 EIF,
4370 PUSHB_2,
4371 bci_align_segments,
4373 SZP1, /* set zp1 to normal zone 1 */
4374 CALL,
4376 ENDF,
4382 * bci_action_anchor
4383 * bci_action_anchor_serif
4384 * bci_action_anchor_round
4385 * bci_action_anchor_round_serif
4387 * Higher-level routines for calling `bci_anchor'.
4390 unsigned char FPGM(bci_action_anchor) [] =
4393 PUSHB_1,
4394 bci_action_anchor,
4395 FDEF,
4397 PUSHB_3,
4400 bci_anchor,
4401 CALL,
4403 ENDF,
4407 unsigned char FPGM(bci_action_anchor_serif) [] =
4410 PUSHB_1,
4411 bci_action_anchor_serif,
4412 FDEF,
4414 PUSHB_3,
4417 bci_anchor,
4418 CALL,
4420 ENDF,
4424 unsigned char FPGM(bci_action_anchor_round) [] =
4427 PUSHB_1,
4428 bci_action_anchor_round,
4429 FDEF,
4431 PUSHB_3,
4434 bci_anchor,
4435 CALL,
4437 ENDF,
4441 unsigned char FPGM(bci_action_anchor_round_serif) [] =
4444 PUSHB_1,
4445 bci_action_anchor_round_serif,
4446 FDEF,
4448 PUSHB_3,
4451 bci_anchor,
4452 CALL,
4454 ENDF,
4460 * bci_action_blue_anchor
4462 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4463 * and to set the edge anchor.
4465 * in: anchor_point (in twilight zone)
4466 * blue_cvt_idx
4467 * edge_point (in twilight zone)
4468 * ... stuff for bci_align_segments (edge) ...
4470 * sal: sal_anchor
4472 * uses: bci_action_blue
4475 unsigned char FPGM(bci_action_blue_anchor) [] =
4478 PUSHB_1,
4479 bci_action_blue_anchor,
4480 FDEF,
4482 /* store anchor point number in `sal_anchor' */
4483 PUSHB_1,
4484 sal_anchor,
4485 SWAP,
4488 PUSHB_1,
4489 bci_action_blue,
4490 CALL,
4492 ENDF,
4498 * bci_action_blue
4500 * Handle the BLUE action to align an edge with a blue zone.
4502 * in: blue_cvt_idx
4503 * edge_point (in twilight zone)
4504 * ... stuff for bci_align_segments (edge) ...
4506 * uses: bci_align_segments
4509 unsigned char FPGM(bci_action_blue) [] =
4512 PUSHB_1,
4513 bci_action_blue,
4514 FDEF,
4516 PUSHB_1,
4518 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4520 /* move `edge_point' to `blue_cvt_idx' position; */
4521 /* note that we can't use MIAP since this would modify */
4522 /* the twilight point's original coordinates also */
4523 RCVT,
4524 SWAP,
4525 DUP,
4526 MDAP_noround, /* set rp0 and rp1 to `edge' */
4527 DUP,
4528 GC_cur, /* s: new_pos edge edge_pos */
4529 ROLL,
4530 SWAP,
4531 SUB, /* s: edge (new_pos - edge_pos) */
4532 SHPIX,
4534 PUSHB_2,
4535 bci_align_segments,
4537 SZP1, /* set zp1 to normal zone 1 */
4538 CALL,
4540 ENDF,
4546 * bci_serif_common
4548 * Common code for bci_action_serif routines.
4551 unsigned char FPGM(bci_serif_common) [] =
4554 PUSHB_1,
4555 bci_serif_common,
4556 FDEF,
4558 PUSHB_1,
4560 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4562 DUP,
4563 DUP,
4564 DUP,
4565 PUSHB_1,
4567 MINDEX, /* s: [...] serif serif serif serif base */
4568 DUP,
4569 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4570 MD_orig_ZP2_0,
4571 SWAP,
4572 ALIGNRP, /* align `serif_point' with `base_point' */
4573 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4575 ENDF,
4581 * bci_lower_bound
4583 * Move an edge if necessary to stay within a lower bound.
4585 * in: edge
4586 * bound
4588 * uses: bci_align_segments
4591 unsigned char FPGM(bci_lower_bound) [] =
4594 PUSHB_1,
4595 bci_lower_bound,
4596 FDEF,
4598 SWAP, /* s: edge bound */
4599 DUP,
4600 MDAP_noround, /* set rp0 and rp1 to `bound' */
4601 GC_cur,
4602 PUSHB_1,
4604 CINDEX,
4605 GC_cur, /* s: edge bound_pos edge_pos */
4606 GT, /* edge_pos < bound_pos */
4608 DUP,
4609 ALIGNRP, /* align `edge' to `bound' */
4610 EIF,
4612 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4614 PUSHB_2,
4615 bci_align_segments,
4617 SZP1, /* set zp1 to normal zone 1 */
4618 CALL,
4620 ENDF,
4626 * bci_upper_bound
4628 * Move an edge if necessary to stay within an upper bound.
4630 * in: edge
4631 * bound
4633 * uses: bci_align_segments
4636 unsigned char FPGM(bci_upper_bound) [] =
4639 PUSHB_1,
4640 bci_upper_bound,
4641 FDEF,
4643 SWAP, /* s: edge bound */
4644 DUP,
4645 MDAP_noround, /* set rp0 and rp1 to `bound' */
4646 GC_cur,
4647 PUSHB_1,
4649 CINDEX,
4650 GC_cur, /* s: edge bound_pos edge_pos */
4651 LT, /* edge_pos > bound_pos */
4653 DUP,
4654 ALIGNRP, /* align `edge' to `bound' */
4655 EIF,
4657 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4659 PUSHB_2,
4660 bci_align_segments,
4662 SZP1, /* set zp1 to normal zone 1 */
4663 CALL,
4665 ENDF,
4671 * bci_upper_lower_bound
4673 * Move an edge if necessary to stay within a lower and lower bound.
4675 * in: edge
4676 * lower
4677 * upper
4679 * uses: bci_align_segments
4682 unsigned char FPGM(bci_upper_lower_bound) [] =
4685 PUSHB_1,
4686 bci_upper_lower_bound,
4687 FDEF,
4689 SWAP, /* s: upper serif lower */
4690 DUP,
4691 MDAP_noround, /* set rp0 and rp1 to `lower' */
4692 GC_cur,
4693 PUSHB_1,
4695 CINDEX,
4696 GC_cur, /* s: upper serif lower_pos serif_pos */
4697 GT, /* serif_pos < lower_pos */
4699 DUP,
4700 ALIGNRP, /* align `serif' to `lower' */
4701 EIF,
4703 SWAP, /* s: serif upper */
4704 DUP,
4705 MDAP_noround, /* set rp0 and rp1 to `upper' */
4706 GC_cur,
4707 PUSHB_1,
4709 CINDEX,
4710 GC_cur, /* s: serif upper_pos serif_pos */
4711 LT, /* serif_pos > upper_pos */
4713 DUP,
4714 ALIGNRP, /* align `serif' to `upper' */
4715 EIF,
4717 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4719 PUSHB_2,
4720 bci_align_segments,
4722 SZP1, /* set zp1 to normal zone 1 */
4723 CALL,
4725 ENDF,
4731 * bci_action_serif
4733 * Handle the SERIF action to align a serif with its base.
4735 * in: serif_point (in twilight zone)
4736 * base_point (in twilight zone)
4737 * ... stuff for bci_align_segments (serif) ...
4739 * uses: bci_serif_common
4740 * bci_align_segments
4743 unsigned char FPGM(bci_action_serif) [] =
4746 PUSHB_1,
4747 bci_action_serif,
4748 FDEF,
4750 PUSHB_1,
4751 bci_serif_common,
4752 CALL,
4754 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4756 PUSHB_2,
4757 bci_align_segments,
4759 SZP1, /* set zp1 to normal zone 1 */
4760 CALL,
4762 ENDF,
4768 * bci_action_serif_lower_bound
4770 * Handle the SERIF action to align a serif with its base, then moving it
4771 * again if necessary to stay within a lower bound.
4773 * in: serif_point (in twilight zone)
4774 * base_point (in twilight zone)
4775 * edge[-1] (in twilight zone)
4776 * ... stuff for bci_align_segments (serif) ...
4778 * uses: bci_serif_common
4779 * bci_lower_bound
4782 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4785 PUSHB_1,
4786 bci_action_serif_lower_bound,
4787 FDEF,
4789 PUSHB_1,
4790 bci_serif_common,
4791 CALL,
4793 PUSHB_1,
4794 bci_lower_bound,
4795 CALL,
4797 ENDF,
4803 * bci_action_serif_upper_bound
4805 * Handle the SERIF action to align a serif with its base, then moving it
4806 * again if necessary to stay within an upper bound.
4808 * in: serif_point (in twilight zone)
4809 * base_point (in twilight zone)
4810 * edge[1] (in twilight zone)
4811 * ... stuff for bci_align_segments (serif) ...
4813 * uses: bci_serif_common
4814 * bci_upper_bound
4817 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4820 PUSHB_1,
4821 bci_action_serif_upper_bound,
4822 FDEF,
4824 PUSHB_1,
4825 bci_serif_common,
4826 CALL,
4828 PUSHB_1,
4829 bci_upper_bound,
4830 CALL,
4832 ENDF,
4838 * bci_action_serif_upper_lower_bound
4840 * Handle the SERIF action to align a serif with its base, then moving it
4841 * again if necessary to stay within a lower and upper bound.
4843 * in: serif_point (in twilight zone)
4844 * base_point (in twilight zone)
4845 * edge[-1] (in twilight zone)
4846 * edge[1] (in twilight zone)
4847 * ... stuff for bci_align_segments (serif) ...
4849 * uses: bci_serif_common
4850 * bci_upper_lower_bound
4853 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4856 PUSHB_1,
4857 bci_action_serif_upper_lower_bound,
4858 FDEF,
4860 PUSHB_1,
4862 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4864 PUSHB_1,
4865 bci_serif_common,
4866 CALL,
4868 PUSHB_1,
4869 bci_upper_lower_bound,
4870 CALL,
4872 ENDF,
4878 * bci_serif_anchor_common
4880 * Common code for bci_action_serif_anchor routines.
4882 * sal: sal_anchor
4884 * uses: bci_round
4887 unsigned char FPGM(bci_serif_anchor_common) [] =
4890 PUSHB_1,
4891 bci_serif_anchor_common,
4892 FDEF,
4894 PUSHB_1,
4896 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4898 DUP,
4899 PUSHB_1,
4900 sal_anchor,
4901 SWAP,
4902 WS, /* sal_anchor = edge_point */
4904 DUP,
4905 DUP,
4906 DUP,
4907 GC_cur,
4908 SWAP,
4909 GC_orig,
4910 PUSHB_1,
4911 bci_round,
4912 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4913 SWAP,
4914 SUB,
4915 SHPIX, /* edge = round(edge_orig) */
4917 ENDF,
4923 * bci_action_serif_anchor
4925 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4926 * anchor.
4928 * in: edge_point (in twilight zone)
4929 * ... stuff for bci_align_segments (edge) ...
4931 * uses: bci_serif_anchor_common
4932 * bci_align_segments
4935 unsigned char FPGM(bci_action_serif_anchor) [] =
4938 PUSHB_1,
4939 bci_action_serif_anchor,
4940 FDEF,
4942 PUSHB_1,
4943 bci_serif_anchor_common,
4944 CALL,
4946 MDAP_noround, /* set rp0 and rp1 to `edge' */
4948 PUSHB_2,
4949 bci_align_segments,
4951 SZP1, /* set zp1 to normal zone 1 */
4952 CALL,
4954 ENDF,
4960 * bci_action_serif_anchor_lower_bound
4962 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4963 * anchor, then moving it again if necessary to stay within a lower
4964 * bound.
4966 * in: edge_point (in twilight zone)
4967 * edge[-1] (in twilight zone)
4968 * ... stuff for bci_align_segments (edge) ...
4970 * uses: bci_serif_anchor_common
4971 * bci_lower_bound
4974 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4977 PUSHB_1,
4978 bci_action_serif_anchor_lower_bound,
4979 FDEF,
4981 PUSHB_1,
4982 bci_serif_anchor_common,
4983 CALL,
4985 PUSHB_1,
4986 bci_lower_bound,
4987 CALL,
4989 ENDF,
4995 * bci_action_serif_anchor_upper_bound
4997 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4998 * anchor, then moving it again if necessary to stay within an upper
4999 * bound.
5001 * in: edge_point (in twilight zone)
5002 * edge[1] (in twilight zone)
5003 * ... stuff for bci_align_segments (edge) ...
5005 * uses: bci_serif_anchor_common
5006 * bci_upper_bound
5009 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5012 PUSHB_1,
5013 bci_action_serif_anchor_upper_bound,
5014 FDEF,
5016 PUSHB_1,
5017 bci_serif_anchor_common,
5018 CALL,
5020 PUSHB_1,
5021 bci_upper_bound,
5022 CALL,
5024 ENDF,
5030 * bci_action_serif_anchor_upper_lower_bound
5032 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5033 * anchor, then moving it again if necessary to stay within a lower and
5034 * upper bound.
5036 * in: edge_point (in twilight zone)
5037 * edge[-1] (in twilight zone)
5038 * edge[1] (in twilight zone)
5039 * ... stuff for bci_align_segments (edge) ...
5041 * uses: bci_serif_anchor_common
5042 * bci_upper_lower_bound
5045 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5048 PUSHB_1,
5049 bci_action_serif_anchor_upper_lower_bound,
5050 FDEF,
5052 PUSHB_1,
5053 bci_serif_anchor_common,
5054 CALL,
5056 PUSHB_1,
5057 bci_upper_lower_bound,
5058 CALL,
5060 ENDF,
5066 * bci_serif_link1_common
5068 * Common code for bci_action_serif_link1 routines.
5071 unsigned char FPGM(bci_serif_link1_common) [] =
5074 PUSHB_1,
5075 bci_serif_link1_common,
5076 FDEF,
5078 PUSHB_1,
5080 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5082 PUSHB_1,
5084 CINDEX, /* s: [...] after edge before after */
5085 PUSHB_1,
5087 CINDEX, /* s: [...] after edge before after before */
5088 MD_orig_ZP2_0,
5089 PUSHB_1,
5091 EQ, /* after_orig_pos == before_orig_pos */
5092 IF, /* s: [...] after edge before */
5093 MDAP_noround, /* set rp0 and rp1 to `before' */
5094 DUP,
5095 ALIGNRP, /* align `edge' with `before' */
5096 SWAP,
5097 POP,
5099 ELSE,
5100 /* we have to execute `a*b/c', with b/c very near to 1: */
5101 /* to avoid overflow while retaining precision, */
5102 /* we transform this to `a + a * (b-c)/c' */
5104 PUSHB_1,
5106 CINDEX, /* s: [...] after edge before edge */
5107 PUSHB_1,
5109 CINDEX, /* s: [...] after edge before edge before */
5110 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
5112 DUP,
5113 PUSHB_1,
5115 CINDEX, /* s: [...] after edge before a a after */
5116 PUSHB_1,
5118 CINDEX, /* s: [...] after edge before a a after before */
5119 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
5121 PUSHB_1,
5123 CINDEX, /* s: [...] after edge before a a c after */
5124 PUSHB_1,
5126 CINDEX, /* s: [...] after edge before a a c after before */
5127 MD_cur, /* b = after_pos - before_pos */
5129 PUSHB_1,
5131 CINDEX, /* s: [...] after edge before a a c b c */
5132 SUB, /* b-c */
5134 PUSHW_2,
5135 0x08, /* 0x800 */
5136 0x00,
5137 0x08, /* 0x800 */
5138 0x00,
5139 MUL, /* 0x10000 */
5140 MUL, /* (b-c) in 16.16 format */
5141 SWAP,
5143 DUP,
5144 IF, /* c != 0 ? */
5145 DIV, /* s: [...] after edge before a a (b-c)/c */
5146 ELSE,
5147 POP, /* avoid division by zero */
5148 EIF,
5150 MUL, /* a * (b-c)/c * 2^10 */
5151 DIV_BY_1024, /* a * (b-c)/c */
5152 ADD, /* a*b/c */
5154 SWAP,
5155 MDAP_noround, /* set rp0 and rp1 to `before' */
5156 SWAP, /* s: [...] after a*b/c edge */
5157 DUP,
5158 DUP,
5159 ALIGNRP, /* align `edge' with `before' */
5160 ROLL,
5161 SHPIX, /* shift `edge' by `a*b/c' */
5163 SWAP, /* s: [...] edge after */
5164 POP,
5165 EIF,
5167 ENDF,
5173 * bci_action_serif_link1
5175 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5176 * before and after.
5178 * in: before_point (in twilight zone)
5179 * edge_point (in twilight zone)
5180 * after_point (in twilight zone)
5181 * ... stuff for bci_align_segments (edge) ...
5183 * uses: bci_serif_link1_common
5184 * bci_align_segments
5187 unsigned char FPGM(bci_action_serif_link1) [] =
5190 PUSHB_1,
5191 bci_action_serif_link1,
5192 FDEF,
5194 PUSHB_1,
5195 bci_serif_link1_common,
5196 CALL,
5198 MDAP_noround, /* set rp0 and rp1 to `edge' */
5200 PUSHB_2,
5201 bci_align_segments,
5203 SZP1, /* set zp1 to normal zone 1 */
5204 CALL,
5206 ENDF,
5212 * bci_action_serif_link1_lower_bound
5214 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5215 * before and after. Additionally, move the serif again if necessary to
5216 * stay within a lower bound.
5218 * in: before_point (in twilight zone)
5219 * edge_point (in twilight zone)
5220 * after_point (in twilight zone)
5221 * edge[-1] (in twilight zone)
5222 * ... stuff for bci_align_segments (edge) ...
5224 * uses: bci_serif_link1_common
5225 * bci_lower_bound
5228 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
5231 PUSHB_1,
5232 bci_action_serif_link1_lower_bound,
5233 FDEF,
5235 PUSHB_1,
5236 bci_serif_link1_common,
5237 CALL,
5239 PUSHB_1,
5240 bci_lower_bound,
5241 CALL,
5243 ENDF,
5249 * bci_action_serif_link1_upper_bound
5251 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5252 * before and after. Additionally, move the serif again if necessary to
5253 * stay within an upper bound.
5255 * in: before_point (in twilight zone)
5256 * edge_point (in twilight zone)
5257 * after_point (in twilight zone)
5258 * edge[1] (in twilight zone)
5259 * ... stuff for bci_align_segments (edge) ...
5261 * uses: bci_serif_link1_common
5262 * bci_upper_bound
5265 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
5268 PUSHB_1,
5269 bci_action_serif_link1_upper_bound,
5270 FDEF,
5272 PUSHB_1,
5273 bci_serif_link1_common,
5274 CALL,
5276 PUSHB_1,
5277 bci_upper_bound,
5278 CALL,
5280 ENDF,
5286 * bci_action_serif_link1_upper_lower_bound
5288 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5289 * before and after. Additionally, move the serif again if necessary to
5290 * stay within a lower and upper bound.
5292 * in: before_point (in twilight zone)
5293 * edge_point (in twilight zone)
5294 * after_point (in twilight zone)
5295 * edge[-1] (in twilight zone)
5296 * edge[1] (in twilight zone)
5297 * ... stuff for bci_align_segments (edge) ...
5299 * uses: bci_serif_link1_common
5300 * bci_upper_lower_bound
5303 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
5306 PUSHB_1,
5307 bci_action_serif_link1_upper_lower_bound,
5308 FDEF,
5310 PUSHB_1,
5311 bci_serif_link1_common,
5312 CALL,
5314 PUSHB_1,
5315 bci_upper_lower_bound,
5316 CALL,
5318 ENDF,
5324 * bci_serif_link2_common
5326 * Common code for bci_action_serif_link2 routines.
5328 * sal: sal_anchor
5331 unsigned char FPGM(bci_serif_link2_common) [] =
5334 PUSHB_1,
5335 bci_serif_link2_common,
5336 FDEF,
5338 PUSHB_1,
5340 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5342 DUP, /* s: [...] edge edge */
5343 PUSHB_1,
5344 sal_anchor,
5346 DUP, /* s: [...] edge edge anchor anchor */
5347 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
5349 MD_orig_ZP2_0,
5350 DUP,
5351 ADD,
5352 PUSHB_1,
5354 ADD,
5355 FLOOR,
5356 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5358 SWAP,
5359 DUP,
5360 DUP,
5361 ALIGNRP, /* align `edge' with `sal_anchor' */
5362 ROLL,
5363 SHPIX, /* shift `edge' by `delta' */
5365 ENDF,
5371 * bci_action_serif_link2
5373 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5375 * in: edge_point (in twilight zone)
5376 * ... stuff for bci_align_segments (edge) ...
5378 * uses: bci_serif_link2_common
5379 * bci_align_segments
5382 unsigned char FPGM(bci_action_serif_link2) [] =
5385 PUSHB_1,
5386 bci_action_serif_link2,
5387 FDEF,
5389 PUSHB_1,
5390 bci_serif_link2_common,
5391 CALL,
5393 MDAP_noround, /* set rp0 and rp1 to `edge' */
5395 PUSHB_2,
5396 bci_align_segments,
5398 SZP1, /* set zp1 to normal zone 1 */
5399 CALL,
5401 ENDF,
5407 * bci_action_serif_link2_lower_bound
5409 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5410 * Additionally, move the serif again if necessary to stay within a lower
5411 * bound.
5413 * in: edge_point (in twilight zone)
5414 * edge[-1] (in twilight zone)
5415 * ... stuff for bci_align_segments (edge) ...
5417 * uses: bci_serif_link2_common
5418 * bci_lower_bound
5421 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
5424 PUSHB_1,
5425 bci_action_serif_link2_lower_bound,
5426 FDEF,
5428 PUSHB_1,
5429 bci_serif_link2_common,
5430 CALL,
5432 PUSHB_1,
5433 bci_lower_bound,
5434 CALL,
5436 ENDF,
5442 * bci_action_serif_link2_upper_bound
5444 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5445 * Additionally, move the serif again if necessary to stay within an upper
5446 * bound.
5448 * in: edge_point (in twilight zone)
5449 * edge[1] (in twilight zone)
5450 * ... stuff for bci_align_segments (edge) ...
5452 * uses: bci_serif_link2_common
5453 * bci_upper_bound
5456 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
5459 PUSHB_1,
5460 bci_action_serif_link2_upper_bound,
5461 FDEF,
5463 PUSHB_1,
5464 bci_serif_link2_common,
5465 CALL,
5467 PUSHB_1,
5468 bci_upper_bound,
5469 CALL,
5471 ENDF,
5477 * bci_action_serif_link2_upper_lower_bound
5479 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5480 * Additionally, move the serif again if necessary to stay within a lower
5481 * and upper bound.
5483 * in: edge_point (in twilight zone)
5484 * edge[-1] (in twilight zone)
5485 * edge[1] (in twilight zone)
5486 * ... stuff for bci_align_segments (edge) ...
5488 * uses: bci_serif_link2_common
5489 * bci_upper_lower_bound
5492 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
5495 PUSHB_1,
5496 bci_action_serif_link2_upper_lower_bound,
5497 FDEF,
5499 PUSHB_1,
5500 bci_serif_link2_common,
5501 CALL,
5503 PUSHB_1,
5504 bci_upper_lower_bound,
5505 CALL,
5507 ENDF,
5513 * bci_hint_glyph
5515 * This is the top-level glyph hinting function which parses the arguments
5516 * on the stack and calls subroutines.
5518 * in: action_0_func_idx
5519 * ... data ...
5520 * action_1_func_idx
5521 * ... data ...
5522 * ...
5524 * CVT: cvtl_is_subglyph
5525 * cvtl_use_strong_functions
5527 * sal: sal_stem_width_function
5529 * uses: bci_action_ip_before
5530 * bci_action_ip_after
5531 * bci_action_ip_on
5532 * bci_action_ip_between
5534 * bci_action_adjust_bound
5535 * bci_action_adjust_bound_serif
5536 * bci_action_adjust_bound_round
5537 * bci_action_adjust_bound_round_serif
5539 * bci_action_stem_bound
5540 * bci_action_stem_bound_serif
5541 * bci_action_stem_bound_round
5542 * bci_action_stem_bound_round_serif
5544 * bci_action_link
5545 * bci_action_link_serif
5546 * bci_action_link_round
5547 * bci_action_link_round_serif
5549 * bci_action_anchor
5550 * bci_action_anchor_serif
5551 * bci_action_anchor_round
5552 * bci_action_anchor_round_serif
5554 * bci_action_blue_anchor
5556 * bci_action_adjust
5557 * bci_action_adjust_serif
5558 * bci_action_adjust_round
5559 * bci_action_adjust_round_serif
5561 * bci_action_stem
5562 * bci_action_stem_serif
5563 * bci_action_stem_round
5564 * bci_action_stem_round_serif
5566 * bci_action_blue
5568 * bci_action_serif
5569 * bci_action_serif_lower_bound
5570 * bci_action_serif_upper_bound
5571 * bci_action_serif_upper_lower_bound
5573 * bci_action_serif_anchor
5574 * bci_action_serif_anchor_lower_bound
5575 * bci_action_serif_anchor_upper_bound
5576 * bci_action_serif_anchor_upper_lower_bound
5578 * bci_action_serif_link1
5579 * bci_action_serif_link1_lower_bound
5580 * bci_action_serif_link1_upper_bound
5581 * bci_action_serif_link1_upper_lower_bound
5583 * bci_action_serif_link2
5584 * bci_action_serif_link2_lower_bound
5585 * bci_action_serif_link2_upper_bound
5586 * bci_action_serif_link2_upper_lower_bound
5589 unsigned char FPGM(bci_hint_glyph) [] =
5592 PUSHB_1,
5593 bci_hint_glyph,
5594 FDEF,
5596 /* set up stem width function based on flag in CVT */
5597 PUSHB_4,
5598 sal_stem_width_function,
5599 bci_strong_stem_width,
5600 bci_smooth_stem_width,
5601 cvtl_use_strong_functions,
5602 RCVT,
5604 POP,
5606 ELSE,
5607 SWAP,
5608 POP,
5610 EIF,
5613 /* start_loop: */
5614 /* loop until all data on stack is used */
5615 CALL,
5616 PUSHB_1,
5618 NEG,
5619 PUSHB_1,
5621 DEPTH,
5623 JROT, /* goto start_loop */
5625 PUSHB_1,
5627 SZP2, /* set zp2 to normal zone 1 */
5628 IUP_y,
5630 ENDF,
5635 #define COPY_FPGM(func_name) \
5636 do \
5638 memcpy(bufp, fpgm_ ## func_name, \
5639 sizeof (fpgm_ ## func_name)); \
5640 bufp += sizeof (fpgm_ ## func_name); \
5641 } while (0)
5643 static FT_Error
5644 TA_table_build_fpgm(FT_Byte** fpgm,
5645 FT_ULong* fpgm_len,
5646 SFNT* sfnt,
5647 FONT* font)
5649 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5650 glyf_Data* data = (glyf_Data*)glyf_table->data;
5652 FT_UInt buf_len;
5653 FT_UInt len;
5654 FT_Byte* buf;
5655 FT_Byte* bufp;
5658 /* for compatibility with dumb bytecode interpreters or analyzers, */
5659 /* FDEFs are stored in ascending index order, without holes -- */
5660 /* note that some FDEFs are not always needed */
5661 /* (depending on options of `TTFautohint'), */
5662 /* but implementing dynamic FDEF indices would be a lot of work */
5664 buf_len = sizeof (FPGM(bci_align_top_a))
5665 + (font->increase_x_height
5666 ? (sizeof (FPGM(bci_align_top_b1a))
5668 + sizeof (FPGM(bci_align_top_b1b)))
5669 : sizeof (FPGM(bci_align_top_b2)))
5670 + sizeof (FPGM(bci_align_top_c))
5671 + sizeof (FPGM(bci_round))
5672 + sizeof (FPGM(bci_smooth_stem_width))
5673 + sizeof (FPGM(bci_get_best_width))
5674 + sizeof (FPGM(bci_strong_stem_width_a))
5676 + sizeof (FPGM(bci_strong_stem_width_b))
5677 + sizeof (FPGM(bci_loop_do))
5678 + sizeof (FPGM(bci_loop))
5679 + sizeof (FPGM(bci_cvt_rescale))
5680 + sizeof (FPGM(bci_cvt_rescale_range))
5681 + sizeof (FPGM(bci_vwidth_data_store))
5682 + sizeof (FPGM(bci_smooth_blue_round))
5683 + sizeof (FPGM(bci_strong_blue_round))
5684 + sizeof (FPGM(bci_blue_round_range))
5685 + sizeof (FPGM(bci_decrement_component_counter))
5686 + sizeof (FPGM(bci_get_point_extrema))
5687 + sizeof (FPGM(bci_nibbles))
5688 + sizeof (FPGM(bci_number_set_is_element))
5689 + sizeof (FPGM(bci_number_set_is_element2))
5691 + sizeof (FPGM(bci_create_segment))
5692 + sizeof (FPGM(bci_create_segments_a))
5694 + sizeof (FPGM(bci_create_segments_b))
5695 + (font->control_data_head != 0
5696 ? sizeof (FPGM(bci_create_segments_c))
5697 : 0)
5698 + sizeof (FPGM(bci_create_segments_d))
5700 + sizeof (FPGM(bci_create_segments_0))
5701 + sizeof (FPGM(bci_create_segments_1))
5702 + sizeof (FPGM(bci_create_segments_2))
5703 + sizeof (FPGM(bci_create_segments_3))
5704 + sizeof (FPGM(bci_create_segments_4))
5705 + sizeof (FPGM(bci_create_segments_5))
5706 + sizeof (FPGM(bci_create_segments_6))
5707 + sizeof (FPGM(bci_create_segments_7))
5708 + sizeof (FPGM(bci_create_segments_8))
5709 + sizeof (FPGM(bci_create_segments_9))
5711 + sizeof (FPGM(bci_create_segments_composite_a))
5713 + sizeof (FPGM(bci_create_segments_composite_b))
5714 + (font->control_data_head != 0
5715 ? sizeof (FPGM(bci_create_segments_composite_c))
5716 : 0)
5717 + sizeof (FPGM(bci_create_segments_composite_d))
5719 + sizeof (FPGM(bci_create_segments_composite_0))
5720 + sizeof (FPGM(bci_create_segments_composite_1))
5721 + sizeof (FPGM(bci_create_segments_composite_2))
5722 + sizeof (FPGM(bci_create_segments_composite_3))
5723 + sizeof (FPGM(bci_create_segments_composite_4))
5724 + sizeof (FPGM(bci_create_segments_composite_5))
5725 + sizeof (FPGM(bci_create_segments_composite_6))
5726 + sizeof (FPGM(bci_create_segments_composite_7))
5727 + sizeof (FPGM(bci_create_segments_composite_8))
5728 + sizeof (FPGM(bci_create_segments_composite_9))
5730 + sizeof (FPGM(bci_align_point))
5731 + sizeof (FPGM(bci_align_segment))
5732 + sizeof (FPGM(bci_align_segments))
5734 + sizeof (FPGM(bci_scale_contour))
5735 + sizeof (FPGM(bci_scale_glyph))
5736 + sizeof (FPGM(bci_scale_composite_glyph))
5737 + sizeof (FPGM(bci_shift_contour))
5738 + sizeof (FPGM(bci_shift_subglyph_a))
5739 + (font->control_data_head != 0
5740 ? sizeof (FPGM(bci_shift_subglyph_b))
5741 : 0)
5742 + sizeof (FPGM(bci_shift_subglyph_c))
5744 + sizeof (FPGM(bci_ip_outer_align_point))
5745 + sizeof (FPGM(bci_ip_on_align_points))
5746 + sizeof (FPGM(bci_ip_between_align_point))
5747 + sizeof (FPGM(bci_ip_between_align_points))
5749 + sizeof (FPGM(bci_adjust_common))
5750 + sizeof (FPGM(bci_stem_common))
5751 + sizeof (FPGM(bci_serif_common))
5752 + sizeof (FPGM(bci_serif_anchor_common))
5753 + sizeof (FPGM(bci_serif_link1_common))
5754 + sizeof (FPGM(bci_serif_link2_common))
5756 + sizeof (FPGM(bci_lower_bound))
5757 + sizeof (FPGM(bci_upper_bound))
5758 + sizeof (FPGM(bci_upper_lower_bound))
5760 + sizeof (FPGM(bci_adjust_bound))
5761 + sizeof (FPGM(bci_stem_bound))
5762 + sizeof (FPGM(bci_link))
5763 + sizeof (FPGM(bci_anchor))
5764 + sizeof (FPGM(bci_adjust))
5765 + sizeof (FPGM(bci_stem))
5767 + sizeof (FPGM(bci_action_ip_before))
5768 + sizeof (FPGM(bci_action_ip_after))
5769 + sizeof (FPGM(bci_action_ip_on))
5770 + sizeof (FPGM(bci_action_ip_between))
5772 + sizeof (FPGM(bci_action_blue))
5773 + sizeof (FPGM(bci_action_blue_anchor))
5775 + sizeof (FPGM(bci_action_anchor))
5776 + sizeof (FPGM(bci_action_anchor_serif))
5777 + sizeof (FPGM(bci_action_anchor_round))
5778 + sizeof (FPGM(bci_action_anchor_round_serif))
5780 + sizeof (FPGM(bci_action_adjust))
5781 + sizeof (FPGM(bci_action_adjust_serif))
5782 + sizeof (FPGM(bci_action_adjust_round))
5783 + sizeof (FPGM(bci_action_adjust_round_serif))
5784 + sizeof (FPGM(bci_action_adjust_bound))
5785 + sizeof (FPGM(bci_action_adjust_bound_serif))
5786 + sizeof (FPGM(bci_action_adjust_bound_round))
5787 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5789 + sizeof (FPGM(bci_action_link))
5790 + sizeof (FPGM(bci_action_link_serif))
5791 + sizeof (FPGM(bci_action_link_round))
5792 + sizeof (FPGM(bci_action_link_round_serif))
5794 + sizeof (FPGM(bci_action_stem))
5795 + sizeof (FPGM(bci_action_stem_serif))
5796 + sizeof (FPGM(bci_action_stem_round))
5797 + sizeof (FPGM(bci_action_stem_round_serif))
5798 + sizeof (FPGM(bci_action_stem_bound))
5799 + sizeof (FPGM(bci_action_stem_bound_serif))
5800 + sizeof (FPGM(bci_action_stem_bound_round))
5801 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5803 + sizeof (FPGM(bci_action_serif))
5804 + sizeof (FPGM(bci_action_serif_lower_bound))
5805 + sizeof (FPGM(bci_action_serif_upper_bound))
5806 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5808 + sizeof (FPGM(bci_action_serif_anchor))
5809 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5810 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5811 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5813 + sizeof (FPGM(bci_action_serif_link1))
5814 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5815 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5816 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5818 + sizeof (FPGM(bci_action_serif_link2))
5819 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5820 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5821 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5823 + sizeof (FPGM(bci_hint_glyph));
5825 /* buffer length must be a multiple of four */
5826 len = (buf_len + 3) & ~3;
5827 buf = (FT_Byte*)malloc(len);
5828 if (!buf)
5829 return FT_Err_Out_Of_Memory;
5831 /* pad end of buffer with zeros */
5832 buf[len - 1] = 0x00;
5833 buf[len - 2] = 0x00;
5834 buf[len - 3] = 0x00;
5836 /* copy font program into buffer and fill in the missing variables */
5837 bufp = buf;
5839 COPY_FPGM(bci_align_top_a);
5840 if (font->increase_x_height)
5842 COPY_FPGM(bci_align_top_b1a);
5843 *(bufp++) = HIGH(font->increase_x_height);
5844 *(bufp++) = LOW(font->increase_x_height);
5845 COPY_FPGM(bci_align_top_b1b);
5847 else
5848 COPY_FPGM(bci_align_top_b2);
5849 COPY_FPGM(bci_align_top_c);
5851 COPY_FPGM(bci_round);
5852 COPY_FPGM(bci_smooth_stem_width);
5853 COPY_FPGM(bci_get_best_width);
5854 COPY_FPGM(bci_strong_stem_width_a);
5855 *(bufp++) = (unsigned char)data->num_used_styles;
5856 COPY_FPGM(bci_strong_stem_width_b);
5857 COPY_FPGM(bci_loop_do);
5858 COPY_FPGM(bci_loop);
5859 COPY_FPGM(bci_cvt_rescale);
5860 COPY_FPGM(bci_cvt_rescale_range);
5861 COPY_FPGM(bci_vwidth_data_store);
5862 COPY_FPGM(bci_smooth_blue_round);
5863 COPY_FPGM(bci_strong_blue_round);
5864 COPY_FPGM(bci_blue_round_range);
5865 COPY_FPGM(bci_decrement_component_counter);
5866 COPY_FPGM(bci_get_point_extrema);
5867 COPY_FPGM(bci_nibbles);
5868 COPY_FPGM(bci_number_set_is_element);
5869 COPY_FPGM(bci_number_set_is_element2);
5871 COPY_FPGM(bci_create_segment);
5872 COPY_FPGM(bci_create_segments_a);
5873 *(bufp++) = (unsigned char)data->num_used_styles;
5874 COPY_FPGM(bci_create_segments_b);
5875 if (font->control_data_head)
5876 COPY_FPGM(bci_create_segments_c);
5877 COPY_FPGM(bci_create_segments_d);
5879 COPY_FPGM(bci_create_segments_0);
5880 COPY_FPGM(bci_create_segments_1);
5881 COPY_FPGM(bci_create_segments_2);
5882 COPY_FPGM(bci_create_segments_3);
5883 COPY_FPGM(bci_create_segments_4);
5884 COPY_FPGM(bci_create_segments_5);
5885 COPY_FPGM(bci_create_segments_6);
5886 COPY_FPGM(bci_create_segments_7);
5887 COPY_FPGM(bci_create_segments_8);
5888 COPY_FPGM(bci_create_segments_9);
5890 COPY_FPGM(bci_create_segments_composite_a);
5891 *(bufp++) = (unsigned char)data->num_used_styles;
5892 COPY_FPGM(bci_create_segments_composite_b);
5893 if (font->control_data_head)
5894 COPY_FPGM(bci_create_segments_composite_c);
5895 COPY_FPGM(bci_create_segments_composite_d);
5897 COPY_FPGM(bci_create_segments_composite_0);
5898 COPY_FPGM(bci_create_segments_composite_1);
5899 COPY_FPGM(bci_create_segments_composite_2);
5900 COPY_FPGM(bci_create_segments_composite_3);
5901 COPY_FPGM(bci_create_segments_composite_4);
5902 COPY_FPGM(bci_create_segments_composite_5);
5903 COPY_FPGM(bci_create_segments_composite_6);
5904 COPY_FPGM(bci_create_segments_composite_7);
5905 COPY_FPGM(bci_create_segments_composite_8);
5906 COPY_FPGM(bci_create_segments_composite_9);
5908 COPY_FPGM(bci_align_point);
5909 COPY_FPGM(bci_align_segment);
5910 COPY_FPGM(bci_align_segments);
5912 COPY_FPGM(bci_scale_contour);
5913 COPY_FPGM(bci_scale_glyph);
5914 COPY_FPGM(bci_scale_composite_glyph);
5915 COPY_FPGM(bci_shift_contour);
5916 COPY_FPGM(bci_shift_subglyph_a);
5917 if (font->control_data_head)
5918 COPY_FPGM(bci_shift_subglyph_b);
5919 COPY_FPGM(bci_shift_subglyph_c);
5921 COPY_FPGM(bci_ip_outer_align_point);
5922 COPY_FPGM(bci_ip_on_align_points);
5923 COPY_FPGM(bci_ip_between_align_point);
5924 COPY_FPGM(bci_ip_between_align_points);
5926 COPY_FPGM(bci_adjust_common);
5927 COPY_FPGM(bci_stem_common);
5928 COPY_FPGM(bci_serif_common);
5929 COPY_FPGM(bci_serif_anchor_common);
5930 COPY_FPGM(bci_serif_link1_common);
5931 COPY_FPGM(bci_serif_link2_common);
5933 COPY_FPGM(bci_lower_bound);
5934 COPY_FPGM(bci_upper_bound);
5935 COPY_FPGM(bci_upper_lower_bound);
5937 COPY_FPGM(bci_adjust_bound);
5938 COPY_FPGM(bci_stem_bound);
5939 COPY_FPGM(bci_link);
5940 COPY_FPGM(bci_anchor);
5941 COPY_FPGM(bci_adjust);
5942 COPY_FPGM(bci_stem);
5944 COPY_FPGM(bci_action_ip_before);
5945 COPY_FPGM(bci_action_ip_after);
5946 COPY_FPGM(bci_action_ip_on);
5947 COPY_FPGM(bci_action_ip_between);
5949 COPY_FPGM(bci_action_blue);
5950 COPY_FPGM(bci_action_blue_anchor);
5952 COPY_FPGM(bci_action_anchor);
5953 COPY_FPGM(bci_action_anchor_serif);
5954 COPY_FPGM(bci_action_anchor_round);
5955 COPY_FPGM(bci_action_anchor_round_serif);
5957 COPY_FPGM(bci_action_adjust);
5958 COPY_FPGM(bci_action_adjust_serif);
5959 COPY_FPGM(bci_action_adjust_round);
5960 COPY_FPGM(bci_action_adjust_round_serif);
5961 COPY_FPGM(bci_action_adjust_bound);
5962 COPY_FPGM(bci_action_adjust_bound_serif);
5963 COPY_FPGM(bci_action_adjust_bound_round);
5964 COPY_FPGM(bci_action_adjust_bound_round_serif);
5966 COPY_FPGM(bci_action_link);
5967 COPY_FPGM(bci_action_link_serif);
5968 COPY_FPGM(bci_action_link_round);
5969 COPY_FPGM(bci_action_link_round_serif);
5971 COPY_FPGM(bci_action_stem);
5972 COPY_FPGM(bci_action_stem_serif);
5973 COPY_FPGM(bci_action_stem_round);
5974 COPY_FPGM(bci_action_stem_round_serif);
5975 COPY_FPGM(bci_action_stem_bound);
5976 COPY_FPGM(bci_action_stem_bound_serif);
5977 COPY_FPGM(bci_action_stem_bound_round);
5978 COPY_FPGM(bci_action_stem_bound_round_serif);
5980 COPY_FPGM(bci_action_serif);
5981 COPY_FPGM(bci_action_serif_lower_bound);
5982 COPY_FPGM(bci_action_serif_upper_bound);
5983 COPY_FPGM(bci_action_serif_upper_lower_bound);
5985 COPY_FPGM(bci_action_serif_anchor);
5986 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5987 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5988 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5990 COPY_FPGM(bci_action_serif_link1);
5991 COPY_FPGM(bci_action_serif_link1_lower_bound);
5992 COPY_FPGM(bci_action_serif_link1_upper_bound);
5993 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5995 COPY_FPGM(bci_action_serif_link2);
5996 COPY_FPGM(bci_action_serif_link2_lower_bound);
5997 COPY_FPGM(bci_action_serif_link2_upper_bound);
5998 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
6000 COPY_FPGM(bci_hint_glyph);
6002 *fpgm = buf;
6003 *fpgm_len = buf_len;
6005 return FT_Err_Ok;
6009 FT_Error
6010 TA_sfnt_build_fpgm_table(SFNT* sfnt,
6011 FONT* font)
6013 FT_Error error;
6015 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6016 glyf_Data* data = (glyf_Data*)glyf_table->data;
6018 FT_Byte* fpgm_buf;
6019 FT_ULong fpgm_len;
6022 error = TA_sfnt_add_table_info(sfnt);
6023 if (error)
6024 goto Exit;
6026 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
6027 if (glyf_table->processed)
6029 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
6030 goto Exit;
6033 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
6034 if (error)
6035 goto Exit;
6037 if (fpgm_len > sfnt->max_instructions)
6038 sfnt->max_instructions = fpgm_len;
6040 /* in case of success, `fpgm_buf' gets linked */
6041 /* and is eventually freed in `TA_font_unload' */
6042 error = TA_font_add_table(font,
6043 &sfnt->table_infos[sfnt->num_table_infos - 1],
6044 TTAG_fpgm, fpgm_len, fpgm_buf);
6045 if (error)
6046 free(fpgm_buf);
6047 else
6048 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
6050 Exit:
6051 return error;
6054 /* end of tafpgm.c */