Reduce memory consumption.
[ttfautohint.git] / lib / tafpgm.c
blobb72568d8f214ca1a3e7f9e506fa2631d6b124f0e
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
32 GC_orig, \
33 SWAP, \
34 GC_orig, \
35 SWAP, \
36 SUB
38 #define MD_orig_ZP2_0 \
39 MD_orig_fixed
41 #define MD_orig_ZP2_1 \
42 PUSHB_1, \
43 0, \
44 SZP2, \
45 MD_orig_fixed, \
46 PUSHB_1, \
47 1, \
48 SZP2
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
52 #define DO_SCALE \
53 DUP, /* s: a a */ \
54 PUSHB_1, \
55 cvtl_scale, \
56 RCVT, \
57 MUL, /* delta * 2^10 */ \
58 PUSHB_1, \
59 cvtl_0x10000, \
60 RCVT, \
61 DIV, /* delta */ \
62 ADD /* a + delta */
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
71 * bci_round
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
76 * in: val
77 * out: ROUND(val)
80 unsigned char FPGM(bci_round) [] =
83 PUSHB_1,
84 bci_round,
85 FDEF,
87 PUSHB_1,
88 32,
89 ADD,
90 FLOOR,
92 ENDF,
98 * bci_smooth_stem_width
100 * This is the equivalent to the following code from function
101 * `ta_latin_compute_stem_width':
103 * dist = ABS(width)
105 * if (stem_is_serif
106 * && dist < 3*64)
107 * || is_extra_light:
108 * return width
109 * else if base_is_round:
110 * if dist < 80
111 * dist = 64
112 * else if dist < 56:
113 * dist = 56
115 * delta = ABS(dist - std_width)
117 * if delta < 40:
118 * dist = std_width
119 * if dist < 48
120 * dist = 48
121 * goto End
123 * if dist < 3*64:
124 * delta = dist
125 * dist = FLOOR(dist)
126 * delta = delta - dist
128 * if delta < 10:
129 * dist = dist + delta
130 * else if delta < 32:
131 * dist = dist + 10
132 * else if delta < 54:
133 * dist = dist + 54
134 * else
135 * dist = dist + delta
136 * else
137 * dist = ROUND(dist)
139 * End:
140 * if width < 0:
141 * dist = -dist
142 * return dist
145 * in: width
146 * stem_is_serif
147 * base_is_round
149 * out: new_width
151 * CVT: cvtl_is_extra_light
152 * std_width
155 unsigned char FPGM(bci_smooth_stem_width_a) [] =
158 PUSHB_1,
159 bci_smooth_stem_width,
160 FDEF,
162 DUP,
163 ABS, /* s: base_is_round stem_is_serif width dist */
165 DUP,
166 PUSHB_1,
167 3*64,
168 LT, /* dist < 3*64 */
170 PUSHB_1,
172 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
173 AND, /* stem_is_serif && dist < 3*64 */
175 PUSHB_1,
176 cvtl_is_extra_light,
177 RCVT,
178 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
180 IF, /* s: base_is_round width dist */
181 POP,
182 SWAP,
183 POP, /* s: width */
185 ELSE,
186 ROLL, /* s: width dist base_is_round */
187 IF, /* s: width dist */
188 DUP,
189 PUSHB_1,
191 LT, /* dist < 80 */
192 IF, /* s: width dist */
193 POP,
194 PUSHB_1,
195 64, /* dist = 64 */
196 EIF,
198 ELSE,
199 DUP,
200 PUSHB_1,
202 LT, /* dist < 56 */
203 IF, /* s: width dist */
204 POP,
205 PUSHB_1,
206 56, /* dist = 56 */
207 EIF,
208 EIF,
210 DUP, /* s: width dist dist */
211 PUSHB_1,
215 /* %c, index of std_width */
217 unsigned char FPGM(bci_smooth_stem_width_b) [] =
220 RCVT,
221 SUB,
222 ABS, /* s: width dist delta */
224 PUSHB_1,
226 LT, /* delta < 40 */
227 IF, /* s: width dist */
228 POP,
229 PUSHB_1,
233 /* %c, index of std_width */
235 unsigned char FPGM(bci_smooth_stem_width_c) [] =
238 RCVT, /* dist = std_width */
239 DUP,
240 PUSHB_1,
242 LT, /* dist < 48 */
244 POP,
245 PUSHB_1,
246 48, /* dist = 48 */
247 EIF,
249 ELSE,
250 DUP, /* s: width dist dist */
251 PUSHB_1,
252 3*64,
253 LT, /* dist < 3*64 */
255 DUP, /* s: width delta dist */
256 FLOOR, /* dist = FLOOR(dist) */
257 DUP, /* s: width delta dist dist */
258 ROLL,
259 ROLL, /* s: width dist delta dist */
260 SUB, /* delta = delta - dist */
262 DUP, /* s: width dist delta delta */
263 PUSHB_1,
265 LT, /* delta < 10 */
266 IF, /* s: width dist delta */
267 ADD, /* dist = dist + delta */
269 ELSE,
270 DUP,
271 PUSHB_1,
273 LT, /* delta < 32 */
275 POP,
276 PUSHB_1,
278 ADD, /* dist = dist + 10 */
280 ELSE,
281 DUP,
282 PUSHB_1,
284 LT, /* delta < 54 */
286 POP,
287 PUSHB_1,
289 ADD, /* dist = dist + 54 */
291 ELSE,
292 ADD, /* dist = dist + delta */
294 EIF,
295 EIF,
296 EIF,
298 ELSE,
299 PUSHB_1,
300 bci_round,
301 CALL, /* dist = round(dist) */
303 EIF,
304 EIF,
306 SWAP, /* s: dist width */
307 PUSHB_1,
309 LT, /* width < 0 */
311 NEG, /* dist = -dist */
312 EIF,
313 EIF,
315 ENDF,
321 * bci_get_best_width
323 * An auxiliary function for `bci_strong_stem_width'.
325 * in: n (initialized with CVT index for first vertical width)
326 * dist
328 * out: n+1
329 * dist
331 * CVT: widths[]
333 * sal: sal_best
334 * sal_ref
337 unsigned char FPGM(bci_get_best_width) [] =
340 PUSHB_1,
341 bci_get_best_width,
342 FDEF,
344 DUP,
345 RCVT, /* s: dist n w */
346 DUP,
347 PUSHB_1,
349 CINDEX, /* s: dist n w w dist */
350 SUB,
351 ABS, /* s: dist n w d */
352 DUP,
353 PUSHB_1,
354 sal_best,
355 RS, /* s: dist n w d d best */
356 LT, /* d < best */
358 PUSHB_1,
359 sal_best,
360 SWAP,
361 WS, /* best = d */
362 PUSHB_1,
363 sal_ref,
364 SWAP,
365 WS, /* reference = w */
367 ELSE,
368 POP,
369 POP,
370 EIF,
372 PUSHB_1,
374 ADD, /* n = n + 1 */
376 ENDF,
382 * bci_strong_stem_width
384 * This is the equivalent to the following code (function
385 * `ta_latin_snap_width' and some lines from
386 * `ta_latin_compute_stem_width'):
388 * best = 64 + 32 + 2;
389 * reference = width
390 * dist = ABS(width)
392 * for n in 0 .. num_widths:
393 * w = widths[n]
394 * d = ABS(dist - w)
396 * if d < best:
397 * best = d
398 * reference = w;
400 * if dist >= reference:
401 * if dist < ROUND(reference) + 48:
402 * dist = reference
403 * else
404 * if dist > ROUND(reference) - 48:
405 * dist = reference
407 * if dist >= 64:
408 * dist = ROUND(dist)
409 * else
410 * dist = 64
412 * if width < 0:
413 * dist = -dist
414 * return dist
416 * in: width
417 * stem_is_serif (unused)
418 * base_is_round (unused)
420 * out: new_width
422 * CVT: widths[]
425 unsigned char FPGM(bci_strong_stem_width_a) [] =
428 PUSHB_1,
429 bci_strong_stem_width,
430 FDEF,
432 SWAP,
433 POP,
434 SWAP,
435 POP,
436 DUP,
437 ABS, /* s: width dist */
439 PUSHB_2,
440 sal_best,
441 64 + 32 + 2,
442 WS, /* sal_best = 98 */
444 DUP,
445 PUSHB_1,
446 sal_ref,
447 SWAP,
448 WS, /* sal_ref = width */
450 PUSHB_3,
453 /* %c, first index of vertical widths */
454 /* %c, number of vertical widths */
456 unsigned char FPGM(bci_strong_stem_width_b) [] =
459 bci_get_best_width,
460 LOOPCALL,
462 POP, /* s: width dist */
463 DUP,
464 PUSHB_1,
465 sal_ref,
466 RS, /* s: width dist dist reference */
467 DUP,
468 ROLL,
469 DUP,
470 ROLL,
471 PUSHB_1,
472 bci_round,
473 CALL, /* s: width dist reference dist dist ROUND(reference) */
474 PUSHB_2,
477 CINDEX,
478 ROLL, /* s: width dist reference dist ROUND(reference) 48 reference dist */
480 LTEQ, /* dist >= reference */
481 IF, /* s: width dist reference dist ROUND(reference) 48 */
482 ADD,
483 LT, /* dist < ROUND(reference) + 48 */
485 ELSE,
486 SUB,
487 GT, /* dist > ROUND(reference) - 48 */
488 EIF,
491 SWAP, /* s: width reference dist */
492 EIF,
493 POP,
495 DUP,
496 PUSHB_1,
498 GTEQ, /* dist >= 64 */
500 PUSHB_1,
501 bci_round,
502 CALL, /* dist = ROUND(dist) */
504 ELSE,
505 POP,
506 PUSHB_1,
507 64, /* dist = 64 */
508 EIF,
510 SWAP, /* s: dist width */
511 PUSHB_1,
513 LT, /* width < 0 */
515 NEG, /* dist = -dist */
516 EIF,
518 ENDF,
524 * bci_loop
526 * Take a range and a function number and apply the function to all
527 * elements of the range.
529 * in: func_num
530 * end
531 * start
533 * sal: sal_i (counter initialized with `start')
534 * sal_limit (`end')
535 * sal_func (`func_num')
538 unsigned char FPGM(bci_loop) [] =
541 PUSHB_1,
542 bci_loop,
543 FDEF,
545 PUSHB_1,
546 sal_func,
547 SWAP,
548 WS, /* sal_func = func_num */
549 PUSHB_1,
550 sal_limit,
551 SWAP,
552 WS, /* sal_limit = end */
553 PUSHB_1,
554 sal_i,
555 SWAP,
556 WS, /* sal_i = start */
558 /* start_loop: */
559 PUSHB_1,
560 sal_i,
562 PUSHB_1,
563 sal_limit,
565 LTEQ, /* start <= end */
567 PUSHB_1,
568 sal_func,
570 CALL,
571 PUSHB_3,
572 sal_i,
574 sal_i,
576 ADD, /* start = start + 1 */
579 PUSHB_1,
581 NEG,
582 JMPR, /* goto start_loop */
583 EIF,
585 ENDF,
591 * bci_cvt_rescale
593 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
595 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
596 * consequently, the calculation `a * b/c' is done as `a + delta' with
597 * `delta = a * (b-c)/c'. This avoids overflow.
599 * sal: sal_i (CVT index)
601 * CVT: cvtl_scale
602 * cvtl_0x10000
605 unsigned char FPGM(bci_cvt_rescale) [] =
608 PUSHB_1,
609 bci_cvt_rescale,
610 FDEF,
612 PUSHB_1,
613 sal_i,
615 DUP,
616 RCVT,
617 DO_SCALE,
618 WCVTP,
620 ENDF,
626 * bci_blue_round
628 * Round a blue ref value and adjust its corresponding shoot value.
630 * sal: sal_i (CVT index)
634 unsigned char FPGM(bci_blue_round_a) [] =
637 PUSHB_1,
638 bci_blue_round,
639 FDEF,
641 PUSHB_1,
642 sal_i,
644 DUP,
645 RCVT, /* s: ref_idx ref */
647 DUP,
648 PUSHB_1,
649 bci_round,
650 CALL,
651 SWAP, /* s: ref_idx round(ref) ref */
653 PUSHB_2,
657 /* %c, blue_count */
659 unsigned char FPGM(bci_blue_round_b) [] =
663 CINDEX,
664 ADD, /* s: ref_idx round(ref) ref shoot_idx */
665 DUP,
666 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
668 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
669 SWAP,
670 SUB, /* s: ref_idx round(ref) shoot_idx dist */
671 DUP,
672 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
674 DUP,
675 PUSHB_1,
677 LT, /* delta < 32 */
679 POP,
680 PUSHB_1,
681 0, /* delta = 0 */
683 ELSE,
684 PUSHB_1,
686 LT, /* delta < 48 */
688 PUSHB_1,
689 32, /* delta = 32 */
691 ELSE,
692 PUSHB_1,
693 64, /* delta = 64 */
694 EIF,
695 EIF,
697 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
698 PUSHB_1,
700 LT, /* dist < 0 */
702 NEG, /* delta = -delta */
703 EIF,
705 PUSHB_1,
707 CINDEX,
708 SWAP,
709 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
711 WCVTP,
712 WCVTP,
714 ENDF,
720 * bci_decrement_component_counter
722 * An auxiliary function for composite glyphs.
724 * CVT: cvtl_is_subglyph
727 unsigned char FPGM(bci_decrement_component_counter) [] =
730 PUSHB_1,
731 bci_decrement_component_counter,
732 FDEF,
734 /* decrement `cvtl_is_subglyph' counter */
735 PUSHB_2,
736 cvtl_is_subglyph,
737 cvtl_is_subglyph,
738 RCVT,
739 PUSHB_1,
741 SUB,
742 WCVTP,
744 ENDF,
750 * bci_get_point_extrema
752 * An auxiliary function for `bci_create_segment'.
754 * in: point-1
755 * out: point
757 * sal: sal_point_min
758 * sal_point_max
761 unsigned char FPGM(bci_get_point_extrema) [] =
764 PUSHB_1,
765 bci_get_point_extrema,
766 FDEF,
768 PUSHB_1,
770 ADD, /* s: point */
771 DUP,
772 DUP,
774 /* check whether `point' is a new minimum */
775 PUSHB_1,
776 sal_point_min,
777 RS, /* s: point point point point_min */
778 MD_orig,
779 /* if distance is negative, we have a new minimum */
780 PUSHB_1,
783 IF, /* s: point point */
784 DUP,
785 PUSHB_1,
786 sal_point_min,
787 SWAP,
789 EIF,
791 /* check whether `point' is a new maximum */
792 PUSHB_1,
793 sal_point_max,
794 RS, /* s: point point point_max */
795 MD_orig,
796 /* if distance is positive, we have a new maximum */
797 PUSHB_1,
800 IF, /* s: point */
801 DUP,
802 PUSHB_1,
803 sal_point_max,
804 SWAP,
806 EIF, /* s: point */
808 ENDF,
814 * bci_nibbles
816 * Pop a byte with two delta arguments in its nibbles and push the
817 * expanded arguments separately as two bytes.
819 * in: 16 * (end - start) + (start - base)
821 * out: start
822 * end
824 * sal: sal_base (set to `end' at return)
828 unsigned char FPGM(bci_nibbles) [] =
830 PUSHB_1,
831 bci_nibbles,
832 FDEF,
834 DUP,
835 PUSHW_1,
836 0x04, /* 16*64 */
837 0x00,
838 DIV, /* s: in hnibble */
839 DUP,
840 PUSHW_1,
841 0x04, /* 16*64 */
842 0x00,
843 MUL, /* s: in hnibble (hnibble * 16) */
844 ROLL,
845 SWAP,
846 SUB, /* s: hnibble lnibble */
848 PUSHB_1,
849 sal_base,
851 ADD, /* s: hnibble start */
852 DUP,
853 ROLL,
854 ADD, /* s: start end */
856 DUP,
857 PUSHB_1,
858 sal_base,
859 SWAP,
860 WS, /* sal_base = end */
862 SWAP,
864 ENDF,
870 * bci_create_segment
872 * Store start and end point of a segment in the storage area,
873 * then construct a point in the twilight zone to represent it.
875 * This function is used by `bci_create_segment_points'.
877 * in: start
878 * end
879 * [last (if wrap-around segment)]
880 * [first (if wrap-around segment)]
882 * uses: bci_get_point_extrema
883 * bci_nibbles
885 * sal: sal_i (start of current segment)
886 * sal_j (current twilight point)
887 * sal_point_min
888 * sal_point_max
889 * sal_base
890 * sal_num_packed_segments
892 * CVT: cvtl_scale
893 * cvtl_0x10000
894 * cvtl_temp
896 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
897 * delta values in nibbles (without a wrap-around segment).
900 unsigned char FPGM(bci_create_segment) [] =
903 PUSHB_1,
904 bci_create_segment,
905 FDEF,
907 PUSHB_2,
909 sal_num_packed_segments,
911 NEQ,
913 PUSHB_2,
914 sal_num_packed_segments,
915 sal_num_packed_segments,
917 PUSHB_1,
919 SUB,
920 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
922 PUSHB_1,
923 bci_nibbles,
924 CALL,
925 EIF,
927 PUSHB_1,
928 sal_i,
930 PUSHB_1,
932 CINDEX,
933 WS, /* sal[sal_i] = start */
935 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
936 PUSHB_3,
937 sal_i,
939 sal_i,
941 ADD, /* sal_i = sal_i + 1 */
944 /* initialize inner loop(s) */
945 PUSHB_2,
946 sal_point_min,
948 CINDEX,
949 WS, /* sal_point_min = start */
950 PUSHB_2,
951 sal_point_max,
953 CINDEX,
954 WS, /* sal_point_max = start */
956 PUSHB_1,
958 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
960 SWAP,
961 DUP,
962 PUSHB_1,
964 CINDEX, /* s: start end end start */
965 LT, /* start > end */
967 /* we have a wrap-around segment with two more arguments */
968 /* to give the last and first point of the contour, respectively; */
969 /* our job is to store a segment `start'-`last', */
970 /* and to get extrema for the two segments */
971 /* `start'-`last' and `first'-`end' */
973 /* s: first last start end */
974 PUSHB_1,
975 sal_i,
977 PUSHB_1,
979 CINDEX,
980 WS, /* sal[sal_i] = last */
982 ROLL,
983 ROLL, /* s: first end last start */
984 DUP,
985 ROLL,
986 SWAP, /* s: first end start last start */
987 SUB, /* s: first end start loop_count */
989 PUSHB_1,
990 bci_get_point_extrema,
991 LOOPCALL,
992 /* clean up stack */
993 POP,
995 SWAP, /* s: end first */
996 PUSHB_1,
998 SUB,
999 DUP,
1000 ROLL, /* s: (first - 1) (first - 1) end */
1001 SWAP,
1002 SUB, /* s: (first - 1) loop_count */
1004 PUSHB_1,
1005 bci_get_point_extrema,
1006 LOOPCALL,
1007 /* clean up stack */
1008 POP,
1010 ELSE, /* s: start end */
1011 PUSHB_1,
1012 sal_i,
1014 PUSHB_1,
1016 CINDEX,
1017 WS, /* sal[sal_i] = end */
1019 PUSHB_1,
1021 CINDEX,
1022 SUB, /* s: start loop_count */
1024 PUSHB_1,
1025 bci_get_point_extrema,
1026 LOOPCALL,
1027 /* clean up stack */
1028 POP,
1029 EIF,
1031 /* the twilight point representing a segment */
1032 /* is in the middle between the minimum and maximum */
1033 PUSHB_1,
1034 sal_point_min,
1036 GC_orig,
1037 PUSHB_1,
1038 sal_point_max,
1040 GC_orig,
1041 ADD,
1042 PUSHB_1,
1043 2*64,
1044 DIV, /* s: middle_pos */
1046 DO_SCALE, /* middle_pos = middle_pos * scale */
1048 /* write it to temporary CVT location */
1049 PUSHB_2,
1050 cvtl_temp,
1052 SZP0, /* set zp0 to twilight zone 0 */
1053 SWAP,
1054 WCVTP,
1056 /* create twilight point with index `sal_j' */
1057 PUSHB_1,
1058 sal_j,
1060 PUSHB_1,
1061 cvtl_temp,
1062 MIAP_noround,
1064 PUSHB_3,
1065 sal_j,
1067 sal_j,
1069 ADD, /* twilight_point = twilight_point + 1 */
1072 ENDF,
1078 * bci_create_segments
1080 * This is the top-level entry function.
1082 * It pops point ranges from the stack to define segments, computes
1083 * twilight points to represent segments, and finally calls
1084 * `bci_hint_glyph' to handle the rest.
1086 * in: num_packed_segments
1087 * num_segments (N)
1088 * segment_start_0
1089 * segment_end_0
1090 * [contour_last 0 (if wrap-around segment)]
1091 * [contour_first 0 (if wrap-around segment)]
1092 * segment_start_1
1093 * segment_end_1
1094 * [contour_last 0 (if wrap-around segment)]
1095 * [contour_first 0 (if wrap-around segment)]
1096 * ...
1097 * segment_start_(N-1)
1098 * segment_end_(N-1)
1099 * [contour_last (N-1) (if wrap-around segment)]
1100 * [contour_first (N-1) (if wrap-around segment)]
1101 * ... stuff for bci_hint_glyph ...
1103 * uses: bci_create_segment
1105 * sal: sal_i (start of current segment)
1106 * sal_j (current twilight point)
1107 * sal_num_packed_segments
1108 * sal_base (the base for delta values in nibbles)
1110 * CVT: cvtl_is_subglyph
1112 * If `num_packed_segments' is set to p, the first p start/end pairs are
1113 * stored as delta values in nibbles, with the `start' delta in the lower
1114 * nibble (and there are no wrap-around segments). For example, if the
1115 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1116 * stack are 0x21, 0x32, and 0x14.
1120 unsigned char FPGM(bci_create_segments) [] =
1123 PUSHB_1,
1124 bci_create_segments,
1125 FDEF,
1127 /* only do something if we are not a subglyph */
1128 PUSHB_2,
1130 cvtl_is_subglyph,
1131 RCVT,
1134 /* all our measurements are taken along the y axis */
1135 SVTCA_y,
1137 PUSHB_1,
1138 sal_num_packed_segments,
1139 SWAP,
1142 DUP,
1143 ADD,
1144 PUSHB_1,
1146 SUB, /* delta = (2*num_segments - 1) */
1148 PUSHB_6,
1149 sal_segment_offset,
1150 sal_segment_offset,
1152 sal_j,
1154 sal_base,
1156 WS, /* sal_base = 0 */
1157 WS, /* sal_j = 0 (point offset) */
1159 ROLL,
1160 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1162 /* `bci_create_segment_point' also increases the loop counter by 1; */
1163 /* this effectively means we have a loop step of 2 */
1164 PUSHB_2,
1165 bci_create_segment,
1166 bci_loop,
1167 CALL,
1169 PUSHB_1,
1170 bci_hint_glyph,
1171 CALL,
1173 ELSE,
1174 CLEAR,
1175 EIF,
1177 ENDF,
1183 * bci_create_segments_X
1185 * Top-level routines for calling `bci_create_segments'.
1188 unsigned char FPGM(bci_create_segments_0) [] =
1191 PUSHB_1,
1192 bci_create_segments_0,
1193 FDEF,
1195 PUSHB_2,
1197 bci_create_segments,
1198 CALL,
1200 ENDF,
1204 unsigned char FPGM(bci_create_segments_1) [] =
1207 PUSHB_1,
1208 bci_create_segments_1,
1209 FDEF,
1211 PUSHB_2,
1213 bci_create_segments,
1214 CALL,
1216 ENDF,
1220 unsigned char FPGM(bci_create_segments_2) [] =
1223 PUSHB_1,
1224 bci_create_segments_2,
1225 FDEF,
1227 PUSHB_2,
1229 bci_create_segments,
1230 CALL,
1232 ENDF,
1236 unsigned char FPGM(bci_create_segments_3) [] =
1239 PUSHB_1,
1240 bci_create_segments_3,
1241 FDEF,
1243 PUSHB_2,
1245 bci_create_segments,
1246 CALL,
1248 ENDF,
1252 unsigned char FPGM(bci_create_segments_4) [] =
1255 PUSHB_1,
1256 bci_create_segments_4,
1257 FDEF,
1259 PUSHB_2,
1261 bci_create_segments,
1262 CALL,
1264 ENDF,
1268 unsigned char FPGM(bci_create_segments_5) [] =
1271 PUSHB_1,
1272 bci_create_segments_5,
1273 FDEF,
1275 PUSHB_2,
1277 bci_create_segments,
1278 CALL,
1280 ENDF,
1284 unsigned char FPGM(bci_create_segments_6) [] =
1287 PUSHB_1,
1288 bci_create_segments_6,
1289 FDEF,
1291 PUSHB_2,
1293 bci_create_segments,
1294 CALL,
1296 ENDF,
1300 unsigned char FPGM(bci_create_segments_7) [] =
1303 PUSHB_1,
1304 bci_create_segments_7,
1305 FDEF,
1307 PUSHB_2,
1309 bci_create_segments,
1310 CALL,
1312 ENDF,
1316 unsigned char FPGM(bci_create_segments_8) [] =
1319 PUSHB_1,
1320 bci_create_segments_8,
1321 FDEF,
1323 PUSHB_2,
1325 bci_create_segments,
1326 CALL,
1328 ENDF,
1332 unsigned char FPGM(bci_create_segments_9) [] =
1335 PUSHB_1,
1336 bci_create_segments_9,
1337 FDEF,
1339 PUSHB_2,
1341 bci_create_segments,
1342 CALL,
1344 ENDF,
1350 * bci_create_segments_composite
1352 * The same as `bci_create_segments'.
1353 * It also decrements the composite component counter.
1355 * uses: bci_decrement_composite_counter
1357 * CVT: cvtl_is_subglyph
1360 unsigned char FPGM(bci_create_segments_composite) [] =
1363 PUSHB_1,
1364 bci_create_segments_composite,
1365 FDEF,
1367 PUSHB_1,
1368 bci_decrement_component_counter,
1369 CALL,
1371 /* only do something if we are not a subglyph */
1372 PUSHB_2,
1374 cvtl_is_subglyph,
1375 RCVT,
1378 /* all our measurements are taken along the y axis */
1379 SVTCA_y,
1381 PUSHB_1,
1382 sal_num_packed_segments,
1383 SWAP,
1386 DUP,
1387 ADD,
1388 PUSHB_1,
1390 SUB, /* delta = (2*num_segments - 1) */
1392 PUSHB_6,
1393 sal_segment_offset,
1394 sal_segment_offset,
1396 sal_j,
1398 sal_base,
1400 WS, /* sal_base = 0 */
1401 WS, /* sal_j = 0 (point offset) */
1403 ROLL,
1404 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1406 /* `bci_create_segment_point' also increases the loop counter by 1; */
1407 /* this effectively means we have a loop step of 2 */
1408 PUSHB_2,
1409 bci_create_segment,
1410 bci_loop,
1411 CALL,
1413 PUSHB_1,
1414 bci_hint_glyph,
1415 CALL,
1417 ELSE,
1418 CLEAR,
1419 EIF,
1421 ENDF,
1427 * bci_create_segments_composite_X
1429 * Top-level routines for calling `bci_create_segments_composite'.
1432 unsigned char FPGM(bci_create_segments_composite_0) [] =
1435 PUSHB_1,
1436 bci_create_segments_composite_0,
1437 FDEF,
1439 PUSHB_2,
1441 bci_create_segments_composite,
1442 CALL,
1444 ENDF,
1448 unsigned char FPGM(bci_create_segments_composite_1) [] =
1451 PUSHB_1,
1452 bci_create_segments_composite_1,
1453 FDEF,
1455 PUSHB_2,
1457 bci_create_segments_composite,
1458 CALL,
1460 ENDF,
1464 unsigned char FPGM(bci_create_segments_composite_2) [] =
1467 PUSHB_1,
1468 bci_create_segments_composite_2,
1469 FDEF,
1471 PUSHB_2,
1473 bci_create_segments_composite,
1474 CALL,
1476 ENDF,
1480 unsigned char FPGM(bci_create_segments_composite_3) [] =
1483 PUSHB_1,
1484 bci_create_segments_composite_3,
1485 FDEF,
1487 PUSHB_2,
1489 bci_create_segments_composite,
1490 CALL,
1492 ENDF,
1496 unsigned char FPGM(bci_create_segments_composite_4) [] =
1499 PUSHB_1,
1500 bci_create_segments_composite_4,
1501 FDEF,
1503 PUSHB_2,
1505 bci_create_segments_composite,
1506 CALL,
1508 ENDF,
1512 unsigned char FPGM(bci_create_segments_composite_5) [] =
1515 PUSHB_1,
1516 bci_create_segments_composite_5,
1517 FDEF,
1519 PUSHB_2,
1521 bci_create_segments_composite,
1522 CALL,
1524 ENDF,
1528 unsigned char FPGM(bci_create_segments_composite_6) [] =
1531 PUSHB_1,
1532 bci_create_segments_composite_6,
1533 FDEF,
1535 PUSHB_2,
1537 bci_create_segments_composite,
1538 CALL,
1540 ENDF,
1544 unsigned char FPGM(bci_create_segments_composite_7) [] =
1547 PUSHB_1,
1548 bci_create_segments_composite_7,
1549 FDEF,
1551 PUSHB_2,
1553 bci_create_segments_composite,
1554 CALL,
1556 ENDF,
1560 unsigned char FPGM(bci_create_segments_composite_8) [] =
1563 PUSHB_1,
1564 bci_create_segments_composite_8,
1565 FDEF,
1567 PUSHB_2,
1569 bci_create_segments_composite,
1570 CALL,
1572 ENDF,
1576 unsigned char FPGM(bci_create_segments_composite_9) [] =
1579 PUSHB_1,
1580 bci_create_segments_composite_9,
1581 FDEF,
1583 PUSHB_2,
1585 bci_create_segments_composite,
1586 CALL,
1588 ENDF,
1594 * bci_align_segment
1596 * Align all points in a segment to the twilight point in rp0.
1597 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1599 * in: segment_index
1602 unsigned char FPGM(bci_align_segment) [] =
1605 PUSHB_1,
1606 bci_align_segment,
1607 FDEF,
1609 /* we need the values of `sal_segment_offset + 2*segment_index' */
1610 /* and `sal_segment_offset + 2*segment_index + 1' */
1611 DUP,
1612 ADD,
1613 PUSHB_1,
1614 sal_segment_offset,
1615 ADD,
1616 DUP,
1618 SWAP,
1619 PUSHB_1,
1621 ADD,
1622 RS, /* s: first last */
1624 /* start_loop: */
1625 PUSHB_1,
1627 CINDEX, /* s: first last first */
1628 PUSHB_1,
1630 CINDEX, /* s: first last first last */
1631 LTEQ, /* first <= end */
1632 IF, /* s: first last */
1633 SWAP,
1634 DUP, /* s: last first first */
1635 ALIGNRP, /* align point with index `first' with rp0 */
1637 PUSHB_1,
1639 ADD, /* first = first + 1 */
1640 SWAP, /* s: first last */
1642 PUSHB_1,
1644 NEG,
1645 JMPR, /* goto start_loop */
1647 ELSE,
1648 POP,
1649 POP,
1650 EIF,
1652 ENDF,
1658 * bci_align_segments
1660 * Align segments to the twilight point in rp0.
1661 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1663 * in: first_segment
1664 * loop_counter (N)
1665 * segment_1
1666 * segment_2
1667 * ...
1668 * segment_N
1670 * uses: handle_segment
1674 unsigned char FPGM(bci_align_segments) [] =
1677 PUSHB_1,
1678 bci_align_segments,
1679 FDEF,
1681 PUSHB_1,
1682 bci_align_segment,
1683 CALL,
1685 PUSHB_1,
1686 bci_align_segment,
1687 LOOPCALL,
1689 ENDF,
1695 * bci_scale_contour
1697 * Scale a contour using two points giving the maximum and minimum
1698 * coordinates.
1700 * It expects that no point on the contour is touched.
1702 * in: min_point
1703 * max_point
1705 * CVT: cvtl_scale
1706 * cvtl_0x10000
1709 unsigned char FPGM(bci_scale_contour) [] =
1712 PUSHB_1,
1713 bci_scale_contour,
1714 FDEF,
1716 DUP,
1717 DUP,
1718 GC_orig,
1719 DUP,
1720 DO_SCALE, /* min_pos_new = min_pos * scale */
1721 SWAP,
1722 SUB,
1723 SHPIX,
1725 /* don't scale a single-point contour twice */
1726 SWAP,
1727 DUP,
1728 ROLL,
1729 NEQ,
1731 DUP,
1732 GC_orig,
1733 DUP,
1734 DO_SCALE, /* max_pos_new = max_pos * scale */
1735 SWAP,
1736 SUB,
1737 SHPIX,
1739 ELSE,
1740 POP,
1741 EIF,
1743 ENDF,
1749 * bci_scale_glyph
1751 * Scale a glyph using a list of points (two points per contour, giving
1752 * the maximum and mininum coordinates).
1754 * It expects that no point in the glyph is touched.
1756 * Note that the point numbers are sorted in ascending order;
1757 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1758 * contour without specifying which one is the minimum and maximum.
1760 * in: num_contours (N)
1761 * min_point_1
1762 * max_point_1
1763 * min_point_2
1764 * max_point_2
1765 * ...
1766 * min_point_N
1767 * max_point_N
1769 * uses: bci_scale_contour
1771 * CVT: cvtl_is_subglyph
1774 unsigned char FPGM(bci_scale_glyph) [] =
1777 PUSHB_1,
1778 bci_scale_glyph,
1779 FDEF,
1781 /* only do something if we are not a subglyph */
1782 PUSHB_2,
1784 cvtl_is_subglyph,
1785 RCVT,
1788 /* all our measurements are taken along the y axis */
1789 SVTCA_y,
1791 PUSHB_1,
1793 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1795 PUSHB_1,
1796 bci_scale_contour,
1797 LOOPCALL,
1799 PUSHB_1,
1801 SZP2, /* set zp2 to normal zone 1 */
1802 IUP_y,
1804 ELSE,
1805 CLEAR,
1806 EIF,
1808 ENDF,
1814 * bci_scale_composite_glyph
1816 * The same as `bci_scale_composite_glyph'.
1817 * It also decrements the composite component counter.
1819 * uses: bci_decrement_component_counter
1821 * CVT: cvtl_is_subglyph
1824 unsigned char FPGM(bci_scale_composite_glyph) [] =
1827 PUSHB_1,
1828 bci_scale_composite_glyph,
1829 FDEF,
1831 PUSHB_1,
1832 bci_decrement_component_counter,
1833 CALL,
1835 /* only do something if we are not a subglyph */
1836 PUSHB_2,
1838 cvtl_is_subglyph,
1839 RCVT,
1842 /* all our measurements are taken along the y axis */
1843 SVTCA_y,
1845 PUSHB_1,
1847 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1849 PUSHB_1,
1850 bci_scale_contour,
1851 LOOPCALL,
1853 PUSHB_1,
1855 SZP2, /* set zp2 to normal zone 1 */
1856 IUP_y,
1858 ELSE,
1859 CLEAR,
1860 EIF,
1862 ENDF,
1868 * bci_shift_contour
1870 * Shift a contour by a given amount.
1872 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1873 * point to the normal zone 1.
1875 * in: contour
1876 * out: contour + 1
1879 unsigned char FPGM(bci_shift_contour) [] =
1882 PUSHB_1,
1883 bci_shift_contour,
1884 FDEF,
1886 DUP,
1887 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1889 PUSHB_1,
1891 ADD,
1893 ENDF,
1899 * bci_shift_subglyph
1901 * Shift a subglyph. To be more specific, it corrects the already applied
1902 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1903 * also.
1905 * If this function is called, a point `x' in the subglyph has been scaled
1906 * already (during the hinting of the subglyph itself), and `offset' has
1907 * been applied also:
1909 * x -> x * scale + offset (1)
1911 * However, the offset should be applied first, then the scaling:
1913 * x -> (x + offset) * scale (2)
1915 * Our job is now to transform (1) to (2); a simple calculation shows that
1916 * we have to shift all points of the subglyph by
1918 * offset * scale - offset = offset * (scale - 1)
1920 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1922 * in: offset (in FUnits)
1923 * num_contours
1924 * first_contour
1926 * CVT: cvtl_funits_to_pixels
1927 * cvtl_0x10000
1928 * cvtl_scale
1931 unsigned char FPGM(bci_shift_subglyph) [] =
1934 PUSHB_1,
1935 bci_shift_subglyph,
1936 FDEF,
1938 SVTCA_y,
1940 PUSHB_1,
1941 cvtl_funits_to_pixels,
1942 RCVT, /* scaling factor FUnits -> pixels */
1943 MUL,
1944 PUSHB_1,
1945 cvtl_0x10000,
1946 RCVT,
1947 DIV,
1949 /* the autohinter always rounds offsets */
1950 PUSHB_1,
1951 bci_round,
1952 CALL, /* offset = round(offset) */
1954 PUSHB_1,
1955 cvtl_scale,
1956 RCVT,
1957 MUL,
1958 PUSHB_1,
1959 cvtl_0x10000,
1960 RCVT,
1961 DIV, /* delta = offset * (scale - 1) */
1963 /* and round again */
1964 PUSHB_1,
1965 bci_round,
1966 CALL, /* offset = round(offset) */
1968 PUSHB_1,
1970 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1972 /* we create twilight point 0 as a reference point, */
1973 /* setting the original position to zero (using `cvtl_temp') */
1974 PUSHB_5,
1977 cvtl_temp,
1978 cvtl_temp,
1980 WCVTP,
1981 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1983 SWAP, /* s: first_contour num_contours 0 delta */
1984 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1986 PUSHB_2,
1987 bci_shift_contour,
1989 SZP2, /* set zp2 to normal zone 1 */
1990 LOOPCALL,
1992 ENDF,
1998 * bci_ip_outer_align_point
2000 * Auxiliary function for `bci_action_ip_before' and
2001 * `bci_action_ip_after'.
2003 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2004 * zone, and both zp1 and zp2 set to normal zone.
2006 * in: point
2008 * sal: sal_i (edge_orig_pos)
2010 * CVT: cvtl_scale
2011 * cvtl_0x10000
2014 unsigned char FPGM(bci_ip_outer_align_point) [] =
2017 PUSHB_1,
2018 bci_ip_outer_align_point,
2019 FDEF,
2021 DUP,
2022 ALIGNRP, /* align `point' with `edge' */
2023 DUP,
2024 GC_orig,
2025 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2027 PUSHB_1,
2028 sal_i,
2030 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2031 SHPIX,
2033 ENDF,
2039 * bci_ip_on_align_points
2041 * Auxiliary function for `bci_action_ip_on'.
2043 * in: edge (in twilight zone)
2044 * loop_counter (N)
2045 * point_1
2046 * point_2
2047 * ...
2048 * point_N
2051 unsigned char FPGM(bci_ip_on_align_points) [] =
2054 PUSHB_1,
2055 bci_ip_on_align_points,
2056 FDEF,
2058 MDAP_noround, /* set rp0 and rp1 to `edge' */
2060 SLOOP,
2061 ALIGNRP,
2063 ENDF,
2069 * bci_ip_between_align_point
2071 * Auxiliary function for `bci_ip_between_align_points'.
2073 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2074 * zone, and both zp1 and zp2 set to normal zone.
2076 * in: point
2078 * sal: sal_i (edge_orig_pos)
2079 * sal_j (stretch_factor)
2081 * CVT: cvtl_scale
2082 * cvtl_0x10000
2085 unsigned char FPGM(bci_ip_between_align_point) [] =
2088 PUSHB_1,
2089 bci_ip_between_align_point,
2090 FDEF,
2092 DUP,
2093 ALIGNRP, /* align `point' with `edge' */
2094 DUP,
2095 GC_orig,
2096 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2098 PUSHB_1,
2099 sal_i,
2101 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2102 PUSHB_1,
2103 sal_j,
2105 MUL, /* s: point delta */
2106 SHPIX,
2108 ENDF,
2114 * bci_ip_between_align_points
2116 * Auxiliary function for `bci_action_ip_between'.
2118 * in: after_edge (in twilight zone)
2119 * before_edge (in twilight zone)
2120 * loop_counter (N)
2121 * point_1
2122 * point_2
2123 * ...
2124 * point_N
2126 * sal: sal_i (before_orig_pos)
2127 * sal_j (stretch_factor)
2129 * uses: bci_ip_between_align_point
2132 unsigned char FPGM(bci_ip_between_align_points) [] =
2135 PUSHB_1,
2136 bci_ip_between_align_points,
2137 FDEF,
2139 PUSHB_2,
2142 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2143 CINDEX,
2144 DUP, /* s: ... before after before before */
2145 MDAP_noround, /* set rp0 and rp1 to `before' */
2146 DUP,
2147 GC_orig, /* s: ... before after before before_orig_pos */
2148 PUSHB_1,
2149 sal_i,
2150 SWAP,
2151 WS, /* sal_i = before_orig_pos */
2152 PUSHB_1,
2154 CINDEX, /* s: ... before after before after */
2155 MD_cur, /* b = after_pos - before_pos */
2156 ROLL,
2157 ROLL,
2158 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
2159 DIV, /* s: a/b */
2160 PUSHB_1,
2161 sal_j,
2162 SWAP,
2163 WS, /* sal_j = stretch_factor */
2165 PUSHB_3,
2166 bci_ip_between_align_point,
2169 SZP2, /* set zp2 to normal zone 1 */
2170 SZP1, /* set zp1 to normal zone 1 */
2171 LOOPCALL,
2173 ENDF,
2179 * bci_action_ip_before
2181 * Handle `ip_before' data to align points located before the first edge.
2183 * in: first_edge (in twilight zone)
2184 * loop_counter (N)
2185 * point_1
2186 * point_2
2187 * ...
2188 * point_N
2190 * sal: sal_i (first_edge_orig_pos)
2192 * uses: bci_ip_outer_align_point
2195 unsigned char FPGM(bci_action_ip_before) [] =
2198 PUSHB_1,
2199 bci_action_ip_before,
2200 FDEF,
2202 PUSHB_1,
2204 SZP2, /* set zp2 to twilight zone 0 */
2206 DUP,
2207 GC_orig,
2208 PUSHB_1,
2209 sal_i,
2210 SWAP,
2211 WS, /* sal_i = first_edge_orig_pos */
2213 PUSHB_3,
2217 SZP2, /* set zp2 to normal zone 1 */
2218 SZP1, /* set zp1 to normal zone 1 */
2219 SZP0, /* set zp0 to twilight zone 0 */
2221 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2223 PUSHB_1,
2224 bci_ip_outer_align_point,
2225 LOOPCALL,
2227 ENDF,
2233 * bci_action_ip_after
2235 * Handle `ip_after' data to align points located after the last edge.
2237 * in: last_edge (in twilight zone)
2238 * loop_counter (N)
2239 * point_1
2240 * point_2
2241 * ...
2242 * point_N
2244 * sal: sal_i (last_edge_orig_pos)
2246 * uses: bci_ip_outer_align_point
2249 unsigned char FPGM(bci_action_ip_after) [] =
2252 PUSHB_1,
2253 bci_action_ip_after,
2254 FDEF,
2256 PUSHB_1,
2258 SZP2, /* set zp2 to twilight zone 0 */
2260 DUP,
2261 GC_orig,
2262 PUSHB_1,
2263 sal_i,
2264 SWAP,
2265 WS, /* sal_i = last_edge_orig_pos */
2267 PUSHB_3,
2271 SZP2, /* set zp2 to normal zone 1 */
2272 SZP1, /* set zp1 to normal zone 1 */
2273 SZP0, /* set zp0 to twilight zone 0 */
2275 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2277 PUSHB_1,
2278 bci_ip_outer_align_point,
2279 LOOPCALL,
2281 ENDF,
2287 * bci_action_ip_on
2289 * Handle `ip_on' data to align points located on an edge coordinate (but
2290 * not part of an edge).
2292 * in: loop_counter (M)
2293 * edge_1 (in twilight zone)
2294 * loop_counter (N_1)
2295 * point_1
2296 * point_2
2297 * ...
2298 * point_N_1
2299 * edge_2 (in twilight zone)
2300 * loop_counter (N_2)
2301 * point_1
2302 * point_2
2303 * ...
2304 * point_N_2
2305 * ...
2306 * edge_M (in twilight zone)
2307 * loop_counter (N_M)
2308 * point_1
2309 * point_2
2310 * ...
2311 * point_N_M
2313 * uses: bci_ip_on_align_points
2316 unsigned char FPGM(bci_action_ip_on) [] =
2319 PUSHB_1,
2320 bci_action_ip_on,
2321 FDEF,
2323 PUSHB_2,
2326 SZP1, /* set zp1 to normal zone 1 */
2327 SZP0, /* set zp0 to twilight zone 0 */
2329 PUSHB_1,
2330 bci_ip_on_align_points,
2331 LOOPCALL,
2333 ENDF,
2339 * bci_action_ip_between
2341 * Handle `ip_between' data to align points located between two edges.
2343 * in: loop_counter (M)
2344 * before_edge_1 (in twilight zone)
2345 * after_edge_1 (in twilight zone)
2346 * loop_counter (N_1)
2347 * point_1
2348 * point_2
2349 * ...
2350 * point_N_1
2351 * before_edge_2 (in twilight zone)
2352 * after_edge_2 (in twilight zone)
2353 * loop_counter (N_2)
2354 * point_1
2355 * point_2
2356 * ...
2357 * point_N_2
2358 * ...
2359 * before_edge_M (in twilight zone)
2360 * after_edge_M (in twilight zone)
2361 * loop_counter (N_M)
2362 * point_1
2363 * point_2
2364 * ...
2365 * point_N_M
2367 * uses: bci_ip_between_align_points
2370 unsigned char FPGM(bci_action_ip_between) [] =
2373 PUSHB_1,
2374 bci_action_ip_between,
2375 FDEF,
2377 PUSHB_1,
2378 bci_ip_between_align_points,
2379 LOOPCALL,
2381 ENDF,
2387 * bci_adjust_common
2389 * Common code for bci_action_adjust routines.
2392 unsigned char FPGM(bci_adjust_common) [] =
2395 PUSHB_1,
2396 bci_adjust_common,
2397 FDEF,
2399 PUSHB_1,
2401 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2403 PUSHB_1,
2405 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2406 PUSHB_1,
2408 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2409 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2411 PUSHB_1,
2412 cvtl_stem_width_function,
2413 RCVT,
2414 CALL,
2415 NEG, /* s: [...] edge2 edge -cur_len */
2417 ROLL, /* s: [...] edge -cur_len edge2 */
2418 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2419 SWAP,
2420 DUP,
2421 DUP, /* s: [...] -cur_len edge edge edge */
2422 ALIGNRP, /* align `edge' with `edge2' */
2423 ROLL,
2424 SHPIX, /* shift `edge' by -cur_len */
2426 ENDF,
2432 * bci_adjust_bound
2434 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2435 * edge of the stem has already been moved, then moving it again if
2436 * necessary to stay bound.
2438 * in: edge2_is_serif
2439 * edge_is_round
2440 * edge_point (in twilight zone)
2441 * edge2_point (in twilight zone)
2442 * edge[-1] (in twilight zone)
2443 * ... stuff for bci_align_segments (edge) ...
2445 * uses: bci_adjust_common
2448 unsigned char FPGM(bci_adjust_bound) [] =
2451 PUSHB_1,
2452 bci_adjust_bound,
2453 FDEF,
2455 PUSHB_1,
2456 bci_adjust_common,
2457 CALL,
2459 SWAP, /* s: edge edge[-1] */
2460 DUP,
2461 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2462 GC_cur,
2463 PUSHB_1,
2465 CINDEX,
2466 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2467 GT, /* edge_pos < edge[-1]_pos */
2469 DUP,
2470 ALIGNRP, /* align `edge' to `edge[-1]' */
2471 EIF,
2473 MDAP_noround, /* set rp0 and rp1 to `edge' */
2475 PUSHB_2,
2476 bci_align_segments,
2478 SZP1, /* set zp1 to normal zone 1 */
2479 CALL,
2481 ENDF,
2487 * bci_action_adjust_bound
2488 * bci_action_adjust_bound_serif
2489 * bci_action_adjust_bound_round
2490 * bci_action_adjust_bound_round_serif
2492 * Higher-level routines for calling `bci_adjust_bound'.
2495 unsigned char FPGM(bci_action_adjust_bound) [] =
2498 PUSHB_1,
2499 bci_action_adjust_bound,
2500 FDEF,
2502 PUSHB_3,
2505 bci_adjust_bound,
2506 CALL,
2508 ENDF,
2512 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2515 PUSHB_1,
2516 bci_action_adjust_bound_serif,
2517 FDEF,
2519 PUSHB_3,
2522 bci_adjust_bound,
2523 CALL,
2525 ENDF,
2529 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2532 PUSHB_1,
2533 bci_action_adjust_bound_round,
2534 FDEF,
2536 PUSHB_3,
2539 bci_adjust_bound,
2540 CALL,
2542 ENDF,
2546 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2549 PUSHB_1,
2550 bci_action_adjust_bound_round_serif,
2551 FDEF,
2553 PUSHB_3,
2556 bci_adjust_bound,
2557 CALL,
2559 ENDF,
2565 * bci_adjust
2567 * Handle the ADJUST action to align an edge of a stem if the other edge
2568 * of the stem has already been moved.
2570 * in: edge2_is_serif
2571 * edge_is_round
2572 * edge_point (in twilight zone)
2573 * edge2_point (in twilight zone)
2574 * ... stuff for bci_align_segments (edge) ...
2576 * uses: bci_adjust_common
2579 unsigned char FPGM(bci_adjust) [] =
2582 PUSHB_1,
2583 bci_adjust,
2584 FDEF,
2586 PUSHB_1,
2587 bci_adjust_common,
2588 CALL,
2590 MDAP_noround, /* set rp0 and rp1 to `edge' */
2592 PUSHB_2,
2593 bci_align_segments,
2595 SZP1, /* set zp1 to normal zone 1 */
2596 CALL,
2598 ENDF,
2604 * bci_action_adjust
2605 * bci_action_adjust_serif
2606 * bci_action_adjust_round
2607 * bci_action_adjust_round_serif
2609 * Higher-level routines for calling `bci_adjust'.
2612 unsigned char FPGM(bci_action_adjust) [] =
2615 PUSHB_1,
2616 bci_action_adjust,
2617 FDEF,
2619 PUSHB_3,
2622 bci_adjust,
2623 CALL,
2625 ENDF,
2629 unsigned char FPGM(bci_action_adjust_serif) [] =
2632 PUSHB_1,
2633 bci_action_adjust_serif,
2634 FDEF,
2636 PUSHB_3,
2639 bci_adjust,
2640 CALL,
2642 ENDF,
2646 unsigned char FPGM(bci_action_adjust_round) [] =
2649 PUSHB_1,
2650 bci_action_adjust_round,
2651 FDEF,
2653 PUSHB_3,
2656 bci_adjust,
2657 CALL,
2659 ENDF,
2663 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2666 PUSHB_1,
2667 bci_action_adjust_round_serif,
2668 FDEF,
2670 PUSHB_3,
2673 bci_adjust,
2674 CALL,
2676 ENDF,
2682 * bci_stem_common
2684 * Common code for bci_action_stem routines.
2687 #undef sal_u_off
2688 #define sal_u_off sal_temp1
2689 #undef sal_d_off
2690 #define sal_d_off sal_temp2
2691 #undef sal_org_len
2692 #define sal_org_len sal_temp3
2693 #undef sal_edge2
2694 #define sal_edge2 sal_temp3
2696 unsigned char FPGM(bci_stem_common) [] =
2699 PUSHB_1,
2700 bci_stem_common,
2701 FDEF,
2703 PUSHB_1,
2705 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2707 PUSHB_1,
2709 CINDEX,
2710 PUSHB_1,
2712 CINDEX,
2713 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2714 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2716 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2717 DUP,
2718 PUSHB_1,
2719 sal_org_len,
2720 SWAP,
2723 PUSHB_1,
2724 cvtl_stem_width_function,
2725 RCVT,
2726 CALL, /* s: [...] edge2 edge cur_len */
2728 DUP,
2729 PUSHB_1,
2731 LT, /* cur_len < 96 */
2733 DUP,
2734 PUSHB_1,
2736 LTEQ, /* cur_len <= 64 */
2738 PUSHB_4,
2739 sal_u_off,
2741 sal_d_off,
2744 ELSE,
2745 PUSHB_4,
2746 sal_u_off,
2748 sal_d_off,
2750 EIF,
2754 SWAP, /* s: [...] edge2 cur_len edge */
2755 DUP,
2756 PUSHB_1,
2757 sal_anchor,
2759 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2760 ROLL,
2761 SWAP,
2762 MD_orig_ZP2_0,
2763 SWAP,
2764 GC_cur,
2765 ADD, /* s: [...] edge2 cur_len edge org_pos */
2766 PUSHB_1,
2767 sal_org_len,
2769 PUSHB_1,
2770 2*64,
2771 DIV,
2772 ADD, /* s: [...] edge2 cur_len edge org_center */
2774 DUP,
2775 PUSHB_1,
2776 bci_round,
2777 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2779 DUP,
2780 ROLL,
2781 ROLL,
2782 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2784 DUP,
2785 PUSHB_1,
2786 sal_u_off,
2788 ADD,
2789 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2791 SWAP,
2792 PUSHB_1,
2793 sal_d_off,
2795 SUB,
2796 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2798 LT, /* delta1 < delta2 */
2800 PUSHB_1,
2801 sal_u_off,
2803 SUB, /* cur_pos1 = cur_pos1 - u_off */
2805 ELSE,
2806 PUSHB_1,
2807 sal_d_off,
2809 ADD, /* cur_pos1 = cur_pos1 + d_off */
2810 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2812 PUSHB_1,
2814 CINDEX,
2815 PUSHB_1,
2816 2*64,
2817 DIV,
2818 SUB, /* arg = cur_pos1 - cur_len/2 */
2820 SWAP, /* s: [...] edge2 cur_len arg edge */
2821 DUP,
2822 DUP,
2823 PUSHB_1,
2825 MINDEX,
2826 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2827 GC_cur,
2828 SUB,
2829 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2831 ELSE,
2832 SWAP, /* s: [...] edge2 cur_len edge */
2833 PUSHB_1,
2834 sal_anchor,
2836 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
2837 PUSHB_1,
2839 CINDEX,
2840 PUSHB_1,
2841 sal_anchor,
2843 MD_orig_ZP2_0,
2844 ADD, /* s: [...] edge2 cur_len edge org_pos */
2846 DUP,
2847 PUSHB_1,
2848 sal_org_len,
2850 PUSHB_1,
2851 2*64,
2852 DIV,
2853 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2855 SWAP,
2856 DUP,
2857 PUSHB_1,
2858 bci_round,
2859 CALL, /* cur_pos1 = ROUND(org_pos) */
2860 SWAP,
2861 PUSHB_1,
2862 sal_org_len,
2864 ADD,
2865 PUSHB_1,
2866 bci_round,
2867 CALL,
2868 PUSHB_1,
2870 CINDEX,
2871 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2873 PUSHB_1,
2875 CINDEX,
2876 PUSHB_1,
2877 2*64,
2878 DIV,
2879 PUSHB_1,
2881 MINDEX,
2882 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2884 DUP,
2885 PUSHB_1,
2887 CINDEX,
2888 ADD,
2889 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2890 SWAP,
2891 PUSHB_1,
2893 CINDEX,
2894 ADD,
2895 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2896 LT, /* delta1 < delta2 */
2898 POP, /* arg = cur_pos1 */
2900 ELSE,
2901 SWAP,
2902 POP, /* arg = cur_pos2 */
2903 EIF, /* s: [...] edge2 cur_len edge arg */
2904 SWAP,
2905 DUP,
2906 DUP,
2907 PUSHB_1,
2909 MINDEX,
2910 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2911 GC_cur,
2912 SUB,
2913 SHPIX, /* edge = arg */
2914 EIF, /* s: [...] edge2 cur_len edge */
2916 ENDF,
2922 * bci_stem_bound
2924 * Handle the STEM action to align two edges of a stem, then moving one
2925 * edge again if necessary to stay bound.
2927 * The code after computing `cur_len' to shift `edge' and `edge2'
2928 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2930 * if cur_len < 96:
2931 * if cur_len < = 64:
2932 * u_off = 32
2933 * d_off = 32
2934 * else:
2935 * u_off = 38
2936 * d_off = 26
2938 * org_pos = anchor + (edge_orig - anchor_orig);
2939 * org_center = org_pos + org_len / 2;
2941 * cur_pos1 = ROUND(org_center)
2942 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2943 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2944 * if (delta1 < delta2):
2945 * cur_pos1 = cur_pos1 - u_off
2946 * else:
2947 * cur_pos1 = cur_pos1 + d_off
2949 * edge = cur_pos1 - cur_len / 2
2951 * else:
2952 * org_pos = anchor + (edge_orig - anchor_orig)
2953 * org_center = org_pos + org_len / 2;
2955 * cur_pos1 = ROUND(org_pos)
2956 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2957 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2958 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2960 * if (delta1 < delta2):
2961 * edge = cur_pos1
2962 * else:
2963 * edge = cur_pos2
2965 * edge2 = edge + cur_len
2967 * in: edge2_is_serif
2968 * edge_is_round
2969 * edge_point (in twilight zone)
2970 * edge2_point (in twilight zone)
2971 * edge[-1] (in twilight zone)
2972 * ... stuff for bci_align_segments (edge) ...
2973 * ... stuff for bci_align_segments (edge2)...
2975 * sal: sal_anchor
2976 * sal_temp1
2977 * sal_temp2
2978 * sal_temp3
2980 * uses: bci_stem_common
2983 unsigned char FPGM(bci_stem_bound) [] =
2986 PUSHB_1,
2987 bci_stem_bound,
2988 FDEF,
2990 PUSHB_1,
2991 bci_stem_common,
2992 CALL,
2994 ROLL, /* s: edge[-1] cur_len edge edge2 */
2995 DUP,
2996 DUP,
2997 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2998 PUSHB_1,
2999 sal_edge2,
3000 SWAP,
3001 WS, /* s: edge[-1] cur_len edge edge2 */
3002 ROLL,
3003 SHPIX, /* edge2 = edge + cur_len */
3005 SWAP, /* s: edge edge[-1] */
3006 DUP,
3007 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3008 GC_cur,
3009 PUSHB_1,
3011 CINDEX,
3012 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3013 GT, /* edge_pos < edge[-1]_pos */
3015 DUP,
3016 ALIGNRP, /* align `edge' to `edge[-1]' */
3017 EIF,
3019 MDAP_noround, /* set rp0 and rp1 to `edge' */
3021 PUSHB_2,
3022 bci_align_segments,
3024 SZP1, /* set zp1 to normal zone 1 */
3025 CALL,
3027 PUSHB_1,
3028 sal_edge2,
3030 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3032 PUSHB_1,
3033 bci_align_segments,
3034 CALL,
3036 ENDF,
3042 * bci_action_stem_bound
3043 * bci_action_stem_bound_serif
3044 * bci_action_stem_bound_round
3045 * bci_action_stem_bound_round_serif
3047 * Higher-level routines for calling `bci_stem_bound'.
3050 unsigned char FPGM(bci_action_stem_bound) [] =
3053 PUSHB_1,
3054 bci_action_stem_bound,
3055 FDEF,
3057 PUSHB_3,
3060 bci_stem_bound,
3061 CALL,
3063 ENDF,
3067 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3070 PUSHB_1,
3071 bci_action_stem_bound_serif,
3072 FDEF,
3074 PUSHB_3,
3077 bci_stem_bound,
3078 CALL,
3080 ENDF,
3084 unsigned char FPGM(bci_action_stem_bound_round) [] =
3087 PUSHB_1,
3088 bci_action_stem_bound_round,
3089 FDEF,
3091 PUSHB_3,
3094 bci_stem_bound,
3095 CALL,
3097 ENDF,
3101 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3104 PUSHB_1,
3105 bci_action_stem_bound_round_serif,
3106 FDEF,
3108 PUSHB_3,
3111 bci_stem_bound,
3112 CALL,
3114 ENDF,
3120 * bci_stem
3122 * Handle the STEM action to align two edges of a stem.
3124 * See `bci_stem_bound' for more details.
3126 * in: edge2_is_serif
3127 * edge_is_round
3128 * edge_point (in twilight zone)
3129 * edge2_point (in twilight zone)
3130 * ... stuff for bci_align_segments (edge) ...
3131 * ... stuff for bci_align_segments (edge2)...
3133 * sal: sal_anchor
3134 * sal_temp1
3135 * sal_temp2
3136 * sal_temp3
3138 * uses: bci_stem_common
3141 unsigned char FPGM(bci_stem) [] =
3144 PUSHB_1,
3145 bci_stem,
3146 FDEF,
3148 PUSHB_1,
3149 bci_stem_common,
3150 CALL,
3152 POP,
3153 SWAP, /* s: cur_len edge2 */
3154 DUP,
3155 DUP,
3156 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3157 PUSHB_1,
3158 sal_edge2,
3159 SWAP,
3160 WS, /* s: cur_len edge2 */
3161 SWAP,
3162 SHPIX, /* edge2 = edge + cur_len */
3164 PUSHB_2,
3165 bci_align_segments,
3167 SZP1, /* set zp1 to normal zone 1 */
3168 CALL,
3170 PUSHB_1,
3171 sal_edge2,
3173 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3175 PUSHB_1,
3176 bci_align_segments,
3177 CALL,
3178 ENDF,
3184 * bci_action_stem
3185 * bci_action_stem_serif
3186 * bci_action_stem_round
3187 * bci_action_stem_round_serif
3189 * Higher-level routines for calling `bci_stem'.
3192 unsigned char FPGM(bci_action_stem) [] =
3195 PUSHB_1,
3196 bci_action_stem,
3197 FDEF,
3199 PUSHB_3,
3202 bci_stem,
3203 CALL,
3205 ENDF,
3209 unsigned char FPGM(bci_action_stem_serif) [] =
3212 PUSHB_1,
3213 bci_action_stem_serif,
3214 FDEF,
3216 PUSHB_3,
3219 bci_stem,
3220 CALL,
3222 ENDF,
3226 unsigned char FPGM(bci_action_stem_round) [] =
3229 PUSHB_1,
3230 bci_action_stem_round,
3231 FDEF,
3233 PUSHB_3,
3236 bci_stem,
3237 CALL,
3239 ENDF,
3243 unsigned char FPGM(bci_action_stem_round_serif) [] =
3246 PUSHB_1,
3247 bci_action_stem_round_serif,
3248 FDEF,
3250 PUSHB_3,
3253 bci_stem,
3254 CALL,
3256 ENDF,
3262 * bci_link
3264 * Handle the LINK action to link an edge to another one.
3266 * in: stem_is_serif
3267 * base_is_round
3268 * base_point (in twilight zone)
3269 * stem_point (in twilight zone)
3270 * ... stuff for bci_align_segments (base) ...
3273 unsigned char FPGM(bci_link) [] =
3276 PUSHB_1,
3277 bci_link,
3278 FDEF,
3280 PUSHB_1,
3282 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3284 PUSHB_1,
3286 CINDEX,
3287 PUSHB_1,
3289 MINDEX,
3290 DUP, /* s: stem is_round is_serif stem base base */
3291 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3293 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3295 PUSHB_1,
3296 cvtl_stem_width_function,
3297 RCVT,
3298 CALL, /* s: stem new_dist */
3300 SWAP,
3301 DUP,
3302 ALIGNRP, /* align `stem_point' with `base_point' */
3303 DUP,
3304 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3305 SWAP,
3306 SHPIX, /* stem_point = base_point + new_dist */
3308 PUSHB_2,
3309 bci_align_segments,
3311 SZP1, /* set zp1 to normal zone 1 */
3312 CALL,
3314 ENDF,
3320 * bci_action_link
3321 * bci_action_link_serif
3322 * bci_action_link_round
3323 * bci_action_link_round_serif
3325 * Higher-level routines for calling `bci_link'.
3328 unsigned char FPGM(bci_action_link) [] =
3331 PUSHB_1,
3332 bci_action_link,
3333 FDEF,
3335 PUSHB_3,
3338 bci_link,
3339 CALL,
3341 ENDF,
3345 unsigned char FPGM(bci_action_link_serif) [] =
3348 PUSHB_1,
3349 bci_action_link_serif,
3350 FDEF,
3352 PUSHB_3,
3355 bci_link,
3356 CALL,
3358 ENDF,
3362 unsigned char FPGM(bci_action_link_round) [] =
3365 PUSHB_1,
3366 bci_action_link_round,
3367 FDEF,
3369 PUSHB_3,
3372 bci_link,
3373 CALL,
3375 ENDF,
3379 unsigned char FPGM(bci_action_link_round_serif) [] =
3382 PUSHB_1,
3383 bci_action_link_round_serif,
3384 FDEF,
3386 PUSHB_3,
3389 bci_link,
3390 CALL,
3392 ENDF,
3398 * bci_anchor
3400 * Handle the ANCHOR action to align two edges
3401 * and to set the edge anchor.
3403 * The code after computing `cur_len' to shift `edge' and `edge2'
3404 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3406 * if cur_len < 96:
3407 * if cur_len < = 64:
3408 * u_off = 32
3409 * d_off = 32
3410 * else:
3411 * u_off = 38
3412 * d_off = 26
3414 * org_center = edge_orig + org_len / 2
3415 * cur_pos1 = ROUND(org_center)
3417 * error1 = ABS(org_center - (cur_pos1 - u_off))
3418 * error2 = ABS(org_center - (cur_pos1 + d_off))
3419 * if (error1 < error2):
3420 * cur_pos1 = cur_pos1 - u_off
3421 * else:
3422 * cur_pos1 = cur_pos1 + d_off
3424 * edge = cur_pos1 - cur_len / 2
3425 * edge2 = edge + cur_len
3427 * else:
3428 * edge = ROUND(edge_orig)
3430 * in: edge2_is_serif
3431 * edge_is_round
3432 * edge_point (in twilight zone)
3433 * edge2_point (in twilight zone)
3434 * ... stuff for bci_align_segments (edge) ...
3436 * sal: sal_anchor
3437 * sal_temp1
3438 * sal_temp2
3439 * sal_temp3
3442 #undef sal_u_off
3443 #define sal_u_off sal_temp1
3444 #undef sal_d_off
3445 #define sal_d_off sal_temp2
3446 #undef sal_org_len
3447 #define sal_org_len sal_temp3
3449 unsigned char FPGM(bci_anchor) [] =
3452 PUSHB_1,
3453 bci_anchor,
3454 FDEF,
3456 /* store anchor point number in `sal_anchor' */
3457 PUSHB_2,
3458 sal_anchor,
3460 CINDEX,
3461 WS, /* sal_anchor = edge_point */
3463 PUSHB_1,
3465 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3467 PUSHB_1,
3469 CINDEX,
3470 PUSHB_1,
3472 CINDEX,
3473 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3474 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3476 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3477 DUP,
3478 PUSHB_1,
3479 sal_org_len,
3480 SWAP,
3483 PUSHB_1,
3484 cvtl_stem_width_function,
3485 RCVT,
3486 CALL, /* s: edge2 edge cur_len */
3488 DUP,
3489 PUSHB_1,
3491 LT, /* cur_len < 96 */
3493 DUP,
3494 PUSHB_1,
3496 LTEQ, /* cur_len <= 64 */
3498 PUSHB_4,
3499 sal_u_off,
3501 sal_d_off,
3504 ELSE,
3505 PUSHB_4,
3506 sal_u_off,
3508 sal_d_off,
3510 EIF,
3514 SWAP, /* s: edge2 cur_len edge */
3515 DUP, /* s: edge2 cur_len edge edge */
3517 GC_orig,
3518 PUSHB_1,
3519 sal_org_len,
3521 PUSHB_1,
3522 2*64,
3523 DIV,
3524 ADD, /* s: edge2 cur_len edge org_center */
3526 DUP,
3527 PUSHB_1,
3528 bci_round,
3529 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3531 DUP,
3532 ROLL,
3533 ROLL,
3534 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3536 DUP,
3537 PUSHB_1,
3538 sal_u_off,
3540 ADD,
3541 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3543 SWAP,
3544 PUSHB_1,
3545 sal_d_off,
3547 SUB,
3548 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3550 LT, /* error1 < error2 */
3552 PUSHB_1,
3553 sal_u_off,
3555 SUB, /* cur_pos1 = cur_pos1 - u_off */
3557 ELSE,
3558 PUSHB_1,
3559 sal_d_off,
3561 ADD, /* cur_pos1 = cur_pos1 + d_off */
3562 EIF, /* s: edge2 cur_len edge cur_pos1 */
3564 PUSHB_1,
3566 CINDEX,
3567 PUSHB_1,
3568 2*64,
3569 DIV,
3570 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3572 PUSHB_1,
3574 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3575 GC_cur,
3576 SUB,
3577 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3579 SWAP, /* s: cur_len edge2 */
3580 DUP,
3581 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3582 SWAP,
3583 SHPIX, /* edge2 = edge1 + cur_len */
3585 ELSE,
3586 POP, /* s: edge2 edge */
3587 DUP,
3588 DUP,
3589 GC_cur,
3590 SWAP,
3591 GC_orig,
3592 PUSHB_1,
3593 bci_round,
3594 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3595 SWAP,
3596 SUB,
3597 SHPIX, /* edge = round(edge_orig) */
3599 /* clean up stack */
3600 POP,
3601 EIF,
3603 PUSHB_2,
3604 bci_align_segments,
3606 SZP1, /* set zp1 to normal zone 1 */
3607 CALL,
3609 ENDF,
3615 * bci_action_anchor
3616 * bci_action_anchor_serif
3617 * bci_action_anchor_round
3618 * bci_action_anchor_round_serif
3620 * Higher-level routines for calling `bci_anchor'.
3623 unsigned char FPGM(bci_action_anchor) [] =
3626 PUSHB_1,
3627 bci_action_anchor,
3628 FDEF,
3630 PUSHB_3,
3633 bci_anchor,
3634 CALL,
3636 ENDF,
3640 unsigned char FPGM(bci_action_anchor_serif) [] =
3643 PUSHB_1,
3644 bci_action_anchor_serif,
3645 FDEF,
3647 PUSHB_3,
3650 bci_anchor,
3651 CALL,
3653 ENDF,
3657 unsigned char FPGM(bci_action_anchor_round) [] =
3660 PUSHB_1,
3661 bci_action_anchor_round,
3662 FDEF,
3664 PUSHB_3,
3667 bci_anchor,
3668 CALL,
3670 ENDF,
3674 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3677 PUSHB_1,
3678 bci_action_anchor_round_serif,
3679 FDEF,
3681 PUSHB_3,
3684 bci_anchor,
3685 CALL,
3687 ENDF,
3693 * bci_action_blue_anchor
3695 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3696 * and to set the edge anchor.
3698 * in: anchor_point (in twilight zone)
3699 * blue_cvt_idx
3700 * edge_point (in twilight zone)
3701 * ... stuff for bci_align_segments (edge) ...
3703 * sal: sal_anchor
3705 * uses: bci_action_blue
3708 unsigned char FPGM(bci_action_blue_anchor) [] =
3711 PUSHB_1,
3712 bci_action_blue_anchor,
3713 FDEF,
3715 /* store anchor point number in `sal_anchor' */
3716 PUSHB_1,
3717 sal_anchor,
3718 SWAP,
3721 PUSHB_1,
3722 bci_action_blue,
3723 CALL,
3725 ENDF,
3731 * bci_action_blue
3733 * Handle the BLUE action to align an edge with a blue zone.
3735 * in: blue_cvt_idx
3736 * edge_point (in twilight zone)
3737 * ... stuff for bci_align_segments (edge) ...
3740 unsigned char FPGM(bci_action_blue) [] =
3743 PUSHB_1,
3744 bci_action_blue,
3745 FDEF,
3747 PUSHB_1,
3749 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3751 /* move `edge_point' to `blue_cvt_idx' position; */
3752 /* note that we can't use MIAP since this would modify */
3753 /* the twilight point's original coordinates also */
3754 RCVT,
3755 SWAP,
3756 DUP,
3757 MDAP_noround, /* set rp0 and rp1 to `edge' */
3758 DUP,
3759 GC_cur, /* s: new_pos edge edge_pos */
3760 ROLL,
3761 SWAP,
3762 SUB, /* s: edge (new_pos - edge_pos) */
3763 SHPIX,
3765 PUSHB_2,
3766 bci_align_segments,
3768 SZP1, /* set zp1 to normal zone 1 */
3769 CALL,
3771 ENDF,
3777 * bci_serif_common
3779 * Common code for bci_action_serif routines.
3782 unsigned char FPGM(bci_serif_common) [] =
3785 PUSHB_1,
3786 bci_serif_common,
3787 FDEF,
3789 PUSHB_1,
3791 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3793 DUP,
3794 DUP,
3795 DUP,
3796 PUSHB_1,
3798 MINDEX, /* s: [...] serif serif serif serif base */
3799 DUP,
3800 MDAP_noround, /* set rp0 and rp1 to `base_point' */
3801 MD_orig_ZP2_0,
3802 SWAP,
3803 ALIGNRP, /* align `serif_point' with `base_point' */
3804 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
3806 ENDF,
3812 * bci_lower_bound
3814 * Move an edge if necessary to stay within a lower bound.
3816 * in: edge
3817 * bound
3820 unsigned char FPGM(bci_lower_bound) [] =
3823 PUSHB_1,
3824 bci_lower_bound,
3825 FDEF,
3827 SWAP, /* s: edge bound */
3828 DUP,
3829 MDAP_noround, /* set rp0 and rp1 to `bound' */
3830 GC_cur,
3831 PUSHB_1,
3833 CINDEX,
3834 GC_cur, /* s: edge bound_pos edge_pos */
3835 GT, /* edge_pos < bound_pos */
3837 DUP,
3838 ALIGNRP, /* align `edge' to `bound' */
3839 EIF,
3841 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3843 PUSHB_2,
3844 bci_align_segments,
3846 SZP1, /* set zp1 to normal zone 1 */
3847 CALL,
3849 ENDF,
3855 * bci_upper_bound
3857 * Move an edge if necessary to stay within an upper bound.
3859 * in: edge
3860 * bound
3863 unsigned char FPGM(bci_upper_bound) [] =
3866 PUSHB_1,
3867 bci_upper_bound,
3868 FDEF,
3870 SWAP, /* s: edge bound */
3871 DUP,
3872 MDAP_noround, /* set rp0 and rp1 to `bound' */
3873 GC_cur,
3874 PUSHB_1,
3876 CINDEX,
3877 GC_cur, /* s: edge bound_pos edge_pos */
3878 LT, /* edge_pos > bound_pos */
3880 DUP,
3881 ALIGNRP, /* align `edge' to `bound' */
3882 EIF,
3884 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3886 PUSHB_2,
3887 bci_align_segments,
3889 SZP1, /* set zp1 to normal zone 1 */
3890 CALL,
3892 ENDF,
3898 * bci_upper_lower_bound
3900 * Move an edge if necessary to stay within a lower and lower bound.
3902 * in: edge
3903 * lower
3904 * upper
3907 unsigned char FPGM(bci_upper_lower_bound) [] =
3910 PUSHB_1,
3911 bci_upper_lower_bound,
3912 FDEF,
3914 SWAP, /* s: upper serif lower */
3915 DUP,
3916 MDAP_noround, /* set rp0 and rp1 to `lower' */
3917 GC_cur,
3918 PUSHB_1,
3920 CINDEX,
3921 GC_cur, /* s: upper serif lower_pos serif_pos */
3922 GT, /* serif_pos < lower_pos */
3924 DUP,
3925 ALIGNRP, /* align `serif' to `lower' */
3926 EIF,
3928 SWAP, /* s: serif upper */
3929 DUP,
3930 MDAP_noround, /* set rp0 and rp1 to `upper' */
3931 GC_cur,
3932 PUSHB_1,
3934 CINDEX,
3935 GC_cur, /* s: serif upper_pos serif_pos */
3936 LT, /* serif_pos > upper_pos */
3938 DUP,
3939 ALIGNRP, /* align `serif' to `upper' */
3940 EIF,
3942 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
3944 PUSHB_2,
3945 bci_align_segments,
3947 SZP1, /* set zp1 to normal zone 1 */
3948 CALL,
3950 ENDF,
3956 * bci_action_serif
3958 * Handle the SERIF action to align a serif with its base.
3960 * in: serif_point (in twilight zone)
3961 * base_point (in twilight zone)
3962 * ... stuff for bci_align_segments (serif) ...
3964 * uses: bci_serif_common
3967 unsigned char FPGM(bci_action_serif) [] =
3970 PUSHB_1,
3971 bci_action_serif,
3972 FDEF,
3974 PUSHB_1,
3975 bci_serif_common,
3976 CALL,
3978 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
3980 PUSHB_2,
3981 bci_align_segments,
3983 SZP1, /* set zp1 to normal zone 1 */
3984 CALL,
3986 ENDF,
3992 * bci_action_serif_lower_bound
3994 * Handle the SERIF action to align a serif with its base, then moving it
3995 * again if necessary to stay within a lower bound.
3997 * in: serif_point (in twilight zone)
3998 * base_point (in twilight zone)
3999 * edge[-1] (in twilight zone)
4000 * ... stuff for bci_align_segments (serif) ...
4002 * uses: bci_serif_common
4003 * bci_lower_bound
4006 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4009 PUSHB_1,
4010 bci_action_serif_lower_bound,
4011 FDEF,
4013 PUSHB_1,
4014 bci_serif_common,
4015 CALL,
4017 PUSHB_1,
4018 bci_lower_bound,
4019 CALL,
4021 ENDF,
4027 * bci_action_serif_upper_bound
4029 * Handle the SERIF action to align a serif with its base, then moving it
4030 * again if necessary to stay within an upper bound.
4032 * in: serif_point (in twilight zone)
4033 * base_point (in twilight zone)
4034 * edge[1] (in twilight zone)
4035 * ... stuff for bci_align_segments (serif) ...
4037 * uses: bci_serif_common
4038 * bci_upper_bound
4041 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4044 PUSHB_1,
4045 bci_action_serif_upper_bound,
4046 FDEF,
4048 PUSHB_1,
4049 bci_serif_common,
4050 CALL,
4052 PUSHB_1,
4053 bci_upper_bound,
4054 CALL,
4056 ENDF,
4062 * bci_action_serif_upper_lower_bound
4064 * Handle the SERIF action to align a serif with its base, then moving it
4065 * again if necessary to stay within a lower and upper bound.
4067 * in: serif_point (in twilight zone)
4068 * base_point (in twilight zone)
4069 * edge[-1] (in twilight zone)
4070 * edge[1] (in twilight zone)
4071 * ... stuff for bci_align_segments (serif) ...
4073 * uses: bci_serif_common
4074 * bci_upper_lower_bound
4077 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4080 PUSHB_1,
4081 bci_action_serif_upper_lower_bound,
4082 FDEF,
4084 PUSHB_1,
4086 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4088 PUSHB_1,
4089 bci_serif_common,
4090 CALL,
4092 PUSHB_1,
4093 bci_upper_lower_bound,
4094 CALL,
4096 ENDF,
4102 * bci_serif_anchor_common
4104 * Common code for bci_action_serif_anchor routines.
4107 unsigned char FPGM(bci_serif_anchor_common) [] =
4110 PUSHB_1,
4111 bci_serif_anchor_common,
4112 FDEF,
4114 PUSHB_1,
4116 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4118 DUP,
4119 PUSHB_1,
4120 sal_anchor,
4121 SWAP,
4122 WS, /* sal_anchor = edge_point */
4124 DUP,
4125 DUP,
4126 DUP,
4127 GC_cur,
4128 SWAP,
4129 GC_orig,
4130 PUSHB_1,
4131 bci_round,
4132 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4133 SWAP,
4134 SUB,
4135 SHPIX, /* edge = round(edge_orig) */
4137 ENDF,
4143 * bci_action_serif_anchor
4145 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4146 * anchor.
4148 * in: edge_point (in twilight zone)
4149 * ... stuff for bci_align_segments (edge) ...
4151 * uses: bci_serif_anchor_common
4154 unsigned char FPGM(bci_action_serif_anchor) [] =
4157 PUSHB_1,
4158 bci_action_serif_anchor,
4159 FDEF,
4161 PUSHB_1,
4162 bci_serif_anchor_common,
4163 CALL,
4165 MDAP_noround, /* set rp0 and rp1 to `edge' */
4167 PUSHB_2,
4168 bci_align_segments,
4170 SZP1, /* set zp1 to normal zone 1 */
4171 CALL,
4173 ENDF,
4179 * bci_action_serif_anchor_lower_bound
4181 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4182 * anchor, then moving it again if necessary to stay within a lower
4183 * bound.
4185 * in: edge_point (in twilight zone)
4186 * edge[-1] (in twilight zone)
4187 * ... stuff for bci_align_segments (edge) ...
4189 * uses: bci_serif_anchor_common
4190 * bci_lower_bound
4193 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4196 PUSHB_1,
4197 bci_action_serif_anchor_lower_bound,
4198 FDEF,
4200 PUSHB_1,
4201 bci_serif_anchor_common,
4202 CALL,
4204 PUSHB_1,
4205 bci_lower_bound,
4206 CALL,
4208 ENDF,
4214 * bci_action_serif_anchor_upper_bound
4216 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4217 * anchor, then moving it again if necessary to stay within an upper
4218 * bound.
4220 * in: edge_point (in twilight zone)
4221 * edge[1] (in twilight zone)
4222 * ... stuff for bci_align_segments (edge) ...
4224 * uses: bci_serif_anchor_common
4225 * bci_upper_bound
4228 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4231 PUSHB_1,
4232 bci_action_serif_anchor_upper_bound,
4233 FDEF,
4235 PUSHB_1,
4236 bci_serif_anchor_common,
4237 CALL,
4239 PUSHB_1,
4240 bci_upper_bound,
4241 CALL,
4243 ENDF,
4249 * bci_action_serif_anchor_upper_lower_bound
4251 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4252 * anchor, then moving it again if necessary to stay within a lower and
4253 * upper bound.
4255 * in: edge_point (in twilight zone)
4256 * edge[-1] (in twilight zone)
4257 * edge[1] (in twilight zone)
4258 * ... stuff for bci_align_segments (edge) ...
4260 * uses: bci_serif_anchor_common
4261 * bci_upper_lower_bound
4264 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4267 PUSHB_1,
4268 bci_action_serif_anchor_upper_lower_bound,
4269 FDEF,
4271 PUSHB_1,
4272 bci_serif_anchor_common,
4273 CALL,
4275 PUSHB_1,
4276 bci_upper_lower_bound,
4277 CALL,
4279 ENDF,
4285 * bci_serif_link1_common
4287 * Common code for bci_action_serif_link1 routines.
4290 unsigned char FPGM(bci_serif_link1_common) [] =
4293 PUSHB_1,
4294 bci_serif_link1_common,
4295 FDEF,
4297 PUSHB_1,
4299 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4301 PUSHB_1,
4303 CINDEX, /* s: [...] after edge before after */
4304 PUSHB_1,
4306 CINDEX, /* s: [...] after edge before after before */
4307 MD_orig_ZP2_0,
4308 PUSHB_1,
4310 EQ, /* after_orig_pos == before_orig_pos */
4311 IF, /* s: [...] after edge before */
4312 MDAP_noround, /* set rp0 and rp1 to `before' */
4313 DUP,
4314 ALIGNRP, /* align `edge' with `before' */
4315 SWAP,
4316 POP,
4318 ELSE,
4319 /* we have to execute `a*b/c', with b/c very near to 1: */
4320 /* to avoid overflow while retaining precision, */
4321 /* we transform this to `a + a * (b-c)/c' */
4323 PUSHB_1,
4325 CINDEX, /* s: [...] after edge before edge */
4326 PUSHB_1,
4328 CINDEX, /* s: [...] after edge before edge before */
4329 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4331 DUP,
4332 PUSHB_1,
4334 CINDEX, /* s: [...] after edge before a a after */
4335 PUSHB_1,
4337 CINDEX, /* s: [...] after edge before a a after before */
4338 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4340 PUSHB_1,
4342 CINDEX, /* s: [...] after edge before a a c after */
4343 PUSHB_1,
4345 CINDEX, /* s: [...] after edge before a a c after before */
4346 MD_cur, /* b = after_pos - before_pos */
4348 PUSHB_1,
4350 CINDEX, /* s: [...] after edge before a a c b c */
4351 SUB, /* b-c */
4353 PUSHB_1,
4354 cvtl_0x10000,
4355 RCVT,
4356 MUL, /* (b-c) in 16.16 format */
4357 SWAP,
4358 DIV, /* s: [...] after edge before a a (b-c)/c */
4360 MUL, /* a * (b-c)/c * 2^10 */
4361 PUSHB_1,
4362 cvtl_0x10000,
4363 RCVT,
4364 DIV, /* a * (b-c)/c */
4365 ADD, /* a*b/c */
4367 SWAP,
4368 MDAP_noround, /* set rp0 and rp1 to `before' */
4369 SWAP, /* s: [...] after a*b/c edge */
4370 DUP,
4371 DUP,
4372 ALIGNRP, /* align `edge' with `before' */
4373 ROLL,
4374 SHPIX, /* shift `edge' by `a*b/c' */
4376 SWAP, /* s: [...] edge after */
4377 POP,
4378 EIF,
4380 ENDF,
4386 * bci_action_serif_link1
4388 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4389 * before and after.
4391 * in: before_point (in twilight zone)
4392 * edge_point (in twilight zone)
4393 * after_point (in twilight zone)
4394 * ... stuff for bci_align_segments (edge) ...
4396 * uses: bci_serif_link1_common
4399 unsigned char FPGM(bci_action_serif_link1) [] =
4402 PUSHB_1,
4403 bci_action_serif_link1,
4404 FDEF,
4406 PUSHB_1,
4407 bci_serif_link1_common,
4408 CALL,
4410 MDAP_noround, /* set rp0 and rp1 to `edge' */
4412 PUSHB_2,
4413 bci_align_segments,
4415 SZP1, /* set zp1 to normal zone 1 */
4416 CALL,
4418 ENDF,
4424 * bci_action_serif_link1_lower_bound
4426 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4427 * before and after. Additionally, move the serif again if necessary to
4428 * stay within a lower bound.
4430 * in: before_point (in twilight zone)
4431 * edge_point (in twilight zone)
4432 * after_point (in twilight zone)
4433 * edge[-1] (in twilight zone)
4434 * ... stuff for bci_align_segments (edge) ...
4436 * uses: bci_serif_link1_common
4437 * bci_lower_bound
4440 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4443 PUSHB_1,
4444 bci_action_serif_link1_lower_bound,
4445 FDEF,
4447 PUSHB_1,
4448 bci_serif_link1_common,
4449 CALL,
4451 PUSHB_1,
4452 bci_lower_bound,
4453 CALL,
4455 ENDF,
4461 * bci_action_serif_link1_upper_bound
4463 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4464 * before and after. Additionally, move the serif again if necessary to
4465 * stay within an upper bound.
4467 * in: before_point (in twilight zone)
4468 * edge_point (in twilight zone)
4469 * after_point (in twilight zone)
4470 * edge[1] (in twilight zone)
4471 * ... stuff for bci_align_segments (edge) ...
4473 * uses: bci_serif_link1_common
4474 * bci_upper_bound
4477 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4480 PUSHB_1,
4481 bci_action_serif_link1_upper_bound,
4482 FDEF,
4484 PUSHB_1,
4485 bci_serif_link1_common,
4486 CALL,
4488 PUSHB_1,
4489 bci_upper_bound,
4490 CALL,
4492 ENDF,
4498 * bci_action_serif_link1_upper_lower_bound
4500 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4501 * before and after. Additionally, move the serif again if necessary to
4502 * stay within a lower and upper bound.
4504 * in: before_point (in twilight zone)
4505 * edge_point (in twilight zone)
4506 * after_point (in twilight zone)
4507 * edge[-1] (in twilight zone)
4508 * edge[1] (in twilight zone)
4509 * ... stuff for bci_align_segments (edge) ...
4511 * uses: bci_serif_link1_common
4512 * bci_upper_lower_bound
4515 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
4518 PUSHB_1,
4519 bci_action_serif_link1_upper_lower_bound,
4520 FDEF,
4522 PUSHB_1,
4523 bci_serif_link1_common,
4524 CALL,
4526 PUSHB_1,
4527 bci_upper_lower_bound,
4528 CALL,
4530 ENDF,
4536 * bci_serif_link2_common
4538 * Common code for bci_action_serif_link2 routines.
4541 unsigned char FPGM(bci_serif_link2_common) [] =
4544 PUSHB_1,
4545 bci_serif_link2_common,
4546 FDEF,
4548 PUSHB_1,
4550 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4552 DUP, /* s: [...] edge edge */
4553 PUSHB_1,
4554 sal_anchor,
4556 DUP, /* s: [...] edge edge anchor anchor */
4557 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4559 MD_orig_ZP2_0,
4560 DUP,
4561 ADD,
4562 PUSHB_1,
4564 ADD,
4565 FLOOR,
4566 PUSHB_1,
4567 2*64,
4568 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4570 SWAP,
4571 DUP,
4572 DUP,
4573 ALIGNRP, /* align `edge' with `sal_anchor' */
4574 ROLL,
4575 SHPIX, /* shift `edge' by `delta' */
4577 ENDF,
4583 * bci_action_serif_link2
4585 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4587 * in: edge_point (in twilight zone)
4588 * ... stuff for bci_align_segments (edge) ...
4590 * uses: bci_serif_link2_common
4593 unsigned char FPGM(bci_action_serif_link2) [] =
4596 PUSHB_1,
4597 bci_action_serif_link2,
4598 FDEF,
4600 PUSHB_1,
4601 bci_serif_link2_common,
4602 CALL,
4604 MDAP_noround, /* set rp0 and rp1 to `edge' */
4606 PUSHB_2,
4607 bci_align_segments,
4609 SZP1, /* set zp1 to normal zone 1 */
4610 CALL,
4612 ENDF,
4618 * bci_action_serif_link2_lower_bound
4620 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4621 * Additionally, move the serif again if necessary to stay within a lower
4622 * bound.
4624 * in: edge_point (in twilight zone)
4625 * edge[-1] (in twilight zone)
4626 * ... stuff for bci_align_segments (edge) ...
4628 * uses: bci_serif_link2_common
4629 * bci_lower_bound
4632 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4635 PUSHB_1,
4636 bci_action_serif_link2_lower_bound,
4637 FDEF,
4639 PUSHB_1,
4640 bci_serif_link2_common,
4641 CALL,
4643 PUSHB_1,
4644 bci_lower_bound,
4645 CALL,
4647 ENDF,
4653 * bci_action_serif_link2_upper_bound
4655 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4656 * Additionally, move the serif again if necessary to stay within an upper
4657 * bound.
4659 * in: edge_point (in twilight zone)
4660 * edge[1] (in twilight zone)
4661 * ... stuff for bci_align_segments (edge) ...
4663 * uses: bci_serif_link2_common
4664 * bci_upper_bound
4667 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4670 PUSHB_1,
4671 bci_action_serif_link2_upper_bound,
4672 FDEF,
4674 PUSHB_1,
4675 bci_serif_link2_common,
4676 CALL,
4678 PUSHB_1,
4679 bci_upper_bound,
4680 CALL,
4682 ENDF,
4688 * bci_action_serif_link2_upper_lower_bound
4690 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4691 * Additionally, move the serif again if necessary to stay within a lower
4692 * and upper bound.
4694 * in: edge_point (in twilight zone)
4695 * edge[-1] (in twilight zone)
4696 * edge[1] (in twilight zone)
4697 * ... stuff for bci_align_segments (edge) ...
4699 * uses: bci_serif_link2_common
4700 * bci_upper_lower_bound
4703 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
4706 PUSHB_1,
4707 bci_action_serif_link2_upper_lower_bound,
4708 FDEF,
4710 PUSHB_1,
4711 bci_serif_link2_common,
4712 CALL,
4714 PUSHB_1,
4715 bci_upper_lower_bound,
4716 CALL,
4718 ENDF,
4724 * bci_hint_glyph
4726 * This is the top-level glyph hinting function which parses the arguments
4727 * on the stack and calls subroutines.
4729 * in: action_0_func_idx
4730 * ... data ...
4731 * action_1_func_idx
4732 * ... data ...
4733 * ...
4735 * uses: bci_action_ip_before
4736 * bci_action_ip_after
4737 * bci_action_ip_on
4738 * bci_action_ip_between
4740 * bci_action_adjust_bound
4741 * bci_action_adjust_bound_serif
4742 * bci_action_adjust_bound_round
4743 * bci_action_adjust_bound_round_serif
4745 * bci_action_stem_bound
4746 * bci_action_stem_bound_serif
4747 * bci_action_stem_bound_round
4748 * bci_action_stem_bound_round_serif
4750 * bci_action_link
4751 * bci_action_link_serif
4752 * bci_action_link_round
4753 * bci_action_link_round_serif
4755 * bci_action_anchor
4756 * bci_action_anchor_serif
4757 * bci_action_anchor_round
4758 * bci_action_anchor_round_serif
4760 * bci_action_blue_anchor
4762 * bci_action_adjust
4763 * bci_action_adjust_serif
4764 * bci_action_adjust_round
4765 * bci_action_adjust_round_serif
4767 * bci_action_stem
4768 * bci_action_stem_serif
4769 * bci_action_stem_round
4770 * bci_action_stem_round_serif
4772 * bci_action_blue
4774 * bci_action_serif
4775 * bci_action_serif_lower_bound
4776 * bci_action_serif_upper_bound
4777 * bci_action_serif_upper_lower_bound
4779 * bci_action_serif_anchor
4780 * bci_action_serif_anchor_lower_bound
4781 * bci_action_serif_anchor_upper_bound
4782 * bci_action_serif_anchor_upper_lower_bound
4784 * bci_action_serif_link1
4785 * bci_action_serif_link1_lower_bound
4786 * bci_action_serif_link1_upper_bound
4787 * bci_action_serif_link1_upper_lower_bound
4789 * bci_action_serif_link2
4790 * bci_action_serif_link2_lower_bound
4791 * bci_action_serif_link2_upper_bound
4792 * bci_action_serif_link2_upper_lower_bound
4794 * CVT: cvtl_is_subglyph
4797 unsigned char FPGM(bci_hint_glyph) [] =
4800 PUSHB_1,
4801 bci_hint_glyph,
4802 FDEF,
4804 /* start_loop: */
4805 /* loop until all data on stack is used */
4806 CALL,
4807 PUSHB_1,
4809 NEG,
4810 PUSHB_1,
4812 DEPTH,
4814 JROT, /* goto start_loop */
4816 PUSHB_1,
4818 SZP2, /* set zp2 to normal zone 1 */
4819 IUP_y,
4821 ENDF,
4826 #define COPY_FPGM(func_name) \
4827 memcpy(buf_p, fpgm_ ## func_name, \
4828 sizeof (fpgm_ ## func_name)); \
4829 buf_p += sizeof (fpgm_ ## func_name) \
4831 static FT_Error
4832 TA_table_build_fpgm(FT_Byte** fpgm,
4833 FT_ULong* fpgm_len,
4834 FONT* font)
4836 FT_UInt buf_len;
4837 FT_UInt len;
4838 FT_Byte* buf;
4839 FT_Byte* buf_p;
4842 buf_len = sizeof (FPGM(bci_round))
4843 + sizeof (FPGM(bci_smooth_stem_width_a))
4845 + sizeof (FPGM(bci_smooth_stem_width_b))
4847 + sizeof (FPGM(bci_smooth_stem_width_c))
4848 + sizeof (FPGM(bci_get_best_width))
4849 + sizeof (FPGM(bci_strong_stem_width_a))
4851 + sizeof (FPGM(bci_strong_stem_width_b))
4852 + sizeof (FPGM(bci_loop))
4853 + sizeof (FPGM(bci_cvt_rescale))
4854 + sizeof (FPGM(bci_blue_round_a))
4856 + sizeof (FPGM(bci_blue_round_b))
4857 + sizeof (FPGM(bci_decrement_component_counter))
4858 + sizeof (FPGM(bci_get_point_extrema))
4859 + sizeof (FPGM(bci_nibbles))
4861 + sizeof (FPGM(bci_create_segment))
4862 + sizeof (FPGM(bci_create_segments))
4863 + sizeof (FPGM(bci_create_segments_0))
4864 + sizeof (FPGM(bci_create_segments_1))
4865 + sizeof (FPGM(bci_create_segments_2))
4866 + sizeof (FPGM(bci_create_segments_3))
4867 + sizeof (FPGM(bci_create_segments_4))
4868 + sizeof (FPGM(bci_create_segments_5))
4869 + sizeof (FPGM(bci_create_segments_6))
4870 + sizeof (FPGM(bci_create_segments_7))
4871 + sizeof (FPGM(bci_create_segments_8))
4872 + sizeof (FPGM(bci_create_segments_9))
4873 + sizeof (FPGM(bci_create_segments_composite))
4874 + sizeof (FPGM(bci_create_segments_composite_0))
4875 + sizeof (FPGM(bci_create_segments_composite_1))
4876 + sizeof (FPGM(bci_create_segments_composite_2))
4877 + sizeof (FPGM(bci_create_segments_composite_3))
4878 + sizeof (FPGM(bci_create_segments_composite_4))
4879 + sizeof (FPGM(bci_create_segments_composite_5))
4880 + sizeof (FPGM(bci_create_segments_composite_6))
4881 + sizeof (FPGM(bci_create_segments_composite_7))
4882 + sizeof (FPGM(bci_create_segments_composite_8))
4883 + sizeof (FPGM(bci_create_segments_composite_9))
4884 + sizeof (FPGM(bci_align_segment))
4885 + sizeof (FPGM(bci_align_segments))
4887 + sizeof (FPGM(bci_scale_contour))
4888 + sizeof (FPGM(bci_scale_glyph))
4889 + sizeof (FPGM(bci_scale_composite_glyph))
4890 + sizeof (FPGM(bci_shift_contour))
4891 + sizeof (FPGM(bci_shift_subglyph))
4893 + sizeof (FPGM(bci_ip_outer_align_point))
4894 + sizeof (FPGM(bci_ip_on_align_points))
4895 + sizeof (FPGM(bci_ip_between_align_point))
4896 + sizeof (FPGM(bci_ip_between_align_points))
4898 + sizeof (FPGM(bci_adjust_common))
4899 + sizeof (FPGM(bci_stem_common))
4900 + sizeof (FPGM(bci_serif_common))
4901 + sizeof (FPGM(bci_serif_anchor_common))
4902 + sizeof (FPGM(bci_serif_link1_common))
4903 + sizeof (FPGM(bci_serif_link2_common))
4905 + sizeof (FPGM(bci_lower_bound))
4906 + sizeof (FPGM(bci_upper_bound))
4907 + sizeof (FPGM(bci_upper_lower_bound))
4909 + sizeof (FPGM(bci_action_ip_before))
4910 + sizeof (FPGM(bci_action_ip_after))
4911 + sizeof (FPGM(bci_action_ip_on))
4912 + sizeof (FPGM(bci_action_ip_between))
4914 + sizeof (FPGM(bci_adjust_bound))
4915 + sizeof (FPGM(bci_action_adjust_bound))
4916 + sizeof (FPGM(bci_action_adjust_bound_serif))
4917 + sizeof (FPGM(bci_action_adjust_bound_round))
4918 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
4919 + sizeof (FPGM(bci_stem_bound))
4920 + sizeof (FPGM(bci_action_stem_bound))
4921 + sizeof (FPGM(bci_action_stem_bound_serif))
4922 + sizeof (FPGM(bci_action_stem_bound_round))
4923 + sizeof (FPGM(bci_action_stem_bound_round_serif))
4924 + sizeof (FPGM(bci_link))
4925 + sizeof (FPGM(bci_action_link))
4926 + sizeof (FPGM(bci_action_link_serif))
4927 + sizeof (FPGM(bci_action_link_round))
4928 + sizeof (FPGM(bci_action_link_round_serif))
4929 + sizeof (FPGM(bci_anchor))
4930 + sizeof (FPGM(bci_action_anchor))
4931 + sizeof (FPGM(bci_action_anchor_serif))
4932 + sizeof (FPGM(bci_action_anchor_round))
4933 + sizeof (FPGM(bci_action_anchor_round_serif))
4934 + sizeof (FPGM(bci_action_blue_anchor))
4935 + sizeof (FPGM(bci_adjust))
4936 + sizeof (FPGM(bci_action_adjust))
4937 + sizeof (FPGM(bci_action_adjust_serif))
4938 + sizeof (FPGM(bci_action_adjust_round))
4939 + sizeof (FPGM(bci_action_adjust_round_serif))
4940 + sizeof (FPGM(bci_stem))
4941 + sizeof (FPGM(bci_action_stem))
4942 + sizeof (FPGM(bci_action_stem_serif))
4943 + sizeof (FPGM(bci_action_stem_round))
4944 + sizeof (FPGM(bci_action_stem_round_serif))
4945 + sizeof (FPGM(bci_action_blue))
4946 + sizeof (FPGM(bci_action_serif))
4947 + sizeof (FPGM(bci_action_serif_lower_bound))
4948 + sizeof (FPGM(bci_action_serif_upper_bound))
4949 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
4950 + sizeof (FPGM(bci_action_serif_anchor))
4951 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
4952 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
4953 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
4954 + sizeof (FPGM(bci_action_serif_link1))
4955 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
4956 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
4957 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
4958 + sizeof (FPGM(bci_action_serif_link2))
4959 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
4960 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
4961 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
4963 + sizeof (FPGM(bci_hint_glyph));
4965 /* buffer length must be a multiple of four */
4966 len = (buf_len + 3) & ~3;
4967 buf = (FT_Byte*)malloc(len);
4968 if (!buf)
4969 return FT_Err_Out_Of_Memory;
4971 /* pad end of buffer with zeros */
4972 buf[len - 1] = 0x00;
4973 buf[len - 2] = 0x00;
4974 buf[len - 3] = 0x00;
4976 /* copy font program into buffer and fill in the missing variables */
4977 buf_p = buf;
4979 COPY_FPGM(bci_round);
4980 COPY_FPGM(bci_smooth_stem_width_a);
4981 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4982 COPY_FPGM(bci_smooth_stem_width_b);
4983 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4984 COPY_FPGM(bci_smooth_stem_width_c);
4985 COPY_FPGM(bci_get_best_width);
4986 COPY_FPGM(bci_strong_stem_width_a);
4987 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4988 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font);
4989 COPY_FPGM(bci_strong_stem_width_b);
4990 COPY_FPGM(bci_loop);
4991 COPY_FPGM(bci_cvt_rescale);
4992 COPY_FPGM(bci_blue_round_a);
4993 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
4994 COPY_FPGM(bci_blue_round_b);
4995 COPY_FPGM(bci_decrement_component_counter);
4996 COPY_FPGM(bci_get_point_extrema);
4997 COPY_FPGM(bci_nibbles);
4999 COPY_FPGM(bci_create_segment);
5000 COPY_FPGM(bci_create_segments);
5001 COPY_FPGM(bci_create_segments_0);
5002 COPY_FPGM(bci_create_segments_1);
5003 COPY_FPGM(bci_create_segments_2);
5004 COPY_FPGM(bci_create_segments_3);
5005 COPY_FPGM(bci_create_segments_4);
5006 COPY_FPGM(bci_create_segments_5);
5007 COPY_FPGM(bci_create_segments_6);
5008 COPY_FPGM(bci_create_segments_7);
5009 COPY_FPGM(bci_create_segments_8);
5010 COPY_FPGM(bci_create_segments_9);
5011 COPY_FPGM(bci_create_segments_composite);
5012 COPY_FPGM(bci_create_segments_composite_0);
5013 COPY_FPGM(bci_create_segments_composite_1);
5014 COPY_FPGM(bci_create_segments_composite_2);
5015 COPY_FPGM(bci_create_segments_composite_3);
5016 COPY_FPGM(bci_create_segments_composite_4);
5017 COPY_FPGM(bci_create_segments_composite_5);
5018 COPY_FPGM(bci_create_segments_composite_6);
5019 COPY_FPGM(bci_create_segments_composite_7);
5020 COPY_FPGM(bci_create_segments_composite_8);
5021 COPY_FPGM(bci_create_segments_composite_9);
5022 COPY_FPGM(bci_align_segment);
5023 COPY_FPGM(bci_align_segments);
5025 COPY_FPGM(bci_scale_contour);
5026 COPY_FPGM(bci_scale_glyph);
5027 COPY_FPGM(bci_scale_composite_glyph);
5028 COPY_FPGM(bci_shift_contour);
5029 COPY_FPGM(bci_shift_subglyph);
5031 COPY_FPGM(bci_ip_outer_align_point);
5032 COPY_FPGM(bci_ip_on_align_points);
5033 COPY_FPGM(bci_ip_between_align_point);
5034 COPY_FPGM(bci_ip_between_align_points);
5036 COPY_FPGM(bci_adjust_common);
5037 COPY_FPGM(bci_stem_common);
5038 COPY_FPGM(bci_serif_common);
5039 COPY_FPGM(bci_serif_anchor_common);
5040 COPY_FPGM(bci_serif_link1_common);
5041 COPY_FPGM(bci_serif_link2_common);
5043 COPY_FPGM(bci_lower_bound);
5044 COPY_FPGM(bci_upper_bound);
5045 COPY_FPGM(bci_upper_lower_bound);
5047 COPY_FPGM(bci_action_ip_before);
5048 COPY_FPGM(bci_action_ip_after);
5049 COPY_FPGM(bci_action_ip_on);
5050 COPY_FPGM(bci_action_ip_between);
5052 COPY_FPGM(bci_adjust_bound);
5053 COPY_FPGM(bci_action_adjust_bound);
5054 COPY_FPGM(bci_action_adjust_bound_serif);
5055 COPY_FPGM(bci_action_adjust_bound_round);
5056 COPY_FPGM(bci_action_adjust_bound_round_serif);
5057 COPY_FPGM(bci_stem_bound);
5058 COPY_FPGM(bci_action_stem_bound);
5059 COPY_FPGM(bci_action_stem_bound_serif);
5060 COPY_FPGM(bci_action_stem_bound_round);
5061 COPY_FPGM(bci_action_stem_bound_round_serif);
5062 COPY_FPGM(bci_link);
5063 COPY_FPGM(bci_action_link);
5064 COPY_FPGM(bci_action_link_serif);
5065 COPY_FPGM(bci_action_link_round);
5066 COPY_FPGM(bci_action_link_round_serif);
5067 COPY_FPGM(bci_anchor);
5068 COPY_FPGM(bci_action_anchor);
5069 COPY_FPGM(bci_action_anchor_serif);
5070 COPY_FPGM(bci_action_anchor_round);
5071 COPY_FPGM(bci_action_anchor_round_serif);
5072 COPY_FPGM(bci_action_blue_anchor);
5073 COPY_FPGM(bci_adjust);
5074 COPY_FPGM(bci_action_adjust);
5075 COPY_FPGM(bci_action_adjust_serif);
5076 COPY_FPGM(bci_action_adjust_round);
5077 COPY_FPGM(bci_action_adjust_round_serif);
5078 COPY_FPGM(bci_stem);
5079 COPY_FPGM(bci_action_stem);
5080 COPY_FPGM(bci_action_stem_serif);
5081 COPY_FPGM(bci_action_stem_round);
5082 COPY_FPGM(bci_action_stem_round_serif);
5083 COPY_FPGM(bci_action_blue);
5084 COPY_FPGM(bci_action_serif);
5085 COPY_FPGM(bci_action_serif_lower_bound);
5086 COPY_FPGM(bci_action_serif_upper_bound);
5087 COPY_FPGM(bci_action_serif_upper_lower_bound);
5088 COPY_FPGM(bci_action_serif_anchor);
5089 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5090 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5091 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5092 COPY_FPGM(bci_action_serif_link1);
5093 COPY_FPGM(bci_action_serif_link1_lower_bound);
5094 COPY_FPGM(bci_action_serif_link1_upper_bound);
5095 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5096 COPY_FPGM(bci_action_serif_link2);
5097 COPY_FPGM(bci_action_serif_link2_lower_bound);
5098 COPY_FPGM(bci_action_serif_link2_upper_bound);
5099 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5101 COPY_FPGM(bci_hint_glyph);
5103 *fpgm = buf;
5104 *fpgm_len = buf_len;
5106 return FT_Err_Ok;
5110 FT_Error
5111 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5112 FONT* font)
5114 FT_Error error;
5116 FT_Byte* fpgm_buf;
5117 FT_ULong fpgm_len;
5120 error = TA_sfnt_add_table_info(sfnt);
5121 if (error)
5122 return error;
5124 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
5125 if (error)
5126 return error;
5128 if (fpgm_len > sfnt->max_instructions)
5129 sfnt->max_instructions = fpgm_len;
5131 /* in case of success, `fpgm_buf' gets linked */
5132 /* and is eventually freed in `TA_font_unload' */
5133 error = TA_font_add_table(font,
5134 &sfnt->table_infos[sfnt->num_table_infos - 1],
5135 TTAG_fpgm, fpgm_len, fpgm_buf);
5136 if (error)
5138 free(fpgm_buf);
5139 return error;
5142 return FT_Err_Ok;
5145 /* end of tafpgm.c */