In `prep' table, replace calls to bci_loop with LOOPCALL.
[ttfautohint.git] / lib / tafpgm.c
blobd48a761ac5e1df0f3c5829ef589b69bedc7d4db8
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2012 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
77 * out: ROUND(val)
80 unsigned char FPGM(bci_round) [] =
83 PUSHB_1,
84 bci_round,
85 FDEF,
87 PUSHB_1,
88 32,
89 ADD,
90 FLOOR,
92 ENDF,
98 * bci_smooth_stem_width
100 * This is the equivalent to the following code from function
101 * `ta_latin_compute_stem_width':
103 * dist = ABS(width)
105 * if (stem_is_serif
106 * && dist < 3*64)
107 * || is_extra_light:
108 * return width
109 * else if base_is_round:
110 * if dist < 80
111 * dist = 64
112 * else if dist < 56:
113 * dist = 56
115 * delta = ABS(dist - std_width)
117 * if delta < 40:
118 * dist = std_width
119 * if dist < 48
120 * dist = 48
121 * goto End
123 * if dist < 3*64:
124 * delta = dist
125 * dist = FLOOR(dist)
126 * delta = delta - dist
128 * if delta < 10:
129 * dist = dist + delta
130 * else if delta < 32:
131 * dist = dist + 10
132 * else if delta < 54:
133 * dist = dist + 54
134 * else
135 * dist = dist + delta
136 * else
137 * dist = ROUND(dist)
139 * End:
140 * if width < 0:
141 * dist = -dist
142 * return dist
145 * in: width
146 * stem_is_serif
147 * base_is_round
149 * out: new_width
151 * CVT: cvtl_is_extra_light
152 * std_width
154 * uses: bci_round
157 unsigned char FPGM(bci_smooth_stem_width_a) [] =
160 PUSHB_1,
161 bci_smooth_stem_width,
162 FDEF,
164 DUP,
165 ABS, /* s: base_is_round stem_is_serif width dist */
167 DUP,
168 PUSHB_1,
169 3*64,
170 LT, /* dist < 3*64 */
172 PUSHB_1,
174 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
175 AND, /* stem_is_serif && dist < 3*64 */
177 PUSHB_1,
178 cvtl_is_extra_light,
179 RCVT,
180 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
182 IF, /* s: base_is_round width dist */
183 POP,
184 SWAP,
185 POP, /* s: width */
187 ELSE,
188 ROLL, /* s: width dist base_is_round */
189 IF, /* s: width dist */
190 DUP,
191 PUSHB_1,
193 LT, /* dist < 80 */
194 IF, /* s: width dist */
195 POP,
196 PUSHB_1,
197 64, /* dist = 64 */
198 EIF,
200 ELSE,
201 DUP,
202 PUSHB_1,
204 LT, /* dist < 56 */
205 IF, /* s: width dist */
206 POP,
207 PUSHB_1,
208 56, /* dist = 56 */
209 EIF,
210 EIF,
212 DUP, /* s: width dist dist */
213 PUSHB_1,
217 /* %c, index of std_width */
219 unsigned char FPGM(bci_smooth_stem_width_b) [] =
222 RCVT,
223 SUB,
224 ABS, /* s: width dist delta */
226 PUSHB_1,
228 LT, /* delta < 40 */
229 IF, /* s: width dist */
230 POP,
231 PUSHB_1,
235 /* %c, index of std_width */
237 unsigned char FPGM(bci_smooth_stem_width_c) [] =
240 RCVT, /* dist = std_width */
241 DUP,
242 PUSHB_1,
244 LT, /* dist < 48 */
246 POP,
247 PUSHB_1,
248 48, /* dist = 48 */
249 EIF,
251 ELSE,
252 DUP, /* s: width dist dist */
253 PUSHB_1,
254 3*64,
255 LT, /* dist < 3*64 */
257 DUP, /* s: width delta dist */
258 FLOOR, /* dist = FLOOR(dist) */
259 DUP, /* s: width delta dist dist */
260 ROLL,
261 ROLL, /* s: width dist delta dist */
262 SUB, /* delta = delta - dist */
264 DUP, /* s: width dist delta delta */
265 PUSHB_1,
267 LT, /* delta < 10 */
268 IF, /* s: width dist delta */
269 ADD, /* dist = dist + delta */
271 ELSE,
272 DUP,
273 PUSHB_1,
275 LT, /* delta < 32 */
277 POP,
278 PUSHB_1,
280 ADD, /* dist = dist + 10 */
282 ELSE,
283 DUP,
284 PUSHB_1,
286 LT, /* delta < 54 */
288 POP,
289 PUSHB_1,
291 ADD, /* dist = dist + 54 */
293 ELSE,
294 ADD, /* dist = dist + delta */
296 EIF,
297 EIF,
298 EIF,
300 ELSE,
301 PUSHB_1,
302 bci_round,
303 CALL, /* dist = round(dist) */
305 EIF,
306 EIF,
308 SWAP, /* s: dist width */
309 PUSHB_1,
311 LT, /* width < 0 */
313 NEG, /* dist = -dist */
314 EIF,
315 EIF,
317 ENDF,
323 * bci_get_best_width
325 * An auxiliary function for `bci_strong_stem_width'.
327 * in: n (initialized with CVT index for first vertical width)
328 * dist
330 * out: n+1
331 * dist
333 * sal: sal_best
334 * sal_ref
336 * CVT: widths[]
339 unsigned char FPGM(bci_get_best_width) [] =
342 PUSHB_1,
343 bci_get_best_width,
344 FDEF,
346 DUP,
347 RCVT, /* s: dist n w */
348 DUP,
349 PUSHB_1,
351 CINDEX, /* s: dist n w w dist */
352 SUB,
353 ABS, /* s: dist n w d */
354 DUP,
355 PUSHB_1,
356 sal_best,
357 RS, /* s: dist n w d d best */
358 LT, /* d < best */
360 PUSHB_1,
361 sal_best,
362 SWAP,
363 WS, /* best = d */
364 PUSHB_1,
365 sal_ref,
366 SWAP,
367 WS, /* reference = w */
369 ELSE,
370 POP,
371 POP,
372 EIF,
374 PUSHB_1,
376 ADD, /* n = n + 1 */
378 ENDF,
384 * bci_strong_stem_width
386 * This is the equivalent to the following code (function
387 * `ta_latin_snap_width' and some lines from
388 * `ta_latin_compute_stem_width'):
390 * best = 64 + 32 + 2;
391 * reference = width
392 * dist = ABS(width)
394 * for n in 0 .. num_widths:
395 * w = widths[n]
396 * d = ABS(dist - w)
398 * if d < best:
399 * best = d
400 * reference = w;
402 * if dist >= reference:
403 * if dist < ROUND(reference) + 48:
404 * dist = reference
405 * else
406 * if dist > ROUND(reference) - 48:
407 * dist = reference
409 * if dist >= 64:
410 * dist = ROUND(dist)
411 * else
412 * dist = 64
414 * if width < 0:
415 * dist = -dist
416 * return dist
418 * in: width
419 * stem_is_serif (unused)
420 * base_is_round (unused)
422 * out: new_width
424 * sal: sal_best
425 * sal_ref
427 * CVT: widths[]
429 * uses: bci_get_best_width
430 * bci_round
433 unsigned char FPGM(bci_strong_stem_width_a) [] =
436 PUSHB_1,
437 bci_strong_stem_width,
438 FDEF,
440 SWAP,
441 POP,
442 SWAP,
443 POP,
444 DUP,
445 ABS, /* s: width dist */
447 PUSHB_2,
448 sal_best,
449 64 + 32 + 2,
450 WS, /* sal_best = 98 */
452 DUP,
453 PUSHB_1,
454 sal_ref,
455 SWAP,
456 WS, /* sal_ref = width */
458 PUSHB_3,
461 /* %c, first index of vertical widths */
462 /* %c, number of vertical widths */
464 unsigned char FPGM(bci_strong_stem_width_b) [] =
467 bci_get_best_width,
468 LOOPCALL,
470 POP, /* s: width dist */
471 DUP,
472 PUSHB_1,
473 sal_ref,
474 RS, /* s: width dist dist reference */
475 DUP,
476 ROLL,
477 DUP,
478 ROLL,
479 PUSHB_1,
480 bci_round,
481 CALL, /* s: width dist reference dist dist ROUND(reference) */
482 PUSHB_2,
485 CINDEX,
486 ROLL, /* s: width dist reference dist ROUND(reference) 48 reference dist */
488 LTEQ, /* dist >= reference */
489 IF, /* s: width dist reference dist ROUND(reference) 48 */
490 ADD,
491 LT, /* dist < ROUND(reference) + 48 */
493 ELSE,
494 SUB,
495 GT, /* dist > ROUND(reference) - 48 */
496 EIF,
499 SWAP, /* s: width reference dist */
500 EIF,
501 POP,
503 DUP,
504 PUSHB_1,
506 GTEQ, /* dist >= 64 */
508 PUSHB_1,
509 bci_round,
510 CALL, /* dist = ROUND(dist) */
512 ELSE,
513 POP,
514 PUSHB_1,
515 64, /* dist = 64 */
516 EIF,
518 SWAP, /* s: dist width */
519 PUSHB_1,
521 LT, /* width < 0 */
523 NEG, /* dist = -dist */
524 EIF,
526 ENDF,
532 * bci_loop
534 * Take a range and a function number and apply the function to all
535 * elements of the range.
537 * in: func_num
538 * end
539 * start
541 * sal: sal_i (counter initialized with `start')
542 * sal_limit (`end')
543 * sal_func (`func_num')
546 unsigned char FPGM(bci_loop) [] =
549 PUSHB_1,
550 bci_loop,
551 FDEF,
553 PUSHB_1,
554 sal_func,
555 SWAP,
556 WS, /* sal_func = func_num */
557 PUSHB_1,
558 sal_limit,
559 SWAP,
560 WS, /* sal_limit = end */
561 PUSHB_1,
562 sal_i,
563 SWAP,
564 WS, /* sal_i = start */
566 /* start_loop: */
567 PUSHB_1,
568 sal_i,
570 PUSHB_1,
571 sal_limit,
573 LTEQ, /* start <= end */
575 PUSHB_1,
576 sal_func,
578 CALL,
579 PUSHB_3,
580 sal_i,
582 sal_i,
584 ADD, /* start = start + 1 */
587 PUSHB_1,
589 NEG,
590 JMPR, /* goto start_loop */
591 EIF,
593 ENDF,
599 * bci_cvt_rescale
601 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
603 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
604 * consequently, the calculation `a * b/c' is done as `a + delta' with
605 * `delta = a * (b-c)/c'. This avoids overflow.
607 * in: cvt_idx
609 * out: cvt_idx+1
611 * CVT: cvtl_scale
612 * cvtl_0x10000
615 unsigned char FPGM(bci_cvt_rescale) [] =
618 PUSHB_1,
619 bci_cvt_rescale,
620 FDEF,
622 DUP,
623 DUP,
624 RCVT,
625 DO_SCALE,
626 WCVTP,
628 PUSHB_1,
630 ADD,
632 ENDF,
638 * bci_blue_round
640 * Round a blue ref value and adjust its corresponding shoot value.
642 * in: ref_idx
644 * out: ref_idx+1
646 * uses: bci_round
649 unsigned char FPGM(bci_blue_round_a) [] =
652 PUSHB_1,
653 bci_blue_round,
654 FDEF,
656 DUP,
657 DUP,
658 RCVT, /* s: ref_idx ref_idx ref */
660 DUP,
661 PUSHB_1,
662 bci_round,
663 CALL,
664 SWAP, /* s: ref_idx ref_idx round(ref) ref */
666 PUSHB_2,
670 /* %c, blue_count */
672 unsigned char FPGM(bci_blue_round_b) [] =
676 CINDEX,
677 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
678 DUP,
679 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
681 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
682 SWAP,
683 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
684 DUP,
685 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
687 DUP,
688 PUSHB_1,
690 LT, /* delta < 32 */
692 POP,
693 PUSHB_1,
694 0, /* delta = 0 */
696 ELSE,
697 PUSHB_1,
699 LT, /* delta < 48 */
701 PUSHB_1,
702 32, /* delta = 32 */
704 ELSE,
705 PUSHB_1,
706 64, /* delta = 64 */
707 EIF,
708 EIF,
710 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
711 PUSHB_1,
713 LT, /* dist < 0 */
715 NEG, /* delta = -delta */
716 EIF,
718 PUSHB_1,
720 CINDEX,
721 SWAP,
722 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
724 WCVTP,
725 WCVTP,
727 PUSHB_1,
729 ADD, /* s: (ref_idx + 1) */
731 ENDF,
737 * bci_decrement_component_counter
739 * An auxiliary function for composite glyphs.
741 * CVT: cvtl_is_subglyph
744 unsigned char FPGM(bci_decrement_component_counter) [] =
747 PUSHB_1,
748 bci_decrement_component_counter,
749 FDEF,
751 /* decrement `cvtl_is_subglyph' counter */
752 PUSHB_2,
753 cvtl_is_subglyph,
754 cvtl_is_subglyph,
755 RCVT,
756 PUSHB_1,
758 SUB,
759 WCVTP,
761 ENDF,
767 * bci_get_point_extrema
769 * An auxiliary function for `bci_create_segment'.
771 * in: point-1
772 * out: point
774 * sal: sal_point_min
775 * sal_point_max
778 unsigned char FPGM(bci_get_point_extrema) [] =
781 PUSHB_1,
782 bci_get_point_extrema,
783 FDEF,
785 PUSHB_1,
787 ADD, /* s: point */
788 DUP,
789 DUP,
791 /* check whether `point' is a new minimum */
792 PUSHB_1,
793 sal_point_min,
794 RS, /* s: point point point point_min */
795 MD_orig,
796 /* if distance is negative, we have a new minimum */
797 PUSHB_1,
800 IF, /* s: point point */
801 DUP,
802 PUSHB_1,
803 sal_point_min,
804 SWAP,
806 EIF,
808 /* check whether `point' is a new maximum */
809 PUSHB_1,
810 sal_point_max,
811 RS, /* s: point point point_max */
812 MD_orig,
813 /* if distance is positive, we have a new maximum */
814 PUSHB_1,
817 IF, /* s: point */
818 DUP,
819 PUSHB_1,
820 sal_point_max,
821 SWAP,
823 EIF, /* s: point */
825 ENDF,
831 * bci_nibbles
833 * Pop a byte with two delta arguments in its nibbles and push the
834 * expanded arguments separately as two bytes.
836 * in: 16 * (end - start) + (start - base)
838 * out: start
839 * end
841 * sal: sal_base (set to `end' at return)
845 unsigned char FPGM(bci_nibbles) [] =
847 PUSHB_1,
848 bci_nibbles,
849 FDEF,
851 DUP,
852 PUSHW_1,
853 0x04, /* 16*64 */
854 0x00,
855 DIV, /* s: in hnibble */
856 DUP,
857 PUSHW_1,
858 0x04, /* 16*64 */
859 0x00,
860 MUL, /* s: in hnibble (hnibble * 16) */
861 ROLL,
862 SWAP,
863 SUB, /* s: hnibble lnibble */
865 PUSHB_1,
866 sal_base,
868 ADD, /* s: hnibble start */
869 DUP,
870 ROLL,
871 ADD, /* s: start end */
873 DUP,
874 PUSHB_1,
875 sal_base,
876 SWAP,
877 WS, /* sal_base = end */
879 SWAP,
881 ENDF,
887 * bci_number_set_is_element
889 * Pop values from stack until it is empty. If one of them is equal to
890 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
891 * otherwise).
893 * in: ppem_value_1
894 * ppem_value_2
895 * ...
897 * CVT: cvtl_is_element
900 unsigned char FPGM(bci_number_set_is_element) [] =
903 PUSHB_1,
904 bci_number_set_is_element,
905 FDEF,
907 /* start_loop: */
908 MPPEM,
911 PUSHB_2,
912 cvtl_is_element,
914 WCVTP,
915 EIF,
917 DEPTH,
918 PUSHB_1,
920 NEG,
921 SWAP,
922 JROT, /* goto start_loop if stack depth != 0 */
924 ENDF,
930 * bci_number_set_is_element2
932 * Pop value ranges from stack until it is empty. If one of them contains
933 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
934 * otherwise).
936 * in: ppem_range_1_start
937 * ppem_range_1_end
938 * ppem_range_2_start
939 * ppem_range_2_end
940 * ...
942 * CVT: cvtl_is_element
945 unsigned char FPGM(bci_number_set_is_element2) [] =
948 PUSHB_1,
949 bci_number_set_is_element2,
950 FDEF,
952 /* start_loop: */
953 MPPEM,
954 LTEQ,
956 MPPEM,
957 GTEQ,
959 PUSHB_2,
960 cvtl_is_element,
962 WCVTP,
963 EIF,
964 ELSE,
965 POP,
966 EIF,
968 DEPTH,
969 PUSHB_1,
971 NEG,
972 SWAP,
973 JROT, /* goto start_loop if stack depth != 0 */
975 ENDF,
981 * bci_create_segment
983 * Store start and end point of a segment in the storage area,
984 * then construct a point in the twilight zone to represent it.
986 * This function is used by `bci_create_segment_points'.
988 * in: start
989 * end
990 * [last (if wrap-around segment)]
991 * [first (if wrap-around segment)]
993 * sal: sal_i (start of current segment)
994 * sal_j (current twilight point)
995 * sal_point_min
996 * sal_point_max
997 * sal_base
998 * sal_num_packed_segments
1000 * CVT: cvtl_scale
1001 * cvtl_0x10000
1002 * cvtl_temp
1004 * uses: bci_get_point_extrema
1005 * bci_nibbles
1007 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1008 * delta values in nibbles (without a wrap-around segment).
1011 unsigned char FPGM(bci_create_segment) [] =
1014 PUSHB_1,
1015 bci_create_segment,
1016 FDEF,
1018 PUSHB_2,
1020 sal_num_packed_segments,
1022 NEQ,
1024 PUSHB_2,
1025 sal_num_packed_segments,
1026 sal_num_packed_segments,
1028 PUSHB_1,
1030 SUB,
1031 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1033 PUSHB_1,
1034 bci_nibbles,
1035 CALL,
1036 EIF,
1038 PUSHB_1,
1039 sal_i,
1041 PUSHB_1,
1043 CINDEX,
1044 WS, /* sal[sal_i] = start */
1046 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
1047 PUSHB_3,
1048 sal_i,
1050 sal_i,
1052 ADD, /* sal_i = sal_i + 1 */
1055 /* initialize inner loop(s) */
1056 PUSHB_2,
1057 sal_point_min,
1059 CINDEX,
1060 WS, /* sal_point_min = start */
1061 PUSHB_2,
1062 sal_point_max,
1064 CINDEX,
1065 WS, /* sal_point_max = start */
1067 PUSHB_1,
1069 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1071 SWAP,
1072 DUP,
1073 PUSHB_1,
1075 CINDEX, /* s: start end end start */
1076 LT, /* start > end */
1078 /* we have a wrap-around segment with two more arguments */
1079 /* to give the last and first point of the contour, respectively; */
1080 /* our job is to store a segment `start'-`last', */
1081 /* and to get extrema for the two segments */
1082 /* `start'-`last' and `first'-`end' */
1084 /* s: first last start end */
1085 PUSHB_1,
1086 sal_i,
1088 PUSHB_1,
1090 CINDEX,
1091 WS, /* sal[sal_i] = last */
1093 ROLL,
1094 ROLL, /* s: first end last start */
1095 DUP,
1096 ROLL,
1097 SWAP, /* s: first end start last start */
1098 SUB, /* s: first end start loop_count */
1100 PUSHB_1,
1101 bci_get_point_extrema,
1102 LOOPCALL,
1103 /* clean up stack */
1104 POP,
1106 SWAP, /* s: end first */
1107 PUSHB_1,
1109 SUB,
1110 DUP,
1111 ROLL, /* s: (first - 1) (first - 1) end */
1112 SWAP,
1113 SUB, /* s: (first - 1) loop_count */
1115 PUSHB_1,
1116 bci_get_point_extrema,
1117 LOOPCALL,
1118 /* clean up stack */
1119 POP,
1121 ELSE, /* s: start end */
1122 PUSHB_1,
1123 sal_i,
1125 PUSHB_1,
1127 CINDEX,
1128 WS, /* sal[sal_i] = end */
1130 PUSHB_1,
1132 CINDEX,
1133 SUB, /* s: start loop_count */
1135 PUSHB_1,
1136 bci_get_point_extrema,
1137 LOOPCALL,
1138 /* clean up stack */
1139 POP,
1140 EIF,
1142 /* the twilight point representing a segment */
1143 /* is in the middle between the minimum and maximum */
1144 PUSHB_1,
1145 sal_point_min,
1147 GC_orig,
1148 PUSHB_1,
1149 sal_point_max,
1151 GC_orig,
1152 ADD,
1153 PUSHB_1,
1154 2*64,
1155 DIV, /* s: middle_pos */
1157 DO_SCALE, /* middle_pos = middle_pos * scale */
1159 /* write it to temporary CVT location */
1160 PUSHB_2,
1161 cvtl_temp,
1163 SZP0, /* set zp0 to twilight zone 0 */
1164 SWAP,
1165 WCVTP,
1167 /* create twilight point with index `sal_j' */
1168 PUSHB_1,
1169 sal_j,
1171 PUSHB_1,
1172 cvtl_temp,
1173 MIAP_noround,
1175 PUSHB_3,
1176 sal_j,
1178 sal_j,
1180 ADD, /* twilight_point = twilight_point + 1 */
1183 ENDF,
1189 * bci_create_segments
1191 * This is the top-level entry function.
1193 * It pops point ranges from the stack to define segments, computes
1194 * twilight points to represent segments, and finally calls
1195 * `bci_hint_glyph' to handle the rest.
1197 * in: num_packed_segments
1198 * num_segments (N)
1199 * segment_start_0
1200 * segment_end_0
1201 * [contour_last 0 (if wrap-around segment)]
1202 * [contour_first 0 (if wrap-around segment)]
1203 * segment_start_1
1204 * segment_end_1
1205 * [contour_last 0 (if wrap-around segment)]
1206 * [contour_first 0 (if wrap-around segment)]
1207 * ...
1208 * segment_start_(N-1)
1209 * segment_end_(N-1)
1210 * [contour_last (N-1) (if wrap-around segment)]
1211 * [contour_first (N-1) (if wrap-around segment)]
1212 * ... stuff for bci_hint_glyph ...
1214 * sal: sal_i (start of current segment)
1215 * sal_j (current twilight point)
1216 * sal_num_packed_segments
1217 * sal_base (the base for delta values in nibbles)
1219 * CVT: cvtl_is_subglyph
1221 * uses: bci_create_segment
1222 * bci_loop
1223 * bci_hint_glyph
1225 * If `num_packed_segments' is set to p, the first p start/end pairs are
1226 * stored as delta values in nibbles, with the `start' delta in the lower
1227 * nibble (and there are no wrap-around segments). For example, if the
1228 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1229 * stack are 0x21, 0x32, and 0x14.
1233 unsigned char FPGM(bci_create_segments) [] =
1236 PUSHB_1,
1237 bci_create_segments,
1238 FDEF,
1240 /* only do something if we are not a subglyph */
1241 PUSHB_2,
1243 cvtl_is_subglyph,
1244 RCVT,
1247 /* all our measurements are taken along the y axis */
1248 SVTCA_y,
1250 PUSHB_1,
1251 sal_num_packed_segments,
1252 SWAP,
1255 DUP,
1256 ADD,
1257 PUSHB_1,
1259 SUB, /* delta = (2*num_segments - 1) */
1261 PUSHB_6,
1262 sal_segment_offset,
1263 sal_segment_offset,
1265 sal_j,
1267 sal_base,
1269 WS, /* sal_base = 0 */
1270 WS, /* sal_j = 0 (point offset) */
1272 ROLL,
1273 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1275 /* `bci_create_segment_point' also increases the loop counter by 1; */
1276 /* this effectively means we have a loop step of 2 */
1277 PUSHB_2,
1278 bci_create_segment,
1279 bci_loop,
1280 CALL,
1282 PUSHB_1,
1283 bci_hint_glyph,
1284 CALL,
1286 ELSE,
1287 CLEAR,
1288 EIF,
1290 ENDF,
1296 * bci_create_segments_X
1298 * Top-level routines for calling `bci_create_segments'.
1301 unsigned char FPGM(bci_create_segments_0) [] =
1304 PUSHB_1,
1305 bci_create_segments_0,
1306 FDEF,
1308 PUSHB_2,
1310 bci_create_segments,
1311 CALL,
1313 ENDF,
1317 unsigned char FPGM(bci_create_segments_1) [] =
1320 PUSHB_1,
1321 bci_create_segments_1,
1322 FDEF,
1324 PUSHB_2,
1326 bci_create_segments,
1327 CALL,
1329 ENDF,
1333 unsigned char FPGM(bci_create_segments_2) [] =
1336 PUSHB_1,
1337 bci_create_segments_2,
1338 FDEF,
1340 PUSHB_2,
1342 bci_create_segments,
1343 CALL,
1345 ENDF,
1349 unsigned char FPGM(bci_create_segments_3) [] =
1352 PUSHB_1,
1353 bci_create_segments_3,
1354 FDEF,
1356 PUSHB_2,
1358 bci_create_segments,
1359 CALL,
1361 ENDF,
1365 unsigned char FPGM(bci_create_segments_4) [] =
1368 PUSHB_1,
1369 bci_create_segments_4,
1370 FDEF,
1372 PUSHB_2,
1374 bci_create_segments,
1375 CALL,
1377 ENDF,
1381 unsigned char FPGM(bci_create_segments_5) [] =
1384 PUSHB_1,
1385 bci_create_segments_5,
1386 FDEF,
1388 PUSHB_2,
1390 bci_create_segments,
1391 CALL,
1393 ENDF,
1397 unsigned char FPGM(bci_create_segments_6) [] =
1400 PUSHB_1,
1401 bci_create_segments_6,
1402 FDEF,
1404 PUSHB_2,
1406 bci_create_segments,
1407 CALL,
1409 ENDF,
1413 unsigned char FPGM(bci_create_segments_7) [] =
1416 PUSHB_1,
1417 bci_create_segments_7,
1418 FDEF,
1420 PUSHB_2,
1422 bci_create_segments,
1423 CALL,
1425 ENDF,
1429 unsigned char FPGM(bci_create_segments_8) [] =
1432 PUSHB_1,
1433 bci_create_segments_8,
1434 FDEF,
1436 PUSHB_2,
1438 bci_create_segments,
1439 CALL,
1441 ENDF,
1445 unsigned char FPGM(bci_create_segments_9) [] =
1448 PUSHB_1,
1449 bci_create_segments_9,
1450 FDEF,
1452 PUSHB_2,
1454 bci_create_segments,
1455 CALL,
1457 ENDF,
1463 * bci_create_segments_composite
1465 * The same as `bci_create_segments'.
1466 * It also decrements the composite component counter.
1468 * sal: sal_num_packed_segments
1469 * sal_segment_offset
1471 * CVT: cvtl_is_subglyph
1473 * uses: bci_decrement_component_counter
1474 * bci_create_segment
1475 * bci_loop
1476 * bci_hint_glyph
1479 unsigned char FPGM(bci_create_segments_composite) [] =
1482 PUSHB_1,
1483 bci_create_segments_composite,
1484 FDEF,
1486 PUSHB_1,
1487 bci_decrement_component_counter,
1488 CALL,
1490 /* only do something if we are not a subglyph */
1491 PUSHB_2,
1493 cvtl_is_subglyph,
1494 RCVT,
1497 /* all our measurements are taken along the y axis */
1498 SVTCA_y,
1500 PUSHB_1,
1501 sal_num_packed_segments,
1502 SWAP,
1505 DUP,
1506 ADD,
1507 PUSHB_1,
1509 SUB, /* delta = (2*num_segments - 1) */
1511 PUSHB_6,
1512 sal_segment_offset,
1513 sal_segment_offset,
1515 sal_j,
1517 sal_base,
1519 WS, /* sal_base = 0 */
1520 WS, /* sal_j = 0 (point offset) */
1522 ROLL,
1523 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1525 /* `bci_create_segment_point' also increases the loop counter by 1; */
1526 /* this effectively means we have a loop step of 2 */
1527 PUSHB_2,
1528 bci_create_segment,
1529 bci_loop,
1530 CALL,
1532 PUSHB_1,
1533 bci_hint_glyph,
1534 CALL,
1536 ELSE,
1537 CLEAR,
1538 EIF,
1540 ENDF,
1546 * bci_create_segments_composite_X
1548 * Top-level routines for calling `bci_create_segments_composite'.
1551 unsigned char FPGM(bci_create_segments_composite_0) [] =
1554 PUSHB_1,
1555 bci_create_segments_composite_0,
1556 FDEF,
1558 PUSHB_2,
1560 bci_create_segments_composite,
1561 CALL,
1563 ENDF,
1567 unsigned char FPGM(bci_create_segments_composite_1) [] =
1570 PUSHB_1,
1571 bci_create_segments_composite_1,
1572 FDEF,
1574 PUSHB_2,
1576 bci_create_segments_composite,
1577 CALL,
1579 ENDF,
1583 unsigned char FPGM(bci_create_segments_composite_2) [] =
1586 PUSHB_1,
1587 bci_create_segments_composite_2,
1588 FDEF,
1590 PUSHB_2,
1592 bci_create_segments_composite,
1593 CALL,
1595 ENDF,
1599 unsigned char FPGM(bci_create_segments_composite_3) [] =
1602 PUSHB_1,
1603 bci_create_segments_composite_3,
1604 FDEF,
1606 PUSHB_2,
1608 bci_create_segments_composite,
1609 CALL,
1611 ENDF,
1615 unsigned char FPGM(bci_create_segments_composite_4) [] =
1618 PUSHB_1,
1619 bci_create_segments_composite_4,
1620 FDEF,
1622 PUSHB_2,
1624 bci_create_segments_composite,
1625 CALL,
1627 ENDF,
1631 unsigned char FPGM(bci_create_segments_composite_5) [] =
1634 PUSHB_1,
1635 bci_create_segments_composite_5,
1636 FDEF,
1638 PUSHB_2,
1640 bci_create_segments_composite,
1641 CALL,
1643 ENDF,
1647 unsigned char FPGM(bci_create_segments_composite_6) [] =
1650 PUSHB_1,
1651 bci_create_segments_composite_6,
1652 FDEF,
1654 PUSHB_2,
1656 bci_create_segments_composite,
1657 CALL,
1659 ENDF,
1663 unsigned char FPGM(bci_create_segments_composite_7) [] =
1666 PUSHB_1,
1667 bci_create_segments_composite_7,
1668 FDEF,
1670 PUSHB_2,
1672 bci_create_segments_composite,
1673 CALL,
1675 ENDF,
1679 unsigned char FPGM(bci_create_segments_composite_8) [] =
1682 PUSHB_1,
1683 bci_create_segments_composite_8,
1684 FDEF,
1686 PUSHB_2,
1688 bci_create_segments_composite,
1689 CALL,
1691 ENDF,
1695 unsigned char FPGM(bci_create_segments_composite_9) [] =
1698 PUSHB_1,
1699 bci_create_segments_composite_9,
1700 FDEF,
1702 PUSHB_2,
1704 bci_create_segments_composite,
1705 CALL,
1707 ENDF,
1713 * bci_align_segment
1715 * Align all points in a segment to the twilight point in rp0.
1716 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1718 * in: segment_index
1720 * sal: sal_segment_offset
1723 unsigned char FPGM(bci_align_segment) [] =
1726 PUSHB_1,
1727 bci_align_segment,
1728 FDEF,
1730 /* we need the values of `sal_segment_offset + 2*segment_index' */
1731 /* and `sal_segment_offset + 2*segment_index + 1' */
1732 DUP,
1733 ADD,
1734 PUSHB_1,
1735 sal_segment_offset,
1736 ADD,
1737 DUP,
1739 SWAP,
1740 PUSHB_1,
1742 ADD,
1743 RS, /* s: first last */
1745 /* start_loop: */
1746 PUSHB_1,
1748 CINDEX, /* s: first last first */
1749 PUSHB_1,
1751 CINDEX, /* s: first last first last */
1752 LTEQ, /* first <= end */
1753 IF, /* s: first last */
1754 SWAP,
1755 DUP, /* s: last first first */
1756 ALIGNRP, /* align point with index `first' with rp0 */
1758 PUSHB_1,
1760 ADD, /* first = first + 1 */
1761 SWAP, /* s: first last */
1763 PUSHB_1,
1765 NEG,
1766 JMPR, /* goto start_loop */
1768 ELSE,
1769 POP,
1770 POP,
1771 EIF,
1773 ENDF,
1779 * bci_align_segments
1781 * Align segments to the twilight point in rp0.
1782 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1784 * in: first_segment
1785 * loop_counter (N)
1786 * segment_1
1787 * segment_2
1788 * ...
1789 * segment_N
1791 * uses: bci_align_segment
1794 unsigned char FPGM(bci_align_segments) [] =
1797 PUSHB_1,
1798 bci_align_segments,
1799 FDEF,
1801 PUSHB_1,
1802 bci_align_segment,
1803 CALL,
1805 PUSHB_1,
1806 bci_align_segment,
1807 LOOPCALL,
1809 ENDF,
1815 * bci_scale_contour
1817 * Scale a contour using two points giving the maximum and minimum
1818 * coordinates.
1820 * It expects that no point on the contour is touched.
1822 * in: min_point
1823 * max_point
1825 * CVT: cvtl_scale
1826 * cvtl_0x10000
1829 unsigned char FPGM(bci_scale_contour) [] =
1832 PUSHB_1,
1833 bci_scale_contour,
1834 FDEF,
1836 DUP,
1837 DUP,
1838 GC_orig,
1839 DUP,
1840 DO_SCALE, /* min_pos_new = min_pos * scale */
1841 SWAP,
1842 SUB,
1843 SHPIX,
1845 /* don't scale a single-point contour twice */
1846 SWAP,
1847 DUP,
1848 ROLL,
1849 NEQ,
1851 DUP,
1852 GC_orig,
1853 DUP,
1854 DO_SCALE, /* max_pos_new = max_pos * scale */
1855 SWAP,
1856 SUB,
1857 SHPIX,
1859 ELSE,
1860 POP,
1861 EIF,
1863 ENDF,
1869 * bci_scale_glyph
1871 * Scale a glyph using a list of points (two points per contour, giving
1872 * the maximum and mininum coordinates).
1874 * It expects that no point in the glyph is touched.
1876 * Note that the point numbers are sorted in ascending order;
1877 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1878 * contour without specifying which one is the minimum and maximum.
1880 * in: num_contours (N)
1881 * min_point_1
1882 * max_point_1
1883 * min_point_2
1884 * max_point_2
1885 * ...
1886 * min_point_N
1887 * max_point_N
1889 * CVT: cvtl_is_subglyph
1891 * uses: bci_scale_contour
1894 unsigned char FPGM(bci_scale_glyph) [] =
1897 PUSHB_1,
1898 bci_scale_glyph,
1899 FDEF,
1901 /* only do something if we are not a subglyph */
1902 PUSHB_2,
1904 cvtl_is_subglyph,
1905 RCVT,
1908 /* all our measurements are taken along the y axis */
1909 SVTCA_y,
1911 PUSHB_1,
1913 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1915 PUSHB_1,
1916 bci_scale_contour,
1917 LOOPCALL,
1919 PUSHB_1,
1921 SZP2, /* set zp2 to normal zone 1 */
1922 IUP_y,
1924 ELSE,
1925 CLEAR,
1926 EIF,
1928 ENDF,
1934 * bci_scale_composite_glyph
1936 * The same as `bci_scale_composite_glyph'.
1937 * It also decrements the composite component counter.
1939 * CVT: cvtl_is_subglyph
1941 * uses: bci_decrement_component_counter
1942 * bci_scale_contour
1945 unsigned char FPGM(bci_scale_composite_glyph) [] =
1948 PUSHB_1,
1949 bci_scale_composite_glyph,
1950 FDEF,
1952 PUSHB_1,
1953 bci_decrement_component_counter,
1954 CALL,
1956 /* only do something if we are not a subglyph */
1957 PUSHB_2,
1959 cvtl_is_subglyph,
1960 RCVT,
1963 /* all our measurements are taken along the y axis */
1964 SVTCA_y,
1966 PUSHB_1,
1968 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1970 PUSHB_1,
1971 bci_scale_contour,
1972 LOOPCALL,
1974 PUSHB_1,
1976 SZP2, /* set zp2 to normal zone 1 */
1977 IUP_y,
1979 ELSE,
1980 CLEAR,
1981 EIF,
1983 ENDF,
1989 * bci_shift_contour
1991 * Shift a contour by a given amount.
1993 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1994 * point to the normal zone 1.
1996 * in: contour
1997 * out: contour + 1
2000 unsigned char FPGM(bci_shift_contour) [] =
2003 PUSHB_1,
2004 bci_shift_contour,
2005 FDEF,
2007 DUP,
2008 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2010 PUSHB_1,
2012 ADD,
2014 ENDF,
2020 * bci_shift_subglyph
2022 * Shift a subglyph. To be more specific, it corrects the already applied
2023 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2024 * also.
2026 * If this function is called, a point `x' in the subglyph has been scaled
2027 * already (during the hinting of the subglyph itself), and `offset' has
2028 * been applied also:
2030 * x -> x * scale + offset (1)
2032 * However, the offset should be applied first, then the scaling:
2034 * x -> (x + offset) * scale (2)
2036 * Our job is now to transform (1) to (2); a simple calculation shows that
2037 * we have to shift all points of the subglyph by
2039 * offset * scale - offset = offset * (scale - 1)
2041 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2043 * in: offset (in FUnits)
2044 * num_contours
2045 * first_contour
2047 * CVT: cvtl_funits_to_pixels
2048 * cvtl_0x10000
2049 * cvtl_scale
2051 * uses: bci_round
2052 * bci_shift_contour
2055 unsigned char FPGM(bci_shift_subglyph) [] =
2058 PUSHB_1,
2059 bci_shift_subglyph,
2060 FDEF,
2062 SVTCA_y,
2064 PUSHB_1,
2065 cvtl_funits_to_pixels,
2066 RCVT, /* scaling factor FUnits -> pixels */
2067 MUL,
2068 PUSHB_1,
2069 cvtl_0x10000,
2070 RCVT,
2071 DIV,
2073 /* the autohinter always rounds offsets */
2074 PUSHB_1,
2075 bci_round,
2076 CALL, /* offset = round(offset) */
2078 PUSHB_1,
2079 cvtl_scale,
2080 RCVT,
2081 MUL,
2082 PUSHB_1,
2083 cvtl_0x10000,
2084 RCVT,
2085 DIV, /* delta = offset * (scale - 1) */
2087 /* and round again */
2088 PUSHB_1,
2089 bci_round,
2090 CALL, /* offset = round(offset) */
2092 PUSHB_1,
2094 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2096 /* we create twilight point 0 as a reference point, */
2097 /* setting the original position to zero (using `cvtl_temp') */
2098 PUSHB_5,
2101 cvtl_temp,
2102 cvtl_temp,
2104 WCVTP,
2105 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2107 SWAP, /* s: first_contour num_contours 0 delta */
2108 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2110 PUSHB_2,
2111 bci_shift_contour,
2113 SZP2, /* set zp2 to normal zone 1 */
2114 LOOPCALL,
2116 ENDF,
2122 * bci_ip_outer_align_point
2124 * Auxiliary function for `bci_action_ip_before' and
2125 * `bci_action_ip_after'.
2127 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2128 * zone, and both zp1 and zp2 set to normal zone.
2130 * in: point
2132 * sal: sal_i (edge_orig_pos)
2134 * CVT: cvtl_scale
2135 * cvtl_0x10000
2138 unsigned char FPGM(bci_ip_outer_align_point) [] =
2141 PUSHB_1,
2142 bci_ip_outer_align_point,
2143 FDEF,
2145 DUP,
2146 ALIGNRP, /* align `point' with `edge' */
2147 DUP,
2148 GC_orig,
2149 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2151 PUSHB_1,
2152 sal_i,
2154 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2155 SHPIX,
2157 ENDF,
2163 * bci_ip_on_align_points
2165 * Auxiliary function for `bci_action_ip_on'.
2167 * in: edge (in twilight zone)
2168 * loop_counter (N)
2169 * point_1
2170 * point_2
2171 * ...
2172 * point_N
2175 unsigned char FPGM(bci_ip_on_align_points) [] =
2178 PUSHB_1,
2179 bci_ip_on_align_points,
2180 FDEF,
2182 MDAP_noround, /* set rp0 and rp1 to `edge' */
2184 SLOOP,
2185 ALIGNRP,
2187 ENDF,
2193 * bci_ip_between_align_point
2195 * Auxiliary function for `bci_ip_between_align_points'.
2197 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2198 * zone, and both zp1 and zp2 set to normal zone.
2200 * in: point
2202 * sal: sal_i (edge_orig_pos)
2203 * sal_j (stretch_factor)
2205 * CVT: cvtl_scale
2206 * cvtl_0x10000
2209 unsigned char FPGM(bci_ip_between_align_point) [] =
2212 PUSHB_1,
2213 bci_ip_between_align_point,
2214 FDEF,
2216 DUP,
2217 ALIGNRP, /* align `point' with `edge' */
2218 DUP,
2219 GC_orig,
2220 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2222 PUSHB_1,
2223 sal_i,
2225 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2226 PUSHB_1,
2227 sal_j,
2229 MUL, /* s: point delta */
2230 SHPIX,
2232 ENDF,
2238 * bci_ip_between_align_points
2240 * Auxiliary function for `bci_action_ip_between'.
2242 * in: after_edge (in twilight zone)
2243 * before_edge (in twilight zone)
2244 * loop_counter (N)
2245 * point_1
2246 * point_2
2247 * ...
2248 * point_N
2250 * sal: sal_i (before_orig_pos)
2251 * sal_j (stretch_factor)
2253 * uses: bci_ip_between_align_point
2256 unsigned char FPGM(bci_ip_between_align_points) [] =
2259 PUSHB_1,
2260 bci_ip_between_align_points,
2261 FDEF,
2263 PUSHB_2,
2266 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2267 CINDEX,
2268 DUP, /* s: ... before after before before */
2269 MDAP_noround, /* set rp0 and rp1 to `before' */
2270 DUP,
2271 GC_orig, /* s: ... before after before before_orig_pos */
2272 PUSHB_1,
2273 sal_i,
2274 SWAP,
2275 WS, /* sal_i = before_orig_pos */
2276 PUSHB_1,
2278 CINDEX, /* s: ... before after before after */
2279 MD_cur, /* a = after_pos - before_pos */
2280 ROLL,
2281 ROLL,
2282 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2284 DUP,
2285 IF, /* b != 0 ? */
2286 DIV, /* s: a/b */
2287 ELSE,
2288 POP, /* avoid division by zero */
2289 EIF,
2291 PUSHB_1,
2292 sal_j,
2293 SWAP,
2294 WS, /* sal_j = stretch_factor */
2296 PUSHB_3,
2297 bci_ip_between_align_point,
2300 SZP2, /* set zp2 to normal zone 1 */
2301 SZP1, /* set zp1 to normal zone 1 */
2302 LOOPCALL,
2304 ENDF,
2310 * bci_action_ip_before
2312 * Handle `ip_before' data to align points located before the first edge.
2314 * in: first_edge (in twilight zone)
2315 * loop_counter (N)
2316 * point_1
2317 * point_2
2318 * ...
2319 * point_N
2321 * sal: sal_i (first_edge_orig_pos)
2323 * uses: bci_ip_outer_align_point
2326 unsigned char FPGM(bci_action_ip_before) [] =
2329 PUSHB_1,
2330 bci_action_ip_before,
2331 FDEF,
2333 PUSHB_1,
2335 SZP2, /* set zp2 to twilight zone 0 */
2337 DUP,
2338 GC_orig,
2339 PUSHB_1,
2340 sal_i,
2341 SWAP,
2342 WS, /* sal_i = first_edge_orig_pos */
2344 PUSHB_3,
2348 SZP2, /* set zp2 to normal zone 1 */
2349 SZP1, /* set zp1 to normal zone 1 */
2350 SZP0, /* set zp0 to twilight zone 0 */
2352 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2354 PUSHB_1,
2355 bci_ip_outer_align_point,
2356 LOOPCALL,
2358 ENDF,
2364 * bci_action_ip_after
2366 * Handle `ip_after' data to align points located after the last edge.
2368 * in: last_edge (in twilight zone)
2369 * loop_counter (N)
2370 * point_1
2371 * point_2
2372 * ...
2373 * point_N
2375 * sal: sal_i (last_edge_orig_pos)
2377 * uses: bci_ip_outer_align_point
2380 unsigned char FPGM(bci_action_ip_after) [] =
2383 PUSHB_1,
2384 bci_action_ip_after,
2385 FDEF,
2387 PUSHB_1,
2389 SZP2, /* set zp2 to twilight zone 0 */
2391 DUP,
2392 GC_orig,
2393 PUSHB_1,
2394 sal_i,
2395 SWAP,
2396 WS, /* sal_i = last_edge_orig_pos */
2398 PUSHB_3,
2402 SZP2, /* set zp2 to normal zone 1 */
2403 SZP1, /* set zp1 to normal zone 1 */
2404 SZP0, /* set zp0 to twilight zone 0 */
2406 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2408 PUSHB_1,
2409 bci_ip_outer_align_point,
2410 LOOPCALL,
2412 ENDF,
2418 * bci_action_ip_on
2420 * Handle `ip_on' data to align points located on an edge coordinate (but
2421 * not part of an edge).
2423 * in: loop_counter (M)
2424 * edge_1 (in twilight zone)
2425 * loop_counter (N_1)
2426 * point_1
2427 * point_2
2428 * ...
2429 * point_N_1
2430 * edge_2 (in twilight zone)
2431 * loop_counter (N_2)
2432 * point_1
2433 * point_2
2434 * ...
2435 * point_N_2
2436 * ...
2437 * edge_M (in twilight zone)
2438 * loop_counter (N_M)
2439 * point_1
2440 * point_2
2441 * ...
2442 * point_N_M
2444 * uses: bci_ip_on_align_points
2447 unsigned char FPGM(bci_action_ip_on) [] =
2450 PUSHB_1,
2451 bci_action_ip_on,
2452 FDEF,
2454 PUSHB_2,
2457 SZP1, /* set zp1 to normal zone 1 */
2458 SZP0, /* set zp0 to twilight zone 0 */
2460 PUSHB_1,
2461 bci_ip_on_align_points,
2462 LOOPCALL,
2464 ENDF,
2470 * bci_action_ip_between
2472 * Handle `ip_between' data to align points located between two edges.
2474 * in: loop_counter (M)
2475 * before_edge_1 (in twilight zone)
2476 * after_edge_1 (in twilight zone)
2477 * loop_counter (N_1)
2478 * point_1
2479 * point_2
2480 * ...
2481 * point_N_1
2482 * before_edge_2 (in twilight zone)
2483 * after_edge_2 (in twilight zone)
2484 * loop_counter (N_2)
2485 * point_1
2486 * point_2
2487 * ...
2488 * point_N_2
2489 * ...
2490 * before_edge_M (in twilight zone)
2491 * after_edge_M (in twilight zone)
2492 * loop_counter (N_M)
2493 * point_1
2494 * point_2
2495 * ...
2496 * point_N_M
2498 * uses: bci_ip_between_align_points
2501 unsigned char FPGM(bci_action_ip_between) [] =
2504 PUSHB_1,
2505 bci_action_ip_between,
2506 FDEF,
2508 PUSHB_1,
2509 bci_ip_between_align_points,
2510 LOOPCALL,
2512 ENDF,
2518 * bci_adjust_common
2520 * Common code for bci_action_adjust routines.
2522 * uses: func[cvtl_stem_width_function]
2525 unsigned char FPGM(bci_adjust_common) [] =
2528 PUSHB_1,
2529 bci_adjust_common,
2530 FDEF,
2532 PUSHB_1,
2534 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2536 PUSHB_1,
2538 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2539 PUSHB_1,
2541 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2542 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2544 PUSHB_1,
2545 cvtl_stem_width_function,
2546 RCVT,
2547 CALL,
2548 NEG, /* s: [...] edge2 edge -cur_len */
2550 ROLL, /* s: [...] edge -cur_len edge2 */
2551 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2552 SWAP,
2553 DUP,
2554 DUP, /* s: [...] -cur_len edge edge edge */
2555 ALIGNRP, /* align `edge' with `edge2' */
2556 ROLL,
2557 SHPIX, /* shift `edge' by -cur_len */
2559 ENDF,
2565 * bci_adjust_bound
2567 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2568 * edge of the stem has already been moved, then moving it again if
2569 * necessary to stay bound.
2571 * in: edge2_is_serif
2572 * edge_is_round
2573 * edge_point (in twilight zone)
2574 * edge2_point (in twilight zone)
2575 * edge[-1] (in twilight zone)
2576 * ... stuff for bci_align_segments (edge) ...
2578 * uses: bci_adjust_common
2579 * bci_align_segments
2582 unsigned char FPGM(bci_adjust_bound) [] =
2585 PUSHB_1,
2586 bci_adjust_bound,
2587 FDEF,
2589 PUSHB_1,
2590 bci_adjust_common,
2591 CALL,
2593 SWAP, /* s: edge edge[-1] */
2594 DUP,
2595 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2596 GC_cur,
2597 PUSHB_1,
2599 CINDEX,
2600 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2601 GT, /* edge_pos < edge[-1]_pos */
2603 DUP,
2604 ALIGNRP, /* align `edge' to `edge[-1]' */
2605 EIF,
2607 MDAP_noround, /* set rp0 and rp1 to `edge' */
2609 PUSHB_2,
2610 bci_align_segments,
2612 SZP1, /* set zp1 to normal zone 1 */
2613 CALL,
2615 ENDF,
2621 * bci_action_adjust_bound
2622 * bci_action_adjust_bound_serif
2623 * bci_action_adjust_bound_round
2624 * bci_action_adjust_bound_round_serif
2626 * Higher-level routines for calling `bci_adjust_bound'.
2629 unsigned char FPGM(bci_action_adjust_bound) [] =
2632 PUSHB_1,
2633 bci_action_adjust_bound,
2634 FDEF,
2636 PUSHB_3,
2639 bci_adjust_bound,
2640 CALL,
2642 ENDF,
2646 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2649 PUSHB_1,
2650 bci_action_adjust_bound_serif,
2651 FDEF,
2653 PUSHB_3,
2656 bci_adjust_bound,
2657 CALL,
2659 ENDF,
2663 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2666 PUSHB_1,
2667 bci_action_adjust_bound_round,
2668 FDEF,
2670 PUSHB_3,
2673 bci_adjust_bound,
2674 CALL,
2676 ENDF,
2680 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2683 PUSHB_1,
2684 bci_action_adjust_bound_round_serif,
2685 FDEF,
2687 PUSHB_3,
2690 bci_adjust_bound,
2691 CALL,
2693 ENDF,
2699 * bci_adjust
2701 * Handle the ADJUST action to align an edge of a stem if the other edge
2702 * of the stem has already been moved.
2704 * in: edge2_is_serif
2705 * edge_is_round
2706 * edge_point (in twilight zone)
2707 * edge2_point (in twilight zone)
2708 * ... stuff for bci_align_segments (edge) ...
2710 * uses: bci_adjust_common
2711 * bci_align_segments
2714 unsigned char FPGM(bci_adjust) [] =
2717 PUSHB_1,
2718 bci_adjust,
2719 FDEF,
2721 PUSHB_1,
2722 bci_adjust_common,
2723 CALL,
2725 MDAP_noround, /* set rp0 and rp1 to `edge' */
2727 PUSHB_2,
2728 bci_align_segments,
2730 SZP1, /* set zp1 to normal zone 1 */
2731 CALL,
2733 ENDF,
2739 * bci_action_adjust
2740 * bci_action_adjust_serif
2741 * bci_action_adjust_round
2742 * bci_action_adjust_round_serif
2744 * Higher-level routines for calling `bci_adjust'.
2747 unsigned char FPGM(bci_action_adjust) [] =
2750 PUSHB_1,
2751 bci_action_adjust,
2752 FDEF,
2754 PUSHB_3,
2757 bci_adjust,
2758 CALL,
2760 ENDF,
2764 unsigned char FPGM(bci_action_adjust_serif) [] =
2767 PUSHB_1,
2768 bci_action_adjust_serif,
2769 FDEF,
2771 PUSHB_3,
2774 bci_adjust,
2775 CALL,
2777 ENDF,
2781 unsigned char FPGM(bci_action_adjust_round) [] =
2784 PUSHB_1,
2785 bci_action_adjust_round,
2786 FDEF,
2788 PUSHB_3,
2791 bci_adjust,
2792 CALL,
2794 ENDF,
2798 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2801 PUSHB_1,
2802 bci_action_adjust_round_serif,
2803 FDEF,
2805 PUSHB_3,
2808 bci_adjust,
2809 CALL,
2811 ENDF,
2817 * bci_stem_common
2819 * Common code for bci_action_stem routines.
2821 * sal: sal_anchor
2822 * sal_temp1
2823 * sal_temp2
2824 * sal_temp3
2826 * uses: func[cvtl_stem_width_function]
2827 * bci_round
2830 #undef sal_u_off
2831 #define sal_u_off sal_temp1
2832 #undef sal_d_off
2833 #define sal_d_off sal_temp2
2834 #undef sal_org_len
2835 #define sal_org_len sal_temp3
2836 #undef sal_edge2
2837 #define sal_edge2 sal_temp3
2839 unsigned char FPGM(bci_stem_common) [] =
2842 PUSHB_1,
2843 bci_stem_common,
2844 FDEF,
2846 PUSHB_1,
2848 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2850 PUSHB_1,
2852 CINDEX,
2853 PUSHB_1,
2855 CINDEX,
2856 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2857 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2859 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2860 DUP,
2861 PUSHB_1,
2862 sal_org_len,
2863 SWAP,
2866 PUSHB_1,
2867 cvtl_stem_width_function,
2868 RCVT,
2869 CALL, /* s: [...] edge2 edge cur_len */
2871 DUP,
2872 PUSHB_1,
2874 LT, /* cur_len < 96 */
2876 DUP,
2877 PUSHB_1,
2879 LTEQ, /* cur_len <= 64 */
2881 PUSHB_4,
2882 sal_u_off,
2884 sal_d_off,
2887 ELSE,
2888 PUSHB_4,
2889 sal_u_off,
2891 sal_d_off,
2893 EIF,
2897 SWAP, /* s: [...] edge2 cur_len edge */
2898 DUP,
2899 PUSHB_1,
2900 sal_anchor,
2902 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2903 ROLL,
2904 SWAP,
2905 MD_orig_ZP2_0,
2906 SWAP,
2907 GC_cur,
2908 ADD, /* s: [...] edge2 cur_len edge org_pos */
2909 PUSHB_1,
2910 sal_org_len,
2912 PUSHB_1,
2913 2*64,
2914 DIV,
2915 ADD, /* s: [...] edge2 cur_len edge org_center */
2917 DUP,
2918 PUSHB_1,
2919 bci_round,
2920 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2922 DUP,
2923 ROLL,
2924 ROLL,
2925 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2927 DUP,
2928 PUSHB_1,
2929 sal_u_off,
2931 ADD,
2932 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2934 SWAP,
2935 PUSHB_1,
2936 sal_d_off,
2938 SUB,
2939 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2941 LT, /* delta1 < delta2 */
2943 PUSHB_1,
2944 sal_u_off,
2946 SUB, /* cur_pos1 = cur_pos1 - u_off */
2948 ELSE,
2949 PUSHB_1,
2950 sal_d_off,
2952 ADD, /* cur_pos1 = cur_pos1 + d_off */
2953 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2955 PUSHB_1,
2957 CINDEX,
2958 PUSHB_1,
2959 2*64,
2960 DIV,
2961 SUB, /* arg = cur_pos1 - cur_len/2 */
2963 SWAP, /* s: [...] edge2 cur_len arg edge */
2964 DUP,
2965 DUP,
2966 PUSHB_1,
2968 MINDEX,
2969 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2970 GC_cur,
2971 SUB,
2972 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2974 ELSE,
2975 SWAP, /* s: [...] edge2 cur_len edge */
2976 PUSHB_1,
2977 sal_anchor,
2979 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
2980 PUSHB_1,
2982 CINDEX,
2983 PUSHB_1,
2984 sal_anchor,
2986 MD_orig_ZP2_0,
2987 ADD, /* s: [...] edge2 cur_len edge org_pos */
2989 DUP,
2990 PUSHB_1,
2991 sal_org_len,
2993 PUSHB_1,
2994 2*64,
2995 DIV,
2996 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2998 SWAP,
2999 DUP,
3000 PUSHB_1,
3001 bci_round,
3002 CALL, /* cur_pos1 = ROUND(org_pos) */
3003 SWAP,
3004 PUSHB_1,
3005 sal_org_len,
3007 ADD,
3008 PUSHB_1,
3009 bci_round,
3010 CALL,
3011 PUSHB_1,
3013 CINDEX,
3014 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3016 PUSHB_1,
3018 CINDEX,
3019 PUSHB_1,
3020 2*64,
3021 DIV,
3022 PUSHB_1,
3024 MINDEX,
3025 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3027 DUP,
3028 PUSHB_1,
3030 CINDEX,
3031 ADD,
3032 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3033 SWAP,
3034 PUSHB_1,
3036 CINDEX,
3037 ADD,
3038 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3039 LT, /* delta1 < delta2 */
3041 POP, /* arg = cur_pos1 */
3043 ELSE,
3044 SWAP,
3045 POP, /* arg = cur_pos2 */
3046 EIF, /* s: [...] edge2 cur_len edge arg */
3047 SWAP,
3048 DUP,
3049 DUP,
3050 PUSHB_1,
3052 MINDEX,
3053 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3054 GC_cur,
3055 SUB,
3056 SHPIX, /* edge = arg */
3057 EIF, /* s: [...] edge2 cur_len edge */
3059 ENDF,
3065 * bci_stem_bound
3067 * Handle the STEM action to align two edges of a stem, then moving one
3068 * edge again if necessary to stay bound.
3070 * The code after computing `cur_len' to shift `edge' and `edge2'
3071 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3073 * if cur_len < 96:
3074 * if cur_len < = 64:
3075 * u_off = 32
3076 * d_off = 32
3077 * else:
3078 * u_off = 38
3079 * d_off = 26
3081 * org_pos = anchor + (edge_orig - anchor_orig);
3082 * org_center = org_pos + org_len / 2;
3084 * cur_pos1 = ROUND(org_center)
3085 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3086 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3087 * if (delta1 < delta2):
3088 * cur_pos1 = cur_pos1 - u_off
3089 * else:
3090 * cur_pos1 = cur_pos1 + d_off
3092 * edge = cur_pos1 - cur_len / 2
3094 * else:
3095 * org_pos = anchor + (edge_orig - anchor_orig)
3096 * org_center = org_pos + org_len / 2;
3098 * cur_pos1 = ROUND(org_pos)
3099 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3100 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3101 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3103 * if (delta1 < delta2):
3104 * edge = cur_pos1
3105 * else:
3106 * edge = cur_pos2
3108 * edge2 = edge + cur_len
3110 * in: edge2_is_serif
3111 * edge_is_round
3112 * edge_point (in twilight zone)
3113 * edge2_point (in twilight zone)
3114 * edge[-1] (in twilight zone)
3115 * ... stuff for bci_align_segments (edge) ...
3116 * ... stuff for bci_align_segments (edge2)...
3118 * sal: sal_anchor
3119 * sal_temp1
3120 * sal_temp2
3121 * sal_temp3
3123 * uses: bci_stem_common
3124 * bci_align_segments
3127 unsigned char FPGM(bci_stem_bound) [] =
3130 PUSHB_1,
3131 bci_stem_bound,
3132 FDEF,
3134 PUSHB_1,
3135 bci_stem_common,
3136 CALL,
3138 ROLL, /* s: edge[-1] cur_len edge edge2 */
3139 DUP,
3140 DUP,
3141 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3142 PUSHB_1,
3143 sal_edge2,
3144 SWAP,
3145 WS, /* s: edge[-1] cur_len edge edge2 */
3146 ROLL,
3147 SHPIX, /* edge2 = edge + cur_len */
3149 SWAP, /* s: edge edge[-1] */
3150 DUP,
3151 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3152 GC_cur,
3153 PUSHB_1,
3155 CINDEX,
3156 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3157 GT, /* edge_pos < edge[-1]_pos */
3159 DUP,
3160 ALIGNRP, /* align `edge' to `edge[-1]' */
3161 EIF,
3163 MDAP_noround, /* set rp0 and rp1 to `edge' */
3165 PUSHB_2,
3166 bci_align_segments,
3168 SZP1, /* set zp1 to normal zone 1 */
3169 CALL,
3171 PUSHB_1,
3172 sal_edge2,
3174 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3176 PUSHB_1,
3177 bci_align_segments,
3178 CALL,
3180 ENDF,
3186 * bci_action_stem_bound
3187 * bci_action_stem_bound_serif
3188 * bci_action_stem_bound_round
3189 * bci_action_stem_bound_round_serif
3191 * Higher-level routines for calling `bci_stem_bound'.
3194 unsigned char FPGM(bci_action_stem_bound) [] =
3197 PUSHB_1,
3198 bci_action_stem_bound,
3199 FDEF,
3201 PUSHB_3,
3204 bci_stem_bound,
3205 CALL,
3207 ENDF,
3211 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3214 PUSHB_1,
3215 bci_action_stem_bound_serif,
3216 FDEF,
3218 PUSHB_3,
3221 bci_stem_bound,
3222 CALL,
3224 ENDF,
3228 unsigned char FPGM(bci_action_stem_bound_round) [] =
3231 PUSHB_1,
3232 bci_action_stem_bound_round,
3233 FDEF,
3235 PUSHB_3,
3238 bci_stem_bound,
3239 CALL,
3241 ENDF,
3245 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3248 PUSHB_1,
3249 bci_action_stem_bound_round_serif,
3250 FDEF,
3252 PUSHB_3,
3255 bci_stem_bound,
3256 CALL,
3258 ENDF,
3264 * bci_stem
3266 * Handle the STEM action to align two edges of a stem.
3268 * See `bci_stem_bound' for more details.
3270 * in: edge2_is_serif
3271 * edge_is_round
3272 * edge_point (in twilight zone)
3273 * edge2_point (in twilight zone)
3274 * ... stuff for bci_align_segments (edge) ...
3275 * ... stuff for bci_align_segments (edge2)...
3277 * sal: sal_anchor
3278 * sal_temp1
3279 * sal_temp2
3280 * sal_temp3
3282 * uses: bci_stem_common
3283 * bci_align_segments
3286 unsigned char FPGM(bci_stem) [] =
3289 PUSHB_1,
3290 bci_stem,
3291 FDEF,
3293 PUSHB_1,
3294 bci_stem_common,
3295 CALL,
3297 POP,
3298 SWAP, /* s: cur_len edge2 */
3299 DUP,
3300 DUP,
3301 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3302 PUSHB_1,
3303 sal_edge2,
3304 SWAP,
3305 WS, /* s: cur_len edge2 */
3306 SWAP,
3307 SHPIX, /* edge2 = edge + cur_len */
3309 PUSHB_2,
3310 bci_align_segments,
3312 SZP1, /* set zp1 to normal zone 1 */
3313 CALL,
3315 PUSHB_1,
3316 sal_edge2,
3318 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3320 PUSHB_1,
3321 bci_align_segments,
3322 CALL,
3323 ENDF,
3329 * bci_action_stem
3330 * bci_action_stem_serif
3331 * bci_action_stem_round
3332 * bci_action_stem_round_serif
3334 * Higher-level routines for calling `bci_stem'.
3337 unsigned char FPGM(bci_action_stem) [] =
3340 PUSHB_1,
3341 bci_action_stem,
3342 FDEF,
3344 PUSHB_3,
3347 bci_stem,
3348 CALL,
3350 ENDF,
3354 unsigned char FPGM(bci_action_stem_serif) [] =
3357 PUSHB_1,
3358 bci_action_stem_serif,
3359 FDEF,
3361 PUSHB_3,
3364 bci_stem,
3365 CALL,
3367 ENDF,
3371 unsigned char FPGM(bci_action_stem_round) [] =
3374 PUSHB_1,
3375 bci_action_stem_round,
3376 FDEF,
3378 PUSHB_3,
3381 bci_stem,
3382 CALL,
3384 ENDF,
3388 unsigned char FPGM(bci_action_stem_round_serif) [] =
3391 PUSHB_1,
3392 bci_action_stem_round_serif,
3393 FDEF,
3395 PUSHB_3,
3398 bci_stem,
3399 CALL,
3401 ENDF,
3407 * bci_link
3409 * Handle the LINK action to link an edge to another one.
3411 * in: stem_is_serif
3412 * base_is_round
3413 * base_point (in twilight zone)
3414 * stem_point (in twilight zone)
3415 * ... stuff for bci_align_segments (base) ...
3417 * uses: func[cvtl_stem_width_function]
3418 * bci_align_segments
3421 unsigned char FPGM(bci_link) [] =
3424 PUSHB_1,
3425 bci_link,
3426 FDEF,
3428 PUSHB_1,
3430 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3432 PUSHB_1,
3434 CINDEX,
3435 PUSHB_1,
3437 MINDEX,
3438 DUP, /* s: stem is_round is_serif stem base base */
3439 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3441 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3443 PUSHB_1,
3444 cvtl_stem_width_function,
3445 RCVT,
3446 CALL, /* s: stem new_dist */
3448 SWAP,
3449 DUP,
3450 ALIGNRP, /* align `stem_point' with `base_point' */
3451 DUP,
3452 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3453 SWAP,
3454 SHPIX, /* stem_point = base_point + new_dist */
3456 PUSHB_2,
3457 bci_align_segments,
3459 SZP1, /* set zp1 to normal zone 1 */
3460 CALL,
3462 ENDF,
3468 * bci_action_link
3469 * bci_action_link_serif
3470 * bci_action_link_round
3471 * bci_action_link_round_serif
3473 * Higher-level routines for calling `bci_link'.
3476 unsigned char FPGM(bci_action_link) [] =
3479 PUSHB_1,
3480 bci_action_link,
3481 FDEF,
3483 PUSHB_3,
3486 bci_link,
3487 CALL,
3489 ENDF,
3493 unsigned char FPGM(bci_action_link_serif) [] =
3496 PUSHB_1,
3497 bci_action_link_serif,
3498 FDEF,
3500 PUSHB_3,
3503 bci_link,
3504 CALL,
3506 ENDF,
3510 unsigned char FPGM(bci_action_link_round) [] =
3513 PUSHB_1,
3514 bci_action_link_round,
3515 FDEF,
3517 PUSHB_3,
3520 bci_link,
3521 CALL,
3523 ENDF,
3527 unsigned char FPGM(bci_action_link_round_serif) [] =
3530 PUSHB_1,
3531 bci_action_link_round_serif,
3532 FDEF,
3534 PUSHB_3,
3537 bci_link,
3538 CALL,
3540 ENDF,
3546 * bci_anchor
3548 * Handle the ANCHOR action to align two edges
3549 * and to set the edge anchor.
3551 * The code after computing `cur_len' to shift `edge' and `edge2'
3552 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3554 * if cur_len < 96:
3555 * if cur_len < = 64:
3556 * u_off = 32
3557 * d_off = 32
3558 * else:
3559 * u_off = 38
3560 * d_off = 26
3562 * org_center = edge_orig + org_len / 2
3563 * cur_pos1 = ROUND(org_center)
3565 * error1 = ABS(org_center - (cur_pos1 - u_off))
3566 * error2 = ABS(org_center - (cur_pos1 + d_off))
3567 * if (error1 < error2):
3568 * cur_pos1 = cur_pos1 - u_off
3569 * else:
3570 * cur_pos1 = cur_pos1 + d_off
3572 * edge = cur_pos1 - cur_len / 2
3573 * edge2 = edge + cur_len
3575 * else:
3576 * edge = ROUND(edge_orig)
3578 * in: edge2_is_serif
3579 * edge_is_round
3580 * edge_point (in twilight zone)
3581 * edge2_point (in twilight zone)
3582 * ... stuff for bci_align_segments (edge) ...
3584 * sal: sal_anchor
3585 * sal_temp1
3586 * sal_temp2
3587 * sal_temp3
3589 * uses: func[cvtl_stem_width_function]
3590 * bci_round
3591 * bci_align_segments
3594 #undef sal_u_off
3595 #define sal_u_off sal_temp1
3596 #undef sal_d_off
3597 #define sal_d_off sal_temp2
3598 #undef sal_org_len
3599 #define sal_org_len sal_temp3
3601 unsigned char FPGM(bci_anchor) [] =
3604 PUSHB_1,
3605 bci_anchor,
3606 FDEF,
3608 /* store anchor point number in `sal_anchor' */
3609 PUSHB_2,
3610 sal_anchor,
3612 CINDEX,
3613 WS, /* sal_anchor = edge_point */
3615 PUSHB_1,
3617 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3619 PUSHB_1,
3621 CINDEX,
3622 PUSHB_1,
3624 CINDEX,
3625 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3626 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3628 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3629 DUP,
3630 PUSHB_1,
3631 sal_org_len,
3632 SWAP,
3635 PUSHB_1,
3636 cvtl_stem_width_function,
3637 RCVT,
3638 CALL, /* s: edge2 edge cur_len */
3640 DUP,
3641 PUSHB_1,
3643 LT, /* cur_len < 96 */
3645 DUP,
3646 PUSHB_1,
3648 LTEQ, /* cur_len <= 64 */
3650 PUSHB_4,
3651 sal_u_off,
3653 sal_d_off,
3656 ELSE,
3657 PUSHB_4,
3658 sal_u_off,
3660 sal_d_off,
3662 EIF,
3666 SWAP, /* s: edge2 cur_len edge */
3667 DUP, /* s: edge2 cur_len edge edge */
3669 GC_orig,
3670 PUSHB_1,
3671 sal_org_len,
3673 PUSHB_1,
3674 2*64,
3675 DIV,
3676 ADD, /* s: edge2 cur_len edge org_center */
3678 DUP,
3679 PUSHB_1,
3680 bci_round,
3681 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3683 DUP,
3684 ROLL,
3685 ROLL,
3686 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3688 DUP,
3689 PUSHB_1,
3690 sal_u_off,
3692 ADD,
3693 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3695 SWAP,
3696 PUSHB_1,
3697 sal_d_off,
3699 SUB,
3700 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3702 LT, /* error1 < error2 */
3704 PUSHB_1,
3705 sal_u_off,
3707 SUB, /* cur_pos1 = cur_pos1 - u_off */
3709 ELSE,
3710 PUSHB_1,
3711 sal_d_off,
3713 ADD, /* cur_pos1 = cur_pos1 + d_off */
3714 EIF, /* s: edge2 cur_len edge cur_pos1 */
3716 PUSHB_1,
3718 CINDEX,
3719 PUSHB_1,
3720 2*64,
3721 DIV,
3722 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3724 PUSHB_1,
3726 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3727 GC_cur,
3728 SUB,
3729 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3731 SWAP, /* s: cur_len edge2 */
3732 DUP,
3733 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3734 SWAP,
3735 SHPIX, /* edge2 = edge1 + cur_len */
3737 ELSE,
3738 POP, /* s: edge2 edge */
3739 DUP,
3740 DUP,
3741 GC_cur,
3742 SWAP,
3743 GC_orig,
3744 PUSHB_1,
3745 bci_round,
3746 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3747 SWAP,
3748 SUB,
3749 SHPIX, /* edge = round(edge_orig) */
3751 /* clean up stack */
3752 POP,
3753 EIF,
3755 PUSHB_2,
3756 bci_align_segments,
3758 SZP1, /* set zp1 to normal zone 1 */
3759 CALL,
3761 ENDF,
3767 * bci_action_anchor
3768 * bci_action_anchor_serif
3769 * bci_action_anchor_round
3770 * bci_action_anchor_round_serif
3772 * Higher-level routines for calling `bci_anchor'.
3775 unsigned char FPGM(bci_action_anchor) [] =
3778 PUSHB_1,
3779 bci_action_anchor,
3780 FDEF,
3782 PUSHB_3,
3785 bci_anchor,
3786 CALL,
3788 ENDF,
3792 unsigned char FPGM(bci_action_anchor_serif) [] =
3795 PUSHB_1,
3796 bci_action_anchor_serif,
3797 FDEF,
3799 PUSHB_3,
3802 bci_anchor,
3803 CALL,
3805 ENDF,
3809 unsigned char FPGM(bci_action_anchor_round) [] =
3812 PUSHB_1,
3813 bci_action_anchor_round,
3814 FDEF,
3816 PUSHB_3,
3819 bci_anchor,
3820 CALL,
3822 ENDF,
3826 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3829 PUSHB_1,
3830 bci_action_anchor_round_serif,
3831 FDEF,
3833 PUSHB_3,
3836 bci_anchor,
3837 CALL,
3839 ENDF,
3845 * bci_action_blue_anchor
3847 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3848 * and to set the edge anchor.
3850 * in: anchor_point (in twilight zone)
3851 * blue_cvt_idx
3852 * edge_point (in twilight zone)
3853 * ... stuff for bci_align_segments (edge) ...
3855 * sal: sal_anchor
3857 * uses: bci_action_blue
3860 unsigned char FPGM(bci_action_blue_anchor) [] =
3863 PUSHB_1,
3864 bci_action_blue_anchor,
3865 FDEF,
3867 /* store anchor point number in `sal_anchor' */
3868 PUSHB_1,
3869 sal_anchor,
3870 SWAP,
3873 PUSHB_1,
3874 bci_action_blue,
3875 CALL,
3877 ENDF,
3883 * bci_action_blue
3885 * Handle the BLUE action to align an edge with a blue zone.
3887 * in: blue_cvt_idx
3888 * edge_point (in twilight zone)
3889 * ... stuff for bci_align_segments (edge) ...
3891 * uses: bci_align_segments
3894 unsigned char FPGM(bci_action_blue) [] =
3897 PUSHB_1,
3898 bci_action_blue,
3899 FDEF,
3901 PUSHB_1,
3903 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3905 /* move `edge_point' to `blue_cvt_idx' position; */
3906 /* note that we can't use MIAP since this would modify */
3907 /* the twilight point's original coordinates also */
3908 RCVT,
3909 SWAP,
3910 DUP,
3911 MDAP_noround, /* set rp0 and rp1 to `edge' */
3912 DUP,
3913 GC_cur, /* s: new_pos edge edge_pos */
3914 ROLL,
3915 SWAP,
3916 SUB, /* s: edge (new_pos - edge_pos) */
3917 SHPIX,
3919 PUSHB_2,
3920 bci_align_segments,
3922 SZP1, /* set zp1 to normal zone 1 */
3923 CALL,
3925 ENDF,
3931 * bci_serif_common
3933 * Common code for bci_action_serif routines.
3936 unsigned char FPGM(bci_serif_common) [] =
3939 PUSHB_1,
3940 bci_serif_common,
3941 FDEF,
3943 PUSHB_1,
3945 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3947 DUP,
3948 DUP,
3949 DUP,
3950 PUSHB_1,
3952 MINDEX, /* s: [...] serif serif serif serif base */
3953 DUP,
3954 MDAP_noround, /* set rp0 and rp1 to `base_point' */
3955 MD_orig_ZP2_0,
3956 SWAP,
3957 ALIGNRP, /* align `serif_point' with `base_point' */
3958 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
3960 ENDF,
3966 * bci_lower_bound
3968 * Move an edge if necessary to stay within a lower bound.
3970 * in: edge
3971 * bound
3973 * uses: bci_align_segments
3976 unsigned char FPGM(bci_lower_bound) [] =
3979 PUSHB_1,
3980 bci_lower_bound,
3981 FDEF,
3983 SWAP, /* s: edge bound */
3984 DUP,
3985 MDAP_noround, /* set rp0 and rp1 to `bound' */
3986 GC_cur,
3987 PUSHB_1,
3989 CINDEX,
3990 GC_cur, /* s: edge bound_pos edge_pos */
3991 GT, /* edge_pos < bound_pos */
3993 DUP,
3994 ALIGNRP, /* align `edge' to `bound' */
3995 EIF,
3997 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3999 PUSHB_2,
4000 bci_align_segments,
4002 SZP1, /* set zp1 to normal zone 1 */
4003 CALL,
4005 ENDF,
4011 * bci_upper_bound
4013 * Move an edge if necessary to stay within an upper bound.
4015 * in: edge
4016 * bound
4018 * uses: bci_align_segments
4021 unsigned char FPGM(bci_upper_bound) [] =
4024 PUSHB_1,
4025 bci_upper_bound,
4026 FDEF,
4028 SWAP, /* s: edge bound */
4029 DUP,
4030 MDAP_noround, /* set rp0 and rp1 to `bound' */
4031 GC_cur,
4032 PUSHB_1,
4034 CINDEX,
4035 GC_cur, /* s: edge bound_pos edge_pos */
4036 LT, /* edge_pos > bound_pos */
4038 DUP,
4039 ALIGNRP, /* align `edge' to `bound' */
4040 EIF,
4042 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4044 PUSHB_2,
4045 bci_align_segments,
4047 SZP1, /* set zp1 to normal zone 1 */
4048 CALL,
4050 ENDF,
4056 * bci_upper_lower_bound
4058 * Move an edge if necessary to stay within a lower and lower bound.
4060 * in: edge
4061 * lower
4062 * upper
4064 * uses: bci_align_segments
4067 unsigned char FPGM(bci_upper_lower_bound) [] =
4070 PUSHB_1,
4071 bci_upper_lower_bound,
4072 FDEF,
4074 SWAP, /* s: upper serif lower */
4075 DUP,
4076 MDAP_noround, /* set rp0 and rp1 to `lower' */
4077 GC_cur,
4078 PUSHB_1,
4080 CINDEX,
4081 GC_cur, /* s: upper serif lower_pos serif_pos */
4082 GT, /* serif_pos < lower_pos */
4084 DUP,
4085 ALIGNRP, /* align `serif' to `lower' */
4086 EIF,
4088 SWAP, /* s: serif upper */
4089 DUP,
4090 MDAP_noround, /* set rp0 and rp1 to `upper' */
4091 GC_cur,
4092 PUSHB_1,
4094 CINDEX,
4095 GC_cur, /* s: serif upper_pos serif_pos */
4096 LT, /* serif_pos > upper_pos */
4098 DUP,
4099 ALIGNRP, /* align `serif' to `upper' */
4100 EIF,
4102 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4104 PUSHB_2,
4105 bci_align_segments,
4107 SZP1, /* set zp1 to normal zone 1 */
4108 CALL,
4110 ENDF,
4116 * bci_action_serif
4118 * Handle the SERIF action to align a serif with its base.
4120 * in: serif_point (in twilight zone)
4121 * base_point (in twilight zone)
4122 * ... stuff for bci_align_segments (serif) ...
4124 * uses: bci_serif_common
4125 * bci_align_segments
4128 unsigned char FPGM(bci_action_serif) [] =
4131 PUSHB_1,
4132 bci_action_serif,
4133 FDEF,
4135 PUSHB_1,
4136 bci_serif_common,
4137 CALL,
4139 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4141 PUSHB_2,
4142 bci_align_segments,
4144 SZP1, /* set zp1 to normal zone 1 */
4145 CALL,
4147 ENDF,
4153 * bci_action_serif_lower_bound
4155 * Handle the SERIF action to align a serif with its base, then moving it
4156 * again if necessary to stay within a lower bound.
4158 * in: serif_point (in twilight zone)
4159 * base_point (in twilight zone)
4160 * edge[-1] (in twilight zone)
4161 * ... stuff for bci_align_segments (serif) ...
4163 * uses: bci_serif_common
4164 * bci_lower_bound
4167 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4170 PUSHB_1,
4171 bci_action_serif_lower_bound,
4172 FDEF,
4174 PUSHB_1,
4175 bci_serif_common,
4176 CALL,
4178 PUSHB_1,
4179 bci_lower_bound,
4180 CALL,
4182 ENDF,
4188 * bci_action_serif_upper_bound
4190 * Handle the SERIF action to align a serif with its base, then moving it
4191 * again if necessary to stay within an upper bound.
4193 * in: serif_point (in twilight zone)
4194 * base_point (in twilight zone)
4195 * edge[1] (in twilight zone)
4196 * ... stuff for bci_align_segments (serif) ...
4198 * uses: bci_serif_common
4199 * bci_upper_bound
4202 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4205 PUSHB_1,
4206 bci_action_serif_upper_bound,
4207 FDEF,
4209 PUSHB_1,
4210 bci_serif_common,
4211 CALL,
4213 PUSHB_1,
4214 bci_upper_bound,
4215 CALL,
4217 ENDF,
4223 * bci_action_serif_upper_lower_bound
4225 * Handle the SERIF action to align a serif with its base, then moving it
4226 * again if necessary to stay within a lower and upper bound.
4228 * in: serif_point (in twilight zone)
4229 * base_point (in twilight zone)
4230 * edge[-1] (in twilight zone)
4231 * edge[1] (in twilight zone)
4232 * ... stuff for bci_align_segments (serif) ...
4234 * uses: bci_serif_common
4235 * bci_upper_lower_bound
4238 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4241 PUSHB_1,
4242 bci_action_serif_upper_lower_bound,
4243 FDEF,
4245 PUSHB_1,
4247 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4249 PUSHB_1,
4250 bci_serif_common,
4251 CALL,
4253 PUSHB_1,
4254 bci_upper_lower_bound,
4255 CALL,
4257 ENDF,
4263 * bci_serif_anchor_common
4265 * Common code for bci_action_serif_anchor routines.
4267 * sal: sal_anchor
4269 * uses: bci_round
4272 unsigned char FPGM(bci_serif_anchor_common) [] =
4275 PUSHB_1,
4276 bci_serif_anchor_common,
4277 FDEF,
4279 PUSHB_1,
4281 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4283 DUP,
4284 PUSHB_1,
4285 sal_anchor,
4286 SWAP,
4287 WS, /* sal_anchor = edge_point */
4289 DUP,
4290 DUP,
4291 DUP,
4292 GC_cur,
4293 SWAP,
4294 GC_orig,
4295 PUSHB_1,
4296 bci_round,
4297 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4298 SWAP,
4299 SUB,
4300 SHPIX, /* edge = round(edge_orig) */
4302 ENDF,
4308 * bci_action_serif_anchor
4310 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4311 * anchor.
4313 * in: edge_point (in twilight zone)
4314 * ... stuff for bci_align_segments (edge) ...
4316 * uses: bci_serif_anchor_common
4317 * bci_align_segments
4320 unsigned char FPGM(bci_action_serif_anchor) [] =
4323 PUSHB_1,
4324 bci_action_serif_anchor,
4325 FDEF,
4327 PUSHB_1,
4328 bci_serif_anchor_common,
4329 CALL,
4331 MDAP_noround, /* set rp0 and rp1 to `edge' */
4333 PUSHB_2,
4334 bci_align_segments,
4336 SZP1, /* set zp1 to normal zone 1 */
4337 CALL,
4339 ENDF,
4345 * bci_action_serif_anchor_lower_bound
4347 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4348 * anchor, then moving it again if necessary to stay within a lower
4349 * bound.
4351 * in: edge_point (in twilight zone)
4352 * edge[-1] (in twilight zone)
4353 * ... stuff for bci_align_segments (edge) ...
4355 * uses: bci_serif_anchor_common
4356 * bci_lower_bound
4359 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4362 PUSHB_1,
4363 bci_action_serif_anchor_lower_bound,
4364 FDEF,
4366 PUSHB_1,
4367 bci_serif_anchor_common,
4368 CALL,
4370 PUSHB_1,
4371 bci_lower_bound,
4372 CALL,
4374 ENDF,
4380 * bci_action_serif_anchor_upper_bound
4382 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4383 * anchor, then moving it again if necessary to stay within an upper
4384 * bound.
4386 * in: edge_point (in twilight zone)
4387 * edge[1] (in twilight zone)
4388 * ... stuff for bci_align_segments (edge) ...
4390 * uses: bci_serif_anchor_common
4391 * bci_upper_bound
4394 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4397 PUSHB_1,
4398 bci_action_serif_anchor_upper_bound,
4399 FDEF,
4401 PUSHB_1,
4402 bci_serif_anchor_common,
4403 CALL,
4405 PUSHB_1,
4406 bci_upper_bound,
4407 CALL,
4409 ENDF,
4415 * bci_action_serif_anchor_upper_lower_bound
4417 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4418 * anchor, then moving it again if necessary to stay within a lower and
4419 * upper bound.
4421 * in: edge_point (in twilight zone)
4422 * edge[-1] (in twilight zone)
4423 * edge[1] (in twilight zone)
4424 * ... stuff for bci_align_segments (edge) ...
4426 * uses: bci_serif_anchor_common
4427 * bci_upper_lower_bound
4430 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4433 PUSHB_1,
4434 bci_action_serif_anchor_upper_lower_bound,
4435 FDEF,
4437 PUSHB_1,
4438 bci_serif_anchor_common,
4439 CALL,
4441 PUSHB_1,
4442 bci_upper_lower_bound,
4443 CALL,
4445 ENDF,
4451 * bci_serif_link1_common
4453 * Common code for bci_action_serif_link1 routines.
4455 * CVT: cvtl_0x10000
4458 unsigned char FPGM(bci_serif_link1_common) [] =
4461 PUSHB_1,
4462 bci_serif_link1_common,
4463 FDEF,
4465 PUSHB_1,
4467 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4469 PUSHB_1,
4471 CINDEX, /* s: [...] after edge before after */
4472 PUSHB_1,
4474 CINDEX, /* s: [...] after edge before after before */
4475 MD_orig_ZP2_0,
4476 PUSHB_1,
4478 EQ, /* after_orig_pos == before_orig_pos */
4479 IF, /* s: [...] after edge before */
4480 MDAP_noround, /* set rp0 and rp1 to `before' */
4481 DUP,
4482 ALIGNRP, /* align `edge' with `before' */
4483 SWAP,
4484 POP,
4486 ELSE,
4487 /* we have to execute `a*b/c', with b/c very near to 1: */
4488 /* to avoid overflow while retaining precision, */
4489 /* we transform this to `a + a * (b-c)/c' */
4491 PUSHB_1,
4493 CINDEX, /* s: [...] after edge before edge */
4494 PUSHB_1,
4496 CINDEX, /* s: [...] after edge before edge before */
4497 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4499 DUP,
4500 PUSHB_1,
4502 CINDEX, /* s: [...] after edge before a a after */
4503 PUSHB_1,
4505 CINDEX, /* s: [...] after edge before a a after before */
4506 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4508 PUSHB_1,
4510 CINDEX, /* s: [...] after edge before a a c after */
4511 PUSHB_1,
4513 CINDEX, /* s: [...] after edge before a a c after before */
4514 MD_cur, /* b = after_pos - before_pos */
4516 PUSHB_1,
4518 CINDEX, /* s: [...] after edge before a a c b c */
4519 SUB, /* b-c */
4521 PUSHB_1,
4522 cvtl_0x10000,
4523 RCVT,
4524 MUL, /* (b-c) in 16.16 format */
4525 SWAP,
4527 DUP,
4528 IF, /* c != 0 ? */
4529 DIV, /* s: [...] after edge before a a (b-c)/c */
4530 ELSE,
4531 POP, /* avoid division by zero */
4532 EIF,
4534 MUL, /* a * (b-c)/c * 2^10 */
4535 PUSHB_1,
4536 cvtl_0x10000,
4537 RCVT,
4538 DIV, /* a * (b-c)/c */
4539 ADD, /* a*b/c */
4541 SWAP,
4542 MDAP_noround, /* set rp0 and rp1 to `before' */
4543 SWAP, /* s: [...] after a*b/c edge */
4544 DUP,
4545 DUP,
4546 ALIGNRP, /* align `edge' with `before' */
4547 ROLL,
4548 SHPIX, /* shift `edge' by `a*b/c' */
4550 SWAP, /* s: [...] edge after */
4551 POP,
4552 EIF,
4554 ENDF,
4560 * bci_action_serif_link1
4562 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4563 * before and after.
4565 * in: before_point (in twilight zone)
4566 * edge_point (in twilight zone)
4567 * after_point (in twilight zone)
4568 * ... stuff for bci_align_segments (edge) ...
4570 * uses: bci_serif_link1_common
4571 * bci_align_segments
4574 unsigned char FPGM(bci_action_serif_link1) [] =
4577 PUSHB_1,
4578 bci_action_serif_link1,
4579 FDEF,
4581 PUSHB_1,
4582 bci_serif_link1_common,
4583 CALL,
4585 MDAP_noround, /* set rp0 and rp1 to `edge' */
4587 PUSHB_2,
4588 bci_align_segments,
4590 SZP1, /* set zp1 to normal zone 1 */
4591 CALL,
4593 ENDF,
4599 * bci_action_serif_link1_lower_bound
4601 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4602 * before and after. Additionally, move the serif again if necessary to
4603 * stay within a lower bound.
4605 * in: before_point (in twilight zone)
4606 * edge_point (in twilight zone)
4607 * after_point (in twilight zone)
4608 * edge[-1] (in twilight zone)
4609 * ... stuff for bci_align_segments (edge) ...
4611 * uses: bci_serif_link1_common
4612 * bci_lower_bound
4615 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4618 PUSHB_1,
4619 bci_action_serif_link1_lower_bound,
4620 FDEF,
4622 PUSHB_1,
4623 bci_serif_link1_common,
4624 CALL,
4626 PUSHB_1,
4627 bci_lower_bound,
4628 CALL,
4630 ENDF,
4636 * bci_action_serif_link1_upper_bound
4638 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4639 * before and after. Additionally, move the serif again if necessary to
4640 * stay within an upper bound.
4642 * in: before_point (in twilight zone)
4643 * edge_point (in twilight zone)
4644 * after_point (in twilight zone)
4645 * edge[1] (in twilight zone)
4646 * ... stuff for bci_align_segments (edge) ...
4648 * uses: bci_serif_link1_common
4649 * bci_upper_bound
4652 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4655 PUSHB_1,
4656 bci_action_serif_link1_upper_bound,
4657 FDEF,
4659 PUSHB_1,
4660 bci_serif_link1_common,
4661 CALL,
4663 PUSHB_1,
4664 bci_upper_bound,
4665 CALL,
4667 ENDF,
4673 * bci_action_serif_link1_upper_lower_bound
4675 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4676 * before and after. Additionally, move the serif again if necessary to
4677 * stay within a lower and upper bound.
4679 * in: before_point (in twilight zone)
4680 * edge_point (in twilight zone)
4681 * after_point (in twilight zone)
4682 * edge[-1] (in twilight zone)
4683 * edge[1] (in twilight zone)
4684 * ... stuff for bci_align_segments (edge) ...
4686 * uses: bci_serif_link1_common
4687 * bci_upper_lower_bound
4690 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
4693 PUSHB_1,
4694 bci_action_serif_link1_upper_lower_bound,
4695 FDEF,
4697 PUSHB_1,
4698 bci_serif_link1_common,
4699 CALL,
4701 PUSHB_1,
4702 bci_upper_lower_bound,
4703 CALL,
4705 ENDF,
4711 * bci_serif_link2_common
4713 * Common code for bci_action_serif_link2 routines.
4715 * sal: sal_anchor
4718 unsigned char FPGM(bci_serif_link2_common) [] =
4721 PUSHB_1,
4722 bci_serif_link2_common,
4723 FDEF,
4725 PUSHB_1,
4727 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4729 DUP, /* s: [...] edge edge */
4730 PUSHB_1,
4731 sal_anchor,
4733 DUP, /* s: [...] edge edge anchor anchor */
4734 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4736 MD_orig_ZP2_0,
4737 DUP,
4738 ADD,
4739 PUSHB_1,
4741 ADD,
4742 FLOOR,
4743 PUSHB_1,
4744 2*64,
4745 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4747 SWAP,
4748 DUP,
4749 DUP,
4750 ALIGNRP, /* align `edge' with `sal_anchor' */
4751 ROLL,
4752 SHPIX, /* shift `edge' by `delta' */
4754 ENDF,
4760 * bci_action_serif_link2
4762 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4764 * in: edge_point (in twilight zone)
4765 * ... stuff for bci_align_segments (edge) ...
4767 * uses: bci_serif_link2_common
4768 * bci_align_segments
4771 unsigned char FPGM(bci_action_serif_link2) [] =
4774 PUSHB_1,
4775 bci_action_serif_link2,
4776 FDEF,
4778 PUSHB_1,
4779 bci_serif_link2_common,
4780 CALL,
4782 MDAP_noround, /* set rp0 and rp1 to `edge' */
4784 PUSHB_2,
4785 bci_align_segments,
4787 SZP1, /* set zp1 to normal zone 1 */
4788 CALL,
4790 ENDF,
4796 * bci_action_serif_link2_lower_bound
4798 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4799 * Additionally, move the serif again if necessary to stay within a lower
4800 * bound.
4802 * in: edge_point (in twilight zone)
4803 * edge[-1] (in twilight zone)
4804 * ... stuff for bci_align_segments (edge) ...
4806 * uses: bci_serif_link2_common
4807 * bci_lower_bound
4810 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4813 PUSHB_1,
4814 bci_action_serif_link2_lower_bound,
4815 FDEF,
4817 PUSHB_1,
4818 bci_serif_link2_common,
4819 CALL,
4821 PUSHB_1,
4822 bci_lower_bound,
4823 CALL,
4825 ENDF,
4831 * bci_action_serif_link2_upper_bound
4833 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4834 * Additionally, move the serif again if necessary to stay within an upper
4835 * bound.
4837 * in: edge_point (in twilight zone)
4838 * edge[1] (in twilight zone)
4839 * ... stuff for bci_align_segments (edge) ...
4841 * uses: bci_serif_link2_common
4842 * bci_upper_bound
4845 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4848 PUSHB_1,
4849 bci_action_serif_link2_upper_bound,
4850 FDEF,
4852 PUSHB_1,
4853 bci_serif_link2_common,
4854 CALL,
4856 PUSHB_1,
4857 bci_upper_bound,
4858 CALL,
4860 ENDF,
4866 * bci_action_serif_link2_upper_lower_bound
4868 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4869 * Additionally, move the serif again if necessary to stay within a lower
4870 * and upper bound.
4872 * in: edge_point (in twilight zone)
4873 * edge[-1] (in twilight zone)
4874 * edge[1] (in twilight zone)
4875 * ... stuff for bci_align_segments (edge) ...
4877 * uses: bci_serif_link2_common
4878 * bci_upper_lower_bound
4881 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
4884 PUSHB_1,
4885 bci_action_serif_link2_upper_lower_bound,
4886 FDEF,
4888 PUSHB_1,
4889 bci_serif_link2_common,
4890 CALL,
4892 PUSHB_1,
4893 bci_upper_lower_bound,
4894 CALL,
4896 ENDF,
4902 * bci_hint_glyph
4904 * This is the top-level glyph hinting function which parses the arguments
4905 * on the stack and calls subroutines.
4907 * in: action_0_func_idx
4908 * ... data ...
4909 * action_1_func_idx
4910 * ... data ...
4911 * ...
4913 * CVT: cvtl_is_subglyph
4915 * uses: bci_action_ip_before
4916 * bci_action_ip_after
4917 * bci_action_ip_on
4918 * bci_action_ip_between
4920 * bci_action_adjust_bound
4921 * bci_action_adjust_bound_serif
4922 * bci_action_adjust_bound_round
4923 * bci_action_adjust_bound_round_serif
4925 * bci_action_stem_bound
4926 * bci_action_stem_bound_serif
4927 * bci_action_stem_bound_round
4928 * bci_action_stem_bound_round_serif
4930 * bci_action_link
4931 * bci_action_link_serif
4932 * bci_action_link_round
4933 * bci_action_link_round_serif
4935 * bci_action_anchor
4936 * bci_action_anchor_serif
4937 * bci_action_anchor_round
4938 * bci_action_anchor_round_serif
4940 * bci_action_blue_anchor
4942 * bci_action_adjust
4943 * bci_action_adjust_serif
4944 * bci_action_adjust_round
4945 * bci_action_adjust_round_serif
4947 * bci_action_stem
4948 * bci_action_stem_serif
4949 * bci_action_stem_round
4950 * bci_action_stem_round_serif
4952 * bci_action_blue
4954 * bci_action_serif
4955 * bci_action_serif_lower_bound
4956 * bci_action_serif_upper_bound
4957 * bci_action_serif_upper_lower_bound
4959 * bci_action_serif_anchor
4960 * bci_action_serif_anchor_lower_bound
4961 * bci_action_serif_anchor_upper_bound
4962 * bci_action_serif_anchor_upper_lower_bound
4964 * bci_action_serif_link1
4965 * bci_action_serif_link1_lower_bound
4966 * bci_action_serif_link1_upper_bound
4967 * bci_action_serif_link1_upper_lower_bound
4969 * bci_action_serif_link2
4970 * bci_action_serif_link2_lower_bound
4971 * bci_action_serif_link2_upper_bound
4972 * bci_action_serif_link2_upper_lower_bound
4975 unsigned char FPGM(bci_hint_glyph) [] =
4978 PUSHB_1,
4979 bci_hint_glyph,
4980 FDEF,
4982 /* start_loop: */
4983 /* loop until all data on stack is used */
4984 CALL,
4985 PUSHB_1,
4987 NEG,
4988 PUSHB_1,
4990 DEPTH,
4992 JROT, /* goto start_loop */
4994 PUSHB_1,
4996 SZP2, /* set zp2 to normal zone 1 */
4997 IUP_y,
4999 ENDF,
5004 #define COPY_FPGM(func_name) \
5005 memcpy(buf_p, fpgm_ ## func_name, \
5006 sizeof (fpgm_ ## func_name)); \
5007 buf_p += sizeof (fpgm_ ## func_name) \
5009 static FT_Error
5010 TA_table_build_fpgm(FT_Byte** fpgm,
5011 FT_ULong* fpgm_len,
5012 FONT* font)
5014 FT_UInt buf_len;
5015 FT_UInt len;
5016 FT_Byte* buf;
5017 FT_Byte* buf_p;
5020 /* for compatibility with dumb bytecode interpreters or analyzers, */
5021 /* FDEFs are stored in ascending index order, without holes -- */
5022 /* note that some FDEFs are not always needed */
5023 /* (depending on options of `TTFautohint'), */
5024 /* but implementing dynamic FDEF indices would be a lot of work */
5026 buf_len = sizeof (FPGM(bci_round))
5027 + sizeof (FPGM(bci_smooth_stem_width_a))
5029 + sizeof (FPGM(bci_smooth_stem_width_b))
5031 + sizeof (FPGM(bci_smooth_stem_width_c))
5032 + sizeof (FPGM(bci_get_best_width))
5033 + sizeof (FPGM(bci_strong_stem_width_a))
5035 + sizeof (FPGM(bci_strong_stem_width_b))
5036 + sizeof (FPGM(bci_loop))
5037 + sizeof (FPGM(bci_cvt_rescale))
5038 + sizeof (FPGM(bci_blue_round_a))
5040 + sizeof (FPGM(bci_blue_round_b))
5041 + sizeof (FPGM(bci_decrement_component_counter))
5042 + sizeof (FPGM(bci_get_point_extrema))
5043 + sizeof (FPGM(bci_nibbles))
5044 + sizeof (FPGM(bci_number_set_is_element))
5045 + sizeof (FPGM(bci_number_set_is_element2))
5047 + sizeof (FPGM(bci_create_segment))
5048 + sizeof (FPGM(bci_create_segments))
5050 + sizeof (FPGM(bci_create_segments_0))
5051 + sizeof (FPGM(bci_create_segments_1))
5052 + sizeof (FPGM(bci_create_segments_2))
5053 + sizeof (FPGM(bci_create_segments_3))
5054 + sizeof (FPGM(bci_create_segments_4))
5055 + sizeof (FPGM(bci_create_segments_5))
5056 + sizeof (FPGM(bci_create_segments_6))
5057 + sizeof (FPGM(bci_create_segments_7))
5058 + sizeof (FPGM(bci_create_segments_8))
5059 + sizeof (FPGM(bci_create_segments_9))
5061 + sizeof (FPGM(bci_create_segments_composite))
5063 + sizeof (FPGM(bci_create_segments_composite_0))
5064 + sizeof (FPGM(bci_create_segments_composite_1))
5065 + sizeof (FPGM(bci_create_segments_composite_2))
5066 + sizeof (FPGM(bci_create_segments_composite_3))
5067 + sizeof (FPGM(bci_create_segments_composite_4))
5068 + sizeof (FPGM(bci_create_segments_composite_5))
5069 + sizeof (FPGM(bci_create_segments_composite_6))
5070 + sizeof (FPGM(bci_create_segments_composite_7))
5071 + sizeof (FPGM(bci_create_segments_composite_8))
5072 + sizeof (FPGM(bci_create_segments_composite_9))
5074 + sizeof (FPGM(bci_align_segment))
5075 + sizeof (FPGM(bci_align_segments))
5077 + sizeof (FPGM(bci_scale_contour))
5078 + sizeof (FPGM(bci_scale_glyph))
5079 + sizeof (FPGM(bci_scale_composite_glyph))
5080 + sizeof (FPGM(bci_shift_contour))
5081 + sizeof (FPGM(bci_shift_subglyph))
5083 + sizeof (FPGM(bci_ip_outer_align_point))
5084 + sizeof (FPGM(bci_ip_on_align_points))
5085 + sizeof (FPGM(bci_ip_between_align_point))
5086 + sizeof (FPGM(bci_ip_between_align_points))
5088 + sizeof (FPGM(bci_adjust_common))
5089 + sizeof (FPGM(bci_stem_common))
5090 + sizeof (FPGM(bci_serif_common))
5091 + sizeof (FPGM(bci_serif_anchor_common))
5092 + sizeof (FPGM(bci_serif_link1_common))
5093 + sizeof (FPGM(bci_serif_link2_common))
5095 + sizeof (FPGM(bci_lower_bound))
5096 + sizeof (FPGM(bci_upper_bound))
5097 + sizeof (FPGM(bci_upper_lower_bound))
5099 + sizeof (FPGM(bci_adjust_bound))
5100 + sizeof (FPGM(bci_stem_bound))
5101 + sizeof (FPGM(bci_link))
5102 + sizeof (FPGM(bci_anchor))
5103 + sizeof (FPGM(bci_adjust))
5104 + sizeof (FPGM(bci_stem))
5106 + sizeof (FPGM(bci_action_ip_before))
5107 + sizeof (FPGM(bci_action_ip_after))
5108 + sizeof (FPGM(bci_action_ip_on))
5109 + sizeof (FPGM(bci_action_ip_between))
5111 + sizeof (FPGM(bci_action_blue))
5112 + sizeof (FPGM(bci_action_blue_anchor))
5114 + sizeof (FPGM(bci_action_anchor))
5115 + sizeof (FPGM(bci_action_anchor_serif))
5116 + sizeof (FPGM(bci_action_anchor_round))
5117 + sizeof (FPGM(bci_action_anchor_round_serif))
5119 + sizeof (FPGM(bci_action_adjust))
5120 + sizeof (FPGM(bci_action_adjust_serif))
5121 + sizeof (FPGM(bci_action_adjust_round))
5122 + sizeof (FPGM(bci_action_adjust_round_serif))
5123 + sizeof (FPGM(bci_action_adjust_bound))
5124 + sizeof (FPGM(bci_action_adjust_bound_serif))
5125 + sizeof (FPGM(bci_action_adjust_bound_round))
5126 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5128 + sizeof (FPGM(bci_action_link))
5129 + sizeof (FPGM(bci_action_link_serif))
5130 + sizeof (FPGM(bci_action_link_round))
5131 + sizeof (FPGM(bci_action_link_round_serif))
5133 + sizeof (FPGM(bci_action_stem))
5134 + sizeof (FPGM(bci_action_stem_serif))
5135 + sizeof (FPGM(bci_action_stem_round))
5136 + sizeof (FPGM(bci_action_stem_round_serif))
5137 + sizeof (FPGM(bci_action_stem_bound))
5138 + sizeof (FPGM(bci_action_stem_bound_serif))
5139 + sizeof (FPGM(bci_action_stem_bound_round))
5140 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5142 + sizeof (FPGM(bci_action_serif))
5143 + sizeof (FPGM(bci_action_serif_lower_bound))
5144 + sizeof (FPGM(bci_action_serif_upper_bound))
5145 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5147 + sizeof (FPGM(bci_action_serif_anchor))
5148 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5149 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5150 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5152 + sizeof (FPGM(bci_action_serif_link1))
5153 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5154 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5155 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5157 + sizeof (FPGM(bci_action_serif_link2))
5158 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5159 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5160 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5162 + sizeof (FPGM(bci_hint_glyph));
5164 /* buffer length must be a multiple of four */
5165 len = (buf_len + 3) & ~3;
5166 buf = (FT_Byte*)malloc(len);
5167 if (!buf)
5168 return FT_Err_Out_Of_Memory;
5170 /* pad end of buffer with zeros */
5171 buf[len - 1] = 0x00;
5172 buf[len - 2] = 0x00;
5173 buf[len - 3] = 0x00;
5175 /* copy font program into buffer and fill in the missing variables */
5176 buf_p = buf;
5178 COPY_FPGM(bci_round);
5179 COPY_FPGM(bci_smooth_stem_width_a);
5180 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5181 COPY_FPGM(bci_smooth_stem_width_b);
5182 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5183 COPY_FPGM(bci_smooth_stem_width_c);
5184 COPY_FPGM(bci_get_best_width);
5185 COPY_FPGM(bci_strong_stem_width_a);
5186 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5187 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font);
5188 COPY_FPGM(bci_strong_stem_width_b);
5189 COPY_FPGM(bci_loop);
5190 COPY_FPGM(bci_cvt_rescale);
5191 COPY_FPGM(bci_blue_round_a);
5192 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
5193 COPY_FPGM(bci_blue_round_b);
5194 COPY_FPGM(bci_decrement_component_counter);
5195 COPY_FPGM(bci_get_point_extrema);
5196 COPY_FPGM(bci_nibbles);
5197 COPY_FPGM(bci_number_set_is_element);
5198 COPY_FPGM(bci_number_set_is_element2);
5200 COPY_FPGM(bci_create_segment);
5201 COPY_FPGM(bci_create_segments);
5203 COPY_FPGM(bci_create_segments_0);
5204 COPY_FPGM(bci_create_segments_1);
5205 COPY_FPGM(bci_create_segments_2);
5206 COPY_FPGM(bci_create_segments_3);
5207 COPY_FPGM(bci_create_segments_4);
5208 COPY_FPGM(bci_create_segments_5);
5209 COPY_FPGM(bci_create_segments_6);
5210 COPY_FPGM(bci_create_segments_7);
5211 COPY_FPGM(bci_create_segments_8);
5212 COPY_FPGM(bci_create_segments_9);
5214 COPY_FPGM(bci_create_segments_composite);
5216 COPY_FPGM(bci_create_segments_composite_0);
5217 COPY_FPGM(bci_create_segments_composite_1);
5218 COPY_FPGM(bci_create_segments_composite_2);
5219 COPY_FPGM(bci_create_segments_composite_3);
5220 COPY_FPGM(bci_create_segments_composite_4);
5221 COPY_FPGM(bci_create_segments_composite_5);
5222 COPY_FPGM(bci_create_segments_composite_6);
5223 COPY_FPGM(bci_create_segments_composite_7);
5224 COPY_FPGM(bci_create_segments_composite_8);
5225 COPY_FPGM(bci_create_segments_composite_9);
5227 COPY_FPGM(bci_align_segment);
5228 COPY_FPGM(bci_align_segments);
5230 COPY_FPGM(bci_scale_contour);
5231 COPY_FPGM(bci_scale_glyph);
5232 COPY_FPGM(bci_scale_composite_glyph);
5233 COPY_FPGM(bci_shift_contour);
5234 COPY_FPGM(bci_shift_subglyph);
5236 COPY_FPGM(bci_ip_outer_align_point);
5237 COPY_FPGM(bci_ip_on_align_points);
5238 COPY_FPGM(bci_ip_between_align_point);
5239 COPY_FPGM(bci_ip_between_align_points);
5241 COPY_FPGM(bci_adjust_common);
5242 COPY_FPGM(bci_stem_common);
5243 COPY_FPGM(bci_serif_common);
5244 COPY_FPGM(bci_serif_anchor_common);
5245 COPY_FPGM(bci_serif_link1_common);
5246 COPY_FPGM(bci_serif_link2_common);
5248 COPY_FPGM(bci_lower_bound);
5249 COPY_FPGM(bci_upper_bound);
5250 COPY_FPGM(bci_upper_lower_bound);
5252 COPY_FPGM(bci_adjust_bound);
5253 COPY_FPGM(bci_stem_bound);
5254 COPY_FPGM(bci_link);
5255 COPY_FPGM(bci_anchor);
5256 COPY_FPGM(bci_adjust);
5257 COPY_FPGM(bci_stem);
5259 COPY_FPGM(bci_action_ip_before);
5260 COPY_FPGM(bci_action_ip_after);
5261 COPY_FPGM(bci_action_ip_on);
5262 COPY_FPGM(bci_action_ip_between);
5264 COPY_FPGM(bci_action_blue);
5265 COPY_FPGM(bci_action_blue_anchor);
5267 COPY_FPGM(bci_action_anchor);
5268 COPY_FPGM(bci_action_anchor_serif);
5269 COPY_FPGM(bci_action_anchor_round);
5270 COPY_FPGM(bci_action_anchor_round_serif);
5272 COPY_FPGM(bci_action_adjust);
5273 COPY_FPGM(bci_action_adjust_serif);
5274 COPY_FPGM(bci_action_adjust_round);
5275 COPY_FPGM(bci_action_adjust_round_serif);
5276 COPY_FPGM(bci_action_adjust_bound);
5277 COPY_FPGM(bci_action_adjust_bound_serif);
5278 COPY_FPGM(bci_action_adjust_bound_round);
5279 COPY_FPGM(bci_action_adjust_bound_round_serif);
5281 COPY_FPGM(bci_action_link);
5282 COPY_FPGM(bci_action_link_serif);
5283 COPY_FPGM(bci_action_link_round);
5284 COPY_FPGM(bci_action_link_round_serif);
5286 COPY_FPGM(bci_action_stem);
5287 COPY_FPGM(bci_action_stem_serif);
5288 COPY_FPGM(bci_action_stem_round);
5289 COPY_FPGM(bci_action_stem_round_serif);
5290 COPY_FPGM(bci_action_stem_bound);
5291 COPY_FPGM(bci_action_stem_bound_serif);
5292 COPY_FPGM(bci_action_stem_bound_round);
5293 COPY_FPGM(bci_action_stem_bound_round_serif);
5295 COPY_FPGM(bci_action_serif);
5296 COPY_FPGM(bci_action_serif_lower_bound);
5297 COPY_FPGM(bci_action_serif_upper_bound);
5298 COPY_FPGM(bci_action_serif_upper_lower_bound);
5300 COPY_FPGM(bci_action_serif_anchor);
5301 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5302 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5303 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5305 COPY_FPGM(bci_action_serif_link1);
5306 COPY_FPGM(bci_action_serif_link1_lower_bound);
5307 COPY_FPGM(bci_action_serif_link1_upper_bound);
5308 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5310 COPY_FPGM(bci_action_serif_link2);
5311 COPY_FPGM(bci_action_serif_link2_lower_bound);
5312 COPY_FPGM(bci_action_serif_link2_upper_bound);
5313 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5315 COPY_FPGM(bci_hint_glyph);
5317 *fpgm = buf;
5318 *fpgm_len = buf_len;
5320 return FT_Err_Ok;
5324 FT_Error
5325 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5326 FONT* font)
5328 FT_Error error = FT_Err_Ok;
5330 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5331 glyf_Data* data = (glyf_Data*)glyf_table->data;
5333 FT_Byte* fpgm_buf;
5334 FT_ULong fpgm_len;
5337 error = TA_sfnt_add_table_info(sfnt);
5338 if (error)
5339 goto Exit;
5341 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5342 if (glyf_table->processed)
5344 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5345 goto Exit;
5348 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
5349 if (error)
5350 goto Exit;
5352 if (fpgm_len > sfnt->max_instructions)
5353 sfnt->max_instructions = fpgm_len;
5355 /* in case of success, `fpgm_buf' gets linked */
5356 /* and is eventually freed in `TA_font_unload' */
5357 error = TA_font_add_table(font,
5358 &sfnt->table_infos[sfnt->num_table_infos - 1],
5359 TTAG_fpgm, fpgm_len, fpgm_buf);
5360 if (error)
5361 free(fpgm_buf);
5362 else
5363 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5365 Exit:
5366 return error;
5369 /* end of tafpgm.c */