Add function to read a delta exceptions file.
[ttfautohint.git] / lib / tafpgm.c
blob40a0098f2d930beee7cb6011c785d2c5f0f947cd
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,
1836 ELSE,
1837 CLEAR,
1838 EIF,
1840 ENDF,
1846 * bci_create_segments_X
1848 * Top-level routines for calling `bci_create_segments'.
1851 unsigned char FPGM(bci_create_segments_0) [] =
1854 PUSHB_1,
1855 bci_create_segments_0,
1856 FDEF,
1858 PUSHB_2,
1860 bci_create_segments,
1861 CALL,
1863 ENDF,
1867 unsigned char FPGM(bci_create_segments_1) [] =
1870 PUSHB_1,
1871 bci_create_segments_1,
1872 FDEF,
1874 PUSHB_2,
1876 bci_create_segments,
1877 CALL,
1879 ENDF,
1883 unsigned char FPGM(bci_create_segments_2) [] =
1886 PUSHB_1,
1887 bci_create_segments_2,
1888 FDEF,
1890 PUSHB_2,
1892 bci_create_segments,
1893 CALL,
1895 ENDF,
1899 unsigned char FPGM(bci_create_segments_3) [] =
1902 PUSHB_1,
1903 bci_create_segments_3,
1904 FDEF,
1906 PUSHB_2,
1908 bci_create_segments,
1909 CALL,
1911 ENDF,
1915 unsigned char FPGM(bci_create_segments_4) [] =
1918 PUSHB_1,
1919 bci_create_segments_4,
1920 FDEF,
1922 PUSHB_2,
1924 bci_create_segments,
1925 CALL,
1927 ENDF,
1931 unsigned char FPGM(bci_create_segments_5) [] =
1934 PUSHB_1,
1935 bci_create_segments_5,
1936 FDEF,
1938 PUSHB_2,
1940 bci_create_segments,
1941 CALL,
1943 ENDF,
1947 unsigned char FPGM(bci_create_segments_6) [] =
1950 PUSHB_1,
1951 bci_create_segments_6,
1952 FDEF,
1954 PUSHB_2,
1956 bci_create_segments,
1957 CALL,
1959 ENDF,
1963 unsigned char FPGM(bci_create_segments_7) [] =
1966 PUSHB_1,
1967 bci_create_segments_7,
1968 FDEF,
1970 PUSHB_2,
1972 bci_create_segments,
1973 CALL,
1975 ENDF,
1979 unsigned char FPGM(bci_create_segments_8) [] =
1982 PUSHB_1,
1983 bci_create_segments_8,
1984 FDEF,
1986 PUSHB_2,
1988 bci_create_segments,
1989 CALL,
1991 ENDF,
1995 unsigned char FPGM(bci_create_segments_9) [] =
1998 PUSHB_1,
1999 bci_create_segments_9,
2000 FDEF,
2002 PUSHB_2,
2004 bci_create_segments,
2005 CALL,
2007 ENDF,
2013 * bci_create_segments_composite
2015 * The same as `bci_create_segments'.
2016 * It also decrements the composite component counter.
2018 * sal: sal_num_packed_segments
2019 * sal_segment_offset
2020 * sal_vwidth_data_offset
2022 * CVT: cvtl_is_subglyph
2024 * uses: bci_decrement_component_counter
2025 * bci_create_segment
2026 * bci_loop
2027 * bci_hint_glyph
2030 unsigned char FPGM(bci_create_segments_composite_a) [] =
2033 PUSHB_1,
2034 bci_create_segments_composite,
2035 FDEF,
2037 /* all our measurements are taken along the y axis */
2038 SVTCA_y,
2040 PUSHB_1,
2041 bci_decrement_component_counter,
2042 CALL,
2044 /* only do something if we are not a subglyph */
2045 PUSHB_2,
2047 cvtl_is_subglyph,
2048 RCVT,
2051 PUSHB_1,
2052 sal_num_packed_segments,
2053 SWAP,
2056 DUP,
2057 RCVT,
2058 PUSHB_1,
2059 sal_scale, /* sal_scale = CVT(data_offset) */
2060 SWAP,
2063 PUSHB_1,
2064 sal_vwidth_data_offset,
2065 SWAP,
2066 PUSHB_1,
2070 /* %c, number of used styles */
2072 unsigned char FPGM(bci_create_segments_composite_b) [] =
2075 ADD,
2076 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2078 DUP,
2079 ADD,
2080 PUSHB_1,
2082 SUB, /* delta = (2*num_segments - 1) */
2084 PUSHB_6,
2085 sal_segment_offset,
2086 sal_segment_offset,
2088 sal_j,
2090 sal_base,
2092 WS, /* sal_base = 0 */
2093 WS, /* sal_j = 0 (point offset) */
2095 ROLL,
2096 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2098 PUSHB_2,
2099 bci_create_segment,
2100 bci_loop,
2101 CALL,
2103 PUSHB_1,
2104 bci_hint_glyph,
2105 CALL,
2107 ELSE,
2108 CLEAR,
2109 EIF,
2111 ENDF,
2117 * bci_create_segments_composite_X
2119 * Top-level routines for calling `bci_create_segments_composite'.
2122 unsigned char FPGM(bci_create_segments_composite_0) [] =
2125 PUSHB_1,
2126 bci_create_segments_composite_0,
2127 FDEF,
2129 PUSHB_2,
2131 bci_create_segments_composite,
2132 CALL,
2134 ENDF,
2138 unsigned char FPGM(bci_create_segments_composite_1) [] =
2141 PUSHB_1,
2142 bci_create_segments_composite_1,
2143 FDEF,
2145 PUSHB_2,
2147 bci_create_segments_composite,
2148 CALL,
2150 ENDF,
2154 unsigned char FPGM(bci_create_segments_composite_2) [] =
2157 PUSHB_1,
2158 bci_create_segments_composite_2,
2159 FDEF,
2161 PUSHB_2,
2163 bci_create_segments_composite,
2164 CALL,
2166 ENDF,
2170 unsigned char FPGM(bci_create_segments_composite_3) [] =
2173 PUSHB_1,
2174 bci_create_segments_composite_3,
2175 FDEF,
2177 PUSHB_2,
2179 bci_create_segments_composite,
2180 CALL,
2182 ENDF,
2186 unsigned char FPGM(bci_create_segments_composite_4) [] =
2189 PUSHB_1,
2190 bci_create_segments_composite_4,
2191 FDEF,
2193 PUSHB_2,
2195 bci_create_segments_composite,
2196 CALL,
2198 ENDF,
2202 unsigned char FPGM(bci_create_segments_composite_5) [] =
2205 PUSHB_1,
2206 bci_create_segments_composite_5,
2207 FDEF,
2209 PUSHB_2,
2211 bci_create_segments_composite,
2212 CALL,
2214 ENDF,
2218 unsigned char FPGM(bci_create_segments_composite_6) [] =
2221 PUSHB_1,
2222 bci_create_segments_composite_6,
2223 FDEF,
2225 PUSHB_2,
2227 bci_create_segments_composite,
2228 CALL,
2230 ENDF,
2234 unsigned char FPGM(bci_create_segments_composite_7) [] =
2237 PUSHB_1,
2238 bci_create_segments_composite_7,
2239 FDEF,
2241 PUSHB_2,
2243 bci_create_segments_composite,
2244 CALL,
2246 ENDF,
2250 unsigned char FPGM(bci_create_segments_composite_8) [] =
2253 PUSHB_1,
2254 bci_create_segments_composite_8,
2255 FDEF,
2257 PUSHB_2,
2259 bci_create_segments_composite,
2260 CALL,
2262 ENDF,
2266 unsigned char FPGM(bci_create_segments_composite_9) [] =
2269 PUSHB_1,
2270 bci_create_segments_composite_9,
2271 FDEF,
2273 PUSHB_2,
2275 bci_create_segments_composite,
2276 CALL,
2278 ENDF,
2284 * bci_align_point
2286 * An auxiliary function for `bci_align_segment'.
2288 * in: point
2290 * out: point+1
2293 unsigned char FPGM(bci_align_point) [] =
2296 PUSHB_1,
2297 bci_align_point,
2298 FDEF,
2300 DUP,
2301 ALIGNRP, /* align point with rp0 */
2303 PUSHB_1,
2305 ADD,
2307 ENDF,
2313 * bci_align_segment
2315 * Align all points in a segment to the twilight point in rp0.
2316 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2318 * in: segment_index
2320 * sal: sal_segment_offset
2322 * uses: bci_align_point
2325 unsigned char FPGM(bci_align_segment) [] =
2328 PUSHB_1,
2329 bci_align_segment,
2330 FDEF,
2332 /* we need the values of `sal_segment_offset + 2*segment_index' */
2333 /* and `sal_segment_offset + 2*segment_index + 1' */
2334 DUP,
2335 ADD,
2336 PUSHB_1,
2337 sal_segment_offset,
2338 ADD,
2339 DUP,
2341 SWAP,
2342 PUSHB_1,
2344 ADD,
2345 RS, /* s: first last */
2347 PUSHB_1,
2349 CINDEX, /* s: first last first */
2350 SUB,
2351 PUSHB_1,
2353 ADD, /* s: first loop_count */
2355 PUSHB_1,
2356 bci_align_point,
2357 LOOPCALL,
2358 /* clean up stack */
2359 POP,
2361 ENDF,
2367 * bci_align_segments
2369 * Align segments to the twilight point in rp0.
2370 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2372 * in: first_segment
2373 * loop_counter (N)
2374 * segment_1
2375 * segment_2
2376 * ...
2377 * segment_N
2379 * uses: bci_align_segment
2382 unsigned char FPGM(bci_align_segments) [] =
2385 PUSHB_1,
2386 bci_align_segments,
2387 FDEF,
2389 PUSHB_1,
2390 bci_align_segment,
2391 CALL,
2393 PUSHB_1,
2394 bci_align_segment,
2395 LOOPCALL,
2397 ENDF,
2403 * bci_scale_contour
2405 * Scale a contour using two points giving the maximum and minimum
2406 * coordinates.
2408 * It expects that no point on the contour is touched.
2410 * in: min_point
2411 * max_point
2413 * sal: sal_scale
2416 unsigned char FPGM(bci_scale_contour) [] =
2419 PUSHB_1,
2420 bci_scale_contour,
2421 FDEF,
2423 DUP,
2424 DUP,
2425 GC_orig,
2426 DUP,
2427 DO_SCALE, /* min_pos_new = min_pos * scale */
2428 SWAP,
2429 SUB,
2430 SHPIX,
2432 /* don't scale a single-point contour twice */
2433 SWAP,
2434 DUP,
2435 ROLL,
2436 NEQ,
2438 DUP,
2439 GC_orig,
2440 DUP,
2441 DO_SCALE, /* max_pos_new = max_pos * scale */
2442 SWAP,
2443 SUB,
2444 SHPIX,
2446 ELSE,
2447 POP,
2448 EIF,
2450 ENDF,
2456 * bci_scale_glyph
2458 * Scale a glyph using a list of points (two points per contour, giving
2459 * the maximum and mininum coordinates).
2461 * It expects that no point in the glyph is touched.
2463 * Note that the point numbers are sorted in ascending order;
2464 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2465 * contour without specifying which one is the minimum and maximum.
2467 * in: num_contours (N)
2468 * min_point_1
2469 * max_point_1
2470 * min_point_2
2471 * max_point_2
2472 * ...
2473 * min_point_N
2474 * max_point_N
2476 * CVT: cvtl_is_subglyph
2478 * uses: bci_scale_contour
2481 unsigned char FPGM(bci_scale_glyph) [] =
2484 PUSHB_1,
2485 bci_scale_glyph,
2486 FDEF,
2488 /* all our measurements are taken along the y axis */
2489 SVTCA_y,
2491 /* only do something if we are not a subglyph */
2492 PUSHB_2,
2494 cvtl_is_subglyph,
2495 RCVT,
2498 PUSHB_1,
2500 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2502 PUSHB_1,
2503 bci_scale_contour,
2504 LOOPCALL,
2506 PUSHB_1,
2508 SZP2, /* set zp2 to normal zone 1 */
2509 IUP_y,
2511 ELSE,
2512 CLEAR,
2513 EIF,
2515 ENDF,
2521 * bci_scale_composite_glyph
2523 * The same as `bci_scale_glyph'.
2524 * It also decrements the composite component counter.
2526 * CVT: cvtl_is_subglyph
2528 * uses: bci_decrement_component_counter
2529 * bci_scale_contour
2532 unsigned char FPGM(bci_scale_composite_glyph) [] =
2535 PUSHB_1,
2536 bci_scale_composite_glyph,
2537 FDEF,
2539 /* all our measurements are taken along the y axis */
2540 SVTCA_y,
2542 PUSHB_1,
2543 bci_decrement_component_counter,
2544 CALL,
2546 /* only do something if we are not a subglyph */
2547 PUSHB_2,
2549 cvtl_is_subglyph,
2550 RCVT,
2553 PUSHB_1,
2555 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2557 PUSHB_1,
2558 bci_scale_contour,
2559 LOOPCALL,
2561 PUSHB_1,
2563 SZP2, /* set zp2 to normal zone 1 */
2564 IUP_y,
2566 ELSE,
2567 CLEAR,
2568 EIF,
2570 ENDF,
2576 * bci_shift_contour
2578 * Shift a contour by a given amount.
2580 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2581 * point to the normal zone 1.
2583 * in: contour
2585 * out: contour+1
2588 unsigned char FPGM(bci_shift_contour) [] =
2591 PUSHB_1,
2592 bci_shift_contour,
2593 FDEF,
2595 DUP,
2596 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2598 PUSHB_1,
2600 ADD,
2602 ENDF,
2608 * bci_shift_subglyph
2610 * Shift a subglyph. To be more specific, it corrects the already applied
2611 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2612 * also.
2614 * If this function is called, a point `x' in the subglyph has been scaled
2615 * already (during the hinting of the subglyph itself), and `offset' has
2616 * been applied also:
2618 * x -> x * scale + offset (1)
2620 * However, the offset should be applied first, then the scaling:
2622 * x -> (x + offset) * scale (2)
2624 * Our job is now to transform (1) to (2); a simple calculation shows that
2625 * we have to shift all points of the subglyph by
2627 * offset * scale - offset = offset * (scale - 1)
2629 * Note that `sal_scale' is equal to the above `scale - 1'.
2631 * in: offset (in FUnits)
2632 * num_contours
2633 * first_contour
2635 * CVT: cvtl_funits_to_pixels
2637 * sal: sal_scale
2639 * uses: bci_round
2640 * bci_shift_contour
2643 unsigned char FPGM(bci_shift_subglyph) [] =
2646 PUSHB_1,
2647 bci_shift_subglyph,
2648 FDEF,
2650 /* all our measurements are taken along the y axis */
2651 SVTCA_y,
2653 PUSHB_1,
2654 cvtl_funits_to_pixels,
2655 RCVT, /* scaling factor FUnits -> pixels */
2656 MUL,
2657 DIV_BY_1024,
2659 /* the autohinter always rounds offsets */
2660 PUSHB_1,
2661 bci_round,
2662 CALL, /* offset = round(offset) */
2664 PUSHB_1,
2665 sal_scale,
2667 MUL,
2668 DIV_BY_1024, /* delta = offset * (scale - 1) */
2670 /* and round again */
2671 PUSHB_1,
2672 bci_round,
2673 CALL, /* offset = round(offset) */
2675 PUSHB_1,
2677 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2679 /* we create twilight point 0 as a reference point, */
2680 /* setting the original position to zero (using `cvtl_temp') */
2681 PUSHB_5,
2684 cvtl_temp,
2685 cvtl_temp,
2687 WCVTP,
2688 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2690 SWAP, /* s: first_contour num_contours 0 delta */
2691 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2693 PUSHB_2,
2694 bci_shift_contour,
2696 SZP2, /* set zp2 to normal zone 1 */
2697 LOOPCALL,
2699 ENDF,
2705 * bci_ip_outer_align_point
2707 * Auxiliary function for `bci_action_ip_before' and
2708 * `bci_action_ip_after'.
2710 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2711 * zone, and both zp1 and zp2 set to normal zone.
2713 * in: point
2715 * sal: sal_i (edge_orig_pos)
2716 * sal_scale
2719 unsigned char FPGM(bci_ip_outer_align_point) [] =
2722 PUSHB_1,
2723 bci_ip_outer_align_point,
2724 FDEF,
2726 DUP,
2727 ALIGNRP, /* align `point' with `edge' */
2728 DUP,
2729 GC_orig,
2730 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2732 PUSHB_1,
2733 sal_i,
2735 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2736 SHPIX,
2738 ENDF,
2744 * bci_ip_on_align_points
2746 * Auxiliary function for `bci_action_ip_on'.
2748 * in: edge (in twilight zone)
2749 * loop_counter (N)
2750 * point_1
2751 * point_2
2752 * ...
2753 * point_N
2756 unsigned char FPGM(bci_ip_on_align_points) [] =
2759 PUSHB_1,
2760 bci_ip_on_align_points,
2761 FDEF,
2763 MDAP_noround, /* set rp0 and rp1 to `edge' */
2765 SLOOP,
2766 ALIGNRP,
2768 ENDF,
2774 * bci_ip_between_align_point
2776 * Auxiliary function for `bci_ip_between_align_points'.
2778 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2779 * zone, and both zp1 and zp2 set to normal zone.
2781 * in: point
2783 * sal: sal_i (edge_orig_pos)
2784 * sal_j (stretch_factor)
2785 * sal_scale
2788 unsigned char FPGM(bci_ip_between_align_point) [] =
2791 PUSHB_1,
2792 bci_ip_between_align_point,
2793 FDEF,
2795 DUP,
2796 ALIGNRP, /* align `point' with `edge' */
2797 DUP,
2798 GC_orig,
2799 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2801 PUSHB_1,
2802 sal_i,
2804 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2805 PUSHB_1,
2806 sal_j,
2808 MUL, /* s: point delta */
2809 SHPIX,
2811 ENDF,
2817 * bci_ip_between_align_points
2819 * Auxiliary function for `bci_action_ip_between'.
2821 * in: after_edge (in twilight zone)
2822 * before_edge (in twilight zone)
2823 * loop_counter (N)
2824 * point_1
2825 * point_2
2826 * ...
2827 * point_N
2829 * sal: sal_i (before_orig_pos)
2830 * sal_j (stretch_factor)
2832 * uses: bci_ip_between_align_point
2835 unsigned char FPGM(bci_ip_between_align_points) [] =
2838 PUSHB_1,
2839 bci_ip_between_align_points,
2840 FDEF,
2842 PUSHB_2,
2845 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2846 CINDEX,
2847 DUP, /* s: ... before after before before */
2848 MDAP_noround, /* set rp0 and rp1 to `before' */
2849 DUP,
2850 GC_orig, /* s: ... before after before before_orig_pos */
2851 PUSHB_1,
2852 sal_i,
2853 SWAP,
2854 WS, /* sal_i = before_orig_pos */
2855 PUSHB_1,
2857 CINDEX, /* s: ... before after before after */
2858 MD_cur, /* a = after_pos - before_pos */
2859 ROLL,
2860 ROLL,
2861 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2863 DUP,
2864 IF, /* b != 0 ? */
2865 DIV, /* s: a/b */
2866 ELSE,
2867 POP, /* avoid division by zero */
2868 EIF,
2870 PUSHB_1,
2871 sal_j,
2872 SWAP,
2873 WS, /* sal_j = stretch_factor */
2875 PUSHB_3,
2876 bci_ip_between_align_point,
2879 SZP2, /* set zp2 to normal zone 1 */
2880 SZP1, /* set zp1 to normal zone 1 */
2881 LOOPCALL,
2883 ENDF,
2889 * bci_action_ip_before
2891 * Handle `ip_before' data to align points located before the first edge.
2893 * in: first_edge (in twilight zone)
2894 * loop_counter (N)
2895 * point_1
2896 * point_2
2897 * ...
2898 * point_N
2900 * sal: sal_i (first_edge_orig_pos)
2902 * uses: bci_ip_outer_align_point
2905 unsigned char FPGM(bci_action_ip_before) [] =
2908 PUSHB_1,
2909 bci_action_ip_before,
2910 FDEF,
2912 PUSHB_1,
2914 SZP2, /* set zp2 to twilight zone 0 */
2916 DUP,
2917 GC_orig,
2918 PUSHB_1,
2919 sal_i,
2920 SWAP,
2921 WS, /* sal_i = first_edge_orig_pos */
2923 PUSHB_3,
2927 SZP2, /* set zp2 to normal zone 1 */
2928 SZP1, /* set zp1 to normal zone 1 */
2929 SZP0, /* set zp0 to twilight zone 0 */
2931 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2933 PUSHB_1,
2934 bci_ip_outer_align_point,
2935 LOOPCALL,
2937 ENDF,
2943 * bci_action_ip_after
2945 * Handle `ip_after' data to align points located after the last edge.
2947 * in: last_edge (in twilight zone)
2948 * loop_counter (N)
2949 * point_1
2950 * point_2
2951 * ...
2952 * point_N
2954 * sal: sal_i (last_edge_orig_pos)
2956 * uses: bci_ip_outer_align_point
2959 unsigned char FPGM(bci_action_ip_after) [] =
2962 PUSHB_1,
2963 bci_action_ip_after,
2964 FDEF,
2966 PUSHB_1,
2968 SZP2, /* set zp2 to twilight zone 0 */
2970 DUP,
2971 GC_orig,
2972 PUSHB_1,
2973 sal_i,
2974 SWAP,
2975 WS, /* sal_i = last_edge_orig_pos */
2977 PUSHB_3,
2981 SZP2, /* set zp2 to normal zone 1 */
2982 SZP1, /* set zp1 to normal zone 1 */
2983 SZP0, /* set zp0 to twilight zone 0 */
2985 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2987 PUSHB_1,
2988 bci_ip_outer_align_point,
2989 LOOPCALL,
2991 ENDF,
2997 * bci_action_ip_on
2999 * Handle `ip_on' data to align points located on an edge coordinate (but
3000 * not part of an edge).
3002 * in: loop_counter (M)
3003 * edge_1 (in twilight zone)
3004 * loop_counter (N_1)
3005 * point_1
3006 * point_2
3007 * ...
3008 * point_N_1
3009 * edge_2 (in twilight zone)
3010 * loop_counter (N_2)
3011 * point_1
3012 * point_2
3013 * ...
3014 * point_N_2
3015 * ...
3016 * edge_M (in twilight zone)
3017 * loop_counter (N_M)
3018 * point_1
3019 * point_2
3020 * ...
3021 * point_N_M
3023 * uses: bci_ip_on_align_points
3026 unsigned char FPGM(bci_action_ip_on) [] =
3029 PUSHB_1,
3030 bci_action_ip_on,
3031 FDEF,
3033 PUSHB_2,
3036 SZP1, /* set zp1 to normal zone 1 */
3037 SZP0, /* set zp0 to twilight zone 0 */
3039 PUSHB_1,
3040 bci_ip_on_align_points,
3041 LOOPCALL,
3043 ENDF,
3049 * bci_action_ip_between
3051 * Handle `ip_between' data to align points located between two edges.
3053 * in: loop_counter (M)
3054 * before_edge_1 (in twilight zone)
3055 * after_edge_1 (in twilight zone)
3056 * loop_counter (N_1)
3057 * point_1
3058 * point_2
3059 * ...
3060 * point_N_1
3061 * before_edge_2 (in twilight zone)
3062 * after_edge_2 (in twilight zone)
3063 * loop_counter (N_2)
3064 * point_1
3065 * point_2
3066 * ...
3067 * point_N_2
3068 * ...
3069 * before_edge_M (in twilight zone)
3070 * after_edge_M (in twilight zone)
3071 * loop_counter (N_M)
3072 * point_1
3073 * point_2
3074 * ...
3075 * point_N_M
3077 * uses: bci_ip_between_align_points
3080 unsigned char FPGM(bci_action_ip_between) [] =
3083 PUSHB_1,
3084 bci_action_ip_between,
3085 FDEF,
3087 PUSHB_1,
3088 bci_ip_between_align_points,
3089 LOOPCALL,
3091 ENDF,
3097 * bci_adjust_common
3099 * Common code for bci_action_adjust routines.
3101 * uses: func[sal_stem_width_function]
3104 unsigned char FPGM(bci_adjust_common) [] =
3107 PUSHB_1,
3108 bci_adjust_common,
3109 FDEF,
3111 PUSHB_1,
3113 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3115 PUSHB_1,
3117 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3118 PUSHB_1,
3120 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3121 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3123 PUSHB_1,
3124 sal_stem_width_function,
3126 CALL,
3127 NEG, /* s: [...] edge2 edge -cur_len */
3129 ROLL, /* s: [...] edge -cur_len edge2 */
3130 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3131 SWAP,
3132 DUP,
3133 DUP, /* s: [...] -cur_len edge edge edge */
3134 ALIGNRP, /* align `edge' with `edge2' */
3135 ROLL,
3136 SHPIX, /* shift `edge' by -cur_len */
3138 ENDF,
3144 * bci_adjust_bound
3146 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3147 * edge of the stem has already been moved, then moving it again if
3148 * necessary to stay bound.
3150 * in: edge2_is_serif
3151 * edge_is_round
3152 * edge_point (in twilight zone)
3153 * edge2_point (in twilight zone)
3154 * edge[-1] (in twilight zone)
3155 * ... stuff for bci_align_segments (edge) ...
3157 * uses: bci_adjust_common
3158 * bci_align_segments
3161 unsigned char FPGM(bci_adjust_bound) [] =
3164 PUSHB_1,
3165 bci_adjust_bound,
3166 FDEF,
3168 PUSHB_1,
3169 bci_adjust_common,
3170 CALL,
3172 SWAP, /* s: edge edge[-1] */
3173 DUP,
3174 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3175 GC_cur,
3176 PUSHB_1,
3178 CINDEX,
3179 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3180 GT, /* edge_pos < edge[-1]_pos */
3182 DUP,
3183 ALIGNRP, /* align `edge' to `edge[-1]' */
3184 EIF,
3186 MDAP_noround, /* set rp0 and rp1 to `edge' */
3188 PUSHB_2,
3189 bci_align_segments,
3191 SZP1, /* set zp1 to normal zone 1 */
3192 CALL,
3194 ENDF,
3200 * bci_action_adjust_bound
3201 * bci_action_adjust_bound_serif
3202 * bci_action_adjust_bound_round
3203 * bci_action_adjust_bound_round_serif
3205 * Higher-level routines for calling `bci_adjust_bound'.
3208 unsigned char FPGM(bci_action_adjust_bound) [] =
3211 PUSHB_1,
3212 bci_action_adjust_bound,
3213 FDEF,
3215 PUSHB_3,
3218 bci_adjust_bound,
3219 CALL,
3221 ENDF,
3225 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3228 PUSHB_1,
3229 bci_action_adjust_bound_serif,
3230 FDEF,
3232 PUSHB_3,
3235 bci_adjust_bound,
3236 CALL,
3238 ENDF,
3242 unsigned char FPGM(bci_action_adjust_bound_round) [] =
3245 PUSHB_1,
3246 bci_action_adjust_bound_round,
3247 FDEF,
3249 PUSHB_3,
3252 bci_adjust_bound,
3253 CALL,
3255 ENDF,
3259 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3262 PUSHB_1,
3263 bci_action_adjust_bound_round_serif,
3264 FDEF,
3266 PUSHB_3,
3269 bci_adjust_bound,
3270 CALL,
3272 ENDF,
3278 * bci_adjust
3280 * Handle the ADJUST action to align an edge of a stem if the other edge
3281 * of the stem has already been moved.
3283 * in: edge2_is_serif
3284 * edge_is_round
3285 * edge_point (in twilight zone)
3286 * edge2_point (in twilight zone)
3287 * ... stuff for bci_align_segments (edge) ...
3289 * uses: bci_adjust_common
3290 * bci_align_segments
3293 unsigned char FPGM(bci_adjust) [] =
3296 PUSHB_1,
3297 bci_adjust,
3298 FDEF,
3300 PUSHB_1,
3301 bci_adjust_common,
3302 CALL,
3304 MDAP_noround, /* set rp0 and rp1 to `edge' */
3306 PUSHB_2,
3307 bci_align_segments,
3309 SZP1, /* set zp1 to normal zone 1 */
3310 CALL,
3312 ENDF,
3318 * bci_action_adjust
3319 * bci_action_adjust_serif
3320 * bci_action_adjust_round
3321 * bci_action_adjust_round_serif
3323 * Higher-level routines for calling `bci_adjust'.
3326 unsigned char FPGM(bci_action_adjust) [] =
3329 PUSHB_1,
3330 bci_action_adjust,
3331 FDEF,
3333 PUSHB_3,
3336 bci_adjust,
3337 CALL,
3339 ENDF,
3343 unsigned char FPGM(bci_action_adjust_serif) [] =
3346 PUSHB_1,
3347 bci_action_adjust_serif,
3348 FDEF,
3350 PUSHB_3,
3353 bci_adjust,
3354 CALL,
3356 ENDF,
3360 unsigned char FPGM(bci_action_adjust_round) [] =
3363 PUSHB_1,
3364 bci_action_adjust_round,
3365 FDEF,
3367 PUSHB_3,
3370 bci_adjust,
3371 CALL,
3373 ENDF,
3377 unsigned char FPGM(bci_action_adjust_round_serif) [] =
3380 PUSHB_1,
3381 bci_action_adjust_round_serif,
3382 FDEF,
3384 PUSHB_3,
3387 bci_adjust,
3388 CALL,
3390 ENDF,
3396 * bci_stem_common
3398 * Common code for bci_action_stem routines.
3400 * sal: sal_anchor
3401 * sal_temp1
3402 * sal_temp2
3403 * sal_temp3
3405 * uses: func[sal_stem_width_function]
3406 * bci_round
3409 #undef sal_u_off
3410 #define sal_u_off sal_temp1
3411 #undef sal_d_off
3412 #define sal_d_off sal_temp2
3413 #undef sal_org_len
3414 #define sal_org_len sal_temp3
3415 #undef sal_edge2
3416 #define sal_edge2 sal_temp3
3418 unsigned char FPGM(bci_stem_common) [] =
3421 PUSHB_1,
3422 bci_stem_common,
3423 FDEF,
3425 PUSHB_1,
3427 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3429 PUSHB_1,
3431 CINDEX,
3432 PUSHB_1,
3434 CINDEX,
3435 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3436 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3438 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3439 DUP,
3440 PUSHB_1,
3441 sal_org_len,
3442 SWAP,
3445 PUSHB_1,
3446 sal_stem_width_function,
3448 CALL, /* s: [...] edge2 edge cur_len */
3450 DUP,
3451 PUSHB_1,
3453 LT, /* cur_len < 96 */
3455 DUP,
3456 PUSHB_1,
3458 LTEQ, /* cur_len <= 64 */
3460 PUSHB_4,
3461 sal_u_off,
3463 sal_d_off,
3466 ELSE,
3467 PUSHB_4,
3468 sal_u_off,
3470 sal_d_off,
3472 EIF,
3476 SWAP, /* s: [...] edge2 cur_len edge */
3477 DUP,
3478 PUSHB_1,
3479 sal_anchor,
3481 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3482 ROLL,
3483 SWAP,
3484 MD_orig_ZP2_0,
3485 SWAP,
3486 GC_cur,
3487 ADD, /* s: [...] edge2 cur_len edge org_pos */
3488 PUSHB_1,
3489 sal_org_len,
3491 DIV_BY_2,
3492 ADD, /* s: [...] edge2 cur_len edge org_center */
3494 DUP,
3495 PUSHB_1,
3496 bci_round,
3497 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3499 DUP,
3500 ROLL,
3501 ROLL,
3502 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3504 DUP,
3505 PUSHB_1,
3506 sal_u_off,
3508 ADD,
3509 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3511 SWAP,
3512 PUSHB_1,
3513 sal_d_off,
3515 SUB,
3516 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3518 LT, /* delta1 < delta2 */
3520 PUSHB_1,
3521 sal_u_off,
3523 SUB, /* cur_pos1 = cur_pos1 - u_off */
3525 ELSE,
3526 PUSHB_1,
3527 sal_d_off,
3529 ADD, /* cur_pos1 = cur_pos1 + d_off */
3530 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3532 PUSHB_1,
3534 CINDEX,
3535 DIV_BY_2,
3536 SUB, /* arg = cur_pos1 - cur_len/2 */
3538 SWAP, /* s: [...] edge2 cur_len arg edge */
3539 DUP,
3540 DUP,
3541 PUSHB_1,
3543 MINDEX,
3544 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3545 GC_cur,
3546 SUB,
3547 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3549 ELSE,
3550 SWAP, /* s: [...] edge2 cur_len edge */
3551 PUSHB_1,
3552 sal_anchor,
3554 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3555 PUSHB_1,
3557 CINDEX,
3558 PUSHB_1,
3559 sal_anchor,
3561 MD_orig_ZP2_0,
3562 ADD, /* s: [...] edge2 cur_len edge org_pos */
3564 DUP,
3565 PUSHB_1,
3566 sal_org_len,
3568 DIV_BY_2,
3569 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3571 SWAP,
3572 DUP,
3573 PUSHB_1,
3574 bci_round,
3575 CALL, /* cur_pos1 = ROUND(org_pos) */
3576 SWAP,
3577 PUSHB_1,
3578 sal_org_len,
3580 ADD,
3581 PUSHB_1,
3582 bci_round,
3583 CALL,
3584 PUSHB_1,
3586 CINDEX,
3587 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3589 PUSHB_1,
3591 CINDEX,
3592 DIV_BY_2,
3593 PUSHB_1,
3595 MINDEX,
3596 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3598 DUP,
3599 PUSHB_1,
3601 CINDEX,
3602 ADD,
3603 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3604 SWAP,
3605 PUSHB_1,
3607 CINDEX,
3608 ADD,
3609 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3610 LT, /* delta1 < delta2 */
3612 POP, /* arg = cur_pos1 */
3614 ELSE,
3615 SWAP,
3616 POP, /* arg = cur_pos2 */
3617 EIF, /* s: [...] edge2 cur_len edge arg */
3618 SWAP,
3619 DUP,
3620 DUP,
3621 PUSHB_1,
3623 MINDEX,
3624 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3625 GC_cur,
3626 SUB,
3627 SHPIX, /* edge = arg */
3628 EIF, /* s: [...] edge2 cur_len edge */
3630 ENDF,
3636 * bci_stem_bound
3638 * Handle the STEM action to align two edges of a stem, then moving one
3639 * edge again if necessary to stay bound.
3641 * The code after computing `cur_len' to shift `edge' and `edge2'
3642 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3644 * if cur_len < 96:
3645 * if cur_len < = 64:
3646 * u_off = 32
3647 * d_off = 32
3648 * else:
3649 * u_off = 38
3650 * d_off = 26
3652 * org_pos = anchor + (edge_orig - anchor_orig)
3653 * org_center = org_pos + org_len / 2
3655 * cur_pos1 = ROUND(org_center)
3656 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3657 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3658 * if (delta1 < delta2):
3659 * cur_pos1 = cur_pos1 - u_off
3660 * else:
3661 * cur_pos1 = cur_pos1 + d_off
3663 * edge = cur_pos1 - cur_len / 2
3665 * else:
3666 * org_pos = anchor + (edge_orig - anchor_orig)
3667 * org_center = org_pos + org_len / 2
3669 * cur_pos1 = ROUND(org_pos)
3670 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3671 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3672 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3674 * if (delta1 < delta2):
3675 * edge = cur_pos1
3676 * else:
3677 * edge = cur_pos2
3679 * edge2 = edge + cur_len
3681 * in: edge2_is_serif
3682 * edge_is_round
3683 * edge_point (in twilight zone)
3684 * edge2_point (in twilight zone)
3685 * edge[-1] (in twilight zone)
3686 * ... stuff for bci_align_segments (edge) ...
3687 * ... stuff for bci_align_segments (edge2)...
3689 * sal: sal_anchor
3690 * sal_temp1
3691 * sal_temp2
3692 * sal_temp3
3694 * uses: bci_stem_common
3695 * bci_align_segments
3698 unsigned char FPGM(bci_stem_bound) [] =
3701 PUSHB_1,
3702 bci_stem_bound,
3703 FDEF,
3705 PUSHB_1,
3706 bci_stem_common,
3707 CALL,
3709 ROLL, /* s: edge[-1] cur_len edge edge2 */
3710 DUP,
3711 DUP,
3712 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3713 PUSHB_1,
3714 sal_edge2,
3715 SWAP,
3716 WS, /* s: edge[-1] cur_len edge edge2 */
3717 ROLL,
3718 SHPIX, /* edge2 = edge + cur_len */
3720 SWAP, /* s: edge edge[-1] */
3721 DUP,
3722 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3723 GC_cur,
3724 PUSHB_1,
3726 CINDEX,
3727 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3728 GT, /* edge_pos < edge[-1]_pos */
3730 DUP,
3731 ALIGNRP, /* align `edge' to `edge[-1]' */
3732 EIF,
3734 MDAP_noround, /* set rp0 and rp1 to `edge' */
3736 PUSHB_2,
3737 bci_align_segments,
3739 SZP1, /* set zp1 to normal zone 1 */
3740 CALL,
3742 PUSHB_1,
3743 sal_edge2,
3745 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3747 PUSHB_1,
3748 bci_align_segments,
3749 CALL,
3751 ENDF,
3757 * bci_action_stem_bound
3758 * bci_action_stem_bound_serif
3759 * bci_action_stem_bound_round
3760 * bci_action_stem_bound_round_serif
3762 * Higher-level routines for calling `bci_stem_bound'.
3765 unsigned char FPGM(bci_action_stem_bound) [] =
3768 PUSHB_1,
3769 bci_action_stem_bound,
3770 FDEF,
3772 PUSHB_3,
3775 bci_stem_bound,
3776 CALL,
3778 ENDF,
3782 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3785 PUSHB_1,
3786 bci_action_stem_bound_serif,
3787 FDEF,
3789 PUSHB_3,
3792 bci_stem_bound,
3793 CALL,
3795 ENDF,
3799 unsigned char FPGM(bci_action_stem_bound_round) [] =
3802 PUSHB_1,
3803 bci_action_stem_bound_round,
3804 FDEF,
3806 PUSHB_3,
3809 bci_stem_bound,
3810 CALL,
3812 ENDF,
3816 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3819 PUSHB_1,
3820 bci_action_stem_bound_round_serif,
3821 FDEF,
3823 PUSHB_3,
3826 bci_stem_bound,
3827 CALL,
3829 ENDF,
3835 * bci_stem
3837 * Handle the STEM action to align two edges of a stem.
3839 * See `bci_stem_bound' for more details.
3841 * in: edge2_is_serif
3842 * edge_is_round
3843 * edge_point (in twilight zone)
3844 * edge2_point (in twilight zone)
3845 * ... stuff for bci_align_segments (edge) ...
3846 * ... stuff for bci_align_segments (edge2)...
3848 * sal: sal_anchor
3849 * sal_temp1
3850 * sal_temp2
3851 * sal_temp3
3853 * uses: bci_stem_common
3854 * bci_align_segments
3857 unsigned char FPGM(bci_stem) [] =
3860 PUSHB_1,
3861 bci_stem,
3862 FDEF,
3864 PUSHB_1,
3865 bci_stem_common,
3866 CALL,
3868 POP,
3869 SWAP, /* s: cur_len edge2 */
3870 DUP,
3871 DUP,
3872 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3873 PUSHB_1,
3874 sal_edge2,
3875 SWAP,
3876 WS, /* s: cur_len edge2 */
3877 SWAP,
3878 SHPIX, /* edge2 = edge + cur_len */
3880 PUSHB_2,
3881 bci_align_segments,
3883 SZP1, /* set zp1 to normal zone 1 */
3884 CALL,
3886 PUSHB_1,
3887 sal_edge2,
3889 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3891 PUSHB_1,
3892 bci_align_segments,
3893 CALL,
3894 ENDF,
3900 * bci_action_stem
3901 * bci_action_stem_serif
3902 * bci_action_stem_round
3903 * bci_action_stem_round_serif
3905 * Higher-level routines for calling `bci_stem'.
3908 unsigned char FPGM(bci_action_stem) [] =
3911 PUSHB_1,
3912 bci_action_stem,
3913 FDEF,
3915 PUSHB_3,
3918 bci_stem,
3919 CALL,
3921 ENDF,
3925 unsigned char FPGM(bci_action_stem_serif) [] =
3928 PUSHB_1,
3929 bci_action_stem_serif,
3930 FDEF,
3932 PUSHB_3,
3935 bci_stem,
3936 CALL,
3938 ENDF,
3942 unsigned char FPGM(bci_action_stem_round) [] =
3945 PUSHB_1,
3946 bci_action_stem_round,
3947 FDEF,
3949 PUSHB_3,
3952 bci_stem,
3953 CALL,
3955 ENDF,
3959 unsigned char FPGM(bci_action_stem_round_serif) [] =
3962 PUSHB_1,
3963 bci_action_stem_round_serif,
3964 FDEF,
3966 PUSHB_3,
3969 bci_stem,
3970 CALL,
3972 ENDF,
3978 * bci_link
3980 * Handle the LINK action to link an edge to another one.
3982 * in: stem_is_serif
3983 * base_is_round
3984 * base_point (in twilight zone)
3985 * stem_point (in twilight zone)
3986 * ... stuff for bci_align_segments (base) ...
3988 * uses: func[sal_stem_width_function]
3989 * bci_align_segments
3992 unsigned char FPGM(bci_link) [] =
3995 PUSHB_1,
3996 bci_link,
3997 FDEF,
3999 PUSHB_1,
4001 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4003 PUSHB_1,
4005 CINDEX,
4006 PUSHB_1,
4008 MINDEX,
4009 DUP, /* s: stem is_round is_serif stem base base */
4010 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4012 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4014 PUSHB_1,
4015 sal_stem_width_function,
4017 CALL, /* s: stem new_dist */
4019 SWAP,
4020 DUP,
4021 ALIGNRP, /* align `stem_point' with `base_point' */
4022 DUP,
4023 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4024 SWAP,
4025 SHPIX, /* stem_point = base_point + new_dist */
4027 PUSHB_2,
4028 bci_align_segments,
4030 SZP1, /* set zp1 to normal zone 1 */
4031 CALL,
4033 ENDF,
4039 * bci_action_link
4040 * bci_action_link_serif
4041 * bci_action_link_round
4042 * bci_action_link_round_serif
4044 * Higher-level routines for calling `bci_link'.
4047 unsigned char FPGM(bci_action_link) [] =
4050 PUSHB_1,
4051 bci_action_link,
4052 FDEF,
4054 PUSHB_3,
4057 bci_link,
4058 CALL,
4060 ENDF,
4064 unsigned char FPGM(bci_action_link_serif) [] =
4067 PUSHB_1,
4068 bci_action_link_serif,
4069 FDEF,
4071 PUSHB_3,
4074 bci_link,
4075 CALL,
4077 ENDF,
4081 unsigned char FPGM(bci_action_link_round) [] =
4084 PUSHB_1,
4085 bci_action_link_round,
4086 FDEF,
4088 PUSHB_3,
4091 bci_link,
4092 CALL,
4094 ENDF,
4098 unsigned char FPGM(bci_action_link_round_serif) [] =
4101 PUSHB_1,
4102 bci_action_link_round_serif,
4103 FDEF,
4105 PUSHB_3,
4108 bci_link,
4109 CALL,
4111 ENDF,
4117 * bci_anchor
4119 * Handle the ANCHOR action to align two edges
4120 * and to set the edge anchor.
4122 * The code after computing `cur_len' to shift `edge' and `edge2'
4123 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4125 * if cur_len < 96:
4126 * if cur_len < = 64:
4127 * u_off = 32
4128 * d_off = 32
4129 * else:
4130 * u_off = 38
4131 * d_off = 26
4133 * org_center = edge_orig + org_len / 2
4134 * cur_pos1 = ROUND(org_center)
4136 * error1 = ABS(org_center - (cur_pos1 - u_off))
4137 * error2 = ABS(org_center - (cur_pos1 + d_off))
4138 * if (error1 < error2):
4139 * cur_pos1 = cur_pos1 - u_off
4140 * else:
4141 * cur_pos1 = cur_pos1 + d_off
4143 * edge = cur_pos1 - cur_len / 2
4144 * edge2 = edge + cur_len
4146 * else:
4147 * edge = ROUND(edge_orig)
4149 * in: edge2_is_serif
4150 * edge_is_round
4151 * edge_point (in twilight zone)
4152 * edge2_point (in twilight zone)
4153 * ... stuff for bci_align_segments (edge) ...
4155 * sal: sal_anchor
4156 * sal_temp1
4157 * sal_temp2
4158 * sal_temp3
4160 * uses: func[sal_stem_width_function]
4161 * bci_round
4162 * bci_align_segments
4165 #undef sal_u_off
4166 #define sal_u_off sal_temp1
4167 #undef sal_d_off
4168 #define sal_d_off sal_temp2
4169 #undef sal_org_len
4170 #define sal_org_len sal_temp3
4172 unsigned char FPGM(bci_anchor) [] =
4175 PUSHB_1,
4176 bci_anchor,
4177 FDEF,
4179 /* store anchor point number in `sal_anchor' */
4180 PUSHB_2,
4181 sal_anchor,
4183 CINDEX,
4184 WS, /* sal_anchor = edge_point */
4186 PUSHB_1,
4188 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4190 PUSHB_1,
4192 CINDEX,
4193 PUSHB_1,
4195 CINDEX,
4196 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4197 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4199 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4200 DUP,
4201 PUSHB_1,
4202 sal_org_len,
4203 SWAP,
4206 PUSHB_1,
4207 sal_stem_width_function,
4209 CALL, /* s: edge2 edge cur_len */
4211 DUP,
4212 PUSHB_1,
4214 LT, /* cur_len < 96 */
4216 DUP,
4217 PUSHB_1,
4219 LTEQ, /* cur_len <= 64 */
4221 PUSHB_4,
4222 sal_u_off,
4224 sal_d_off,
4227 ELSE,
4228 PUSHB_4,
4229 sal_u_off,
4231 sal_d_off,
4233 EIF,
4237 SWAP, /* s: edge2 cur_len edge */
4238 DUP, /* s: edge2 cur_len edge edge */
4240 GC_orig,
4241 PUSHB_1,
4242 sal_org_len,
4244 DIV_BY_2,
4245 ADD, /* s: edge2 cur_len edge org_center */
4247 DUP,
4248 PUSHB_1,
4249 bci_round,
4250 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4252 DUP,
4253 ROLL,
4254 ROLL,
4255 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4257 DUP,
4258 PUSHB_1,
4259 sal_u_off,
4261 ADD,
4262 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4264 SWAP,
4265 PUSHB_1,
4266 sal_d_off,
4268 SUB,
4269 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4271 LT, /* error1 < error2 */
4273 PUSHB_1,
4274 sal_u_off,
4276 SUB, /* cur_pos1 = cur_pos1 - u_off */
4278 ELSE,
4279 PUSHB_1,
4280 sal_d_off,
4282 ADD, /* cur_pos1 = cur_pos1 + d_off */
4283 EIF, /* s: edge2 cur_len edge cur_pos1 */
4285 PUSHB_1,
4287 CINDEX,
4288 DIV_BY_2,
4289 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4291 PUSHB_1,
4293 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4294 GC_cur,
4295 SUB,
4296 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4298 SWAP, /* s: cur_len edge2 */
4299 DUP,
4300 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4301 SWAP,
4302 SHPIX, /* edge2 = edge1 + cur_len */
4304 ELSE,
4305 POP, /* s: edge2 edge */
4306 DUP,
4307 DUP,
4308 GC_cur,
4309 SWAP,
4310 GC_orig,
4311 PUSHB_1,
4312 bci_round,
4313 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4314 SWAP,
4315 SUB,
4316 SHPIX, /* edge = round(edge_orig) */
4318 /* clean up stack */
4319 POP,
4320 EIF,
4322 PUSHB_2,
4323 bci_align_segments,
4325 SZP1, /* set zp1 to normal zone 1 */
4326 CALL,
4328 ENDF,
4334 * bci_action_anchor
4335 * bci_action_anchor_serif
4336 * bci_action_anchor_round
4337 * bci_action_anchor_round_serif
4339 * Higher-level routines for calling `bci_anchor'.
4342 unsigned char FPGM(bci_action_anchor) [] =
4345 PUSHB_1,
4346 bci_action_anchor,
4347 FDEF,
4349 PUSHB_3,
4352 bci_anchor,
4353 CALL,
4355 ENDF,
4359 unsigned char FPGM(bci_action_anchor_serif) [] =
4362 PUSHB_1,
4363 bci_action_anchor_serif,
4364 FDEF,
4366 PUSHB_3,
4369 bci_anchor,
4370 CALL,
4372 ENDF,
4376 unsigned char FPGM(bci_action_anchor_round) [] =
4379 PUSHB_1,
4380 bci_action_anchor_round,
4381 FDEF,
4383 PUSHB_3,
4386 bci_anchor,
4387 CALL,
4389 ENDF,
4393 unsigned char FPGM(bci_action_anchor_round_serif) [] =
4396 PUSHB_1,
4397 bci_action_anchor_round_serif,
4398 FDEF,
4400 PUSHB_3,
4403 bci_anchor,
4404 CALL,
4406 ENDF,
4412 * bci_action_blue_anchor
4414 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4415 * and to set the edge anchor.
4417 * in: anchor_point (in twilight zone)
4418 * blue_cvt_idx
4419 * edge_point (in twilight zone)
4420 * ... stuff for bci_align_segments (edge) ...
4422 * sal: sal_anchor
4424 * uses: bci_action_blue
4427 unsigned char FPGM(bci_action_blue_anchor) [] =
4430 PUSHB_1,
4431 bci_action_blue_anchor,
4432 FDEF,
4434 /* store anchor point number in `sal_anchor' */
4435 PUSHB_1,
4436 sal_anchor,
4437 SWAP,
4440 PUSHB_1,
4441 bci_action_blue,
4442 CALL,
4444 ENDF,
4450 * bci_action_blue
4452 * Handle the BLUE action to align an edge with a blue zone.
4454 * in: blue_cvt_idx
4455 * edge_point (in twilight zone)
4456 * ... stuff for bci_align_segments (edge) ...
4458 * uses: bci_align_segments
4461 unsigned char FPGM(bci_action_blue) [] =
4464 PUSHB_1,
4465 bci_action_blue,
4466 FDEF,
4468 PUSHB_1,
4470 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4472 /* move `edge_point' to `blue_cvt_idx' position; */
4473 /* note that we can't use MIAP since this would modify */
4474 /* the twilight point's original coordinates also */
4475 RCVT,
4476 SWAP,
4477 DUP,
4478 MDAP_noround, /* set rp0 and rp1 to `edge' */
4479 DUP,
4480 GC_cur, /* s: new_pos edge edge_pos */
4481 ROLL,
4482 SWAP,
4483 SUB, /* s: edge (new_pos - edge_pos) */
4484 SHPIX,
4486 PUSHB_2,
4487 bci_align_segments,
4489 SZP1, /* set zp1 to normal zone 1 */
4490 CALL,
4492 ENDF,
4498 * bci_serif_common
4500 * Common code for bci_action_serif routines.
4503 unsigned char FPGM(bci_serif_common) [] =
4506 PUSHB_1,
4507 bci_serif_common,
4508 FDEF,
4510 PUSHB_1,
4512 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4514 DUP,
4515 DUP,
4516 DUP,
4517 PUSHB_1,
4519 MINDEX, /* s: [...] serif serif serif serif base */
4520 DUP,
4521 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4522 MD_orig_ZP2_0,
4523 SWAP,
4524 ALIGNRP, /* align `serif_point' with `base_point' */
4525 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4527 ENDF,
4533 * bci_lower_bound
4535 * Move an edge if necessary to stay within a lower bound.
4537 * in: edge
4538 * bound
4540 * uses: bci_align_segments
4543 unsigned char FPGM(bci_lower_bound) [] =
4546 PUSHB_1,
4547 bci_lower_bound,
4548 FDEF,
4550 SWAP, /* s: edge bound */
4551 DUP,
4552 MDAP_noround, /* set rp0 and rp1 to `bound' */
4553 GC_cur,
4554 PUSHB_1,
4556 CINDEX,
4557 GC_cur, /* s: edge bound_pos edge_pos */
4558 GT, /* edge_pos < bound_pos */
4560 DUP,
4561 ALIGNRP, /* align `edge' to `bound' */
4562 EIF,
4564 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4566 PUSHB_2,
4567 bci_align_segments,
4569 SZP1, /* set zp1 to normal zone 1 */
4570 CALL,
4572 ENDF,
4578 * bci_upper_bound
4580 * Move an edge if necessary to stay within an upper bound.
4582 * in: edge
4583 * bound
4585 * uses: bci_align_segments
4588 unsigned char FPGM(bci_upper_bound) [] =
4591 PUSHB_1,
4592 bci_upper_bound,
4593 FDEF,
4595 SWAP, /* s: edge bound */
4596 DUP,
4597 MDAP_noround, /* set rp0 and rp1 to `bound' */
4598 GC_cur,
4599 PUSHB_1,
4601 CINDEX,
4602 GC_cur, /* s: edge bound_pos edge_pos */
4603 LT, /* edge_pos > bound_pos */
4605 DUP,
4606 ALIGNRP, /* align `edge' to `bound' */
4607 EIF,
4609 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4611 PUSHB_2,
4612 bci_align_segments,
4614 SZP1, /* set zp1 to normal zone 1 */
4615 CALL,
4617 ENDF,
4623 * bci_upper_lower_bound
4625 * Move an edge if necessary to stay within a lower and lower bound.
4627 * in: edge
4628 * lower
4629 * upper
4631 * uses: bci_align_segments
4634 unsigned char FPGM(bci_upper_lower_bound) [] =
4637 PUSHB_1,
4638 bci_upper_lower_bound,
4639 FDEF,
4641 SWAP, /* s: upper serif lower */
4642 DUP,
4643 MDAP_noround, /* set rp0 and rp1 to `lower' */
4644 GC_cur,
4645 PUSHB_1,
4647 CINDEX,
4648 GC_cur, /* s: upper serif lower_pos serif_pos */
4649 GT, /* serif_pos < lower_pos */
4651 DUP,
4652 ALIGNRP, /* align `serif' to `lower' */
4653 EIF,
4655 SWAP, /* s: serif upper */
4656 DUP,
4657 MDAP_noround, /* set rp0 and rp1 to `upper' */
4658 GC_cur,
4659 PUSHB_1,
4661 CINDEX,
4662 GC_cur, /* s: serif upper_pos serif_pos */
4663 LT, /* serif_pos > upper_pos */
4665 DUP,
4666 ALIGNRP, /* align `serif' to `upper' */
4667 EIF,
4669 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4671 PUSHB_2,
4672 bci_align_segments,
4674 SZP1, /* set zp1 to normal zone 1 */
4675 CALL,
4677 ENDF,
4683 * bci_action_serif
4685 * Handle the SERIF action to align a serif with its base.
4687 * in: serif_point (in twilight zone)
4688 * base_point (in twilight zone)
4689 * ... stuff for bci_align_segments (serif) ...
4691 * uses: bci_serif_common
4692 * bci_align_segments
4695 unsigned char FPGM(bci_action_serif) [] =
4698 PUSHB_1,
4699 bci_action_serif,
4700 FDEF,
4702 PUSHB_1,
4703 bci_serif_common,
4704 CALL,
4706 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4708 PUSHB_2,
4709 bci_align_segments,
4711 SZP1, /* set zp1 to normal zone 1 */
4712 CALL,
4714 ENDF,
4720 * bci_action_serif_lower_bound
4722 * Handle the SERIF action to align a serif with its base, then moving it
4723 * again if necessary to stay within a lower bound.
4725 * in: serif_point (in twilight zone)
4726 * base_point (in twilight zone)
4727 * edge[-1] (in twilight zone)
4728 * ... stuff for bci_align_segments (serif) ...
4730 * uses: bci_serif_common
4731 * bci_lower_bound
4734 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4737 PUSHB_1,
4738 bci_action_serif_lower_bound,
4739 FDEF,
4741 PUSHB_1,
4742 bci_serif_common,
4743 CALL,
4745 PUSHB_1,
4746 bci_lower_bound,
4747 CALL,
4749 ENDF,
4755 * bci_action_serif_upper_bound
4757 * Handle the SERIF action to align a serif with its base, then moving it
4758 * again if necessary to stay within an upper bound.
4760 * in: serif_point (in twilight zone)
4761 * base_point (in twilight zone)
4762 * edge[1] (in twilight zone)
4763 * ... stuff for bci_align_segments (serif) ...
4765 * uses: bci_serif_common
4766 * bci_upper_bound
4769 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4772 PUSHB_1,
4773 bci_action_serif_upper_bound,
4774 FDEF,
4776 PUSHB_1,
4777 bci_serif_common,
4778 CALL,
4780 PUSHB_1,
4781 bci_upper_bound,
4782 CALL,
4784 ENDF,
4790 * bci_action_serif_upper_lower_bound
4792 * Handle the SERIF action to align a serif with its base, then moving it
4793 * again if necessary to stay within a lower and upper bound.
4795 * in: serif_point (in twilight zone)
4796 * base_point (in twilight zone)
4797 * edge[-1] (in twilight zone)
4798 * edge[1] (in twilight zone)
4799 * ... stuff for bci_align_segments (serif) ...
4801 * uses: bci_serif_common
4802 * bci_upper_lower_bound
4805 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4808 PUSHB_1,
4809 bci_action_serif_upper_lower_bound,
4810 FDEF,
4812 PUSHB_1,
4814 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4816 PUSHB_1,
4817 bci_serif_common,
4818 CALL,
4820 PUSHB_1,
4821 bci_upper_lower_bound,
4822 CALL,
4824 ENDF,
4830 * bci_serif_anchor_common
4832 * Common code for bci_action_serif_anchor routines.
4834 * sal: sal_anchor
4836 * uses: bci_round
4839 unsigned char FPGM(bci_serif_anchor_common) [] =
4842 PUSHB_1,
4843 bci_serif_anchor_common,
4844 FDEF,
4846 PUSHB_1,
4848 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4850 DUP,
4851 PUSHB_1,
4852 sal_anchor,
4853 SWAP,
4854 WS, /* sal_anchor = edge_point */
4856 DUP,
4857 DUP,
4858 DUP,
4859 GC_cur,
4860 SWAP,
4861 GC_orig,
4862 PUSHB_1,
4863 bci_round,
4864 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4865 SWAP,
4866 SUB,
4867 SHPIX, /* edge = round(edge_orig) */
4869 ENDF,
4875 * bci_action_serif_anchor
4877 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4878 * anchor.
4880 * in: edge_point (in twilight zone)
4881 * ... stuff for bci_align_segments (edge) ...
4883 * uses: bci_serif_anchor_common
4884 * bci_align_segments
4887 unsigned char FPGM(bci_action_serif_anchor) [] =
4890 PUSHB_1,
4891 bci_action_serif_anchor,
4892 FDEF,
4894 PUSHB_1,
4895 bci_serif_anchor_common,
4896 CALL,
4898 MDAP_noround, /* set rp0 and rp1 to `edge' */
4900 PUSHB_2,
4901 bci_align_segments,
4903 SZP1, /* set zp1 to normal zone 1 */
4904 CALL,
4906 ENDF,
4912 * bci_action_serif_anchor_lower_bound
4914 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4915 * anchor, then moving it again if necessary to stay within a lower
4916 * bound.
4918 * in: edge_point (in twilight zone)
4919 * edge[-1] (in twilight zone)
4920 * ... stuff for bci_align_segments (edge) ...
4922 * uses: bci_serif_anchor_common
4923 * bci_lower_bound
4926 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4929 PUSHB_1,
4930 bci_action_serif_anchor_lower_bound,
4931 FDEF,
4933 PUSHB_1,
4934 bci_serif_anchor_common,
4935 CALL,
4937 PUSHB_1,
4938 bci_lower_bound,
4939 CALL,
4941 ENDF,
4947 * bci_action_serif_anchor_upper_bound
4949 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4950 * anchor, then moving it again if necessary to stay within an upper
4951 * bound.
4953 * in: edge_point (in twilight zone)
4954 * edge[1] (in twilight zone)
4955 * ... stuff for bci_align_segments (edge) ...
4957 * uses: bci_serif_anchor_common
4958 * bci_upper_bound
4961 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4964 PUSHB_1,
4965 bci_action_serif_anchor_upper_bound,
4966 FDEF,
4968 PUSHB_1,
4969 bci_serif_anchor_common,
4970 CALL,
4972 PUSHB_1,
4973 bci_upper_bound,
4974 CALL,
4976 ENDF,
4982 * bci_action_serif_anchor_upper_lower_bound
4984 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4985 * anchor, then moving it again if necessary to stay within a lower and
4986 * upper bound.
4988 * in: edge_point (in twilight zone)
4989 * edge[-1] (in twilight zone)
4990 * edge[1] (in twilight zone)
4991 * ... stuff for bci_align_segments (edge) ...
4993 * uses: bci_serif_anchor_common
4994 * bci_upper_lower_bound
4997 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5000 PUSHB_1,
5001 bci_action_serif_anchor_upper_lower_bound,
5002 FDEF,
5004 PUSHB_1,
5005 bci_serif_anchor_common,
5006 CALL,
5008 PUSHB_1,
5009 bci_upper_lower_bound,
5010 CALL,
5012 ENDF,
5018 * bci_serif_link1_common
5020 * Common code for bci_action_serif_link1 routines.
5023 unsigned char FPGM(bci_serif_link1_common) [] =
5026 PUSHB_1,
5027 bci_serif_link1_common,
5028 FDEF,
5030 PUSHB_1,
5032 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5034 PUSHB_1,
5036 CINDEX, /* s: [...] after edge before after */
5037 PUSHB_1,
5039 CINDEX, /* s: [...] after edge before after before */
5040 MD_orig_ZP2_0,
5041 PUSHB_1,
5043 EQ, /* after_orig_pos == before_orig_pos */
5044 IF, /* s: [...] after edge before */
5045 MDAP_noround, /* set rp0 and rp1 to `before' */
5046 DUP,
5047 ALIGNRP, /* align `edge' with `before' */
5048 SWAP,
5049 POP,
5051 ELSE,
5052 /* we have to execute `a*b/c', with b/c very near to 1: */
5053 /* to avoid overflow while retaining precision, */
5054 /* we transform this to `a + a * (b-c)/c' */
5056 PUSHB_1,
5058 CINDEX, /* s: [...] after edge before edge */
5059 PUSHB_1,
5061 CINDEX, /* s: [...] after edge before edge before */
5062 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
5064 DUP,
5065 PUSHB_1,
5067 CINDEX, /* s: [...] after edge before a a after */
5068 PUSHB_1,
5070 CINDEX, /* s: [...] after edge before a a after before */
5071 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
5073 PUSHB_1,
5075 CINDEX, /* s: [...] after edge before a a c after */
5076 PUSHB_1,
5078 CINDEX, /* s: [...] after edge before a a c after before */
5079 MD_cur, /* b = after_pos - before_pos */
5081 PUSHB_1,
5083 CINDEX, /* s: [...] after edge before a a c b c */
5084 SUB, /* b-c */
5086 PUSHW_2,
5087 0x08, /* 0x800 */
5088 0x00,
5089 0x08, /* 0x800 */
5090 0x00,
5091 MUL, /* 0x10000 */
5092 MUL, /* (b-c) in 16.16 format */
5093 SWAP,
5095 DUP,
5096 IF, /* c != 0 ? */
5097 DIV, /* s: [...] after edge before a a (b-c)/c */
5098 ELSE,
5099 POP, /* avoid division by zero */
5100 EIF,
5102 MUL, /* a * (b-c)/c * 2^10 */
5103 DIV_BY_1024, /* a * (b-c)/c */
5104 ADD, /* a*b/c */
5106 SWAP,
5107 MDAP_noround, /* set rp0 and rp1 to `before' */
5108 SWAP, /* s: [...] after a*b/c edge */
5109 DUP,
5110 DUP,
5111 ALIGNRP, /* align `edge' with `before' */
5112 ROLL,
5113 SHPIX, /* shift `edge' by `a*b/c' */
5115 SWAP, /* s: [...] edge after */
5116 POP,
5117 EIF,
5119 ENDF,
5125 * bci_action_serif_link1
5127 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5128 * before and after.
5130 * in: before_point (in twilight zone)
5131 * edge_point (in twilight zone)
5132 * after_point (in twilight zone)
5133 * ... stuff for bci_align_segments (edge) ...
5135 * uses: bci_serif_link1_common
5136 * bci_align_segments
5139 unsigned char FPGM(bci_action_serif_link1) [] =
5142 PUSHB_1,
5143 bci_action_serif_link1,
5144 FDEF,
5146 PUSHB_1,
5147 bci_serif_link1_common,
5148 CALL,
5150 MDAP_noround, /* set rp0 and rp1 to `edge' */
5152 PUSHB_2,
5153 bci_align_segments,
5155 SZP1, /* set zp1 to normal zone 1 */
5156 CALL,
5158 ENDF,
5164 * bci_action_serif_link1_lower_bound
5166 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5167 * before and after. Additionally, move the serif again if necessary to
5168 * stay within a lower bound.
5170 * in: before_point (in twilight zone)
5171 * edge_point (in twilight zone)
5172 * after_point (in twilight zone)
5173 * edge[-1] (in twilight zone)
5174 * ... stuff for bci_align_segments (edge) ...
5176 * uses: bci_serif_link1_common
5177 * bci_lower_bound
5180 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
5183 PUSHB_1,
5184 bci_action_serif_link1_lower_bound,
5185 FDEF,
5187 PUSHB_1,
5188 bci_serif_link1_common,
5189 CALL,
5191 PUSHB_1,
5192 bci_lower_bound,
5193 CALL,
5195 ENDF,
5201 * bci_action_serif_link1_upper_bound
5203 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5204 * before and after. Additionally, move the serif again if necessary to
5205 * stay within an upper bound.
5207 * in: before_point (in twilight zone)
5208 * edge_point (in twilight zone)
5209 * after_point (in twilight zone)
5210 * edge[1] (in twilight zone)
5211 * ... stuff for bci_align_segments (edge) ...
5213 * uses: bci_serif_link1_common
5214 * bci_upper_bound
5217 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
5220 PUSHB_1,
5221 bci_action_serif_link1_upper_bound,
5222 FDEF,
5224 PUSHB_1,
5225 bci_serif_link1_common,
5226 CALL,
5228 PUSHB_1,
5229 bci_upper_bound,
5230 CALL,
5232 ENDF,
5238 * bci_action_serif_link1_upper_lower_bound
5240 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5241 * before and after. Additionally, move the serif again if necessary to
5242 * stay within a lower and upper bound.
5244 * in: before_point (in twilight zone)
5245 * edge_point (in twilight zone)
5246 * after_point (in twilight zone)
5247 * edge[-1] (in twilight zone)
5248 * edge[1] (in twilight zone)
5249 * ... stuff for bci_align_segments (edge) ...
5251 * uses: bci_serif_link1_common
5252 * bci_upper_lower_bound
5255 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
5258 PUSHB_1,
5259 bci_action_serif_link1_upper_lower_bound,
5260 FDEF,
5262 PUSHB_1,
5263 bci_serif_link1_common,
5264 CALL,
5266 PUSHB_1,
5267 bci_upper_lower_bound,
5268 CALL,
5270 ENDF,
5276 * bci_serif_link2_common
5278 * Common code for bci_action_serif_link2 routines.
5280 * sal: sal_anchor
5283 unsigned char FPGM(bci_serif_link2_common) [] =
5286 PUSHB_1,
5287 bci_serif_link2_common,
5288 FDEF,
5290 PUSHB_1,
5292 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5294 DUP, /* s: [...] edge edge */
5295 PUSHB_1,
5296 sal_anchor,
5298 DUP, /* s: [...] edge edge anchor anchor */
5299 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
5301 MD_orig_ZP2_0,
5302 DUP,
5303 ADD,
5304 PUSHB_1,
5306 ADD,
5307 FLOOR,
5308 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5310 SWAP,
5311 DUP,
5312 DUP,
5313 ALIGNRP, /* align `edge' with `sal_anchor' */
5314 ROLL,
5315 SHPIX, /* shift `edge' by `delta' */
5317 ENDF,
5323 * bci_action_serif_link2
5325 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5327 * in: edge_point (in twilight zone)
5328 * ... stuff for bci_align_segments (edge) ...
5330 * uses: bci_serif_link2_common
5331 * bci_align_segments
5334 unsigned char FPGM(bci_action_serif_link2) [] =
5337 PUSHB_1,
5338 bci_action_serif_link2,
5339 FDEF,
5341 PUSHB_1,
5342 bci_serif_link2_common,
5343 CALL,
5345 MDAP_noround, /* set rp0 and rp1 to `edge' */
5347 PUSHB_2,
5348 bci_align_segments,
5350 SZP1, /* set zp1 to normal zone 1 */
5351 CALL,
5353 ENDF,
5359 * bci_action_serif_link2_lower_bound
5361 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5362 * Additionally, move the serif again if necessary to stay within a lower
5363 * bound.
5365 * in: edge_point (in twilight zone)
5366 * edge[-1] (in twilight zone)
5367 * ... stuff for bci_align_segments (edge) ...
5369 * uses: bci_serif_link2_common
5370 * bci_lower_bound
5373 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
5376 PUSHB_1,
5377 bci_action_serif_link2_lower_bound,
5378 FDEF,
5380 PUSHB_1,
5381 bci_serif_link2_common,
5382 CALL,
5384 PUSHB_1,
5385 bci_lower_bound,
5386 CALL,
5388 ENDF,
5394 * bci_action_serif_link2_upper_bound
5396 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5397 * Additionally, move the serif again if necessary to stay within an upper
5398 * bound.
5400 * in: edge_point (in twilight zone)
5401 * edge[1] (in twilight zone)
5402 * ... stuff for bci_align_segments (edge) ...
5404 * uses: bci_serif_link2_common
5405 * bci_upper_bound
5408 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
5411 PUSHB_1,
5412 bci_action_serif_link2_upper_bound,
5413 FDEF,
5415 PUSHB_1,
5416 bci_serif_link2_common,
5417 CALL,
5419 PUSHB_1,
5420 bci_upper_bound,
5421 CALL,
5423 ENDF,
5429 * bci_action_serif_link2_upper_lower_bound
5431 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5432 * Additionally, move the serif again if necessary to stay within a lower
5433 * and upper bound.
5435 * in: edge_point (in twilight zone)
5436 * edge[-1] (in twilight zone)
5437 * edge[1] (in twilight zone)
5438 * ... stuff for bci_align_segments (edge) ...
5440 * uses: bci_serif_link2_common
5441 * bci_upper_lower_bound
5444 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
5447 PUSHB_1,
5448 bci_action_serif_link2_upper_lower_bound,
5449 FDEF,
5451 PUSHB_1,
5452 bci_serif_link2_common,
5453 CALL,
5455 PUSHB_1,
5456 bci_upper_lower_bound,
5457 CALL,
5459 ENDF,
5465 * bci_hint_glyph
5467 * This is the top-level glyph hinting function which parses the arguments
5468 * on the stack and calls subroutines.
5470 * in: action_0_func_idx
5471 * ... data ...
5472 * action_1_func_idx
5473 * ... data ...
5474 * ...
5476 * CVT: cvtl_is_subglyph
5477 * cvtl_use_strong_functions
5479 * sal: sal_stem_width_function
5481 * uses: bci_action_ip_before
5482 * bci_action_ip_after
5483 * bci_action_ip_on
5484 * bci_action_ip_between
5486 * bci_action_adjust_bound
5487 * bci_action_adjust_bound_serif
5488 * bci_action_adjust_bound_round
5489 * bci_action_adjust_bound_round_serif
5491 * bci_action_stem_bound
5492 * bci_action_stem_bound_serif
5493 * bci_action_stem_bound_round
5494 * bci_action_stem_bound_round_serif
5496 * bci_action_link
5497 * bci_action_link_serif
5498 * bci_action_link_round
5499 * bci_action_link_round_serif
5501 * bci_action_anchor
5502 * bci_action_anchor_serif
5503 * bci_action_anchor_round
5504 * bci_action_anchor_round_serif
5506 * bci_action_blue_anchor
5508 * bci_action_adjust
5509 * bci_action_adjust_serif
5510 * bci_action_adjust_round
5511 * bci_action_adjust_round_serif
5513 * bci_action_stem
5514 * bci_action_stem_serif
5515 * bci_action_stem_round
5516 * bci_action_stem_round_serif
5518 * bci_action_blue
5520 * bci_action_serif
5521 * bci_action_serif_lower_bound
5522 * bci_action_serif_upper_bound
5523 * bci_action_serif_upper_lower_bound
5525 * bci_action_serif_anchor
5526 * bci_action_serif_anchor_lower_bound
5527 * bci_action_serif_anchor_upper_bound
5528 * bci_action_serif_anchor_upper_lower_bound
5530 * bci_action_serif_link1
5531 * bci_action_serif_link1_lower_bound
5532 * bci_action_serif_link1_upper_bound
5533 * bci_action_serif_link1_upper_lower_bound
5535 * bci_action_serif_link2
5536 * bci_action_serif_link2_lower_bound
5537 * bci_action_serif_link2_upper_bound
5538 * bci_action_serif_link2_upper_lower_bound
5541 unsigned char FPGM(bci_hint_glyph) [] =
5544 PUSHB_1,
5545 bci_hint_glyph,
5546 FDEF,
5548 /* set up stem width function based on flag in CVT */
5549 PUSHB_4,
5550 sal_stem_width_function,
5551 bci_strong_stem_width,
5552 bci_smooth_stem_width,
5553 cvtl_use_strong_functions,
5554 RCVT,
5556 POP,
5558 ELSE,
5559 SWAP,
5560 POP,
5562 EIF,
5565 /* start_loop: */
5566 /* loop until all data on stack is used */
5567 CALL,
5568 PUSHB_1,
5570 NEG,
5571 PUSHB_1,
5573 DEPTH,
5575 JROT, /* goto start_loop */
5577 PUSHB_1,
5579 SZP2, /* set zp2 to normal zone 1 */
5580 IUP_y,
5582 ENDF,
5587 #define COPY_FPGM(func_name) \
5588 do \
5590 memcpy(bufp, fpgm_ ## func_name, \
5591 sizeof (fpgm_ ## func_name)); \
5592 bufp += sizeof (fpgm_ ## func_name); \
5593 } while (0)
5595 static FT_Error
5596 TA_table_build_fpgm(FT_Byte** fpgm,
5597 FT_ULong* fpgm_len,
5598 SFNT* sfnt,
5599 FONT* font)
5601 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5602 glyf_Data* data = (glyf_Data*)glyf_table->data;
5604 FT_UInt buf_len;
5605 FT_UInt len;
5606 FT_Byte* buf;
5607 FT_Byte* bufp;
5610 /* for compatibility with dumb bytecode interpreters or analyzers, */
5611 /* FDEFs are stored in ascending index order, without holes -- */
5612 /* note that some FDEFs are not always needed */
5613 /* (depending on options of `TTFautohint'), */
5614 /* but implementing dynamic FDEF indices would be a lot of work */
5616 buf_len = sizeof (FPGM(bci_align_top_a))
5617 + (font->increase_x_height
5618 ? (sizeof (FPGM(bci_align_top_b1a))
5620 + sizeof (FPGM(bci_align_top_b1b)))
5621 : sizeof (FPGM(bci_align_top_b2)))
5622 + sizeof (FPGM(bci_align_top_c))
5623 + sizeof (FPGM(bci_round))
5624 + sizeof (FPGM(bci_smooth_stem_width))
5625 + sizeof (FPGM(bci_get_best_width))
5626 + sizeof (FPGM(bci_strong_stem_width_a))
5628 + sizeof (FPGM(bci_strong_stem_width_b))
5629 + sizeof (FPGM(bci_loop_do))
5630 + sizeof (FPGM(bci_loop))
5631 + sizeof (FPGM(bci_cvt_rescale))
5632 + sizeof (FPGM(bci_cvt_rescale_range))
5633 + sizeof (FPGM(bci_vwidth_data_store))
5634 + sizeof (FPGM(bci_smooth_blue_round))
5635 + sizeof (FPGM(bci_strong_blue_round))
5636 + sizeof (FPGM(bci_blue_round_range))
5637 + sizeof (FPGM(bci_decrement_component_counter))
5638 + sizeof (FPGM(bci_get_point_extrema))
5639 + sizeof (FPGM(bci_nibbles))
5640 + sizeof (FPGM(bci_number_set_is_element))
5641 + sizeof (FPGM(bci_number_set_is_element2))
5643 + sizeof (FPGM(bci_create_segment))
5644 + sizeof (FPGM(bci_create_segments_a))
5646 + sizeof (FPGM(bci_create_segments_b))
5648 + sizeof (FPGM(bci_create_segments_0))
5649 + sizeof (FPGM(bci_create_segments_1))
5650 + sizeof (FPGM(bci_create_segments_2))
5651 + sizeof (FPGM(bci_create_segments_3))
5652 + sizeof (FPGM(bci_create_segments_4))
5653 + sizeof (FPGM(bci_create_segments_5))
5654 + sizeof (FPGM(bci_create_segments_6))
5655 + sizeof (FPGM(bci_create_segments_7))
5656 + sizeof (FPGM(bci_create_segments_8))
5657 + sizeof (FPGM(bci_create_segments_9))
5659 + sizeof (FPGM(bci_create_segments_composite_a))
5661 + sizeof (FPGM(bci_create_segments_composite_b))
5663 + sizeof (FPGM(bci_create_segments_composite_0))
5664 + sizeof (FPGM(bci_create_segments_composite_1))
5665 + sizeof (FPGM(bci_create_segments_composite_2))
5666 + sizeof (FPGM(bci_create_segments_composite_3))
5667 + sizeof (FPGM(bci_create_segments_composite_4))
5668 + sizeof (FPGM(bci_create_segments_composite_5))
5669 + sizeof (FPGM(bci_create_segments_composite_6))
5670 + sizeof (FPGM(bci_create_segments_composite_7))
5671 + sizeof (FPGM(bci_create_segments_composite_8))
5672 + sizeof (FPGM(bci_create_segments_composite_9))
5674 + sizeof (FPGM(bci_align_point))
5675 + sizeof (FPGM(bci_align_segment))
5676 + sizeof (FPGM(bci_align_segments))
5678 + sizeof (FPGM(bci_scale_contour))
5679 + sizeof (FPGM(bci_scale_glyph))
5680 + sizeof (FPGM(bci_scale_composite_glyph))
5681 + sizeof (FPGM(bci_shift_contour))
5682 + sizeof (FPGM(bci_shift_subglyph))
5684 + sizeof (FPGM(bci_ip_outer_align_point))
5685 + sizeof (FPGM(bci_ip_on_align_points))
5686 + sizeof (FPGM(bci_ip_between_align_point))
5687 + sizeof (FPGM(bci_ip_between_align_points))
5689 + sizeof (FPGM(bci_adjust_common))
5690 + sizeof (FPGM(bci_stem_common))
5691 + sizeof (FPGM(bci_serif_common))
5692 + sizeof (FPGM(bci_serif_anchor_common))
5693 + sizeof (FPGM(bci_serif_link1_common))
5694 + sizeof (FPGM(bci_serif_link2_common))
5696 + sizeof (FPGM(bci_lower_bound))
5697 + sizeof (FPGM(bci_upper_bound))
5698 + sizeof (FPGM(bci_upper_lower_bound))
5700 + sizeof (FPGM(bci_adjust_bound))
5701 + sizeof (FPGM(bci_stem_bound))
5702 + sizeof (FPGM(bci_link))
5703 + sizeof (FPGM(bci_anchor))
5704 + sizeof (FPGM(bci_adjust))
5705 + sizeof (FPGM(bci_stem))
5707 + sizeof (FPGM(bci_action_ip_before))
5708 + sizeof (FPGM(bci_action_ip_after))
5709 + sizeof (FPGM(bci_action_ip_on))
5710 + sizeof (FPGM(bci_action_ip_between))
5712 + sizeof (FPGM(bci_action_blue))
5713 + sizeof (FPGM(bci_action_blue_anchor))
5715 + sizeof (FPGM(bci_action_anchor))
5716 + sizeof (FPGM(bci_action_anchor_serif))
5717 + sizeof (FPGM(bci_action_anchor_round))
5718 + sizeof (FPGM(bci_action_anchor_round_serif))
5720 + sizeof (FPGM(bci_action_adjust))
5721 + sizeof (FPGM(bci_action_adjust_serif))
5722 + sizeof (FPGM(bci_action_adjust_round))
5723 + sizeof (FPGM(bci_action_adjust_round_serif))
5724 + sizeof (FPGM(bci_action_adjust_bound))
5725 + sizeof (FPGM(bci_action_adjust_bound_serif))
5726 + sizeof (FPGM(bci_action_adjust_bound_round))
5727 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5729 + sizeof (FPGM(bci_action_link))
5730 + sizeof (FPGM(bci_action_link_serif))
5731 + sizeof (FPGM(bci_action_link_round))
5732 + sizeof (FPGM(bci_action_link_round_serif))
5734 + sizeof (FPGM(bci_action_stem))
5735 + sizeof (FPGM(bci_action_stem_serif))
5736 + sizeof (FPGM(bci_action_stem_round))
5737 + sizeof (FPGM(bci_action_stem_round_serif))
5738 + sizeof (FPGM(bci_action_stem_bound))
5739 + sizeof (FPGM(bci_action_stem_bound_serif))
5740 + sizeof (FPGM(bci_action_stem_bound_round))
5741 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5743 + sizeof (FPGM(bci_action_serif))
5744 + sizeof (FPGM(bci_action_serif_lower_bound))
5745 + sizeof (FPGM(bci_action_serif_upper_bound))
5746 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5748 + sizeof (FPGM(bci_action_serif_anchor))
5749 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5750 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5751 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5753 + sizeof (FPGM(bci_action_serif_link1))
5754 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5755 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5756 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5758 + sizeof (FPGM(bci_action_serif_link2))
5759 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5760 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5761 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5763 + sizeof (FPGM(bci_hint_glyph));
5765 /* buffer length must be a multiple of four */
5766 len = (buf_len + 3) & ~3;
5767 buf = (FT_Byte*)malloc(len);
5768 if (!buf)
5769 return FT_Err_Out_Of_Memory;
5771 /* pad end of buffer with zeros */
5772 buf[len - 1] = 0x00;
5773 buf[len - 2] = 0x00;
5774 buf[len - 3] = 0x00;
5776 /* copy font program into buffer and fill in the missing variables */
5777 bufp = buf;
5779 COPY_FPGM(bci_align_top_a);
5780 if (font->increase_x_height)
5782 COPY_FPGM(bci_align_top_b1a);
5783 *(bufp++) = HIGH(font->increase_x_height);
5784 *(bufp++) = LOW(font->increase_x_height);
5785 COPY_FPGM(bci_align_top_b1b);
5787 else
5788 COPY_FPGM(bci_align_top_b2);
5789 COPY_FPGM(bci_align_top_c);
5791 COPY_FPGM(bci_round);
5792 COPY_FPGM(bci_smooth_stem_width);
5793 COPY_FPGM(bci_get_best_width);
5794 COPY_FPGM(bci_strong_stem_width_a);
5795 *(bufp++) = (unsigned char)data->num_used_styles;
5796 COPY_FPGM(bci_strong_stem_width_b);
5797 COPY_FPGM(bci_loop_do);
5798 COPY_FPGM(bci_loop);
5799 COPY_FPGM(bci_cvt_rescale);
5800 COPY_FPGM(bci_cvt_rescale_range);
5801 COPY_FPGM(bci_vwidth_data_store);
5802 COPY_FPGM(bci_smooth_blue_round);
5803 COPY_FPGM(bci_strong_blue_round);
5804 COPY_FPGM(bci_blue_round_range);
5805 COPY_FPGM(bci_decrement_component_counter);
5806 COPY_FPGM(bci_get_point_extrema);
5807 COPY_FPGM(bci_nibbles);
5808 COPY_FPGM(bci_number_set_is_element);
5809 COPY_FPGM(bci_number_set_is_element2);
5811 COPY_FPGM(bci_create_segment);
5812 COPY_FPGM(bci_create_segments_a);
5813 *(bufp++) = (unsigned char)data->num_used_styles;
5814 COPY_FPGM(bci_create_segments_b);
5816 COPY_FPGM(bci_create_segments_0);
5817 COPY_FPGM(bci_create_segments_1);
5818 COPY_FPGM(bci_create_segments_2);
5819 COPY_FPGM(bci_create_segments_3);
5820 COPY_FPGM(bci_create_segments_4);
5821 COPY_FPGM(bci_create_segments_5);
5822 COPY_FPGM(bci_create_segments_6);
5823 COPY_FPGM(bci_create_segments_7);
5824 COPY_FPGM(bci_create_segments_8);
5825 COPY_FPGM(bci_create_segments_9);
5827 COPY_FPGM(bci_create_segments_composite_a);
5828 *(bufp++) = (unsigned char)data->num_used_styles;
5829 COPY_FPGM(bci_create_segments_composite_b);
5831 COPY_FPGM(bci_create_segments_composite_0);
5832 COPY_FPGM(bci_create_segments_composite_1);
5833 COPY_FPGM(bci_create_segments_composite_2);
5834 COPY_FPGM(bci_create_segments_composite_3);
5835 COPY_FPGM(bci_create_segments_composite_4);
5836 COPY_FPGM(bci_create_segments_composite_5);
5837 COPY_FPGM(bci_create_segments_composite_6);
5838 COPY_FPGM(bci_create_segments_composite_7);
5839 COPY_FPGM(bci_create_segments_composite_8);
5840 COPY_FPGM(bci_create_segments_composite_9);
5842 COPY_FPGM(bci_align_point);
5843 COPY_FPGM(bci_align_segment);
5844 COPY_FPGM(bci_align_segments);
5846 COPY_FPGM(bci_scale_contour);
5847 COPY_FPGM(bci_scale_glyph);
5848 COPY_FPGM(bci_scale_composite_glyph);
5849 COPY_FPGM(bci_shift_contour);
5850 COPY_FPGM(bci_shift_subglyph);
5852 COPY_FPGM(bci_ip_outer_align_point);
5853 COPY_FPGM(bci_ip_on_align_points);
5854 COPY_FPGM(bci_ip_between_align_point);
5855 COPY_FPGM(bci_ip_between_align_points);
5857 COPY_FPGM(bci_adjust_common);
5858 COPY_FPGM(bci_stem_common);
5859 COPY_FPGM(bci_serif_common);
5860 COPY_FPGM(bci_serif_anchor_common);
5861 COPY_FPGM(bci_serif_link1_common);
5862 COPY_FPGM(bci_serif_link2_common);
5864 COPY_FPGM(bci_lower_bound);
5865 COPY_FPGM(bci_upper_bound);
5866 COPY_FPGM(bci_upper_lower_bound);
5868 COPY_FPGM(bci_adjust_bound);
5869 COPY_FPGM(bci_stem_bound);
5870 COPY_FPGM(bci_link);
5871 COPY_FPGM(bci_anchor);
5872 COPY_FPGM(bci_adjust);
5873 COPY_FPGM(bci_stem);
5875 COPY_FPGM(bci_action_ip_before);
5876 COPY_FPGM(bci_action_ip_after);
5877 COPY_FPGM(bci_action_ip_on);
5878 COPY_FPGM(bci_action_ip_between);
5880 COPY_FPGM(bci_action_blue);
5881 COPY_FPGM(bci_action_blue_anchor);
5883 COPY_FPGM(bci_action_anchor);
5884 COPY_FPGM(bci_action_anchor_serif);
5885 COPY_FPGM(bci_action_anchor_round);
5886 COPY_FPGM(bci_action_anchor_round_serif);
5888 COPY_FPGM(bci_action_adjust);
5889 COPY_FPGM(bci_action_adjust_serif);
5890 COPY_FPGM(bci_action_adjust_round);
5891 COPY_FPGM(bci_action_adjust_round_serif);
5892 COPY_FPGM(bci_action_adjust_bound);
5893 COPY_FPGM(bci_action_adjust_bound_serif);
5894 COPY_FPGM(bci_action_adjust_bound_round);
5895 COPY_FPGM(bci_action_adjust_bound_round_serif);
5897 COPY_FPGM(bci_action_link);
5898 COPY_FPGM(bci_action_link_serif);
5899 COPY_FPGM(bci_action_link_round);
5900 COPY_FPGM(bci_action_link_round_serif);
5902 COPY_FPGM(bci_action_stem);
5903 COPY_FPGM(bci_action_stem_serif);
5904 COPY_FPGM(bci_action_stem_round);
5905 COPY_FPGM(bci_action_stem_round_serif);
5906 COPY_FPGM(bci_action_stem_bound);
5907 COPY_FPGM(bci_action_stem_bound_serif);
5908 COPY_FPGM(bci_action_stem_bound_round);
5909 COPY_FPGM(bci_action_stem_bound_round_serif);
5911 COPY_FPGM(bci_action_serif);
5912 COPY_FPGM(bci_action_serif_lower_bound);
5913 COPY_FPGM(bci_action_serif_upper_bound);
5914 COPY_FPGM(bci_action_serif_upper_lower_bound);
5916 COPY_FPGM(bci_action_serif_anchor);
5917 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5918 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5919 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5921 COPY_FPGM(bci_action_serif_link1);
5922 COPY_FPGM(bci_action_serif_link1_lower_bound);
5923 COPY_FPGM(bci_action_serif_link1_upper_bound);
5924 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5926 COPY_FPGM(bci_action_serif_link2);
5927 COPY_FPGM(bci_action_serif_link2_lower_bound);
5928 COPY_FPGM(bci_action_serif_link2_upper_bound);
5929 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5931 COPY_FPGM(bci_hint_glyph);
5933 *fpgm = buf;
5934 *fpgm_len = buf_len;
5936 return FT_Err_Ok;
5940 FT_Error
5941 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5942 FONT* font)
5944 FT_Error error;
5946 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5947 glyf_Data* data = (glyf_Data*)glyf_table->data;
5949 FT_Byte* fpgm_buf;
5950 FT_ULong fpgm_len;
5953 error = TA_sfnt_add_table_info(sfnt);
5954 if (error)
5955 goto Exit;
5957 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5958 if (glyf_table->processed)
5960 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5961 goto Exit;
5964 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
5965 if (error)
5966 goto Exit;
5968 if (fpgm_len > sfnt->max_instructions)
5969 sfnt->max_instructions = fpgm_len;
5971 /* in case of success, `fpgm_buf' gets linked */
5972 /* and is eventually freed in `TA_font_unload' */
5973 error = TA_font_add_table(font,
5974 &sfnt->table_infos[sfnt->num_table_infos - 1],
5975 TTAG_fpgm, fpgm_len, fpgm_buf);
5976 if (error)
5977 free(fpgm_buf);
5978 else
5979 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5981 Exit:
5982 return error;
5985 /* end of tafpgm.c */