Reduce size of generated bytecode, part 4.
[ttfautohint.git] / lib / tafpgm.c
blob7c352f4075a5c5f4c5aeef50e7cb74d243140bf8
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 DUP,
88 ABS,
89 PUSHB_1,
90 32,
91 ADD,
92 FLOOR,
93 SWAP,
94 PUSHB_1,
96 LT,
97 IF,
98 NEG,
99 EIF,
101 ENDF,
107 * bci_compute_stem_width
109 * This is the equivalent to the following code from function
110 * `ta_latin_compute_stem_width':
112 * dist = ABS(width)
114 * if (stem_is_serif
115 * && dist < 3*64)
116 * || is_extra_light:
117 * return width
118 * else if base_is_round:
119 * if dist < 80
120 * dist = 64
121 * else if dist < 56:
122 * dist = 56
124 * delta = ABS(dist - std_width)
126 * if delta < 40:
127 * dist = std_width
128 * if dist < 48
129 * dist = 48
130 * goto End
132 * if dist < 3*64:
133 * delta = dist
134 * dist = FLOOR(dist)
135 * delta = delta - dist
137 * if delta < 10:
138 * dist = dist + delta
139 * else if delta < 32:
140 * dist = dist + 10
141 * else if delta < 54:
142 * dist = dist + 54
143 * else
144 * dist = dist + delta
145 * else
146 * dist = ROUND(dist)
148 * End:
149 * if width < 0:
150 * dist = -dist
151 * return dist
154 * in: width
155 * stem_is_serif
156 * base_is_round
158 * out: new_width
160 * CVT: cvtl_is_extra_light
161 * std_width
164 unsigned char FPGM(bci_compute_stem_width_a) [] =
167 PUSHB_1,
168 bci_compute_stem_width,
169 FDEF,
171 DUP,
172 ABS, /* s: base_is_round stem_is_serif width dist */
174 DUP,
175 PUSHB_1,
176 3*64,
177 LT, /* dist < 3*64 */
179 PUSHB_1,
181 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
182 AND, /* stem_is_serif && dist < 3*64 */
184 PUSHB_1,
185 cvtl_is_extra_light,
186 RCVT,
187 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
189 IF, /* s: base_is_round width dist */
190 POP,
191 SWAP,
192 POP, /* s: width */
194 ELSE,
195 ROLL, /* s: width dist base_is_round */
196 IF, /* s: width dist */
197 DUP,
198 PUSHB_1,
200 LT, /* dist < 80 */
201 IF, /* s: width dist */
202 POP,
203 PUSHB_1,
204 64, /* dist = 64 */
205 EIF,
207 ELSE,
208 DUP,
209 PUSHB_1,
211 LT, /* dist < 56 */
212 IF, /* s: width dist */
213 POP,
214 PUSHB_1,
215 56, /* dist = 56 */
216 EIF,
217 EIF,
219 DUP, /* s: width dist dist */
220 PUSHB_1,
224 /* %c, index of std_width */
226 unsigned char FPGM(bci_compute_stem_width_b) [] =
229 RCVT,
230 SUB,
231 ABS, /* s: width dist delta */
233 PUSHB_1,
235 LT, /* delta < 40 */
236 IF, /* s: width dist */
237 POP,
238 PUSHB_1,
242 /* %c, index of std_width */
244 unsigned char FPGM(bci_compute_stem_width_c) [] =
247 RCVT, /* dist = std_width */
248 DUP,
249 PUSHB_1,
251 LT, /* dist < 48 */
253 POP,
254 PUSHB_1,
255 48, /* dist = 48 */
256 EIF,
258 ELSE,
259 DUP, /* s: width dist dist */
260 PUSHB_1,
261 3*64,
262 LT, /* dist < 3*64 */
264 DUP, /* s: width delta dist */
265 FLOOR, /* dist = FLOOR(dist) */
266 DUP, /* s: width delta dist dist */
267 ROLL,
268 ROLL, /* s: width dist delta dist */
269 SUB, /* delta = delta - dist */
271 DUP, /* s: width dist delta delta */
272 PUSHB_1,
274 LT, /* delta < 10 */
275 IF, /* s: width dist delta */
276 ADD, /* dist = dist + delta */
278 ELSE,
279 DUP,
280 PUSHB_1,
282 LT, /* delta < 32 */
284 POP,
285 PUSHB_1,
287 ADD, /* dist = dist + 10 */
289 ELSE,
290 DUP,
291 PUSHB_1,
293 LT, /* delta < 54 */
295 POP,
296 PUSHB_1,
298 ADD, /* dist = dist + 54 */
300 ELSE,
301 ADD, /* dist = dist + delta */
303 EIF,
304 EIF,
305 EIF,
307 ELSE,
308 PUSHB_1,
309 bci_round,
310 CALL, /* dist = round(dist) */
312 EIF,
313 EIF,
315 SWAP, /* s: dist width */
316 PUSHB_1,
318 LT, /* width < 0 */
320 NEG, /* dist = -dist */
321 EIF,
322 EIF,
324 ENDF,
330 * bci_loop
332 * Take a range and a function number and apply the function to all
333 * elements of the range.
335 * in: func_num
336 * end
337 * start
339 * sal: sal_i (counter initialized with `start')
340 * sal_limit (`end')
341 * sal_func (`func_num')
344 unsigned char FPGM(bci_loop) [] =
347 PUSHB_1,
348 bci_loop,
349 FDEF,
351 PUSHB_1,
352 sal_func,
353 SWAP,
354 WS, /* sal_func = func_num */
355 PUSHB_1,
356 sal_limit,
357 SWAP,
358 WS, /* sal_limit = end */
359 PUSHB_1,
360 sal_i,
361 SWAP,
362 WS, /* sal_i = start */
364 /* start_loop: */
365 PUSHB_1,
366 sal_i,
368 PUSHB_1,
369 sal_limit,
371 LTEQ, /* start <= end */
373 PUSHB_1,
374 sal_func,
376 CALL,
377 PUSHB_3,
378 sal_i,
380 sal_i,
382 ADD, /* start = start + 1 */
385 PUSHB_1,
387 NEG,
388 JMPR, /* goto start_loop */
389 EIF,
391 ENDF,
397 * bci_cvt_rescale
399 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
401 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
402 * consequently, the calculation `a * b/c' is done as `a + delta' with
403 * `delta = a * (b-c)/c'. This avoids overflow.
405 * sal: sal_i (CVT index)
407 * CVT: cvtl_scale
408 * cvtl_0x10000
411 unsigned char FPGM(bci_cvt_rescale) [] =
414 PUSHB_1,
415 bci_cvt_rescale,
416 FDEF,
418 PUSHB_1,
419 sal_i,
421 DUP,
422 RCVT,
423 DO_SCALE,
424 WCVTP,
426 ENDF,
432 * bci_blue_round
434 * Round a blue ref value and adjust its corresponding shoot value.
436 * sal: sal_i (CVT index)
440 unsigned char FPGM(bci_blue_round_a) [] =
443 PUSHB_1,
444 bci_blue_round,
445 FDEF,
447 PUSHB_1,
448 sal_i,
450 DUP,
451 RCVT, /* s: ref_idx ref */
453 DUP,
454 PUSHB_1,
455 bci_round,
456 CALL,
457 SWAP, /* s: ref_idx round(ref) ref */
459 PUSHB_2,
463 /* %c, blue_count */
465 unsigned char FPGM(bci_blue_round_b) [] =
469 CINDEX,
470 ADD, /* s: ref_idx round(ref) ref shoot_idx */
471 DUP,
472 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
474 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
475 SWAP,
476 SUB, /* s: ref_idx round(ref) shoot_idx dist */
477 DUP,
478 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
480 DUP,
481 PUSHB_1,
483 LT, /* delta < 32 */
485 POP,
486 PUSHB_1,
487 0, /* delta = 0 */
489 ELSE,
490 PUSHB_1,
492 LT, /* delta < 48 */
494 PUSHB_1,
495 32, /* delta = 32 */
497 ELSE,
498 PUSHB_1,
499 64, /* delta = 64 */
500 EIF,
501 EIF,
503 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
504 PUSHB_1,
506 LT, /* dist < 0 */
508 NEG, /* delta = -delta */
509 EIF,
511 PUSHB_1,
513 CINDEX,
514 SWAP,
515 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
517 WCVTP,
518 WCVTP,
520 ENDF,
526 * bci_decrement_component_counter
528 * An auxiliary function for composite glyphs.
530 * CVT: cvtl_is_subglyph
533 unsigned char FPGM(bci_decrement_component_counter) [] =
536 PUSHB_1,
537 bci_decrement_component_counter,
538 FDEF,
540 /* decrement `cvtl_is_subglyph' counter */
541 PUSHB_2,
542 cvtl_is_subglyph,
543 cvtl_is_subglyph,
544 RCVT,
545 PUSHB_1,
547 SUB,
548 WCVTP,
550 ENDF,
556 * bci_get_point_extrema
558 * An auxiliary function for `bci_create_segment'.
560 * in: point-1
561 * out: point
563 * sal: sal_point_min
564 * sal_point_max
567 unsigned char FPGM(bci_get_point_extrema) [] =
570 PUSHB_1,
571 bci_get_point_extrema,
572 FDEF,
574 PUSHB_1,
576 ADD, /* s: point */
577 DUP,
578 DUP,
580 /* check whether `point' is a new minimum */
581 PUSHB_1,
582 sal_point_min,
583 RS, /* s: point point point point_min */
584 MD_orig,
585 /* if distance is negative, we have a new minimum */
586 PUSHB_1,
589 IF, /* s: point point */
590 DUP,
591 PUSHB_1,
592 sal_point_min,
593 SWAP,
595 EIF,
597 /* check whether `point' is a new maximum */
598 PUSHB_1,
599 sal_point_max,
600 RS, /* s: point point point_max */
601 MD_orig,
602 /* if distance is positive, we have a new maximum */
603 PUSHB_1,
606 IF, /* s: point */
607 DUP,
608 PUSHB_1,
609 sal_point_max,
610 SWAP,
612 EIF, /* s: point */
614 ENDF,
620 * bci_nibbles
622 * Pop a byte with two delta arguments in its nibbles and push the
623 * expanded arguments separately as two bytes.
625 * in: 16 * (end - start) + (start - base)
627 * out: start
628 * end
630 * sal: sal_base (set to `end' at return)
634 unsigned char FPGM(bci_nibbles) [] =
636 PUSHB_1,
637 bci_nibbles,
638 FDEF,
640 DUP,
641 PUSHW_1,
642 0x04, /* 16*64 */
643 0x00,
644 DIV, /* s: in hnibble */
645 DUP,
646 PUSHW_1,
647 0x04, /* 16*64 */
648 0x00,
649 MUL, /* s: in hnibble (hnibble * 16) */
650 ROLL,
651 SWAP,
652 SUB, /* s: hnibble lnibble */
654 PUSHB_1,
655 sal_base,
657 ADD, /* s: hnibble start */
658 DUP,
659 ROLL,
660 ADD, /* s: start end */
662 DUP,
663 PUSHB_1,
664 sal_base,
665 SWAP,
666 WS, /* sal_base = end */
668 SWAP,
670 ENDF,
676 * bci_create_segment
678 * Store start and end point of a segment in the storage area,
679 * then construct a point in the twilight zone to represent it.
681 * This function is used by `bci_create_segment_points'.
683 * in: start
684 * end
685 * [last (if wrap-around segment)]
686 * [first (if wrap-around segment)]
688 * uses: bci_get_point_extrema
689 * bci_nibbles
691 * sal: sal_i (start of current segment)
692 * sal_j (current twilight point)
693 * sal_point_min
694 * sal_point_max
695 * sal_base
696 * sal_num_packed_segments
698 * CVT: cvtl_scale
699 * cvtl_0x10000
700 * cvtl_temp
702 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
703 * delta values in nibbles (without a wrap-around segment).
706 unsigned char FPGM(bci_create_segment) [] =
709 PUSHB_1,
710 bci_create_segment,
711 FDEF,
713 PUSHB_2,
715 sal_num_packed_segments,
717 NEQ,
719 PUSHB_2,
720 sal_num_packed_segments,
721 sal_num_packed_segments,
723 PUSHB_1,
725 SUB,
726 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
728 PUSHB_1,
729 bci_nibbles,
730 CALL,
731 EIF,
733 PUSHB_1,
734 sal_i,
736 PUSHB_1,
738 CINDEX,
739 WS, /* sal[sal_i] = start */
741 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
742 PUSHB_3,
743 sal_i,
745 sal_i,
747 ADD, /* sal_i = sal_i + 1 */
750 /* initialize inner loop(s) */
751 PUSHB_2,
752 sal_point_min,
754 CINDEX,
755 WS, /* sal_point_min = start */
756 PUSHB_2,
757 sal_point_max,
759 CINDEX,
760 WS, /* sal_point_max = start */
762 PUSHB_1,
764 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
766 SWAP,
767 DUP,
768 PUSHB_1,
770 CINDEX, /* s: start end end start */
771 LT, /* start > end */
773 /* we have a wrap-around segment with two more arguments */
774 /* to give the last and first point of the contour, respectively; */
775 /* our job is to store a segment `start'-`last', */
776 /* and to get extrema for the two segments */
777 /* `start'-`last' and `first'-`end' */
779 /* s: first last start end */
780 PUSHB_1,
781 sal_i,
783 PUSHB_1,
785 CINDEX,
786 WS, /* sal[sal_i] = last */
788 ROLL,
789 ROLL, /* s: first end last start */
790 DUP,
791 ROLL,
792 SWAP, /* s: first end start last start */
793 SUB, /* s: first end start loop_count */
795 PUSHB_1,
796 bci_get_point_extrema,
797 LOOPCALL,
798 /* clean up stack */
799 POP,
801 SWAP, /* s: end first */
802 PUSHB_1,
804 SUB,
805 DUP,
806 ROLL, /* s: (first - 1) (first - 1) end */
807 SWAP,
808 SUB, /* s: (first - 1) loop_count */
810 PUSHB_1,
811 bci_get_point_extrema,
812 LOOPCALL,
813 /* clean up stack */
814 POP,
816 ELSE, /* s: start end */
817 PUSHB_1,
818 sal_i,
820 PUSHB_1,
822 CINDEX,
823 WS, /* sal[sal_i] = end */
825 PUSHB_1,
827 CINDEX,
828 SUB, /* s: start loop_count */
830 PUSHB_1,
831 bci_get_point_extrema,
832 LOOPCALL,
833 /* clean up stack */
834 POP,
835 EIF,
837 /* the twilight point representing a segment */
838 /* is in the middle between the minimum and maximum */
839 PUSHB_1,
840 sal_point_min,
842 GC_orig,
843 PUSHB_1,
844 sal_point_max,
846 GC_orig,
847 ADD,
848 PUSHB_1,
849 2*64,
850 DIV, /* s: middle_pos */
852 DO_SCALE, /* middle_pos = middle_pos * scale */
854 /* write it to temporary CVT location */
855 PUSHB_2,
856 cvtl_temp,
858 SZP0, /* set zp0 to twilight zone 0 */
859 SWAP,
860 WCVTP,
862 /* create twilight point with index `sal_j' */
863 PUSHB_1,
864 sal_j,
866 PUSHB_1,
867 cvtl_temp,
868 MIAP_noround,
870 PUSHB_3,
871 sal_j,
873 sal_j,
875 ADD, /* twilight_point = twilight_point + 1 */
878 ENDF,
884 * bci_create_segments
886 * This is the top-level entry function.
888 * It pops point ranges from the stack to define segments, computes
889 * twilight points to represent segments, and finally calls
890 * `bci_hint_glyph' to handle the rest.
892 * in: num_packed_segments
893 * num_segments (N)
894 * segment_start_0
895 * segment_end_0
896 * [contour_last 0 (if wrap-around segment)]
897 * [contour_first 0 (if wrap-around segment)]
898 * segment_start_1
899 * segment_end_1
900 * [contour_last 0 (if wrap-around segment)]
901 * [contour_first 0 (if wrap-around segment)]
902 * ...
903 * segment_start_(N-1)
904 * segment_end_(N-1)
905 * [contour_last (N-1) (if wrap-around segment)]
906 * [contour_first (N-1) (if wrap-around segment)]
907 * ... stuff for bci_hint_glyph ...
909 * uses: bci_create_segment
911 * sal: sal_i (start of current segment)
912 * sal_j (current twilight point)
913 * sal_num_packed_segments
914 * sal_base (the base for delta values in nibbles)
916 * CVT: cvtl_is_subglyph
918 * If `num_packed_segments' is set to p, the first p start/end pairs are
919 * stored as delta values in nibbles, with the `start' delta in the lower
920 * nibble (and there are no wrap-around segments). For example, if the
921 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
922 * stack are 0x21, 0x32, and 0x14.
926 unsigned char FPGM(bci_create_segments) [] =
929 PUSHB_1,
930 bci_create_segments,
931 FDEF,
933 /* only do something if we are not a subglyph */
934 PUSHB_2,
936 cvtl_is_subglyph,
937 RCVT,
940 /* all our measurements are taken along the y axis */
941 SVTCA_y,
943 PUSHB_1,
944 sal_num_packed_segments,
945 SWAP,
948 DUP,
949 ADD,
950 PUSHB_1,
952 SUB, /* delta = (2*num_segments - 1) */
954 PUSHB_6,
955 sal_segment_offset,
956 sal_segment_offset,
958 sal_j,
960 sal_base,
962 WS, /* sal_base = 0 */
963 WS, /* sal_j = 0 (point offset) */
965 ROLL,
966 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
968 /* `bci_create_segment_point' also increases the loop counter by 1; */
969 /* this effectively means we have a loop step of 2 */
970 PUSHB_2,
971 bci_create_segment,
972 bci_loop,
973 CALL,
975 PUSHB_1,
976 bci_hint_glyph,
977 CALL,
979 ELSE,
980 CLEAR,
981 EIF,
983 ENDF,
989 * bci_create_segments_X
991 * Top-level routines for calling `bci_create_segments'.
994 unsigned char FPGM(bci_create_segments_0) [] =
997 PUSHB_1,
998 bci_create_segments_0,
999 FDEF,
1001 PUSHB_2,
1003 bci_create_segments,
1004 CALL,
1006 ENDF,
1010 unsigned char FPGM(bci_create_segments_1) [] =
1013 PUSHB_1,
1014 bci_create_segments_1,
1015 FDEF,
1017 PUSHB_2,
1019 bci_create_segments,
1020 CALL,
1022 ENDF,
1026 unsigned char FPGM(bci_create_segments_2) [] =
1029 PUSHB_1,
1030 bci_create_segments_2,
1031 FDEF,
1033 PUSHB_2,
1035 bci_create_segments,
1036 CALL,
1038 ENDF,
1042 unsigned char FPGM(bci_create_segments_3) [] =
1045 PUSHB_1,
1046 bci_create_segments_3,
1047 FDEF,
1049 PUSHB_2,
1051 bci_create_segments,
1052 CALL,
1054 ENDF,
1058 unsigned char FPGM(bci_create_segments_4) [] =
1061 PUSHB_1,
1062 bci_create_segments_4,
1063 FDEF,
1065 PUSHB_2,
1067 bci_create_segments,
1068 CALL,
1070 ENDF,
1074 unsigned char FPGM(bci_create_segments_5) [] =
1077 PUSHB_1,
1078 bci_create_segments_5,
1079 FDEF,
1081 PUSHB_2,
1083 bci_create_segments,
1084 CALL,
1086 ENDF,
1090 unsigned char FPGM(bci_create_segments_6) [] =
1093 PUSHB_1,
1094 bci_create_segments_6,
1095 FDEF,
1097 PUSHB_2,
1099 bci_create_segments,
1100 CALL,
1102 ENDF,
1106 unsigned char FPGM(bci_create_segments_7) [] =
1109 PUSHB_1,
1110 bci_create_segments_7,
1111 FDEF,
1113 PUSHB_2,
1115 bci_create_segments,
1116 CALL,
1118 ENDF,
1122 unsigned char FPGM(bci_create_segments_8) [] =
1125 PUSHB_1,
1126 bci_create_segments_8,
1127 FDEF,
1129 PUSHB_2,
1131 bci_create_segments,
1132 CALL,
1134 ENDF,
1138 unsigned char FPGM(bci_create_segments_9) [] =
1141 PUSHB_1,
1142 bci_create_segments_9,
1143 FDEF,
1145 PUSHB_2,
1147 bci_create_segments,
1148 CALL,
1150 ENDF,
1156 * bci_create_segments_composite
1158 * The same as `bci_create_segments'.
1159 * It also decrements the composite component counter.
1161 * uses: bci_decrement_composite_counter
1163 * CVT: cvtl_is_subglyph
1166 unsigned char FPGM(bci_create_segments_composite) [] =
1169 PUSHB_1,
1170 bci_create_segments_composite,
1171 FDEF,
1173 PUSHB_1,
1174 bci_decrement_component_counter,
1175 CALL,
1177 /* only do something if we are not a subglyph */
1178 PUSHB_2,
1180 cvtl_is_subglyph,
1181 RCVT,
1184 /* all our measurements are taken along the y axis */
1185 SVTCA_y,
1187 PUSHB_1,
1188 sal_num_packed_segments,
1189 SWAP,
1192 DUP,
1193 ADD,
1194 PUSHB_1,
1196 SUB, /* delta = (2*num_segments - 1) */
1198 PUSHB_6,
1199 sal_segment_offset,
1200 sal_segment_offset,
1202 sal_j,
1204 sal_base,
1206 WS, /* sal_base = 0 */
1207 WS, /* sal_j = 0 (point offset) */
1209 ROLL,
1210 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1212 /* `bci_create_segment_point' also increases the loop counter by 1; */
1213 /* this effectively means we have a loop step of 2 */
1214 PUSHB_2,
1215 bci_create_segment,
1216 bci_loop,
1217 CALL,
1219 PUSHB_1,
1220 bci_hint_glyph,
1221 CALL,
1223 ELSE,
1224 CLEAR,
1225 EIF,
1227 ENDF,
1233 * bci_create_segments_composite_X
1235 * Top-level routines for calling `bci_create_segments_composite'.
1238 unsigned char FPGM(bci_create_segments_composite_0) [] =
1241 PUSHB_1,
1242 bci_create_segments_composite_0,
1243 FDEF,
1245 PUSHB_2,
1247 bci_create_segments_composite,
1248 CALL,
1250 ENDF,
1254 unsigned char FPGM(bci_create_segments_composite_1) [] =
1257 PUSHB_1,
1258 bci_create_segments_composite_1,
1259 FDEF,
1261 PUSHB_2,
1263 bci_create_segments_composite,
1264 CALL,
1266 ENDF,
1270 unsigned char FPGM(bci_create_segments_composite_2) [] =
1273 PUSHB_1,
1274 bci_create_segments_composite_2,
1275 FDEF,
1277 PUSHB_2,
1279 bci_create_segments_composite,
1280 CALL,
1282 ENDF,
1286 unsigned char FPGM(bci_create_segments_composite_3) [] =
1289 PUSHB_1,
1290 bci_create_segments_composite_3,
1291 FDEF,
1293 PUSHB_2,
1295 bci_create_segments_composite,
1296 CALL,
1298 ENDF,
1302 unsigned char FPGM(bci_create_segments_composite_4) [] =
1305 PUSHB_1,
1306 bci_create_segments_composite_4,
1307 FDEF,
1309 PUSHB_2,
1311 bci_create_segments_composite,
1312 CALL,
1314 ENDF,
1318 unsigned char FPGM(bci_create_segments_composite_5) [] =
1321 PUSHB_1,
1322 bci_create_segments_composite_5,
1323 FDEF,
1325 PUSHB_2,
1327 bci_create_segments_composite,
1328 CALL,
1330 ENDF,
1334 unsigned char FPGM(bci_create_segments_composite_6) [] =
1337 PUSHB_1,
1338 bci_create_segments_composite_6,
1339 FDEF,
1341 PUSHB_2,
1343 bci_create_segments_composite,
1344 CALL,
1346 ENDF,
1350 unsigned char FPGM(bci_create_segments_composite_7) [] =
1353 PUSHB_1,
1354 bci_create_segments_composite_7,
1355 FDEF,
1357 PUSHB_2,
1359 bci_create_segments_composite,
1360 CALL,
1362 ENDF,
1366 unsigned char FPGM(bci_create_segments_composite_8) [] =
1369 PUSHB_1,
1370 bci_create_segments_composite_8,
1371 FDEF,
1373 PUSHB_2,
1375 bci_create_segments_composite,
1376 CALL,
1378 ENDF,
1382 unsigned char FPGM(bci_create_segments_composite_9) [] =
1385 PUSHB_1,
1386 bci_create_segments_composite_9,
1387 FDEF,
1389 PUSHB_2,
1391 bci_create_segments_composite,
1392 CALL,
1394 ENDF,
1400 * bci_align_segment
1402 * Align all points in a segment to the twilight point in rp0.
1403 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1405 * in: segment_index
1408 unsigned char FPGM(bci_align_segment) [] =
1411 PUSHB_1,
1412 bci_align_segment,
1413 FDEF,
1415 /* we need the values of `sal_segment_offset + 2*segment_index' */
1416 /* and `sal_segment_offset + 2*segment_index + 1' */
1417 DUP,
1418 ADD,
1419 PUSHB_1,
1420 sal_segment_offset,
1421 ADD,
1422 DUP,
1424 SWAP,
1425 PUSHB_1,
1427 ADD,
1428 RS, /* s: first last */
1430 /* start_loop: */
1431 PUSHB_1,
1433 CINDEX, /* s: first last first */
1434 PUSHB_1,
1436 CINDEX, /* s: first last first last */
1437 LTEQ, /* first <= end */
1438 IF, /* s: first last */
1439 SWAP,
1440 DUP, /* s: last first first */
1441 ALIGNRP, /* align point with index `first' with rp0 */
1443 PUSHB_1,
1445 ADD, /* first = first + 1 */
1446 SWAP, /* s: first last */
1448 PUSHB_1,
1450 NEG,
1451 JMPR, /* goto start_loop */
1453 ELSE,
1454 POP,
1455 POP,
1456 EIF,
1458 ENDF,
1464 * bci_align_segments
1466 * Align segments to the twilight point in rp0.
1467 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1469 * in: first_segment
1470 * loop_counter (N)
1471 * segment_1
1472 * segment_2
1473 * ...
1474 * segment_N
1476 * uses: handle_segment
1480 unsigned char FPGM(bci_align_segments) [] =
1483 PUSHB_1,
1484 bci_align_segments,
1485 FDEF,
1487 PUSHB_1,
1488 bci_align_segment,
1489 CALL,
1491 PUSHB_1,
1492 bci_align_segment,
1493 LOOPCALL,
1495 ENDF,
1501 * bci_scale_contour
1503 * Scale a contour using two points giving the maximum and minimum
1504 * coordinates.
1506 * It expects that no point on the contour is touched.
1508 * in: min_point
1509 * max_point
1511 * CVT: cvtl_scale
1512 * cvtl_0x10000
1515 unsigned char FPGM(bci_scale_contour) [] =
1518 PUSHB_1,
1519 bci_scale_contour,
1520 FDEF,
1522 DUP,
1523 DUP,
1524 GC_orig,
1525 DUP,
1526 DO_SCALE, /* min_pos_new = min_pos * scale */
1527 SWAP,
1528 SUB,
1529 SHPIX,
1531 /* don't scale a single-point contour twice */
1532 SWAP,
1533 DUP,
1534 ROLL,
1535 NEQ,
1537 DUP,
1538 GC_orig,
1539 DUP,
1540 DO_SCALE, /* max_pos_new = max_pos * scale */
1541 SWAP,
1542 SUB,
1543 SHPIX,
1545 ELSE,
1546 POP,
1547 EIF,
1549 ENDF,
1555 * bci_scale_glyph
1557 * Scale a glyph using a list of points (two points per contour, giving
1558 * the maximum and mininum coordinates).
1560 * It expects that no point in the glyph is touched.
1562 * Note that the point numbers are sorted in ascending order;
1563 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1564 * contour without specifying which one is the minimum and maximum.
1566 * in: num_contours (N)
1567 * min_point_1
1568 * max_point_1
1569 * min_point_2
1570 * max_point_2
1571 * ...
1572 * min_point_N
1573 * max_point_N
1575 * uses: bci_scale_contour
1577 * CVT: cvtl_is_subglyph
1580 unsigned char FPGM(bci_scale_glyph) [] =
1583 PUSHB_1,
1584 bci_scale_glyph,
1585 FDEF,
1587 /* only do something if we are not a subglyph */
1588 PUSHB_2,
1590 cvtl_is_subglyph,
1591 RCVT,
1594 /* all our measurements are taken along the y axis */
1595 SVTCA_y,
1597 PUSHB_1,
1599 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1601 PUSHB_1,
1602 bci_scale_contour,
1603 LOOPCALL,
1605 PUSHB_1,
1607 SZP2, /* set zp2 to normal zone 1 */
1608 IUP_y,
1610 ELSE,
1611 CLEAR,
1612 EIF,
1614 ENDF,
1620 * bci_scale_composite_glyph
1622 * The same as `bci_scale_composite_glyph'.
1623 * It also decrements the composite component counter.
1625 * uses: bci_decrement_component_counter
1627 * CVT: cvtl_is_subglyph
1630 unsigned char FPGM(bci_scale_composite_glyph) [] =
1633 PUSHB_1,
1634 bci_scale_composite_glyph,
1635 FDEF,
1637 PUSHB_1,
1638 bci_decrement_component_counter,
1639 CALL,
1641 /* only do something if we are not a subglyph */
1642 PUSHB_2,
1644 cvtl_is_subglyph,
1645 RCVT,
1648 /* all our measurements are taken along the y axis */
1649 SVTCA_y,
1651 PUSHB_1,
1653 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1655 PUSHB_1,
1656 bci_scale_contour,
1657 LOOPCALL,
1659 PUSHB_1,
1661 SZP2, /* set zp2 to normal zone 1 */
1662 IUP_y,
1664 ELSE,
1665 CLEAR,
1666 EIF,
1668 ENDF,
1674 * bci_shift_contour
1676 * Shift a contour by a given amount.
1678 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1679 * point to the normal zone 1.
1681 * in: contour
1682 * out: contour + 1
1685 unsigned char FPGM(bci_shift_contour) [] =
1688 PUSHB_1,
1689 bci_shift_contour,
1690 FDEF,
1692 DUP,
1693 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1695 PUSHB_1,
1697 ADD,
1699 ENDF,
1705 * bci_shift_subglyph
1707 * Shift a subglyph. To be more specific, it corrects the already applied
1708 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1709 * also.
1711 * If this function is called, a point `x' in the subglyph has been scaled
1712 * already (during the hinting of the subglyph itself), and `offset' has
1713 * been applied also:
1715 * x -> x * scale + offset (1)
1717 * However, the offset should be applied first, then the scaling:
1719 * x -> (x + offset) * scale (2)
1721 * Our job is now to transform (1) to (2); a simple calculation shows that
1722 * we have to shift all points of the subglyph by
1724 * offset * scale - offset = offset * (scale - 1)
1726 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1728 * in: offset (in FUnits)
1729 * num_contours
1730 * first_contour
1732 * CVT: cvtl_funits_to_pixels
1733 * cvtl_0x10000
1734 * cvtl_scale
1737 unsigned char FPGM(bci_shift_subglyph) [] =
1740 PUSHB_1,
1741 bci_shift_subglyph,
1742 FDEF,
1744 SVTCA_y,
1746 PUSHB_1,
1747 cvtl_funits_to_pixels,
1748 RCVT, /* scaling factor FUnits -> pixels */
1749 MUL,
1750 PUSHB_1,
1751 cvtl_0x10000,
1752 RCVT,
1753 DIV,
1755 /* the autohinter always rounds offsets */
1756 PUSHB_1,
1757 bci_round,
1758 CALL, /* offset = round(offset) */
1760 PUSHB_1,
1761 cvtl_scale,
1762 RCVT,
1763 MUL,
1764 PUSHB_1,
1765 cvtl_0x10000,
1766 RCVT,
1767 DIV, /* delta = offset * (scale - 1) */
1769 /* and round again */
1770 PUSHB_1,
1771 bci_round,
1772 CALL, /* offset = round(offset) */
1774 PUSHB_1,
1776 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1778 /* we create twilight point 0 as a reference point, */
1779 /* setting the original position to zero (using `cvtl_temp') */
1780 PUSHB_5,
1783 cvtl_temp,
1784 cvtl_temp,
1786 WCVTP,
1787 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1789 SWAP, /* s: first_contour num_contours 0 delta */
1790 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1792 PUSHB_2,
1793 bci_shift_contour,
1795 SZP2, /* set zp2 to normal zone 1 */
1796 LOOPCALL,
1798 ENDF,
1804 * bci_ip_outer_align_point
1806 * Auxiliary function for `bci_action_ip_before' and
1807 * `bci_action_ip_after'.
1809 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1810 * zone, and both zp1 and zp2 set to normal zone.
1812 * in: point
1814 * sal: sal_i (edge_orig_pos)
1816 * CVT: cvtl_scale
1817 * cvtl_0x10000
1820 unsigned char FPGM(bci_ip_outer_align_point) [] =
1823 PUSHB_1,
1824 bci_ip_outer_align_point,
1825 FDEF,
1827 DUP,
1828 ALIGNRP, /* align `point' with `edge' */
1829 DUP,
1830 GC_orig,
1831 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1833 PUSHB_1,
1834 sal_i,
1836 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1837 SHPIX,
1839 ENDF,
1845 * bci_ip_on_align_points
1847 * Auxiliary function for `bci_action_ip_on'.
1849 * in: edge (in twilight zone)
1850 * loop_counter (N)
1851 * point_1
1852 * point_2
1853 * ...
1854 * point_N
1857 unsigned char FPGM(bci_ip_on_align_points) [] =
1860 PUSHB_1,
1861 bci_ip_on_align_points,
1862 FDEF,
1864 MDAP_noround, /* set rp0 and rp1 to `edge' */
1866 SLOOP,
1867 ALIGNRP,
1869 ENDF,
1875 * bci_ip_between_align_point
1877 * Auxiliary function for `bci_ip_between_align_points'.
1879 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1880 * zone, and both zp1 and zp2 set to normal zone.
1882 * in: point
1884 * sal: sal_i (edge_orig_pos)
1885 * sal_j (stretch_factor)
1887 * CVT: cvtl_scale
1888 * cvtl_0x10000
1891 unsigned char FPGM(bci_ip_between_align_point) [] =
1894 PUSHB_1,
1895 bci_ip_between_align_point,
1896 FDEF,
1898 DUP,
1899 ALIGNRP, /* align `point' with `edge' */
1900 DUP,
1901 GC_orig,
1902 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1904 PUSHB_1,
1905 sal_i,
1907 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1908 PUSHB_1,
1909 sal_j,
1911 MUL, /* s: point delta */
1912 SHPIX,
1914 ENDF,
1920 * bci_ip_between_align_points
1922 * Auxiliary function for `bci_action_ip_between'.
1924 * in: after_edge (in twilight zone)
1925 * before_edge (in twilight zone)
1926 * loop_counter (N)
1927 * point_1
1928 * point_2
1929 * ...
1930 * point_N
1932 * sal: sal_i (before_orig_pos)
1933 * sal_j (stretch_factor)
1935 * uses: bci_ip_between_align_point
1938 unsigned char FPGM(bci_ip_between_align_points) [] =
1941 PUSHB_1,
1942 bci_ip_between_align_points,
1943 FDEF,
1945 PUSHB_2,
1948 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1949 CINDEX,
1950 DUP, /* s: ... before after before before */
1951 MDAP_noround, /* set rp0 and rp1 to `before' */
1952 DUP,
1953 GC_orig, /* s: ... before after before before_orig_pos */
1954 PUSHB_1,
1955 sal_i,
1956 SWAP,
1957 WS, /* sal_i = before_orig_pos */
1958 PUSHB_1,
1960 CINDEX, /* s: ... before after before after */
1961 MD_cur, /* b = after_pos - before_pos */
1962 ROLL,
1963 ROLL,
1964 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
1965 DIV, /* s: a/b */
1966 PUSHB_1,
1967 sal_j,
1968 SWAP,
1969 WS, /* sal_j = stretch_factor */
1971 PUSHB_3,
1972 bci_ip_between_align_point,
1975 SZP2, /* set zp2 to normal zone 1 */
1976 SZP1, /* set zp1 to normal zone 1 */
1977 LOOPCALL,
1979 ENDF,
1985 * bci_action_ip_before
1987 * Handle `ip_before' data to align points located before the first edge.
1989 * in: first_edge (in twilight zone)
1990 * loop_counter (N)
1991 * point_1
1992 * point_2
1993 * ...
1994 * point_N
1996 * sal: sal_i (first_edge_orig_pos)
1998 * uses: bci_ip_outer_align_point
2001 unsigned char FPGM(bci_action_ip_before) [] =
2004 PUSHB_1,
2005 bci_action_ip_before,
2006 FDEF,
2008 PUSHB_1,
2010 SZP2, /* set zp2 to twilight zone 0 */
2012 DUP,
2013 GC_orig,
2014 PUSHB_1,
2015 sal_i,
2016 SWAP,
2017 WS, /* sal_i = first_edge_orig_pos */
2019 PUSHB_3,
2023 SZP2, /* set zp2 to normal zone 1 */
2024 SZP1, /* set zp1 to normal zone 1 */
2025 SZP0, /* set zp0 to twilight zone 0 */
2027 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2029 PUSHB_1,
2030 bci_ip_outer_align_point,
2031 LOOPCALL,
2033 ENDF,
2039 * bci_action_ip_after
2041 * Handle `ip_after' data to align points located after the last edge.
2043 * in: last_edge (in twilight zone)
2044 * loop_counter (N)
2045 * point_1
2046 * point_2
2047 * ...
2048 * point_N
2050 * sal: sal_i (last_edge_orig_pos)
2052 * uses: bci_ip_outer_align_point
2055 unsigned char FPGM(bci_action_ip_after) [] =
2058 PUSHB_1,
2059 bci_action_ip_after,
2060 FDEF,
2062 PUSHB_1,
2064 SZP2, /* set zp2 to twilight zone 0 */
2066 DUP,
2067 GC_orig,
2068 PUSHB_1,
2069 sal_i,
2070 SWAP,
2071 WS, /* sal_i = last_edge_orig_pos */
2073 PUSHB_3,
2077 SZP2, /* set zp2 to normal zone 1 */
2078 SZP1, /* set zp1 to normal zone 1 */
2079 SZP0, /* set zp0 to twilight zone 0 */
2081 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2083 PUSHB_1,
2084 bci_ip_outer_align_point,
2085 LOOPCALL,
2087 ENDF,
2093 * bci_action_ip_on
2095 * Handle `ip_on' data to align points located on an edge coordinate (but
2096 * not part of an edge).
2098 * in: loop_counter (M)
2099 * edge_1 (in twilight zone)
2100 * loop_counter (N_1)
2101 * point_1
2102 * point_2
2103 * ...
2104 * point_N_1
2105 * edge_2 (in twilight zone)
2106 * loop_counter (N_2)
2107 * point_1
2108 * point_2
2109 * ...
2110 * point_N_2
2111 * ...
2112 * edge_M (in twilight zone)
2113 * loop_counter (N_M)
2114 * point_1
2115 * point_2
2116 * ...
2117 * point_N_M
2119 * uses: bci_ip_on_align_points
2122 unsigned char FPGM(bci_action_ip_on) [] =
2125 PUSHB_1,
2126 bci_action_ip_on,
2127 FDEF,
2129 PUSHB_2,
2132 SZP1, /* set zp1 to normal zone 1 */
2133 SZP0, /* set zp0 to twilight zone 0 */
2135 PUSHB_1,
2136 bci_ip_on_align_points,
2137 LOOPCALL,
2139 ENDF,
2145 * bci_action_ip_between
2147 * Handle `ip_between' data to align points located between two edges.
2149 * in: loop_counter (M)
2150 * before_edge_1 (in twilight zone)
2151 * after_edge_1 (in twilight zone)
2152 * loop_counter (N_1)
2153 * point_1
2154 * point_2
2155 * ...
2156 * point_N_1
2157 * before_edge_2 (in twilight zone)
2158 * after_edge_2 (in twilight zone)
2159 * loop_counter (N_2)
2160 * point_1
2161 * point_2
2162 * ...
2163 * point_N_2
2164 * ...
2165 * before_edge_M (in twilight zone)
2166 * after_edge_M (in twilight zone)
2167 * loop_counter (N_M)
2168 * point_1
2169 * point_2
2170 * ...
2171 * point_N_M
2173 * uses: bci_ip_between_align_points
2176 unsigned char FPGM(bci_action_ip_between) [] =
2179 PUSHB_1,
2180 bci_action_ip_between,
2181 FDEF,
2183 PUSHB_1,
2184 bci_ip_between_align_points,
2185 LOOPCALL,
2187 ENDF,
2193 * bci_adjust_common
2195 * Common code for bci_action_adjust routines.
2198 unsigned char FPGM(bci_adjust_common) [] =
2201 PUSHB_1,
2202 bci_adjust_common,
2203 FDEF,
2205 PUSHB_1,
2207 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2209 PUSHB_1,
2211 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2212 PUSHB_1,
2214 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2215 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2217 PUSHB_1,
2218 bci_compute_stem_width,
2219 CALL,
2220 NEG, /* s: [...] edge2 edge -cur_len */
2222 ROLL, /* s: [...] edge -cur_len edge2 */
2223 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2224 SWAP,
2225 DUP,
2226 DUP, /* s: [...] -cur_len edge edge edge */
2227 ALIGNRP, /* align `edge' with `edge2' */
2228 ROLL,
2229 SHPIX, /* shift `edge' by -cur_len */
2231 ENDF,
2237 * bci_adjust_bound
2239 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2240 * edge of the stem has already been moved, then moving it again if
2241 * necessary to stay bound.
2243 * in: edge2_is_serif
2244 * edge_is_round
2245 * edge_point (in twilight zone)
2246 * edge2_point (in twilight zone)
2247 * edge[-1] (in twilight zone)
2248 * ... stuff for bci_align_segments (edge) ...
2250 * uses: bci_adjust_common
2253 unsigned char FPGM(bci_adjust_bound) [] =
2256 PUSHB_1,
2257 bci_adjust_bound,
2258 FDEF,
2260 PUSHB_1,
2261 bci_adjust_common,
2262 CALL,
2264 SWAP, /* s: edge edge[-1] */
2265 DUP,
2266 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2267 GC_cur,
2268 PUSHB_1,
2270 CINDEX,
2271 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2272 GT, /* edge_pos < edge[-1]_pos */
2274 DUP,
2275 ALIGNRP, /* align `edge' to `edge[-1]' */
2276 EIF,
2278 MDAP_noround, /* set rp0 and rp1 to `edge' */
2280 PUSHB_2,
2281 bci_align_segments,
2283 SZP1, /* set zp1 to normal zone 1 */
2284 CALL,
2286 ENDF,
2292 * bci_action_adjust_bound
2293 * bci_action_adjust_bound_serif
2294 * bci_action_adjust_bound_round
2295 * bci_action_adjust_bound_round_serif
2297 * Higher-level routines for calling `bci_adjust_bound'.
2300 unsigned char FPGM(bci_action_adjust_bound) [] =
2303 PUSHB_1,
2304 bci_action_adjust_bound,
2305 FDEF,
2307 PUSHB_3,
2310 bci_adjust_bound,
2311 CALL,
2313 ENDF,
2317 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2320 PUSHB_1,
2321 bci_action_adjust_bound_serif,
2322 FDEF,
2324 PUSHB_3,
2327 bci_adjust_bound,
2328 CALL,
2330 ENDF,
2334 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2337 PUSHB_1,
2338 bci_action_adjust_bound_round,
2339 FDEF,
2341 PUSHB_3,
2344 bci_adjust_bound,
2345 CALL,
2347 ENDF,
2351 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2354 PUSHB_1,
2355 bci_action_adjust_bound_round_serif,
2356 FDEF,
2358 PUSHB_3,
2361 bci_adjust_bound,
2362 CALL,
2364 ENDF,
2370 * bci_adjust
2372 * Handle the ADJUST action to align an edge of a stem if the other edge
2373 * of the stem has already been moved.
2375 * in: edge2_is_serif
2376 * edge_is_round
2377 * edge_point (in twilight zone)
2378 * edge2_point (in twilight zone)
2379 * ... stuff for bci_align_segments (edge) ...
2381 * uses: bci_adjust_common
2384 unsigned char FPGM(bci_adjust) [] =
2387 PUSHB_1,
2388 bci_adjust,
2389 FDEF,
2391 PUSHB_1,
2392 bci_adjust_common,
2393 CALL,
2395 MDAP_noround, /* set rp0 and rp1 to `edge' */
2397 PUSHB_2,
2398 bci_align_segments,
2400 SZP1, /* set zp1 to normal zone 1 */
2401 CALL,
2403 ENDF,
2409 * bci_action_adjust
2410 * bci_action_adjust_serif
2411 * bci_action_adjust_round
2412 * bci_action_adjust_round_serif
2414 * Higher-level routines for calling `bci_adjust'.
2417 unsigned char FPGM(bci_action_adjust) [] =
2420 PUSHB_1,
2421 bci_action_adjust,
2422 FDEF,
2424 PUSHB_3,
2427 bci_adjust,
2428 CALL,
2430 ENDF,
2434 unsigned char FPGM(bci_action_adjust_serif) [] =
2437 PUSHB_1,
2438 bci_action_adjust_serif,
2439 FDEF,
2441 PUSHB_3,
2444 bci_adjust,
2445 CALL,
2447 ENDF,
2451 unsigned char FPGM(bci_action_adjust_round) [] =
2454 PUSHB_1,
2455 bci_action_adjust_round,
2456 FDEF,
2458 PUSHB_3,
2461 bci_adjust,
2462 CALL,
2464 ENDF,
2468 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2471 PUSHB_1,
2472 bci_action_adjust_round_serif,
2473 FDEF,
2475 PUSHB_3,
2478 bci_adjust,
2479 CALL,
2481 ENDF,
2487 * bci_stem_common
2489 * Common code for bci_action_stem routines.
2492 #undef sal_u_off
2493 #define sal_u_off sal_temp1
2494 #undef sal_d_off
2495 #define sal_d_off sal_temp2
2496 #undef sal_org_len
2497 #define sal_org_len sal_temp3
2498 #undef sal_edge2
2499 #define sal_edge2 sal_temp3
2501 unsigned char FPGM(bci_stem_common) [] =
2504 PUSHB_1,
2505 bci_stem_common,
2506 FDEF,
2508 PUSHB_1,
2510 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2512 PUSHB_1,
2514 CINDEX,
2515 PUSHB_1,
2517 CINDEX,
2518 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2519 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2521 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2522 DUP,
2523 PUSHB_1,
2524 sal_org_len,
2525 SWAP,
2528 PUSHB_1,
2529 bci_compute_stem_width,
2530 CALL, /* s: [...] edge2 edge cur_len */
2532 DUP,
2533 PUSHB_1,
2535 LT, /* cur_len < 96 */
2537 DUP,
2538 PUSHB_1,
2540 LTEQ, /* cur_len <= 64 */
2542 PUSHB_4,
2543 sal_u_off,
2545 sal_d_off,
2548 ELSE,
2549 PUSHB_4,
2550 sal_u_off,
2552 sal_d_off,
2554 EIF,
2558 SWAP, /* s: [...] edge2 cur_len edge */
2559 DUP,
2560 PUSHB_1,
2561 sal_anchor,
2563 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2564 ROLL,
2565 SWAP,
2566 MD_orig_ZP2_0,
2567 SWAP,
2568 GC_cur,
2569 ADD, /* s: [...] edge2 cur_len edge org_pos */
2570 PUSHB_1,
2571 sal_org_len,
2573 PUSHB_1,
2574 2*64,
2575 DIV,
2576 ADD, /* s: [...] edge2 cur_len edge org_center */
2578 DUP,
2579 PUSHB_1,
2580 bci_round,
2581 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2583 DUP,
2584 ROLL,
2585 ROLL,
2586 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2588 DUP,
2589 PUSHB_1,
2590 sal_u_off,
2592 ADD,
2593 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2595 SWAP,
2596 PUSHB_1,
2597 sal_d_off,
2599 SUB,
2600 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2602 LT, /* delta1 < delta2 */
2604 PUSHB_1,
2605 sal_u_off,
2607 SUB, /* cur_pos1 = cur_pos1 - u_off */
2609 ELSE,
2610 PUSHB_1,
2611 sal_d_off,
2613 ADD, /* cur_pos1 = cur_pos1 + d_off */
2614 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2616 PUSHB_1,
2618 CINDEX,
2619 PUSHB_1,
2620 2*64,
2621 DIV,
2622 SUB, /* arg = cur_pos1 - cur_len/2 */
2624 SWAP, /* s: [...] edge2 cur_len arg edge */
2625 DUP,
2626 DUP,
2627 PUSHB_1,
2629 MINDEX,
2630 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2631 GC_cur,
2632 SUB,
2633 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2635 ELSE,
2636 SWAP, /* s: [...] edge2 cur_len edge */
2637 PUSHB_1,
2638 sal_anchor,
2640 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
2641 PUSHB_1,
2643 CINDEX,
2644 PUSHB_1,
2645 sal_anchor,
2647 MD_orig_ZP2_0,
2648 ADD, /* s: [...] edge2 cur_len edge org_pos */
2650 DUP,
2651 PUSHB_1,
2652 sal_org_len,
2654 PUSHB_1,
2655 2*64,
2656 DIV,
2657 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2659 SWAP,
2660 DUP,
2661 PUSHB_1,
2662 bci_round,
2663 CALL, /* cur_pos1 = ROUND(org_pos) */
2664 SWAP,
2665 PUSHB_1,
2666 sal_org_len,
2668 ADD,
2669 PUSHB_1,
2670 bci_round,
2671 CALL,
2672 PUSHB_1,
2674 CINDEX,
2675 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2677 PUSHB_1,
2679 CINDEX,
2680 PUSHB_1,
2681 2*64,
2682 DIV,
2683 PUSHB_1,
2685 MINDEX,
2686 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2688 DUP,
2689 PUSHB_1,
2691 CINDEX,
2692 ADD,
2693 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2694 SWAP,
2695 PUSHB_1,
2697 CINDEX,
2698 ADD,
2699 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2700 LT, /* delta1 < delta2 */
2702 POP, /* arg = cur_pos1 */
2704 ELSE,
2705 SWAP,
2706 POP, /* arg = cur_pos2 */
2707 EIF, /* s: [...] edge2 cur_len edge arg */
2708 SWAP,
2709 DUP,
2710 DUP,
2711 PUSHB_1,
2713 MINDEX,
2714 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2715 GC_cur,
2716 SUB,
2717 SHPIX, /* edge = arg */
2718 EIF, /* s: [...] edge2 cur_len edge */
2720 ENDF,
2726 * bci_stem_bound
2728 * Handle the STEM action to align two edges of a stem, then moving one
2729 * edge again if necessary to stay bound.
2731 * The code after computing `cur_len' to shift `edge' and `edge2'
2732 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2734 * if cur_len < 96:
2735 * if cur_len < = 64:
2736 * u_off = 32
2737 * d_off = 32
2738 * else:
2739 * u_off = 38
2740 * d_off = 26
2742 * org_pos = anchor + (edge_orig - anchor_orig);
2743 * org_center = org_pos + org_len / 2;
2745 * cur_pos1 = ROUND(org_center)
2746 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2747 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2748 * if (delta1 < delta2):
2749 * cur_pos1 = cur_pos1 - u_off
2750 * else:
2751 * cur_pos1 = cur_pos1 + d_off
2753 * edge = cur_pos1 - cur_len / 2
2755 * else:
2756 * org_pos = anchor + (edge_orig - anchor_orig)
2757 * org_center = org_pos + org_len / 2;
2759 * cur_pos1 = ROUND(org_pos)
2760 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2761 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2762 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2764 * if (delta1 < delta2):
2765 * edge = cur_pos1
2766 * else:
2767 * edge = cur_pos2
2769 * edge2 = edge + cur_len
2771 * in: edge2_is_serif
2772 * edge_is_round
2773 * edge_point (in twilight zone)
2774 * edge2_point (in twilight zone)
2775 * edge[-1] (in twilight zone)
2776 * ... stuff for bci_align_segments (edge) ...
2777 * ... stuff for bci_align_segments (edge2)...
2779 * sal: sal_anchor
2780 * sal_temp1
2781 * sal_temp2
2782 * sal_temp3
2784 * uses: bci_stem_common
2787 unsigned char FPGM(bci_stem_bound) [] =
2790 PUSHB_1,
2791 bci_stem_bound,
2792 FDEF,
2794 PUSHB_1,
2795 bci_stem_common,
2796 CALL,
2798 ROLL, /* s: edge[-1] cur_len edge edge2 */
2799 DUP,
2800 DUP,
2801 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2802 PUSHB_1,
2803 sal_edge2,
2804 SWAP,
2805 WS, /* s: edge[-1] cur_len edge edge2 */
2806 ROLL,
2807 SHPIX, /* edge2 = edge + cur_len */
2809 SWAP, /* s: edge edge[-1] */
2810 DUP,
2811 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2812 GC_cur,
2813 PUSHB_1,
2815 CINDEX,
2816 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2817 GT, /* edge_pos < edge[-1]_pos */
2819 DUP,
2820 ALIGNRP, /* align `edge' to `edge[-1]' */
2821 EIF,
2823 MDAP_noround, /* set rp0 and rp1 to `edge' */
2825 PUSHB_2,
2826 bci_align_segments,
2828 SZP1, /* set zp1 to normal zone 1 */
2829 CALL,
2831 PUSHB_1,
2832 sal_edge2,
2834 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2836 PUSHB_1,
2837 bci_align_segments,
2838 CALL,
2840 ENDF,
2846 * bci_action_stem_bound
2847 * bci_action_stem_bound_serif
2848 * bci_action_stem_bound_round
2849 * bci_action_stem_bound_round_serif
2851 * Higher-level routines for calling `bci_stem_bound'.
2854 unsigned char FPGM(bci_action_stem_bound) [] =
2857 PUSHB_1,
2858 bci_action_stem_bound,
2859 FDEF,
2861 PUSHB_3,
2864 bci_stem_bound,
2865 CALL,
2867 ENDF,
2871 unsigned char FPGM(bci_action_stem_bound_serif) [] =
2874 PUSHB_1,
2875 bci_action_stem_bound_serif,
2876 FDEF,
2878 PUSHB_3,
2881 bci_stem_bound,
2882 CALL,
2884 ENDF,
2888 unsigned char FPGM(bci_action_stem_bound_round) [] =
2891 PUSHB_1,
2892 bci_action_stem_bound_round,
2893 FDEF,
2895 PUSHB_3,
2898 bci_stem_bound,
2899 CALL,
2901 ENDF,
2905 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
2908 PUSHB_1,
2909 bci_action_stem_bound_round_serif,
2910 FDEF,
2912 PUSHB_3,
2915 bci_stem_bound,
2916 CALL,
2918 ENDF,
2924 * bci_stem
2926 * Handle the STEM action to align two edges of a stem.
2928 * See `bci_stem_bound' for more details.
2930 * in: edge2_is_serif
2931 * edge_is_round
2932 * edge_point (in twilight zone)
2933 * edge2_point (in twilight zone)
2934 * ... stuff for bci_align_segments (edge) ...
2935 * ... stuff for bci_align_segments (edge2)...
2937 * sal: sal_anchor
2938 * sal_temp1
2939 * sal_temp2
2940 * sal_temp3
2942 * uses: bci_stem_common
2945 unsigned char FPGM(bci_stem) [] =
2948 PUSHB_1,
2949 bci_stem,
2950 FDEF,
2952 PUSHB_1,
2953 bci_stem_common,
2954 CALL,
2956 POP,
2957 SWAP, /* s: cur_len edge2 */
2958 DUP,
2959 DUP,
2960 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2961 PUSHB_1,
2962 sal_edge2,
2963 SWAP,
2964 WS, /* s: cur_len edge2 */
2965 SWAP,
2966 SHPIX, /* edge2 = edge + cur_len */
2968 PUSHB_2,
2969 bci_align_segments,
2971 SZP1, /* set zp1 to normal zone 1 */
2972 CALL,
2974 PUSHB_1,
2975 sal_edge2,
2977 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2979 PUSHB_1,
2980 bci_align_segments,
2981 CALL,
2982 ENDF,
2988 * bci_action_stem
2989 * bci_action_stem_serif
2990 * bci_action_stem_round
2991 * bci_action_stem_round_serif
2993 * Higher-level routines for calling `bci_stem'.
2996 unsigned char FPGM(bci_action_stem) [] =
2999 PUSHB_1,
3000 bci_action_stem,
3001 FDEF,
3003 PUSHB_3,
3006 bci_stem,
3007 CALL,
3009 ENDF,
3013 unsigned char FPGM(bci_action_stem_serif) [] =
3016 PUSHB_1,
3017 bci_action_stem_serif,
3018 FDEF,
3020 PUSHB_3,
3023 bci_stem,
3024 CALL,
3026 ENDF,
3030 unsigned char FPGM(bci_action_stem_round) [] =
3033 PUSHB_1,
3034 bci_action_stem_round,
3035 FDEF,
3037 PUSHB_3,
3040 bci_stem,
3041 CALL,
3043 ENDF,
3047 unsigned char FPGM(bci_action_stem_round_serif) [] =
3050 PUSHB_1,
3051 bci_action_stem_round_serif,
3052 FDEF,
3054 PUSHB_3,
3057 bci_stem,
3058 CALL,
3060 ENDF,
3066 * bci_link
3068 * Handle the LINK action to link an edge to another one.
3070 * in: stem_is_serif
3071 * base_is_round
3072 * base_point (in twilight zone)
3073 * stem_point (in twilight zone)
3074 * ... stuff for bci_align_segments (base) ...
3077 unsigned char FPGM(bci_link) [] =
3080 PUSHB_1,
3081 bci_link,
3082 FDEF,
3084 PUSHB_1,
3086 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3088 PUSHB_1,
3090 CINDEX,
3091 PUSHB_1,
3093 MINDEX,
3094 DUP, /* s: stem is_round is_serif stem base base */
3095 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3097 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3099 PUSHB_1,
3100 bci_compute_stem_width,
3101 CALL, /* s: stem new_dist */
3103 SWAP,
3104 DUP,
3105 ALIGNRP, /* align `stem_point' with `base_point' */
3106 DUP,
3107 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3108 SWAP,
3109 SHPIX, /* stem_point = base_point + new_dist */
3111 PUSHB_2,
3112 bci_align_segments,
3114 SZP1, /* set zp1 to normal zone 1 */
3115 CALL,
3117 ENDF,
3123 * bci_action_link
3124 * bci_action_link_serif
3125 * bci_action_link_round
3126 * bci_action_link_round_serif
3128 * Higher-level routines for calling `bci_link'.
3131 unsigned char FPGM(bci_action_link) [] =
3134 PUSHB_1,
3135 bci_action_link,
3136 FDEF,
3138 PUSHB_3,
3141 bci_link,
3142 CALL,
3144 ENDF,
3148 unsigned char FPGM(bci_action_link_serif) [] =
3151 PUSHB_1,
3152 bci_action_link_serif,
3153 FDEF,
3155 PUSHB_3,
3158 bci_link,
3159 CALL,
3161 ENDF,
3165 unsigned char FPGM(bci_action_link_round) [] =
3168 PUSHB_1,
3169 bci_action_link_round,
3170 FDEF,
3172 PUSHB_3,
3175 bci_link,
3176 CALL,
3178 ENDF,
3182 unsigned char FPGM(bci_action_link_round_serif) [] =
3185 PUSHB_1,
3186 bci_action_link_round_serif,
3187 FDEF,
3189 PUSHB_3,
3192 bci_link,
3193 CALL,
3195 ENDF,
3201 * bci_anchor
3203 * Handle the ANCHOR action to align two edges
3204 * and to set the edge anchor.
3206 * The code after computing `cur_len' to shift `edge' and `edge2'
3207 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3209 * if cur_len < 96:
3210 * if cur_len < = 64:
3211 * u_off = 32
3212 * d_off = 32
3213 * else:
3214 * u_off = 38
3215 * d_off = 26
3217 * org_center = edge_orig + org_len / 2
3218 * cur_pos1 = ROUND(org_center)
3220 * error1 = ABS(org_center - (cur_pos1 - u_off))
3221 * error2 = ABS(org_center - (cur_pos1 + d_off))
3222 * if (error1 < error2):
3223 * cur_pos1 = cur_pos1 - u_off
3224 * else:
3225 * cur_pos1 = cur_pos1 + d_off
3227 * edge = cur_pos1 - cur_len / 2
3228 * edge2 = edge + cur_len
3230 * else:
3231 * edge = ROUND(edge_orig)
3233 * in: edge2_is_serif
3234 * edge_is_round
3235 * edge_point (in twilight zone)
3236 * edge2_point (in twilight zone)
3237 * ... stuff for bci_align_segments (edge) ...
3239 * sal: sal_anchor
3240 * sal_temp1
3241 * sal_temp2
3242 * sal_temp3
3245 #undef sal_u_off
3246 #define sal_u_off sal_temp1
3247 #undef sal_d_off
3248 #define sal_d_off sal_temp2
3249 #undef sal_org_len
3250 #define sal_org_len sal_temp3
3252 unsigned char FPGM(bci_anchor) [] =
3255 PUSHB_1,
3256 bci_anchor,
3257 FDEF,
3259 /* store anchor point number in `sal_anchor' */
3260 PUSHB_2,
3261 sal_anchor,
3263 CINDEX,
3264 WS, /* sal_anchor = edge_point */
3266 PUSHB_1,
3268 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3270 PUSHB_1,
3272 CINDEX,
3273 PUSHB_1,
3275 CINDEX,
3276 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3277 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3279 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3280 DUP,
3281 PUSHB_1,
3282 sal_org_len,
3283 SWAP,
3286 PUSHB_1,
3287 bci_compute_stem_width,
3288 CALL, /* s: edge2 edge cur_len */
3290 DUP,
3291 PUSHB_1,
3293 LT, /* cur_len < 96 */
3295 DUP,
3296 PUSHB_1,
3298 LTEQ, /* cur_len <= 64 */
3300 PUSHB_4,
3301 sal_u_off,
3303 sal_d_off,
3306 ELSE,
3307 PUSHB_4,
3308 sal_u_off,
3310 sal_d_off,
3312 EIF,
3316 SWAP, /* s: edge2 cur_len edge */
3317 DUP, /* s: edge2 cur_len edge edge */
3319 GC_orig,
3320 PUSHB_1,
3321 sal_org_len,
3323 PUSHB_1,
3324 2*64,
3325 DIV,
3326 ADD, /* s: edge2 cur_len edge org_center */
3328 DUP,
3329 PUSHB_1,
3330 bci_round,
3331 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3333 DUP,
3334 ROLL,
3335 ROLL,
3336 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3338 DUP,
3339 PUSHB_1,
3340 sal_u_off,
3342 ADD,
3343 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3345 SWAP,
3346 PUSHB_1,
3347 sal_d_off,
3349 SUB,
3350 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3352 LT, /* error1 < error2 */
3354 PUSHB_1,
3355 sal_u_off,
3357 SUB, /* cur_pos1 = cur_pos1 - u_off */
3359 ELSE,
3360 PUSHB_1,
3361 sal_d_off,
3363 ADD, /* cur_pos1 = cur_pos1 + d_off */
3364 EIF, /* s: edge2 cur_len edge cur_pos1 */
3366 PUSHB_1,
3368 CINDEX,
3369 PUSHB_1,
3370 2*64,
3371 DIV,
3372 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3374 PUSHB_1,
3376 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3377 GC_cur,
3378 SUB,
3379 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3381 SWAP, /* s: cur_len edge2 */
3382 DUP,
3383 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3384 SWAP,
3385 SHPIX, /* edge2 = edge1 + cur_len */
3387 ELSE,
3388 POP, /* s: edge2 edge */
3389 DUP,
3390 DUP,
3391 GC_cur,
3392 SWAP,
3393 GC_orig,
3394 PUSHB_1,
3395 bci_round,
3396 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3397 SWAP,
3398 SUB,
3399 SHPIX, /* edge = round(edge_orig) */
3401 /* clean up stack */
3402 POP,
3403 EIF,
3405 PUSHB_2,
3406 bci_align_segments,
3408 SZP1, /* set zp1 to normal zone 1 */
3409 CALL,
3411 ENDF,
3417 * bci_action_anchor
3418 * bci_action_anchor_serif
3419 * bci_action_anchor_round
3420 * bci_action_anchor_round_serif
3422 * Higher-level routines for calling `bci_anchor'.
3425 unsigned char FPGM(bci_action_anchor) [] =
3428 PUSHB_1,
3429 bci_action_anchor,
3430 FDEF,
3432 PUSHB_3,
3435 bci_anchor,
3436 CALL,
3438 ENDF,
3442 unsigned char FPGM(bci_action_anchor_serif) [] =
3445 PUSHB_1,
3446 bci_action_anchor_serif,
3447 FDEF,
3449 PUSHB_3,
3452 bci_anchor,
3453 CALL,
3455 ENDF,
3459 unsigned char FPGM(bci_action_anchor_round) [] =
3462 PUSHB_1,
3463 bci_action_anchor_round,
3464 FDEF,
3466 PUSHB_3,
3469 bci_anchor,
3470 CALL,
3472 ENDF,
3476 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3479 PUSHB_1,
3480 bci_action_anchor_round_serif,
3481 FDEF,
3483 PUSHB_3,
3486 bci_anchor,
3487 CALL,
3489 ENDF,
3495 * bci_action_blue_anchor
3497 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3498 * and to set the edge anchor.
3500 * in: anchor_point (in twilight zone)
3501 * blue_cvt_idx
3502 * edge_point (in twilight zone)
3503 * ... stuff for bci_align_segments (edge) ...
3505 * sal: sal_anchor
3507 * uses: bci_action_blue
3510 unsigned char FPGM(bci_action_blue_anchor) [] =
3513 PUSHB_1,
3514 bci_action_blue_anchor,
3515 FDEF,
3517 /* store anchor point number in `sal_anchor' */
3518 PUSHB_1,
3519 sal_anchor,
3520 SWAP,
3523 PUSHB_1,
3524 bci_action_blue,
3525 CALL,
3527 ENDF,
3533 * bci_action_blue
3535 * Handle the BLUE action to align an edge with a blue zone.
3537 * in: blue_cvt_idx
3538 * edge_point (in twilight zone)
3539 * ... stuff for bci_align_segments (edge) ...
3542 unsigned char FPGM(bci_action_blue) [] =
3545 PUSHB_1,
3546 bci_action_blue,
3547 FDEF,
3549 PUSHB_1,
3551 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3553 /* move `edge_point' to `blue_cvt_idx' position; */
3554 /* note that we can't use MIAP since this would modify */
3555 /* the twilight point's original coordinates also */
3556 RCVT,
3557 SWAP,
3558 DUP,
3559 MDAP_noround, /* set rp0 and rp1 to `edge' */
3560 DUP,
3561 GC_cur, /* s: new_pos edge edge_pos */
3562 ROLL,
3563 SWAP,
3564 SUB, /* s: edge (new_pos - edge_pos) */
3565 SHPIX,
3567 PUSHB_2,
3568 bci_align_segments,
3570 SZP1, /* set zp1 to normal zone 1 */
3571 CALL,
3573 ENDF,
3579 * bci_serif_common
3581 * Common code for bci_action_serif routines.
3584 unsigned char FPGM(bci_serif_common) [] =
3587 PUSHB_1,
3588 bci_serif_common,
3589 FDEF,
3591 PUSHB_1,
3593 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3595 DUP,
3596 DUP,
3597 DUP,
3598 PUSHB_1,
3600 MINDEX, /* s: [...] serif serif serif serif base */
3601 DUP,
3602 MDAP_noround, /* set rp0 and rp1 to `base_point' */
3603 MD_orig_ZP2_0,
3604 SWAP,
3605 ALIGNRP, /* align `serif_point' with `base_point' */
3606 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
3608 ENDF,
3614 * bci_lower_bound
3616 * Move an edge if necessary to stay within a lower bound.
3618 * in: edge
3619 * bound
3622 unsigned char FPGM(bci_lower_bound) [] =
3625 PUSHB_1,
3626 bci_lower_bound,
3627 FDEF,
3629 SWAP, /* s: edge bound */
3630 DUP,
3631 MDAP_noround, /* set rp0 and rp1 to `bound' */
3632 GC_cur,
3633 PUSHB_1,
3635 CINDEX,
3636 GC_cur, /* s: edge bound_pos edge_pos */
3637 GT, /* edge_pos < bound_pos */
3639 DUP,
3640 ALIGNRP, /* align `edge' to `bound' */
3641 EIF,
3643 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3645 PUSHB_2,
3646 bci_align_segments,
3648 SZP1, /* set zp1 to normal zone 1 */
3649 CALL,
3651 ENDF,
3657 * bci_upper_bound
3659 * Move an edge if necessary to stay within an upper bound.
3661 * in: edge
3662 * bound
3665 unsigned char FPGM(bci_upper_bound) [] =
3668 PUSHB_1,
3669 bci_upper_bound,
3670 FDEF,
3672 SWAP, /* s: edge bound */
3673 DUP,
3674 MDAP_noround, /* set rp0 and rp1 to `bound' */
3675 GC_cur,
3676 PUSHB_1,
3678 CINDEX,
3679 GC_cur, /* s: edge bound_pos edge_pos */
3680 LT, /* edge_pos > bound_pos */
3682 DUP,
3683 ALIGNRP, /* align `edge' to `bound' */
3684 EIF,
3686 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3688 PUSHB_2,
3689 bci_align_segments,
3691 SZP1, /* set zp1 to normal zone 1 */
3692 CALL,
3694 ENDF,
3700 * bci_lower_upper_bound
3702 * Move an edge if necessary to stay within a lower and lower bound.
3704 * in: edge
3705 * lower
3706 * upper
3709 unsigned char FPGM(bci_lower_upper_bound) [] =
3712 PUSHB_1,
3713 bci_lower_upper_bound,
3714 FDEF,
3716 SWAP, /* s: upper serif lower */
3717 DUP,
3718 MDAP_noround, /* set rp0 and rp1 to `lower' */
3719 GC_cur,
3720 PUSHB_1,
3722 CINDEX,
3723 GC_cur, /* s: upper serif lower_pos serif_pos */
3724 GT, /* serif_pos < lower_pos */
3726 DUP,
3727 ALIGNRP, /* align `serif' to `lower' */
3728 EIF,
3730 SWAP, /* s: serif upper */
3731 DUP,
3732 MDAP_noround, /* set rp0 and rp1 to `upper' */
3733 GC_cur,
3734 PUSHB_1,
3736 CINDEX,
3737 GC_cur, /* s: serif upper_pos serif_pos */
3738 LT, /* serif_pos > upper_pos */
3740 DUP,
3741 ALIGNRP, /* align `serif' to `upper' */
3742 EIF,
3744 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
3746 PUSHB_2,
3747 bci_align_segments,
3749 SZP1, /* set zp1 to normal zone 1 */
3750 CALL,
3752 ENDF,
3758 * bci_action_serif
3760 * Handle the SERIF action to align a serif with its base.
3762 * in: serif_point (in twilight zone)
3763 * base_point (in twilight zone)
3764 * ... stuff for bci_align_segments (serif) ...
3766 * uses: bci_serif_common
3769 unsigned char FPGM(bci_action_serif) [] =
3772 PUSHB_1,
3773 bci_action_serif,
3774 FDEF,
3776 PUSHB_1,
3777 bci_serif_common,
3778 CALL,
3780 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
3782 PUSHB_2,
3783 bci_align_segments,
3785 SZP1, /* set zp1 to normal zone 1 */
3786 CALL,
3788 ENDF,
3794 * bci_action_serif_lower_bound
3796 * Handle the SERIF action to align a serif with its base, then moving it
3797 * again if necessary to stay within a lower bound.
3799 * in: serif_point (in twilight zone)
3800 * base_point (in twilight zone)
3801 * edge[-1] (in twilight zone)
3802 * ... stuff for bci_align_segments (serif) ...
3804 * uses: bci_serif_common
3805 * bci_lower_bound
3808 unsigned char FPGM(bci_action_serif_lower_bound) [] =
3811 PUSHB_1,
3812 bci_action_serif_lower_bound,
3813 FDEF,
3815 PUSHB_1,
3816 bci_serif_common,
3817 CALL,
3819 PUSHB_1,
3820 bci_lower_bound,
3821 CALL,
3823 ENDF,
3829 * bci_action_serif_upper_bound
3831 * Handle the SERIF action to align a serif with its base, then moving it
3832 * again if necessary to stay within an upper bound.
3834 * in: serif_point (in twilight zone)
3835 * base_point (in twilight zone)
3836 * edge[1] (in twilight zone)
3837 * ... stuff for bci_align_segments (serif) ...
3839 * uses: bci_serif_common
3840 * bci_upper_bound
3843 unsigned char FPGM(bci_action_serif_upper_bound) [] =
3846 PUSHB_1,
3847 bci_action_serif_upper_bound,
3848 FDEF,
3850 PUSHB_1,
3851 bci_serif_common,
3852 CALL,
3854 PUSHB_1,
3855 bci_upper_bound,
3856 CALL,
3858 ENDF,
3864 * bci_action_serif_lower_upper_bound
3866 * Handle the SERIF action to align a serif with its base, then moving it
3867 * again if necessary to stay within a lower and upper bound.
3869 * in: serif_point (in twilight zone)
3870 * base_point (in twilight zone)
3871 * edge[-1] (in twilight zone)
3872 * edge[1] (in twilight zone)
3873 * ... stuff for bci_align_segments (serif) ...
3875 * uses: bci_serif_common
3876 * bci_lower_upper_bound
3879 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] =
3882 PUSHB_1,
3883 bci_action_serif_lower_upper_bound,
3884 FDEF,
3886 PUSHB_1,
3888 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3890 PUSHB_1,
3891 bci_serif_common,
3892 CALL,
3894 PUSHB_1,
3895 bci_lower_upper_bound,
3896 CALL,
3898 ENDF,
3904 * bci_serif_anchor_common
3906 * Common code for bci_action_serif_anchor routines.
3909 unsigned char FPGM(bci_serif_anchor_common) [] =
3912 PUSHB_1,
3913 bci_serif_anchor_common,
3914 FDEF,
3916 PUSHB_1,
3918 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3920 DUP,
3921 PUSHB_1,
3922 sal_anchor,
3923 SWAP,
3924 WS, /* sal_anchor = edge_point */
3926 DUP,
3927 DUP,
3928 DUP,
3929 GC_cur,
3930 SWAP,
3931 GC_orig,
3932 PUSHB_1,
3933 bci_round,
3934 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
3935 SWAP,
3936 SUB,
3937 SHPIX, /* edge = round(edge_orig) */
3939 ENDF,
3945 * bci_action_serif_anchor
3947 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3948 * anchor.
3950 * in: edge_point (in twilight zone)
3951 * ... stuff for bci_align_segments (edge) ...
3953 * uses: bci_serif_anchor_common
3956 unsigned char FPGM(bci_action_serif_anchor) [] =
3959 PUSHB_1,
3960 bci_action_serif_anchor,
3961 FDEF,
3963 PUSHB_1,
3964 bci_serif_anchor_common,
3965 CALL,
3967 MDAP_noround, /* set rp0 and rp1 to `edge' */
3969 PUSHB_2,
3970 bci_align_segments,
3972 SZP1, /* set zp1 to normal zone 1 */
3973 CALL,
3975 ENDF,
3981 * bci_action_serif_anchor_lower_bound
3983 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3984 * anchor, then moving it again if necessary to stay within a lower
3985 * bound.
3987 * in: edge_point (in twilight zone)
3988 * edge[-1] (in twilight zone)
3989 * ... stuff for bci_align_segments (edge) ...
3991 * uses: bci_serif_anchor_common
3992 * bci_lower_bound
3995 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
3998 PUSHB_1,
3999 bci_action_serif_anchor_lower_bound,
4000 FDEF,
4002 PUSHB_1,
4003 bci_serif_anchor_common,
4004 CALL,
4006 PUSHB_1,
4007 bci_lower_bound,
4008 CALL,
4010 ENDF,
4016 * bci_action_serif_anchor_upper_bound
4018 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4019 * anchor, then moving it again if necessary to stay within an upper
4020 * bound.
4022 * in: edge_point (in twilight zone)
4023 * edge[1] (in twilight zone)
4024 * ... stuff for bci_align_segments (edge) ...
4026 * uses: bci_serif_anchor_common
4027 * bci_upper_bound
4030 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4033 PUSHB_1,
4034 bci_action_serif_anchor_upper_bound,
4035 FDEF,
4037 PUSHB_1,
4038 bci_serif_anchor_common,
4039 CALL,
4041 PUSHB_1,
4042 bci_upper_bound,
4043 CALL,
4045 ENDF,
4051 * bci_action_serif_anchor_lower_upper_bound
4053 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4054 * anchor, then moving it again if necessary to stay within a lower and
4055 * upper bound.
4057 * in: edge_point (in twilight zone)
4058 * edge[-1] (in twilight zone)
4059 * edge[1] (in twilight zone)
4060 * ... stuff for bci_align_segments (edge) ...
4062 * uses: bci_serif_anchor_common
4063 * bci_lower_upper_bound
4066 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] =
4069 PUSHB_1,
4070 bci_action_serif_anchor_lower_upper_bound,
4071 FDEF,
4073 PUSHB_1,
4074 bci_serif_anchor_common,
4075 CALL,
4077 PUSHB_1,
4078 bci_lower_upper_bound,
4079 CALL,
4081 ENDF,
4087 * bci_serif_link1_common
4089 * Common code for bci_action_serif_link1 routines.
4092 unsigned char FPGM(bci_serif_link1_common) [] =
4095 PUSHB_1,
4096 bci_serif_link1_common,
4097 FDEF,
4099 PUSHB_1,
4101 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4103 PUSHB_1,
4105 CINDEX, /* s: [...] after edge before after */
4106 PUSHB_1,
4108 CINDEX, /* s: [...] after edge before after before */
4109 MD_orig_ZP2_0,
4110 PUSHB_1,
4112 EQ, /* after_orig_pos == before_orig_pos */
4113 IF, /* s: [...] after edge before */
4114 MDAP_noround, /* set rp0 and rp1 to `before' */
4115 DUP,
4116 ALIGNRP, /* align `edge' with `before' */
4117 SWAP,
4118 POP,
4120 ELSE,
4121 /* we have to execute `a*b/c', with b/c very near to 1: */
4122 /* to avoid overflow while retaining precision, */
4123 /* we transform this to `a + a * (b-c)/c' */
4125 PUSHB_1,
4127 CINDEX, /* s: [...] after edge before edge */
4128 PUSHB_1,
4130 CINDEX, /* s: [...] after edge before edge before */
4131 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4133 DUP,
4134 PUSHB_1,
4136 CINDEX, /* s: [...] after edge before a a after */
4137 PUSHB_1,
4139 CINDEX, /* s: [...] after edge before a a after before */
4140 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4142 PUSHB_1,
4144 CINDEX, /* s: [...] after edge before a a c after */
4145 PUSHB_1,
4147 CINDEX, /* s: [...] after edge before a a c after before */
4148 MD_cur, /* b = after_pos - before_pos */
4150 PUSHB_1,
4152 CINDEX, /* s: [...] after edge before a a c b c */
4153 SUB, /* b-c */
4155 PUSHB_1,
4156 cvtl_0x10000,
4157 RCVT,
4158 MUL, /* (b-c) in 16.16 format */
4159 SWAP,
4160 DIV, /* s: [...] after edge before a a (b-c)/c */
4162 MUL, /* a * (b-c)/c * 2^10 */
4163 PUSHB_1,
4164 cvtl_0x10000,
4165 RCVT,
4166 DIV, /* a * (b-c)/c */
4167 ADD, /* a*b/c */
4169 SWAP,
4170 MDAP_noround, /* set rp0 and rp1 to `before' */
4171 SWAP, /* s: [...] after a*b/c edge */
4172 DUP,
4173 DUP,
4174 ALIGNRP, /* align `edge' with `before' */
4175 ROLL,
4176 SHPIX, /* shift `edge' by `a*b/c' */
4178 SWAP, /* s: [...] edge after */
4179 POP,
4180 EIF,
4182 ENDF,
4188 * bci_action_serif_link1
4190 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4191 * before and after.
4193 * in: before_point (in twilight zone)
4194 * edge_point (in twilight zone)
4195 * after_point (in twilight zone)
4196 * ... stuff for bci_align_segments (edge) ...
4198 * uses: bci_serif_link1_common
4201 unsigned char FPGM(bci_action_serif_link1) [] =
4204 PUSHB_1,
4205 bci_action_serif_link1,
4206 FDEF,
4208 PUSHB_1,
4209 bci_serif_link1_common,
4210 CALL,
4212 MDAP_noround, /* set rp0 and rp1 to `edge' */
4214 PUSHB_2,
4215 bci_align_segments,
4217 SZP1, /* set zp1 to normal zone 1 */
4218 CALL,
4220 ENDF,
4226 * bci_action_serif_link1_lower_bound
4228 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4229 * before and after. Additionally, move the serif again if necessary to
4230 * stay within a lower bound.
4232 * in: before_point (in twilight zone)
4233 * edge_point (in twilight zone)
4234 * after_point (in twilight zone)
4235 * edge[-1] (in twilight zone)
4236 * ... stuff for bci_align_segments (edge) ...
4238 * uses: bci_serif_link1_common
4239 * bci_lower_bound
4242 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4245 PUSHB_1,
4246 bci_action_serif_link1_lower_bound,
4247 FDEF,
4249 PUSHB_1,
4250 bci_serif_link1_common,
4251 CALL,
4253 PUSHB_1,
4254 bci_lower_bound,
4255 CALL,
4257 ENDF,
4263 * bci_action_serif_link1_upper_bound
4265 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4266 * before and after. Additionally, move the serif again if necessary to
4267 * stay within an upper bound.
4269 * in: before_point (in twilight zone)
4270 * edge_point (in twilight zone)
4271 * after_point (in twilight zone)
4272 * edge[1] (in twilight zone)
4273 * ... stuff for bci_align_segments (edge) ...
4275 * uses: bci_serif_link1_common
4276 * bci_upper_bound
4279 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4282 PUSHB_1,
4283 bci_action_serif_link1_upper_bound,
4284 FDEF,
4286 PUSHB_1,
4287 bci_serif_link1_common,
4288 CALL,
4290 PUSHB_1,
4291 bci_upper_bound,
4292 CALL,
4294 ENDF,
4300 * bci_action_serif_link1_lower_upper_bound
4302 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4303 * before and after. Additionally, move the serif again if necessary to
4304 * stay within a lower and upper bound.
4306 * in: before_point (in twilight zone)
4307 * edge_point (in twilight zone)
4308 * after_point (in twilight zone)
4309 * edge[-1] (in twilight zone)
4310 * edge[1] (in twilight zone)
4311 * ... stuff for bci_align_segments (edge) ...
4313 * uses: bci_serif_link1_common
4314 * bci_lower_upper_bound
4317 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] =
4320 PUSHB_1,
4321 bci_action_serif_link1_lower_upper_bound,
4322 FDEF,
4324 PUSHB_1,
4325 bci_serif_link1_common,
4326 CALL,
4328 PUSHB_1,
4329 bci_lower_upper_bound,
4330 CALL,
4332 ENDF,
4338 * bci_serif_link2_common
4340 * Common code for bci_action_serif_link2 routines.
4343 unsigned char FPGM(bci_serif_link2_common) [] =
4346 PUSHB_1,
4347 bci_serif_link2_common,
4348 FDEF,
4350 PUSHB_1,
4352 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4354 DUP, /* s: [...] edge edge */
4355 PUSHB_1,
4356 sal_anchor,
4358 DUP, /* s: [...] edge edge anchor anchor */
4359 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4361 MD_orig_ZP2_0,
4362 DUP,
4363 ADD,
4364 PUSHB_1,
4366 ADD,
4367 FLOOR,
4368 PUSHB_1,
4369 2*64,
4370 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4372 SWAP,
4373 DUP,
4374 DUP,
4375 ALIGNRP, /* align `edge' with `sal_anchor' */
4376 ROLL,
4377 SHPIX, /* shift `edge' by `delta' */
4379 ENDF,
4385 * bci_action_serif_link2
4387 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4389 * in: edge_point (in twilight zone)
4390 * ... stuff for bci_align_segments (edge) ...
4392 * uses: bci_serif_link2_common
4395 unsigned char FPGM(bci_action_serif_link2) [] =
4398 PUSHB_1,
4399 bci_action_serif_link2,
4400 FDEF,
4402 PUSHB_1,
4403 bci_serif_link2_common,
4404 CALL,
4406 MDAP_noround, /* set rp0 and rp1 to `edge' */
4408 PUSHB_2,
4409 bci_align_segments,
4411 SZP1, /* set zp1 to normal zone 1 */
4412 CALL,
4414 ENDF,
4420 * bci_action_serif_link2_lower_bound
4422 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4423 * Additionally, move the serif again if necessary to stay within a lower
4424 * bound.
4426 * in: edge_point (in twilight zone)
4427 * edge[-1] (in twilight zone)
4428 * ... stuff for bci_align_segments (edge) ...
4430 * uses: bci_serif_link2_common
4431 * bci_lower_bound
4434 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4437 PUSHB_1,
4438 bci_action_serif_link2_lower_bound,
4439 FDEF,
4441 PUSHB_1,
4442 bci_serif_link2_common,
4443 CALL,
4445 PUSHB_1,
4446 bci_lower_bound,
4447 CALL,
4449 ENDF,
4455 * bci_action_serif_link2_upper_bound
4457 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4458 * Additionally, move the serif again if necessary to stay within an upper
4459 * bound.
4461 * in: edge_point (in twilight zone)
4462 * edge[1] (in twilight zone)
4463 * ... stuff for bci_align_segments (edge) ...
4465 * uses: bci_serif_link2_common
4466 * bci_upper_bound
4469 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4472 PUSHB_1,
4473 bci_action_serif_link2_upper_bound,
4474 FDEF,
4476 PUSHB_1,
4477 bci_serif_link2_common,
4478 CALL,
4480 PUSHB_1,
4481 bci_upper_bound,
4482 CALL,
4484 ENDF,
4490 * bci_action_serif_link2_lower_upper_bound
4492 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4493 * Additionally, move the serif again if necessary to stay within a lower
4494 * and upper bound.
4496 * in: edge_point (in twilight zone)
4497 * edge[-1] (in twilight zone)
4498 * edge[1] (in twilight zone)
4499 * ... stuff for bci_align_segments (edge) ...
4501 * uses: bci_serif_link2_common
4502 * bci_lower_upper_bound
4505 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] =
4508 PUSHB_1,
4509 bci_action_serif_link2_lower_upper_bound,
4510 FDEF,
4512 PUSHB_1,
4513 bci_serif_link2_common,
4514 CALL,
4516 PUSHB_1,
4517 bci_lower_upper_bound,
4518 CALL,
4520 ENDF,
4526 * bci_hint_glyph
4528 * This is the top-level glyph hinting function which parses the arguments
4529 * on the stack and calls subroutines.
4531 * in: action_0_func_idx
4532 * ... data ...
4533 * action_1_func_idx
4534 * ... data ...
4535 * ...
4537 * uses: bci_action_ip_before
4538 * bci_action_ip_after
4539 * bci_action_ip_on
4540 * bci_action_ip_between
4542 * bci_action_adjust_bound
4543 * bci_action_adjust_bound_serif
4544 * bci_action_adjust_bound_round
4545 * bci_action_adjust_bound_round_serif
4547 * bci_action_stem_bound
4548 * bci_action_stem_bound_serif
4549 * bci_action_stem_bound_round
4550 * bci_action_stem_bound_round_serif
4552 * bci_action_link
4553 * bci_action_link_serif
4554 * bci_action_link_round
4555 * bci_action_link_round_serif
4557 * bci_action_anchor
4558 * bci_action_anchor_serif
4559 * bci_action_anchor_round
4560 * bci_action_anchor_round_serif
4562 * bci_action_blue_anchor
4564 * bci_action_adjust
4565 * bci_action_adjust_serif
4566 * bci_action_adjust_round
4567 * bci_action_adjust_round_serif
4569 * bci_action_stem
4570 * bci_action_stem_serif
4571 * bci_action_stem_round
4572 * bci_action_stem_round_serif
4574 * bci_action_blue
4576 * bci_action_serif
4577 * bci_action_serif_lower_bound
4578 * bci_action_serif_upper_bound
4579 * bci_action_serif_lower_upper_bound
4581 * bci_action_serif_anchor
4582 * bci_action_serif_anchor_lower_bound
4583 * bci_action_serif_anchor_upper_bound
4584 * bci_action_serif_anchor_lower_upper_bound
4586 * bci_action_serif_link1
4587 * bci_action_serif_link1_lower_bound
4588 * bci_action_serif_link1_upper_bound
4589 * bci_action_serif_link1_lower_upper_bound
4591 * bci_action_serif_link2
4592 * bci_action_serif_link2_lower_bound
4593 * bci_action_serif_link2_upper_bound
4594 * bci_action_serif_link2_lower_upper_bound
4596 * CVT: cvtl_is_subglyph
4599 unsigned char FPGM(bci_hint_glyph) [] =
4602 PUSHB_1,
4603 bci_hint_glyph,
4604 FDEF,
4606 /* start_loop: */
4607 /* loop until all data on stack is used */
4608 CALL,
4609 PUSHB_1,
4611 NEG,
4612 PUSHB_1,
4614 DEPTH,
4616 JROT, /* goto start_loop */
4618 PUSHB_1,
4620 SZP2, /* set zp2 to normal zone 1 */
4621 IUP_y,
4623 ENDF,
4628 #define COPY_FPGM(func_name) \
4629 memcpy(buf_p, fpgm_ ## func_name, \
4630 sizeof (fpgm_ ## func_name)); \
4631 buf_p += sizeof (fpgm_ ## func_name) \
4633 static FT_Error
4634 TA_table_build_fpgm(FT_Byte** fpgm,
4635 FT_ULong* fpgm_len,
4636 FONT* font)
4638 FT_UInt buf_len;
4639 FT_UInt len;
4640 FT_Byte* buf;
4641 FT_Byte* buf_p;
4644 buf_len = sizeof (FPGM(bci_round))
4645 + sizeof (FPGM(bci_compute_stem_width_a))
4647 + sizeof (FPGM(bci_compute_stem_width_b))
4649 + sizeof (FPGM(bci_compute_stem_width_c))
4650 + sizeof (FPGM(bci_loop))
4651 + sizeof (FPGM(bci_cvt_rescale))
4652 + sizeof (FPGM(bci_blue_round_a))
4654 + sizeof (FPGM(bci_blue_round_b))
4655 + sizeof (FPGM(bci_decrement_component_counter))
4656 + sizeof (FPGM(bci_get_point_extrema))
4657 + sizeof (FPGM(bci_nibbles))
4659 + sizeof (FPGM(bci_create_segment))
4660 + sizeof (FPGM(bci_create_segments))
4661 + sizeof (FPGM(bci_create_segments_0))
4662 + sizeof (FPGM(bci_create_segments_1))
4663 + sizeof (FPGM(bci_create_segments_2))
4664 + sizeof (FPGM(bci_create_segments_3))
4665 + sizeof (FPGM(bci_create_segments_4))
4666 + sizeof (FPGM(bci_create_segments_5))
4667 + sizeof (FPGM(bci_create_segments_6))
4668 + sizeof (FPGM(bci_create_segments_7))
4669 + sizeof (FPGM(bci_create_segments_8))
4670 + sizeof (FPGM(bci_create_segments_9))
4671 + sizeof (FPGM(bci_create_segments_composite))
4672 + sizeof (FPGM(bci_create_segments_composite_0))
4673 + sizeof (FPGM(bci_create_segments_composite_1))
4674 + sizeof (FPGM(bci_create_segments_composite_2))
4675 + sizeof (FPGM(bci_create_segments_composite_3))
4676 + sizeof (FPGM(bci_create_segments_composite_4))
4677 + sizeof (FPGM(bci_create_segments_composite_5))
4678 + sizeof (FPGM(bci_create_segments_composite_6))
4679 + sizeof (FPGM(bci_create_segments_composite_7))
4680 + sizeof (FPGM(bci_create_segments_composite_8))
4681 + sizeof (FPGM(bci_create_segments_composite_9))
4682 + sizeof (FPGM(bci_align_segment))
4683 + sizeof (FPGM(bci_align_segments))
4685 + sizeof (FPGM(bci_scale_contour))
4686 + sizeof (FPGM(bci_scale_glyph))
4687 + sizeof (FPGM(bci_scale_composite_glyph))
4688 + sizeof (FPGM(bci_shift_contour))
4689 + sizeof (FPGM(bci_shift_subglyph))
4691 + sizeof (FPGM(bci_ip_outer_align_point))
4692 + sizeof (FPGM(bci_ip_on_align_points))
4693 + sizeof (FPGM(bci_ip_between_align_point))
4694 + sizeof (FPGM(bci_ip_between_align_points))
4696 + sizeof (FPGM(bci_adjust_common))
4697 + sizeof (FPGM(bci_stem_common))
4698 + sizeof (FPGM(bci_serif_common))
4699 + sizeof (FPGM(bci_serif_anchor_common))
4700 + sizeof (FPGM(bci_serif_link1_common))
4701 + sizeof (FPGM(bci_serif_link2_common))
4703 + sizeof (FPGM(bci_lower_bound))
4704 + sizeof (FPGM(bci_upper_bound))
4705 + sizeof (FPGM(bci_lower_upper_bound))
4707 + sizeof (FPGM(bci_action_ip_before))
4708 + sizeof (FPGM(bci_action_ip_after))
4709 + sizeof (FPGM(bci_action_ip_on))
4710 + sizeof (FPGM(bci_action_ip_between))
4712 + sizeof (FPGM(bci_adjust_bound))
4713 + sizeof (FPGM(bci_action_adjust_bound))
4714 + sizeof (FPGM(bci_action_adjust_bound_serif))
4715 + sizeof (FPGM(bci_action_adjust_bound_round))
4716 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
4717 + sizeof (FPGM(bci_stem_bound))
4718 + sizeof (FPGM(bci_action_stem_bound))
4719 + sizeof (FPGM(bci_action_stem_bound_serif))
4720 + sizeof (FPGM(bci_action_stem_bound_round))
4721 + sizeof (FPGM(bci_action_stem_bound_round_serif))
4722 + sizeof (FPGM(bci_link))
4723 + sizeof (FPGM(bci_action_link))
4724 + sizeof (FPGM(bci_action_link_serif))
4725 + sizeof (FPGM(bci_action_link_round))
4726 + sizeof (FPGM(bci_action_link_round_serif))
4727 + sizeof (FPGM(bci_anchor))
4728 + sizeof (FPGM(bci_action_anchor))
4729 + sizeof (FPGM(bci_action_anchor_serif))
4730 + sizeof (FPGM(bci_action_anchor_round))
4731 + sizeof (FPGM(bci_action_anchor_round_serif))
4732 + sizeof (FPGM(bci_action_blue_anchor))
4733 + sizeof (FPGM(bci_adjust))
4734 + sizeof (FPGM(bci_action_adjust))
4735 + sizeof (FPGM(bci_action_adjust_serif))
4736 + sizeof (FPGM(bci_action_adjust_round))
4737 + sizeof (FPGM(bci_action_adjust_round_serif))
4738 + sizeof (FPGM(bci_stem))
4739 + sizeof (FPGM(bci_action_stem))
4740 + sizeof (FPGM(bci_action_stem_serif))
4741 + sizeof (FPGM(bci_action_stem_round))
4742 + sizeof (FPGM(bci_action_stem_round_serif))
4743 + sizeof (FPGM(bci_action_blue))
4744 + sizeof (FPGM(bci_action_serif))
4745 + sizeof (FPGM(bci_action_serif_lower_bound))
4746 + sizeof (FPGM(bci_action_serif_upper_bound))
4747 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
4748 + sizeof (FPGM(bci_action_serif_anchor))
4749 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
4750 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
4751 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
4752 + sizeof (FPGM(bci_action_serif_link1))
4753 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
4754 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
4755 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
4756 + sizeof (FPGM(bci_action_serif_link2))
4757 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
4758 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
4759 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
4761 + sizeof (FPGM(bci_hint_glyph));
4763 /* buffer length must be a multiple of four */
4764 len = (buf_len + 3) & ~3;
4765 buf = (FT_Byte*)malloc(len);
4766 if (!buf)
4767 return FT_Err_Out_Of_Memory;
4769 /* pad end of buffer with zeros */
4770 buf[len - 1] = 0x00;
4771 buf[len - 2] = 0x00;
4772 buf[len - 3] = 0x00;
4774 /* copy font program into buffer and fill in the missing variables */
4775 buf_p = buf;
4777 COPY_FPGM(bci_round);
4778 COPY_FPGM(bci_compute_stem_width_a);
4779 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4780 COPY_FPGM(bci_compute_stem_width_b);
4781 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4782 COPY_FPGM(bci_compute_stem_width_c);
4783 COPY_FPGM(bci_loop);
4784 COPY_FPGM(bci_cvt_rescale);
4785 COPY_FPGM(bci_blue_round_a);
4786 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
4787 COPY_FPGM(bci_blue_round_b);
4788 COPY_FPGM(bci_decrement_component_counter);
4789 COPY_FPGM(bci_get_point_extrema);
4790 COPY_FPGM(bci_nibbles);
4792 COPY_FPGM(bci_create_segment);
4793 COPY_FPGM(bci_create_segments);
4794 COPY_FPGM(bci_create_segments_0);
4795 COPY_FPGM(bci_create_segments_1);
4796 COPY_FPGM(bci_create_segments_2);
4797 COPY_FPGM(bci_create_segments_3);
4798 COPY_FPGM(bci_create_segments_4);
4799 COPY_FPGM(bci_create_segments_5);
4800 COPY_FPGM(bci_create_segments_6);
4801 COPY_FPGM(bci_create_segments_7);
4802 COPY_FPGM(bci_create_segments_8);
4803 COPY_FPGM(bci_create_segments_9);
4804 COPY_FPGM(bci_create_segments_composite);
4805 COPY_FPGM(bci_create_segments_composite_0);
4806 COPY_FPGM(bci_create_segments_composite_1);
4807 COPY_FPGM(bci_create_segments_composite_2);
4808 COPY_FPGM(bci_create_segments_composite_3);
4809 COPY_FPGM(bci_create_segments_composite_4);
4810 COPY_FPGM(bci_create_segments_composite_5);
4811 COPY_FPGM(bci_create_segments_composite_6);
4812 COPY_FPGM(bci_create_segments_composite_7);
4813 COPY_FPGM(bci_create_segments_composite_8);
4814 COPY_FPGM(bci_create_segments_composite_9);
4815 COPY_FPGM(bci_align_segment);
4816 COPY_FPGM(bci_align_segments);
4818 COPY_FPGM(bci_scale_contour);
4819 COPY_FPGM(bci_scale_glyph);
4820 COPY_FPGM(bci_scale_composite_glyph);
4821 COPY_FPGM(bci_shift_contour);
4822 COPY_FPGM(bci_shift_subglyph);
4824 COPY_FPGM(bci_ip_outer_align_point);
4825 COPY_FPGM(bci_ip_on_align_points);
4826 COPY_FPGM(bci_ip_between_align_point);
4827 COPY_FPGM(bci_ip_between_align_points);
4829 COPY_FPGM(bci_adjust_common);
4830 COPY_FPGM(bci_stem_common);
4831 COPY_FPGM(bci_serif_common);
4832 COPY_FPGM(bci_serif_anchor_common);
4833 COPY_FPGM(bci_serif_link1_common);
4834 COPY_FPGM(bci_serif_link2_common);
4836 COPY_FPGM(bci_lower_bound);
4837 COPY_FPGM(bci_upper_bound);
4838 COPY_FPGM(bci_lower_upper_bound);
4840 COPY_FPGM(bci_action_ip_before);
4841 COPY_FPGM(bci_action_ip_after);
4842 COPY_FPGM(bci_action_ip_on);
4843 COPY_FPGM(bci_action_ip_between);
4845 COPY_FPGM(bci_adjust_bound);
4846 COPY_FPGM(bci_action_adjust_bound);
4847 COPY_FPGM(bci_action_adjust_bound_serif);
4848 COPY_FPGM(bci_action_adjust_bound_round);
4849 COPY_FPGM(bci_action_adjust_bound_round_serif);
4850 COPY_FPGM(bci_stem_bound);
4851 COPY_FPGM(bci_action_stem_bound);
4852 COPY_FPGM(bci_action_stem_bound_serif);
4853 COPY_FPGM(bci_action_stem_bound_round);
4854 COPY_FPGM(bci_action_stem_bound_round_serif);
4855 COPY_FPGM(bci_link);
4856 COPY_FPGM(bci_action_link);
4857 COPY_FPGM(bci_action_link_serif);
4858 COPY_FPGM(bci_action_link_round);
4859 COPY_FPGM(bci_action_link_round_serif);
4860 COPY_FPGM(bci_anchor);
4861 COPY_FPGM(bci_action_anchor);
4862 COPY_FPGM(bci_action_anchor_serif);
4863 COPY_FPGM(bci_action_anchor_round);
4864 COPY_FPGM(bci_action_anchor_round_serif);
4865 COPY_FPGM(bci_action_blue_anchor);
4866 COPY_FPGM(bci_adjust);
4867 COPY_FPGM(bci_action_adjust);
4868 COPY_FPGM(bci_action_adjust_serif);
4869 COPY_FPGM(bci_action_adjust_round);
4870 COPY_FPGM(bci_action_adjust_round_serif);
4871 COPY_FPGM(bci_stem);
4872 COPY_FPGM(bci_action_stem);
4873 COPY_FPGM(bci_action_stem_serif);
4874 COPY_FPGM(bci_action_stem_round);
4875 COPY_FPGM(bci_action_stem_round_serif);
4876 COPY_FPGM(bci_action_blue);
4877 COPY_FPGM(bci_action_serif);
4878 COPY_FPGM(bci_action_serif_lower_bound);
4879 COPY_FPGM(bci_action_serif_upper_bound);
4880 COPY_FPGM(bci_action_serif_lower_upper_bound);
4881 COPY_FPGM(bci_action_serif_anchor);
4882 COPY_FPGM(bci_action_serif_anchor_lower_bound);
4883 COPY_FPGM(bci_action_serif_anchor_upper_bound);
4884 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
4885 COPY_FPGM(bci_action_serif_link1);
4886 COPY_FPGM(bci_action_serif_link1_lower_bound);
4887 COPY_FPGM(bci_action_serif_link1_upper_bound);
4888 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
4889 COPY_FPGM(bci_action_serif_link2);
4890 COPY_FPGM(bci_action_serif_link2_lower_bound);
4891 COPY_FPGM(bci_action_serif_link2_upper_bound);
4892 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
4894 COPY_FPGM(bci_hint_glyph);
4896 *fpgm = buf;
4897 *fpgm_len = buf_len;
4899 return FT_Err_Ok;
4903 FT_Error
4904 TA_sfnt_build_fpgm_table(SFNT* sfnt,
4905 FONT* font)
4907 FT_Error error;
4909 FT_Byte* fpgm_buf;
4910 FT_ULong fpgm_len;
4913 error = TA_sfnt_add_table_info(sfnt);
4914 if (error)
4915 return error;
4917 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
4918 if (error)
4919 return error;
4921 if (fpgm_len > sfnt->max_instructions)
4922 sfnt->max_instructions = fpgm_len;
4924 /* in case of success, `fpgm_buf' gets linked */
4925 /* and is eventually freed in `TA_font_unload' */
4926 error = TA_font_add_table(font,
4927 &sfnt->table_infos[sfnt->num_table_infos - 1],
4928 TTAG_fpgm, fpgm_len, fpgm_buf);
4929 if (error)
4931 free(fpgm_buf);
4932 return error;
4935 return FT_Err_Ok;
4938 /* end of tafpgm.c */