Improve comment.
[ttfautohint.git] / lib / tafpgm.c
blob55bc1ea7e64fa835edf3983e12c9e0781d1ecfb2
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 * This is the equivalent to the following code (function
666 * `ta_latin_metrics_scale_dim':
668 * delta = dist;
669 * if (dist < 0)
670 * delta = -delta;
672 * if (delta < 32)
673 * delta = 0;
674 * else if (delta < 48)
675 * delta = 32;
676 * else
677 * delta = 64;
679 * if (dist < 0)
680 * delta = -delta;
682 * in: ref_idx
684 * out: ref_idx+1
686 * uses: bci_round
689 unsigned char FPGM(bci_blue_round_a) [] =
692 PUSHB_1,
693 bci_blue_round,
694 FDEF,
696 DUP,
697 DUP,
698 RCVT, /* s: ref_idx ref_idx ref */
700 DUP,
701 PUSHB_1,
702 bci_round,
703 CALL,
704 SWAP, /* s: ref_idx ref_idx round(ref) ref */
706 PUSHB_2,
710 /* %c, blue_count */
712 unsigned char FPGM(bci_blue_round_b) [] =
716 CINDEX,
717 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
718 DUP,
719 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
721 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
722 SWAP,
723 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
724 DUP,
725 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
727 DUP,
728 PUSHB_1,
730 LT, /* delta < 32 */
732 POP,
733 PUSHB_1,
734 0, /* delta = 0 */
736 ELSE,
737 PUSHB_1,
739 LT, /* delta < 48 */
741 PUSHB_1,
742 32, /* delta = 32 */
744 ELSE,
745 PUSHB_1,
746 64, /* delta = 64 */
747 EIF,
748 EIF,
750 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
751 PUSHB_1,
753 LT, /* dist < 0 */
755 NEG, /* delta = -delta */
756 EIF,
758 PUSHB_1,
760 CINDEX,
761 SWAP,
762 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
764 WCVTP,
765 WCVTP,
767 PUSHB_1,
769 ADD, /* s: (ref_idx + 1) */
771 ENDF,
777 * bci_decrement_component_counter
779 * An auxiliary function for composite glyphs.
781 * CVT: cvtl_is_subglyph
784 unsigned char FPGM(bci_decrement_component_counter) [] =
787 PUSHB_1,
788 bci_decrement_component_counter,
789 FDEF,
791 /* decrement `cvtl_is_subglyph' counter */
792 PUSHB_2,
793 cvtl_is_subglyph,
794 cvtl_is_subglyph,
795 RCVT,
796 PUSHB_1,
798 SUB,
799 WCVTP,
801 ENDF,
807 * bci_get_point_extrema
809 * An auxiliary function for `bci_create_segment'.
811 * in: point-1
813 * out: point
815 * sal: sal_point_min
816 * sal_point_max
819 unsigned char FPGM(bci_get_point_extrema) [] =
822 PUSHB_1,
823 bci_get_point_extrema,
824 FDEF,
826 PUSHB_1,
828 ADD, /* s: point */
829 DUP,
830 DUP,
832 /* check whether `point' is a new minimum */
833 PUSHB_1,
834 sal_point_min,
835 RS, /* s: point point point point_min */
836 MD_orig,
837 /* if distance is negative, we have a new minimum */
838 PUSHB_1,
841 IF, /* s: point point */
842 DUP,
843 PUSHB_1,
844 sal_point_min,
845 SWAP,
847 EIF,
849 /* check whether `point' is a new maximum */
850 PUSHB_1,
851 sal_point_max,
852 RS, /* s: point point point_max */
853 MD_orig,
854 /* if distance is positive, we have a new maximum */
855 PUSHB_1,
858 IF, /* s: point */
859 DUP,
860 PUSHB_1,
861 sal_point_max,
862 SWAP,
864 EIF, /* s: point */
866 ENDF,
872 * bci_nibbles
874 * Pop a byte with two delta arguments in its nibbles and push the
875 * expanded arguments separately as two bytes.
877 * in: 16 * (end - start) + (start - base)
879 * out: start
880 * end
882 * sal: sal_base (set to `end' at return)
886 unsigned char FPGM(bci_nibbles) [] =
888 PUSHB_1,
889 bci_nibbles,
890 FDEF,
892 DUP,
893 PUSHW_1,
894 0x04, /* 16*64 */
895 0x00,
896 DIV, /* s: in hnibble */
897 DUP,
898 PUSHW_1,
899 0x04, /* 16*64 */
900 0x00,
901 MUL, /* s: in hnibble (hnibble * 16) */
902 ROLL,
903 SWAP,
904 SUB, /* s: hnibble lnibble */
906 PUSHB_1,
907 sal_base,
909 ADD, /* s: hnibble start */
910 DUP,
911 ROLL,
912 ADD, /* s: start end */
914 DUP,
915 PUSHB_1,
916 sal_base,
917 SWAP,
918 WS, /* sal_base = end */
920 SWAP,
922 ENDF,
928 * bci_number_set_is_element
930 * Pop values from stack until it is empty. If one of them is equal to
931 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
932 * otherwise).
934 * in: ppem_value_1
935 * ppem_value_2
936 * ...
938 * CVT: cvtl_is_element
941 unsigned char FPGM(bci_number_set_is_element) [] =
944 PUSHB_1,
945 bci_number_set_is_element,
946 FDEF,
948 /* start_loop: */
949 MPPEM,
952 PUSHB_2,
953 cvtl_is_element,
955 WCVTP,
956 EIF,
958 DEPTH,
959 PUSHB_1,
961 NEG,
962 SWAP,
963 JROT, /* goto start_loop if stack depth != 0 */
965 ENDF,
971 * bci_number_set_is_element2
973 * Pop value ranges from stack until it is empty. If one of them contains
974 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
975 * otherwise).
977 * in: ppem_range_1_start
978 * ppem_range_1_end
979 * ppem_range_2_start
980 * ppem_range_2_end
981 * ...
983 * CVT: cvtl_is_element
986 unsigned char FPGM(bci_number_set_is_element2) [] =
989 PUSHB_1,
990 bci_number_set_is_element2,
991 FDEF,
993 /* start_loop: */
994 MPPEM,
995 LTEQ,
997 MPPEM,
998 GTEQ,
1000 PUSHB_2,
1001 cvtl_is_element,
1003 WCVTP,
1004 EIF,
1005 ELSE,
1006 POP,
1007 EIF,
1009 DEPTH,
1010 PUSHB_1,
1012 NEG,
1013 SWAP,
1014 JROT, /* goto start_loop if stack depth != 0 */
1016 ENDF,
1022 * bci_create_segment
1024 * Store start and end point of a segment in the storage area,
1025 * then construct a point in the twilight zone to represent it.
1027 * This function is used by `bci_create_segments'.
1029 * in: start
1030 * end
1031 * [last (if wrap-around segment)]
1032 * [first (if wrap-around segment)]
1034 * sal: sal_i (start of current segment)
1035 * sal_j (current twilight point)
1036 * sal_point_min
1037 * sal_point_max
1038 * sal_base
1039 * sal_num_packed_segments
1041 * CVT: cvtl_scale
1042 * cvtl_0x10000
1043 * cvtl_temp
1045 * uses: bci_get_point_extrema
1046 * bci_nibbles
1048 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1049 * delta values in nibbles (without a wrap-around segment).
1052 unsigned char FPGM(bci_create_segment) [] =
1055 PUSHB_1,
1056 bci_create_segment,
1057 FDEF,
1059 PUSHB_2,
1061 sal_num_packed_segments,
1063 NEQ,
1065 PUSHB_2,
1066 sal_num_packed_segments,
1067 sal_num_packed_segments,
1069 PUSHB_1,
1071 SUB,
1072 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1074 PUSHB_1,
1075 bci_nibbles,
1076 CALL,
1077 EIF,
1079 PUSHB_1,
1080 sal_i,
1082 PUSHB_1,
1084 CINDEX,
1085 WS, /* sal[sal_i] = start */
1087 /* initialize inner loop(s) */
1088 PUSHB_2,
1089 sal_point_min,
1091 CINDEX,
1092 WS, /* sal_point_min = start */
1093 PUSHB_2,
1094 sal_point_max,
1096 CINDEX,
1097 WS, /* sal_point_max = start */
1099 PUSHB_1,
1101 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1103 SWAP,
1104 DUP,
1105 PUSHB_1,
1107 CINDEX, /* s: start end end start */
1108 LT, /* start > end */
1110 /* we have a wrap-around segment with two more arguments */
1111 /* to give the last and first point of the contour, respectively; */
1112 /* our job is to store a segment `start'-`last', */
1113 /* and to get extrema for the two segments */
1114 /* `start'-`last' and `first'-`end' */
1116 /* s: first last start end */
1117 PUSHB_2,
1119 sal_i,
1121 ADD,
1122 PUSHB_1,
1124 CINDEX,
1125 WS, /* sal[sal_i + 1] = last */
1127 ROLL,
1128 ROLL, /* s: first end last start */
1129 DUP,
1130 ROLL,
1131 SWAP, /* s: first end start last start */
1132 SUB, /* s: first end start loop_count */
1134 PUSHB_1,
1135 bci_get_point_extrema,
1136 LOOPCALL,
1137 /* clean up stack */
1138 POP,
1140 SWAP, /* s: end first */
1141 PUSHB_1,
1143 SUB,
1144 DUP,
1145 ROLL, /* s: (first - 1) (first - 1) end */
1146 SWAP,
1147 SUB, /* s: (first - 1) loop_count */
1149 PUSHB_1,
1150 bci_get_point_extrema,
1151 LOOPCALL,
1152 /* clean up stack */
1153 POP,
1155 ELSE, /* s: start end */
1156 PUSHB_2,
1158 sal_i,
1160 ADD,
1161 PUSHB_1,
1163 CINDEX,
1164 WS, /* sal[sal_i + 1] = end */
1166 PUSHB_1,
1168 CINDEX,
1169 SUB, /* s: start loop_count */
1171 PUSHB_1,
1172 bci_get_point_extrema,
1173 LOOPCALL,
1174 /* clean up stack */
1175 POP,
1176 EIF,
1178 /* the twilight point representing a segment */
1179 /* is in the middle between the minimum and maximum */
1180 PUSHB_1,
1181 sal_point_min,
1183 GC_orig,
1184 PUSHB_1,
1185 sal_point_max,
1187 GC_orig,
1188 ADD,
1189 PUSHB_1,
1190 2*64,
1191 DIV, /* s: middle_pos */
1193 DO_SCALE, /* middle_pos = middle_pos * scale */
1195 /* write it to temporary CVT location */
1196 PUSHB_2,
1197 cvtl_temp,
1199 SZP0, /* set zp0 to twilight zone 0 */
1200 SWAP,
1201 WCVTP,
1203 /* create twilight point with index `sal_j' */
1204 PUSHB_1,
1205 sal_j,
1207 PUSHB_1,
1208 cvtl_temp,
1209 MIAP_noround,
1211 PUSHB_3,
1212 sal_j,
1214 sal_j,
1216 ADD, /* twilight_point = twilight_point + 1 */
1219 ENDF,
1225 * bci_create_segments
1227 * This is the top-level entry function.
1229 * It pops point ranges from the stack to define segments, computes
1230 * twilight points to represent segments, and finally calls
1231 * `bci_hint_glyph' to handle the rest.
1233 * in: num_packed_segments
1234 * num_segments (N)
1235 * segment_start_0
1236 * segment_end_0
1237 * [contour_last 0 (if wrap-around segment)]
1238 * [contour_first 0 (if wrap-around segment)]
1239 * segment_start_1
1240 * segment_end_1
1241 * [contour_last 0 (if wrap-around segment)]
1242 * [contour_first 0 (if wrap-around segment)]
1243 * ...
1244 * segment_start_(N-1)
1245 * segment_end_(N-1)
1246 * [contour_last (N-1) (if wrap-around segment)]
1247 * [contour_first (N-1) (if wrap-around segment)]
1248 * ... stuff for bci_hint_glyph ...
1250 * sal: sal_i (start of current segment)
1251 * sal_j (current twilight point)
1252 * sal_num_packed_segments
1253 * sal_base (the base for delta values in nibbles)
1255 * CVT: cvtl_is_subglyph
1257 * uses: bci_create_segment
1258 * bci_loop
1259 * bci_hint_glyph
1261 * If `num_packed_segments' is set to p, the first p start/end pairs are
1262 * stored as delta values in nibbles, with the `start' delta in the lower
1263 * nibble (and there are no wrap-around segments). For example, if the
1264 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1265 * stack are 0x21, 0x32, and 0x14.
1269 unsigned char FPGM(bci_create_segments) [] =
1272 PUSHB_1,
1273 bci_create_segments,
1274 FDEF,
1276 /* only do something if we are not a subglyph */
1277 PUSHB_2,
1279 cvtl_is_subglyph,
1280 RCVT,
1283 /* all our measurements are taken along the y axis */
1284 SVTCA_y,
1286 PUSHB_1,
1287 sal_num_packed_segments,
1288 SWAP,
1291 DUP,
1292 ADD,
1293 PUSHB_1,
1295 SUB, /* delta = (2*num_segments - 1) */
1297 PUSHB_6,
1298 sal_segment_offset,
1299 sal_segment_offset,
1301 sal_j,
1303 sal_base,
1305 WS, /* sal_base = 0 */
1306 WS, /* sal_j = 0 (point offset) */
1308 ROLL,
1309 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1311 PUSHB_2,
1312 bci_create_segment,
1313 bci_loop,
1314 CALL,
1316 PUSHB_1,
1317 bci_hint_glyph,
1318 CALL,
1320 ELSE,
1321 CLEAR,
1322 EIF,
1324 ENDF,
1330 * bci_create_segments_X
1332 * Top-level routines for calling `bci_create_segments'.
1335 unsigned char FPGM(bci_create_segments_0) [] =
1338 PUSHB_1,
1339 bci_create_segments_0,
1340 FDEF,
1342 PUSHB_2,
1344 bci_create_segments,
1345 CALL,
1347 ENDF,
1351 unsigned char FPGM(bci_create_segments_1) [] =
1354 PUSHB_1,
1355 bci_create_segments_1,
1356 FDEF,
1358 PUSHB_2,
1360 bci_create_segments,
1361 CALL,
1363 ENDF,
1367 unsigned char FPGM(bci_create_segments_2) [] =
1370 PUSHB_1,
1371 bci_create_segments_2,
1372 FDEF,
1374 PUSHB_2,
1376 bci_create_segments,
1377 CALL,
1379 ENDF,
1383 unsigned char FPGM(bci_create_segments_3) [] =
1386 PUSHB_1,
1387 bci_create_segments_3,
1388 FDEF,
1390 PUSHB_2,
1392 bci_create_segments,
1393 CALL,
1395 ENDF,
1399 unsigned char FPGM(bci_create_segments_4) [] =
1402 PUSHB_1,
1403 bci_create_segments_4,
1404 FDEF,
1406 PUSHB_2,
1408 bci_create_segments,
1409 CALL,
1411 ENDF,
1415 unsigned char FPGM(bci_create_segments_5) [] =
1418 PUSHB_1,
1419 bci_create_segments_5,
1420 FDEF,
1422 PUSHB_2,
1424 bci_create_segments,
1425 CALL,
1427 ENDF,
1431 unsigned char FPGM(bci_create_segments_6) [] =
1434 PUSHB_1,
1435 bci_create_segments_6,
1436 FDEF,
1438 PUSHB_2,
1440 bci_create_segments,
1441 CALL,
1443 ENDF,
1447 unsigned char FPGM(bci_create_segments_7) [] =
1450 PUSHB_1,
1451 bci_create_segments_7,
1452 FDEF,
1454 PUSHB_2,
1456 bci_create_segments,
1457 CALL,
1459 ENDF,
1463 unsigned char FPGM(bci_create_segments_8) [] =
1466 PUSHB_1,
1467 bci_create_segments_8,
1468 FDEF,
1470 PUSHB_2,
1472 bci_create_segments,
1473 CALL,
1475 ENDF,
1479 unsigned char FPGM(bci_create_segments_9) [] =
1482 PUSHB_1,
1483 bci_create_segments_9,
1484 FDEF,
1486 PUSHB_2,
1488 bci_create_segments,
1489 CALL,
1491 ENDF,
1497 * bci_create_segments_composite
1499 * The same as `bci_create_segments'.
1500 * It also decrements the composite component counter.
1502 * sal: sal_num_packed_segments
1503 * sal_segment_offset
1505 * CVT: cvtl_is_subglyph
1507 * uses: bci_decrement_component_counter
1508 * bci_create_segment
1509 * bci_loop
1510 * bci_hint_glyph
1513 unsigned char FPGM(bci_create_segments_composite) [] =
1516 PUSHB_1,
1517 bci_create_segments_composite,
1518 FDEF,
1520 PUSHB_1,
1521 bci_decrement_component_counter,
1522 CALL,
1524 /* only do something if we are not a subglyph */
1525 PUSHB_2,
1527 cvtl_is_subglyph,
1528 RCVT,
1531 /* all our measurements are taken along the y axis */
1532 SVTCA_y,
1534 PUSHB_1,
1535 sal_num_packed_segments,
1536 SWAP,
1539 DUP,
1540 ADD,
1541 PUSHB_1,
1543 SUB, /* delta = (2*num_segments - 1) */
1545 PUSHB_6,
1546 sal_segment_offset,
1547 sal_segment_offset,
1549 sal_j,
1551 sal_base,
1553 WS, /* sal_base = 0 */
1554 WS, /* sal_j = 0 (point offset) */
1556 ROLL,
1557 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1559 PUSHB_2,
1560 bci_create_segment,
1561 bci_loop,
1562 CALL,
1564 PUSHB_1,
1565 bci_hint_glyph,
1566 CALL,
1568 ELSE,
1569 CLEAR,
1570 EIF,
1572 ENDF,
1578 * bci_create_segments_composite_X
1580 * Top-level routines for calling `bci_create_segments_composite'.
1583 unsigned char FPGM(bci_create_segments_composite_0) [] =
1586 PUSHB_1,
1587 bci_create_segments_composite_0,
1588 FDEF,
1590 PUSHB_2,
1592 bci_create_segments_composite,
1593 CALL,
1595 ENDF,
1599 unsigned char FPGM(bci_create_segments_composite_1) [] =
1602 PUSHB_1,
1603 bci_create_segments_composite_1,
1604 FDEF,
1606 PUSHB_2,
1608 bci_create_segments_composite,
1609 CALL,
1611 ENDF,
1615 unsigned char FPGM(bci_create_segments_composite_2) [] =
1618 PUSHB_1,
1619 bci_create_segments_composite_2,
1620 FDEF,
1622 PUSHB_2,
1624 bci_create_segments_composite,
1625 CALL,
1627 ENDF,
1631 unsigned char FPGM(bci_create_segments_composite_3) [] =
1634 PUSHB_1,
1635 bci_create_segments_composite_3,
1636 FDEF,
1638 PUSHB_2,
1640 bci_create_segments_composite,
1641 CALL,
1643 ENDF,
1647 unsigned char FPGM(bci_create_segments_composite_4) [] =
1650 PUSHB_1,
1651 bci_create_segments_composite_4,
1652 FDEF,
1654 PUSHB_2,
1656 bci_create_segments_composite,
1657 CALL,
1659 ENDF,
1663 unsigned char FPGM(bci_create_segments_composite_5) [] =
1666 PUSHB_1,
1667 bci_create_segments_composite_5,
1668 FDEF,
1670 PUSHB_2,
1672 bci_create_segments_composite,
1673 CALL,
1675 ENDF,
1679 unsigned char FPGM(bci_create_segments_composite_6) [] =
1682 PUSHB_1,
1683 bci_create_segments_composite_6,
1684 FDEF,
1686 PUSHB_2,
1688 bci_create_segments_composite,
1689 CALL,
1691 ENDF,
1695 unsigned char FPGM(bci_create_segments_composite_7) [] =
1698 PUSHB_1,
1699 bci_create_segments_composite_7,
1700 FDEF,
1702 PUSHB_2,
1704 bci_create_segments_composite,
1705 CALL,
1707 ENDF,
1711 unsigned char FPGM(bci_create_segments_composite_8) [] =
1714 PUSHB_1,
1715 bci_create_segments_composite_8,
1716 FDEF,
1718 PUSHB_2,
1720 bci_create_segments_composite,
1721 CALL,
1723 ENDF,
1727 unsigned char FPGM(bci_create_segments_composite_9) [] =
1730 PUSHB_1,
1731 bci_create_segments_composite_9,
1732 FDEF,
1734 PUSHB_2,
1736 bci_create_segments_composite,
1737 CALL,
1739 ENDF,
1745 * bci_align_point
1747 * An auxiliary function for `bci_align_segment'.
1749 * in: point
1751 * out: point+1
1754 unsigned char FPGM(bci_align_point) [] =
1757 PUSHB_1,
1758 bci_align_point,
1759 FDEF,
1761 DUP,
1762 ALIGNRP, /* align point with rp0 */
1764 PUSHB_1,
1766 ADD,
1768 ENDF,
1774 * bci_align_segment
1776 * Align all points in a segment to the twilight point in rp0.
1777 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1779 * in: segment_index
1781 * sal: sal_segment_offset
1783 * uses: bci_align_point
1786 unsigned char FPGM(bci_align_segment) [] =
1789 PUSHB_1,
1790 bci_align_segment,
1791 FDEF,
1793 /* we need the values of `sal_segment_offset + 2*segment_index' */
1794 /* and `sal_segment_offset + 2*segment_index + 1' */
1795 DUP,
1796 ADD,
1797 PUSHB_1,
1798 sal_segment_offset,
1799 ADD,
1800 DUP,
1802 SWAP,
1803 PUSHB_1,
1805 ADD,
1806 RS, /* s: first last */
1808 PUSHB_1,
1810 CINDEX, /* s: first last first */
1811 SUB,
1812 PUSHB_1,
1814 ADD, /* s: first loop_count */
1816 PUSHB_1,
1817 bci_align_point,
1818 LOOPCALL,
1819 /* clean up stack */
1820 POP,
1822 ENDF,
1828 * bci_align_segments
1830 * Align segments to the twilight point in rp0.
1831 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1833 * in: first_segment
1834 * loop_counter (N)
1835 * segment_1
1836 * segment_2
1837 * ...
1838 * segment_N
1840 * uses: bci_align_segment
1843 unsigned char FPGM(bci_align_segments) [] =
1846 PUSHB_1,
1847 bci_align_segments,
1848 FDEF,
1850 PUSHB_1,
1851 bci_align_segment,
1852 CALL,
1854 PUSHB_1,
1855 bci_align_segment,
1856 LOOPCALL,
1858 ENDF,
1864 * bci_scale_contour
1866 * Scale a contour using two points giving the maximum and minimum
1867 * coordinates.
1869 * It expects that no point on the contour is touched.
1871 * in: min_point
1872 * max_point
1874 * CVT: cvtl_scale
1875 * cvtl_0x10000
1878 unsigned char FPGM(bci_scale_contour) [] =
1881 PUSHB_1,
1882 bci_scale_contour,
1883 FDEF,
1885 DUP,
1886 DUP,
1887 GC_orig,
1888 DUP,
1889 DO_SCALE, /* min_pos_new = min_pos * scale */
1890 SWAP,
1891 SUB,
1892 SHPIX,
1894 /* don't scale a single-point contour twice */
1895 SWAP,
1896 DUP,
1897 ROLL,
1898 NEQ,
1900 DUP,
1901 GC_orig,
1902 DUP,
1903 DO_SCALE, /* max_pos_new = max_pos * scale */
1904 SWAP,
1905 SUB,
1906 SHPIX,
1908 ELSE,
1909 POP,
1910 EIF,
1912 ENDF,
1918 * bci_scale_glyph
1920 * Scale a glyph using a list of points (two points per contour, giving
1921 * the maximum and mininum coordinates).
1923 * It expects that no point in the glyph is touched.
1925 * Note that the point numbers are sorted in ascending order;
1926 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1927 * contour without specifying which one is the minimum and maximum.
1929 * in: num_contours (N)
1930 * min_point_1
1931 * max_point_1
1932 * min_point_2
1933 * max_point_2
1934 * ...
1935 * min_point_N
1936 * max_point_N
1938 * CVT: cvtl_is_subglyph
1940 * uses: bci_scale_contour
1943 unsigned char FPGM(bci_scale_glyph) [] =
1946 PUSHB_1,
1947 bci_scale_glyph,
1948 FDEF,
1950 /* only do something if we are not a subglyph */
1951 PUSHB_2,
1953 cvtl_is_subglyph,
1954 RCVT,
1957 /* all our measurements are taken along the y axis */
1958 SVTCA_y,
1960 PUSHB_1,
1962 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1964 PUSHB_1,
1965 bci_scale_contour,
1966 LOOPCALL,
1968 PUSHB_1,
1970 SZP2, /* set zp2 to normal zone 1 */
1971 IUP_y,
1973 ELSE,
1974 CLEAR,
1975 EIF,
1977 ENDF,
1983 * bci_scale_composite_glyph
1985 * The same as `bci_scale_glyph'.
1986 * It also decrements the composite component counter.
1988 * CVT: cvtl_is_subglyph
1990 * uses: bci_decrement_component_counter
1991 * bci_scale_contour
1994 unsigned char FPGM(bci_scale_composite_glyph) [] =
1997 PUSHB_1,
1998 bci_scale_composite_glyph,
1999 FDEF,
2001 PUSHB_1,
2002 bci_decrement_component_counter,
2003 CALL,
2005 /* only do something if we are not a subglyph */
2006 PUSHB_2,
2008 cvtl_is_subglyph,
2009 RCVT,
2012 /* all our measurements are taken along the y axis */
2013 SVTCA_y,
2015 PUSHB_1,
2017 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2019 PUSHB_1,
2020 bci_scale_contour,
2021 LOOPCALL,
2023 PUSHB_1,
2025 SZP2, /* set zp2 to normal zone 1 */
2026 IUP_y,
2028 ELSE,
2029 CLEAR,
2030 EIF,
2032 ENDF,
2038 * bci_shift_contour
2040 * Shift a contour by a given amount.
2042 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2043 * point to the normal zone 1.
2045 * in: contour
2047 * out: contour+1
2050 unsigned char FPGM(bci_shift_contour) [] =
2053 PUSHB_1,
2054 bci_shift_contour,
2055 FDEF,
2057 DUP,
2058 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2060 PUSHB_1,
2062 ADD,
2064 ENDF,
2070 * bci_shift_subglyph
2072 * Shift a subglyph. To be more specific, it corrects the already applied
2073 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2074 * also.
2076 * If this function is called, a point `x' in the subglyph has been scaled
2077 * already (during the hinting of the subglyph itself), and `offset' has
2078 * been applied also:
2080 * x -> x * scale + offset (1)
2082 * However, the offset should be applied first, then the scaling:
2084 * x -> (x + offset) * scale (2)
2086 * Our job is now to transform (1) to (2); a simple calculation shows that
2087 * we have to shift all points of the subglyph by
2089 * offset * scale - offset = offset * (scale - 1)
2091 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2093 * in: offset (in FUnits)
2094 * num_contours
2095 * first_contour
2097 * CVT: cvtl_funits_to_pixels
2098 * cvtl_0x10000
2099 * cvtl_scale
2101 * uses: bci_round
2102 * bci_shift_contour
2105 unsigned char FPGM(bci_shift_subglyph) [] =
2108 PUSHB_1,
2109 bci_shift_subglyph,
2110 FDEF,
2112 SVTCA_y,
2114 PUSHB_1,
2115 cvtl_funits_to_pixels,
2116 RCVT, /* scaling factor FUnits -> pixels */
2117 MUL,
2118 PUSHB_1,
2119 cvtl_0x10000,
2120 RCVT,
2121 DIV,
2123 /* the autohinter always rounds offsets */
2124 PUSHB_1,
2125 bci_round,
2126 CALL, /* offset = round(offset) */
2128 PUSHB_1,
2129 cvtl_scale,
2130 RCVT,
2131 MUL,
2132 PUSHB_1,
2133 cvtl_0x10000,
2134 RCVT,
2135 DIV, /* delta = offset * (scale - 1) */
2137 /* and round again */
2138 PUSHB_1,
2139 bci_round,
2140 CALL, /* offset = round(offset) */
2142 PUSHB_1,
2144 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2146 /* we create twilight point 0 as a reference point, */
2147 /* setting the original position to zero (using `cvtl_temp') */
2148 PUSHB_5,
2151 cvtl_temp,
2152 cvtl_temp,
2154 WCVTP,
2155 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2157 SWAP, /* s: first_contour num_contours 0 delta */
2158 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2160 PUSHB_2,
2161 bci_shift_contour,
2163 SZP2, /* set zp2 to normal zone 1 */
2164 LOOPCALL,
2166 ENDF,
2172 * bci_ip_outer_align_point
2174 * Auxiliary function for `bci_action_ip_before' and
2175 * `bci_action_ip_after'.
2177 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2178 * zone, and both zp1 and zp2 set to normal zone.
2180 * in: point
2182 * sal: sal_i (edge_orig_pos)
2184 * CVT: cvtl_scale
2185 * cvtl_0x10000
2188 unsigned char FPGM(bci_ip_outer_align_point) [] =
2191 PUSHB_1,
2192 bci_ip_outer_align_point,
2193 FDEF,
2195 DUP,
2196 ALIGNRP, /* align `point' with `edge' */
2197 DUP,
2198 GC_orig,
2199 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2201 PUSHB_1,
2202 sal_i,
2204 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2205 SHPIX,
2207 ENDF,
2213 * bci_ip_on_align_points
2215 * Auxiliary function for `bci_action_ip_on'.
2217 * in: edge (in twilight zone)
2218 * loop_counter (N)
2219 * point_1
2220 * point_2
2221 * ...
2222 * point_N
2225 unsigned char FPGM(bci_ip_on_align_points) [] =
2228 PUSHB_1,
2229 bci_ip_on_align_points,
2230 FDEF,
2232 MDAP_noround, /* set rp0 and rp1 to `edge' */
2234 SLOOP,
2235 ALIGNRP,
2237 ENDF,
2243 * bci_ip_between_align_point
2245 * Auxiliary function for `bci_ip_between_align_points'.
2247 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2248 * zone, and both zp1 and zp2 set to normal zone.
2250 * in: point
2252 * sal: sal_i (edge_orig_pos)
2253 * sal_j (stretch_factor)
2255 * CVT: cvtl_scale
2256 * cvtl_0x10000
2259 unsigned char FPGM(bci_ip_between_align_point) [] =
2262 PUSHB_1,
2263 bci_ip_between_align_point,
2264 FDEF,
2266 DUP,
2267 ALIGNRP, /* align `point' with `edge' */
2268 DUP,
2269 GC_orig,
2270 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2272 PUSHB_1,
2273 sal_i,
2275 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2276 PUSHB_1,
2277 sal_j,
2279 MUL, /* s: point delta */
2280 SHPIX,
2282 ENDF,
2288 * bci_ip_between_align_points
2290 * Auxiliary function for `bci_action_ip_between'.
2292 * in: after_edge (in twilight zone)
2293 * before_edge (in twilight zone)
2294 * loop_counter (N)
2295 * point_1
2296 * point_2
2297 * ...
2298 * point_N
2300 * sal: sal_i (before_orig_pos)
2301 * sal_j (stretch_factor)
2303 * uses: bci_ip_between_align_point
2306 unsigned char FPGM(bci_ip_between_align_points) [] =
2309 PUSHB_1,
2310 bci_ip_between_align_points,
2311 FDEF,
2313 PUSHB_2,
2316 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2317 CINDEX,
2318 DUP, /* s: ... before after before before */
2319 MDAP_noround, /* set rp0 and rp1 to `before' */
2320 DUP,
2321 GC_orig, /* s: ... before after before before_orig_pos */
2322 PUSHB_1,
2323 sal_i,
2324 SWAP,
2325 WS, /* sal_i = before_orig_pos */
2326 PUSHB_1,
2328 CINDEX, /* s: ... before after before after */
2329 MD_cur, /* a = after_pos - before_pos */
2330 ROLL,
2331 ROLL,
2332 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2334 DUP,
2335 IF, /* b != 0 ? */
2336 DIV, /* s: a/b */
2337 ELSE,
2338 POP, /* avoid division by zero */
2339 EIF,
2341 PUSHB_1,
2342 sal_j,
2343 SWAP,
2344 WS, /* sal_j = stretch_factor */
2346 PUSHB_3,
2347 bci_ip_between_align_point,
2350 SZP2, /* set zp2 to normal zone 1 */
2351 SZP1, /* set zp1 to normal zone 1 */
2352 LOOPCALL,
2354 ENDF,
2360 * bci_action_ip_before
2362 * Handle `ip_before' data to align points located before the first edge.
2364 * in: first_edge (in twilight zone)
2365 * loop_counter (N)
2366 * point_1
2367 * point_2
2368 * ...
2369 * point_N
2371 * sal: sal_i (first_edge_orig_pos)
2373 * uses: bci_ip_outer_align_point
2376 unsigned char FPGM(bci_action_ip_before) [] =
2379 PUSHB_1,
2380 bci_action_ip_before,
2381 FDEF,
2383 PUSHB_1,
2385 SZP2, /* set zp2 to twilight zone 0 */
2387 DUP,
2388 GC_orig,
2389 PUSHB_1,
2390 sal_i,
2391 SWAP,
2392 WS, /* sal_i = first_edge_orig_pos */
2394 PUSHB_3,
2398 SZP2, /* set zp2 to normal zone 1 */
2399 SZP1, /* set zp1 to normal zone 1 */
2400 SZP0, /* set zp0 to twilight zone 0 */
2402 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2404 PUSHB_1,
2405 bci_ip_outer_align_point,
2406 LOOPCALL,
2408 ENDF,
2414 * bci_action_ip_after
2416 * Handle `ip_after' data to align points located after the last edge.
2418 * in: last_edge (in twilight zone)
2419 * loop_counter (N)
2420 * point_1
2421 * point_2
2422 * ...
2423 * point_N
2425 * sal: sal_i (last_edge_orig_pos)
2427 * uses: bci_ip_outer_align_point
2430 unsigned char FPGM(bci_action_ip_after) [] =
2433 PUSHB_1,
2434 bci_action_ip_after,
2435 FDEF,
2437 PUSHB_1,
2439 SZP2, /* set zp2 to twilight zone 0 */
2441 DUP,
2442 GC_orig,
2443 PUSHB_1,
2444 sal_i,
2445 SWAP,
2446 WS, /* sal_i = last_edge_orig_pos */
2448 PUSHB_3,
2452 SZP2, /* set zp2 to normal zone 1 */
2453 SZP1, /* set zp1 to normal zone 1 */
2454 SZP0, /* set zp0 to twilight zone 0 */
2456 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2458 PUSHB_1,
2459 bci_ip_outer_align_point,
2460 LOOPCALL,
2462 ENDF,
2468 * bci_action_ip_on
2470 * Handle `ip_on' data to align points located on an edge coordinate (but
2471 * not part of an edge).
2473 * in: loop_counter (M)
2474 * edge_1 (in twilight zone)
2475 * loop_counter (N_1)
2476 * point_1
2477 * point_2
2478 * ...
2479 * point_N_1
2480 * edge_2 (in twilight zone)
2481 * loop_counter (N_2)
2482 * point_1
2483 * point_2
2484 * ...
2485 * point_N_2
2486 * ...
2487 * edge_M (in twilight zone)
2488 * loop_counter (N_M)
2489 * point_1
2490 * point_2
2491 * ...
2492 * point_N_M
2494 * uses: bci_ip_on_align_points
2497 unsigned char FPGM(bci_action_ip_on) [] =
2500 PUSHB_1,
2501 bci_action_ip_on,
2502 FDEF,
2504 PUSHB_2,
2507 SZP1, /* set zp1 to normal zone 1 */
2508 SZP0, /* set zp0 to twilight zone 0 */
2510 PUSHB_1,
2511 bci_ip_on_align_points,
2512 LOOPCALL,
2514 ENDF,
2520 * bci_action_ip_between
2522 * Handle `ip_between' data to align points located between two edges.
2524 * in: loop_counter (M)
2525 * before_edge_1 (in twilight zone)
2526 * after_edge_1 (in twilight zone)
2527 * loop_counter (N_1)
2528 * point_1
2529 * point_2
2530 * ...
2531 * point_N_1
2532 * before_edge_2 (in twilight zone)
2533 * after_edge_2 (in twilight zone)
2534 * loop_counter (N_2)
2535 * point_1
2536 * point_2
2537 * ...
2538 * point_N_2
2539 * ...
2540 * before_edge_M (in twilight zone)
2541 * after_edge_M (in twilight zone)
2542 * loop_counter (N_M)
2543 * point_1
2544 * point_2
2545 * ...
2546 * point_N_M
2548 * uses: bci_ip_between_align_points
2551 unsigned char FPGM(bci_action_ip_between) [] =
2554 PUSHB_1,
2555 bci_action_ip_between,
2556 FDEF,
2558 PUSHB_1,
2559 bci_ip_between_align_points,
2560 LOOPCALL,
2562 ENDF,
2568 * bci_adjust_common
2570 * Common code for bci_action_adjust routines.
2572 * uses: func[cvtl_stem_width_function]
2575 unsigned char FPGM(bci_adjust_common) [] =
2578 PUSHB_1,
2579 bci_adjust_common,
2580 FDEF,
2582 PUSHB_1,
2584 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2586 PUSHB_1,
2588 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2589 PUSHB_1,
2591 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2592 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2594 PUSHB_1,
2595 cvtl_stem_width_function,
2596 RCVT,
2597 CALL,
2598 NEG, /* s: [...] edge2 edge -cur_len */
2600 ROLL, /* s: [...] edge -cur_len edge2 */
2601 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2602 SWAP,
2603 DUP,
2604 DUP, /* s: [...] -cur_len edge edge edge */
2605 ALIGNRP, /* align `edge' with `edge2' */
2606 ROLL,
2607 SHPIX, /* shift `edge' by -cur_len */
2609 ENDF,
2615 * bci_adjust_bound
2617 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2618 * edge of the stem has already been moved, then moving it again if
2619 * necessary to stay bound.
2621 * in: edge2_is_serif
2622 * edge_is_round
2623 * edge_point (in twilight zone)
2624 * edge2_point (in twilight zone)
2625 * edge[-1] (in twilight zone)
2626 * ... stuff for bci_align_segments (edge) ...
2628 * uses: bci_adjust_common
2629 * bci_align_segments
2632 unsigned char FPGM(bci_adjust_bound) [] =
2635 PUSHB_1,
2636 bci_adjust_bound,
2637 FDEF,
2639 PUSHB_1,
2640 bci_adjust_common,
2641 CALL,
2643 SWAP, /* s: edge edge[-1] */
2644 DUP,
2645 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2646 GC_cur,
2647 PUSHB_1,
2649 CINDEX,
2650 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2651 GT, /* edge_pos < edge[-1]_pos */
2653 DUP,
2654 ALIGNRP, /* align `edge' to `edge[-1]' */
2655 EIF,
2657 MDAP_noround, /* set rp0 and rp1 to `edge' */
2659 PUSHB_2,
2660 bci_align_segments,
2662 SZP1, /* set zp1 to normal zone 1 */
2663 CALL,
2665 ENDF,
2671 * bci_action_adjust_bound
2672 * bci_action_adjust_bound_serif
2673 * bci_action_adjust_bound_round
2674 * bci_action_adjust_bound_round_serif
2676 * Higher-level routines for calling `bci_adjust_bound'.
2679 unsigned char FPGM(bci_action_adjust_bound) [] =
2682 PUSHB_1,
2683 bci_action_adjust_bound,
2684 FDEF,
2686 PUSHB_3,
2689 bci_adjust_bound,
2690 CALL,
2692 ENDF,
2696 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2699 PUSHB_1,
2700 bci_action_adjust_bound_serif,
2701 FDEF,
2703 PUSHB_3,
2706 bci_adjust_bound,
2707 CALL,
2709 ENDF,
2713 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2716 PUSHB_1,
2717 bci_action_adjust_bound_round,
2718 FDEF,
2720 PUSHB_3,
2723 bci_adjust_bound,
2724 CALL,
2726 ENDF,
2730 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2733 PUSHB_1,
2734 bci_action_adjust_bound_round_serif,
2735 FDEF,
2737 PUSHB_3,
2740 bci_adjust_bound,
2741 CALL,
2743 ENDF,
2749 * bci_adjust
2751 * Handle the ADJUST action to align an edge of a stem if the other edge
2752 * of the stem has already been moved.
2754 * in: edge2_is_serif
2755 * edge_is_round
2756 * edge_point (in twilight zone)
2757 * edge2_point (in twilight zone)
2758 * ... stuff for bci_align_segments (edge) ...
2760 * uses: bci_adjust_common
2761 * bci_align_segments
2764 unsigned char FPGM(bci_adjust) [] =
2767 PUSHB_1,
2768 bci_adjust,
2769 FDEF,
2771 PUSHB_1,
2772 bci_adjust_common,
2773 CALL,
2775 MDAP_noround, /* set rp0 and rp1 to `edge' */
2777 PUSHB_2,
2778 bci_align_segments,
2780 SZP1, /* set zp1 to normal zone 1 */
2781 CALL,
2783 ENDF,
2789 * bci_action_adjust
2790 * bci_action_adjust_serif
2791 * bci_action_adjust_round
2792 * bci_action_adjust_round_serif
2794 * Higher-level routines for calling `bci_adjust'.
2797 unsigned char FPGM(bci_action_adjust) [] =
2800 PUSHB_1,
2801 bci_action_adjust,
2802 FDEF,
2804 PUSHB_3,
2807 bci_adjust,
2808 CALL,
2810 ENDF,
2814 unsigned char FPGM(bci_action_adjust_serif) [] =
2817 PUSHB_1,
2818 bci_action_adjust_serif,
2819 FDEF,
2821 PUSHB_3,
2824 bci_adjust,
2825 CALL,
2827 ENDF,
2831 unsigned char FPGM(bci_action_adjust_round) [] =
2834 PUSHB_1,
2835 bci_action_adjust_round,
2836 FDEF,
2838 PUSHB_3,
2841 bci_adjust,
2842 CALL,
2844 ENDF,
2848 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2851 PUSHB_1,
2852 bci_action_adjust_round_serif,
2853 FDEF,
2855 PUSHB_3,
2858 bci_adjust,
2859 CALL,
2861 ENDF,
2867 * bci_stem_common
2869 * Common code for bci_action_stem routines.
2871 * sal: sal_anchor
2872 * sal_temp1
2873 * sal_temp2
2874 * sal_temp3
2876 * uses: func[cvtl_stem_width_function]
2877 * bci_round
2880 #undef sal_u_off
2881 #define sal_u_off sal_temp1
2882 #undef sal_d_off
2883 #define sal_d_off sal_temp2
2884 #undef sal_org_len
2885 #define sal_org_len sal_temp3
2886 #undef sal_edge2
2887 #define sal_edge2 sal_temp3
2889 unsigned char FPGM(bci_stem_common) [] =
2892 PUSHB_1,
2893 bci_stem_common,
2894 FDEF,
2896 PUSHB_1,
2898 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2900 PUSHB_1,
2902 CINDEX,
2903 PUSHB_1,
2905 CINDEX,
2906 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2907 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2909 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2910 DUP,
2911 PUSHB_1,
2912 sal_org_len,
2913 SWAP,
2916 PUSHB_1,
2917 cvtl_stem_width_function,
2918 RCVT,
2919 CALL, /* s: [...] edge2 edge cur_len */
2921 DUP,
2922 PUSHB_1,
2924 LT, /* cur_len < 96 */
2926 DUP,
2927 PUSHB_1,
2929 LTEQ, /* cur_len <= 64 */
2931 PUSHB_4,
2932 sal_u_off,
2934 sal_d_off,
2937 ELSE,
2938 PUSHB_4,
2939 sal_u_off,
2941 sal_d_off,
2943 EIF,
2947 SWAP, /* s: [...] edge2 cur_len edge */
2948 DUP,
2949 PUSHB_1,
2950 sal_anchor,
2952 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2953 ROLL,
2954 SWAP,
2955 MD_orig_ZP2_0,
2956 SWAP,
2957 GC_cur,
2958 ADD, /* s: [...] edge2 cur_len edge org_pos */
2959 PUSHB_1,
2960 sal_org_len,
2962 PUSHB_1,
2963 2*64,
2964 DIV,
2965 ADD, /* s: [...] edge2 cur_len edge org_center */
2967 DUP,
2968 PUSHB_1,
2969 bci_round,
2970 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2972 DUP,
2973 ROLL,
2974 ROLL,
2975 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2977 DUP,
2978 PUSHB_1,
2979 sal_u_off,
2981 ADD,
2982 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2984 SWAP,
2985 PUSHB_1,
2986 sal_d_off,
2988 SUB,
2989 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2991 LT, /* delta1 < delta2 */
2993 PUSHB_1,
2994 sal_u_off,
2996 SUB, /* cur_pos1 = cur_pos1 - u_off */
2998 ELSE,
2999 PUSHB_1,
3000 sal_d_off,
3002 ADD, /* cur_pos1 = cur_pos1 + d_off */
3003 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3005 PUSHB_1,
3007 CINDEX,
3008 PUSHB_1,
3009 2*64,
3010 DIV,
3011 SUB, /* arg = cur_pos1 - cur_len/2 */
3013 SWAP, /* s: [...] edge2 cur_len arg edge */
3014 DUP,
3015 DUP,
3016 PUSHB_1,
3018 MINDEX,
3019 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3020 GC_cur,
3021 SUB,
3022 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3024 ELSE,
3025 SWAP, /* s: [...] edge2 cur_len edge */
3026 PUSHB_1,
3027 sal_anchor,
3029 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3030 PUSHB_1,
3032 CINDEX,
3033 PUSHB_1,
3034 sal_anchor,
3036 MD_orig_ZP2_0,
3037 ADD, /* s: [...] edge2 cur_len edge org_pos */
3039 DUP,
3040 PUSHB_1,
3041 sal_org_len,
3043 PUSHB_1,
3044 2*64,
3045 DIV,
3046 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3048 SWAP,
3049 DUP,
3050 PUSHB_1,
3051 bci_round,
3052 CALL, /* cur_pos1 = ROUND(org_pos) */
3053 SWAP,
3054 PUSHB_1,
3055 sal_org_len,
3057 ADD,
3058 PUSHB_1,
3059 bci_round,
3060 CALL,
3061 PUSHB_1,
3063 CINDEX,
3064 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3066 PUSHB_1,
3068 CINDEX,
3069 PUSHB_1,
3070 2*64,
3071 DIV,
3072 PUSHB_1,
3074 MINDEX,
3075 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3077 DUP,
3078 PUSHB_1,
3080 CINDEX,
3081 ADD,
3082 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3083 SWAP,
3084 PUSHB_1,
3086 CINDEX,
3087 ADD,
3088 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3089 LT, /* delta1 < delta2 */
3091 POP, /* arg = cur_pos1 */
3093 ELSE,
3094 SWAP,
3095 POP, /* arg = cur_pos2 */
3096 EIF, /* s: [...] edge2 cur_len edge arg */
3097 SWAP,
3098 DUP,
3099 DUP,
3100 PUSHB_1,
3102 MINDEX,
3103 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3104 GC_cur,
3105 SUB,
3106 SHPIX, /* edge = arg */
3107 EIF, /* s: [...] edge2 cur_len edge */
3109 ENDF,
3115 * bci_stem_bound
3117 * Handle the STEM action to align two edges of a stem, then moving one
3118 * edge again if necessary to stay bound.
3120 * The code after computing `cur_len' to shift `edge' and `edge2'
3121 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3123 * if cur_len < 96:
3124 * if cur_len < = 64:
3125 * u_off = 32
3126 * d_off = 32
3127 * else:
3128 * u_off = 38
3129 * d_off = 26
3131 * org_pos = anchor + (edge_orig - anchor_orig);
3132 * org_center = org_pos + org_len / 2;
3134 * cur_pos1 = ROUND(org_center)
3135 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3136 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3137 * if (delta1 < delta2):
3138 * cur_pos1 = cur_pos1 - u_off
3139 * else:
3140 * cur_pos1 = cur_pos1 + d_off
3142 * edge = cur_pos1 - cur_len / 2
3144 * else:
3145 * org_pos = anchor + (edge_orig - anchor_orig)
3146 * org_center = org_pos + org_len / 2;
3148 * cur_pos1 = ROUND(org_pos)
3149 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3150 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3151 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3153 * if (delta1 < delta2):
3154 * edge = cur_pos1
3155 * else:
3156 * edge = cur_pos2
3158 * edge2 = edge + cur_len
3160 * in: edge2_is_serif
3161 * edge_is_round
3162 * edge_point (in twilight zone)
3163 * edge2_point (in twilight zone)
3164 * edge[-1] (in twilight zone)
3165 * ... stuff for bci_align_segments (edge) ...
3166 * ... stuff for bci_align_segments (edge2)...
3168 * sal: sal_anchor
3169 * sal_temp1
3170 * sal_temp2
3171 * sal_temp3
3173 * uses: bci_stem_common
3174 * bci_align_segments
3177 unsigned char FPGM(bci_stem_bound) [] =
3180 PUSHB_1,
3181 bci_stem_bound,
3182 FDEF,
3184 PUSHB_1,
3185 bci_stem_common,
3186 CALL,
3188 ROLL, /* s: edge[-1] cur_len edge edge2 */
3189 DUP,
3190 DUP,
3191 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3192 PUSHB_1,
3193 sal_edge2,
3194 SWAP,
3195 WS, /* s: edge[-1] cur_len edge edge2 */
3196 ROLL,
3197 SHPIX, /* edge2 = edge + cur_len */
3199 SWAP, /* s: edge edge[-1] */
3200 DUP,
3201 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3202 GC_cur,
3203 PUSHB_1,
3205 CINDEX,
3206 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3207 GT, /* edge_pos < edge[-1]_pos */
3209 DUP,
3210 ALIGNRP, /* align `edge' to `edge[-1]' */
3211 EIF,
3213 MDAP_noround, /* set rp0 and rp1 to `edge' */
3215 PUSHB_2,
3216 bci_align_segments,
3218 SZP1, /* set zp1 to normal zone 1 */
3219 CALL,
3221 PUSHB_1,
3222 sal_edge2,
3224 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3226 PUSHB_1,
3227 bci_align_segments,
3228 CALL,
3230 ENDF,
3236 * bci_action_stem_bound
3237 * bci_action_stem_bound_serif
3238 * bci_action_stem_bound_round
3239 * bci_action_stem_bound_round_serif
3241 * Higher-level routines for calling `bci_stem_bound'.
3244 unsigned char FPGM(bci_action_stem_bound) [] =
3247 PUSHB_1,
3248 bci_action_stem_bound,
3249 FDEF,
3251 PUSHB_3,
3254 bci_stem_bound,
3255 CALL,
3257 ENDF,
3261 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3264 PUSHB_1,
3265 bci_action_stem_bound_serif,
3266 FDEF,
3268 PUSHB_3,
3271 bci_stem_bound,
3272 CALL,
3274 ENDF,
3278 unsigned char FPGM(bci_action_stem_bound_round) [] =
3281 PUSHB_1,
3282 bci_action_stem_bound_round,
3283 FDEF,
3285 PUSHB_3,
3288 bci_stem_bound,
3289 CALL,
3291 ENDF,
3295 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3298 PUSHB_1,
3299 bci_action_stem_bound_round_serif,
3300 FDEF,
3302 PUSHB_3,
3305 bci_stem_bound,
3306 CALL,
3308 ENDF,
3314 * bci_stem
3316 * Handle the STEM action to align two edges of a stem.
3318 * See `bci_stem_bound' for more details.
3320 * in: edge2_is_serif
3321 * edge_is_round
3322 * edge_point (in twilight zone)
3323 * edge2_point (in twilight zone)
3324 * ... stuff for bci_align_segments (edge) ...
3325 * ... stuff for bci_align_segments (edge2)...
3327 * sal: sal_anchor
3328 * sal_temp1
3329 * sal_temp2
3330 * sal_temp3
3332 * uses: bci_stem_common
3333 * bci_align_segments
3336 unsigned char FPGM(bci_stem) [] =
3339 PUSHB_1,
3340 bci_stem,
3341 FDEF,
3343 PUSHB_1,
3344 bci_stem_common,
3345 CALL,
3347 POP,
3348 SWAP, /* s: cur_len edge2 */
3349 DUP,
3350 DUP,
3351 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3352 PUSHB_1,
3353 sal_edge2,
3354 SWAP,
3355 WS, /* s: cur_len edge2 */
3356 SWAP,
3357 SHPIX, /* edge2 = edge + cur_len */
3359 PUSHB_2,
3360 bci_align_segments,
3362 SZP1, /* set zp1 to normal zone 1 */
3363 CALL,
3365 PUSHB_1,
3366 sal_edge2,
3368 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3370 PUSHB_1,
3371 bci_align_segments,
3372 CALL,
3373 ENDF,
3379 * bci_action_stem
3380 * bci_action_stem_serif
3381 * bci_action_stem_round
3382 * bci_action_stem_round_serif
3384 * Higher-level routines for calling `bci_stem'.
3387 unsigned char FPGM(bci_action_stem) [] =
3390 PUSHB_1,
3391 bci_action_stem,
3392 FDEF,
3394 PUSHB_3,
3397 bci_stem,
3398 CALL,
3400 ENDF,
3404 unsigned char FPGM(bci_action_stem_serif) [] =
3407 PUSHB_1,
3408 bci_action_stem_serif,
3409 FDEF,
3411 PUSHB_3,
3414 bci_stem,
3415 CALL,
3417 ENDF,
3421 unsigned char FPGM(bci_action_stem_round) [] =
3424 PUSHB_1,
3425 bci_action_stem_round,
3426 FDEF,
3428 PUSHB_3,
3431 bci_stem,
3432 CALL,
3434 ENDF,
3438 unsigned char FPGM(bci_action_stem_round_serif) [] =
3441 PUSHB_1,
3442 bci_action_stem_round_serif,
3443 FDEF,
3445 PUSHB_3,
3448 bci_stem,
3449 CALL,
3451 ENDF,
3457 * bci_link
3459 * Handle the LINK action to link an edge to another one.
3461 * in: stem_is_serif
3462 * base_is_round
3463 * base_point (in twilight zone)
3464 * stem_point (in twilight zone)
3465 * ... stuff for bci_align_segments (base) ...
3467 * uses: func[cvtl_stem_width_function]
3468 * bci_align_segments
3471 unsigned char FPGM(bci_link) [] =
3474 PUSHB_1,
3475 bci_link,
3476 FDEF,
3478 PUSHB_1,
3480 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3482 PUSHB_1,
3484 CINDEX,
3485 PUSHB_1,
3487 MINDEX,
3488 DUP, /* s: stem is_round is_serif stem base base */
3489 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3491 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3493 PUSHB_1,
3494 cvtl_stem_width_function,
3495 RCVT,
3496 CALL, /* s: stem new_dist */
3498 SWAP,
3499 DUP,
3500 ALIGNRP, /* align `stem_point' with `base_point' */
3501 DUP,
3502 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3503 SWAP,
3504 SHPIX, /* stem_point = base_point + new_dist */
3506 PUSHB_2,
3507 bci_align_segments,
3509 SZP1, /* set zp1 to normal zone 1 */
3510 CALL,
3512 ENDF,
3518 * bci_action_link
3519 * bci_action_link_serif
3520 * bci_action_link_round
3521 * bci_action_link_round_serif
3523 * Higher-level routines for calling `bci_link'.
3526 unsigned char FPGM(bci_action_link) [] =
3529 PUSHB_1,
3530 bci_action_link,
3531 FDEF,
3533 PUSHB_3,
3536 bci_link,
3537 CALL,
3539 ENDF,
3543 unsigned char FPGM(bci_action_link_serif) [] =
3546 PUSHB_1,
3547 bci_action_link_serif,
3548 FDEF,
3550 PUSHB_3,
3553 bci_link,
3554 CALL,
3556 ENDF,
3560 unsigned char FPGM(bci_action_link_round) [] =
3563 PUSHB_1,
3564 bci_action_link_round,
3565 FDEF,
3567 PUSHB_3,
3570 bci_link,
3571 CALL,
3573 ENDF,
3577 unsigned char FPGM(bci_action_link_round_serif) [] =
3580 PUSHB_1,
3581 bci_action_link_round_serif,
3582 FDEF,
3584 PUSHB_3,
3587 bci_link,
3588 CALL,
3590 ENDF,
3596 * bci_anchor
3598 * Handle the ANCHOR action to align two edges
3599 * and to set the edge anchor.
3601 * The code after computing `cur_len' to shift `edge' and `edge2'
3602 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3604 * if cur_len < 96:
3605 * if cur_len < = 64:
3606 * u_off = 32
3607 * d_off = 32
3608 * else:
3609 * u_off = 38
3610 * d_off = 26
3612 * org_center = edge_orig + org_len / 2
3613 * cur_pos1 = ROUND(org_center)
3615 * error1 = ABS(org_center - (cur_pos1 - u_off))
3616 * error2 = ABS(org_center - (cur_pos1 + d_off))
3617 * if (error1 < error2):
3618 * cur_pos1 = cur_pos1 - u_off
3619 * else:
3620 * cur_pos1 = cur_pos1 + d_off
3622 * edge = cur_pos1 - cur_len / 2
3623 * edge2 = edge + cur_len
3625 * else:
3626 * edge = ROUND(edge_orig)
3628 * in: edge2_is_serif
3629 * edge_is_round
3630 * edge_point (in twilight zone)
3631 * edge2_point (in twilight zone)
3632 * ... stuff for bci_align_segments (edge) ...
3634 * sal: sal_anchor
3635 * sal_temp1
3636 * sal_temp2
3637 * sal_temp3
3639 * uses: func[cvtl_stem_width_function]
3640 * bci_round
3641 * bci_align_segments
3644 #undef sal_u_off
3645 #define sal_u_off sal_temp1
3646 #undef sal_d_off
3647 #define sal_d_off sal_temp2
3648 #undef sal_org_len
3649 #define sal_org_len sal_temp3
3651 unsigned char FPGM(bci_anchor) [] =
3654 PUSHB_1,
3655 bci_anchor,
3656 FDEF,
3658 /* store anchor point number in `sal_anchor' */
3659 PUSHB_2,
3660 sal_anchor,
3662 CINDEX,
3663 WS, /* sal_anchor = edge_point */
3665 PUSHB_1,
3667 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3669 PUSHB_1,
3671 CINDEX,
3672 PUSHB_1,
3674 CINDEX,
3675 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3676 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3678 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3679 DUP,
3680 PUSHB_1,
3681 sal_org_len,
3682 SWAP,
3685 PUSHB_1,
3686 cvtl_stem_width_function,
3687 RCVT,
3688 CALL, /* s: edge2 edge cur_len */
3690 DUP,
3691 PUSHB_1,
3693 LT, /* cur_len < 96 */
3695 DUP,
3696 PUSHB_1,
3698 LTEQ, /* cur_len <= 64 */
3700 PUSHB_4,
3701 sal_u_off,
3703 sal_d_off,
3706 ELSE,
3707 PUSHB_4,
3708 sal_u_off,
3710 sal_d_off,
3712 EIF,
3716 SWAP, /* s: edge2 cur_len edge */
3717 DUP, /* s: edge2 cur_len edge edge */
3719 GC_orig,
3720 PUSHB_1,
3721 sal_org_len,
3723 PUSHB_1,
3724 2*64,
3725 DIV,
3726 ADD, /* s: edge2 cur_len edge org_center */
3728 DUP,
3729 PUSHB_1,
3730 bci_round,
3731 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3733 DUP,
3734 ROLL,
3735 ROLL,
3736 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3738 DUP,
3739 PUSHB_1,
3740 sal_u_off,
3742 ADD,
3743 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3745 SWAP,
3746 PUSHB_1,
3747 sal_d_off,
3749 SUB,
3750 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3752 LT, /* error1 < error2 */
3754 PUSHB_1,
3755 sal_u_off,
3757 SUB, /* cur_pos1 = cur_pos1 - u_off */
3759 ELSE,
3760 PUSHB_1,
3761 sal_d_off,
3763 ADD, /* cur_pos1 = cur_pos1 + d_off */
3764 EIF, /* s: edge2 cur_len edge cur_pos1 */
3766 PUSHB_1,
3768 CINDEX,
3769 PUSHB_1,
3770 2*64,
3771 DIV,
3772 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3774 PUSHB_1,
3776 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3777 GC_cur,
3778 SUB,
3779 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3781 SWAP, /* s: cur_len edge2 */
3782 DUP,
3783 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3784 SWAP,
3785 SHPIX, /* edge2 = edge1 + cur_len */
3787 ELSE,
3788 POP, /* s: edge2 edge */
3789 DUP,
3790 DUP,
3791 GC_cur,
3792 SWAP,
3793 GC_orig,
3794 PUSHB_1,
3795 bci_round,
3796 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3797 SWAP,
3798 SUB,
3799 SHPIX, /* edge = round(edge_orig) */
3801 /* clean up stack */
3802 POP,
3803 EIF,
3805 PUSHB_2,
3806 bci_align_segments,
3808 SZP1, /* set zp1 to normal zone 1 */
3809 CALL,
3811 ENDF,
3817 * bci_action_anchor
3818 * bci_action_anchor_serif
3819 * bci_action_anchor_round
3820 * bci_action_anchor_round_serif
3822 * Higher-level routines for calling `bci_anchor'.
3825 unsigned char FPGM(bci_action_anchor) [] =
3828 PUSHB_1,
3829 bci_action_anchor,
3830 FDEF,
3832 PUSHB_3,
3835 bci_anchor,
3836 CALL,
3838 ENDF,
3842 unsigned char FPGM(bci_action_anchor_serif) [] =
3845 PUSHB_1,
3846 bci_action_anchor_serif,
3847 FDEF,
3849 PUSHB_3,
3852 bci_anchor,
3853 CALL,
3855 ENDF,
3859 unsigned char FPGM(bci_action_anchor_round) [] =
3862 PUSHB_1,
3863 bci_action_anchor_round,
3864 FDEF,
3866 PUSHB_3,
3869 bci_anchor,
3870 CALL,
3872 ENDF,
3876 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3879 PUSHB_1,
3880 bci_action_anchor_round_serif,
3881 FDEF,
3883 PUSHB_3,
3886 bci_anchor,
3887 CALL,
3889 ENDF,
3895 * bci_action_blue_anchor
3897 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3898 * and to set the edge anchor.
3900 * in: anchor_point (in twilight zone)
3901 * blue_cvt_idx
3902 * edge_point (in twilight zone)
3903 * ... stuff for bci_align_segments (edge) ...
3905 * sal: sal_anchor
3907 * uses: bci_action_blue
3910 unsigned char FPGM(bci_action_blue_anchor) [] =
3913 PUSHB_1,
3914 bci_action_blue_anchor,
3915 FDEF,
3917 /* store anchor point number in `sal_anchor' */
3918 PUSHB_1,
3919 sal_anchor,
3920 SWAP,
3923 PUSHB_1,
3924 bci_action_blue,
3925 CALL,
3927 ENDF,
3933 * bci_action_blue
3935 * Handle the BLUE action to align an edge with a blue zone.
3937 * in: blue_cvt_idx
3938 * edge_point (in twilight zone)
3939 * ... stuff for bci_align_segments (edge) ...
3941 * uses: bci_align_segments
3944 unsigned char FPGM(bci_action_blue) [] =
3947 PUSHB_1,
3948 bci_action_blue,
3949 FDEF,
3951 PUSHB_1,
3953 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3955 /* move `edge_point' to `blue_cvt_idx' position; */
3956 /* note that we can't use MIAP since this would modify */
3957 /* the twilight point's original coordinates also */
3958 RCVT,
3959 SWAP,
3960 DUP,
3961 MDAP_noround, /* set rp0 and rp1 to `edge' */
3962 DUP,
3963 GC_cur, /* s: new_pos edge edge_pos */
3964 ROLL,
3965 SWAP,
3966 SUB, /* s: edge (new_pos - edge_pos) */
3967 SHPIX,
3969 PUSHB_2,
3970 bci_align_segments,
3972 SZP1, /* set zp1 to normal zone 1 */
3973 CALL,
3975 ENDF,
3981 * bci_serif_common
3983 * Common code for bci_action_serif routines.
3986 unsigned char FPGM(bci_serif_common) [] =
3989 PUSHB_1,
3990 bci_serif_common,
3991 FDEF,
3993 PUSHB_1,
3995 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3997 DUP,
3998 DUP,
3999 DUP,
4000 PUSHB_1,
4002 MINDEX, /* s: [...] serif serif serif serif base */
4003 DUP,
4004 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4005 MD_orig_ZP2_0,
4006 SWAP,
4007 ALIGNRP, /* align `serif_point' with `base_point' */
4008 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4010 ENDF,
4016 * bci_lower_bound
4018 * Move an edge if necessary to stay within a lower bound.
4020 * in: edge
4021 * bound
4023 * uses: bci_align_segments
4026 unsigned char FPGM(bci_lower_bound) [] =
4029 PUSHB_1,
4030 bci_lower_bound,
4031 FDEF,
4033 SWAP, /* s: edge bound */
4034 DUP,
4035 MDAP_noround, /* set rp0 and rp1 to `bound' */
4036 GC_cur,
4037 PUSHB_1,
4039 CINDEX,
4040 GC_cur, /* s: edge bound_pos edge_pos */
4041 GT, /* edge_pos < bound_pos */
4043 DUP,
4044 ALIGNRP, /* align `edge' to `bound' */
4045 EIF,
4047 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4049 PUSHB_2,
4050 bci_align_segments,
4052 SZP1, /* set zp1 to normal zone 1 */
4053 CALL,
4055 ENDF,
4061 * bci_upper_bound
4063 * Move an edge if necessary to stay within an upper bound.
4065 * in: edge
4066 * bound
4068 * uses: bci_align_segments
4071 unsigned char FPGM(bci_upper_bound) [] =
4074 PUSHB_1,
4075 bci_upper_bound,
4076 FDEF,
4078 SWAP, /* s: edge bound */
4079 DUP,
4080 MDAP_noround, /* set rp0 and rp1 to `bound' */
4081 GC_cur,
4082 PUSHB_1,
4084 CINDEX,
4085 GC_cur, /* s: edge bound_pos edge_pos */
4086 LT, /* edge_pos > bound_pos */
4088 DUP,
4089 ALIGNRP, /* align `edge' to `bound' */
4090 EIF,
4092 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4094 PUSHB_2,
4095 bci_align_segments,
4097 SZP1, /* set zp1 to normal zone 1 */
4098 CALL,
4100 ENDF,
4106 * bci_upper_lower_bound
4108 * Move an edge if necessary to stay within a lower and lower bound.
4110 * in: edge
4111 * lower
4112 * upper
4114 * uses: bci_align_segments
4117 unsigned char FPGM(bci_upper_lower_bound) [] =
4120 PUSHB_1,
4121 bci_upper_lower_bound,
4122 FDEF,
4124 SWAP, /* s: upper serif lower */
4125 DUP,
4126 MDAP_noround, /* set rp0 and rp1 to `lower' */
4127 GC_cur,
4128 PUSHB_1,
4130 CINDEX,
4131 GC_cur, /* s: upper serif lower_pos serif_pos */
4132 GT, /* serif_pos < lower_pos */
4134 DUP,
4135 ALIGNRP, /* align `serif' to `lower' */
4136 EIF,
4138 SWAP, /* s: serif upper */
4139 DUP,
4140 MDAP_noround, /* set rp0 and rp1 to `upper' */
4141 GC_cur,
4142 PUSHB_1,
4144 CINDEX,
4145 GC_cur, /* s: serif upper_pos serif_pos */
4146 LT, /* serif_pos > upper_pos */
4148 DUP,
4149 ALIGNRP, /* align `serif' to `upper' */
4150 EIF,
4152 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4154 PUSHB_2,
4155 bci_align_segments,
4157 SZP1, /* set zp1 to normal zone 1 */
4158 CALL,
4160 ENDF,
4166 * bci_action_serif
4168 * Handle the SERIF action to align a serif with its base.
4170 * in: serif_point (in twilight zone)
4171 * base_point (in twilight zone)
4172 * ... stuff for bci_align_segments (serif) ...
4174 * uses: bci_serif_common
4175 * bci_align_segments
4178 unsigned char FPGM(bci_action_serif) [] =
4181 PUSHB_1,
4182 bci_action_serif,
4183 FDEF,
4185 PUSHB_1,
4186 bci_serif_common,
4187 CALL,
4189 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4191 PUSHB_2,
4192 bci_align_segments,
4194 SZP1, /* set zp1 to normal zone 1 */
4195 CALL,
4197 ENDF,
4203 * bci_action_serif_lower_bound
4205 * Handle the SERIF action to align a serif with its base, then moving it
4206 * again if necessary to stay within a lower bound.
4208 * in: serif_point (in twilight zone)
4209 * base_point (in twilight zone)
4210 * edge[-1] (in twilight zone)
4211 * ... stuff for bci_align_segments (serif) ...
4213 * uses: bci_serif_common
4214 * bci_lower_bound
4217 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4220 PUSHB_1,
4221 bci_action_serif_lower_bound,
4222 FDEF,
4224 PUSHB_1,
4225 bci_serif_common,
4226 CALL,
4228 PUSHB_1,
4229 bci_lower_bound,
4230 CALL,
4232 ENDF,
4238 * bci_action_serif_upper_bound
4240 * Handle the SERIF action to align a serif with its base, then moving it
4241 * again if necessary to stay within an upper bound.
4243 * in: serif_point (in twilight zone)
4244 * base_point (in twilight zone)
4245 * edge[1] (in twilight zone)
4246 * ... stuff for bci_align_segments (serif) ...
4248 * uses: bci_serif_common
4249 * bci_upper_bound
4252 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4255 PUSHB_1,
4256 bci_action_serif_upper_bound,
4257 FDEF,
4259 PUSHB_1,
4260 bci_serif_common,
4261 CALL,
4263 PUSHB_1,
4264 bci_upper_bound,
4265 CALL,
4267 ENDF,
4273 * bci_action_serif_upper_lower_bound
4275 * Handle the SERIF action to align a serif with its base, then moving it
4276 * again if necessary to stay within a lower and upper bound.
4278 * in: serif_point (in twilight zone)
4279 * base_point (in twilight zone)
4280 * edge[-1] (in twilight zone)
4281 * edge[1] (in twilight zone)
4282 * ... stuff for bci_align_segments (serif) ...
4284 * uses: bci_serif_common
4285 * bci_upper_lower_bound
4288 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4291 PUSHB_1,
4292 bci_action_serif_upper_lower_bound,
4293 FDEF,
4295 PUSHB_1,
4297 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4299 PUSHB_1,
4300 bci_serif_common,
4301 CALL,
4303 PUSHB_1,
4304 bci_upper_lower_bound,
4305 CALL,
4307 ENDF,
4313 * bci_serif_anchor_common
4315 * Common code for bci_action_serif_anchor routines.
4317 * sal: sal_anchor
4319 * uses: bci_round
4322 unsigned char FPGM(bci_serif_anchor_common) [] =
4325 PUSHB_1,
4326 bci_serif_anchor_common,
4327 FDEF,
4329 PUSHB_1,
4331 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4333 DUP,
4334 PUSHB_1,
4335 sal_anchor,
4336 SWAP,
4337 WS, /* sal_anchor = edge_point */
4339 DUP,
4340 DUP,
4341 DUP,
4342 GC_cur,
4343 SWAP,
4344 GC_orig,
4345 PUSHB_1,
4346 bci_round,
4347 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4348 SWAP,
4349 SUB,
4350 SHPIX, /* edge = round(edge_orig) */
4352 ENDF,
4358 * bci_action_serif_anchor
4360 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4361 * anchor.
4363 * in: edge_point (in twilight zone)
4364 * ... stuff for bci_align_segments (edge) ...
4366 * uses: bci_serif_anchor_common
4367 * bci_align_segments
4370 unsigned char FPGM(bci_action_serif_anchor) [] =
4373 PUSHB_1,
4374 bci_action_serif_anchor,
4375 FDEF,
4377 PUSHB_1,
4378 bci_serif_anchor_common,
4379 CALL,
4381 MDAP_noround, /* set rp0 and rp1 to `edge' */
4383 PUSHB_2,
4384 bci_align_segments,
4386 SZP1, /* set zp1 to normal zone 1 */
4387 CALL,
4389 ENDF,
4395 * bci_action_serif_anchor_lower_bound
4397 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4398 * anchor, then moving it again if necessary to stay within a lower
4399 * bound.
4401 * in: edge_point (in twilight zone)
4402 * edge[-1] (in twilight zone)
4403 * ... stuff for bci_align_segments (edge) ...
4405 * uses: bci_serif_anchor_common
4406 * bci_lower_bound
4409 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4412 PUSHB_1,
4413 bci_action_serif_anchor_lower_bound,
4414 FDEF,
4416 PUSHB_1,
4417 bci_serif_anchor_common,
4418 CALL,
4420 PUSHB_1,
4421 bci_lower_bound,
4422 CALL,
4424 ENDF,
4430 * bci_action_serif_anchor_upper_bound
4432 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4433 * anchor, then moving it again if necessary to stay within an upper
4434 * bound.
4436 * in: edge_point (in twilight zone)
4437 * edge[1] (in twilight zone)
4438 * ... stuff for bci_align_segments (edge) ...
4440 * uses: bci_serif_anchor_common
4441 * bci_upper_bound
4444 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4447 PUSHB_1,
4448 bci_action_serif_anchor_upper_bound,
4449 FDEF,
4451 PUSHB_1,
4452 bci_serif_anchor_common,
4453 CALL,
4455 PUSHB_1,
4456 bci_upper_bound,
4457 CALL,
4459 ENDF,
4465 * bci_action_serif_anchor_upper_lower_bound
4467 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4468 * anchor, then moving it again if necessary to stay within a lower and
4469 * upper bound.
4471 * in: edge_point (in twilight zone)
4472 * edge[-1] (in twilight zone)
4473 * edge[1] (in twilight zone)
4474 * ... stuff for bci_align_segments (edge) ...
4476 * uses: bci_serif_anchor_common
4477 * bci_upper_lower_bound
4480 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4483 PUSHB_1,
4484 bci_action_serif_anchor_upper_lower_bound,
4485 FDEF,
4487 PUSHB_1,
4488 bci_serif_anchor_common,
4489 CALL,
4491 PUSHB_1,
4492 bci_upper_lower_bound,
4493 CALL,
4495 ENDF,
4501 * bci_serif_link1_common
4503 * Common code for bci_action_serif_link1 routines.
4505 * CVT: cvtl_0x10000
4508 unsigned char FPGM(bci_serif_link1_common) [] =
4511 PUSHB_1,
4512 bci_serif_link1_common,
4513 FDEF,
4515 PUSHB_1,
4517 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4519 PUSHB_1,
4521 CINDEX, /* s: [...] after edge before after */
4522 PUSHB_1,
4524 CINDEX, /* s: [...] after edge before after before */
4525 MD_orig_ZP2_0,
4526 PUSHB_1,
4528 EQ, /* after_orig_pos == before_orig_pos */
4529 IF, /* s: [...] after edge before */
4530 MDAP_noround, /* set rp0 and rp1 to `before' */
4531 DUP,
4532 ALIGNRP, /* align `edge' with `before' */
4533 SWAP,
4534 POP,
4536 ELSE,
4537 /* we have to execute `a*b/c', with b/c very near to 1: */
4538 /* to avoid overflow while retaining precision, */
4539 /* we transform this to `a + a * (b-c)/c' */
4541 PUSHB_1,
4543 CINDEX, /* s: [...] after edge before edge */
4544 PUSHB_1,
4546 CINDEX, /* s: [...] after edge before edge before */
4547 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4549 DUP,
4550 PUSHB_1,
4552 CINDEX, /* s: [...] after edge before a a after */
4553 PUSHB_1,
4555 CINDEX, /* s: [...] after edge before a a after before */
4556 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4558 PUSHB_1,
4560 CINDEX, /* s: [...] after edge before a a c after */
4561 PUSHB_1,
4563 CINDEX, /* s: [...] after edge before a a c after before */
4564 MD_cur, /* b = after_pos - before_pos */
4566 PUSHB_1,
4568 CINDEX, /* s: [...] after edge before a a c b c */
4569 SUB, /* b-c */
4571 PUSHB_1,
4572 cvtl_0x10000,
4573 RCVT,
4574 MUL, /* (b-c) in 16.16 format */
4575 SWAP,
4577 DUP,
4578 IF, /* c != 0 ? */
4579 DIV, /* s: [...] after edge before a a (b-c)/c */
4580 ELSE,
4581 POP, /* avoid division by zero */
4582 EIF,
4584 MUL, /* a * (b-c)/c * 2^10 */
4585 PUSHB_1,
4586 cvtl_0x10000,
4587 RCVT,
4588 DIV, /* a * (b-c)/c */
4589 ADD, /* a*b/c */
4591 SWAP,
4592 MDAP_noround, /* set rp0 and rp1 to `before' */
4593 SWAP, /* s: [...] after a*b/c edge */
4594 DUP,
4595 DUP,
4596 ALIGNRP, /* align `edge' with `before' */
4597 ROLL,
4598 SHPIX, /* shift `edge' by `a*b/c' */
4600 SWAP, /* s: [...] edge after */
4601 POP,
4602 EIF,
4604 ENDF,
4610 * bci_action_serif_link1
4612 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4613 * before and after.
4615 * in: before_point (in twilight zone)
4616 * edge_point (in twilight zone)
4617 * after_point (in twilight zone)
4618 * ... stuff for bci_align_segments (edge) ...
4620 * uses: bci_serif_link1_common
4621 * bci_align_segments
4624 unsigned char FPGM(bci_action_serif_link1) [] =
4627 PUSHB_1,
4628 bci_action_serif_link1,
4629 FDEF,
4631 PUSHB_1,
4632 bci_serif_link1_common,
4633 CALL,
4635 MDAP_noround, /* set rp0 and rp1 to `edge' */
4637 PUSHB_2,
4638 bci_align_segments,
4640 SZP1, /* set zp1 to normal zone 1 */
4641 CALL,
4643 ENDF,
4649 * bci_action_serif_link1_lower_bound
4651 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4652 * before and after. Additionally, move the serif again if necessary to
4653 * stay within a lower bound.
4655 * in: before_point (in twilight zone)
4656 * edge_point (in twilight zone)
4657 * after_point (in twilight zone)
4658 * edge[-1] (in twilight zone)
4659 * ... stuff for bci_align_segments (edge) ...
4661 * uses: bci_serif_link1_common
4662 * bci_lower_bound
4665 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4668 PUSHB_1,
4669 bci_action_serif_link1_lower_bound,
4670 FDEF,
4672 PUSHB_1,
4673 bci_serif_link1_common,
4674 CALL,
4676 PUSHB_1,
4677 bci_lower_bound,
4678 CALL,
4680 ENDF,
4686 * bci_action_serif_link1_upper_bound
4688 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4689 * before and after. Additionally, move the serif again if necessary to
4690 * stay within an upper bound.
4692 * in: before_point (in twilight zone)
4693 * edge_point (in twilight zone)
4694 * after_point (in twilight zone)
4695 * edge[1] (in twilight zone)
4696 * ... stuff for bci_align_segments (edge) ...
4698 * uses: bci_serif_link1_common
4699 * bci_upper_bound
4702 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4705 PUSHB_1,
4706 bci_action_serif_link1_upper_bound,
4707 FDEF,
4709 PUSHB_1,
4710 bci_serif_link1_common,
4711 CALL,
4713 PUSHB_1,
4714 bci_upper_bound,
4715 CALL,
4717 ENDF,
4723 * bci_action_serif_link1_upper_lower_bound
4725 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4726 * before and after. Additionally, move the serif again if necessary to
4727 * stay within a lower and upper bound.
4729 * in: before_point (in twilight zone)
4730 * edge_point (in twilight zone)
4731 * after_point (in twilight zone)
4732 * edge[-1] (in twilight zone)
4733 * edge[1] (in twilight zone)
4734 * ... stuff for bci_align_segments (edge) ...
4736 * uses: bci_serif_link1_common
4737 * bci_upper_lower_bound
4740 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
4743 PUSHB_1,
4744 bci_action_serif_link1_upper_lower_bound,
4745 FDEF,
4747 PUSHB_1,
4748 bci_serif_link1_common,
4749 CALL,
4751 PUSHB_1,
4752 bci_upper_lower_bound,
4753 CALL,
4755 ENDF,
4761 * bci_serif_link2_common
4763 * Common code for bci_action_serif_link2 routines.
4765 * sal: sal_anchor
4768 unsigned char FPGM(bci_serif_link2_common) [] =
4771 PUSHB_1,
4772 bci_serif_link2_common,
4773 FDEF,
4775 PUSHB_1,
4777 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4779 DUP, /* s: [...] edge edge */
4780 PUSHB_1,
4781 sal_anchor,
4783 DUP, /* s: [...] edge edge anchor anchor */
4784 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4786 MD_orig_ZP2_0,
4787 DUP,
4788 ADD,
4789 PUSHB_1,
4791 ADD,
4792 FLOOR,
4793 PUSHB_1,
4794 2*64,
4795 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4797 SWAP,
4798 DUP,
4799 DUP,
4800 ALIGNRP, /* align `edge' with `sal_anchor' */
4801 ROLL,
4802 SHPIX, /* shift `edge' by `delta' */
4804 ENDF,
4810 * bci_action_serif_link2
4812 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4814 * in: edge_point (in twilight zone)
4815 * ... stuff for bci_align_segments (edge) ...
4817 * uses: bci_serif_link2_common
4818 * bci_align_segments
4821 unsigned char FPGM(bci_action_serif_link2) [] =
4824 PUSHB_1,
4825 bci_action_serif_link2,
4826 FDEF,
4828 PUSHB_1,
4829 bci_serif_link2_common,
4830 CALL,
4832 MDAP_noround, /* set rp0 and rp1 to `edge' */
4834 PUSHB_2,
4835 bci_align_segments,
4837 SZP1, /* set zp1 to normal zone 1 */
4838 CALL,
4840 ENDF,
4846 * bci_action_serif_link2_lower_bound
4848 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4849 * Additionally, move the serif again if necessary to stay within a lower
4850 * bound.
4852 * in: edge_point (in twilight zone)
4853 * edge[-1] (in twilight zone)
4854 * ... stuff for bci_align_segments (edge) ...
4856 * uses: bci_serif_link2_common
4857 * bci_lower_bound
4860 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4863 PUSHB_1,
4864 bci_action_serif_link2_lower_bound,
4865 FDEF,
4867 PUSHB_1,
4868 bci_serif_link2_common,
4869 CALL,
4871 PUSHB_1,
4872 bci_lower_bound,
4873 CALL,
4875 ENDF,
4881 * bci_action_serif_link2_upper_bound
4883 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4884 * Additionally, move the serif again if necessary to stay within an upper
4885 * bound.
4887 * in: edge_point (in twilight zone)
4888 * edge[1] (in twilight zone)
4889 * ... stuff for bci_align_segments (edge) ...
4891 * uses: bci_serif_link2_common
4892 * bci_upper_bound
4895 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4898 PUSHB_1,
4899 bci_action_serif_link2_upper_bound,
4900 FDEF,
4902 PUSHB_1,
4903 bci_serif_link2_common,
4904 CALL,
4906 PUSHB_1,
4907 bci_upper_bound,
4908 CALL,
4910 ENDF,
4916 * bci_action_serif_link2_upper_lower_bound
4918 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4919 * Additionally, move the serif again if necessary to stay within a lower
4920 * and upper bound.
4922 * in: edge_point (in twilight zone)
4923 * edge[-1] (in twilight zone)
4924 * edge[1] (in twilight zone)
4925 * ... stuff for bci_align_segments (edge) ...
4927 * uses: bci_serif_link2_common
4928 * bci_upper_lower_bound
4931 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
4934 PUSHB_1,
4935 bci_action_serif_link2_upper_lower_bound,
4936 FDEF,
4938 PUSHB_1,
4939 bci_serif_link2_common,
4940 CALL,
4942 PUSHB_1,
4943 bci_upper_lower_bound,
4944 CALL,
4946 ENDF,
4952 * bci_hint_glyph
4954 * This is the top-level glyph hinting function which parses the arguments
4955 * on the stack and calls subroutines.
4957 * in: action_0_func_idx
4958 * ... data ...
4959 * action_1_func_idx
4960 * ... data ...
4961 * ...
4963 * CVT: cvtl_is_subglyph
4965 * uses: bci_action_ip_before
4966 * bci_action_ip_after
4967 * bci_action_ip_on
4968 * bci_action_ip_between
4970 * bci_action_adjust_bound
4971 * bci_action_adjust_bound_serif
4972 * bci_action_adjust_bound_round
4973 * bci_action_adjust_bound_round_serif
4975 * bci_action_stem_bound
4976 * bci_action_stem_bound_serif
4977 * bci_action_stem_bound_round
4978 * bci_action_stem_bound_round_serif
4980 * bci_action_link
4981 * bci_action_link_serif
4982 * bci_action_link_round
4983 * bci_action_link_round_serif
4985 * bci_action_anchor
4986 * bci_action_anchor_serif
4987 * bci_action_anchor_round
4988 * bci_action_anchor_round_serif
4990 * bci_action_blue_anchor
4992 * bci_action_adjust
4993 * bci_action_adjust_serif
4994 * bci_action_adjust_round
4995 * bci_action_adjust_round_serif
4997 * bci_action_stem
4998 * bci_action_stem_serif
4999 * bci_action_stem_round
5000 * bci_action_stem_round_serif
5002 * bci_action_blue
5004 * bci_action_serif
5005 * bci_action_serif_lower_bound
5006 * bci_action_serif_upper_bound
5007 * bci_action_serif_upper_lower_bound
5009 * bci_action_serif_anchor
5010 * bci_action_serif_anchor_lower_bound
5011 * bci_action_serif_anchor_upper_bound
5012 * bci_action_serif_anchor_upper_lower_bound
5014 * bci_action_serif_link1
5015 * bci_action_serif_link1_lower_bound
5016 * bci_action_serif_link1_upper_bound
5017 * bci_action_serif_link1_upper_lower_bound
5019 * bci_action_serif_link2
5020 * bci_action_serif_link2_lower_bound
5021 * bci_action_serif_link2_upper_bound
5022 * bci_action_serif_link2_upper_lower_bound
5025 unsigned char FPGM(bci_hint_glyph) [] =
5028 PUSHB_1,
5029 bci_hint_glyph,
5030 FDEF,
5032 /* start_loop: */
5033 /* loop until all data on stack is used */
5034 CALL,
5035 PUSHB_1,
5037 NEG,
5038 PUSHB_1,
5040 DEPTH,
5042 JROT, /* goto start_loop */
5044 PUSHB_1,
5046 SZP2, /* set zp2 to normal zone 1 */
5047 IUP_y,
5049 ENDF,
5054 #define COPY_FPGM(func_name) \
5055 memcpy(buf_p, fpgm_ ## func_name, \
5056 sizeof (fpgm_ ## func_name)); \
5057 buf_p += sizeof (fpgm_ ## func_name) \
5059 static FT_Error
5060 TA_table_build_fpgm(FT_Byte** fpgm,
5061 FT_ULong* fpgm_len,
5062 FONT* font)
5064 FT_UInt buf_len;
5065 FT_UInt len;
5066 FT_Byte* buf;
5067 FT_Byte* buf_p;
5070 /* for compatibility with dumb bytecode interpreters or analyzers, */
5071 /* FDEFs are stored in ascending index order, without holes -- */
5072 /* note that some FDEFs are not always needed */
5073 /* (depending on options of `TTFautohint'), */
5074 /* but implementing dynamic FDEF indices would be a lot of work */
5076 buf_len = sizeof (FPGM(bci_round))
5077 + sizeof (FPGM(bci_smooth_stem_width_a))
5079 + sizeof (FPGM(bci_smooth_stem_width_b))
5081 + sizeof (FPGM(bci_smooth_stem_width_c))
5082 + sizeof (FPGM(bci_get_best_width))
5083 + sizeof (FPGM(bci_strong_stem_width_a))
5085 + sizeof (FPGM(bci_strong_stem_width_b))
5086 + sizeof (FPGM(bci_loop_do))
5087 + sizeof (FPGM(bci_loop))
5088 + sizeof (FPGM(bci_cvt_rescale))
5089 + sizeof (FPGM(bci_blue_round_a))
5091 + sizeof (FPGM(bci_blue_round_b))
5092 + sizeof (FPGM(bci_decrement_component_counter))
5093 + sizeof (FPGM(bci_get_point_extrema))
5094 + sizeof (FPGM(bci_nibbles))
5095 + sizeof (FPGM(bci_number_set_is_element))
5096 + sizeof (FPGM(bci_number_set_is_element2))
5098 + sizeof (FPGM(bci_create_segment))
5099 + sizeof (FPGM(bci_create_segments))
5101 + sizeof (FPGM(bci_create_segments_0))
5102 + sizeof (FPGM(bci_create_segments_1))
5103 + sizeof (FPGM(bci_create_segments_2))
5104 + sizeof (FPGM(bci_create_segments_3))
5105 + sizeof (FPGM(bci_create_segments_4))
5106 + sizeof (FPGM(bci_create_segments_5))
5107 + sizeof (FPGM(bci_create_segments_6))
5108 + sizeof (FPGM(bci_create_segments_7))
5109 + sizeof (FPGM(bci_create_segments_8))
5110 + sizeof (FPGM(bci_create_segments_9))
5112 + sizeof (FPGM(bci_create_segments_composite))
5114 + sizeof (FPGM(bci_create_segments_composite_0))
5115 + sizeof (FPGM(bci_create_segments_composite_1))
5116 + sizeof (FPGM(bci_create_segments_composite_2))
5117 + sizeof (FPGM(bci_create_segments_composite_3))
5118 + sizeof (FPGM(bci_create_segments_composite_4))
5119 + sizeof (FPGM(bci_create_segments_composite_5))
5120 + sizeof (FPGM(bci_create_segments_composite_6))
5121 + sizeof (FPGM(bci_create_segments_composite_7))
5122 + sizeof (FPGM(bci_create_segments_composite_8))
5123 + sizeof (FPGM(bci_create_segments_composite_9))
5125 + sizeof (FPGM(bci_align_point))
5126 + sizeof (FPGM(bci_align_segment))
5127 + sizeof (FPGM(bci_align_segments))
5129 + sizeof (FPGM(bci_scale_contour))
5130 + sizeof (FPGM(bci_scale_glyph))
5131 + sizeof (FPGM(bci_scale_composite_glyph))
5132 + sizeof (FPGM(bci_shift_contour))
5133 + sizeof (FPGM(bci_shift_subglyph))
5135 + sizeof (FPGM(bci_ip_outer_align_point))
5136 + sizeof (FPGM(bci_ip_on_align_points))
5137 + sizeof (FPGM(bci_ip_between_align_point))
5138 + sizeof (FPGM(bci_ip_between_align_points))
5140 + sizeof (FPGM(bci_adjust_common))
5141 + sizeof (FPGM(bci_stem_common))
5142 + sizeof (FPGM(bci_serif_common))
5143 + sizeof (FPGM(bci_serif_anchor_common))
5144 + sizeof (FPGM(bci_serif_link1_common))
5145 + sizeof (FPGM(bci_serif_link2_common))
5147 + sizeof (FPGM(bci_lower_bound))
5148 + sizeof (FPGM(bci_upper_bound))
5149 + sizeof (FPGM(bci_upper_lower_bound))
5151 + sizeof (FPGM(bci_adjust_bound))
5152 + sizeof (FPGM(bci_stem_bound))
5153 + sizeof (FPGM(bci_link))
5154 + sizeof (FPGM(bci_anchor))
5155 + sizeof (FPGM(bci_adjust))
5156 + sizeof (FPGM(bci_stem))
5158 + sizeof (FPGM(bci_action_ip_before))
5159 + sizeof (FPGM(bci_action_ip_after))
5160 + sizeof (FPGM(bci_action_ip_on))
5161 + sizeof (FPGM(bci_action_ip_between))
5163 + sizeof (FPGM(bci_action_blue))
5164 + sizeof (FPGM(bci_action_blue_anchor))
5166 + sizeof (FPGM(bci_action_anchor))
5167 + sizeof (FPGM(bci_action_anchor_serif))
5168 + sizeof (FPGM(bci_action_anchor_round))
5169 + sizeof (FPGM(bci_action_anchor_round_serif))
5171 + sizeof (FPGM(bci_action_adjust))
5172 + sizeof (FPGM(bci_action_adjust_serif))
5173 + sizeof (FPGM(bci_action_adjust_round))
5174 + sizeof (FPGM(bci_action_adjust_round_serif))
5175 + sizeof (FPGM(bci_action_adjust_bound))
5176 + sizeof (FPGM(bci_action_adjust_bound_serif))
5177 + sizeof (FPGM(bci_action_adjust_bound_round))
5178 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5180 + sizeof (FPGM(bci_action_link))
5181 + sizeof (FPGM(bci_action_link_serif))
5182 + sizeof (FPGM(bci_action_link_round))
5183 + sizeof (FPGM(bci_action_link_round_serif))
5185 + sizeof (FPGM(bci_action_stem))
5186 + sizeof (FPGM(bci_action_stem_serif))
5187 + sizeof (FPGM(bci_action_stem_round))
5188 + sizeof (FPGM(bci_action_stem_round_serif))
5189 + sizeof (FPGM(bci_action_stem_bound))
5190 + sizeof (FPGM(bci_action_stem_bound_serif))
5191 + sizeof (FPGM(bci_action_stem_bound_round))
5192 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5194 + sizeof (FPGM(bci_action_serif))
5195 + sizeof (FPGM(bci_action_serif_lower_bound))
5196 + sizeof (FPGM(bci_action_serif_upper_bound))
5197 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5199 + sizeof (FPGM(bci_action_serif_anchor))
5200 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5201 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5202 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5204 + sizeof (FPGM(bci_action_serif_link1))
5205 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5206 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5207 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5209 + sizeof (FPGM(bci_action_serif_link2))
5210 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5211 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5212 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5214 + sizeof (FPGM(bci_hint_glyph));
5216 /* buffer length must be a multiple of four */
5217 len = (buf_len + 3) & ~3;
5218 buf = (FT_Byte*)malloc(len);
5219 if (!buf)
5220 return FT_Err_Out_Of_Memory;
5222 /* pad end of buffer with zeros */
5223 buf[len - 1] = 0x00;
5224 buf[len - 2] = 0x00;
5225 buf[len - 3] = 0x00;
5227 /* copy font program into buffer and fill in the missing variables */
5228 buf_p = buf;
5230 COPY_FPGM(bci_round);
5231 COPY_FPGM(bci_smooth_stem_width_a);
5232 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5233 COPY_FPGM(bci_smooth_stem_width_b);
5234 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5235 COPY_FPGM(bci_smooth_stem_width_c);
5236 COPY_FPGM(bci_get_best_width);
5237 COPY_FPGM(bci_strong_stem_width_a);
5238 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5239 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font);
5240 COPY_FPGM(bci_strong_stem_width_b);
5241 COPY_FPGM(bci_loop_do);
5242 COPY_FPGM(bci_loop);
5243 COPY_FPGM(bci_cvt_rescale);
5244 COPY_FPGM(bci_blue_round_a);
5245 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
5246 COPY_FPGM(bci_blue_round_b);
5247 COPY_FPGM(bci_decrement_component_counter);
5248 COPY_FPGM(bci_get_point_extrema);
5249 COPY_FPGM(bci_nibbles);
5250 COPY_FPGM(bci_number_set_is_element);
5251 COPY_FPGM(bci_number_set_is_element2);
5253 COPY_FPGM(bci_create_segment);
5254 COPY_FPGM(bci_create_segments);
5256 COPY_FPGM(bci_create_segments_0);
5257 COPY_FPGM(bci_create_segments_1);
5258 COPY_FPGM(bci_create_segments_2);
5259 COPY_FPGM(bci_create_segments_3);
5260 COPY_FPGM(bci_create_segments_4);
5261 COPY_FPGM(bci_create_segments_5);
5262 COPY_FPGM(bci_create_segments_6);
5263 COPY_FPGM(bci_create_segments_7);
5264 COPY_FPGM(bci_create_segments_8);
5265 COPY_FPGM(bci_create_segments_9);
5267 COPY_FPGM(bci_create_segments_composite);
5269 COPY_FPGM(bci_create_segments_composite_0);
5270 COPY_FPGM(bci_create_segments_composite_1);
5271 COPY_FPGM(bci_create_segments_composite_2);
5272 COPY_FPGM(bci_create_segments_composite_3);
5273 COPY_FPGM(bci_create_segments_composite_4);
5274 COPY_FPGM(bci_create_segments_composite_5);
5275 COPY_FPGM(bci_create_segments_composite_6);
5276 COPY_FPGM(bci_create_segments_composite_7);
5277 COPY_FPGM(bci_create_segments_composite_8);
5278 COPY_FPGM(bci_create_segments_composite_9);
5280 COPY_FPGM(bci_align_point);
5281 COPY_FPGM(bci_align_segment);
5282 COPY_FPGM(bci_align_segments);
5284 COPY_FPGM(bci_scale_contour);
5285 COPY_FPGM(bci_scale_glyph);
5286 COPY_FPGM(bci_scale_composite_glyph);
5287 COPY_FPGM(bci_shift_contour);
5288 COPY_FPGM(bci_shift_subglyph);
5290 COPY_FPGM(bci_ip_outer_align_point);
5291 COPY_FPGM(bci_ip_on_align_points);
5292 COPY_FPGM(bci_ip_between_align_point);
5293 COPY_FPGM(bci_ip_between_align_points);
5295 COPY_FPGM(bci_adjust_common);
5296 COPY_FPGM(bci_stem_common);
5297 COPY_FPGM(bci_serif_common);
5298 COPY_FPGM(bci_serif_anchor_common);
5299 COPY_FPGM(bci_serif_link1_common);
5300 COPY_FPGM(bci_serif_link2_common);
5302 COPY_FPGM(bci_lower_bound);
5303 COPY_FPGM(bci_upper_bound);
5304 COPY_FPGM(bci_upper_lower_bound);
5306 COPY_FPGM(bci_adjust_bound);
5307 COPY_FPGM(bci_stem_bound);
5308 COPY_FPGM(bci_link);
5309 COPY_FPGM(bci_anchor);
5310 COPY_FPGM(bci_adjust);
5311 COPY_FPGM(bci_stem);
5313 COPY_FPGM(bci_action_ip_before);
5314 COPY_FPGM(bci_action_ip_after);
5315 COPY_FPGM(bci_action_ip_on);
5316 COPY_FPGM(bci_action_ip_between);
5318 COPY_FPGM(bci_action_blue);
5319 COPY_FPGM(bci_action_blue_anchor);
5321 COPY_FPGM(bci_action_anchor);
5322 COPY_FPGM(bci_action_anchor_serif);
5323 COPY_FPGM(bci_action_anchor_round);
5324 COPY_FPGM(bci_action_anchor_round_serif);
5326 COPY_FPGM(bci_action_adjust);
5327 COPY_FPGM(bci_action_adjust_serif);
5328 COPY_FPGM(bci_action_adjust_round);
5329 COPY_FPGM(bci_action_adjust_round_serif);
5330 COPY_FPGM(bci_action_adjust_bound);
5331 COPY_FPGM(bci_action_adjust_bound_serif);
5332 COPY_FPGM(bci_action_adjust_bound_round);
5333 COPY_FPGM(bci_action_adjust_bound_round_serif);
5335 COPY_FPGM(bci_action_link);
5336 COPY_FPGM(bci_action_link_serif);
5337 COPY_FPGM(bci_action_link_round);
5338 COPY_FPGM(bci_action_link_round_serif);
5340 COPY_FPGM(bci_action_stem);
5341 COPY_FPGM(bci_action_stem_serif);
5342 COPY_FPGM(bci_action_stem_round);
5343 COPY_FPGM(bci_action_stem_round_serif);
5344 COPY_FPGM(bci_action_stem_bound);
5345 COPY_FPGM(bci_action_stem_bound_serif);
5346 COPY_FPGM(bci_action_stem_bound_round);
5347 COPY_FPGM(bci_action_stem_bound_round_serif);
5349 COPY_FPGM(bci_action_serif);
5350 COPY_FPGM(bci_action_serif_lower_bound);
5351 COPY_FPGM(bci_action_serif_upper_bound);
5352 COPY_FPGM(bci_action_serif_upper_lower_bound);
5354 COPY_FPGM(bci_action_serif_anchor);
5355 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5356 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5357 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5359 COPY_FPGM(bci_action_serif_link1);
5360 COPY_FPGM(bci_action_serif_link1_lower_bound);
5361 COPY_FPGM(bci_action_serif_link1_upper_bound);
5362 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5364 COPY_FPGM(bci_action_serif_link2);
5365 COPY_FPGM(bci_action_serif_link2_lower_bound);
5366 COPY_FPGM(bci_action_serif_link2_upper_bound);
5367 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5369 COPY_FPGM(bci_hint_glyph);
5371 *fpgm = buf;
5372 *fpgm_len = buf_len;
5374 return FT_Err_Ok;
5378 FT_Error
5379 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5380 FONT* font)
5382 FT_Error error = FT_Err_Ok;
5384 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5385 glyf_Data* data = (glyf_Data*)glyf_table->data;
5387 FT_Byte* fpgm_buf;
5388 FT_ULong fpgm_len;
5391 error = TA_sfnt_add_table_info(sfnt);
5392 if (error)
5393 goto Exit;
5395 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5396 if (glyf_table->processed)
5398 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5399 goto Exit;
5402 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
5403 if (error)
5404 goto Exit;
5406 if (fpgm_len > sfnt->max_instructions)
5407 sfnt->max_instructions = fpgm_len;
5409 /* in case of success, `fpgm_buf' gets linked */
5410 /* and is eventually freed in `TA_font_unload' */
5411 error = TA_font_add_table(font,
5412 &sfnt->table_infos[sfnt->num_table_infos - 1],
5413 TTAG_fpgm, fpgm_len, fpgm_buf);
5414 if (error)
5415 free(fpgm_buf);
5416 else
5417 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5419 Exit:
5420 return error;
5423 /* end of tafpgm.c */