Split `tabytecode.c' into `tacvt.c', `tafpgm.c', and `taprep.c'.
[ttfautohint.git] / src / tafpgm.c
blob248f3a2aeff65095cd44a5fb3a3fc22e74667d18
1 /* tafpgm.c */
3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
5 #include "tabytecode.h"
8 /* we need the following macro */
9 /* so that `func_name' doesn't get replaced with its #defined value */
10 /* (as defined in `tabytecode.h') */
12 #define FPGM(func_name) fpgm_ ## func_name
15 /* in the comments below, the top of the stack (`s:') */
16 /* is the rightmost element; the stack is shown */
17 /* after the instruction on the same line has been executed */
19 /* we use two sets of points in the twilight zone (zp0): */
20 /* one set to hold the unhinted segment positions, */
21 /* and another one to track the positions as changed by the hinting -- */
22 /* this is necessary since all points in zp0 */
23 /* have (0,0) as the original coordinates, */
24 /* making e.g. `MD_orig' return useless results */
28 * bci_round
30 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
31 * engine specific corrections are applied.
33 * in: val
34 * out: ROUND(val)
37 unsigned char FPGM(bci_round) [] = {
39 PUSHB_1,
40 bci_round,
41 FDEF,
43 DUP,
44 ABS,
45 PUSHB_1,
46 32,
47 ADD,
48 FLOOR,
49 SWAP,
50 PUSHB_1,
52 LT,
53 IF,
54 NEG,
55 EIF,
57 ENDF,
63 * bci_compute_stem_width
65 * This is the equivalent to the following code from function
66 * `ta_latin_compute_stem_width':
68 * dist = ABS(width)
70 * if (stem_is_serif
71 * && dist < 3*64)
72 * || is_extra_light:
73 * return width
74 * else if base_is_round:
75 * if dist < 80
76 * dist = 64
77 * else if dist < 56:
78 * dist = 56
80 * delta = ABS(dist - std_width)
82 * if delta < 40:
83 * dist = std_width
84 * if dist < 48
85 * dist = 48
86 * goto End
88 * if dist < 3*64:
89 * delta = dist
90 * dist = FLOOR(dist)
91 * delta = delta - dist
93 * if delta < 10:
94 * dist = dist + delta
95 * else if delta < 32:
96 * dist = dist + 10
97 * else if delta < 54:
98 * dist = dist + 54
99 * else
100 * dist = dist + delta
101 * else
102 * dist = ROUND(dist)
104 * End:
105 * if width < 0:
106 * dist = -dist
107 * return dist
110 * in: width
111 * stem_is_serif
112 * base_is_round
113 * out: new_width
114 * sal: sal_is_extra_light
115 * CVT: std_width
118 unsigned char FPGM(bci_compute_stem_width_a) [] = {
120 PUSHB_1,
121 bci_compute_stem_width,
122 FDEF,
124 DUP,
125 ABS, /* s: base_is_round stem_is_serif width dist */
127 DUP,
128 PUSHB_1,
129 3*64,
130 LT, /* dist < 3*64 */
132 PUSHB_1,
134 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
135 AND, /* stem_is_serif && dist < 3*64 */
137 PUSHB_1,
138 sal_is_extra_light,
140 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
142 IF, /* s: base_is_round width dist */
143 POP,
144 SWAP,
145 POP, /* s: width */
147 ELSE,
148 ROLL, /* s: width dist base_is_round */
149 IF, /* s: width dist */
150 DUP,
151 PUSHB_1,
153 LT, /* dist < 80 */
154 IF, /* s: width dist */
155 POP,
156 PUSHB_1,
157 64, /* dist = 64 */
158 EIF,
160 ELSE,
161 DUP,
162 PUSHB_1,
164 LT, /* dist < 56 */
165 IF, /* s: width dist */
166 POP,
167 PUSHB_1,
168 56, /* dist = 56 */
169 EIF,
170 EIF,
172 DUP, /* s: width dist dist */
173 PUSHB_1,
177 /* %c, index of std_width */
179 unsigned char FPGM(bci_compute_stem_width_b) [] = {
181 RCVT,
182 SUB,
183 ABS, /* s: width dist delta */
185 PUSHB_1,
187 LT, /* delta < 40 */
188 IF, /* s: width dist */
189 POP,
190 PUSHB_1,
194 /* %c, index of std_width */
196 unsigned char FPGM(bci_compute_stem_width_c) [] = {
198 RCVT, /* dist = std_width */
199 DUP,
200 PUSHB_1,
202 LT, /* dist < 48 */
204 POP,
205 PUSHB_1,
206 48, /* dist = 48 */
207 EIF,
209 ELSE,
210 DUP, /* s: width dist dist */
211 PUSHB_1,
212 3*64,
213 LT, /* dist < 3*64 */
215 DUP, /* s: width delta dist */
216 FLOOR, /* dist = FLOOR(dist) */
217 DUP, /* s: width delta dist dist */
218 ROLL,
219 ROLL, /* s: width dist delta dist */
220 SUB, /* delta = delta - dist */
222 DUP, /* s: width dist delta delta */
223 PUSHB_1,
225 LT, /* delta < 10 */
226 IF, /* s: width dist delta */
227 ADD, /* dist = dist + delta */
229 ELSE,
230 DUP,
231 PUSHB_1,
233 LT, /* delta < 32 */
235 POP,
236 PUSHB_1,
238 ADD, /* dist = dist + 10 */
240 ELSE,
241 DUP,
242 PUSHB_1,
244 LT, /* delta < 54 */
246 POP,
247 PUSHB_1,
249 ADD, /* dist = dist + 54 */
251 ELSE,
252 ADD, /* dist = dist + delta */
254 EIF,
255 EIF,
256 EIF,
258 ELSE,
259 PUSHB_1,
260 bci_round,
261 CALL, /* dist = round(dist) */
263 EIF,
264 EIF,
266 SWAP, /* s: dist width */
267 PUSHB_1,
269 LT, /* width < 0 */
271 NEG, /* dist = -dist */
272 EIF,
273 EIF,
274 EIF,
276 ENDF,
282 * bci_loop
284 * Take a range and a function number and apply the function to all
285 * elements of the range.
287 * in: func_num
288 * end
289 * start
291 * uses: sal_i (counter initialized with `start')
292 * sal_limit (`end')
293 * sal_func (`func_num')
296 unsigned char FPGM(bci_loop) [] = {
298 PUSHB_1,
299 bci_loop,
300 FDEF,
302 PUSHB_1,
303 sal_func,
304 SWAP,
305 WS, /* sal_func = func_num */
306 PUSHB_1,
307 sal_limit,
308 SWAP,
309 WS, /* sal_limit = end */
310 PUSHB_1,
311 sal_i,
312 SWAP,
313 WS, /* sal_i = start */
315 /* start_loop: */
316 PUSHB_1,
317 sal_i,
319 PUSHB_1,
320 sal_limit,
322 LTEQ, /* start <= end */
324 PUSHB_1,
325 sal_func,
327 CALL,
328 PUSHB_3,
329 sal_i,
331 sal_i,
333 ADD, /* start = start + 1 */
336 PUSHB_1,
338 NEG,
339 JMPR, /* goto start_loop */
340 EIF,
342 ENDF,
348 * bci_cvt_rescale
350 * Rescale CVT value by a given factor.
352 * uses: sal_i (CVT index)
353 * sal_scale (scale in 16.16 format)
356 unsigned char FPGM(bci_cvt_rescale) [] = {
358 PUSHB_1,
359 bci_cvt_rescale,
360 FDEF,
362 PUSHB_1,
363 sal_i,
365 DUP,
366 RCVT,
367 PUSHB_1,
368 sal_scale,
370 MUL, /* CVT * scale * 2^10 */
371 PUSHB_1,
372 sal_0x10000,
374 DIV, /* CVT * scale */
376 WCVTP,
378 ENDF,
384 * bci_blue_round
386 * Round a blue ref value and adjust its corresponding shoot value.
388 * uses: sal_i (CVT index)
392 unsigned char FPGM(bci_blue_round_a) [] = {
394 PUSHB_1,
395 bci_blue_round,
396 FDEF,
398 PUSHB_1,
399 sal_i,
401 DUP,
402 RCVT, /* s: ref_idx ref */
404 DUP,
405 PUSHB_1,
406 bci_round,
407 CALL,
408 SWAP, /* s: ref_idx round(ref) ref */
410 PUSHB_2,
414 /* %c, blue_count */
416 unsigned char FPGM(bci_blue_round_b) [] = {
419 CINDEX,
420 ADD, /* s: ref_idx round(ref) ref shoot_idx */
421 DUP,
422 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
424 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
425 SWAP,
426 SUB, /* s: ref_idx round(ref) shoot_idx dist */
427 DUP,
428 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
430 DUP,
431 PUSHB_1,
433 LT, /* delta < 32 */
435 POP,
436 PUSHB_1,
437 0, /* delta = 0 */
439 ELSE,
440 PUSHB_1,
442 LT, /* delta < 48 */
444 PUSHB_1,
445 32, /* delta = 32 */
447 ELSE,
448 PUSHB_1,
449 64, /* delta = 64 */
450 EIF,
451 EIF,
453 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
454 PUSHB_1,
456 LT, /* dist < 0 */
458 NEG, /* delta = -delta */
459 EIF,
461 PUSHB_1,
463 CINDEX,
464 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
466 WCVTP,
467 WCVTP,
469 ENDF,
475 * bci_get_point_extrema
477 * An auxiliary function for `bci_create_segment'.
479 * in: point-1
480 * out: point
482 * sal: sal_point_min
483 * sal_point_max
486 unsigned char FPGM(bci_get_point_extrema) [] = {
488 PUSHB_1,
489 bci_get_point_extrema,
490 FDEF,
492 PUSHB_1,
494 ADD, /* s: point */
495 DUP,
496 DUP,
498 /* check whether `point' is a new minimum */
499 PUSHB_1,
500 sal_point_min,
501 RS, /* s: point point point point_min */
502 MD_orig,
503 /* if distance is negative, we have a new minimum */
504 PUSHB_1,
507 IF, /* s: point point */
508 DUP,
509 PUSHB_1,
510 sal_point_min,
511 SWAP,
513 EIF,
515 /* check whether `point' is a new maximum */
516 PUSHB_1,
517 sal_point_max,
518 RS, /* s: point point point_max */
519 MD_orig,
520 /* if distance is positive, we have a new maximum */
521 PUSHB_1,
524 IF, /* s: point */
525 DUP,
526 PUSHB_1,
527 sal_point_max,
528 SWAP,
530 EIF, /* s: point */
532 ENDF,
538 * bci_create_segment
540 * Store start and end point of a segment in the storage area,
541 * then construct two points in the twilight zone to represent it:
542 * an original one (which stays unmodified) and a hinted one,
543 * initialized with the original value.
545 * This function is used by `bci_create_segment_points'.
547 * in: start
548 * end
549 * [last (if wrap-around segment)]
550 * [first (if wrap-around segment)]
552 * uses: bci_get_point_extrema
554 * sal: sal_i (start of current segment)
555 * sal_j (current original twilight point)
556 * sal_k (current hinted twilight point)
557 * sal_point_min
558 * sal_point_max
561 unsigned char FPGM(bci_create_segment) [] = {
563 PUSHB_1,
564 bci_create_segment,
565 FDEF,
567 PUSHB_1,
568 sal_i,
570 PUSHB_1,
572 CINDEX,
573 WS, /* sal[sal_i] = start */
575 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
576 PUSHB_3,
577 sal_i,
579 sal_i,
581 ADD, /* sal_i = sal_i + 1 */
584 /* initialize inner loop(s) */
585 PUSHB_2,
586 sal_point_min,
588 CINDEX,
589 WS, /* sal_point_min = start */
590 PUSHB_2,
591 sal_point_max,
593 CINDEX,
594 WS, /* sal_point_max = start */
596 PUSHB_1,
598 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
600 SWAP,
601 DUP,
602 PUSHB_1,
604 CINDEX, /* s: start end end start */
605 LT, /* start > end */
607 /* we have a wrap-around segment with two more arguments */
608 /* to give the last and first point of the contour, respectively; */
609 /* our job is to store a segment `start'-`last', */
610 /* and to get extrema for the two segments */
611 /* `start'-`last' and `first'-`end' */
613 /* s: first last start end */
614 PUSHB_1,
615 sal_i,
617 PUSHB_1,
619 CINDEX,
620 WS, /* sal[sal_i] = last */
622 ROLL,
623 ROLL, /* s: first end last start */
624 DUP,
625 ROLL,
626 SWAP, /* s: first end start last start */
627 SUB, /* s: first end start loop_count */
629 PUSHB_1,
630 bci_get_point_extrema,
631 LOOPCALL,
632 /* clean up stack */
633 POP,
635 SWAP, /* s: end first */
636 PUSHB_1,
638 SUB,
639 DUP,
640 ROLL, /* s: (first - 1) (first - 1) end */
641 SWAP,
642 SUB, /* s: (first - 1) loop_count */
644 PUSHB_1,
645 bci_get_point_extrema,
646 LOOPCALL,
647 /* clean up stack */
648 POP,
650 ELSE, /* s: start end */
651 PUSHB_1,
652 sal_i,
654 PUSHB_1,
656 CINDEX,
657 WS, /* sal[sal_i] = end */
659 PUSHB_1,
661 CINDEX,
662 SUB, /* s: start loop_count */
664 PUSHB_1,
665 bci_get_point_extrema,
666 LOOPCALL,
667 /* clean up stack */
668 POP,
669 EIF,
671 /* the twilight point representing a segment */
672 /* is in the middle between the minimum and maximum */
673 PUSHB_1,
674 sal_point_max,
676 PUSHB_1,
677 sal_point_min,
679 MD_orig,
680 PUSHB_1,
681 2*64,
682 DIV, /* s: delta */
684 PUSHB_4,
685 sal_j,
688 sal_point_min,
690 MDAP_noround, /* set rp0 and rp1 to `sal_point_min' */
691 SZP1, /* set zp1 to twilight zone 0 */
692 SZP2, /* set zp2 to twilight zone 0 */
695 DUP, /* s: delta point[sal_j] point[sal_j] */
696 ALIGNRP, /* align `point[sal_j]' with `sal_point_min' */
697 PUSHB_1,
699 CINDEX, /* s: delta point[sal_j] delta */
700 SHPIX, /* shift `point[sal_j]' by `delta' */
702 PUSHB_1,
703 sal_k,
705 DUP, /* s: delta point[sal_k] point[sal_k] */
706 ALIGNRP, /* align `point[sal_k]' with `sal_point_min' */
707 SWAP,
708 SHPIX, /* shift `point[sal_k]' by `delta' */
710 PUSHB_6,
711 sal_k,
713 sal_k,
714 sal_j,
716 sal_j,
718 ADD, /* original_twilight_point = original_twilight_point + 1 */
721 ADD, /* hinted_twilight_point = hinted_twilight_point + 1 */
724 ENDF,
730 * bci_create_segments
732 * Set up segments by defining point ranges which defines them
733 * and computing twilight points to represent them.
735 * in: num_segments (N)
736 * segment_start_0
737 * segment_end_0
738 * [contour_last 0 (if wrap-around segment)]
739 * [contour_first 0 (if wrap-around segment)]
740 * segment_start_1
741 * segment_end_1
742 * [contour_last 0 (if wrap-around segment)]
743 * [contour_first 0 (if wrap-around segment)]
744 * ...
745 * segment_start_(N-1)
746 * segment_end_(N-1)
747 * [contour_last (N-1) (if wrap-around segment)]
748 * [contour_first (N-1) (if wrap-around segment)]
750 * uses: bci_create_segment
752 * sal: sal_i (start of current segment)
753 * sal_j (current original twilight point)
754 * sal_k (current hinted twilight point)
755 * sal_num_segments
758 unsigned char FPGM(bci_create_segments) [] = {
760 PUSHB_1,
761 bci_create_segments,
762 FDEF,
764 /* all our measurements are taken along the y axis */
765 SVTCA_y,
767 PUSHB_1,
768 sal_num_segments,
769 SWAP,
770 WS, /* sal_num_segments = num_segments */
772 PUSHB_7,
773 sal_segment_offset,
774 sal_segment_offset,
775 sal_num_segments,
777 sal_k,
779 sal_j,
780 sal_num_segments,
782 WS, /* sal_j = num_segments (offset for original points) */
783 WS, /* sal_k = 0 (offset for hinted points) */
786 DUP,
787 ADD,
788 ADD,
789 PUSHB_1,
791 SUB, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
793 /* `bci_create_segment_point' also increases the loop counter by 1; */
794 /* this effectively means we have a loop step of 2 */
795 PUSHB_2,
796 bci_create_segment,
797 bci_loop,
798 CALL,
800 ENDF,
806 * bci_align_segment
808 * Align all points in a segment to the twilight point in rp0.
809 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
811 * in: segment_index
814 unsigned char FPGM(bci_align_segment) [] = {
816 PUSHB_1,
817 bci_align_segment,
818 FDEF,
820 /* we need the values of `sal_segment_offset + 2*segment_index' */
821 /* and `sal_segment_offset + 2*segment_index + 1' */
822 DUP,
823 ADD,
824 PUSHB_1,
825 sal_segment_offset,
826 ADD,
827 DUP,
829 SWAP,
830 PUSHB_1,
832 ADD,
833 RS, /* s: first last */
835 /* start_loop: */
836 PUSHB_1,
838 CINDEX, /* s: first last first */
839 PUSHB_1,
841 CINDEX, /* s: first last first last */
842 LTEQ, /* first <= end */
843 IF, /* s: first last */
844 SWAP,
845 DUP, /* s: last first first */
846 ALIGNRP, /* align point with index `first' with rp0 */
848 PUSHB_1,
850 ADD, /* first = first + 1 */
851 SWAP, /* s: first last */
853 PUSHB_1,
855 NEG,
856 JMPR, /* goto start_loop */
858 ELSE,
859 POP,
860 POP,
861 EIF,
863 ENDF,
868 * bci_align_segments
870 * Align segments to the twilight point in rp0.
871 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
873 * in: first_segment
874 * loop_counter (N)
875 * segment_1
876 * segment_2
877 * ...
878 * segment_N
880 * uses: handle_segment
884 unsigned char FPGM(bci_align_segments) [] = {
886 PUSHB_1,
887 bci_align_segments,
888 FDEF,
890 PUSHB_1,
891 bci_align_segment,
892 CALL,
894 PUSHB_1,
895 bci_align_segment,
896 LOOPCALL,
898 ENDF,
904 * bci_ip_before_align_point
906 * Auxiliary function for `bci_action_ip_before'.
908 * in: point
911 unsigned char FPGM(bci_ip_before_align_point) [] = {
913 PUSHB_1,
914 bci_ip_before_align_point,
915 FDEF,
917 POP, /* XXX */
919 ENDF,
925 * bci_ip_after_align_point
927 * Auxiliary function for `bci_action_ip_after'.
929 * in: point
932 unsigned char FPGM(bci_ip_after_align_point) [] = {
934 PUSHB_1,
935 bci_ip_after_align_point,
936 FDEF,
938 POP, /* XXX */
940 ENDF,
946 * bci_ip_on_align_point
948 * Auxiliary function for `bci_ip_on_align_points'.
950 * in: point
953 unsigned char FPGM(bci_ip_on_align_point) [] = {
955 PUSHB_1,
956 bci_ip_on_align_point,
957 FDEF,
959 POP, /* XXX */
961 ENDF,
967 * bci_ip_on_align_points
969 * Auxiliary function for `bci_action_ip_on'.
971 * in: edge
972 * loop_counter (N)
973 * point_1
974 * point_2
975 * ...
976 * point_N
978 * uses: bci_ip_on_align_point
981 unsigned char FPGM(bci_ip_on_align_points) [] = {
983 PUSHB_1,
984 bci_ip_on_align_points,
985 FDEF,
987 POP, /* XXX */
989 PUSHB_1,
990 bci_ip_on_align_point,
991 LOOPCALL,
993 ENDF,
999 * bci_ip_between_align_point
1001 * Auxiliary function for `bci_ip_between_align_points'.
1003 * in: point
1006 unsigned char FPGM(bci_ip_between_align_point) [] = {
1008 PUSHB_1,
1009 bci_ip_between_align_point,
1010 FDEF,
1012 POP, /* XXX */
1014 ENDF,
1020 * bci_ip_between_align_points
1022 * Auxiliary function for `bci_action_ip_between'.
1024 * in: before_edge
1025 * after_edge
1026 * loop_counter (N)
1027 * point_1
1028 * point_2
1029 * ...
1030 * point_N
1032 * uses: bci_ip_between_align_point
1035 unsigned char FPGM(bci_ip_between_align_points) [] = {
1037 PUSHB_1,
1038 bci_ip_between_align_points,
1039 FDEF,
1041 POP, /* XXX */
1042 POP,
1044 PUSHB_1,
1045 bci_ip_between_align_point,
1046 LOOPCALL,
1048 ENDF,
1054 * bci_action_ip_before
1056 * Handle `ip_before' data to align points located before the first edge.
1058 * in: first_edge
1059 * loop_counter (N)
1060 * point_1
1061 * point_2
1062 * ...
1063 * point_N
1065 * uses: bci_ip_before_align_point
1068 unsigned char FPGM(bci_action_ip_before) [] = {
1070 PUSHB_1,
1071 bci_action_ip_before,
1072 FDEF,
1074 POP, /* XXX */
1076 PUSHB_1,
1077 bci_ip_before_align_point,
1078 LOOPCALL,
1080 ENDF,
1086 * bci_action_ip_after
1088 * Handle `ip_after' data to align points located after the last edge.
1090 * in: last_edge
1091 * loop_counter (N)
1092 * point_1
1093 * point_2
1094 * ...
1095 * point_N
1097 * uses: bci_ip_after_align_point
1100 unsigned char FPGM(bci_action_ip_after) [] = {
1102 PUSHB_1,
1103 bci_action_ip_after,
1104 FDEF,
1106 POP, /* XXX */
1108 PUSHB_1,
1109 bci_ip_after_align_point,
1110 LOOPCALL,
1112 ENDF,
1118 * bci_action_ip_on
1120 * Handle `ip_on' data to align points located on an edge coordinate (but
1121 * not part of an edge).
1123 * in: loop_counter (M)
1124 * edge_1
1125 * loop_counter (N_1)
1126 * point_1
1127 * point_2
1128 * ...
1129 * point_N_1
1130 * edge_2
1131 * loop_counter (N_2)
1132 * point_1
1133 * point_2
1134 * ...
1135 * point_N_2
1136 * ...
1137 * edge_M
1138 * loop_counter (N_M)
1139 * point_1
1140 * point_2
1141 * ...
1142 * point_N_M
1144 * uses: bci_ip_on_align_points
1147 unsigned char FPGM(bci_action_ip_on) [] = {
1149 PUSHB_1,
1150 bci_action_ip_on,
1151 FDEF,
1153 PUSHB_1,
1154 bci_ip_on_align_points,
1155 LOOPCALL,
1157 ENDF,
1163 * bci_action_ip_between
1165 * Handle `ip_between' data to align points located between two edges.
1167 * in: loop_counter (M)
1168 * before_edge_1
1169 * after_edge_1
1170 * loop_counter (N_1)
1171 * point_1
1172 * point_2
1173 * ...
1174 * point_N_1
1175 * before_edge_2
1176 * after_edge_2
1177 * loop_counter (N_2)
1178 * point_1
1179 * point_2
1180 * ...
1181 * point_N_2
1182 * ...
1183 * before_edge_M
1184 * after_edge_M
1185 * loop_counter (N_M)
1186 * point_1
1187 * point_2
1188 * ...
1189 * point_N_M
1191 * uses: bci_ip_between_align_points
1194 unsigned char FPGM(bci_action_ip_between) [] = {
1196 PUSHB_1,
1197 bci_action_ip_between,
1198 FDEF,
1200 PUSHB_1,
1201 bci_ip_between_align_points,
1202 LOOPCALL,
1204 ENDF,
1210 * bci_action_adjust_bound
1212 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1213 * edge of the stem has already been moved, then moving it again if
1214 * necessary to stay bound.
1216 * in: edge2_is_serif
1217 * edge_is_round
1218 * edge_point (in twilight zone)
1219 * edge2_point (in twilight zone)
1220 * edge[-1] (in twilight zone)
1221 * ... stuff for bci_align_segments (edge) ...
1224 unsigned char FPGM(bci_action_adjust_bound) [] = {
1226 PUSHB_1,
1227 bci_action_adjust_bound,
1228 FDEF,
1230 PUSHB_1,
1232 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1234 PUSHB_1,
1236 CINDEX,
1237 PUSHB_1,
1238 sal_num_segments,
1240 ADD, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig */
1241 PUSHB_1,
1243 CINDEX,
1244 PUSHB_1,
1245 sal_num_segments,
1247 ADD, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1248 MD_cur, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1250 PUSHB_1,
1251 bci_compute_stem_width,
1252 CALL,
1253 NEG, /* s: edge[-1] edge2 edge -cur_len */
1255 ROLL, /* s: edge[-1] edge -cur_len edge2 */
1256 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1257 SWAP,
1258 DUP,
1259 DUP, /* s: edge[-1] -cur_len edge edge edge */
1260 ALIGNRP, /* align `edge' with `edge2' */
1261 ROLL,
1262 SHPIX, /* shift `edge' by -cur_len */
1264 SWAP, /* s: edge edge[-1] */
1265 DUP,
1266 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1267 GC_cur,
1268 PUSHB_1,
1270 CINDEX,
1271 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1272 GT, /* edge_pos < edge[-1]_pos */
1274 DUP,
1275 ALIGNRP, /* align `edge' to `edge[-1]' */
1276 EIF,
1278 MDAP_noround, /* set rp0 and rp1 to `edge' */
1280 PUSHB_2,
1281 bci_align_segments,
1283 SZP1, /* set zp1 to normal zone 1 */
1284 CALL,
1286 ENDF,
1292 * bci_action_stem_bound
1294 * Handle the STEM action to align two edges of a stem, then moving one
1295 * edge again if necessary to stay bound.
1297 * The code after computing `cur_len' to shift `edge' and `edge2'
1298 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1300 * if cur_len < 96:
1301 * if cur_len < = 64:
1302 * u_off = 32
1303 * d_off = 32
1304 * else:
1305 * u_off = 38
1306 * d_off = 26
1308 * org_center = edge_orig + org_len / 2
1309 * cur_pos1 = ROUND(org_center)
1311 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1312 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1313 * if (delta1 < delta2):
1314 * cur_pos1 = cur_pos1 - u_off
1315 * else:
1316 * cur_pos1 = cur_pos1 + d_off
1318 * edge = cur_pos1 - cur_len / 2
1320 * else:
1321 * org_pos = anchor + (edge_orig - anchor_orig)
1322 * org_center = edge_orig + org_len / 2
1324 * cur_pos1 = ROUND(org_pos)
1325 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1326 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1327 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1329 * if (delta1 < delta2):
1330 * edge = cur_pos1
1331 * else:
1332 * edge = cur_pos2
1334 * edge2 = edge + cur_len
1336 * in: edge2_is_serif
1337 * edge_is_round
1338 * edge_point (in twilight zone)
1339 * edge2_point (in twilight zone)
1340 * edge[-1] (in twilight zone)
1341 * ... stuff for bci_align_segments (edge) ...
1342 * ... stuff for bci_align_segments (edge2)...
1344 * sal: sal_anchor
1345 * sal_temp1
1346 * sal_temp2
1347 * sal_temp3
1348 * sal_num_segments
1351 #undef sal_u_off
1352 #define sal_u_off sal_temp1
1353 #undef sal_d_off
1354 #define sal_d_off sal_temp2
1355 #undef sal_org_len
1356 #define sal_org_len sal_temp3
1357 #undef sal_edge2
1358 #define sal_edge2 sal_temp3
1360 unsigned char FPGM(bci_action_stem_bound) [] = {
1362 PUSHB_1,
1363 bci_action_stem_bound,
1364 FDEF,
1366 PUSHB_1,
1368 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1370 PUSHB_1,
1372 CINDEX,
1373 PUSHB_1,
1374 sal_num_segments,
1376 ADD,
1377 PUSHB_1,
1379 CINDEX,
1380 DUP,
1381 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1382 PUSHB_1,
1383 sal_num_segments,
1385 ADD, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1387 MD_cur, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1388 DUP,
1389 PUSHB_1,
1390 sal_org_len,
1391 SWAP,
1394 PUSHB_1,
1395 bci_compute_stem_width,
1396 CALL, /* s: edge[-1] edge2 edge cur_len */
1398 DUP,
1399 PUSHB_1,
1401 LT, /* cur_len < 96 */
1403 DUP,
1404 PUSHB_1,
1406 LTEQ, /* cur_len <= 64 */
1408 PUSHB_4,
1409 sal_u_off,
1411 sal_d_off,
1414 ELSE,
1415 PUSHB_4,
1416 sal_u_off,
1418 sal_d_off,
1420 EIF,
1424 SWAP, /* s: edge[-1] edge2 cur_len edge */
1425 DUP,
1426 PUSHB_1,
1427 sal_num_segments,
1429 ADD, /* s: edge[-1] edge2 cur_len edge edge_orig */
1431 GC_cur,
1432 PUSHB_1,
1433 sal_org_len,
1435 PUSHB_1,
1436 2*64,
1437 DIV,
1438 ADD, /* s: edge[-1] edge2 cur_len edge org_center */
1440 DUP,
1441 PUSHB_1,
1442 bci_round,
1443 CALL, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1445 DUP,
1446 ROLL,
1447 ROLL,
1448 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1450 DUP,
1451 PUSHB_1,
1452 sal_u_off,
1454 ADD,
1455 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1457 SWAP,
1458 PUSHB_1,
1459 sal_d_off,
1461 SUB,
1462 ABS, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1464 LT, /* delta1 < delta2 */
1466 PUSHB_1,
1467 sal_u_off,
1469 SUB, /* cur_pos1 = cur_pos1 - u_off */
1471 ELSE,
1472 PUSHB_1,
1473 sal_d_off,
1475 ADD, /* cur_pos1 = cur_pos1 + d_off */
1476 EIF, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1478 PUSHB_1,
1480 CINDEX,
1481 PUSHB_1,
1482 2*64,
1483 DIV,
1484 SUB, /* arg = cur_pos1 - cur_len/2 */
1486 SWAP, /* s: edge[-1] edge2 cur_len arg edge */
1487 DUP,
1488 DUP,
1489 PUSHB_1,
1491 MINDEX,
1492 SWAP, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1493 GC_cur,
1494 SUB,
1495 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1497 ELSE,
1498 SWAP, /* s: edge[-1] edge2 cur_len edge */
1499 DUP,
1500 PUSHB_1,
1501 sal_num_segments,
1503 ADD, /* s: edge[-1] edge2 cur_len edge edge_orig */
1505 GC_cur,
1506 PUSHB_1,
1507 sal_org_len,
1509 PUSHB_1,
1510 2*64,
1511 DIV,
1512 ADD, /* s: edge[-1] edge2 cur_len edge org_center */
1514 PUSHB_1,
1515 sal_anchor,
1517 GC_cur, /* s: edge[-1] edge2 cur_len edge org_center anchor_pos */
1518 PUSHB_1,
1520 CINDEX,
1521 PUSHB_1,
1522 sal_num_segments,
1524 ADD,
1525 PUSHB_1,
1526 sal_anchor,
1528 PUSHB_1,
1529 sal_num_segments,
1531 ADD,
1532 MD_cur,
1533 ADD, /* s: edge[-1] edge2 cur_len edge org_center org_pos */
1535 DUP,
1536 PUSHB_1,
1537 bci_round,
1538 CALL, /* cur_pos1 = ROUND(org_pos) */
1539 SWAP,
1540 PUSHB_1,
1541 sal_org_len,
1543 ADD,
1544 PUSHB_1,
1545 bci_round,
1546 CALL,
1547 PUSHB_1,
1549 CINDEX,
1550 SUB, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1552 PUSHB_1,
1554 CINDEX,
1555 PUSHB_1,
1556 2*64,
1557 DIV,
1558 PUSHB_1,
1560 MINDEX,
1561 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1563 DUP,
1564 PUSHB_1,
1566 CINDEX,
1567 ADD,
1568 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1569 SWAP,
1570 PUSHB_1,
1572 CINDEX,
1573 ADD,
1574 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1575 LT, /* delta1 < delta2 */
1577 POP, /* arg = cur_pos1 */
1578 ELSE,
1579 SWAP,
1580 POP, /* arg = cur_pos2 */
1581 EIF, /* s: edge[-1] edge2 cur_len edge arg */
1582 SWAP,
1583 DUP,
1584 DUP,
1585 PUSHB_1,
1587 MINDEX,
1588 SWAP, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1589 GC_cur,
1590 SUB,
1591 SHPIX, /* edge = arg */
1592 EIF, /* s: edge[-1] edge2 cur_len edge */
1594 ROLL, /* s: edge[-1] cur_len edge edge2 */
1595 DUP,
1596 DUP,
1597 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
1598 PUSHB_1,
1599 sal_edge2,
1600 SWAP,
1601 WS, /* s: edge[-1] cur_len edge edge2 */
1602 ROLL,
1603 SHPIX, /* edge2 = edge + cur_len */
1605 SWAP, /* s: edge edge[-1] */
1606 DUP,
1607 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1608 GC_cur,
1609 PUSHB_1,
1611 CINDEX,
1612 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1613 GT, /* edge_pos < edge[-1]_pos */
1615 DUP,
1616 ALIGNRP, /* align `edge' to `edge[-1]' */
1617 EIF,
1619 MDAP_noround, /* set rp0 and rp1 to `edge' */
1621 PUSHB_2,
1622 bci_align_segments,
1624 SZP1, /* set zp1 to normal zone 1 */
1625 CALL,
1627 PUSHB_1,
1628 sal_edge2,
1630 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1632 PUSHB_1,
1633 bci_align_segments,
1634 CALL,
1636 ENDF,
1642 * bci_action_link
1644 * Handle the LINK action to link an edge to another one.
1646 * in: stem_is_serif
1647 * base_is_round
1648 * base_point (in twilight zone)
1649 * stem_point (in twilight zone)
1650 * ... stuff for bci_align_segments (base) ...
1653 unsigned char FPGM(bci_action_link) [] = {
1655 PUSHB_1,
1656 bci_action_link,
1657 FDEF,
1659 PUSHB_1,
1661 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1663 PUSHB_1,
1665 CINDEX,
1666 PUSHB_1,
1667 sal_num_segments,
1669 ADD,
1670 PUSHB_1,
1672 MINDEX,
1673 DUP,
1674 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1675 PUSHB_1,
1676 sal_num_segments,
1678 ADD, /* s: stem is_round is_serif stem_orig base_orig */
1680 MD_cur, /* s: stem is_round is_serif dist_orig */
1682 PUSHB_1,
1683 bci_compute_stem_width,
1684 CALL, /* s: stem new_dist */
1686 SWAP,
1687 DUP,
1688 ALIGNRP, /* align `stem_point' with `base_point' */
1689 DUP,
1690 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
1691 SWAP,
1692 SHPIX, /* stem_point = base_point + new_dist */
1694 PUSHB_2,
1695 bci_align_segments,
1697 SZP1, /* set zp1 to normal zone 1 */
1698 CALL,
1700 ENDF,
1706 * bci_action_anchor
1708 * Handle the ANCHOR action to align two edges
1709 * and to set the edge anchor.
1711 * The code after computing `cur_len' to shift `edge' and `edge2'
1712 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1714 * if cur_len < 96:
1715 * if cur_len < = 64:
1716 * u_off = 32
1717 * d_off = 32
1718 * else:
1719 * u_off = 38
1720 * d_off = 26
1722 * org_center = edge_orig + org_len / 2
1723 * cur_pos1 = ROUND(org_center)
1725 * error1 = ABS(org_center - (cur_pos1 - u_off))
1726 * error2 = ABS(org_center - (cur_pos1 + d_off))
1727 * if (error1 < error2):
1728 * cur_pos1 = cur_pos1 - u_off
1729 * else:
1730 * cur_pos1 = cur_pos1 + d_off
1732 * edge = cur_pos1 - cur_len / 2
1733 * edge2 = edge + cur_len
1735 * else:
1736 * edge = ROUND(edge_orig)
1738 * in: edge2_is_serif
1739 * edge_is_round
1740 * edge_point (in twilight zone)
1741 * edge2_point (in twilight zone)
1742 * ... stuff for bci_align_segments (edge) ...
1744 * sal: sal_anchor
1745 * sal_temp1
1746 * sal_temp2
1747 * sal_temp3
1750 #undef sal_u_off
1751 #define sal_u_off sal_temp1
1752 #undef sal_d_off
1753 #define sal_d_off sal_temp2
1754 #undef sal_org_len
1755 #define sal_org_len sal_temp3
1757 unsigned char FPGM(bci_action_anchor) [] = {
1759 PUSHB_1,
1760 bci_action_anchor,
1761 FDEF,
1763 /* store anchor point number in `sal_anchor' */
1764 PUSHB_2,
1765 sal_anchor,
1767 CINDEX,
1768 WS, /* sal_anchor = edge_point */
1770 PUSHB_1,
1772 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1774 PUSHB_1,
1776 CINDEX,
1777 PUSHB_1,
1778 sal_num_segments,
1780 ADD,
1781 PUSHB_1,
1783 CINDEX,
1784 DUP,
1785 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1786 PUSHB_1,
1787 sal_num_segments,
1789 ADD, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
1791 MD_cur, /* s: edge2 edge is_round is_serif org_len */
1792 DUP,
1793 PUSHB_1,
1794 sal_org_len,
1795 SWAP,
1798 PUSHB_1,
1799 bci_compute_stem_width,
1800 CALL, /* s: edge2 edge cur_len */
1802 DUP,
1803 PUSHB_1,
1805 LT, /* cur_len < 96 */
1807 DUP,
1808 PUSHB_1,
1810 LTEQ, /* cur_len <= 64 */
1812 PUSHB_4,
1813 sal_u_off,
1815 sal_d_off,
1818 ELSE,
1819 PUSHB_4,
1820 sal_u_off,
1822 sal_d_off,
1824 EIF,
1828 SWAP, /* s: edge2 cur_len edge */
1829 DUP,
1830 PUSHB_1,
1831 sal_num_segments,
1833 ADD, /* s: edge2 cur_len edge edge_orig */
1835 GC_cur,
1836 PUSHB_1,
1837 sal_org_len,
1839 PUSHB_1,
1840 2*64,
1841 DIV,
1842 ADD, /* s: edge2 cur_len edge org_center */
1844 DUP,
1845 PUSHB_1,
1846 bci_round,
1847 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
1849 DUP,
1850 ROLL,
1851 ROLL,
1852 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1854 DUP,
1855 PUSHB_1,
1856 sal_u_off,
1858 ADD,
1859 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1861 SWAP,
1862 PUSHB_1,
1863 sal_d_off,
1865 SUB,
1866 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1868 LT, /* error1 < error2 */
1870 PUSHB_1,
1871 sal_u_off,
1873 SUB, /* cur_pos1 = cur_pos1 - u_off */
1875 ELSE,
1876 PUSHB_1,
1877 sal_d_off,
1879 ADD, /* cur_pos1 = cur_pos1 + d_off */
1880 EIF, /* s: edge2 cur_len edge cur_pos1 */
1882 PUSHB_1,
1884 CINDEX,
1885 PUSHB_1,
1886 2*64,
1887 DIV,
1888 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1890 PUSHB_1,
1892 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1893 GC_cur,
1894 SUB,
1895 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1897 SWAP, /* s: cur_len edge2 */
1898 DUP,
1899 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
1900 SWAP,
1901 SHPIX, /* edge2 = edge1 + cur_len */
1903 ELSE,
1904 POP, /* s: edge2 edge */
1905 DUP,
1906 PUSHB_1,
1907 sal_num_segments,
1909 ADD, /* s: edge2 edge edge_orig */
1911 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
1912 DUP,
1913 ALIGNRP, /* align `edge' with `edge_orig' */
1914 MDAP_round, /* round `edge' */
1916 /* clean up stack */
1917 POP,
1918 EIF,
1920 PUSHB_2,
1921 bci_align_segments,
1923 SZP1, /* set zp1 to normal zone 1 */
1924 CALL,
1926 ENDF,
1932 * bci_action_blue_anchor
1934 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1935 * and to set the edge anchor.
1937 * in: anchor_point (in twilight zone)
1938 * blue_cvt_idx
1939 * edge_point (in twilight zone)
1940 * ... stuff for bci_align_segments (edge) ...
1942 * sal: sal_anchor
1945 unsigned char FPGM(bci_action_blue_anchor) [] = {
1947 PUSHB_1,
1948 bci_action_blue_anchor,
1949 FDEF,
1951 /* store anchor point number in `sal_anchor' */
1952 PUSHB_1,
1953 sal_anchor,
1954 SWAP,
1957 PUSHB_1,
1959 SZP0, /* set zp0 to twilight zone 0 */
1961 /* move `edge_point' to `blue_cvt_idx' position */
1962 MIAP_noround, /* this also sets rp0 */
1964 PUSHB_2,
1965 bci_align_segments,
1967 SZP1, /* set zp1 to normal zone 1 */
1968 CALL,
1970 ENDF,
1976 * bci_action_adjust
1978 * Handle the ADJUST action to align an edge of a stem if the other edge
1979 * of the stem has already been moved.
1981 * in: edge2_is_serif
1982 * edge_is_round
1983 * edge_point (in twilight zone)
1984 * edge2_point (in twilight zone)
1985 * ... stuff for bci_align_segments (edge) ...
1988 unsigned char FPGM(bci_action_adjust) [] = {
1990 PUSHB_1,
1991 bci_action_adjust,
1992 FDEF,
1994 PUSHB_1,
1996 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1998 PUSHB_1,
2000 CINDEX,
2001 PUSHB_1,
2002 sal_num_segments,
2004 ADD, /* s: edge2 edge is_round is_serif edge2_orig */
2005 PUSHB_1,
2007 CINDEX,
2008 PUSHB_1,
2009 sal_num_segments,
2011 ADD, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2012 MD_cur, /* s: edge2 edge is_round is_serif org_len */
2014 PUSHB_1,
2015 bci_compute_stem_width,
2016 CALL,
2017 NEG, /* s: edge2 edge -cur_len */
2019 ROLL,
2020 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2021 SWAP,
2022 DUP,
2023 DUP, /* s: -cur_len edge edge edge */
2024 ALIGNRP, /* align `edge' with `edge2' */
2025 ROLL,
2026 SHPIX, /* shift `edge' by -cur_len */
2028 MDAP_noround, /* set rp0 and rp1 to `edge' */
2030 PUSHB_2,
2031 bci_align_segments,
2033 SZP1, /* set zp1 to normal zone 1 */
2034 CALL,
2036 ENDF,
2042 * bci_action_stem
2044 * Handle the STEM action to align two edges of a stem.
2046 * The code after computing `cur_len' to shift `edge' and `edge2'
2047 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2049 * if cur_len < 96:
2050 * if cur_len < = 64:
2051 * u_off = 32
2052 * d_off = 32
2053 * else:
2054 * u_off = 38
2055 * d_off = 26
2057 * org_center = edge_orig + org_len / 2
2058 * cur_pos1 = ROUND(org_center)
2060 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2061 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2062 * if (delta1 < delta2):
2063 * cur_pos1 = cur_pos1 - u_off
2064 * else:
2065 * cur_pos1 = cur_pos1 + d_off
2067 * edge = cur_pos1 - cur_len / 2
2069 * else:
2070 * org_pos = anchor + (edge_orig - anchor_orig)
2071 * org_center = edge_orig + org_len / 2
2073 * cur_pos1 = ROUND(org_pos)
2074 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2075 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2076 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2078 * if (delta1 < delta2):
2079 * edge = cur_pos1
2080 * else:
2081 * edge = cur_pos2
2083 * edge2 = edge + cur_len
2085 * in: edge2_is_serif
2086 * edge_is_round
2087 * edge_point (in twilight zone)
2088 * edge2_point (in twilight zone)
2089 * ... stuff for bci_align_segments (edge) ...
2090 * ... stuff for bci_align_segments (edge2)...
2092 * sal: sal_anchor
2093 * sal_temp1
2094 * sal_temp2
2095 * sal_temp3
2096 * sal_num_segments
2099 #undef sal_u_off
2100 #define sal_u_off sal_temp1
2101 #undef sal_d_off
2102 #define sal_d_off sal_temp2
2103 #undef sal_org_len
2104 #define sal_org_len sal_temp3
2105 #undef sal_edge2
2106 #define sal_edge2 sal_temp3
2108 unsigned char FPGM(bci_action_stem) [] = {
2110 PUSHB_1,
2111 bci_action_stem,
2112 FDEF,
2114 PUSHB_1,
2116 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2118 PUSHB_1,
2120 CINDEX,
2121 PUSHB_1,
2122 sal_num_segments,
2124 ADD,
2125 PUSHB_1,
2127 CINDEX,
2128 DUP,
2129 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2130 PUSHB_1,
2131 sal_num_segments,
2133 ADD, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2135 MD_cur, /* s: edge2 edge is_round is_serif org_len */
2136 DUP,
2137 PUSHB_1,
2138 sal_org_len,
2139 SWAP,
2142 PUSHB_1,
2143 bci_compute_stem_width,
2144 CALL, /* s: edge2 edge cur_len */
2146 DUP,
2147 PUSHB_1,
2149 LT, /* cur_len < 96 */
2151 DUP,
2152 PUSHB_1,
2154 LTEQ, /* cur_len <= 64 */
2156 PUSHB_4,
2157 sal_u_off,
2159 sal_d_off,
2162 ELSE,
2163 PUSHB_4,
2164 sal_u_off,
2166 sal_d_off,
2168 EIF,
2172 SWAP, /* s: edge2 cur_len edge */
2173 DUP,
2174 PUSHB_1,
2175 sal_num_segments,
2177 ADD, /* s: edge2 cur_len edge edge_orig */
2179 GC_cur,
2180 PUSHB_1,
2181 sal_org_len,
2183 PUSHB_1,
2184 2*64,
2185 DIV,
2186 ADD, /* s: edge2 cur_len edge org_center */
2188 DUP,
2189 PUSHB_1,
2190 bci_round,
2191 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2193 DUP,
2194 ROLL,
2195 ROLL,
2196 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2198 DUP,
2199 PUSHB_1,
2200 sal_u_off,
2202 ADD,
2203 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2205 SWAP,
2206 PUSHB_1,
2207 sal_d_off,
2209 SUB,
2210 ABS, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2212 LT, /* delta1 < delta2 */
2214 PUSHB_1,
2215 sal_u_off,
2217 SUB, /* cur_pos1 = cur_pos1 - u_off */
2219 ELSE,
2220 PUSHB_1,
2221 sal_d_off,
2223 ADD, /* cur_pos1 = cur_pos1 + d_off */
2224 EIF, /* s: edge2 cur_len edge cur_pos1 */
2226 PUSHB_1,
2228 CINDEX,
2229 PUSHB_1,
2230 2*64,
2231 DIV,
2232 SUB, /* arg = cur_pos1 - cur_len/2 */
2234 SWAP, /* s: edge2 cur_len arg edge */
2235 DUP,
2236 PUSHB_1,
2238 MINDEX,
2239 SWAP, /* s: edge2 cur_len edge arg edge */
2240 GC_cur,
2241 SUB,
2242 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2244 ELSE,
2245 SWAP, /* s: edge2 cur_len edge */
2246 DUP,
2247 PUSHB_1,
2248 sal_num_segments,
2250 ADD, /* s: edge2 cur_len edge edge_orig */
2252 GC_cur,
2253 PUSHB_1,
2254 sal_org_len,
2256 PUSHB_1,
2257 2*64,
2258 DIV,
2259 ADD, /* s: edge2 cur_len edge org_center */
2261 PUSHB_1,
2262 sal_anchor,
2264 GC_cur, /* s: edge2 cur_len edge org_center anchor_pos */
2265 PUSHB_1,
2267 CINDEX,
2268 PUSHB_1,
2269 sal_num_segments,
2271 ADD,
2272 PUSHB_1,
2273 sal_anchor,
2275 PUSHB_1,
2276 sal_num_segments,
2278 ADD,
2279 MD_cur,
2280 ADD, /* s: edge2 cur_len edge org_center org_pos */
2282 DUP,
2283 PUSHB_1,
2284 bci_round,
2285 CALL, /* cur_pos1 = ROUND(org_pos) */
2286 SWAP,
2287 PUSHB_1,
2288 sal_org_len,
2290 ADD,
2291 PUSHB_1,
2292 bci_round,
2293 CALL,
2294 PUSHB_1,
2296 CINDEX,
2297 SUB, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2299 PUSHB_1,
2301 CINDEX,
2302 PUSHB_1,
2303 2*64,
2304 DIV,
2305 PUSHB_1,
2307 MINDEX,
2308 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2310 DUP,
2311 PUSHB_1,
2313 CINDEX,
2314 ADD,
2315 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2316 SWAP,
2317 PUSHB_1,
2319 CINDEX,
2320 ADD,
2321 ABS, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2322 LT, /* delta1 < delta2 */
2324 POP, /* arg = cur_pos1 */
2325 ELSE,
2326 SWAP,
2327 POP, /* arg = cur_pos2 */
2328 EIF, /* s: edge2 cur_len edge arg */
2329 SWAP,
2330 DUP,
2331 PUSHB_1,
2333 MINDEX,
2334 SWAP, /* s: edge2 cur_len edge arg edge */
2335 GC_cur,
2336 SUB,
2337 SHPIX, /* edge = arg */
2338 EIF, /* s: edge2 cur_len */
2340 SWAP, /* s: cur_len edge2 */
2341 DUP,
2342 DUP,
2343 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2344 PUSHB_1,
2345 sal_edge2,
2346 SWAP,
2347 WS, /* s: cur_len edge2 */
2348 SWAP,
2349 SHPIX, /* edge2 = edge + cur_len */
2351 PUSHB_2,
2352 bci_align_segments,
2354 SZP1, /* set zp1 to normal zone 1 */
2355 CALL,
2357 PUSHB_1,
2358 sal_edge2,
2360 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2362 PUSHB_1,
2363 bci_align_segments,
2364 CALL,
2365 ENDF,
2371 * bci_action_blue
2373 * Handle the BLUE action to align an edge with a blue zone.
2375 * in: blue_cvt_idx
2376 * edge_point (in twilight zone)
2377 * ... stuff for bci_align_segments (edge) ...
2380 unsigned char FPGM(bci_action_blue) [] = {
2382 PUSHB_1,
2383 bci_action_blue,
2384 FDEF,
2386 PUSHB_1,
2388 SZP0, /* set zp0 to twilight zone 0 */
2390 /* move `edge_point' to `blue_cvt_idx' position */
2391 MIAP_noround, /* this also sets rp0 */
2393 PUSHB_2,
2394 bci_align_segments,
2396 SZP1, /* set zp1 to normal zone 1 */
2397 CALL,
2399 ENDF,
2405 * bci_action_serif
2407 * Handle the SERIF action to align a serif with its base.
2409 * in: serif_point (in twilight zone)
2410 * base_point (in twilight zone)
2411 * ... stuff for bci_align_segments (serif) ...
2414 unsigned char FPGM(bci_action_serif) [] = {
2416 PUSHB_1,
2417 bci_action_serif,
2418 FDEF,
2420 PUSHB_1,
2422 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2424 DUP,
2425 DUP,
2426 PUSHB_1,
2428 MINDEX, /* s: serif serif serif base */
2429 PUSHB_1,
2431 CINDEX,
2432 PUSHB_1,
2433 sal_num_segments,
2435 ADD, /* s: serif serif serif base serif_orig */
2436 SWAP,
2437 DUP,
2438 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2439 PUSHB_1,
2440 sal_num_segments,
2442 ADD, /* s: serif serif serif serif_orig base_orig */
2443 MD_cur,
2444 SWAP,
2445 ALIGNRP, /* align `serif_point' with `base_point' */
2446 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2448 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2450 PUSHB_2,
2451 bci_align_segments,
2453 SZP1, /* set zp1 to normal zone 1 */
2454 CALL,
2456 ENDF,
2462 * bci_action_serif_lower_bound
2464 * Handle the SERIF action to align a serif with its base, then moving it
2465 * again if necessary to stay within a lower bound.
2467 * in: serif_point (in twilight zone)
2468 * base_point (in twilight zone)
2469 * edge[-1] (in twilight zone)
2470 * ... stuff for bci_align_segments (serif) ...
2473 unsigned char FPGM(bci_action_serif_lower_bound) [] = {
2475 PUSHB_1,
2476 bci_action_serif_lower_bound,
2477 FDEF,
2479 PUSHB_1,
2481 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2483 DUP,
2484 DUP,
2485 PUSHB_1,
2487 MINDEX, /* s: edge[-1] serif serif serif base */
2488 PUSHB_1,
2490 CINDEX,
2491 PUSHB_1,
2492 sal_num_segments,
2494 ADD, /* s: edge[-1] serif serif serif base serif_orig */
2495 SWAP,
2496 DUP,
2497 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2498 PUSHB_1,
2499 sal_num_segments,
2501 ADD, /* s: edge[-1] serif serif serif serif_orig base_orig */
2502 MD_cur,
2503 SWAP,
2504 ALIGNRP, /* align `serif_point' with `base_point' */
2505 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2507 SWAP, /* s: serif edge[-1] */
2508 DUP,
2509 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2510 GC_cur,
2511 PUSHB_1,
2513 CINDEX,
2514 GC_cur, /* s: serif edge[-1]_pos serif_pos */
2515 GT, /* serif_pos < edge[-1]_pos */
2517 DUP,
2518 ALIGNRP, /* align `serif' to `edge[-1]' */
2519 EIF,
2521 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2523 PUSHB_2,
2524 bci_align_segments,
2526 SZP1, /* set zp1 to normal zone 1 */
2527 CALL,
2529 ENDF,
2535 * bci_action_serif_upper_bound
2537 * Handle the SERIF action to align a serif with its base, then moving it
2538 * again if necessary to stay within an upper bound.
2540 * in: serif_point (in twilight zone)
2541 * base_point (in twilight zone)
2542 * edge[1] (in twilight zone)
2543 * ... stuff for bci_align_segments (serif) ...
2546 unsigned char FPGM(bci_action_serif_upper_bound) [] = {
2548 PUSHB_1,
2549 bci_action_serif_upper_bound,
2550 FDEF,
2552 PUSHB_1,
2554 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2556 DUP,
2557 DUP,
2558 PUSHB_1,
2560 MINDEX, /* s: edge[1] serif serif serif base */
2561 PUSHB_1,
2563 CINDEX,
2564 PUSHB_1,
2565 sal_num_segments,
2567 ADD, /* s: edge[1] serif serif serif base serif_orig */
2568 SWAP,
2569 DUP,
2570 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2571 PUSHB_1,
2572 sal_num_segments,
2574 ADD, /* s: edge[1] serif serif serif serif_orig base_orig */
2575 MD_cur,
2576 SWAP,
2577 ALIGNRP, /* align `serif_point' with `base_point' */
2578 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2580 SWAP, /* s: serif edge[1] */
2581 DUP,
2582 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2583 GC_cur,
2584 PUSHB_1,
2586 CINDEX,
2587 GC_cur, /* s: serif edge[1]_pos serif_pos */
2588 LT, /* serif_pos > edge[1]_pos */
2590 DUP,
2591 ALIGNRP, /* align `serif' to `edge[1]' */
2592 EIF,
2594 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2596 PUSHB_2,
2597 bci_align_segments,
2599 SZP1, /* set zp1 to normal zone 1 */
2600 CALL,
2602 ENDF,
2608 * bci_action_serif_lower_upper_bound
2610 * Handle the SERIF action to align a serif with its base, then moving it
2611 * again if necessary to stay within a lower and upper bound.
2613 * in: serif_point (in twilight zone)
2614 * base_point (in twilight zone)
2615 * edge[-1] (in twilight zone)
2616 * edge[1] (in twilight zone)
2617 * ... stuff for bci_align_segments (serif) ...
2620 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] = {
2622 PUSHB_1,
2623 bci_action_serif_lower_upper_bound,
2624 FDEF,
2626 PUSHB_1,
2628 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2630 DUP,
2631 DUP,
2632 PUSHB_1,
2634 MINDEX, /* s: edge[1] edge[-1] serif serif serif base */
2635 PUSHB_1,
2637 CINDEX,
2638 PUSHB_1,
2639 sal_num_segments,
2641 ADD, /* s: edge[1] edge[-1] serif serif serif base serif_orig */
2642 SWAP,
2643 DUP,
2644 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2645 PUSHB_1,
2646 sal_num_segments,
2648 ADD, /* s: edge[1] edge[-1] serif serif serif serif_orig base_orig */
2649 MD_cur,
2650 SWAP,
2651 ALIGNRP, /* align `serif_point' with `base_point' */
2652 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2654 SWAP, /* s: edge[1] serif edge[-1] */
2655 DUP,
2656 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2657 GC_cur,
2658 PUSHB_1,
2660 CINDEX,
2661 GC_cur, /* s: edge[1] serif edge[-1]_pos serif_pos */
2662 GT, /* serif_pos < edge[-1]_pos */
2664 DUP,
2665 ALIGNRP, /* align `serif' to `edge[-1]' */
2666 EIF,
2668 SWAP, /* s: serif edge[1] */
2669 DUP,
2670 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2671 GC_cur,
2672 PUSHB_1,
2674 CINDEX,
2675 GC_cur, /* s: serif edge[1]_pos serif_pos */
2676 LT, /* serif_pos > edge[1]_pos */
2678 DUP,
2679 ALIGNRP, /* align `serif' to `edge[1]' */
2680 EIF,
2682 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2684 PUSHB_2,
2685 bci_align_segments,
2687 SZP1, /* set zp1 to normal zone 1 */
2688 CALL,
2690 ENDF,
2696 * bci_action_serif_anchor
2698 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2699 * anchor.
2701 * in: edge_point (in twilight zone)
2702 * ... stuff for bci_align_segments (edge) ...
2705 unsigned char FPGM(bci_action_serif_anchor) [] = {
2707 PUSHB_1,
2708 bci_action_serif_anchor,
2709 FDEF,
2711 PUSHB_1,
2713 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2715 DUP,
2716 PUSHB_1,
2717 sal_anchor,
2718 SWAP,
2719 WS, /* sal_anchor = edge_point */
2721 DUP,
2722 PUSHB_1,
2723 sal_num_segments,
2725 ADD, /* s: edge edge_orig */
2727 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
2728 DUP,
2729 DUP,
2730 ALIGNRP, /* align `edge' with `edge_orig' */
2731 MDAP_round, /* round `edge' */
2733 MDAP_noround, /* set rp0 and rp1 to `edge' */
2735 PUSHB_2,
2736 bci_align_segments,
2738 SZP1, /* set zp1 to normal zone 1 */
2739 CALL,
2741 ENDF,
2747 * bci_action_serif_anchor_lower_bound
2749 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2750 * anchor, then moving it again if necessary to stay within a lower
2751 * bound.
2753 * in: edge_point (in twilight zone)
2754 * edge[-1] (in twilight zone)
2755 * ... stuff for bci_align_segments (edge) ...
2758 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] = {
2760 PUSHB_1,
2761 bci_action_serif_anchor_lower_bound,
2762 FDEF,
2764 PUSHB_1,
2766 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2768 DUP,
2769 PUSHB_1,
2770 sal_anchor,
2771 SWAP,
2772 WS, /* sal_anchor = edge_point */
2774 DUP,
2775 PUSHB_1,
2776 sal_num_segments,
2778 ADD, /* s: edge[-1] edge edge_orig */
2780 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
2781 DUP,
2782 DUP,
2783 ALIGNRP, /* align `edge' with `edge_orig' */
2784 MDAP_round, /* round `edge' */
2786 SWAP, /* s: edge edge[-1] */
2787 DUP,
2788 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2789 GC_cur,
2790 PUSHB_1,
2792 CINDEX,
2793 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2794 GT, /* edge_pos < edge[-1]_pos */
2796 DUP,
2797 ALIGNRP, /* align `edge' to `edge[-1]' */
2798 EIF,
2800 MDAP_noround, /* set rp0 and rp1 to `edge' */
2802 PUSHB_2,
2803 bci_align_segments,
2805 SZP1, /* set zp1 to normal zone 1 */
2806 CALL,
2808 ENDF,
2814 * bci_action_serif_anchor_upper_bound
2816 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2817 * anchor, then moving it again if necessary to stay within an upper
2818 * bound.
2820 * in: edge_point (in twilight zone)
2821 * edge[1] (in twilight zone)
2822 * ... stuff for bci_align_segments (edge) ...
2825 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] = {
2827 PUSHB_1,
2828 bci_action_serif_anchor_upper_bound,
2829 FDEF,
2831 PUSHB_1,
2833 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2835 DUP,
2836 PUSHB_1,
2837 sal_anchor,
2838 SWAP,
2839 WS, /* sal_anchor = edge_point */
2841 DUP,
2842 PUSHB_1,
2843 sal_num_segments,
2845 ADD, /* s: edge[1] edge edge_orig */
2847 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
2848 DUP,
2849 DUP,
2850 ALIGNRP, /* align `edge' with `edge_orig' */
2851 MDAP_round, /* round `edge' */
2853 SWAP, /* s: edge edge[1] */
2854 DUP,
2855 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2856 GC_cur,
2857 PUSHB_1,
2859 CINDEX,
2860 GC_cur, /* s: edge edge[1]_pos edge_pos */
2861 LT, /* edge_pos > edge[1]_pos */
2863 DUP,
2864 ALIGNRP, /* align `edge' to `edge[1]' */
2865 EIF,
2867 MDAP_noround, /* set rp0 and rp1 to `edge' */
2869 PUSHB_2,
2870 bci_align_segments,
2872 SZP1, /* set zp1 to normal zone 1 */
2873 CALL,
2875 ENDF,
2881 * bci_action_serif_anchor_lower_upper_bound
2883 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2884 * anchor, then moving it again if necessary to stay within a lower and
2885 * upper bound.
2887 * in: edge_point (in twilight zone)
2888 * edge[-1] (in twilight zone)
2889 * edge[1] (in twilight zone)
2890 * ... stuff for bci_align_segments (edge) ...
2893 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] = {
2895 PUSHB_1,
2896 bci_action_serif_anchor_lower_upper_bound,
2897 FDEF,
2899 PUSHB_1,
2901 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2903 DUP,
2904 PUSHB_1,
2905 sal_anchor,
2906 SWAP,
2907 WS, /* sal_anchor = edge_point */
2909 DUP,
2910 PUSHB_1,
2911 sal_num_segments,
2913 ADD, /* s: edge[1] edge[-1] edge edge_orig */
2915 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
2916 DUP,
2917 DUP,
2918 ALIGNRP, /* align `edge' with `edge_orig' */
2919 MDAP_round, /* round `edge' */
2921 SWAP, /* s: edge[1] edge edge[-1] */
2922 DUP,
2923 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2924 GC_cur,
2925 PUSHB_1,
2927 CINDEX,
2928 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
2929 GT, /* edge_pos < edge[-1]_pos */
2931 DUP,
2932 ALIGNRP, /* align `edge' to `edge[-1]' */
2933 EIF,
2935 SWAP, /* s: edge edge[1] */
2936 DUP,
2937 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2938 GC_cur,
2939 PUSHB_1,
2941 CINDEX,
2942 GC_cur, /* s: edge edge[1]_pos edge_pos */
2943 LT, /* edge_pos > edge[1]_pos */
2945 DUP,
2946 ALIGNRP, /* align `edge' to `edge[1]' */
2947 EIF,
2949 MDAP_noround, /* set rp0 and rp1 to `edge' */
2951 PUSHB_2,
2952 bci_align_segments,
2954 SZP1, /* set zp1 to normal zone 1 */
2955 CALL,
2957 ENDF,
2963 * bci_action_serif_link1
2965 * Handle the SERIF_LINK1 action to align a serif, depending on edges
2966 * before and after.
2968 * in: before_point (in twilight zone)
2969 * edge_point (in twilight zone)
2970 * after_point (in twilight zone)
2971 * ... stuff for bci_align_segments (edge) ...
2974 unsigned char FPGM(bci_action_serif_link1) [] = {
2976 PUSHB_1,
2977 bci_action_serif_link1,
2978 FDEF,
2980 PUSHB_1,
2982 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2984 PUSHB_1,
2986 CINDEX,
2987 PUSHB_1,
2988 sal_num_segments,
2990 ADD, /* s: after edge before after_orig */
2991 PUSHB_1,
2993 CINDEX,
2994 PUSHB_1,
2995 sal_num_segments,
2997 ADD, /* s: after edge before after_orig before_orig */
2998 MD_cur,
2999 PUSHB_1,
3001 EQ, /* after_orig_pos == before_orig_pos */
3002 IF, /* s: after edge before */
3003 MDAP_noround, /* set rp0 and rp1 to `before' */
3004 DUP,
3005 ALIGNRP, /* align `edge' with `before' */
3006 SWAP,
3007 POP,
3009 ELSE,
3010 PUSHB_1,
3012 CINDEX,
3013 PUSHB_1,
3014 sal_num_segments,
3016 ADD, /* s: ... after edge before edge_orig */
3017 PUSHB_1,
3019 CINDEX,
3020 PUSHB_1,
3021 sal_num_segments,
3023 ADD, /* s: ... after edge before edge_orig before_orig */
3024 MD_cur, /* a = edge_orig_pos - before_orig_pos */
3025 PUSHW_1,
3026 0x10, /* 64*64 */
3027 0x00,
3028 MUL,
3030 PUSHB_1,
3032 CINDEX, /* s: ... after edge before a*64 after */
3033 PUSHB_1,
3035 CINDEX, /* s: ... after edge before a*64 after before */
3036 MD_cur, /* b = after_pos - before_pos */
3037 MUL, /* s: ... after edge before a*b */
3039 PUSHB_1,
3041 CINDEX,
3042 PUSHB_1,
3043 sal_num_segments,
3045 ADD, /* s: ... after edge before a*b after_orig */
3046 PUSHB_1,
3048 CINDEX,
3049 PUSHB_1,
3050 sal_num_segments,
3052 ADD, /* s: ... after edge before a*b after_orig before_orig */
3053 MD_cur, /* c = after_orig_pos - before_orig_pos */
3054 PUSHW_1,
3055 0x10, /* 64*64 */
3056 0x00,
3057 MUL,
3059 DIV, /* s: after edge before a*b/c */
3061 SWAP,
3062 MDAP_noround, /* set rp0 and rp1 to `before' */
3063 SWAP, /* s: after a*b/c edge */
3064 DUP,
3065 DUP,
3066 ALIGNRP, /* align `edge' with `before' */
3067 ROLL,
3068 SHPIX, /* shift `edge' by `a*b/c' */
3070 SWAP, /* s: edge after */
3071 POP,
3072 EIF,
3074 MDAP_noround, /* set rp0 and rp1 to `edge' */
3076 PUSHB_2,
3077 bci_align_segments,
3079 SZP1, /* set zp1 to normal zone 1 */
3080 CALL,
3082 ENDF,
3088 * bci_action_serif_link1_lower_bound
3090 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3091 * before and after. Additionally, move the serif again if necessary to
3092 * stay within a lower bound.
3094 * in: before_point (in twilight zone)
3095 * edge_point (in twilight zone)
3096 * after_point (in twilight zone)
3097 * edge[-1] (in twilight zone)
3098 * ... stuff for bci_align_segments (edge) ...
3101 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] = {
3103 PUSHB_1,
3104 bci_action_serif_link1_lower_bound,
3105 FDEF,
3107 PUSHB_1,
3109 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3111 PUSHB_1,
3113 CINDEX,
3114 PUSHB_1,
3115 sal_num_segments,
3117 ADD, /* s: edge[-1] after edge before after_orig */
3118 PUSHB_1,
3120 CINDEX,
3121 PUSHB_1,
3122 sal_num_segments,
3124 ADD, /* s: edge[-1] after edge before after_orig before_orig */
3125 MD_cur,
3126 PUSHB_1,
3128 EQ, /* after_orig_pos == before_orig_pos */
3129 IF, /* s: edge[-1] after edge before */
3130 MDAP_noround, /* set rp0 and rp1 to `before' */
3131 DUP,
3132 ALIGNRP, /* align `edge' with `before' */
3133 SWAP,
3134 POP,
3136 ELSE,
3137 PUSHB_1,
3139 CINDEX,
3140 PUSHB_1,
3141 sal_num_segments,
3143 ADD, /* s: ... after edge before edge_orig */
3144 PUSHB_1,
3146 CINDEX,
3147 PUSHB_1,
3148 sal_num_segments,
3150 ADD, /* s: ... after edge before edge_orig before_orig */
3151 MD_cur, /* a = edge_orig_pos - before_orig_pos */
3152 PUSHW_1,
3153 0x10, /* 64*64 */
3154 0x00,
3155 MUL,
3157 PUSHB_1,
3159 CINDEX, /* s: ... after edge before a*64 after */
3160 PUSHB_1,
3162 CINDEX, /* s: ... after edge before a*64 after before */
3163 MD_cur, /* b = after_pos - before_pos */
3164 MUL, /* s: ... after edge before a*b */
3166 PUSHB_1,
3168 CINDEX,
3169 PUSHB_1,
3170 sal_num_segments,
3172 ADD, /* s: ... after edge before a*b after_orig */
3173 PUSHB_1,
3175 CINDEX,
3176 PUSHB_1,
3177 sal_num_segments,
3179 ADD, /* s: ... after edge before a*b after_orig before_orig */
3180 MD_cur, /* c = after_orig_pos - before_orig_pos */
3181 PUSHW_1,
3182 0x10, /* 64*64 */
3183 0x00,
3184 MUL,
3186 DIV, /* s: edge[-1] after edge before a*b/c */
3188 SWAP,
3189 MDAP_noround, /* set rp0 and rp1 to `before' */
3190 SWAP, /* s: edge[-1] after a*b/c edge */
3191 DUP,
3192 DUP,
3193 ALIGNRP, /* align `edge' with `before' */
3194 ROLL,
3195 SHPIX, /* shift `edge' by `a*b/c' */
3197 SWAP, /* s: edge[-1] edge after */
3198 POP,
3199 EIF,
3201 SWAP, /* s: edge edge[-1] */
3202 DUP,
3203 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3204 GC_cur,
3205 PUSHB_1,
3207 CINDEX,
3208 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3209 GT, /* edge_pos < edge[-1]_pos */
3211 DUP,
3212 ALIGNRP, /* align `edge' to `edge[-1]' */
3213 EIF,
3215 MDAP_noround, /* set rp0 and rp1 to `edge' */
3217 PUSHB_2,
3218 bci_align_segments,
3220 SZP1, /* set zp1 to normal zone 1 */
3221 CALL,
3222 ENDF,
3228 * bci_action_serif_link1_upper_bound
3230 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3231 * before and after. Additionally, move the serif again if necessary to
3232 * stay within an upper bound.
3234 * in: before_point (in twilight zone)
3235 * edge_point (in twilight zone)
3236 * after_point (in twilight zone)
3237 * edge[1] (in twilight zone)
3238 * ... stuff for bci_align_segments (edge) ...
3241 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] = {
3243 PUSHB_1,
3244 bci_action_serif_link1_upper_bound,
3245 FDEF,
3247 PUSHB_1,
3249 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3251 PUSHB_1,
3253 CINDEX,
3254 PUSHB_1,
3255 sal_num_segments,
3257 ADD, /* s: edge[1] after edge before after_orig */
3258 PUSHB_1,
3260 CINDEX,
3261 PUSHB_1,
3262 sal_num_segments,
3264 ADD, /* s: edge[1] after edge before after_orig before_orig */
3265 MD_cur,
3266 PUSHB_1,
3268 EQ, /* after_orig_pos == before_orig_pos */
3269 IF, /* s: edge[1] after edge before */
3270 MDAP_noround, /* set rp0 and rp1 to `before' */
3271 DUP,
3272 ALIGNRP, /* align `edge' with `before' */
3273 SWAP,
3274 POP,
3276 ELSE,
3277 PUSHB_1,
3279 CINDEX,
3280 PUSHB_1,
3281 sal_num_segments,
3283 ADD, /* s: ... after edge before edge_orig */
3284 PUSHB_1,
3286 CINDEX,
3287 PUSHB_1,
3288 sal_num_segments,
3290 ADD, /* s: ... after edge before edge_orig before_orig */
3291 MD_cur, /* a = edge_orig_pos - before_orig_pos */
3292 PUSHW_1,
3293 0x10, /* 64*64 */
3294 0x00,
3295 MUL,
3297 PUSHB_1,
3299 CINDEX, /* s: ... after edge before a*64 after */
3300 PUSHB_1,
3302 CINDEX, /* s: ... after edge before a*64 after before */
3303 MD_cur, /* b = after_pos - before_pos */
3304 MUL, /* s: ... after edge before a*b */
3306 PUSHB_1,
3308 CINDEX,
3309 PUSHB_1,
3310 sal_num_segments,
3312 ADD, /* s: ... after edge before a*b after_orig */
3313 PUSHB_1,
3315 CINDEX,
3316 PUSHB_1,
3317 sal_num_segments,
3319 ADD, /* s: ... after edge before a*b after_orig before_orig */
3320 MD_cur, /* c = after_orig_pos - before_orig_pos */
3321 PUSHW_1,
3322 0x10, /* 64*64 */
3323 0x00,
3324 MUL,
3326 DIV, /* s: edge[1] after edge before a*b/c */
3328 SWAP,
3329 MDAP_noround, /* set rp0 and rp1 to `before' */
3330 SWAP, /* s: edge[1] after a*b/c edge */
3331 DUP,
3332 DUP,
3333 ALIGNRP, /* align `edge' with `before' */
3334 ROLL,
3335 SHPIX, /* shift `edge' by `a*b/c' */
3337 SWAP, /* s: edge[1] edge after */
3338 POP,
3339 EIF,
3341 SWAP, /* s: edge edge[1] */
3342 DUP,
3343 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3344 GC_cur,
3345 PUSHB_1,
3347 CINDEX,
3348 GC_cur, /* s: edge edge[1]_pos edge_pos */
3349 LT, /* edge_pos > edge[1]_pos */
3351 DUP,
3352 ALIGNRP, /* align `edge' to `edge[1]' */
3353 EIF,
3355 MDAP_noround, /* set rp0 and rp1 to `edge' */
3357 PUSHB_2,
3358 bci_align_segments,
3360 SZP1, /* set zp1 to normal zone 1 */
3361 CALL,
3363 ENDF,
3369 * bci_action_serif_link1_lower_upper_bound
3371 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3372 * before and after. Additionally, move the serif again if necessary to
3373 * stay within a lower and upper bound.
3375 * in: before_point (in twilight zone)
3376 * edge_point (in twilight zone)
3377 * after_point (in twilight zone)
3378 * edge[-1] (in twilight zone)
3379 * edge[1] (in twilight zone)
3380 * ... stuff for bci_align_segments (edge) ...
3383 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] = {
3385 PUSHB_1,
3386 bci_action_serif_link1_lower_upper_bound,
3387 FDEF,
3389 PUSHB_1,
3391 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3393 PUSHB_1,
3395 CINDEX,
3396 PUSHB_1,
3397 sal_num_segments,
3399 ADD, /* s: edge[1] edge[-1] after edge before after_orig */
3400 PUSHB_1,
3402 CINDEX,
3403 PUSHB_1,
3404 sal_num_segments,
3406 ADD, /* s: edge[1] edge[-1] after edge before after_orig before_orig */
3407 MD_cur,
3408 PUSHB_1,
3410 EQ, /* after_orig_pos == before_orig_pos */
3411 IF, /* s: edge[1] edge[-1] after edge before */
3412 MDAP_noround, /* set rp0 and rp1 to `before' */
3413 DUP,
3414 ALIGNRP, /* align `edge' with `before' */
3415 SWAP,
3416 POP,
3418 ELSE,
3419 PUSHB_1,
3421 CINDEX,
3422 PUSHB_1,
3423 sal_num_segments,
3425 ADD, /* s: ... after edge before edge_orig */
3426 PUSHB_1,
3428 CINDEX,
3429 PUSHB_1,
3430 sal_num_segments,
3432 ADD, /* s: ... after edge before edge_orig before_orig */
3433 MD_cur, /* a = edge_orig_pos - before_orig_pos */
3434 PUSHW_1,
3435 0x10, /* 64*64 */
3436 0x00,
3437 MUL,
3439 PUSHB_1,
3441 CINDEX, /* s: ... after edge before a*64 after */
3442 PUSHB_1,
3444 CINDEX, /* s: ... after edge before a*64 after before */
3445 MD_cur, /* b = after_pos - before_pos */
3446 MUL, /* s: ... after edge before a*b */
3448 PUSHB_1,
3450 CINDEX,
3451 PUSHB_1,
3452 sal_num_segments,
3454 ADD, /* s: ... after edge before a*b after_orig */
3455 PUSHB_1,
3457 CINDEX,
3458 PUSHB_1,
3459 sal_num_segments,
3461 ADD, /* s: ... after edge before a*b after_orig before_orig */
3462 MD_cur, /* c = after_orig_pos - before_orig_pos */
3463 PUSHW_1,
3464 0x10, /* 64*64 */
3465 0x00,
3466 MUL,
3468 DIV, /* s: edge[1] edge[-1] after edge before a*b/c */
3470 SWAP,
3471 MDAP_noround, /* set rp0 and rp1 to `before' */
3472 SWAP, /* s: edge[1] edge[-1] after a*b/c edge */
3473 DUP,
3474 DUP,
3475 ALIGNRP, /* align `edge' with `before' */
3476 ROLL,
3477 SHPIX, /* shift `edge' by `a*b/c' */
3479 SWAP, /* s: edge[1] edge[-1] edge after */
3480 POP,
3481 EIF,
3483 SWAP, /* s: edge[1] edge edge[-1] */
3484 DUP,
3485 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3486 GC_cur,
3487 PUSHB_1,
3489 CINDEX,
3490 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
3491 GT, /* edge_pos < edge[-1]_pos */
3493 DUP,
3494 ALIGNRP, /* align `edge' to `edge[-1]' */
3495 EIF,
3497 SWAP, /* s: edge edge[1] */
3498 DUP,
3499 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3500 GC_cur,
3501 PUSHB_1,
3503 CINDEX,
3504 GC_cur, /* s: edge edge[1]_pos edge_pos */
3505 LT, /* edge_pos > edge[1]_pos */
3507 DUP,
3508 ALIGNRP, /* align `edge' to `edge[1]' */
3509 EIF,
3511 MDAP_noround, /* set rp0 and rp1 to `edge' */
3513 PUSHB_2,
3514 bci_align_segments,
3516 SZP1, /* set zp1 to normal zone 1 */
3517 CALL,
3519 ENDF,
3525 * bci_action_serif_link2
3527 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3529 * in: edge_point (in twilight zone)
3530 * ... stuff for bci_align_segments (edge) ...
3533 unsigned char FPGM(bci_action_serif_link2) [] = {
3535 PUSHB_1,
3536 bci_action_serif_link2,
3537 FDEF,
3539 PUSHB_1,
3541 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3543 DUP,
3544 PUSHB_1,
3545 sal_num_segments,
3547 ADD, /* s: edge edge_orig */
3548 PUSHB_1,
3549 sal_anchor,
3551 DUP,
3552 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3553 PUSHB_1,
3554 sal_num_segments,
3556 ADD, /* s: edge edge_orig anchor_orig */
3558 MD_cur,
3559 DUP,
3560 ADD,
3561 PUSHB_1,
3563 ADD,
3564 FLOOR,
3565 PUSHB_1,
3566 2*64,
3567 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3569 SWAP,
3570 DUP,
3571 DUP,
3572 ALIGNRP, /* align `edge' with `sal_anchor' */
3573 ROLL,
3574 SHPIX, /* shift `edge' by `delta' */
3576 MDAP_noround, /* set rp0 and rp1 to `edge' */
3578 PUSHB_2,
3579 bci_align_segments,
3581 SZP1, /* set zp1 to normal zone 1 */
3582 CALL,
3584 ENDF,
3590 * bci_action_serif_link2_lower_bound
3592 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3593 * Additionally, move the serif again if necessary to stay within a lower
3594 * bound.
3596 * in: edge_point (in twilight zone)
3597 * edge[-1] (in twilight zone)
3598 * ... stuff for bci_align_segments (edge) ...
3601 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] = {
3603 PUSHB_1,
3604 bci_action_serif_link2_lower_bound,
3605 FDEF,
3607 PUSHB_1,
3609 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3611 DUP,
3612 PUSHB_1,
3613 sal_num_segments,
3615 ADD, /* s: edge[-1] edge edge_orig */
3616 PUSHB_1,
3617 sal_anchor,
3619 DUP,
3620 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3621 PUSHB_1,
3622 sal_num_segments,
3624 ADD, /* s: edge[-1] edge edge_orig anchor_orig */
3626 MD_cur,
3627 DUP,
3628 ADD,
3629 PUSHB_1,
3631 ADD,
3632 FLOOR,
3633 PUSHB_1,
3634 2*64,
3635 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3637 SWAP,
3638 DUP,
3639 DUP,
3640 ALIGNRP, /* align `edge' with `sal_anchor' */
3641 ROLL,
3642 SHPIX, /* shift `edge' by `delta' */
3644 SWAP, /* s: edge edge[-1] */
3645 DUP,
3646 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3647 GC_cur,
3648 PUSHB_1,
3650 CINDEX,
3651 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3652 GT, /* edge_pos < edge[-1]_pos */
3654 DUP,
3655 ALIGNRP, /* align `edge' to `edge[-1]' */
3656 EIF,
3658 MDAP_noround, /* set rp0 and rp1 to `edge' */
3660 PUSHB_2,
3661 bci_align_segments,
3663 SZP1, /* set zp1 to normal zone 1 */
3664 CALL,
3666 ENDF,
3672 * bci_action_serif_link2_upper_bound
3674 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3675 * Additionally, move the serif again if necessary to stay within an upper
3676 * bound.
3678 * in: edge_point (in twilight zone)
3679 * edge[1] (in twilight zone)
3680 * ... stuff for bci_align_segments (edge) ...
3683 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] = {
3685 PUSHB_1,
3686 bci_action_serif_link2_upper_bound,
3687 FDEF,
3689 PUSHB_1,
3691 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3693 DUP,
3694 PUSHB_1,
3695 sal_num_segments,
3697 ADD, /* s: edge[1] edge edge_orig */
3698 PUSHB_1,
3699 sal_anchor,
3701 DUP,
3702 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3703 PUSHB_1,
3704 sal_num_segments,
3706 ADD, /* s: edge[1] edge edge_orig anchor_orig */
3708 MD_cur,
3709 DUP,
3710 ADD,
3711 PUSHB_1,
3713 ADD,
3714 FLOOR,
3715 PUSHB_1,
3716 2*64,
3717 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3719 SWAP,
3720 DUP,
3721 DUP,
3722 ALIGNRP, /* align `edge' with `sal_anchor' */
3723 ROLL,
3724 SHPIX, /* shift `edge' by `delta' */
3726 SWAP, /* s: edge edge[1] */
3727 DUP,
3728 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3729 GC_cur,
3730 PUSHB_1,
3732 CINDEX,
3733 GC_cur, /* s: edge edge[1]_pos edge_pos */
3734 LT, /* edge_pos > edge[1]_pos */
3736 DUP,
3737 ALIGNRP, /* align `edge' to `edge[1]' */
3738 EIF,
3740 MDAP_noround, /* set rp0 and rp1 to `edge' */
3742 PUSHB_2,
3743 bci_align_segments,
3745 SZP1, /* set zp1 to normal zone 1 */
3746 CALL,
3748 ENDF,
3754 * bci_action_serif_link2_lower_upper_bound
3756 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3757 * Additionally, move the serif again if necessary to stay within a lower
3758 * and upper bound.
3760 * in: edge_point (in twilight zone)
3761 * edge[-1] (in twilight zone)
3762 * edge[1] (in twilight zone)
3763 * ... stuff for bci_align_segments (edge) ...
3766 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] = {
3768 PUSHB_1,
3769 bci_action_serif_link2_lower_upper_bound,
3770 FDEF,
3772 PUSHB_1,
3774 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3776 DUP,
3777 PUSHB_1,
3778 sal_num_segments,
3780 ADD, /* s: edge[1] edge[-1] edge edge_orig */
3781 PUSHB_1,
3782 sal_anchor,
3784 DUP,
3785 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3786 PUSHB_1,
3787 sal_num_segments,
3789 ADD, /* s: edge[1] edge[-1] edge edge_orig anchor_orig */
3791 MD_cur,
3792 DUP,
3793 ADD,
3794 PUSHB_1,
3796 ADD,
3797 FLOOR,
3798 PUSHB_1,
3799 2*64,
3800 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3802 SWAP,
3803 DUP,
3804 DUP,
3805 ALIGNRP, /* align `edge' with `sal_anchor' */
3806 ROLL,
3807 SHPIX, /* shift `edge' by `delta' */
3809 SWAP, /* s: edge[1] edge edge[-1] */
3810 DUP,
3811 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3812 GC_cur,
3813 PUSHB_1,
3815 CINDEX,
3816 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
3817 GT, /* edge_pos < edge[-1]_pos */
3819 DUP,
3820 ALIGNRP, /* align `edge' to `edge[-1]' */
3821 EIF,
3823 SWAP, /* s: edge edge[1] */
3824 DUP,
3825 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3826 GC_cur,
3827 PUSHB_1,
3829 CINDEX,
3830 GC_cur, /* s: edge edge[1]_pos edge_pos */
3831 LT, /* edge_pos > edge[1]_pos */
3833 DUP,
3834 ALIGNRP, /* align `edge' to `edge[1]' */
3835 EIF,
3837 MDAP_noround, /* set rp0 and rp1 to `edge' */
3839 PUSHB_2,
3840 bci_align_segments,
3842 SZP1, /* set zp1 to normal zone 1 */
3843 CALL,
3845 ENDF,
3851 * bci_handle_action
3853 * Execute function.
3855 * in: function_index
3858 unsigned char FPGM(bci_handle_action) [] = {
3860 PUSHB_1,
3861 bci_handle_action,
3862 FDEF,
3864 CALL,
3866 ENDF,
3872 * bci_hint_glyph
3874 * This is the top-level glyph hinting function
3875 * which parses the arguments on the stack and calls subroutines.
3877 * in: num_actions (M)
3878 * action_0_func_idx
3879 * ... data ...
3880 * action_1_func_idx
3881 * ... data ...
3882 * ...
3883 * action_M_func_idx
3884 * ... data ...
3886 * uses: bci_handle_action
3887 * bci_action_adjust_bound
3888 * bci_action_stem_bound
3890 * bci_action_link
3891 * bci_action_anchor
3892 * bci_action_blue_anchor
3893 * bci_action_adjust
3894 * bci_action_stem
3896 * bci_action_blue
3897 * bci_action_serif
3898 * bci_action_serif_anchor
3899 * bci_action_serif_link1
3900 * bci_action_serif_link2
3903 unsigned char FPGM(bci_hint_glyph) [] = {
3905 PUSHB_1,
3906 bci_hint_glyph,
3907 FDEF,
3909 PUSHB_1,
3910 bci_handle_action,
3911 LOOPCALL,
3913 ENDF,
3918 #define COPY_FPGM(func_name) \
3919 memcpy(buf_p, fpgm_ ## func_name, \
3920 sizeof (fpgm_ ## func_name)); \
3921 buf_p += sizeof (fpgm_ ## func_name) \
3923 static FT_Error
3924 TA_table_build_fpgm(FT_Byte** fpgm,
3925 FT_ULong* fpgm_len,
3926 FONT* font)
3928 FT_UInt buf_len;
3929 FT_UInt len;
3930 FT_Byte* buf;
3931 FT_Byte* buf_p;
3934 buf_len = sizeof (FPGM(bci_round))
3935 + sizeof (FPGM(bci_compute_stem_width_a))
3937 + sizeof (FPGM(bci_compute_stem_width_b))
3939 + sizeof (FPGM(bci_compute_stem_width_c))
3940 + sizeof (FPGM(bci_loop))
3941 + sizeof (FPGM(bci_cvt_rescale))
3942 + sizeof (FPGM(bci_blue_round_a))
3944 + sizeof (FPGM(bci_blue_round_b))
3945 + sizeof (FPGM(bci_get_point_extrema))
3947 + sizeof (FPGM(bci_create_segment))
3948 + sizeof (FPGM(bci_create_segments))
3949 + sizeof (FPGM(bci_align_segment))
3950 + sizeof (FPGM(bci_align_segments))
3952 + sizeof (FPGM(bci_ip_before_align_point))
3953 + sizeof (FPGM(bci_ip_after_align_point))
3954 + sizeof (FPGM(bci_ip_on_align_point))
3955 + sizeof (FPGM(bci_ip_on_align_points))
3956 + sizeof (FPGM(bci_ip_between_align_point))
3957 + sizeof (FPGM(bci_ip_between_align_points))
3959 + sizeof (FPGM(bci_action_ip_before))
3960 + sizeof (FPGM(bci_action_ip_after))
3961 + sizeof (FPGM(bci_action_ip_on))
3962 + sizeof (FPGM(bci_action_ip_between))
3964 + sizeof (FPGM(bci_action_adjust_bound))
3965 + sizeof (FPGM(bci_action_stem_bound))
3966 + sizeof (FPGM(bci_action_link))
3967 + sizeof (FPGM(bci_action_anchor))
3968 + sizeof (FPGM(bci_action_blue_anchor))
3969 + sizeof (FPGM(bci_action_adjust))
3970 + sizeof (FPGM(bci_action_stem))
3971 + sizeof (FPGM(bci_action_blue))
3972 + sizeof (FPGM(bci_action_serif))
3973 + sizeof (FPGM(bci_action_serif_lower_bound))
3974 + sizeof (FPGM(bci_action_serif_upper_bound))
3975 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
3976 + sizeof (FPGM(bci_action_serif_anchor))
3977 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
3978 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
3979 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
3980 + sizeof (FPGM(bci_action_serif_link1))
3981 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
3982 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
3983 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
3984 + sizeof (FPGM(bci_action_serif_link2))
3985 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
3986 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
3987 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
3989 + sizeof (FPGM(bci_handle_action))
3990 + sizeof (FPGM(bci_hint_glyph));
3991 /* buffer length must be a multiple of four */
3992 len = (buf_len + 3) & ~3;
3993 buf = (FT_Byte*)malloc(len);
3994 if (!buf)
3995 return FT_Err_Out_Of_Memory;
3997 /* pad end of buffer with zeros */
3998 buf[len - 1] = 0x00;
3999 buf[len - 2] = 0x00;
4000 buf[len - 3] = 0x00;
4002 /* copy font program into buffer and fill in the missing variables */
4003 buf_p = buf;
4005 COPY_FPGM(bci_round);
4006 COPY_FPGM(bci_compute_stem_width_a);
4007 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4008 COPY_FPGM(bci_compute_stem_width_b);
4009 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4010 COPY_FPGM(bci_compute_stem_width_c);
4011 COPY_FPGM(bci_loop);
4012 COPY_FPGM(bci_cvt_rescale);
4013 COPY_FPGM(bci_blue_round_a);
4014 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
4015 COPY_FPGM(bci_blue_round_b);
4016 COPY_FPGM(bci_get_point_extrema);
4018 COPY_FPGM(bci_create_segment);
4019 COPY_FPGM(bci_create_segments);
4020 COPY_FPGM(bci_align_segment);
4021 COPY_FPGM(bci_align_segments);
4023 COPY_FPGM(bci_ip_before_align_point);
4024 COPY_FPGM(bci_ip_after_align_point);
4025 COPY_FPGM(bci_ip_on_align_point);
4026 COPY_FPGM(bci_ip_on_align_points);
4027 COPY_FPGM(bci_ip_between_align_point);
4028 COPY_FPGM(bci_ip_between_align_points);
4030 COPY_FPGM(bci_action_ip_before);
4031 COPY_FPGM(bci_action_ip_after);
4032 COPY_FPGM(bci_action_ip_on);
4033 COPY_FPGM(bci_action_ip_between);
4035 COPY_FPGM(bci_action_adjust_bound);
4036 COPY_FPGM(bci_action_stem_bound);
4037 COPY_FPGM(bci_action_link);
4038 COPY_FPGM(bci_action_anchor);
4039 COPY_FPGM(bci_action_blue_anchor);
4040 COPY_FPGM(bci_action_adjust);
4041 COPY_FPGM(bci_action_stem);
4042 COPY_FPGM(bci_action_blue);
4043 COPY_FPGM(bci_action_serif);
4044 COPY_FPGM(bci_action_serif_lower_bound);
4045 COPY_FPGM(bci_action_serif_upper_bound);
4046 COPY_FPGM(bci_action_serif_lower_upper_bound);
4047 COPY_FPGM(bci_action_serif_anchor);
4048 COPY_FPGM(bci_action_serif_anchor_lower_bound);
4049 COPY_FPGM(bci_action_serif_anchor_upper_bound);
4050 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
4051 COPY_FPGM(bci_action_serif_link1);
4052 COPY_FPGM(bci_action_serif_link1_lower_bound);
4053 COPY_FPGM(bci_action_serif_link1_upper_bound);
4054 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
4055 COPY_FPGM(bci_action_serif_link2);
4056 COPY_FPGM(bci_action_serif_link2_lower_bound);
4057 COPY_FPGM(bci_action_serif_link2_upper_bound);
4058 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
4060 COPY_FPGM(bci_handle_action);
4061 COPY_FPGM(bci_hint_glyph);
4063 *fpgm = buf;
4064 *fpgm_len = buf_len;
4066 return FT_Err_Ok;
4070 FT_Error
4071 TA_sfnt_build_fpgm_table(SFNT* sfnt,
4072 FONT* font)
4074 FT_Error error;
4076 FT_Byte* fpgm_buf;
4077 FT_ULong fpgm_len;
4080 error = TA_sfnt_add_table_info(sfnt);
4081 if (error)
4082 return error;
4084 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
4085 if (error)
4086 return error;
4088 /* in case of success, `fpgm_buf' gets linked */
4089 /* and is eventually freed in `TA_font_unload' */
4090 error = TA_font_add_table(font,
4091 &sfnt->table_infos[sfnt->num_table_infos - 1],
4092 TTAG_fpgm, fpgm_len, fpgm_buf);
4093 if (error)
4095 free(fpgm_buf);
4096 return error;
4099 return FT_Err_Ok;
4102 /* end of tafpgm.c */