Run `update-copyright'.
[ttfautohint.git] / lib / tafpgm.c
blob99eea3f34465da5442039cd7760bee5a7c348419
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2013 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
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
52 #define DO_SCALE \
53 DUP, /* s: a a */ \
54 PUSHB_1, \
55 cvtl_scale, \
56 RCVT, \
57 MUL, /* delta * 2^10 */ \
58 PUSHB_1, \
59 cvtl_0x10000, \
60 RCVT, \
61 DIV, /* delta */ \
62 ADD /* a + delta */
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
71 * bci_round
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
76 * in: val
78 * out: ROUND(val)
81 unsigned char FPGM(bci_round) [] =
84 PUSHB_1,
85 bci_round,
86 FDEF,
88 PUSHB_1,
89 32,
90 ADD,
91 FLOOR,
93 ENDF,
99 * bci_smooth_stem_width
101 * This is the equivalent to the following code from function
102 * `ta_latin_compute_stem_width':
104 * dist = ABS(width)
106 * if (stem_is_serif
107 * && dist < 3*64)
108 * || is_extra_light:
109 * return width
110 * else if base_is_round:
111 * if dist < 80
112 * dist = 64
113 * else if dist < 56:
114 * dist = 56
116 * delta = ABS(dist - std_width)
118 * if delta < 40:
119 * dist = std_width
120 * if dist < 48
121 * dist = 48
122 * goto End
124 * if dist < 3*64:
125 * delta = dist
126 * dist = FLOOR(dist)
127 * delta = delta - dist
129 * if delta < 10:
130 * dist = dist + delta
131 * else if delta < 32:
132 * dist = dist + 10
133 * else if delta < 54:
134 * dist = dist + 54
135 * else
136 * dist = dist + delta
137 * else
138 * dist = ROUND(dist)
140 * End:
141 * if width < 0:
142 * dist = -dist
143 * return dist
146 * in: width
147 * stem_is_serif
148 * base_is_round
150 * out: new_width
152 * CVT: cvtl_is_extra_light
153 * std_width
155 * uses: bci_round
158 unsigned char FPGM(bci_smooth_stem_width_a) [] =
161 PUSHB_1,
162 bci_smooth_stem_width,
163 FDEF,
165 DUP,
166 ABS, /* s: base_is_round stem_is_serif width dist */
168 DUP,
169 PUSHB_1,
170 3*64,
171 LT, /* dist < 3*64 */
173 PUSHB_1,
175 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
176 AND, /* stem_is_serif && dist < 3*64 */
178 PUSHB_1,
179 cvtl_is_extra_light,
180 RCVT,
181 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
183 IF, /* s: base_is_round width dist */
184 POP,
185 SWAP,
186 POP, /* s: width */
188 ELSE,
189 ROLL, /* s: width dist base_is_round */
190 IF, /* s: width dist */
191 DUP,
192 PUSHB_1,
194 LT, /* dist < 80 */
195 IF, /* s: width dist */
196 POP,
197 PUSHB_1,
198 64, /* dist = 64 */
199 EIF,
201 ELSE,
202 DUP,
203 PUSHB_1,
205 LT, /* dist < 56 */
206 IF, /* s: width dist */
207 POP,
208 PUSHB_1,
209 56, /* dist = 56 */
210 EIF,
211 EIF,
213 DUP, /* s: width dist dist */
214 PUSHB_1,
218 /* %c, index of std_width */
220 unsigned char FPGM(bci_smooth_stem_width_b) [] =
223 RCVT,
224 SUB,
225 ABS, /* s: width dist delta */
227 PUSHB_1,
229 LT, /* delta < 40 */
230 IF, /* s: width dist */
231 POP,
232 PUSHB_1,
236 /* %c, index of std_width */
238 unsigned char FPGM(bci_smooth_stem_width_c) [] =
241 RCVT, /* dist = std_width */
242 DUP,
243 PUSHB_1,
245 LT, /* dist < 48 */
247 POP,
248 PUSHB_1,
249 48, /* dist = 48 */
250 EIF,
252 ELSE,
253 DUP, /* s: width dist dist */
254 PUSHB_1,
255 3*64,
256 LT, /* dist < 3*64 */
258 DUP, /* s: width delta dist */
259 FLOOR, /* dist = FLOOR(dist) */
260 DUP, /* s: width delta dist dist */
261 ROLL,
262 ROLL, /* s: width dist delta dist */
263 SUB, /* delta = delta - dist */
265 DUP, /* s: width dist delta delta */
266 PUSHB_1,
268 LT, /* delta < 10 */
269 IF, /* s: width dist delta */
270 ADD, /* dist = dist + delta */
272 ELSE,
273 DUP,
274 PUSHB_1,
276 LT, /* delta < 32 */
278 POP,
279 PUSHB_1,
281 ADD, /* dist = dist + 10 */
283 ELSE,
284 DUP,
285 PUSHB_1,
287 LT, /* delta < 54 */
289 POP,
290 PUSHB_1,
292 ADD, /* dist = dist + 54 */
294 ELSE,
295 ADD, /* dist = dist + delta */
297 EIF,
298 EIF,
299 EIF,
301 ELSE,
302 PUSHB_1,
303 bci_round,
304 CALL, /* dist = round(dist) */
306 EIF,
307 EIF,
309 SWAP, /* s: dist width */
310 PUSHB_1,
312 LT, /* width < 0 */
314 NEG, /* dist = -dist */
315 EIF,
316 EIF,
318 ENDF,
324 * bci_get_best_width
326 * An auxiliary function for `bci_strong_stem_width'.
328 * in: n (initialized with CVT index for first vertical width)
329 * dist
331 * out: n+1
332 * dist
334 * sal: sal_best
335 * sal_ref
337 * CVT: widths[]
340 unsigned char FPGM(bci_get_best_width) [] =
343 PUSHB_1,
344 bci_get_best_width,
345 FDEF,
347 DUP,
348 RCVT, /* s: dist n w */
349 DUP,
350 PUSHB_1,
352 CINDEX, /* s: dist n w w dist */
353 SUB,
354 ABS, /* s: dist n w d */
355 DUP,
356 PUSHB_1,
357 sal_best,
358 RS, /* s: dist n w d d best */
359 LT, /* d < best */
361 PUSHB_1,
362 sal_best,
363 SWAP,
364 WS, /* best = d */
365 PUSHB_1,
366 sal_ref,
367 SWAP,
368 WS, /* reference = w */
370 ELSE,
371 POP,
372 POP,
373 EIF,
375 PUSHB_1,
377 ADD, /* n = n + 1 */
379 ENDF,
385 * bci_strong_stem_width
387 * This is the equivalent to the following code (function
388 * `ta_latin_snap_width' and some lines from
389 * `ta_latin_compute_stem_width'):
391 * best = 64 + 32 + 2;
392 * reference = width
393 * dist = ABS(width)
395 * for n in 0 .. num_widths:
396 * w = widths[n]
397 * d = ABS(dist - w)
399 * if d < best:
400 * best = d
401 * reference = w;
403 * if dist >= reference:
404 * if dist < ROUND(reference) + 48:
405 * dist = reference
406 * else
407 * if dist > ROUND(reference) - 48:
408 * dist = reference
410 * if dist >= 64:
411 * dist = ROUND(dist)
412 * else
413 * dist = 64
415 * if width < 0:
416 * dist = -dist
417 * return dist
419 * in: width
420 * stem_is_serif (unused)
421 * base_is_round (unused)
423 * out: new_width
425 * sal: sal_best
426 * sal_ref
428 * CVT: widths[]
430 * uses: bci_get_best_width
431 * bci_round
434 unsigned char FPGM(bci_strong_stem_width_a) [] =
437 PUSHB_1,
438 bci_strong_stem_width,
439 FDEF,
441 SWAP,
442 POP,
443 SWAP,
444 POP,
445 DUP,
446 ABS, /* s: width dist */
448 PUSHB_2,
449 sal_best,
450 64 + 32 + 2,
451 WS, /* sal_best = 98 */
453 DUP,
454 PUSHB_1,
455 sal_ref,
456 SWAP,
457 WS, /* sal_ref = width */
459 PUSHB_3,
462 /* %c, first index of vertical widths */
463 /* %c, number of vertical widths */
465 unsigned char FPGM(bci_strong_stem_width_b) [] =
468 bci_get_best_width,
469 LOOPCALL,
471 POP, /* s: width dist */
472 DUP,
473 PUSHB_1,
474 sal_ref,
475 RS, /* s: width dist dist reference */
476 DUP,
477 ROLL,
478 DUP,
479 ROLL,
480 PUSHB_1,
481 bci_round,
482 CALL, /* s: width dist reference dist dist ROUND(reference) */
483 PUSHB_2,
486 CINDEX,
487 ROLL, /* s: width dist reference dist ROUND(reference) 48 reference dist */
489 LTEQ, /* dist >= reference */
490 IF, /* s: width dist reference dist ROUND(reference) 48 */
491 ADD,
492 LT, /* dist < ROUND(reference) + 48 */
494 ELSE,
495 SUB,
496 GT, /* dist > ROUND(reference) - 48 */
497 EIF,
500 SWAP, /* s: width reference dist */
501 EIF,
502 POP,
504 DUP,
505 PUSHB_1,
507 GTEQ, /* dist >= 64 */
509 PUSHB_1,
510 bci_round,
511 CALL, /* dist = ROUND(dist) */
513 ELSE,
514 POP,
515 PUSHB_1,
516 64, /* dist = 64 */
517 EIF,
519 SWAP, /* s: dist width */
520 PUSHB_1,
522 LT, /* width < 0 */
524 NEG, /* dist = -dist */
525 EIF,
527 ENDF,
533 * bci_do_loop
535 * An auxiliary function for `bci_loop'.
537 * sal: sal_i (gets incremented by 2 after execution)
538 * sal_func
540 * uses: func[sal_func]
543 unsigned char FPGM(bci_loop_do) [] =
546 PUSHB_1,
547 bci_loop_do,
548 FDEF,
550 PUSHB_1,
551 sal_func,
553 CALL,
555 PUSHB_3,
556 sal_i,
558 sal_i,
560 ADD, /* sal_i = sal_i + 2 */
563 ENDF,
569 * bci_loop
571 * Take a range `start'..`end' and a function number and apply the
572 * associated function to the range elements `start', `start+2',
573 * `start+4', ...
575 * in: func_num
576 * end
577 * start
579 * sal: sal_i (counter initialized with `start')
580 * sal_func (`func_num')
582 * uses: bci_loop_do
585 unsigned char FPGM(bci_loop) [] =
588 PUSHB_1,
589 bci_loop,
590 FDEF,
592 PUSHB_1,
593 sal_func,
594 SWAP,
595 WS, /* sal_func = func_num */
597 SWAP,
598 DUP,
599 PUSHB_1,
600 sal_i,
601 SWAP,
602 WS, /* sal_i = start */
604 SUB,
605 PUSHB_1,
606 2*64,
607 DIV,
608 PUSHB_1,
610 ADD, /* number of loops ((end - start) / 2 + 1) */
612 PUSHB_1,
613 bci_loop_do,
614 LOOPCALL,
616 ENDF,
622 * bci_cvt_rescale
624 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
626 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
627 * consequently, the calculation `a * b/c' is done as `a + delta' with
628 * `delta = a * (b-c)/c'. This avoids overflow.
630 * in: cvt_idx
632 * out: cvt_idx+1
634 * CVT: cvtl_scale
635 * cvtl_0x10000
638 unsigned char FPGM(bci_cvt_rescale) [] =
641 PUSHB_1,
642 bci_cvt_rescale,
643 FDEF,
645 DUP,
646 DUP,
647 RCVT,
648 DO_SCALE,
649 WCVTP,
651 PUSHB_1,
653 ADD,
655 ENDF,
661 * bci_blue_round
663 * Round a blue ref value and adjust its corresponding shoot value.
665 * in: ref_idx
667 * out: ref_idx+1
669 * uses: bci_round
672 unsigned char FPGM(bci_blue_round_a) [] =
675 PUSHB_1,
676 bci_blue_round,
677 FDEF,
679 DUP,
680 DUP,
681 RCVT, /* s: ref_idx ref_idx ref */
683 DUP,
684 PUSHB_1,
685 bci_round,
686 CALL,
687 SWAP, /* s: ref_idx ref_idx round(ref) ref */
689 PUSHB_2,
693 /* %c, blue_count */
695 unsigned char FPGM(bci_blue_round_b) [] =
699 CINDEX,
700 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
701 DUP,
702 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
704 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
705 SWAP,
706 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
707 DUP,
708 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
710 DUP,
711 PUSHB_1,
713 LT, /* delta < 32 */
715 POP,
716 PUSHB_1,
717 0, /* delta = 0 */
719 ELSE,
720 PUSHB_1,
722 LT, /* delta < 48 */
724 PUSHB_1,
725 32, /* delta = 32 */
727 ELSE,
728 PUSHB_1,
729 64, /* delta = 64 */
730 EIF,
731 EIF,
733 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
734 PUSHB_1,
736 LT, /* dist < 0 */
738 NEG, /* delta = -delta */
739 EIF,
741 PUSHB_1,
743 CINDEX,
744 SWAP,
745 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
747 WCVTP,
748 WCVTP,
750 PUSHB_1,
752 ADD, /* s: (ref_idx + 1) */
754 ENDF,
760 * bci_decrement_component_counter
762 * An auxiliary function for composite glyphs.
764 * CVT: cvtl_is_subglyph
767 unsigned char FPGM(bci_decrement_component_counter) [] =
770 PUSHB_1,
771 bci_decrement_component_counter,
772 FDEF,
774 /* decrement `cvtl_is_subglyph' counter */
775 PUSHB_2,
776 cvtl_is_subglyph,
777 cvtl_is_subglyph,
778 RCVT,
779 PUSHB_1,
781 SUB,
782 WCVTP,
784 ENDF,
790 * bci_get_point_extrema
792 * An auxiliary function for `bci_create_segment'.
794 * in: point-1
796 * out: point
798 * sal: sal_point_min
799 * sal_point_max
802 unsigned char FPGM(bci_get_point_extrema) [] =
805 PUSHB_1,
806 bci_get_point_extrema,
807 FDEF,
809 PUSHB_1,
811 ADD, /* s: point */
812 DUP,
813 DUP,
815 /* check whether `point' is a new minimum */
816 PUSHB_1,
817 sal_point_min,
818 RS, /* s: point point point point_min */
819 MD_orig,
820 /* if distance is negative, we have a new minimum */
821 PUSHB_1,
824 IF, /* s: point point */
825 DUP,
826 PUSHB_1,
827 sal_point_min,
828 SWAP,
830 EIF,
832 /* check whether `point' is a new maximum */
833 PUSHB_1,
834 sal_point_max,
835 RS, /* s: point point point_max */
836 MD_orig,
837 /* if distance is positive, we have a new maximum */
838 PUSHB_1,
841 IF, /* s: point */
842 DUP,
843 PUSHB_1,
844 sal_point_max,
845 SWAP,
847 EIF, /* s: point */
849 ENDF,
855 * bci_nibbles
857 * Pop a byte with two delta arguments in its nibbles and push the
858 * expanded arguments separately as two bytes.
860 * in: 16 * (end - start) + (start - base)
862 * out: start
863 * end
865 * sal: sal_base (set to `end' at return)
869 unsigned char FPGM(bci_nibbles) [] =
871 PUSHB_1,
872 bci_nibbles,
873 FDEF,
875 DUP,
876 PUSHW_1,
877 0x04, /* 16*64 */
878 0x00,
879 DIV, /* s: in hnibble */
880 DUP,
881 PUSHW_1,
882 0x04, /* 16*64 */
883 0x00,
884 MUL, /* s: in hnibble (hnibble * 16) */
885 ROLL,
886 SWAP,
887 SUB, /* s: hnibble lnibble */
889 PUSHB_1,
890 sal_base,
892 ADD, /* s: hnibble start */
893 DUP,
894 ROLL,
895 ADD, /* s: start end */
897 DUP,
898 PUSHB_1,
899 sal_base,
900 SWAP,
901 WS, /* sal_base = end */
903 SWAP,
905 ENDF,
911 * bci_number_set_is_element
913 * Pop values from stack until it is empty. If one of them is equal to
914 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
915 * otherwise).
917 * in: ppem_value_1
918 * ppem_value_2
919 * ...
921 * CVT: cvtl_is_element
924 unsigned char FPGM(bci_number_set_is_element) [] =
927 PUSHB_1,
928 bci_number_set_is_element,
929 FDEF,
931 /* start_loop: */
932 MPPEM,
935 PUSHB_2,
936 cvtl_is_element,
938 WCVTP,
939 EIF,
941 DEPTH,
942 PUSHB_1,
944 NEG,
945 SWAP,
946 JROT, /* goto start_loop if stack depth != 0 */
948 ENDF,
954 * bci_number_set_is_element2
956 * Pop value ranges from stack until it is empty. If one of them contains
957 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
958 * otherwise).
960 * in: ppem_range_1_start
961 * ppem_range_1_end
962 * ppem_range_2_start
963 * ppem_range_2_end
964 * ...
966 * CVT: cvtl_is_element
969 unsigned char FPGM(bci_number_set_is_element2) [] =
972 PUSHB_1,
973 bci_number_set_is_element2,
974 FDEF,
976 /* start_loop: */
977 MPPEM,
978 LTEQ,
980 MPPEM,
981 GTEQ,
983 PUSHB_2,
984 cvtl_is_element,
986 WCVTP,
987 EIF,
988 ELSE,
989 POP,
990 EIF,
992 DEPTH,
993 PUSHB_1,
995 NEG,
996 SWAP,
997 JROT, /* goto start_loop if stack depth != 0 */
999 ENDF,
1005 * bci_create_segment
1007 * Store start and end point of a segment in the storage area,
1008 * then construct a point in the twilight zone to represent it.
1010 * This function is used by `bci_create_segments'.
1012 * in: start
1013 * end
1014 * [last (if wrap-around segment)]
1015 * [first (if wrap-around segment)]
1017 * sal: sal_i (start of current segment)
1018 * sal_j (current twilight point)
1019 * sal_point_min
1020 * sal_point_max
1021 * sal_base
1022 * sal_num_packed_segments
1024 * CVT: cvtl_scale
1025 * cvtl_0x10000
1026 * cvtl_temp
1028 * uses: bci_get_point_extrema
1029 * bci_nibbles
1031 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1032 * delta values in nibbles (without a wrap-around segment).
1035 unsigned char FPGM(bci_create_segment) [] =
1038 PUSHB_1,
1039 bci_create_segment,
1040 FDEF,
1042 PUSHB_2,
1044 sal_num_packed_segments,
1046 NEQ,
1048 PUSHB_2,
1049 sal_num_packed_segments,
1050 sal_num_packed_segments,
1052 PUSHB_1,
1054 SUB,
1055 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1057 PUSHB_1,
1058 bci_nibbles,
1059 CALL,
1060 EIF,
1062 PUSHB_1,
1063 sal_i,
1065 PUSHB_1,
1067 CINDEX,
1068 WS, /* sal[sal_i] = start */
1070 /* initialize inner loop(s) */
1071 PUSHB_2,
1072 sal_point_min,
1074 CINDEX,
1075 WS, /* sal_point_min = start */
1076 PUSHB_2,
1077 sal_point_max,
1079 CINDEX,
1080 WS, /* sal_point_max = start */
1082 PUSHB_1,
1084 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1086 SWAP,
1087 DUP,
1088 PUSHB_1,
1090 CINDEX, /* s: start end end start */
1091 LT, /* start > end */
1093 /* we have a wrap-around segment with two more arguments */
1094 /* to give the last and first point of the contour, respectively; */
1095 /* our job is to store a segment `start'-`last', */
1096 /* and to get extrema for the two segments */
1097 /* `start'-`last' and `first'-`end' */
1099 /* s: first last start end */
1100 PUSHB_2,
1102 sal_i,
1104 ADD,
1105 PUSHB_1,
1107 CINDEX,
1108 WS, /* sal[sal_i + 1] = last */
1110 ROLL,
1111 ROLL, /* s: first end last start */
1112 DUP,
1113 ROLL,
1114 SWAP, /* s: first end start last start */
1115 SUB, /* s: first end start loop_count */
1117 PUSHB_1,
1118 bci_get_point_extrema,
1119 LOOPCALL,
1120 /* clean up stack */
1121 POP,
1123 SWAP, /* s: end first */
1124 PUSHB_1,
1126 SUB,
1127 DUP,
1128 ROLL, /* s: (first - 1) (first - 1) end */
1129 SWAP,
1130 SUB, /* s: (first - 1) loop_count */
1132 PUSHB_1,
1133 bci_get_point_extrema,
1134 LOOPCALL,
1135 /* clean up stack */
1136 POP,
1138 ELSE, /* s: start end */
1139 PUSHB_2,
1141 sal_i,
1143 ADD,
1144 PUSHB_1,
1146 CINDEX,
1147 WS, /* sal[sal_i + 1] = end */
1149 PUSHB_1,
1151 CINDEX,
1152 SUB, /* s: start loop_count */
1154 PUSHB_1,
1155 bci_get_point_extrema,
1156 LOOPCALL,
1157 /* clean up stack */
1158 POP,
1159 EIF,
1161 /* the twilight point representing a segment */
1162 /* is in the middle between the minimum and maximum */
1163 PUSHB_1,
1164 sal_point_min,
1166 GC_orig,
1167 PUSHB_1,
1168 sal_point_max,
1170 GC_orig,
1171 ADD,
1172 PUSHB_1,
1173 2*64,
1174 DIV, /* s: middle_pos */
1176 DO_SCALE, /* middle_pos = middle_pos * scale */
1178 /* write it to temporary CVT location */
1179 PUSHB_2,
1180 cvtl_temp,
1182 SZP0, /* set zp0 to twilight zone 0 */
1183 SWAP,
1184 WCVTP,
1186 /* create twilight point with index `sal_j' */
1187 PUSHB_1,
1188 sal_j,
1190 PUSHB_1,
1191 cvtl_temp,
1192 MIAP_noround,
1194 PUSHB_3,
1195 sal_j,
1197 sal_j,
1199 ADD, /* twilight_point = twilight_point + 1 */
1202 ENDF,
1208 * bci_create_segments
1210 * This is the top-level entry function.
1212 * It pops point ranges from the stack to define segments, computes
1213 * twilight points to represent segments, and finally calls
1214 * `bci_hint_glyph' to handle the rest.
1216 * in: num_packed_segments
1217 * num_segments (N)
1218 * segment_start_0
1219 * segment_end_0
1220 * [contour_last 0 (if wrap-around segment)]
1221 * [contour_first 0 (if wrap-around segment)]
1222 * segment_start_1
1223 * segment_end_1
1224 * [contour_last 0 (if wrap-around segment)]
1225 * [contour_first 0 (if wrap-around segment)]
1226 * ...
1227 * segment_start_(N-1)
1228 * segment_end_(N-1)
1229 * [contour_last (N-1) (if wrap-around segment)]
1230 * [contour_first (N-1) (if wrap-around segment)]
1231 * ... stuff for bci_hint_glyph ...
1233 * sal: sal_i (start of current segment)
1234 * sal_j (current twilight point)
1235 * sal_num_packed_segments
1236 * sal_base (the base for delta values in nibbles)
1238 * CVT: cvtl_is_subglyph
1240 * uses: bci_create_segment
1241 * bci_loop
1242 * bci_hint_glyph
1244 * If `num_packed_segments' is set to p, the first p start/end pairs are
1245 * stored as delta values in nibbles, with the `start' delta in the lower
1246 * nibble (and there are no wrap-around segments). For example, if the
1247 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1248 * stack are 0x21, 0x32, and 0x14.
1252 unsigned char FPGM(bci_create_segments) [] =
1255 PUSHB_1,
1256 bci_create_segments,
1257 FDEF,
1259 /* only do something if we are not a subglyph */
1260 PUSHB_2,
1262 cvtl_is_subglyph,
1263 RCVT,
1266 /* all our measurements are taken along the y axis */
1267 SVTCA_y,
1269 PUSHB_1,
1270 sal_num_packed_segments,
1271 SWAP,
1274 DUP,
1275 ADD,
1276 PUSHB_1,
1278 SUB, /* delta = (2*num_segments - 1) */
1280 PUSHB_6,
1281 sal_segment_offset,
1282 sal_segment_offset,
1284 sal_j,
1286 sal_base,
1288 WS, /* sal_base = 0 */
1289 WS, /* sal_j = 0 (point offset) */
1291 ROLL,
1292 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1294 PUSHB_2,
1295 bci_create_segment,
1296 bci_loop,
1297 CALL,
1299 PUSHB_1,
1300 bci_hint_glyph,
1301 CALL,
1303 ELSE,
1304 CLEAR,
1305 EIF,
1307 ENDF,
1313 * bci_create_segments_X
1315 * Top-level routines for calling `bci_create_segments'.
1318 unsigned char FPGM(bci_create_segments_0) [] =
1321 PUSHB_1,
1322 bci_create_segments_0,
1323 FDEF,
1325 PUSHB_2,
1327 bci_create_segments,
1328 CALL,
1330 ENDF,
1334 unsigned char FPGM(bci_create_segments_1) [] =
1337 PUSHB_1,
1338 bci_create_segments_1,
1339 FDEF,
1341 PUSHB_2,
1343 bci_create_segments,
1344 CALL,
1346 ENDF,
1350 unsigned char FPGM(bci_create_segments_2) [] =
1353 PUSHB_1,
1354 bci_create_segments_2,
1355 FDEF,
1357 PUSHB_2,
1359 bci_create_segments,
1360 CALL,
1362 ENDF,
1366 unsigned char FPGM(bci_create_segments_3) [] =
1369 PUSHB_1,
1370 bci_create_segments_3,
1371 FDEF,
1373 PUSHB_2,
1375 bci_create_segments,
1376 CALL,
1378 ENDF,
1382 unsigned char FPGM(bci_create_segments_4) [] =
1385 PUSHB_1,
1386 bci_create_segments_4,
1387 FDEF,
1389 PUSHB_2,
1391 bci_create_segments,
1392 CALL,
1394 ENDF,
1398 unsigned char FPGM(bci_create_segments_5) [] =
1401 PUSHB_1,
1402 bci_create_segments_5,
1403 FDEF,
1405 PUSHB_2,
1407 bci_create_segments,
1408 CALL,
1410 ENDF,
1414 unsigned char FPGM(bci_create_segments_6) [] =
1417 PUSHB_1,
1418 bci_create_segments_6,
1419 FDEF,
1421 PUSHB_2,
1423 bci_create_segments,
1424 CALL,
1426 ENDF,
1430 unsigned char FPGM(bci_create_segments_7) [] =
1433 PUSHB_1,
1434 bci_create_segments_7,
1435 FDEF,
1437 PUSHB_2,
1439 bci_create_segments,
1440 CALL,
1442 ENDF,
1446 unsigned char FPGM(bci_create_segments_8) [] =
1449 PUSHB_1,
1450 bci_create_segments_8,
1451 FDEF,
1453 PUSHB_2,
1455 bci_create_segments,
1456 CALL,
1458 ENDF,
1462 unsigned char FPGM(bci_create_segments_9) [] =
1465 PUSHB_1,
1466 bci_create_segments_9,
1467 FDEF,
1469 PUSHB_2,
1471 bci_create_segments,
1472 CALL,
1474 ENDF,
1480 * bci_create_segments_composite
1482 * The same as `bci_create_segments'.
1483 * It also decrements the composite component counter.
1485 * sal: sal_num_packed_segments
1486 * sal_segment_offset
1488 * CVT: cvtl_is_subglyph
1490 * uses: bci_decrement_component_counter
1491 * bci_create_segment
1492 * bci_loop
1493 * bci_hint_glyph
1496 unsigned char FPGM(bci_create_segments_composite) [] =
1499 PUSHB_1,
1500 bci_create_segments_composite,
1501 FDEF,
1503 PUSHB_1,
1504 bci_decrement_component_counter,
1505 CALL,
1507 /* only do something if we are not a subglyph */
1508 PUSHB_2,
1510 cvtl_is_subglyph,
1511 RCVT,
1514 /* all our measurements are taken along the y axis */
1515 SVTCA_y,
1517 PUSHB_1,
1518 sal_num_packed_segments,
1519 SWAP,
1522 DUP,
1523 ADD,
1524 PUSHB_1,
1526 SUB, /* delta = (2*num_segments - 1) */
1528 PUSHB_6,
1529 sal_segment_offset,
1530 sal_segment_offset,
1532 sal_j,
1534 sal_base,
1536 WS, /* sal_base = 0 */
1537 WS, /* sal_j = 0 (point offset) */
1539 ROLL,
1540 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1542 PUSHB_2,
1543 bci_create_segment,
1544 bci_loop,
1545 CALL,
1547 PUSHB_1,
1548 bci_hint_glyph,
1549 CALL,
1551 ELSE,
1552 CLEAR,
1553 EIF,
1555 ENDF,
1561 * bci_create_segments_composite_X
1563 * Top-level routines for calling `bci_create_segments_composite'.
1566 unsigned char FPGM(bci_create_segments_composite_0) [] =
1569 PUSHB_1,
1570 bci_create_segments_composite_0,
1571 FDEF,
1573 PUSHB_2,
1575 bci_create_segments_composite,
1576 CALL,
1578 ENDF,
1582 unsigned char FPGM(bci_create_segments_composite_1) [] =
1585 PUSHB_1,
1586 bci_create_segments_composite_1,
1587 FDEF,
1589 PUSHB_2,
1591 bci_create_segments_composite,
1592 CALL,
1594 ENDF,
1598 unsigned char FPGM(bci_create_segments_composite_2) [] =
1601 PUSHB_1,
1602 bci_create_segments_composite_2,
1603 FDEF,
1605 PUSHB_2,
1607 bci_create_segments_composite,
1608 CALL,
1610 ENDF,
1614 unsigned char FPGM(bci_create_segments_composite_3) [] =
1617 PUSHB_1,
1618 bci_create_segments_composite_3,
1619 FDEF,
1621 PUSHB_2,
1623 bci_create_segments_composite,
1624 CALL,
1626 ENDF,
1630 unsigned char FPGM(bci_create_segments_composite_4) [] =
1633 PUSHB_1,
1634 bci_create_segments_composite_4,
1635 FDEF,
1637 PUSHB_2,
1639 bci_create_segments_composite,
1640 CALL,
1642 ENDF,
1646 unsigned char FPGM(bci_create_segments_composite_5) [] =
1649 PUSHB_1,
1650 bci_create_segments_composite_5,
1651 FDEF,
1653 PUSHB_2,
1655 bci_create_segments_composite,
1656 CALL,
1658 ENDF,
1662 unsigned char FPGM(bci_create_segments_composite_6) [] =
1665 PUSHB_1,
1666 bci_create_segments_composite_6,
1667 FDEF,
1669 PUSHB_2,
1671 bci_create_segments_composite,
1672 CALL,
1674 ENDF,
1678 unsigned char FPGM(bci_create_segments_composite_7) [] =
1681 PUSHB_1,
1682 bci_create_segments_composite_7,
1683 FDEF,
1685 PUSHB_2,
1687 bci_create_segments_composite,
1688 CALL,
1690 ENDF,
1694 unsigned char FPGM(bci_create_segments_composite_8) [] =
1697 PUSHB_1,
1698 bci_create_segments_composite_8,
1699 FDEF,
1701 PUSHB_2,
1703 bci_create_segments_composite,
1704 CALL,
1706 ENDF,
1710 unsigned char FPGM(bci_create_segments_composite_9) [] =
1713 PUSHB_1,
1714 bci_create_segments_composite_9,
1715 FDEF,
1717 PUSHB_2,
1719 bci_create_segments_composite,
1720 CALL,
1722 ENDF,
1728 * bci_align_point
1730 * An auxiliary function for `bci_align_segment'.
1732 * in: point
1734 * out: point+1
1737 unsigned char FPGM(bci_align_point) [] =
1740 PUSHB_1,
1741 bci_align_point,
1742 FDEF,
1744 DUP,
1745 ALIGNRP, /* align point with rp0 */
1747 PUSHB_1,
1749 ADD,
1751 ENDF,
1757 * bci_align_segment
1759 * Align all points in a segment to the twilight point in rp0.
1760 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1762 * in: segment_index
1764 * sal: sal_segment_offset
1766 * uses: bci_align_point
1769 unsigned char FPGM(bci_align_segment) [] =
1772 PUSHB_1,
1773 bci_align_segment,
1774 FDEF,
1776 /* we need the values of `sal_segment_offset + 2*segment_index' */
1777 /* and `sal_segment_offset + 2*segment_index + 1' */
1778 DUP,
1779 ADD,
1780 PUSHB_1,
1781 sal_segment_offset,
1782 ADD,
1783 DUP,
1785 SWAP,
1786 PUSHB_1,
1788 ADD,
1789 RS, /* s: first last */
1791 PUSHB_1,
1793 CINDEX, /* s: first last first */
1794 SUB,
1795 PUSHB_1,
1797 ADD, /* s: first loop_count */
1799 PUSHB_1,
1800 bci_align_point,
1801 LOOPCALL,
1802 /* clean up stack */
1803 POP,
1805 ENDF,
1811 * bci_align_segments
1813 * Align segments to the twilight point in rp0.
1814 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1816 * in: first_segment
1817 * loop_counter (N)
1818 * segment_1
1819 * segment_2
1820 * ...
1821 * segment_N
1823 * uses: bci_align_segment
1826 unsigned char FPGM(bci_align_segments) [] =
1829 PUSHB_1,
1830 bci_align_segments,
1831 FDEF,
1833 PUSHB_1,
1834 bci_align_segment,
1835 CALL,
1837 PUSHB_1,
1838 bci_align_segment,
1839 LOOPCALL,
1841 ENDF,
1847 * bci_scale_contour
1849 * Scale a contour using two points giving the maximum and minimum
1850 * coordinates.
1852 * It expects that no point on the contour is touched.
1854 * in: min_point
1855 * max_point
1857 * CVT: cvtl_scale
1858 * cvtl_0x10000
1861 unsigned char FPGM(bci_scale_contour) [] =
1864 PUSHB_1,
1865 bci_scale_contour,
1866 FDEF,
1868 DUP,
1869 DUP,
1870 GC_orig,
1871 DUP,
1872 DO_SCALE, /* min_pos_new = min_pos * scale */
1873 SWAP,
1874 SUB,
1875 SHPIX,
1877 /* don't scale a single-point contour twice */
1878 SWAP,
1879 DUP,
1880 ROLL,
1881 NEQ,
1883 DUP,
1884 GC_orig,
1885 DUP,
1886 DO_SCALE, /* max_pos_new = max_pos * scale */
1887 SWAP,
1888 SUB,
1889 SHPIX,
1891 ELSE,
1892 POP,
1893 EIF,
1895 ENDF,
1901 * bci_scale_glyph
1903 * Scale a glyph using a list of points (two points per contour, giving
1904 * the maximum and mininum coordinates).
1906 * It expects that no point in the glyph is touched.
1908 * Note that the point numbers are sorted in ascending order;
1909 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1910 * contour without specifying which one is the minimum and maximum.
1912 * in: num_contours (N)
1913 * min_point_1
1914 * max_point_1
1915 * min_point_2
1916 * max_point_2
1917 * ...
1918 * min_point_N
1919 * max_point_N
1921 * CVT: cvtl_is_subglyph
1923 * uses: bci_scale_contour
1926 unsigned char FPGM(bci_scale_glyph) [] =
1929 PUSHB_1,
1930 bci_scale_glyph,
1931 FDEF,
1933 /* only do something if we are not a subglyph */
1934 PUSHB_2,
1936 cvtl_is_subglyph,
1937 RCVT,
1940 /* all our measurements are taken along the y axis */
1941 SVTCA_y,
1943 PUSHB_1,
1945 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1947 PUSHB_1,
1948 bci_scale_contour,
1949 LOOPCALL,
1951 PUSHB_1,
1953 SZP2, /* set zp2 to normal zone 1 */
1954 IUP_y,
1956 ELSE,
1957 CLEAR,
1958 EIF,
1960 ENDF,
1966 * bci_scale_composite_glyph
1968 * The same as `bci_scale_glyph'.
1969 * It also decrements the composite component counter.
1971 * CVT: cvtl_is_subglyph
1973 * uses: bci_decrement_component_counter
1974 * bci_scale_contour
1977 unsigned char FPGM(bci_scale_composite_glyph) [] =
1980 PUSHB_1,
1981 bci_scale_composite_glyph,
1982 FDEF,
1984 PUSHB_1,
1985 bci_decrement_component_counter,
1986 CALL,
1988 /* only do something if we are not a subglyph */
1989 PUSHB_2,
1991 cvtl_is_subglyph,
1992 RCVT,
1995 /* all our measurements are taken along the y axis */
1996 SVTCA_y,
1998 PUSHB_1,
2000 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2002 PUSHB_1,
2003 bci_scale_contour,
2004 LOOPCALL,
2006 PUSHB_1,
2008 SZP2, /* set zp2 to normal zone 1 */
2009 IUP_y,
2011 ELSE,
2012 CLEAR,
2013 EIF,
2015 ENDF,
2021 * bci_shift_contour
2023 * Shift a contour by a given amount.
2025 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2026 * point to the normal zone 1.
2028 * in: contour
2030 * out: contour+1
2033 unsigned char FPGM(bci_shift_contour) [] =
2036 PUSHB_1,
2037 bci_shift_contour,
2038 FDEF,
2040 DUP,
2041 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2043 PUSHB_1,
2045 ADD,
2047 ENDF,
2053 * bci_shift_subglyph
2055 * Shift a subglyph. To be more specific, it corrects the already applied
2056 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2057 * also.
2059 * If this function is called, a point `x' in the subglyph has been scaled
2060 * already (during the hinting of the subglyph itself), and `offset' has
2061 * been applied also:
2063 * x -> x * scale + offset (1)
2065 * However, the offset should be applied first, then the scaling:
2067 * x -> (x + offset) * scale (2)
2069 * Our job is now to transform (1) to (2); a simple calculation shows that
2070 * we have to shift all points of the subglyph by
2072 * offset * scale - offset = offset * (scale - 1)
2074 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2076 * in: offset (in FUnits)
2077 * num_contours
2078 * first_contour
2080 * CVT: cvtl_funits_to_pixels
2081 * cvtl_0x10000
2082 * cvtl_scale
2084 * uses: bci_round
2085 * bci_shift_contour
2088 unsigned char FPGM(bci_shift_subglyph) [] =
2091 PUSHB_1,
2092 bci_shift_subglyph,
2093 FDEF,
2095 SVTCA_y,
2097 PUSHB_1,
2098 cvtl_funits_to_pixels,
2099 RCVT, /* scaling factor FUnits -> pixels */
2100 MUL,
2101 PUSHB_1,
2102 cvtl_0x10000,
2103 RCVT,
2104 DIV,
2106 /* the autohinter always rounds offsets */
2107 PUSHB_1,
2108 bci_round,
2109 CALL, /* offset = round(offset) */
2111 PUSHB_1,
2112 cvtl_scale,
2113 RCVT,
2114 MUL,
2115 PUSHB_1,
2116 cvtl_0x10000,
2117 RCVT,
2118 DIV, /* delta = offset * (scale - 1) */
2120 /* and round again */
2121 PUSHB_1,
2122 bci_round,
2123 CALL, /* offset = round(offset) */
2125 PUSHB_1,
2127 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2129 /* we create twilight point 0 as a reference point, */
2130 /* setting the original position to zero (using `cvtl_temp') */
2131 PUSHB_5,
2134 cvtl_temp,
2135 cvtl_temp,
2137 WCVTP,
2138 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2140 SWAP, /* s: first_contour num_contours 0 delta */
2141 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2143 PUSHB_2,
2144 bci_shift_contour,
2146 SZP2, /* set zp2 to normal zone 1 */
2147 LOOPCALL,
2149 ENDF,
2155 * bci_ip_outer_align_point
2157 * Auxiliary function for `bci_action_ip_before' and
2158 * `bci_action_ip_after'.
2160 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2161 * zone, and both zp1 and zp2 set to normal zone.
2163 * in: point
2165 * sal: sal_i (edge_orig_pos)
2167 * CVT: cvtl_scale
2168 * cvtl_0x10000
2171 unsigned char FPGM(bci_ip_outer_align_point) [] =
2174 PUSHB_1,
2175 bci_ip_outer_align_point,
2176 FDEF,
2178 DUP,
2179 ALIGNRP, /* align `point' with `edge' */
2180 DUP,
2181 GC_orig,
2182 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2184 PUSHB_1,
2185 sal_i,
2187 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2188 SHPIX,
2190 ENDF,
2196 * bci_ip_on_align_points
2198 * Auxiliary function for `bci_action_ip_on'.
2200 * in: edge (in twilight zone)
2201 * loop_counter (N)
2202 * point_1
2203 * point_2
2204 * ...
2205 * point_N
2208 unsigned char FPGM(bci_ip_on_align_points) [] =
2211 PUSHB_1,
2212 bci_ip_on_align_points,
2213 FDEF,
2215 MDAP_noround, /* set rp0 and rp1 to `edge' */
2217 SLOOP,
2218 ALIGNRP,
2220 ENDF,
2226 * bci_ip_between_align_point
2228 * Auxiliary function for `bci_ip_between_align_points'.
2230 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2231 * zone, and both zp1 and zp2 set to normal zone.
2233 * in: point
2235 * sal: sal_i (edge_orig_pos)
2236 * sal_j (stretch_factor)
2238 * CVT: cvtl_scale
2239 * cvtl_0x10000
2242 unsigned char FPGM(bci_ip_between_align_point) [] =
2245 PUSHB_1,
2246 bci_ip_between_align_point,
2247 FDEF,
2249 DUP,
2250 ALIGNRP, /* align `point' with `edge' */
2251 DUP,
2252 GC_orig,
2253 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2255 PUSHB_1,
2256 sal_i,
2258 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2259 PUSHB_1,
2260 sal_j,
2262 MUL, /* s: point delta */
2263 SHPIX,
2265 ENDF,
2271 * bci_ip_between_align_points
2273 * Auxiliary function for `bci_action_ip_between'.
2275 * in: after_edge (in twilight zone)
2276 * before_edge (in twilight zone)
2277 * loop_counter (N)
2278 * point_1
2279 * point_2
2280 * ...
2281 * point_N
2283 * sal: sal_i (before_orig_pos)
2284 * sal_j (stretch_factor)
2286 * uses: bci_ip_between_align_point
2289 unsigned char FPGM(bci_ip_between_align_points) [] =
2292 PUSHB_1,
2293 bci_ip_between_align_points,
2294 FDEF,
2296 PUSHB_2,
2299 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2300 CINDEX,
2301 DUP, /* s: ... before after before before */
2302 MDAP_noround, /* set rp0 and rp1 to `before' */
2303 DUP,
2304 GC_orig, /* s: ... before after before before_orig_pos */
2305 PUSHB_1,
2306 sal_i,
2307 SWAP,
2308 WS, /* sal_i = before_orig_pos */
2309 PUSHB_1,
2311 CINDEX, /* s: ... before after before after */
2312 MD_cur, /* a = after_pos - before_pos */
2313 ROLL,
2314 ROLL,
2315 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2317 DUP,
2318 IF, /* b != 0 ? */
2319 DIV, /* s: a/b */
2320 ELSE,
2321 POP, /* avoid division by zero */
2322 EIF,
2324 PUSHB_1,
2325 sal_j,
2326 SWAP,
2327 WS, /* sal_j = stretch_factor */
2329 PUSHB_3,
2330 bci_ip_between_align_point,
2333 SZP2, /* set zp2 to normal zone 1 */
2334 SZP1, /* set zp1 to normal zone 1 */
2335 LOOPCALL,
2337 ENDF,
2343 * bci_action_ip_before
2345 * Handle `ip_before' data to align points located before the first edge.
2347 * in: first_edge (in twilight zone)
2348 * loop_counter (N)
2349 * point_1
2350 * point_2
2351 * ...
2352 * point_N
2354 * sal: sal_i (first_edge_orig_pos)
2356 * uses: bci_ip_outer_align_point
2359 unsigned char FPGM(bci_action_ip_before) [] =
2362 PUSHB_1,
2363 bci_action_ip_before,
2364 FDEF,
2366 PUSHB_1,
2368 SZP2, /* set zp2 to twilight zone 0 */
2370 DUP,
2371 GC_orig,
2372 PUSHB_1,
2373 sal_i,
2374 SWAP,
2375 WS, /* sal_i = first_edge_orig_pos */
2377 PUSHB_3,
2381 SZP2, /* set zp2 to normal zone 1 */
2382 SZP1, /* set zp1 to normal zone 1 */
2383 SZP0, /* set zp0 to twilight zone 0 */
2385 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2387 PUSHB_1,
2388 bci_ip_outer_align_point,
2389 LOOPCALL,
2391 ENDF,
2397 * bci_action_ip_after
2399 * Handle `ip_after' data to align points located after the last edge.
2401 * in: last_edge (in twilight zone)
2402 * loop_counter (N)
2403 * point_1
2404 * point_2
2405 * ...
2406 * point_N
2408 * sal: sal_i (last_edge_orig_pos)
2410 * uses: bci_ip_outer_align_point
2413 unsigned char FPGM(bci_action_ip_after) [] =
2416 PUSHB_1,
2417 bci_action_ip_after,
2418 FDEF,
2420 PUSHB_1,
2422 SZP2, /* set zp2 to twilight zone 0 */
2424 DUP,
2425 GC_orig,
2426 PUSHB_1,
2427 sal_i,
2428 SWAP,
2429 WS, /* sal_i = last_edge_orig_pos */
2431 PUSHB_3,
2435 SZP2, /* set zp2 to normal zone 1 */
2436 SZP1, /* set zp1 to normal zone 1 */
2437 SZP0, /* set zp0 to twilight zone 0 */
2439 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2441 PUSHB_1,
2442 bci_ip_outer_align_point,
2443 LOOPCALL,
2445 ENDF,
2451 * bci_action_ip_on
2453 * Handle `ip_on' data to align points located on an edge coordinate (but
2454 * not part of an edge).
2456 * in: loop_counter (M)
2457 * edge_1 (in twilight zone)
2458 * loop_counter (N_1)
2459 * point_1
2460 * point_2
2461 * ...
2462 * point_N_1
2463 * edge_2 (in twilight zone)
2464 * loop_counter (N_2)
2465 * point_1
2466 * point_2
2467 * ...
2468 * point_N_2
2469 * ...
2470 * edge_M (in twilight zone)
2471 * loop_counter (N_M)
2472 * point_1
2473 * point_2
2474 * ...
2475 * point_N_M
2477 * uses: bci_ip_on_align_points
2480 unsigned char FPGM(bci_action_ip_on) [] =
2483 PUSHB_1,
2484 bci_action_ip_on,
2485 FDEF,
2487 PUSHB_2,
2490 SZP1, /* set zp1 to normal zone 1 */
2491 SZP0, /* set zp0 to twilight zone 0 */
2493 PUSHB_1,
2494 bci_ip_on_align_points,
2495 LOOPCALL,
2497 ENDF,
2503 * bci_action_ip_between
2505 * Handle `ip_between' data to align points located between two edges.
2507 * in: loop_counter (M)
2508 * before_edge_1 (in twilight zone)
2509 * after_edge_1 (in twilight zone)
2510 * loop_counter (N_1)
2511 * point_1
2512 * point_2
2513 * ...
2514 * point_N_1
2515 * before_edge_2 (in twilight zone)
2516 * after_edge_2 (in twilight zone)
2517 * loop_counter (N_2)
2518 * point_1
2519 * point_2
2520 * ...
2521 * point_N_2
2522 * ...
2523 * before_edge_M (in twilight zone)
2524 * after_edge_M (in twilight zone)
2525 * loop_counter (N_M)
2526 * point_1
2527 * point_2
2528 * ...
2529 * point_N_M
2531 * uses: bci_ip_between_align_points
2534 unsigned char FPGM(bci_action_ip_between) [] =
2537 PUSHB_1,
2538 bci_action_ip_between,
2539 FDEF,
2541 PUSHB_1,
2542 bci_ip_between_align_points,
2543 LOOPCALL,
2545 ENDF,
2551 * bci_adjust_common
2553 * Common code for bci_action_adjust routines.
2555 * uses: func[cvtl_stem_width_function]
2558 unsigned char FPGM(bci_adjust_common) [] =
2561 PUSHB_1,
2562 bci_adjust_common,
2563 FDEF,
2565 PUSHB_1,
2567 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2569 PUSHB_1,
2571 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2572 PUSHB_1,
2574 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2575 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2577 PUSHB_1,
2578 cvtl_stem_width_function,
2579 RCVT,
2580 CALL,
2581 NEG, /* s: [...] edge2 edge -cur_len */
2583 ROLL, /* s: [...] edge -cur_len edge2 */
2584 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2585 SWAP,
2586 DUP,
2587 DUP, /* s: [...] -cur_len edge edge edge */
2588 ALIGNRP, /* align `edge' with `edge2' */
2589 ROLL,
2590 SHPIX, /* shift `edge' by -cur_len */
2592 ENDF,
2598 * bci_adjust_bound
2600 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2601 * edge of the stem has already been moved, then moving it again if
2602 * necessary to stay bound.
2604 * in: edge2_is_serif
2605 * edge_is_round
2606 * edge_point (in twilight zone)
2607 * edge2_point (in twilight zone)
2608 * edge[-1] (in twilight zone)
2609 * ... stuff for bci_align_segments (edge) ...
2611 * uses: bci_adjust_common
2612 * bci_align_segments
2615 unsigned char FPGM(bci_adjust_bound) [] =
2618 PUSHB_1,
2619 bci_adjust_bound,
2620 FDEF,
2622 PUSHB_1,
2623 bci_adjust_common,
2624 CALL,
2626 SWAP, /* s: edge edge[-1] */
2627 DUP,
2628 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2629 GC_cur,
2630 PUSHB_1,
2632 CINDEX,
2633 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2634 GT, /* edge_pos < edge[-1]_pos */
2636 DUP,
2637 ALIGNRP, /* align `edge' to `edge[-1]' */
2638 EIF,
2640 MDAP_noround, /* set rp0 and rp1 to `edge' */
2642 PUSHB_2,
2643 bci_align_segments,
2645 SZP1, /* set zp1 to normal zone 1 */
2646 CALL,
2648 ENDF,
2654 * bci_action_adjust_bound
2655 * bci_action_adjust_bound_serif
2656 * bci_action_adjust_bound_round
2657 * bci_action_adjust_bound_round_serif
2659 * Higher-level routines for calling `bci_adjust_bound'.
2662 unsigned char FPGM(bci_action_adjust_bound) [] =
2665 PUSHB_1,
2666 bci_action_adjust_bound,
2667 FDEF,
2669 PUSHB_3,
2672 bci_adjust_bound,
2673 CALL,
2675 ENDF,
2679 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2682 PUSHB_1,
2683 bci_action_adjust_bound_serif,
2684 FDEF,
2686 PUSHB_3,
2689 bci_adjust_bound,
2690 CALL,
2692 ENDF,
2696 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2699 PUSHB_1,
2700 bci_action_adjust_bound_round,
2701 FDEF,
2703 PUSHB_3,
2706 bci_adjust_bound,
2707 CALL,
2709 ENDF,
2713 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2716 PUSHB_1,
2717 bci_action_adjust_bound_round_serif,
2718 FDEF,
2720 PUSHB_3,
2723 bci_adjust_bound,
2724 CALL,
2726 ENDF,
2732 * bci_adjust
2734 * Handle the ADJUST action to align an edge of a stem if the other edge
2735 * of the stem has already been moved.
2737 * in: edge2_is_serif
2738 * edge_is_round
2739 * edge_point (in twilight zone)
2740 * edge2_point (in twilight zone)
2741 * ... stuff for bci_align_segments (edge) ...
2743 * uses: bci_adjust_common
2744 * bci_align_segments
2747 unsigned char FPGM(bci_adjust) [] =
2750 PUSHB_1,
2751 bci_adjust,
2752 FDEF,
2754 PUSHB_1,
2755 bci_adjust_common,
2756 CALL,
2758 MDAP_noround, /* set rp0 and rp1 to `edge' */
2760 PUSHB_2,
2761 bci_align_segments,
2763 SZP1, /* set zp1 to normal zone 1 */
2764 CALL,
2766 ENDF,
2772 * bci_action_adjust
2773 * bci_action_adjust_serif
2774 * bci_action_adjust_round
2775 * bci_action_adjust_round_serif
2777 * Higher-level routines for calling `bci_adjust'.
2780 unsigned char FPGM(bci_action_adjust) [] =
2783 PUSHB_1,
2784 bci_action_adjust,
2785 FDEF,
2787 PUSHB_3,
2790 bci_adjust,
2791 CALL,
2793 ENDF,
2797 unsigned char FPGM(bci_action_adjust_serif) [] =
2800 PUSHB_1,
2801 bci_action_adjust_serif,
2802 FDEF,
2804 PUSHB_3,
2807 bci_adjust,
2808 CALL,
2810 ENDF,
2814 unsigned char FPGM(bci_action_adjust_round) [] =
2817 PUSHB_1,
2818 bci_action_adjust_round,
2819 FDEF,
2821 PUSHB_3,
2824 bci_adjust,
2825 CALL,
2827 ENDF,
2831 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2834 PUSHB_1,
2835 bci_action_adjust_round_serif,
2836 FDEF,
2838 PUSHB_3,
2841 bci_adjust,
2842 CALL,
2844 ENDF,
2850 * bci_stem_common
2852 * Common code for bci_action_stem routines.
2854 * sal: sal_anchor
2855 * sal_temp1
2856 * sal_temp2
2857 * sal_temp3
2859 * uses: func[cvtl_stem_width_function]
2860 * bci_round
2863 #undef sal_u_off
2864 #define sal_u_off sal_temp1
2865 #undef sal_d_off
2866 #define sal_d_off sal_temp2
2867 #undef sal_org_len
2868 #define sal_org_len sal_temp3
2869 #undef sal_edge2
2870 #define sal_edge2 sal_temp3
2872 unsigned char FPGM(bci_stem_common) [] =
2875 PUSHB_1,
2876 bci_stem_common,
2877 FDEF,
2879 PUSHB_1,
2881 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2883 PUSHB_1,
2885 CINDEX,
2886 PUSHB_1,
2888 CINDEX,
2889 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2890 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2892 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2893 DUP,
2894 PUSHB_1,
2895 sal_org_len,
2896 SWAP,
2899 PUSHB_1,
2900 cvtl_stem_width_function,
2901 RCVT,
2902 CALL, /* s: [...] edge2 edge cur_len */
2904 DUP,
2905 PUSHB_1,
2907 LT, /* cur_len < 96 */
2909 DUP,
2910 PUSHB_1,
2912 LTEQ, /* cur_len <= 64 */
2914 PUSHB_4,
2915 sal_u_off,
2917 sal_d_off,
2920 ELSE,
2921 PUSHB_4,
2922 sal_u_off,
2924 sal_d_off,
2926 EIF,
2930 SWAP, /* s: [...] edge2 cur_len edge */
2931 DUP,
2932 PUSHB_1,
2933 sal_anchor,
2935 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2936 ROLL,
2937 SWAP,
2938 MD_orig_ZP2_0,
2939 SWAP,
2940 GC_cur,
2941 ADD, /* s: [...] edge2 cur_len edge org_pos */
2942 PUSHB_1,
2943 sal_org_len,
2945 PUSHB_1,
2946 2*64,
2947 DIV,
2948 ADD, /* s: [...] edge2 cur_len edge org_center */
2950 DUP,
2951 PUSHB_1,
2952 bci_round,
2953 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2955 DUP,
2956 ROLL,
2957 ROLL,
2958 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2960 DUP,
2961 PUSHB_1,
2962 sal_u_off,
2964 ADD,
2965 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2967 SWAP,
2968 PUSHB_1,
2969 sal_d_off,
2971 SUB,
2972 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2974 LT, /* delta1 < delta2 */
2976 PUSHB_1,
2977 sal_u_off,
2979 SUB, /* cur_pos1 = cur_pos1 - u_off */
2981 ELSE,
2982 PUSHB_1,
2983 sal_d_off,
2985 ADD, /* cur_pos1 = cur_pos1 + d_off */
2986 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2988 PUSHB_1,
2990 CINDEX,
2991 PUSHB_1,
2992 2*64,
2993 DIV,
2994 SUB, /* arg = cur_pos1 - cur_len/2 */
2996 SWAP, /* s: [...] edge2 cur_len arg edge */
2997 DUP,
2998 DUP,
2999 PUSHB_1,
3001 MINDEX,
3002 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3003 GC_cur,
3004 SUB,
3005 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3007 ELSE,
3008 SWAP, /* s: [...] edge2 cur_len edge */
3009 PUSHB_1,
3010 sal_anchor,
3012 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3013 PUSHB_1,
3015 CINDEX,
3016 PUSHB_1,
3017 sal_anchor,
3019 MD_orig_ZP2_0,
3020 ADD, /* s: [...] edge2 cur_len edge org_pos */
3022 DUP,
3023 PUSHB_1,
3024 sal_org_len,
3026 PUSHB_1,
3027 2*64,
3028 DIV,
3029 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3031 SWAP,
3032 DUP,
3033 PUSHB_1,
3034 bci_round,
3035 CALL, /* cur_pos1 = ROUND(org_pos) */
3036 SWAP,
3037 PUSHB_1,
3038 sal_org_len,
3040 ADD,
3041 PUSHB_1,
3042 bci_round,
3043 CALL,
3044 PUSHB_1,
3046 CINDEX,
3047 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3049 PUSHB_1,
3051 CINDEX,
3052 PUSHB_1,
3053 2*64,
3054 DIV,
3055 PUSHB_1,
3057 MINDEX,
3058 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3060 DUP,
3061 PUSHB_1,
3063 CINDEX,
3064 ADD,
3065 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3066 SWAP,
3067 PUSHB_1,
3069 CINDEX,
3070 ADD,
3071 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3072 LT, /* delta1 < delta2 */
3074 POP, /* arg = cur_pos1 */
3076 ELSE,
3077 SWAP,
3078 POP, /* arg = cur_pos2 */
3079 EIF, /* s: [...] edge2 cur_len edge arg */
3080 SWAP,
3081 DUP,
3082 DUP,
3083 PUSHB_1,
3085 MINDEX,
3086 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3087 GC_cur,
3088 SUB,
3089 SHPIX, /* edge = arg */
3090 EIF, /* s: [...] edge2 cur_len edge */
3092 ENDF,
3098 * bci_stem_bound
3100 * Handle the STEM action to align two edges of a stem, then moving one
3101 * edge again if necessary to stay bound.
3103 * The code after computing `cur_len' to shift `edge' and `edge2'
3104 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3106 * if cur_len < 96:
3107 * if cur_len < = 64:
3108 * u_off = 32
3109 * d_off = 32
3110 * else:
3111 * u_off = 38
3112 * d_off = 26
3114 * org_pos = anchor + (edge_orig - anchor_orig);
3115 * org_center = org_pos + org_len / 2;
3117 * cur_pos1 = ROUND(org_center)
3118 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3119 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3120 * if (delta1 < delta2):
3121 * cur_pos1 = cur_pos1 - u_off
3122 * else:
3123 * cur_pos1 = cur_pos1 + d_off
3125 * edge = cur_pos1 - cur_len / 2
3127 * else:
3128 * org_pos = anchor + (edge_orig - anchor_orig)
3129 * org_center = org_pos + org_len / 2;
3131 * cur_pos1 = ROUND(org_pos)
3132 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3133 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3134 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3136 * if (delta1 < delta2):
3137 * edge = cur_pos1
3138 * else:
3139 * edge = cur_pos2
3141 * edge2 = edge + cur_len
3143 * in: edge2_is_serif
3144 * edge_is_round
3145 * edge_point (in twilight zone)
3146 * edge2_point (in twilight zone)
3147 * edge[-1] (in twilight zone)
3148 * ... stuff for bci_align_segments (edge) ...
3149 * ... stuff for bci_align_segments (edge2)...
3151 * sal: sal_anchor
3152 * sal_temp1
3153 * sal_temp2
3154 * sal_temp3
3156 * uses: bci_stem_common
3157 * bci_align_segments
3160 unsigned char FPGM(bci_stem_bound) [] =
3163 PUSHB_1,
3164 bci_stem_bound,
3165 FDEF,
3167 PUSHB_1,
3168 bci_stem_common,
3169 CALL,
3171 ROLL, /* s: edge[-1] cur_len edge edge2 */
3172 DUP,
3173 DUP,
3174 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3175 PUSHB_1,
3176 sal_edge2,
3177 SWAP,
3178 WS, /* s: edge[-1] cur_len edge edge2 */
3179 ROLL,
3180 SHPIX, /* edge2 = edge + cur_len */
3182 SWAP, /* s: edge edge[-1] */
3183 DUP,
3184 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3185 GC_cur,
3186 PUSHB_1,
3188 CINDEX,
3189 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3190 GT, /* edge_pos < edge[-1]_pos */
3192 DUP,
3193 ALIGNRP, /* align `edge' to `edge[-1]' */
3194 EIF,
3196 MDAP_noround, /* set rp0 and rp1 to `edge' */
3198 PUSHB_2,
3199 bci_align_segments,
3201 SZP1, /* set zp1 to normal zone 1 */
3202 CALL,
3204 PUSHB_1,
3205 sal_edge2,
3207 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3209 PUSHB_1,
3210 bci_align_segments,
3211 CALL,
3213 ENDF,
3219 * bci_action_stem_bound
3220 * bci_action_stem_bound_serif
3221 * bci_action_stem_bound_round
3222 * bci_action_stem_bound_round_serif
3224 * Higher-level routines for calling `bci_stem_bound'.
3227 unsigned char FPGM(bci_action_stem_bound) [] =
3230 PUSHB_1,
3231 bci_action_stem_bound,
3232 FDEF,
3234 PUSHB_3,
3237 bci_stem_bound,
3238 CALL,
3240 ENDF,
3244 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3247 PUSHB_1,
3248 bci_action_stem_bound_serif,
3249 FDEF,
3251 PUSHB_3,
3254 bci_stem_bound,
3255 CALL,
3257 ENDF,
3261 unsigned char FPGM(bci_action_stem_bound_round) [] =
3264 PUSHB_1,
3265 bci_action_stem_bound_round,
3266 FDEF,
3268 PUSHB_3,
3271 bci_stem_bound,
3272 CALL,
3274 ENDF,
3278 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3281 PUSHB_1,
3282 bci_action_stem_bound_round_serif,
3283 FDEF,
3285 PUSHB_3,
3288 bci_stem_bound,
3289 CALL,
3291 ENDF,
3297 * bci_stem
3299 * Handle the STEM action to align two edges of a stem.
3301 * See `bci_stem_bound' for more details.
3303 * in: edge2_is_serif
3304 * edge_is_round
3305 * edge_point (in twilight zone)
3306 * edge2_point (in twilight zone)
3307 * ... stuff for bci_align_segments (edge) ...
3308 * ... stuff for bci_align_segments (edge2)...
3310 * sal: sal_anchor
3311 * sal_temp1
3312 * sal_temp2
3313 * sal_temp3
3315 * uses: bci_stem_common
3316 * bci_align_segments
3319 unsigned char FPGM(bci_stem) [] =
3322 PUSHB_1,
3323 bci_stem,
3324 FDEF,
3326 PUSHB_1,
3327 bci_stem_common,
3328 CALL,
3330 POP,
3331 SWAP, /* s: cur_len edge2 */
3332 DUP,
3333 DUP,
3334 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3335 PUSHB_1,
3336 sal_edge2,
3337 SWAP,
3338 WS, /* s: cur_len edge2 */
3339 SWAP,
3340 SHPIX, /* edge2 = edge + cur_len */
3342 PUSHB_2,
3343 bci_align_segments,
3345 SZP1, /* set zp1 to normal zone 1 */
3346 CALL,
3348 PUSHB_1,
3349 sal_edge2,
3351 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3353 PUSHB_1,
3354 bci_align_segments,
3355 CALL,
3356 ENDF,
3362 * bci_action_stem
3363 * bci_action_stem_serif
3364 * bci_action_stem_round
3365 * bci_action_stem_round_serif
3367 * Higher-level routines for calling `bci_stem'.
3370 unsigned char FPGM(bci_action_stem) [] =
3373 PUSHB_1,
3374 bci_action_stem,
3375 FDEF,
3377 PUSHB_3,
3380 bci_stem,
3381 CALL,
3383 ENDF,
3387 unsigned char FPGM(bci_action_stem_serif) [] =
3390 PUSHB_1,
3391 bci_action_stem_serif,
3392 FDEF,
3394 PUSHB_3,
3397 bci_stem,
3398 CALL,
3400 ENDF,
3404 unsigned char FPGM(bci_action_stem_round) [] =
3407 PUSHB_1,
3408 bci_action_stem_round,
3409 FDEF,
3411 PUSHB_3,
3414 bci_stem,
3415 CALL,
3417 ENDF,
3421 unsigned char FPGM(bci_action_stem_round_serif) [] =
3424 PUSHB_1,
3425 bci_action_stem_round_serif,
3426 FDEF,
3428 PUSHB_3,
3431 bci_stem,
3432 CALL,
3434 ENDF,
3440 * bci_link
3442 * Handle the LINK action to link an edge to another one.
3444 * in: stem_is_serif
3445 * base_is_round
3446 * base_point (in twilight zone)
3447 * stem_point (in twilight zone)
3448 * ... stuff for bci_align_segments (base) ...
3450 * uses: func[cvtl_stem_width_function]
3451 * bci_align_segments
3454 unsigned char FPGM(bci_link) [] =
3457 PUSHB_1,
3458 bci_link,
3459 FDEF,
3461 PUSHB_1,
3463 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3465 PUSHB_1,
3467 CINDEX,
3468 PUSHB_1,
3470 MINDEX,
3471 DUP, /* s: stem is_round is_serif stem base base */
3472 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3474 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3476 PUSHB_1,
3477 cvtl_stem_width_function,
3478 RCVT,
3479 CALL, /* s: stem new_dist */
3481 SWAP,
3482 DUP,
3483 ALIGNRP, /* align `stem_point' with `base_point' */
3484 DUP,
3485 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3486 SWAP,
3487 SHPIX, /* stem_point = base_point + new_dist */
3489 PUSHB_2,
3490 bci_align_segments,
3492 SZP1, /* set zp1 to normal zone 1 */
3493 CALL,
3495 ENDF,
3501 * bci_action_link
3502 * bci_action_link_serif
3503 * bci_action_link_round
3504 * bci_action_link_round_serif
3506 * Higher-level routines for calling `bci_link'.
3509 unsigned char FPGM(bci_action_link) [] =
3512 PUSHB_1,
3513 bci_action_link,
3514 FDEF,
3516 PUSHB_3,
3519 bci_link,
3520 CALL,
3522 ENDF,
3526 unsigned char FPGM(bci_action_link_serif) [] =
3529 PUSHB_1,
3530 bci_action_link_serif,
3531 FDEF,
3533 PUSHB_3,
3536 bci_link,
3537 CALL,
3539 ENDF,
3543 unsigned char FPGM(bci_action_link_round) [] =
3546 PUSHB_1,
3547 bci_action_link_round,
3548 FDEF,
3550 PUSHB_3,
3553 bci_link,
3554 CALL,
3556 ENDF,
3560 unsigned char FPGM(bci_action_link_round_serif) [] =
3563 PUSHB_1,
3564 bci_action_link_round_serif,
3565 FDEF,
3567 PUSHB_3,
3570 bci_link,
3571 CALL,
3573 ENDF,
3579 * bci_anchor
3581 * Handle the ANCHOR action to align two edges
3582 * and to set the edge anchor.
3584 * The code after computing `cur_len' to shift `edge' and `edge2'
3585 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3587 * if cur_len < 96:
3588 * if cur_len < = 64:
3589 * u_off = 32
3590 * d_off = 32
3591 * else:
3592 * u_off = 38
3593 * d_off = 26
3595 * org_center = edge_orig + org_len / 2
3596 * cur_pos1 = ROUND(org_center)
3598 * error1 = ABS(org_center - (cur_pos1 - u_off))
3599 * error2 = ABS(org_center - (cur_pos1 + d_off))
3600 * if (error1 < error2):
3601 * cur_pos1 = cur_pos1 - u_off
3602 * else:
3603 * cur_pos1 = cur_pos1 + d_off
3605 * edge = cur_pos1 - cur_len / 2
3606 * edge2 = edge + cur_len
3608 * else:
3609 * edge = ROUND(edge_orig)
3611 * in: edge2_is_serif
3612 * edge_is_round
3613 * edge_point (in twilight zone)
3614 * edge2_point (in twilight zone)
3615 * ... stuff for bci_align_segments (edge) ...
3617 * sal: sal_anchor
3618 * sal_temp1
3619 * sal_temp2
3620 * sal_temp3
3622 * uses: func[cvtl_stem_width_function]
3623 * bci_round
3624 * bci_align_segments
3627 #undef sal_u_off
3628 #define sal_u_off sal_temp1
3629 #undef sal_d_off
3630 #define sal_d_off sal_temp2
3631 #undef sal_org_len
3632 #define sal_org_len sal_temp3
3634 unsigned char FPGM(bci_anchor) [] =
3637 PUSHB_1,
3638 bci_anchor,
3639 FDEF,
3641 /* store anchor point number in `sal_anchor' */
3642 PUSHB_2,
3643 sal_anchor,
3645 CINDEX,
3646 WS, /* sal_anchor = edge_point */
3648 PUSHB_1,
3650 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3652 PUSHB_1,
3654 CINDEX,
3655 PUSHB_1,
3657 CINDEX,
3658 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3659 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3661 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3662 DUP,
3663 PUSHB_1,
3664 sal_org_len,
3665 SWAP,
3668 PUSHB_1,
3669 cvtl_stem_width_function,
3670 RCVT,
3671 CALL, /* s: edge2 edge cur_len */
3673 DUP,
3674 PUSHB_1,
3676 LT, /* cur_len < 96 */
3678 DUP,
3679 PUSHB_1,
3681 LTEQ, /* cur_len <= 64 */
3683 PUSHB_4,
3684 sal_u_off,
3686 sal_d_off,
3689 ELSE,
3690 PUSHB_4,
3691 sal_u_off,
3693 sal_d_off,
3695 EIF,
3699 SWAP, /* s: edge2 cur_len edge */
3700 DUP, /* s: edge2 cur_len edge edge */
3702 GC_orig,
3703 PUSHB_1,
3704 sal_org_len,
3706 PUSHB_1,
3707 2*64,
3708 DIV,
3709 ADD, /* s: edge2 cur_len edge org_center */
3711 DUP,
3712 PUSHB_1,
3713 bci_round,
3714 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3716 DUP,
3717 ROLL,
3718 ROLL,
3719 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3721 DUP,
3722 PUSHB_1,
3723 sal_u_off,
3725 ADD,
3726 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3728 SWAP,
3729 PUSHB_1,
3730 sal_d_off,
3732 SUB,
3733 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3735 LT, /* error1 < error2 */
3737 PUSHB_1,
3738 sal_u_off,
3740 SUB, /* cur_pos1 = cur_pos1 - u_off */
3742 ELSE,
3743 PUSHB_1,
3744 sal_d_off,
3746 ADD, /* cur_pos1 = cur_pos1 + d_off */
3747 EIF, /* s: edge2 cur_len edge cur_pos1 */
3749 PUSHB_1,
3751 CINDEX,
3752 PUSHB_1,
3753 2*64,
3754 DIV,
3755 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3757 PUSHB_1,
3759 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3760 GC_cur,
3761 SUB,
3762 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3764 SWAP, /* s: cur_len edge2 */
3765 DUP,
3766 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3767 SWAP,
3768 SHPIX, /* edge2 = edge1 + cur_len */
3770 ELSE,
3771 POP, /* s: edge2 edge */
3772 DUP,
3773 DUP,
3774 GC_cur,
3775 SWAP,
3776 GC_orig,
3777 PUSHB_1,
3778 bci_round,
3779 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3780 SWAP,
3781 SUB,
3782 SHPIX, /* edge = round(edge_orig) */
3784 /* clean up stack */
3785 POP,
3786 EIF,
3788 PUSHB_2,
3789 bci_align_segments,
3791 SZP1, /* set zp1 to normal zone 1 */
3792 CALL,
3794 ENDF,
3800 * bci_action_anchor
3801 * bci_action_anchor_serif
3802 * bci_action_anchor_round
3803 * bci_action_anchor_round_serif
3805 * Higher-level routines for calling `bci_anchor'.
3808 unsigned char FPGM(bci_action_anchor) [] =
3811 PUSHB_1,
3812 bci_action_anchor,
3813 FDEF,
3815 PUSHB_3,
3818 bci_anchor,
3819 CALL,
3821 ENDF,
3825 unsigned char FPGM(bci_action_anchor_serif) [] =
3828 PUSHB_1,
3829 bci_action_anchor_serif,
3830 FDEF,
3832 PUSHB_3,
3835 bci_anchor,
3836 CALL,
3838 ENDF,
3842 unsigned char FPGM(bci_action_anchor_round) [] =
3845 PUSHB_1,
3846 bci_action_anchor_round,
3847 FDEF,
3849 PUSHB_3,
3852 bci_anchor,
3853 CALL,
3855 ENDF,
3859 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3862 PUSHB_1,
3863 bci_action_anchor_round_serif,
3864 FDEF,
3866 PUSHB_3,
3869 bci_anchor,
3870 CALL,
3872 ENDF,
3878 * bci_action_blue_anchor
3880 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3881 * and to set the edge anchor.
3883 * in: anchor_point (in twilight zone)
3884 * blue_cvt_idx
3885 * edge_point (in twilight zone)
3886 * ... stuff for bci_align_segments (edge) ...
3888 * sal: sal_anchor
3890 * uses: bci_action_blue
3893 unsigned char FPGM(bci_action_blue_anchor) [] =
3896 PUSHB_1,
3897 bci_action_blue_anchor,
3898 FDEF,
3900 /* store anchor point number in `sal_anchor' */
3901 PUSHB_1,
3902 sal_anchor,
3903 SWAP,
3906 PUSHB_1,
3907 bci_action_blue,
3908 CALL,
3910 ENDF,
3916 * bci_action_blue
3918 * Handle the BLUE action to align an edge with a blue zone.
3920 * in: blue_cvt_idx
3921 * edge_point (in twilight zone)
3922 * ... stuff for bci_align_segments (edge) ...
3924 * uses: bci_align_segments
3927 unsigned char FPGM(bci_action_blue) [] =
3930 PUSHB_1,
3931 bci_action_blue,
3932 FDEF,
3934 PUSHB_1,
3936 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3938 /* move `edge_point' to `blue_cvt_idx' position; */
3939 /* note that we can't use MIAP since this would modify */
3940 /* the twilight point's original coordinates also */
3941 RCVT,
3942 SWAP,
3943 DUP,
3944 MDAP_noround, /* set rp0 and rp1 to `edge' */
3945 DUP,
3946 GC_cur, /* s: new_pos edge edge_pos */
3947 ROLL,
3948 SWAP,
3949 SUB, /* s: edge (new_pos - edge_pos) */
3950 SHPIX,
3952 PUSHB_2,
3953 bci_align_segments,
3955 SZP1, /* set zp1 to normal zone 1 */
3956 CALL,
3958 ENDF,
3964 * bci_serif_common
3966 * Common code for bci_action_serif routines.
3969 unsigned char FPGM(bci_serif_common) [] =
3972 PUSHB_1,
3973 bci_serif_common,
3974 FDEF,
3976 PUSHB_1,
3978 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3980 DUP,
3981 DUP,
3982 DUP,
3983 PUSHB_1,
3985 MINDEX, /* s: [...] serif serif serif serif base */
3986 DUP,
3987 MDAP_noround, /* set rp0 and rp1 to `base_point' */
3988 MD_orig_ZP2_0,
3989 SWAP,
3990 ALIGNRP, /* align `serif_point' with `base_point' */
3991 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
3993 ENDF,
3999 * bci_lower_bound
4001 * Move an edge if necessary to stay within a lower bound.
4003 * in: edge
4004 * bound
4006 * uses: bci_align_segments
4009 unsigned char FPGM(bci_lower_bound) [] =
4012 PUSHB_1,
4013 bci_lower_bound,
4014 FDEF,
4016 SWAP, /* s: edge bound */
4017 DUP,
4018 MDAP_noround, /* set rp0 and rp1 to `bound' */
4019 GC_cur,
4020 PUSHB_1,
4022 CINDEX,
4023 GC_cur, /* s: edge bound_pos edge_pos */
4024 GT, /* edge_pos < bound_pos */
4026 DUP,
4027 ALIGNRP, /* align `edge' to `bound' */
4028 EIF,
4030 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4032 PUSHB_2,
4033 bci_align_segments,
4035 SZP1, /* set zp1 to normal zone 1 */
4036 CALL,
4038 ENDF,
4044 * bci_upper_bound
4046 * Move an edge if necessary to stay within an upper bound.
4048 * in: edge
4049 * bound
4051 * uses: bci_align_segments
4054 unsigned char FPGM(bci_upper_bound) [] =
4057 PUSHB_1,
4058 bci_upper_bound,
4059 FDEF,
4061 SWAP, /* s: edge bound */
4062 DUP,
4063 MDAP_noround, /* set rp0 and rp1 to `bound' */
4064 GC_cur,
4065 PUSHB_1,
4067 CINDEX,
4068 GC_cur, /* s: edge bound_pos edge_pos */
4069 LT, /* edge_pos > bound_pos */
4071 DUP,
4072 ALIGNRP, /* align `edge' to `bound' */
4073 EIF,
4075 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4077 PUSHB_2,
4078 bci_align_segments,
4080 SZP1, /* set zp1 to normal zone 1 */
4081 CALL,
4083 ENDF,
4089 * bci_upper_lower_bound
4091 * Move an edge if necessary to stay within a lower and lower bound.
4093 * in: edge
4094 * lower
4095 * upper
4097 * uses: bci_align_segments
4100 unsigned char FPGM(bci_upper_lower_bound) [] =
4103 PUSHB_1,
4104 bci_upper_lower_bound,
4105 FDEF,
4107 SWAP, /* s: upper serif lower */
4108 DUP,
4109 MDAP_noround, /* set rp0 and rp1 to `lower' */
4110 GC_cur,
4111 PUSHB_1,
4113 CINDEX,
4114 GC_cur, /* s: upper serif lower_pos serif_pos */
4115 GT, /* serif_pos < lower_pos */
4117 DUP,
4118 ALIGNRP, /* align `serif' to `lower' */
4119 EIF,
4121 SWAP, /* s: serif upper */
4122 DUP,
4123 MDAP_noround, /* set rp0 and rp1 to `upper' */
4124 GC_cur,
4125 PUSHB_1,
4127 CINDEX,
4128 GC_cur, /* s: serif upper_pos serif_pos */
4129 LT, /* serif_pos > upper_pos */
4131 DUP,
4132 ALIGNRP, /* align `serif' to `upper' */
4133 EIF,
4135 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4137 PUSHB_2,
4138 bci_align_segments,
4140 SZP1, /* set zp1 to normal zone 1 */
4141 CALL,
4143 ENDF,
4149 * bci_action_serif
4151 * Handle the SERIF action to align a serif with its base.
4153 * in: serif_point (in twilight zone)
4154 * base_point (in twilight zone)
4155 * ... stuff for bci_align_segments (serif) ...
4157 * uses: bci_serif_common
4158 * bci_align_segments
4161 unsigned char FPGM(bci_action_serif) [] =
4164 PUSHB_1,
4165 bci_action_serif,
4166 FDEF,
4168 PUSHB_1,
4169 bci_serif_common,
4170 CALL,
4172 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4174 PUSHB_2,
4175 bci_align_segments,
4177 SZP1, /* set zp1 to normal zone 1 */
4178 CALL,
4180 ENDF,
4186 * bci_action_serif_lower_bound
4188 * Handle the SERIF action to align a serif with its base, then moving it
4189 * again if necessary to stay within a lower bound.
4191 * in: serif_point (in twilight zone)
4192 * base_point (in twilight zone)
4193 * edge[-1] (in twilight zone)
4194 * ... stuff for bci_align_segments (serif) ...
4196 * uses: bci_serif_common
4197 * bci_lower_bound
4200 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4203 PUSHB_1,
4204 bci_action_serif_lower_bound,
4205 FDEF,
4207 PUSHB_1,
4208 bci_serif_common,
4209 CALL,
4211 PUSHB_1,
4212 bci_lower_bound,
4213 CALL,
4215 ENDF,
4221 * bci_action_serif_upper_bound
4223 * Handle the SERIF action to align a serif with its base, then moving it
4224 * again if necessary to stay within an upper bound.
4226 * in: serif_point (in twilight zone)
4227 * base_point (in twilight zone)
4228 * edge[1] (in twilight zone)
4229 * ... stuff for bci_align_segments (serif) ...
4231 * uses: bci_serif_common
4232 * bci_upper_bound
4235 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4238 PUSHB_1,
4239 bci_action_serif_upper_bound,
4240 FDEF,
4242 PUSHB_1,
4243 bci_serif_common,
4244 CALL,
4246 PUSHB_1,
4247 bci_upper_bound,
4248 CALL,
4250 ENDF,
4256 * bci_action_serif_upper_lower_bound
4258 * Handle the SERIF action to align a serif with its base, then moving it
4259 * again if necessary to stay within a lower and upper bound.
4261 * in: serif_point (in twilight zone)
4262 * base_point (in twilight zone)
4263 * edge[-1] (in twilight zone)
4264 * edge[1] (in twilight zone)
4265 * ... stuff for bci_align_segments (serif) ...
4267 * uses: bci_serif_common
4268 * bci_upper_lower_bound
4271 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4274 PUSHB_1,
4275 bci_action_serif_upper_lower_bound,
4276 FDEF,
4278 PUSHB_1,
4280 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4282 PUSHB_1,
4283 bci_serif_common,
4284 CALL,
4286 PUSHB_1,
4287 bci_upper_lower_bound,
4288 CALL,
4290 ENDF,
4296 * bci_serif_anchor_common
4298 * Common code for bci_action_serif_anchor routines.
4300 * sal: sal_anchor
4302 * uses: bci_round
4305 unsigned char FPGM(bci_serif_anchor_common) [] =
4308 PUSHB_1,
4309 bci_serif_anchor_common,
4310 FDEF,
4312 PUSHB_1,
4314 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4316 DUP,
4317 PUSHB_1,
4318 sal_anchor,
4319 SWAP,
4320 WS, /* sal_anchor = edge_point */
4322 DUP,
4323 DUP,
4324 DUP,
4325 GC_cur,
4326 SWAP,
4327 GC_orig,
4328 PUSHB_1,
4329 bci_round,
4330 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4331 SWAP,
4332 SUB,
4333 SHPIX, /* edge = round(edge_orig) */
4335 ENDF,
4341 * bci_action_serif_anchor
4343 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4344 * anchor.
4346 * in: edge_point (in twilight zone)
4347 * ... stuff for bci_align_segments (edge) ...
4349 * uses: bci_serif_anchor_common
4350 * bci_align_segments
4353 unsigned char FPGM(bci_action_serif_anchor) [] =
4356 PUSHB_1,
4357 bci_action_serif_anchor,
4358 FDEF,
4360 PUSHB_1,
4361 bci_serif_anchor_common,
4362 CALL,
4364 MDAP_noround, /* set rp0 and rp1 to `edge' */
4366 PUSHB_2,
4367 bci_align_segments,
4369 SZP1, /* set zp1 to normal zone 1 */
4370 CALL,
4372 ENDF,
4378 * bci_action_serif_anchor_lower_bound
4380 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4381 * anchor, then moving it again if necessary to stay within a lower
4382 * bound.
4384 * in: edge_point (in twilight zone)
4385 * edge[-1] (in twilight zone)
4386 * ... stuff for bci_align_segments (edge) ...
4388 * uses: bci_serif_anchor_common
4389 * bci_lower_bound
4392 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4395 PUSHB_1,
4396 bci_action_serif_anchor_lower_bound,
4397 FDEF,
4399 PUSHB_1,
4400 bci_serif_anchor_common,
4401 CALL,
4403 PUSHB_1,
4404 bci_lower_bound,
4405 CALL,
4407 ENDF,
4413 * bci_action_serif_anchor_upper_bound
4415 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4416 * anchor, then moving it again if necessary to stay within an upper
4417 * bound.
4419 * in: edge_point (in twilight zone)
4420 * edge[1] (in twilight zone)
4421 * ... stuff for bci_align_segments (edge) ...
4423 * uses: bci_serif_anchor_common
4424 * bci_upper_bound
4427 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4430 PUSHB_1,
4431 bci_action_serif_anchor_upper_bound,
4432 FDEF,
4434 PUSHB_1,
4435 bci_serif_anchor_common,
4436 CALL,
4438 PUSHB_1,
4439 bci_upper_bound,
4440 CALL,
4442 ENDF,
4448 * bci_action_serif_anchor_upper_lower_bound
4450 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4451 * anchor, then moving it again if necessary to stay within a lower and
4452 * upper bound.
4454 * in: edge_point (in twilight zone)
4455 * edge[-1] (in twilight zone)
4456 * edge[1] (in twilight zone)
4457 * ... stuff for bci_align_segments (edge) ...
4459 * uses: bci_serif_anchor_common
4460 * bci_upper_lower_bound
4463 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4466 PUSHB_1,
4467 bci_action_serif_anchor_upper_lower_bound,
4468 FDEF,
4470 PUSHB_1,
4471 bci_serif_anchor_common,
4472 CALL,
4474 PUSHB_1,
4475 bci_upper_lower_bound,
4476 CALL,
4478 ENDF,
4484 * bci_serif_link1_common
4486 * Common code for bci_action_serif_link1 routines.
4488 * CVT: cvtl_0x10000
4491 unsigned char FPGM(bci_serif_link1_common) [] =
4494 PUSHB_1,
4495 bci_serif_link1_common,
4496 FDEF,
4498 PUSHB_1,
4500 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4502 PUSHB_1,
4504 CINDEX, /* s: [...] after edge before after */
4505 PUSHB_1,
4507 CINDEX, /* s: [...] after edge before after before */
4508 MD_orig_ZP2_0,
4509 PUSHB_1,
4511 EQ, /* after_orig_pos == before_orig_pos */
4512 IF, /* s: [...] after edge before */
4513 MDAP_noround, /* set rp0 and rp1 to `before' */
4514 DUP,
4515 ALIGNRP, /* align `edge' with `before' */
4516 SWAP,
4517 POP,
4519 ELSE,
4520 /* we have to execute `a*b/c', with b/c very near to 1: */
4521 /* to avoid overflow while retaining precision, */
4522 /* we transform this to `a + a * (b-c)/c' */
4524 PUSHB_1,
4526 CINDEX, /* s: [...] after edge before edge */
4527 PUSHB_1,
4529 CINDEX, /* s: [...] after edge before edge before */
4530 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4532 DUP,
4533 PUSHB_1,
4535 CINDEX, /* s: [...] after edge before a a after */
4536 PUSHB_1,
4538 CINDEX, /* s: [...] after edge before a a after before */
4539 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4541 PUSHB_1,
4543 CINDEX, /* s: [...] after edge before a a c after */
4544 PUSHB_1,
4546 CINDEX, /* s: [...] after edge before a a c after before */
4547 MD_cur, /* b = after_pos - before_pos */
4549 PUSHB_1,
4551 CINDEX, /* s: [...] after edge before a a c b c */
4552 SUB, /* b-c */
4554 PUSHB_1,
4555 cvtl_0x10000,
4556 RCVT,
4557 MUL, /* (b-c) in 16.16 format */
4558 SWAP,
4560 DUP,
4561 IF, /* c != 0 ? */
4562 DIV, /* s: [...] after edge before a a (b-c)/c */
4563 ELSE,
4564 POP, /* avoid division by zero */
4565 EIF,
4567 MUL, /* a * (b-c)/c * 2^10 */
4568 PUSHB_1,
4569 cvtl_0x10000,
4570 RCVT,
4571 DIV, /* a * (b-c)/c */
4572 ADD, /* a*b/c */
4574 SWAP,
4575 MDAP_noround, /* set rp0 and rp1 to `before' */
4576 SWAP, /* s: [...] after a*b/c edge */
4577 DUP,
4578 DUP,
4579 ALIGNRP, /* align `edge' with `before' */
4580 ROLL,
4581 SHPIX, /* shift `edge' by `a*b/c' */
4583 SWAP, /* s: [...] edge after */
4584 POP,
4585 EIF,
4587 ENDF,
4593 * bci_action_serif_link1
4595 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4596 * before and after.
4598 * in: before_point (in twilight zone)
4599 * edge_point (in twilight zone)
4600 * after_point (in twilight zone)
4601 * ... stuff for bci_align_segments (edge) ...
4603 * uses: bci_serif_link1_common
4604 * bci_align_segments
4607 unsigned char FPGM(bci_action_serif_link1) [] =
4610 PUSHB_1,
4611 bci_action_serif_link1,
4612 FDEF,
4614 PUSHB_1,
4615 bci_serif_link1_common,
4616 CALL,
4618 MDAP_noround, /* set rp0 and rp1 to `edge' */
4620 PUSHB_2,
4621 bci_align_segments,
4623 SZP1, /* set zp1 to normal zone 1 */
4624 CALL,
4626 ENDF,
4632 * bci_action_serif_link1_lower_bound
4634 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4635 * before and after. Additionally, move the serif again if necessary to
4636 * stay within a lower bound.
4638 * in: before_point (in twilight zone)
4639 * edge_point (in twilight zone)
4640 * after_point (in twilight zone)
4641 * edge[-1] (in twilight zone)
4642 * ... stuff for bci_align_segments (edge) ...
4644 * uses: bci_serif_link1_common
4645 * bci_lower_bound
4648 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4651 PUSHB_1,
4652 bci_action_serif_link1_lower_bound,
4653 FDEF,
4655 PUSHB_1,
4656 bci_serif_link1_common,
4657 CALL,
4659 PUSHB_1,
4660 bci_lower_bound,
4661 CALL,
4663 ENDF,
4669 * bci_action_serif_link1_upper_bound
4671 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4672 * before and after. Additionally, move the serif again if necessary to
4673 * stay within an upper bound.
4675 * in: before_point (in twilight zone)
4676 * edge_point (in twilight zone)
4677 * after_point (in twilight zone)
4678 * edge[1] (in twilight zone)
4679 * ... stuff for bci_align_segments (edge) ...
4681 * uses: bci_serif_link1_common
4682 * bci_upper_bound
4685 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4688 PUSHB_1,
4689 bci_action_serif_link1_upper_bound,
4690 FDEF,
4692 PUSHB_1,
4693 bci_serif_link1_common,
4694 CALL,
4696 PUSHB_1,
4697 bci_upper_bound,
4698 CALL,
4700 ENDF,
4706 * bci_action_serif_link1_upper_lower_bound
4708 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4709 * before and after. Additionally, move the serif again if necessary to
4710 * stay within a lower and upper bound.
4712 * in: before_point (in twilight zone)
4713 * edge_point (in twilight zone)
4714 * after_point (in twilight zone)
4715 * edge[-1] (in twilight zone)
4716 * edge[1] (in twilight zone)
4717 * ... stuff for bci_align_segments (edge) ...
4719 * uses: bci_serif_link1_common
4720 * bci_upper_lower_bound
4723 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
4726 PUSHB_1,
4727 bci_action_serif_link1_upper_lower_bound,
4728 FDEF,
4730 PUSHB_1,
4731 bci_serif_link1_common,
4732 CALL,
4734 PUSHB_1,
4735 bci_upper_lower_bound,
4736 CALL,
4738 ENDF,
4744 * bci_serif_link2_common
4746 * Common code for bci_action_serif_link2 routines.
4748 * sal: sal_anchor
4751 unsigned char FPGM(bci_serif_link2_common) [] =
4754 PUSHB_1,
4755 bci_serif_link2_common,
4756 FDEF,
4758 PUSHB_1,
4760 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4762 DUP, /* s: [...] edge edge */
4763 PUSHB_1,
4764 sal_anchor,
4766 DUP, /* s: [...] edge edge anchor anchor */
4767 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4769 MD_orig_ZP2_0,
4770 DUP,
4771 ADD,
4772 PUSHB_1,
4774 ADD,
4775 FLOOR,
4776 PUSHB_1,
4777 2*64,
4778 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4780 SWAP,
4781 DUP,
4782 DUP,
4783 ALIGNRP, /* align `edge' with `sal_anchor' */
4784 ROLL,
4785 SHPIX, /* shift `edge' by `delta' */
4787 ENDF,
4793 * bci_action_serif_link2
4795 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4797 * in: edge_point (in twilight zone)
4798 * ... stuff for bci_align_segments (edge) ...
4800 * uses: bci_serif_link2_common
4801 * bci_align_segments
4804 unsigned char FPGM(bci_action_serif_link2) [] =
4807 PUSHB_1,
4808 bci_action_serif_link2,
4809 FDEF,
4811 PUSHB_1,
4812 bci_serif_link2_common,
4813 CALL,
4815 MDAP_noround, /* set rp0 and rp1 to `edge' */
4817 PUSHB_2,
4818 bci_align_segments,
4820 SZP1, /* set zp1 to normal zone 1 */
4821 CALL,
4823 ENDF,
4829 * bci_action_serif_link2_lower_bound
4831 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4832 * Additionally, move the serif again if necessary to stay within a lower
4833 * bound.
4835 * in: edge_point (in twilight zone)
4836 * edge[-1] (in twilight zone)
4837 * ... stuff for bci_align_segments (edge) ...
4839 * uses: bci_serif_link2_common
4840 * bci_lower_bound
4843 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4846 PUSHB_1,
4847 bci_action_serif_link2_lower_bound,
4848 FDEF,
4850 PUSHB_1,
4851 bci_serif_link2_common,
4852 CALL,
4854 PUSHB_1,
4855 bci_lower_bound,
4856 CALL,
4858 ENDF,
4864 * bci_action_serif_link2_upper_bound
4866 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4867 * Additionally, move the serif again if necessary to stay within an upper
4868 * bound.
4870 * in: edge_point (in twilight zone)
4871 * edge[1] (in twilight zone)
4872 * ... stuff for bci_align_segments (edge) ...
4874 * uses: bci_serif_link2_common
4875 * bci_upper_bound
4878 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4881 PUSHB_1,
4882 bci_action_serif_link2_upper_bound,
4883 FDEF,
4885 PUSHB_1,
4886 bci_serif_link2_common,
4887 CALL,
4889 PUSHB_1,
4890 bci_upper_bound,
4891 CALL,
4893 ENDF,
4899 * bci_action_serif_link2_upper_lower_bound
4901 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4902 * Additionally, move the serif again if necessary to stay within a lower
4903 * and upper bound.
4905 * in: edge_point (in twilight zone)
4906 * edge[-1] (in twilight zone)
4907 * edge[1] (in twilight zone)
4908 * ... stuff for bci_align_segments (edge) ...
4910 * uses: bci_serif_link2_common
4911 * bci_upper_lower_bound
4914 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
4917 PUSHB_1,
4918 bci_action_serif_link2_upper_lower_bound,
4919 FDEF,
4921 PUSHB_1,
4922 bci_serif_link2_common,
4923 CALL,
4925 PUSHB_1,
4926 bci_upper_lower_bound,
4927 CALL,
4929 ENDF,
4935 * bci_hint_glyph
4937 * This is the top-level glyph hinting function which parses the arguments
4938 * on the stack and calls subroutines.
4940 * in: action_0_func_idx
4941 * ... data ...
4942 * action_1_func_idx
4943 * ... data ...
4944 * ...
4946 * CVT: cvtl_is_subglyph
4948 * uses: bci_action_ip_before
4949 * bci_action_ip_after
4950 * bci_action_ip_on
4951 * bci_action_ip_between
4953 * bci_action_adjust_bound
4954 * bci_action_adjust_bound_serif
4955 * bci_action_adjust_bound_round
4956 * bci_action_adjust_bound_round_serif
4958 * bci_action_stem_bound
4959 * bci_action_stem_bound_serif
4960 * bci_action_stem_bound_round
4961 * bci_action_stem_bound_round_serif
4963 * bci_action_link
4964 * bci_action_link_serif
4965 * bci_action_link_round
4966 * bci_action_link_round_serif
4968 * bci_action_anchor
4969 * bci_action_anchor_serif
4970 * bci_action_anchor_round
4971 * bci_action_anchor_round_serif
4973 * bci_action_blue_anchor
4975 * bci_action_adjust
4976 * bci_action_adjust_serif
4977 * bci_action_adjust_round
4978 * bci_action_adjust_round_serif
4980 * bci_action_stem
4981 * bci_action_stem_serif
4982 * bci_action_stem_round
4983 * bci_action_stem_round_serif
4985 * bci_action_blue
4987 * bci_action_serif
4988 * bci_action_serif_lower_bound
4989 * bci_action_serif_upper_bound
4990 * bci_action_serif_upper_lower_bound
4992 * bci_action_serif_anchor
4993 * bci_action_serif_anchor_lower_bound
4994 * bci_action_serif_anchor_upper_bound
4995 * bci_action_serif_anchor_upper_lower_bound
4997 * bci_action_serif_link1
4998 * bci_action_serif_link1_lower_bound
4999 * bci_action_serif_link1_upper_bound
5000 * bci_action_serif_link1_upper_lower_bound
5002 * bci_action_serif_link2
5003 * bci_action_serif_link2_lower_bound
5004 * bci_action_serif_link2_upper_bound
5005 * bci_action_serif_link2_upper_lower_bound
5008 unsigned char FPGM(bci_hint_glyph) [] =
5011 PUSHB_1,
5012 bci_hint_glyph,
5013 FDEF,
5015 /* start_loop: */
5016 /* loop until all data on stack is used */
5017 CALL,
5018 PUSHB_1,
5020 NEG,
5021 PUSHB_1,
5023 DEPTH,
5025 JROT, /* goto start_loop */
5027 PUSHB_1,
5029 SZP2, /* set zp2 to normal zone 1 */
5030 IUP_y,
5032 ENDF,
5037 #define COPY_FPGM(func_name) \
5038 memcpy(buf_p, fpgm_ ## func_name, \
5039 sizeof (fpgm_ ## func_name)); \
5040 buf_p += sizeof (fpgm_ ## func_name) \
5042 static FT_Error
5043 TA_table_build_fpgm(FT_Byte** fpgm,
5044 FT_ULong* fpgm_len,
5045 FONT* font)
5047 FT_UInt buf_len;
5048 FT_UInt len;
5049 FT_Byte* buf;
5050 FT_Byte* buf_p;
5053 /* for compatibility with dumb bytecode interpreters or analyzers, */
5054 /* FDEFs are stored in ascending index order, without holes -- */
5055 /* note that some FDEFs are not always needed */
5056 /* (depending on options of `TTFautohint'), */
5057 /* but implementing dynamic FDEF indices would be a lot of work */
5059 buf_len = sizeof (FPGM(bci_round))
5060 + sizeof (FPGM(bci_smooth_stem_width_a))
5062 + sizeof (FPGM(bci_smooth_stem_width_b))
5064 + sizeof (FPGM(bci_smooth_stem_width_c))
5065 + sizeof (FPGM(bci_get_best_width))
5066 + sizeof (FPGM(bci_strong_stem_width_a))
5068 + sizeof (FPGM(bci_strong_stem_width_b))
5069 + sizeof (FPGM(bci_loop_do))
5070 + sizeof (FPGM(bci_loop))
5071 + sizeof (FPGM(bci_cvt_rescale))
5072 + sizeof (FPGM(bci_blue_round_a))
5074 + sizeof (FPGM(bci_blue_round_b))
5075 + sizeof (FPGM(bci_decrement_component_counter))
5076 + sizeof (FPGM(bci_get_point_extrema))
5077 + sizeof (FPGM(bci_nibbles))
5078 + sizeof (FPGM(bci_number_set_is_element))
5079 + sizeof (FPGM(bci_number_set_is_element2))
5081 + sizeof (FPGM(bci_create_segment))
5082 + sizeof (FPGM(bci_create_segments))
5084 + sizeof (FPGM(bci_create_segments_0))
5085 + sizeof (FPGM(bci_create_segments_1))
5086 + sizeof (FPGM(bci_create_segments_2))
5087 + sizeof (FPGM(bci_create_segments_3))
5088 + sizeof (FPGM(bci_create_segments_4))
5089 + sizeof (FPGM(bci_create_segments_5))
5090 + sizeof (FPGM(bci_create_segments_6))
5091 + sizeof (FPGM(bci_create_segments_7))
5092 + sizeof (FPGM(bci_create_segments_8))
5093 + sizeof (FPGM(bci_create_segments_9))
5095 + sizeof (FPGM(bci_create_segments_composite))
5097 + sizeof (FPGM(bci_create_segments_composite_0))
5098 + sizeof (FPGM(bci_create_segments_composite_1))
5099 + sizeof (FPGM(bci_create_segments_composite_2))
5100 + sizeof (FPGM(bci_create_segments_composite_3))
5101 + sizeof (FPGM(bci_create_segments_composite_4))
5102 + sizeof (FPGM(bci_create_segments_composite_5))
5103 + sizeof (FPGM(bci_create_segments_composite_6))
5104 + sizeof (FPGM(bci_create_segments_composite_7))
5105 + sizeof (FPGM(bci_create_segments_composite_8))
5106 + sizeof (FPGM(bci_create_segments_composite_9))
5108 + sizeof (FPGM(bci_align_point))
5109 + sizeof (FPGM(bci_align_segment))
5110 + sizeof (FPGM(bci_align_segments))
5112 + sizeof (FPGM(bci_scale_contour))
5113 + sizeof (FPGM(bci_scale_glyph))
5114 + sizeof (FPGM(bci_scale_composite_glyph))
5115 + sizeof (FPGM(bci_shift_contour))
5116 + sizeof (FPGM(bci_shift_subglyph))
5118 + sizeof (FPGM(bci_ip_outer_align_point))
5119 + sizeof (FPGM(bci_ip_on_align_points))
5120 + sizeof (FPGM(bci_ip_between_align_point))
5121 + sizeof (FPGM(bci_ip_between_align_points))
5123 + sizeof (FPGM(bci_adjust_common))
5124 + sizeof (FPGM(bci_stem_common))
5125 + sizeof (FPGM(bci_serif_common))
5126 + sizeof (FPGM(bci_serif_anchor_common))
5127 + sizeof (FPGM(bci_serif_link1_common))
5128 + sizeof (FPGM(bci_serif_link2_common))
5130 + sizeof (FPGM(bci_lower_bound))
5131 + sizeof (FPGM(bci_upper_bound))
5132 + sizeof (FPGM(bci_upper_lower_bound))
5134 + sizeof (FPGM(bci_adjust_bound))
5135 + sizeof (FPGM(bci_stem_bound))
5136 + sizeof (FPGM(bci_link))
5137 + sizeof (FPGM(bci_anchor))
5138 + sizeof (FPGM(bci_adjust))
5139 + sizeof (FPGM(bci_stem))
5141 + sizeof (FPGM(bci_action_ip_before))
5142 + sizeof (FPGM(bci_action_ip_after))
5143 + sizeof (FPGM(bci_action_ip_on))
5144 + sizeof (FPGM(bci_action_ip_between))
5146 + sizeof (FPGM(bci_action_blue))
5147 + sizeof (FPGM(bci_action_blue_anchor))
5149 + sizeof (FPGM(bci_action_anchor))
5150 + sizeof (FPGM(bci_action_anchor_serif))
5151 + sizeof (FPGM(bci_action_anchor_round))
5152 + sizeof (FPGM(bci_action_anchor_round_serif))
5154 + sizeof (FPGM(bci_action_adjust))
5155 + sizeof (FPGM(bci_action_adjust_serif))
5156 + sizeof (FPGM(bci_action_adjust_round))
5157 + sizeof (FPGM(bci_action_adjust_round_serif))
5158 + sizeof (FPGM(bci_action_adjust_bound))
5159 + sizeof (FPGM(bci_action_adjust_bound_serif))
5160 + sizeof (FPGM(bci_action_adjust_bound_round))
5161 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5163 + sizeof (FPGM(bci_action_link))
5164 + sizeof (FPGM(bci_action_link_serif))
5165 + sizeof (FPGM(bci_action_link_round))
5166 + sizeof (FPGM(bci_action_link_round_serif))
5168 + sizeof (FPGM(bci_action_stem))
5169 + sizeof (FPGM(bci_action_stem_serif))
5170 + sizeof (FPGM(bci_action_stem_round))
5171 + sizeof (FPGM(bci_action_stem_round_serif))
5172 + sizeof (FPGM(bci_action_stem_bound))
5173 + sizeof (FPGM(bci_action_stem_bound_serif))
5174 + sizeof (FPGM(bci_action_stem_bound_round))
5175 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5177 + sizeof (FPGM(bci_action_serif))
5178 + sizeof (FPGM(bci_action_serif_lower_bound))
5179 + sizeof (FPGM(bci_action_serif_upper_bound))
5180 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5182 + sizeof (FPGM(bci_action_serif_anchor))
5183 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5184 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5185 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5187 + sizeof (FPGM(bci_action_serif_link1))
5188 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5189 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5190 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5192 + sizeof (FPGM(bci_action_serif_link2))
5193 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5194 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5195 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5197 + sizeof (FPGM(bci_hint_glyph));
5199 /* buffer length must be a multiple of four */
5200 len = (buf_len + 3) & ~3;
5201 buf = (FT_Byte*)malloc(len);
5202 if (!buf)
5203 return FT_Err_Out_Of_Memory;
5205 /* pad end of buffer with zeros */
5206 buf[len - 1] = 0x00;
5207 buf[len - 2] = 0x00;
5208 buf[len - 3] = 0x00;
5210 /* copy font program into buffer and fill in the missing variables */
5211 buf_p = buf;
5213 COPY_FPGM(bci_round);
5214 COPY_FPGM(bci_smooth_stem_width_a);
5215 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5216 COPY_FPGM(bci_smooth_stem_width_b);
5217 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5218 COPY_FPGM(bci_smooth_stem_width_c);
5219 COPY_FPGM(bci_get_best_width);
5220 COPY_FPGM(bci_strong_stem_width_a);
5221 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5222 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font);
5223 COPY_FPGM(bci_strong_stem_width_b);
5224 COPY_FPGM(bci_loop_do);
5225 COPY_FPGM(bci_loop);
5226 COPY_FPGM(bci_cvt_rescale);
5227 COPY_FPGM(bci_blue_round_a);
5228 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
5229 COPY_FPGM(bci_blue_round_b);
5230 COPY_FPGM(bci_decrement_component_counter);
5231 COPY_FPGM(bci_get_point_extrema);
5232 COPY_FPGM(bci_nibbles);
5233 COPY_FPGM(bci_number_set_is_element);
5234 COPY_FPGM(bci_number_set_is_element2);
5236 COPY_FPGM(bci_create_segment);
5237 COPY_FPGM(bci_create_segments);
5239 COPY_FPGM(bci_create_segments_0);
5240 COPY_FPGM(bci_create_segments_1);
5241 COPY_FPGM(bci_create_segments_2);
5242 COPY_FPGM(bci_create_segments_3);
5243 COPY_FPGM(bci_create_segments_4);
5244 COPY_FPGM(bci_create_segments_5);
5245 COPY_FPGM(bci_create_segments_6);
5246 COPY_FPGM(bci_create_segments_7);
5247 COPY_FPGM(bci_create_segments_8);
5248 COPY_FPGM(bci_create_segments_9);
5250 COPY_FPGM(bci_create_segments_composite);
5252 COPY_FPGM(bci_create_segments_composite_0);
5253 COPY_FPGM(bci_create_segments_composite_1);
5254 COPY_FPGM(bci_create_segments_composite_2);
5255 COPY_FPGM(bci_create_segments_composite_3);
5256 COPY_FPGM(bci_create_segments_composite_4);
5257 COPY_FPGM(bci_create_segments_composite_5);
5258 COPY_FPGM(bci_create_segments_composite_6);
5259 COPY_FPGM(bci_create_segments_composite_7);
5260 COPY_FPGM(bci_create_segments_composite_8);
5261 COPY_FPGM(bci_create_segments_composite_9);
5263 COPY_FPGM(bci_align_point);
5264 COPY_FPGM(bci_align_segment);
5265 COPY_FPGM(bci_align_segments);
5267 COPY_FPGM(bci_scale_contour);
5268 COPY_FPGM(bci_scale_glyph);
5269 COPY_FPGM(bci_scale_composite_glyph);
5270 COPY_FPGM(bci_shift_contour);
5271 COPY_FPGM(bci_shift_subglyph);
5273 COPY_FPGM(bci_ip_outer_align_point);
5274 COPY_FPGM(bci_ip_on_align_points);
5275 COPY_FPGM(bci_ip_between_align_point);
5276 COPY_FPGM(bci_ip_between_align_points);
5278 COPY_FPGM(bci_adjust_common);
5279 COPY_FPGM(bci_stem_common);
5280 COPY_FPGM(bci_serif_common);
5281 COPY_FPGM(bci_serif_anchor_common);
5282 COPY_FPGM(bci_serif_link1_common);
5283 COPY_FPGM(bci_serif_link2_common);
5285 COPY_FPGM(bci_lower_bound);
5286 COPY_FPGM(bci_upper_bound);
5287 COPY_FPGM(bci_upper_lower_bound);
5289 COPY_FPGM(bci_adjust_bound);
5290 COPY_FPGM(bci_stem_bound);
5291 COPY_FPGM(bci_link);
5292 COPY_FPGM(bci_anchor);
5293 COPY_FPGM(bci_adjust);
5294 COPY_FPGM(bci_stem);
5296 COPY_FPGM(bci_action_ip_before);
5297 COPY_FPGM(bci_action_ip_after);
5298 COPY_FPGM(bci_action_ip_on);
5299 COPY_FPGM(bci_action_ip_between);
5301 COPY_FPGM(bci_action_blue);
5302 COPY_FPGM(bci_action_blue_anchor);
5304 COPY_FPGM(bci_action_anchor);
5305 COPY_FPGM(bci_action_anchor_serif);
5306 COPY_FPGM(bci_action_anchor_round);
5307 COPY_FPGM(bci_action_anchor_round_serif);
5309 COPY_FPGM(bci_action_adjust);
5310 COPY_FPGM(bci_action_adjust_serif);
5311 COPY_FPGM(bci_action_adjust_round);
5312 COPY_FPGM(bci_action_adjust_round_serif);
5313 COPY_FPGM(bci_action_adjust_bound);
5314 COPY_FPGM(bci_action_adjust_bound_serif);
5315 COPY_FPGM(bci_action_adjust_bound_round);
5316 COPY_FPGM(bci_action_adjust_bound_round_serif);
5318 COPY_FPGM(bci_action_link);
5319 COPY_FPGM(bci_action_link_serif);
5320 COPY_FPGM(bci_action_link_round);
5321 COPY_FPGM(bci_action_link_round_serif);
5323 COPY_FPGM(bci_action_stem);
5324 COPY_FPGM(bci_action_stem_serif);
5325 COPY_FPGM(bci_action_stem_round);
5326 COPY_FPGM(bci_action_stem_round_serif);
5327 COPY_FPGM(bci_action_stem_bound);
5328 COPY_FPGM(bci_action_stem_bound_serif);
5329 COPY_FPGM(bci_action_stem_bound_round);
5330 COPY_FPGM(bci_action_stem_bound_round_serif);
5332 COPY_FPGM(bci_action_serif);
5333 COPY_FPGM(bci_action_serif_lower_bound);
5334 COPY_FPGM(bci_action_serif_upper_bound);
5335 COPY_FPGM(bci_action_serif_upper_lower_bound);
5337 COPY_FPGM(bci_action_serif_anchor);
5338 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5339 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5340 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5342 COPY_FPGM(bci_action_serif_link1);
5343 COPY_FPGM(bci_action_serif_link1_lower_bound);
5344 COPY_FPGM(bci_action_serif_link1_upper_bound);
5345 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5347 COPY_FPGM(bci_action_serif_link2);
5348 COPY_FPGM(bci_action_serif_link2_lower_bound);
5349 COPY_FPGM(bci_action_serif_link2_upper_bound);
5350 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5352 COPY_FPGM(bci_hint_glyph);
5354 *fpgm = buf;
5355 *fpgm_len = buf_len;
5357 return FT_Err_Ok;
5361 FT_Error
5362 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5363 FONT* font)
5365 FT_Error error = FT_Err_Ok;
5367 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5368 glyf_Data* data = (glyf_Data*)glyf_table->data;
5370 FT_Byte* fpgm_buf;
5371 FT_ULong fpgm_len;
5374 error = TA_sfnt_add_table_info(sfnt);
5375 if (error)
5376 goto Exit;
5378 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5379 if (glyf_table->processed)
5381 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5382 goto Exit;
5385 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
5386 if (error)
5387 goto Exit;
5389 if (fpgm_len > sfnt->max_instructions)
5390 sfnt->max_instructions = fpgm_len;
5392 /* in case of success, `fpgm_buf' gets linked */
5393 /* and is eventually freed in `TA_font_unload' */
5394 error = TA_font_add_table(font,
5395 &sfnt->table_infos[sfnt->num_table_infos - 1],
5396 TTAG_fpgm, fpgm_len, fpgm_buf);
5397 if (error)
5398 free(fpgm_buf);
5399 else
5400 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5402 Exit:
5403 return error;
5406 /* end of tafpgm.c */