Add NUMBERSET_NOT_ASCENDING error code.
[ttfautohint.git] / lib / tafpgm.c
blobcdd96caf5c5c5a62d54cc5bce32f359581aab0f9
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_number_set_is_element
872 * Pop values from stack until it is empty. If one of them is equal to
873 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
874 * otherwise).
876 * in: ppem_value_1
877 * ppem_value_2
878 * ...
880 * CVT: cvtl_is_element
883 unsigned char FPGM(bci_number_set_is_element) [] =
886 PUSHB_1,
887 bci_number_set_is_element,
888 FDEF,
890 PUSHB_2,
891 cvtl_is_element,
893 WCVTP,
895 /* start_loop: */
896 MPPEM,
899 PUSHB_2,
900 cvtl_is_element,
902 WCVTP,
903 EIF,
905 PUSHB_1,
907 NEG,
908 DEPTH,
909 JROT, /* goto start_loop if stack depth != 0 */
911 ENDF,
917 * bci_number_set_is_element2
919 * Pop value ranges from stack until it is empty. If one of them contains
920 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
921 * otherwise).
923 * in: ppem_range_1_start
924 * ppem_range_1_end
925 * ppem_range_2_start
926 * ppem_range_2_end
927 * ...
929 * CVT: cvtl_is_element
932 unsigned char FPGM(bci_number_set_is_element2) [] =
935 PUSHB_1,
936 bci_number_set_is_element2,
937 FDEF,
939 PUSHB_2,
940 cvtl_is_element,
942 WCVTP,
944 /* start_loop: */
945 MPPEM,
946 LTEQ,
948 MPPEM,
949 GTEQ,
951 PUSHB_2,
952 cvtl_is_element,
954 WCVTP,
955 EIF,
956 ELSE,
957 POP,
958 EIF,
960 PUSHB_1,
962 NEG,
963 DEPTH,
964 JROT, /* goto start_loop if stack depth != 0 */
966 ENDF,
972 * bci_create_segment
974 * Store start and end point of a segment in the storage area,
975 * then construct a point in the twilight zone to represent it.
977 * This function is used by `bci_create_segment_points'.
979 * in: start
980 * end
981 * [last (if wrap-around segment)]
982 * [first (if wrap-around segment)]
984 * uses: bci_get_point_extrema
985 * bci_nibbles
987 * sal: sal_i (start of current segment)
988 * sal_j (current twilight point)
989 * sal_point_min
990 * sal_point_max
991 * sal_base
992 * sal_num_packed_segments
994 * CVT: cvtl_scale
995 * cvtl_0x10000
996 * cvtl_temp
998 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
999 * delta values in nibbles (without a wrap-around segment).
1002 unsigned char FPGM(bci_create_segment) [] =
1005 PUSHB_1,
1006 bci_create_segment,
1007 FDEF,
1009 PUSHB_2,
1011 sal_num_packed_segments,
1013 NEQ,
1015 PUSHB_2,
1016 sal_num_packed_segments,
1017 sal_num_packed_segments,
1019 PUSHB_1,
1021 SUB,
1022 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1024 PUSHB_1,
1025 bci_nibbles,
1026 CALL,
1027 EIF,
1029 PUSHB_1,
1030 sal_i,
1032 PUSHB_1,
1034 CINDEX,
1035 WS, /* sal[sal_i] = start */
1037 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
1038 PUSHB_3,
1039 sal_i,
1041 sal_i,
1043 ADD, /* sal_i = sal_i + 1 */
1046 /* initialize inner loop(s) */
1047 PUSHB_2,
1048 sal_point_min,
1050 CINDEX,
1051 WS, /* sal_point_min = start */
1052 PUSHB_2,
1053 sal_point_max,
1055 CINDEX,
1056 WS, /* sal_point_max = start */
1058 PUSHB_1,
1060 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1062 SWAP,
1063 DUP,
1064 PUSHB_1,
1066 CINDEX, /* s: start end end start */
1067 LT, /* start > end */
1069 /* we have a wrap-around segment with two more arguments */
1070 /* to give the last and first point of the contour, respectively; */
1071 /* our job is to store a segment `start'-`last', */
1072 /* and to get extrema for the two segments */
1073 /* `start'-`last' and `first'-`end' */
1075 /* s: first last start end */
1076 PUSHB_1,
1077 sal_i,
1079 PUSHB_1,
1081 CINDEX,
1082 WS, /* sal[sal_i] = last */
1084 ROLL,
1085 ROLL, /* s: first end last start */
1086 DUP,
1087 ROLL,
1088 SWAP, /* s: first end start last start */
1089 SUB, /* s: first end start loop_count */
1091 PUSHB_1,
1092 bci_get_point_extrema,
1093 LOOPCALL,
1094 /* clean up stack */
1095 POP,
1097 SWAP, /* s: end first */
1098 PUSHB_1,
1100 SUB,
1101 DUP,
1102 ROLL, /* s: (first - 1) (first - 1) end */
1103 SWAP,
1104 SUB, /* s: (first - 1) loop_count */
1106 PUSHB_1,
1107 bci_get_point_extrema,
1108 LOOPCALL,
1109 /* clean up stack */
1110 POP,
1112 ELSE, /* s: start end */
1113 PUSHB_1,
1114 sal_i,
1116 PUSHB_1,
1118 CINDEX,
1119 WS, /* sal[sal_i] = end */
1121 PUSHB_1,
1123 CINDEX,
1124 SUB, /* s: start loop_count */
1126 PUSHB_1,
1127 bci_get_point_extrema,
1128 LOOPCALL,
1129 /* clean up stack */
1130 POP,
1131 EIF,
1133 /* the twilight point representing a segment */
1134 /* is in the middle between the minimum and maximum */
1135 PUSHB_1,
1136 sal_point_min,
1138 GC_orig,
1139 PUSHB_1,
1140 sal_point_max,
1142 GC_orig,
1143 ADD,
1144 PUSHB_1,
1145 2*64,
1146 DIV, /* s: middle_pos */
1148 DO_SCALE, /* middle_pos = middle_pos * scale */
1150 /* write it to temporary CVT location */
1151 PUSHB_2,
1152 cvtl_temp,
1154 SZP0, /* set zp0 to twilight zone 0 */
1155 SWAP,
1156 WCVTP,
1158 /* create twilight point with index `sal_j' */
1159 PUSHB_1,
1160 sal_j,
1162 PUSHB_1,
1163 cvtl_temp,
1164 MIAP_noround,
1166 PUSHB_3,
1167 sal_j,
1169 sal_j,
1171 ADD, /* twilight_point = twilight_point + 1 */
1174 ENDF,
1180 * bci_create_segments
1182 * This is the top-level entry function.
1184 * It pops point ranges from the stack to define segments, computes
1185 * twilight points to represent segments, and finally calls
1186 * `bci_hint_glyph' to handle the rest.
1188 * in: num_packed_segments
1189 * num_segments (N)
1190 * segment_start_0
1191 * segment_end_0
1192 * [contour_last 0 (if wrap-around segment)]
1193 * [contour_first 0 (if wrap-around segment)]
1194 * segment_start_1
1195 * segment_end_1
1196 * [contour_last 0 (if wrap-around segment)]
1197 * [contour_first 0 (if wrap-around segment)]
1198 * ...
1199 * segment_start_(N-1)
1200 * segment_end_(N-1)
1201 * [contour_last (N-1) (if wrap-around segment)]
1202 * [contour_first (N-1) (if wrap-around segment)]
1203 * ... stuff for bci_hint_glyph ...
1205 * uses: bci_create_segment
1207 * sal: sal_i (start of current segment)
1208 * sal_j (current twilight point)
1209 * sal_num_packed_segments
1210 * sal_base (the base for delta values in nibbles)
1212 * CVT: cvtl_is_subglyph
1214 * If `num_packed_segments' is set to p, the first p start/end pairs are
1215 * stored as delta values in nibbles, with the `start' delta in the lower
1216 * nibble (and there are no wrap-around segments). For example, if the
1217 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1218 * stack are 0x21, 0x32, and 0x14.
1222 unsigned char FPGM(bci_create_segments) [] =
1225 PUSHB_1,
1226 bci_create_segments,
1227 FDEF,
1229 /* only do something if we are not a subglyph */
1230 PUSHB_2,
1232 cvtl_is_subglyph,
1233 RCVT,
1236 /* all our measurements are taken along the y axis */
1237 SVTCA_y,
1239 PUSHB_1,
1240 sal_num_packed_segments,
1241 SWAP,
1244 DUP,
1245 ADD,
1246 PUSHB_1,
1248 SUB, /* delta = (2*num_segments - 1) */
1250 PUSHB_6,
1251 sal_segment_offset,
1252 sal_segment_offset,
1254 sal_j,
1256 sal_base,
1258 WS, /* sal_base = 0 */
1259 WS, /* sal_j = 0 (point offset) */
1261 ROLL,
1262 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1264 /* `bci_create_segment_point' also increases the loop counter by 1; */
1265 /* this effectively means we have a loop step of 2 */
1266 PUSHB_2,
1267 bci_create_segment,
1268 bci_loop,
1269 CALL,
1271 PUSHB_1,
1272 bci_hint_glyph,
1273 CALL,
1275 ELSE,
1276 CLEAR,
1277 EIF,
1279 ENDF,
1285 * bci_create_segments_X
1287 * Top-level routines for calling `bci_create_segments'.
1290 unsigned char FPGM(bci_create_segments_0) [] =
1293 PUSHB_1,
1294 bci_create_segments_0,
1295 FDEF,
1297 PUSHB_2,
1299 bci_create_segments,
1300 CALL,
1302 ENDF,
1306 unsigned char FPGM(bci_create_segments_1) [] =
1309 PUSHB_1,
1310 bci_create_segments_1,
1311 FDEF,
1313 PUSHB_2,
1315 bci_create_segments,
1316 CALL,
1318 ENDF,
1322 unsigned char FPGM(bci_create_segments_2) [] =
1325 PUSHB_1,
1326 bci_create_segments_2,
1327 FDEF,
1329 PUSHB_2,
1331 bci_create_segments,
1332 CALL,
1334 ENDF,
1338 unsigned char FPGM(bci_create_segments_3) [] =
1341 PUSHB_1,
1342 bci_create_segments_3,
1343 FDEF,
1345 PUSHB_2,
1347 bci_create_segments,
1348 CALL,
1350 ENDF,
1354 unsigned char FPGM(bci_create_segments_4) [] =
1357 PUSHB_1,
1358 bci_create_segments_4,
1359 FDEF,
1361 PUSHB_2,
1363 bci_create_segments,
1364 CALL,
1366 ENDF,
1370 unsigned char FPGM(bci_create_segments_5) [] =
1373 PUSHB_1,
1374 bci_create_segments_5,
1375 FDEF,
1377 PUSHB_2,
1379 bci_create_segments,
1380 CALL,
1382 ENDF,
1386 unsigned char FPGM(bci_create_segments_6) [] =
1389 PUSHB_1,
1390 bci_create_segments_6,
1391 FDEF,
1393 PUSHB_2,
1395 bci_create_segments,
1396 CALL,
1398 ENDF,
1402 unsigned char FPGM(bci_create_segments_7) [] =
1405 PUSHB_1,
1406 bci_create_segments_7,
1407 FDEF,
1409 PUSHB_2,
1411 bci_create_segments,
1412 CALL,
1414 ENDF,
1418 unsigned char FPGM(bci_create_segments_8) [] =
1421 PUSHB_1,
1422 bci_create_segments_8,
1423 FDEF,
1425 PUSHB_2,
1427 bci_create_segments,
1428 CALL,
1430 ENDF,
1434 unsigned char FPGM(bci_create_segments_9) [] =
1437 PUSHB_1,
1438 bci_create_segments_9,
1439 FDEF,
1441 PUSHB_2,
1443 bci_create_segments,
1444 CALL,
1446 ENDF,
1452 * bci_create_segments_composite
1454 * The same as `bci_create_segments'.
1455 * It also decrements the composite component counter.
1457 * uses: bci_decrement_composite_counter
1459 * CVT: cvtl_is_subglyph
1462 unsigned char FPGM(bci_create_segments_composite) [] =
1465 PUSHB_1,
1466 bci_create_segments_composite,
1467 FDEF,
1469 PUSHB_1,
1470 bci_decrement_component_counter,
1471 CALL,
1473 /* only do something if we are not a subglyph */
1474 PUSHB_2,
1476 cvtl_is_subglyph,
1477 RCVT,
1480 /* all our measurements are taken along the y axis */
1481 SVTCA_y,
1483 PUSHB_1,
1484 sal_num_packed_segments,
1485 SWAP,
1488 DUP,
1489 ADD,
1490 PUSHB_1,
1492 SUB, /* delta = (2*num_segments - 1) */
1494 PUSHB_6,
1495 sal_segment_offset,
1496 sal_segment_offset,
1498 sal_j,
1500 sal_base,
1502 WS, /* sal_base = 0 */
1503 WS, /* sal_j = 0 (point offset) */
1505 ROLL,
1506 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1508 /* `bci_create_segment_point' also increases the loop counter by 1; */
1509 /* this effectively means we have a loop step of 2 */
1510 PUSHB_2,
1511 bci_create_segment,
1512 bci_loop,
1513 CALL,
1515 PUSHB_1,
1516 bci_hint_glyph,
1517 CALL,
1519 ELSE,
1520 CLEAR,
1521 EIF,
1523 ENDF,
1529 * bci_create_segments_composite_X
1531 * Top-level routines for calling `bci_create_segments_composite'.
1534 unsigned char FPGM(bci_create_segments_composite_0) [] =
1537 PUSHB_1,
1538 bci_create_segments_composite_0,
1539 FDEF,
1541 PUSHB_2,
1543 bci_create_segments_composite,
1544 CALL,
1546 ENDF,
1550 unsigned char FPGM(bci_create_segments_composite_1) [] =
1553 PUSHB_1,
1554 bci_create_segments_composite_1,
1555 FDEF,
1557 PUSHB_2,
1559 bci_create_segments_composite,
1560 CALL,
1562 ENDF,
1566 unsigned char FPGM(bci_create_segments_composite_2) [] =
1569 PUSHB_1,
1570 bci_create_segments_composite_2,
1571 FDEF,
1573 PUSHB_2,
1575 bci_create_segments_composite,
1576 CALL,
1578 ENDF,
1582 unsigned char FPGM(bci_create_segments_composite_3) [] =
1585 PUSHB_1,
1586 bci_create_segments_composite_3,
1587 FDEF,
1589 PUSHB_2,
1591 bci_create_segments_composite,
1592 CALL,
1594 ENDF,
1598 unsigned char FPGM(bci_create_segments_composite_4) [] =
1601 PUSHB_1,
1602 bci_create_segments_composite_4,
1603 FDEF,
1605 PUSHB_2,
1607 bci_create_segments_composite,
1608 CALL,
1610 ENDF,
1614 unsigned char FPGM(bci_create_segments_composite_5) [] =
1617 PUSHB_1,
1618 bci_create_segments_composite_5,
1619 FDEF,
1621 PUSHB_2,
1623 bci_create_segments_composite,
1624 CALL,
1626 ENDF,
1630 unsigned char FPGM(bci_create_segments_composite_6) [] =
1633 PUSHB_1,
1634 bci_create_segments_composite_6,
1635 FDEF,
1637 PUSHB_2,
1639 bci_create_segments_composite,
1640 CALL,
1642 ENDF,
1646 unsigned char FPGM(bci_create_segments_composite_7) [] =
1649 PUSHB_1,
1650 bci_create_segments_composite_7,
1651 FDEF,
1653 PUSHB_2,
1655 bci_create_segments_composite,
1656 CALL,
1658 ENDF,
1662 unsigned char FPGM(bci_create_segments_composite_8) [] =
1665 PUSHB_1,
1666 bci_create_segments_composite_8,
1667 FDEF,
1669 PUSHB_2,
1671 bci_create_segments_composite,
1672 CALL,
1674 ENDF,
1678 unsigned char FPGM(bci_create_segments_composite_9) [] =
1681 PUSHB_1,
1682 bci_create_segments_composite_9,
1683 FDEF,
1685 PUSHB_2,
1687 bci_create_segments_composite,
1688 CALL,
1690 ENDF,
1696 * bci_align_segment
1698 * Align all points in a segment to the twilight point in rp0.
1699 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1701 * in: segment_index
1704 unsigned char FPGM(bci_align_segment) [] =
1707 PUSHB_1,
1708 bci_align_segment,
1709 FDEF,
1711 /* we need the values of `sal_segment_offset + 2*segment_index' */
1712 /* and `sal_segment_offset + 2*segment_index + 1' */
1713 DUP,
1714 ADD,
1715 PUSHB_1,
1716 sal_segment_offset,
1717 ADD,
1718 DUP,
1720 SWAP,
1721 PUSHB_1,
1723 ADD,
1724 RS, /* s: first last */
1726 /* start_loop: */
1727 PUSHB_1,
1729 CINDEX, /* s: first last first */
1730 PUSHB_1,
1732 CINDEX, /* s: first last first last */
1733 LTEQ, /* first <= end */
1734 IF, /* s: first last */
1735 SWAP,
1736 DUP, /* s: last first first */
1737 ALIGNRP, /* align point with index `first' with rp0 */
1739 PUSHB_1,
1741 ADD, /* first = first + 1 */
1742 SWAP, /* s: first last */
1744 PUSHB_1,
1746 NEG,
1747 JMPR, /* goto start_loop */
1749 ELSE,
1750 POP,
1751 POP,
1752 EIF,
1754 ENDF,
1760 * bci_align_segments
1762 * Align segments to the twilight point in rp0.
1763 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1765 * in: first_segment
1766 * loop_counter (N)
1767 * segment_1
1768 * segment_2
1769 * ...
1770 * segment_N
1772 * uses: handle_segment
1776 unsigned char FPGM(bci_align_segments) [] =
1779 PUSHB_1,
1780 bci_align_segments,
1781 FDEF,
1783 PUSHB_1,
1784 bci_align_segment,
1785 CALL,
1787 PUSHB_1,
1788 bci_align_segment,
1789 LOOPCALL,
1791 ENDF,
1797 * bci_scale_contour
1799 * Scale a contour using two points giving the maximum and minimum
1800 * coordinates.
1802 * It expects that no point on the contour is touched.
1804 * in: min_point
1805 * max_point
1807 * CVT: cvtl_scale
1808 * cvtl_0x10000
1811 unsigned char FPGM(bci_scale_contour) [] =
1814 PUSHB_1,
1815 bci_scale_contour,
1816 FDEF,
1818 DUP,
1819 DUP,
1820 GC_orig,
1821 DUP,
1822 DO_SCALE, /* min_pos_new = min_pos * scale */
1823 SWAP,
1824 SUB,
1825 SHPIX,
1827 /* don't scale a single-point contour twice */
1828 SWAP,
1829 DUP,
1830 ROLL,
1831 NEQ,
1833 DUP,
1834 GC_orig,
1835 DUP,
1836 DO_SCALE, /* max_pos_new = max_pos * scale */
1837 SWAP,
1838 SUB,
1839 SHPIX,
1841 ELSE,
1842 POP,
1843 EIF,
1845 ENDF,
1851 * bci_scale_glyph
1853 * Scale a glyph using a list of points (two points per contour, giving
1854 * the maximum and mininum coordinates).
1856 * It expects that no point in the glyph is touched.
1858 * Note that the point numbers are sorted in ascending order;
1859 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1860 * contour without specifying which one is the minimum and maximum.
1862 * in: num_contours (N)
1863 * min_point_1
1864 * max_point_1
1865 * min_point_2
1866 * max_point_2
1867 * ...
1868 * min_point_N
1869 * max_point_N
1871 * uses: bci_scale_contour
1873 * CVT: cvtl_is_subglyph
1876 unsigned char FPGM(bci_scale_glyph) [] =
1879 PUSHB_1,
1880 bci_scale_glyph,
1881 FDEF,
1883 /* only do something if we are not a subglyph */
1884 PUSHB_2,
1886 cvtl_is_subglyph,
1887 RCVT,
1890 /* all our measurements are taken along the y axis */
1891 SVTCA_y,
1893 PUSHB_1,
1895 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1897 PUSHB_1,
1898 bci_scale_contour,
1899 LOOPCALL,
1901 PUSHB_1,
1903 SZP2, /* set zp2 to normal zone 1 */
1904 IUP_y,
1906 ELSE,
1907 CLEAR,
1908 EIF,
1910 ENDF,
1916 * bci_scale_composite_glyph
1918 * The same as `bci_scale_composite_glyph'.
1919 * It also decrements the composite component counter.
1921 * uses: bci_decrement_component_counter
1923 * CVT: cvtl_is_subglyph
1926 unsigned char FPGM(bci_scale_composite_glyph) [] =
1929 PUSHB_1,
1930 bci_scale_composite_glyph,
1931 FDEF,
1933 PUSHB_1,
1934 bci_decrement_component_counter,
1935 CALL,
1937 /* only do something if we are not a subglyph */
1938 PUSHB_2,
1940 cvtl_is_subglyph,
1941 RCVT,
1944 /* all our measurements are taken along the y axis */
1945 SVTCA_y,
1947 PUSHB_1,
1949 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1951 PUSHB_1,
1952 bci_scale_contour,
1953 LOOPCALL,
1955 PUSHB_1,
1957 SZP2, /* set zp2 to normal zone 1 */
1958 IUP_y,
1960 ELSE,
1961 CLEAR,
1962 EIF,
1964 ENDF,
1970 * bci_shift_contour
1972 * Shift a contour by a given amount.
1974 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1975 * point to the normal zone 1.
1977 * in: contour
1978 * out: contour + 1
1981 unsigned char FPGM(bci_shift_contour) [] =
1984 PUSHB_1,
1985 bci_shift_contour,
1986 FDEF,
1988 DUP,
1989 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1991 PUSHB_1,
1993 ADD,
1995 ENDF,
2001 * bci_shift_subglyph
2003 * Shift a subglyph. To be more specific, it corrects the already applied
2004 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2005 * also.
2007 * If this function is called, a point `x' in the subglyph has been scaled
2008 * already (during the hinting of the subglyph itself), and `offset' has
2009 * been applied also:
2011 * x -> x * scale + offset (1)
2013 * However, the offset should be applied first, then the scaling:
2015 * x -> (x + offset) * scale (2)
2017 * Our job is now to transform (1) to (2); a simple calculation shows that
2018 * we have to shift all points of the subglyph by
2020 * offset * scale - offset = offset * (scale - 1)
2022 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2024 * in: offset (in FUnits)
2025 * num_contours
2026 * first_contour
2028 * CVT: cvtl_funits_to_pixels
2029 * cvtl_0x10000
2030 * cvtl_scale
2033 unsigned char FPGM(bci_shift_subglyph) [] =
2036 PUSHB_1,
2037 bci_shift_subglyph,
2038 FDEF,
2040 SVTCA_y,
2042 PUSHB_1,
2043 cvtl_funits_to_pixels,
2044 RCVT, /* scaling factor FUnits -> pixels */
2045 MUL,
2046 PUSHB_1,
2047 cvtl_0x10000,
2048 RCVT,
2049 DIV,
2051 /* the autohinter always rounds offsets */
2052 PUSHB_1,
2053 bci_round,
2054 CALL, /* offset = round(offset) */
2056 PUSHB_1,
2057 cvtl_scale,
2058 RCVT,
2059 MUL,
2060 PUSHB_1,
2061 cvtl_0x10000,
2062 RCVT,
2063 DIV, /* delta = offset * (scale - 1) */
2065 /* and round again */
2066 PUSHB_1,
2067 bci_round,
2068 CALL, /* offset = round(offset) */
2070 PUSHB_1,
2072 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2074 /* we create twilight point 0 as a reference point, */
2075 /* setting the original position to zero (using `cvtl_temp') */
2076 PUSHB_5,
2079 cvtl_temp,
2080 cvtl_temp,
2082 WCVTP,
2083 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2085 SWAP, /* s: first_contour num_contours 0 delta */
2086 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2088 PUSHB_2,
2089 bci_shift_contour,
2091 SZP2, /* set zp2 to normal zone 1 */
2092 LOOPCALL,
2094 ENDF,
2100 * bci_ip_outer_align_point
2102 * Auxiliary function for `bci_action_ip_before' and
2103 * `bci_action_ip_after'.
2105 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2106 * zone, and both zp1 and zp2 set to normal zone.
2108 * in: point
2110 * sal: sal_i (edge_orig_pos)
2112 * CVT: cvtl_scale
2113 * cvtl_0x10000
2116 unsigned char FPGM(bci_ip_outer_align_point) [] =
2119 PUSHB_1,
2120 bci_ip_outer_align_point,
2121 FDEF,
2123 DUP,
2124 ALIGNRP, /* align `point' with `edge' */
2125 DUP,
2126 GC_orig,
2127 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2129 PUSHB_1,
2130 sal_i,
2132 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2133 SHPIX,
2135 ENDF,
2141 * bci_ip_on_align_points
2143 * Auxiliary function for `bci_action_ip_on'.
2145 * in: edge (in twilight zone)
2146 * loop_counter (N)
2147 * point_1
2148 * point_2
2149 * ...
2150 * point_N
2153 unsigned char FPGM(bci_ip_on_align_points) [] =
2156 PUSHB_1,
2157 bci_ip_on_align_points,
2158 FDEF,
2160 MDAP_noround, /* set rp0 and rp1 to `edge' */
2162 SLOOP,
2163 ALIGNRP,
2165 ENDF,
2171 * bci_ip_between_align_point
2173 * Auxiliary function for `bci_ip_between_align_points'.
2175 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2176 * zone, and both zp1 and zp2 set to normal zone.
2178 * in: point
2180 * sal: sal_i (edge_orig_pos)
2181 * sal_j (stretch_factor)
2183 * CVT: cvtl_scale
2184 * cvtl_0x10000
2187 unsigned char FPGM(bci_ip_between_align_point) [] =
2190 PUSHB_1,
2191 bci_ip_between_align_point,
2192 FDEF,
2194 DUP,
2195 ALIGNRP, /* align `point' with `edge' */
2196 DUP,
2197 GC_orig,
2198 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2200 PUSHB_1,
2201 sal_i,
2203 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2204 PUSHB_1,
2205 sal_j,
2207 MUL, /* s: point delta */
2208 SHPIX,
2210 ENDF,
2216 * bci_ip_between_align_points
2218 * Auxiliary function for `bci_action_ip_between'.
2220 * in: after_edge (in twilight zone)
2221 * before_edge (in twilight zone)
2222 * loop_counter (N)
2223 * point_1
2224 * point_2
2225 * ...
2226 * point_N
2228 * sal: sal_i (before_orig_pos)
2229 * sal_j (stretch_factor)
2231 * uses: bci_ip_between_align_point
2234 unsigned char FPGM(bci_ip_between_align_points) [] =
2237 PUSHB_1,
2238 bci_ip_between_align_points,
2239 FDEF,
2241 PUSHB_2,
2244 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2245 CINDEX,
2246 DUP, /* s: ... before after before before */
2247 MDAP_noround, /* set rp0 and rp1 to `before' */
2248 DUP,
2249 GC_orig, /* s: ... before after before before_orig_pos */
2250 PUSHB_1,
2251 sal_i,
2252 SWAP,
2253 WS, /* sal_i = before_orig_pos */
2254 PUSHB_1,
2256 CINDEX, /* s: ... before after before after */
2257 MD_cur, /* b = after_pos - before_pos */
2258 ROLL,
2259 ROLL,
2260 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
2261 DIV, /* s: a/b */
2262 PUSHB_1,
2263 sal_j,
2264 SWAP,
2265 WS, /* sal_j = stretch_factor */
2267 PUSHB_3,
2268 bci_ip_between_align_point,
2271 SZP2, /* set zp2 to normal zone 1 */
2272 SZP1, /* set zp1 to normal zone 1 */
2273 LOOPCALL,
2275 ENDF,
2281 * bci_action_ip_before
2283 * Handle `ip_before' data to align points located before the first edge.
2285 * in: first_edge (in twilight zone)
2286 * loop_counter (N)
2287 * point_1
2288 * point_2
2289 * ...
2290 * point_N
2292 * sal: sal_i (first_edge_orig_pos)
2294 * uses: bci_ip_outer_align_point
2297 unsigned char FPGM(bci_action_ip_before) [] =
2300 PUSHB_1,
2301 bci_action_ip_before,
2302 FDEF,
2304 PUSHB_1,
2306 SZP2, /* set zp2 to twilight zone 0 */
2308 DUP,
2309 GC_orig,
2310 PUSHB_1,
2311 sal_i,
2312 SWAP,
2313 WS, /* sal_i = first_edge_orig_pos */
2315 PUSHB_3,
2319 SZP2, /* set zp2 to normal zone 1 */
2320 SZP1, /* set zp1 to normal zone 1 */
2321 SZP0, /* set zp0 to twilight zone 0 */
2323 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2325 PUSHB_1,
2326 bci_ip_outer_align_point,
2327 LOOPCALL,
2329 ENDF,
2335 * bci_action_ip_after
2337 * Handle `ip_after' data to align points located after the last edge.
2339 * in: last_edge (in twilight zone)
2340 * loop_counter (N)
2341 * point_1
2342 * point_2
2343 * ...
2344 * point_N
2346 * sal: sal_i (last_edge_orig_pos)
2348 * uses: bci_ip_outer_align_point
2351 unsigned char FPGM(bci_action_ip_after) [] =
2354 PUSHB_1,
2355 bci_action_ip_after,
2356 FDEF,
2358 PUSHB_1,
2360 SZP2, /* set zp2 to twilight zone 0 */
2362 DUP,
2363 GC_orig,
2364 PUSHB_1,
2365 sal_i,
2366 SWAP,
2367 WS, /* sal_i = last_edge_orig_pos */
2369 PUSHB_3,
2373 SZP2, /* set zp2 to normal zone 1 */
2374 SZP1, /* set zp1 to normal zone 1 */
2375 SZP0, /* set zp0 to twilight zone 0 */
2377 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2379 PUSHB_1,
2380 bci_ip_outer_align_point,
2381 LOOPCALL,
2383 ENDF,
2389 * bci_action_ip_on
2391 * Handle `ip_on' data to align points located on an edge coordinate (but
2392 * not part of an edge).
2394 * in: loop_counter (M)
2395 * edge_1 (in twilight zone)
2396 * loop_counter (N_1)
2397 * point_1
2398 * point_2
2399 * ...
2400 * point_N_1
2401 * edge_2 (in twilight zone)
2402 * loop_counter (N_2)
2403 * point_1
2404 * point_2
2405 * ...
2406 * point_N_2
2407 * ...
2408 * edge_M (in twilight zone)
2409 * loop_counter (N_M)
2410 * point_1
2411 * point_2
2412 * ...
2413 * point_N_M
2415 * uses: bci_ip_on_align_points
2418 unsigned char FPGM(bci_action_ip_on) [] =
2421 PUSHB_1,
2422 bci_action_ip_on,
2423 FDEF,
2425 PUSHB_2,
2428 SZP1, /* set zp1 to normal zone 1 */
2429 SZP0, /* set zp0 to twilight zone 0 */
2431 PUSHB_1,
2432 bci_ip_on_align_points,
2433 LOOPCALL,
2435 ENDF,
2441 * bci_action_ip_between
2443 * Handle `ip_between' data to align points located between two edges.
2445 * in: loop_counter (M)
2446 * before_edge_1 (in twilight zone)
2447 * after_edge_1 (in twilight zone)
2448 * loop_counter (N_1)
2449 * point_1
2450 * point_2
2451 * ...
2452 * point_N_1
2453 * before_edge_2 (in twilight zone)
2454 * after_edge_2 (in twilight zone)
2455 * loop_counter (N_2)
2456 * point_1
2457 * point_2
2458 * ...
2459 * point_N_2
2460 * ...
2461 * before_edge_M (in twilight zone)
2462 * after_edge_M (in twilight zone)
2463 * loop_counter (N_M)
2464 * point_1
2465 * point_2
2466 * ...
2467 * point_N_M
2469 * uses: bci_ip_between_align_points
2472 unsigned char FPGM(bci_action_ip_between) [] =
2475 PUSHB_1,
2476 bci_action_ip_between,
2477 FDEF,
2479 PUSHB_1,
2480 bci_ip_between_align_points,
2481 LOOPCALL,
2483 ENDF,
2489 * bci_adjust_common
2491 * Common code for bci_action_adjust routines.
2494 unsigned char FPGM(bci_adjust_common) [] =
2497 PUSHB_1,
2498 bci_adjust_common,
2499 FDEF,
2501 PUSHB_1,
2503 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2505 PUSHB_1,
2507 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2508 PUSHB_1,
2510 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2511 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2513 PUSHB_1,
2514 cvtl_stem_width_function,
2515 RCVT,
2516 CALL,
2517 NEG, /* s: [...] edge2 edge -cur_len */
2519 ROLL, /* s: [...] edge -cur_len edge2 */
2520 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2521 SWAP,
2522 DUP,
2523 DUP, /* s: [...] -cur_len edge edge edge */
2524 ALIGNRP, /* align `edge' with `edge2' */
2525 ROLL,
2526 SHPIX, /* shift `edge' by -cur_len */
2528 ENDF,
2534 * bci_adjust_bound
2536 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2537 * edge of the stem has already been moved, then moving it again if
2538 * necessary to stay bound.
2540 * in: edge2_is_serif
2541 * edge_is_round
2542 * edge_point (in twilight zone)
2543 * edge2_point (in twilight zone)
2544 * edge[-1] (in twilight zone)
2545 * ... stuff for bci_align_segments (edge) ...
2547 * uses: bci_adjust_common
2550 unsigned char FPGM(bci_adjust_bound) [] =
2553 PUSHB_1,
2554 bci_adjust_bound,
2555 FDEF,
2557 PUSHB_1,
2558 bci_adjust_common,
2559 CALL,
2561 SWAP, /* s: edge edge[-1] */
2562 DUP,
2563 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2564 GC_cur,
2565 PUSHB_1,
2567 CINDEX,
2568 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2569 GT, /* edge_pos < edge[-1]_pos */
2571 DUP,
2572 ALIGNRP, /* align `edge' to `edge[-1]' */
2573 EIF,
2575 MDAP_noround, /* set rp0 and rp1 to `edge' */
2577 PUSHB_2,
2578 bci_align_segments,
2580 SZP1, /* set zp1 to normal zone 1 */
2581 CALL,
2583 ENDF,
2589 * bci_action_adjust_bound
2590 * bci_action_adjust_bound_serif
2591 * bci_action_adjust_bound_round
2592 * bci_action_adjust_bound_round_serif
2594 * Higher-level routines for calling `bci_adjust_bound'.
2597 unsigned char FPGM(bci_action_adjust_bound) [] =
2600 PUSHB_1,
2601 bci_action_adjust_bound,
2602 FDEF,
2604 PUSHB_3,
2607 bci_adjust_bound,
2608 CALL,
2610 ENDF,
2614 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
2617 PUSHB_1,
2618 bci_action_adjust_bound_serif,
2619 FDEF,
2621 PUSHB_3,
2624 bci_adjust_bound,
2625 CALL,
2627 ENDF,
2631 unsigned char FPGM(bci_action_adjust_bound_round) [] =
2634 PUSHB_1,
2635 bci_action_adjust_bound_round,
2636 FDEF,
2638 PUSHB_3,
2641 bci_adjust_bound,
2642 CALL,
2644 ENDF,
2648 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
2651 PUSHB_1,
2652 bci_action_adjust_bound_round_serif,
2653 FDEF,
2655 PUSHB_3,
2658 bci_adjust_bound,
2659 CALL,
2661 ENDF,
2667 * bci_adjust
2669 * Handle the ADJUST action to align an edge of a stem if the other edge
2670 * of the stem has already been moved.
2672 * in: edge2_is_serif
2673 * edge_is_round
2674 * edge_point (in twilight zone)
2675 * edge2_point (in twilight zone)
2676 * ... stuff for bci_align_segments (edge) ...
2678 * uses: bci_adjust_common
2681 unsigned char FPGM(bci_adjust) [] =
2684 PUSHB_1,
2685 bci_adjust,
2686 FDEF,
2688 PUSHB_1,
2689 bci_adjust_common,
2690 CALL,
2692 MDAP_noround, /* set rp0 and rp1 to `edge' */
2694 PUSHB_2,
2695 bci_align_segments,
2697 SZP1, /* set zp1 to normal zone 1 */
2698 CALL,
2700 ENDF,
2706 * bci_action_adjust
2707 * bci_action_adjust_serif
2708 * bci_action_adjust_round
2709 * bci_action_adjust_round_serif
2711 * Higher-level routines for calling `bci_adjust'.
2714 unsigned char FPGM(bci_action_adjust) [] =
2717 PUSHB_1,
2718 bci_action_adjust,
2719 FDEF,
2721 PUSHB_3,
2724 bci_adjust,
2725 CALL,
2727 ENDF,
2731 unsigned char FPGM(bci_action_adjust_serif) [] =
2734 PUSHB_1,
2735 bci_action_adjust_serif,
2736 FDEF,
2738 PUSHB_3,
2741 bci_adjust,
2742 CALL,
2744 ENDF,
2748 unsigned char FPGM(bci_action_adjust_round) [] =
2751 PUSHB_1,
2752 bci_action_adjust_round,
2753 FDEF,
2755 PUSHB_3,
2758 bci_adjust,
2759 CALL,
2761 ENDF,
2765 unsigned char FPGM(bci_action_adjust_round_serif) [] =
2768 PUSHB_1,
2769 bci_action_adjust_round_serif,
2770 FDEF,
2772 PUSHB_3,
2775 bci_adjust,
2776 CALL,
2778 ENDF,
2784 * bci_stem_common
2786 * Common code for bci_action_stem routines.
2789 #undef sal_u_off
2790 #define sal_u_off sal_temp1
2791 #undef sal_d_off
2792 #define sal_d_off sal_temp2
2793 #undef sal_org_len
2794 #define sal_org_len sal_temp3
2795 #undef sal_edge2
2796 #define sal_edge2 sal_temp3
2798 unsigned char FPGM(bci_stem_common) [] =
2801 PUSHB_1,
2802 bci_stem_common,
2803 FDEF,
2805 PUSHB_1,
2807 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2809 PUSHB_1,
2811 CINDEX,
2812 PUSHB_1,
2814 CINDEX,
2815 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2816 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2818 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2819 DUP,
2820 PUSHB_1,
2821 sal_org_len,
2822 SWAP,
2825 PUSHB_1,
2826 cvtl_stem_width_function,
2827 RCVT,
2828 CALL, /* s: [...] edge2 edge cur_len */
2830 DUP,
2831 PUSHB_1,
2833 LT, /* cur_len < 96 */
2835 DUP,
2836 PUSHB_1,
2838 LTEQ, /* cur_len <= 64 */
2840 PUSHB_4,
2841 sal_u_off,
2843 sal_d_off,
2846 ELSE,
2847 PUSHB_4,
2848 sal_u_off,
2850 sal_d_off,
2852 EIF,
2856 SWAP, /* s: [...] edge2 cur_len edge */
2857 DUP,
2858 PUSHB_1,
2859 sal_anchor,
2861 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
2862 ROLL,
2863 SWAP,
2864 MD_orig_ZP2_0,
2865 SWAP,
2866 GC_cur,
2867 ADD, /* s: [...] edge2 cur_len edge org_pos */
2868 PUSHB_1,
2869 sal_org_len,
2871 PUSHB_1,
2872 2*64,
2873 DIV,
2874 ADD, /* s: [...] edge2 cur_len edge org_center */
2876 DUP,
2877 PUSHB_1,
2878 bci_round,
2879 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2881 DUP,
2882 ROLL,
2883 ROLL,
2884 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2886 DUP,
2887 PUSHB_1,
2888 sal_u_off,
2890 ADD,
2891 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2893 SWAP,
2894 PUSHB_1,
2895 sal_d_off,
2897 SUB,
2898 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2900 LT, /* delta1 < delta2 */
2902 PUSHB_1,
2903 sal_u_off,
2905 SUB, /* cur_pos1 = cur_pos1 - u_off */
2907 ELSE,
2908 PUSHB_1,
2909 sal_d_off,
2911 ADD, /* cur_pos1 = cur_pos1 + d_off */
2912 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2914 PUSHB_1,
2916 CINDEX,
2917 PUSHB_1,
2918 2*64,
2919 DIV,
2920 SUB, /* arg = cur_pos1 - cur_len/2 */
2922 SWAP, /* s: [...] edge2 cur_len arg edge */
2923 DUP,
2924 DUP,
2925 PUSHB_1,
2927 MINDEX,
2928 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2929 GC_cur,
2930 SUB,
2931 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2933 ELSE,
2934 SWAP, /* s: [...] edge2 cur_len edge */
2935 PUSHB_1,
2936 sal_anchor,
2938 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
2939 PUSHB_1,
2941 CINDEX,
2942 PUSHB_1,
2943 sal_anchor,
2945 MD_orig_ZP2_0,
2946 ADD, /* s: [...] edge2 cur_len edge org_pos */
2948 DUP,
2949 PUSHB_1,
2950 sal_org_len,
2952 PUSHB_1,
2953 2*64,
2954 DIV,
2955 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2957 SWAP,
2958 DUP,
2959 PUSHB_1,
2960 bci_round,
2961 CALL, /* cur_pos1 = ROUND(org_pos) */
2962 SWAP,
2963 PUSHB_1,
2964 sal_org_len,
2966 ADD,
2967 PUSHB_1,
2968 bci_round,
2969 CALL,
2970 PUSHB_1,
2972 CINDEX,
2973 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2975 PUSHB_1,
2977 CINDEX,
2978 PUSHB_1,
2979 2*64,
2980 DIV,
2981 PUSHB_1,
2983 MINDEX,
2984 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2986 DUP,
2987 PUSHB_1,
2989 CINDEX,
2990 ADD,
2991 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2992 SWAP,
2993 PUSHB_1,
2995 CINDEX,
2996 ADD,
2997 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2998 LT, /* delta1 < delta2 */
3000 POP, /* arg = cur_pos1 */
3002 ELSE,
3003 SWAP,
3004 POP, /* arg = cur_pos2 */
3005 EIF, /* s: [...] edge2 cur_len edge arg */
3006 SWAP,
3007 DUP,
3008 DUP,
3009 PUSHB_1,
3011 MINDEX,
3012 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3013 GC_cur,
3014 SUB,
3015 SHPIX, /* edge = arg */
3016 EIF, /* s: [...] edge2 cur_len edge */
3018 ENDF,
3024 * bci_stem_bound
3026 * Handle the STEM action to align two edges of a stem, then moving one
3027 * edge again if necessary to stay bound.
3029 * The code after computing `cur_len' to shift `edge' and `edge2'
3030 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3032 * if cur_len < 96:
3033 * if cur_len < = 64:
3034 * u_off = 32
3035 * d_off = 32
3036 * else:
3037 * u_off = 38
3038 * d_off = 26
3040 * org_pos = anchor + (edge_orig - anchor_orig);
3041 * org_center = org_pos + org_len / 2;
3043 * cur_pos1 = ROUND(org_center)
3044 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3045 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3046 * if (delta1 < delta2):
3047 * cur_pos1 = cur_pos1 - u_off
3048 * else:
3049 * cur_pos1 = cur_pos1 + d_off
3051 * edge = cur_pos1 - cur_len / 2
3053 * else:
3054 * org_pos = anchor + (edge_orig - anchor_orig)
3055 * org_center = org_pos + org_len / 2;
3057 * cur_pos1 = ROUND(org_pos)
3058 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3059 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3060 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3062 * if (delta1 < delta2):
3063 * edge = cur_pos1
3064 * else:
3065 * edge = cur_pos2
3067 * edge2 = edge + cur_len
3069 * in: edge2_is_serif
3070 * edge_is_round
3071 * edge_point (in twilight zone)
3072 * edge2_point (in twilight zone)
3073 * edge[-1] (in twilight zone)
3074 * ... stuff for bci_align_segments (edge) ...
3075 * ... stuff for bci_align_segments (edge2)...
3077 * sal: sal_anchor
3078 * sal_temp1
3079 * sal_temp2
3080 * sal_temp3
3082 * uses: bci_stem_common
3085 unsigned char FPGM(bci_stem_bound) [] =
3088 PUSHB_1,
3089 bci_stem_bound,
3090 FDEF,
3092 PUSHB_1,
3093 bci_stem_common,
3094 CALL,
3096 ROLL, /* s: edge[-1] cur_len edge edge2 */
3097 DUP,
3098 DUP,
3099 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3100 PUSHB_1,
3101 sal_edge2,
3102 SWAP,
3103 WS, /* s: edge[-1] cur_len edge edge2 */
3104 ROLL,
3105 SHPIX, /* edge2 = edge + cur_len */
3107 SWAP, /* s: edge edge[-1] */
3108 DUP,
3109 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3110 GC_cur,
3111 PUSHB_1,
3113 CINDEX,
3114 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3115 GT, /* edge_pos < edge[-1]_pos */
3117 DUP,
3118 ALIGNRP, /* align `edge' to `edge[-1]' */
3119 EIF,
3121 MDAP_noround, /* set rp0 and rp1 to `edge' */
3123 PUSHB_2,
3124 bci_align_segments,
3126 SZP1, /* set zp1 to normal zone 1 */
3127 CALL,
3129 PUSHB_1,
3130 sal_edge2,
3132 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3134 PUSHB_1,
3135 bci_align_segments,
3136 CALL,
3138 ENDF,
3144 * bci_action_stem_bound
3145 * bci_action_stem_bound_serif
3146 * bci_action_stem_bound_round
3147 * bci_action_stem_bound_round_serif
3149 * Higher-level routines for calling `bci_stem_bound'.
3152 unsigned char FPGM(bci_action_stem_bound) [] =
3155 PUSHB_1,
3156 bci_action_stem_bound,
3157 FDEF,
3159 PUSHB_3,
3162 bci_stem_bound,
3163 CALL,
3165 ENDF,
3169 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3172 PUSHB_1,
3173 bci_action_stem_bound_serif,
3174 FDEF,
3176 PUSHB_3,
3179 bci_stem_bound,
3180 CALL,
3182 ENDF,
3186 unsigned char FPGM(bci_action_stem_bound_round) [] =
3189 PUSHB_1,
3190 bci_action_stem_bound_round,
3191 FDEF,
3193 PUSHB_3,
3196 bci_stem_bound,
3197 CALL,
3199 ENDF,
3203 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3206 PUSHB_1,
3207 bci_action_stem_bound_round_serif,
3208 FDEF,
3210 PUSHB_3,
3213 bci_stem_bound,
3214 CALL,
3216 ENDF,
3222 * bci_stem
3224 * Handle the STEM action to align two edges of a stem.
3226 * See `bci_stem_bound' for more details.
3228 * in: edge2_is_serif
3229 * edge_is_round
3230 * edge_point (in twilight zone)
3231 * edge2_point (in twilight zone)
3232 * ... stuff for bci_align_segments (edge) ...
3233 * ... stuff for bci_align_segments (edge2)...
3235 * sal: sal_anchor
3236 * sal_temp1
3237 * sal_temp2
3238 * sal_temp3
3240 * uses: bci_stem_common
3243 unsigned char FPGM(bci_stem) [] =
3246 PUSHB_1,
3247 bci_stem,
3248 FDEF,
3250 PUSHB_1,
3251 bci_stem_common,
3252 CALL,
3254 POP,
3255 SWAP, /* s: cur_len edge2 */
3256 DUP,
3257 DUP,
3258 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3259 PUSHB_1,
3260 sal_edge2,
3261 SWAP,
3262 WS, /* s: cur_len edge2 */
3263 SWAP,
3264 SHPIX, /* edge2 = edge + cur_len */
3266 PUSHB_2,
3267 bci_align_segments,
3269 SZP1, /* set zp1 to normal zone 1 */
3270 CALL,
3272 PUSHB_1,
3273 sal_edge2,
3275 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3277 PUSHB_1,
3278 bci_align_segments,
3279 CALL,
3280 ENDF,
3286 * bci_action_stem
3287 * bci_action_stem_serif
3288 * bci_action_stem_round
3289 * bci_action_stem_round_serif
3291 * Higher-level routines for calling `bci_stem'.
3294 unsigned char FPGM(bci_action_stem) [] =
3297 PUSHB_1,
3298 bci_action_stem,
3299 FDEF,
3301 PUSHB_3,
3304 bci_stem,
3305 CALL,
3307 ENDF,
3311 unsigned char FPGM(bci_action_stem_serif) [] =
3314 PUSHB_1,
3315 bci_action_stem_serif,
3316 FDEF,
3318 PUSHB_3,
3321 bci_stem,
3322 CALL,
3324 ENDF,
3328 unsigned char FPGM(bci_action_stem_round) [] =
3331 PUSHB_1,
3332 bci_action_stem_round,
3333 FDEF,
3335 PUSHB_3,
3338 bci_stem,
3339 CALL,
3341 ENDF,
3345 unsigned char FPGM(bci_action_stem_round_serif) [] =
3348 PUSHB_1,
3349 bci_action_stem_round_serif,
3350 FDEF,
3352 PUSHB_3,
3355 bci_stem,
3356 CALL,
3358 ENDF,
3364 * bci_link
3366 * Handle the LINK action to link an edge to another one.
3368 * in: stem_is_serif
3369 * base_is_round
3370 * base_point (in twilight zone)
3371 * stem_point (in twilight zone)
3372 * ... stuff for bci_align_segments (base) ...
3375 unsigned char FPGM(bci_link) [] =
3378 PUSHB_1,
3379 bci_link,
3380 FDEF,
3382 PUSHB_1,
3384 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3386 PUSHB_1,
3388 CINDEX,
3389 PUSHB_1,
3391 MINDEX,
3392 DUP, /* s: stem is_round is_serif stem base base */
3393 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3395 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3397 PUSHB_1,
3398 cvtl_stem_width_function,
3399 RCVT,
3400 CALL, /* s: stem new_dist */
3402 SWAP,
3403 DUP,
3404 ALIGNRP, /* align `stem_point' with `base_point' */
3405 DUP,
3406 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3407 SWAP,
3408 SHPIX, /* stem_point = base_point + new_dist */
3410 PUSHB_2,
3411 bci_align_segments,
3413 SZP1, /* set zp1 to normal zone 1 */
3414 CALL,
3416 ENDF,
3422 * bci_action_link
3423 * bci_action_link_serif
3424 * bci_action_link_round
3425 * bci_action_link_round_serif
3427 * Higher-level routines for calling `bci_link'.
3430 unsigned char FPGM(bci_action_link) [] =
3433 PUSHB_1,
3434 bci_action_link,
3435 FDEF,
3437 PUSHB_3,
3440 bci_link,
3441 CALL,
3443 ENDF,
3447 unsigned char FPGM(bci_action_link_serif) [] =
3450 PUSHB_1,
3451 bci_action_link_serif,
3452 FDEF,
3454 PUSHB_3,
3457 bci_link,
3458 CALL,
3460 ENDF,
3464 unsigned char FPGM(bci_action_link_round) [] =
3467 PUSHB_1,
3468 bci_action_link_round,
3469 FDEF,
3471 PUSHB_3,
3474 bci_link,
3475 CALL,
3477 ENDF,
3481 unsigned char FPGM(bci_action_link_round_serif) [] =
3484 PUSHB_1,
3485 bci_action_link_round_serif,
3486 FDEF,
3488 PUSHB_3,
3491 bci_link,
3492 CALL,
3494 ENDF,
3500 * bci_anchor
3502 * Handle the ANCHOR action to align two edges
3503 * and to set the edge anchor.
3505 * The code after computing `cur_len' to shift `edge' and `edge2'
3506 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3508 * if cur_len < 96:
3509 * if cur_len < = 64:
3510 * u_off = 32
3511 * d_off = 32
3512 * else:
3513 * u_off = 38
3514 * d_off = 26
3516 * org_center = edge_orig + org_len / 2
3517 * cur_pos1 = ROUND(org_center)
3519 * error1 = ABS(org_center - (cur_pos1 - u_off))
3520 * error2 = ABS(org_center - (cur_pos1 + d_off))
3521 * if (error1 < error2):
3522 * cur_pos1 = cur_pos1 - u_off
3523 * else:
3524 * cur_pos1 = cur_pos1 + d_off
3526 * edge = cur_pos1 - cur_len / 2
3527 * edge2 = edge + cur_len
3529 * else:
3530 * edge = ROUND(edge_orig)
3532 * in: edge2_is_serif
3533 * edge_is_round
3534 * edge_point (in twilight zone)
3535 * edge2_point (in twilight zone)
3536 * ... stuff for bci_align_segments (edge) ...
3538 * sal: sal_anchor
3539 * sal_temp1
3540 * sal_temp2
3541 * sal_temp3
3544 #undef sal_u_off
3545 #define sal_u_off sal_temp1
3546 #undef sal_d_off
3547 #define sal_d_off sal_temp2
3548 #undef sal_org_len
3549 #define sal_org_len sal_temp3
3551 unsigned char FPGM(bci_anchor) [] =
3554 PUSHB_1,
3555 bci_anchor,
3556 FDEF,
3558 /* store anchor point number in `sal_anchor' */
3559 PUSHB_2,
3560 sal_anchor,
3562 CINDEX,
3563 WS, /* sal_anchor = edge_point */
3565 PUSHB_1,
3567 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3569 PUSHB_1,
3571 CINDEX,
3572 PUSHB_1,
3574 CINDEX,
3575 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
3576 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3578 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
3579 DUP,
3580 PUSHB_1,
3581 sal_org_len,
3582 SWAP,
3585 PUSHB_1,
3586 cvtl_stem_width_function,
3587 RCVT,
3588 CALL, /* s: edge2 edge cur_len */
3590 DUP,
3591 PUSHB_1,
3593 LT, /* cur_len < 96 */
3595 DUP,
3596 PUSHB_1,
3598 LTEQ, /* cur_len <= 64 */
3600 PUSHB_4,
3601 sal_u_off,
3603 sal_d_off,
3606 ELSE,
3607 PUSHB_4,
3608 sal_u_off,
3610 sal_d_off,
3612 EIF,
3616 SWAP, /* s: edge2 cur_len edge */
3617 DUP, /* s: edge2 cur_len edge edge */
3619 GC_orig,
3620 PUSHB_1,
3621 sal_org_len,
3623 PUSHB_1,
3624 2*64,
3625 DIV,
3626 ADD, /* s: edge2 cur_len edge org_center */
3628 DUP,
3629 PUSHB_1,
3630 bci_round,
3631 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
3633 DUP,
3634 ROLL,
3635 ROLL,
3636 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3638 DUP,
3639 PUSHB_1,
3640 sal_u_off,
3642 ADD,
3643 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3645 SWAP,
3646 PUSHB_1,
3647 sal_d_off,
3649 SUB,
3650 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3652 LT, /* error1 < error2 */
3654 PUSHB_1,
3655 sal_u_off,
3657 SUB, /* cur_pos1 = cur_pos1 - u_off */
3659 ELSE,
3660 PUSHB_1,
3661 sal_d_off,
3663 ADD, /* cur_pos1 = cur_pos1 + d_off */
3664 EIF, /* s: edge2 cur_len edge cur_pos1 */
3666 PUSHB_1,
3668 CINDEX,
3669 PUSHB_1,
3670 2*64,
3671 DIV,
3672 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3674 PUSHB_1,
3676 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3677 GC_cur,
3678 SUB,
3679 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3681 SWAP, /* s: cur_len edge2 */
3682 DUP,
3683 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3684 SWAP,
3685 SHPIX, /* edge2 = edge1 + cur_len */
3687 ELSE,
3688 POP, /* s: edge2 edge */
3689 DUP,
3690 DUP,
3691 GC_cur,
3692 SWAP,
3693 GC_orig,
3694 PUSHB_1,
3695 bci_round,
3696 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3697 SWAP,
3698 SUB,
3699 SHPIX, /* edge = round(edge_orig) */
3701 /* clean up stack */
3702 POP,
3703 EIF,
3705 PUSHB_2,
3706 bci_align_segments,
3708 SZP1, /* set zp1 to normal zone 1 */
3709 CALL,
3711 ENDF,
3717 * bci_action_anchor
3718 * bci_action_anchor_serif
3719 * bci_action_anchor_round
3720 * bci_action_anchor_round_serif
3722 * Higher-level routines for calling `bci_anchor'.
3725 unsigned char FPGM(bci_action_anchor) [] =
3728 PUSHB_1,
3729 bci_action_anchor,
3730 FDEF,
3732 PUSHB_3,
3735 bci_anchor,
3736 CALL,
3738 ENDF,
3742 unsigned char FPGM(bci_action_anchor_serif) [] =
3745 PUSHB_1,
3746 bci_action_anchor_serif,
3747 FDEF,
3749 PUSHB_3,
3752 bci_anchor,
3753 CALL,
3755 ENDF,
3759 unsigned char FPGM(bci_action_anchor_round) [] =
3762 PUSHB_1,
3763 bci_action_anchor_round,
3764 FDEF,
3766 PUSHB_3,
3769 bci_anchor,
3770 CALL,
3772 ENDF,
3776 unsigned char FPGM(bci_action_anchor_round_serif) [] =
3779 PUSHB_1,
3780 bci_action_anchor_round_serif,
3781 FDEF,
3783 PUSHB_3,
3786 bci_anchor,
3787 CALL,
3789 ENDF,
3795 * bci_action_blue_anchor
3797 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3798 * and to set the edge anchor.
3800 * in: anchor_point (in twilight zone)
3801 * blue_cvt_idx
3802 * edge_point (in twilight zone)
3803 * ... stuff for bci_align_segments (edge) ...
3805 * sal: sal_anchor
3807 * uses: bci_action_blue
3810 unsigned char FPGM(bci_action_blue_anchor) [] =
3813 PUSHB_1,
3814 bci_action_blue_anchor,
3815 FDEF,
3817 /* store anchor point number in `sal_anchor' */
3818 PUSHB_1,
3819 sal_anchor,
3820 SWAP,
3823 PUSHB_1,
3824 bci_action_blue,
3825 CALL,
3827 ENDF,
3833 * bci_action_blue
3835 * Handle the BLUE action to align an edge with a blue zone.
3837 * in: blue_cvt_idx
3838 * edge_point (in twilight zone)
3839 * ... stuff for bci_align_segments (edge) ...
3842 unsigned char FPGM(bci_action_blue) [] =
3845 PUSHB_1,
3846 bci_action_blue,
3847 FDEF,
3849 PUSHB_1,
3851 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3853 /* move `edge_point' to `blue_cvt_idx' position; */
3854 /* note that we can't use MIAP since this would modify */
3855 /* the twilight point's original coordinates also */
3856 RCVT,
3857 SWAP,
3858 DUP,
3859 MDAP_noround, /* set rp0 and rp1 to `edge' */
3860 DUP,
3861 GC_cur, /* s: new_pos edge edge_pos */
3862 ROLL,
3863 SWAP,
3864 SUB, /* s: edge (new_pos - edge_pos) */
3865 SHPIX,
3867 PUSHB_2,
3868 bci_align_segments,
3870 SZP1, /* set zp1 to normal zone 1 */
3871 CALL,
3873 ENDF,
3879 * bci_serif_common
3881 * Common code for bci_action_serif routines.
3884 unsigned char FPGM(bci_serif_common) [] =
3887 PUSHB_1,
3888 bci_serif_common,
3889 FDEF,
3891 PUSHB_1,
3893 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3895 DUP,
3896 DUP,
3897 DUP,
3898 PUSHB_1,
3900 MINDEX, /* s: [...] serif serif serif serif base */
3901 DUP,
3902 MDAP_noround, /* set rp0 and rp1 to `base_point' */
3903 MD_orig_ZP2_0,
3904 SWAP,
3905 ALIGNRP, /* align `serif_point' with `base_point' */
3906 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
3908 ENDF,
3914 * bci_lower_bound
3916 * Move an edge if necessary to stay within a lower bound.
3918 * in: edge
3919 * bound
3922 unsigned char FPGM(bci_lower_bound) [] =
3925 PUSHB_1,
3926 bci_lower_bound,
3927 FDEF,
3929 SWAP, /* s: edge bound */
3930 DUP,
3931 MDAP_noround, /* set rp0 and rp1 to `bound' */
3932 GC_cur,
3933 PUSHB_1,
3935 CINDEX,
3936 GC_cur, /* s: edge bound_pos edge_pos */
3937 GT, /* edge_pos < bound_pos */
3939 DUP,
3940 ALIGNRP, /* align `edge' to `bound' */
3941 EIF,
3943 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3945 PUSHB_2,
3946 bci_align_segments,
3948 SZP1, /* set zp1 to normal zone 1 */
3949 CALL,
3951 ENDF,
3957 * bci_upper_bound
3959 * Move an edge if necessary to stay within an upper bound.
3961 * in: edge
3962 * bound
3965 unsigned char FPGM(bci_upper_bound) [] =
3968 PUSHB_1,
3969 bci_upper_bound,
3970 FDEF,
3972 SWAP, /* s: edge bound */
3973 DUP,
3974 MDAP_noround, /* set rp0 and rp1 to `bound' */
3975 GC_cur,
3976 PUSHB_1,
3978 CINDEX,
3979 GC_cur, /* s: edge bound_pos edge_pos */
3980 LT, /* edge_pos > bound_pos */
3982 DUP,
3983 ALIGNRP, /* align `edge' to `bound' */
3984 EIF,
3986 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
3988 PUSHB_2,
3989 bci_align_segments,
3991 SZP1, /* set zp1 to normal zone 1 */
3992 CALL,
3994 ENDF,
4000 * bci_upper_lower_bound
4002 * Move an edge if necessary to stay within a lower and lower bound.
4004 * in: edge
4005 * lower
4006 * upper
4009 unsigned char FPGM(bci_upper_lower_bound) [] =
4012 PUSHB_1,
4013 bci_upper_lower_bound,
4014 FDEF,
4016 SWAP, /* s: upper serif lower */
4017 DUP,
4018 MDAP_noround, /* set rp0 and rp1 to `lower' */
4019 GC_cur,
4020 PUSHB_1,
4022 CINDEX,
4023 GC_cur, /* s: upper serif lower_pos serif_pos */
4024 GT, /* serif_pos < lower_pos */
4026 DUP,
4027 ALIGNRP, /* align `serif' to `lower' */
4028 EIF,
4030 SWAP, /* s: serif upper */
4031 DUP,
4032 MDAP_noround, /* set rp0 and rp1 to `upper' */
4033 GC_cur,
4034 PUSHB_1,
4036 CINDEX,
4037 GC_cur, /* s: serif upper_pos serif_pos */
4038 LT, /* serif_pos > upper_pos */
4040 DUP,
4041 ALIGNRP, /* align `serif' to `upper' */
4042 EIF,
4044 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4046 PUSHB_2,
4047 bci_align_segments,
4049 SZP1, /* set zp1 to normal zone 1 */
4050 CALL,
4052 ENDF,
4058 * bci_action_serif
4060 * Handle the SERIF action to align a serif with its base.
4062 * in: serif_point (in twilight zone)
4063 * base_point (in twilight zone)
4064 * ... stuff for bci_align_segments (serif) ...
4066 * uses: bci_serif_common
4069 unsigned char FPGM(bci_action_serif) [] =
4072 PUSHB_1,
4073 bci_action_serif,
4074 FDEF,
4076 PUSHB_1,
4077 bci_serif_common,
4078 CALL,
4080 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4082 PUSHB_2,
4083 bci_align_segments,
4085 SZP1, /* set zp1 to normal zone 1 */
4086 CALL,
4088 ENDF,
4094 * bci_action_serif_lower_bound
4096 * Handle the SERIF action to align a serif with its base, then moving it
4097 * again if necessary to stay within a lower bound.
4099 * in: serif_point (in twilight zone)
4100 * base_point (in twilight zone)
4101 * edge[-1] (in twilight zone)
4102 * ... stuff for bci_align_segments (serif) ...
4104 * uses: bci_serif_common
4105 * bci_lower_bound
4108 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4111 PUSHB_1,
4112 bci_action_serif_lower_bound,
4113 FDEF,
4115 PUSHB_1,
4116 bci_serif_common,
4117 CALL,
4119 PUSHB_1,
4120 bci_lower_bound,
4121 CALL,
4123 ENDF,
4129 * bci_action_serif_upper_bound
4131 * Handle the SERIF action to align a serif with its base, then moving it
4132 * again if necessary to stay within an upper bound.
4134 * in: serif_point (in twilight zone)
4135 * base_point (in twilight zone)
4136 * edge[1] (in twilight zone)
4137 * ... stuff for bci_align_segments (serif) ...
4139 * uses: bci_serif_common
4140 * bci_upper_bound
4143 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4146 PUSHB_1,
4147 bci_action_serif_upper_bound,
4148 FDEF,
4150 PUSHB_1,
4151 bci_serif_common,
4152 CALL,
4154 PUSHB_1,
4155 bci_upper_bound,
4156 CALL,
4158 ENDF,
4164 * bci_action_serif_upper_lower_bound
4166 * Handle the SERIF action to align a serif with its base, then moving it
4167 * again if necessary to stay within a lower and upper bound.
4169 * in: serif_point (in twilight zone)
4170 * base_point (in twilight zone)
4171 * edge[-1] (in twilight zone)
4172 * edge[1] (in twilight zone)
4173 * ... stuff for bci_align_segments (serif) ...
4175 * uses: bci_serif_common
4176 * bci_upper_lower_bound
4179 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4182 PUSHB_1,
4183 bci_action_serif_upper_lower_bound,
4184 FDEF,
4186 PUSHB_1,
4188 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4190 PUSHB_1,
4191 bci_serif_common,
4192 CALL,
4194 PUSHB_1,
4195 bci_upper_lower_bound,
4196 CALL,
4198 ENDF,
4204 * bci_serif_anchor_common
4206 * Common code for bci_action_serif_anchor routines.
4209 unsigned char FPGM(bci_serif_anchor_common) [] =
4212 PUSHB_1,
4213 bci_serif_anchor_common,
4214 FDEF,
4216 PUSHB_1,
4218 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4220 DUP,
4221 PUSHB_1,
4222 sal_anchor,
4223 SWAP,
4224 WS, /* sal_anchor = edge_point */
4226 DUP,
4227 DUP,
4228 DUP,
4229 GC_cur,
4230 SWAP,
4231 GC_orig,
4232 PUSHB_1,
4233 bci_round,
4234 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4235 SWAP,
4236 SUB,
4237 SHPIX, /* edge = round(edge_orig) */
4239 ENDF,
4245 * bci_action_serif_anchor
4247 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4248 * anchor.
4250 * in: edge_point (in twilight zone)
4251 * ... stuff for bci_align_segments (edge) ...
4253 * uses: bci_serif_anchor_common
4256 unsigned char FPGM(bci_action_serif_anchor) [] =
4259 PUSHB_1,
4260 bci_action_serif_anchor,
4261 FDEF,
4263 PUSHB_1,
4264 bci_serif_anchor_common,
4265 CALL,
4267 MDAP_noround, /* set rp0 and rp1 to `edge' */
4269 PUSHB_2,
4270 bci_align_segments,
4272 SZP1, /* set zp1 to normal zone 1 */
4273 CALL,
4275 ENDF,
4281 * bci_action_serif_anchor_lower_bound
4283 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4284 * anchor, then moving it again if necessary to stay within a lower
4285 * bound.
4287 * in: edge_point (in twilight zone)
4288 * edge[-1] (in twilight zone)
4289 * ... stuff for bci_align_segments (edge) ...
4291 * uses: bci_serif_anchor_common
4292 * bci_lower_bound
4295 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4298 PUSHB_1,
4299 bci_action_serif_anchor_lower_bound,
4300 FDEF,
4302 PUSHB_1,
4303 bci_serif_anchor_common,
4304 CALL,
4306 PUSHB_1,
4307 bci_lower_bound,
4308 CALL,
4310 ENDF,
4316 * bci_action_serif_anchor_upper_bound
4318 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4319 * anchor, then moving it again if necessary to stay within an upper
4320 * bound.
4322 * in: edge_point (in twilight zone)
4323 * edge[1] (in twilight zone)
4324 * ... stuff for bci_align_segments (edge) ...
4326 * uses: bci_serif_anchor_common
4327 * bci_upper_bound
4330 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4333 PUSHB_1,
4334 bci_action_serif_anchor_upper_bound,
4335 FDEF,
4337 PUSHB_1,
4338 bci_serif_anchor_common,
4339 CALL,
4341 PUSHB_1,
4342 bci_upper_bound,
4343 CALL,
4345 ENDF,
4351 * bci_action_serif_anchor_upper_lower_bound
4353 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4354 * anchor, then moving it again if necessary to stay within a lower and
4355 * upper bound.
4357 * in: edge_point (in twilight zone)
4358 * edge[-1] (in twilight zone)
4359 * edge[1] (in twilight zone)
4360 * ... stuff for bci_align_segments (edge) ...
4362 * uses: bci_serif_anchor_common
4363 * bci_upper_lower_bound
4366 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4369 PUSHB_1,
4370 bci_action_serif_anchor_upper_lower_bound,
4371 FDEF,
4373 PUSHB_1,
4374 bci_serif_anchor_common,
4375 CALL,
4377 PUSHB_1,
4378 bci_upper_lower_bound,
4379 CALL,
4381 ENDF,
4387 * bci_serif_link1_common
4389 * Common code for bci_action_serif_link1 routines.
4392 unsigned char FPGM(bci_serif_link1_common) [] =
4395 PUSHB_1,
4396 bci_serif_link1_common,
4397 FDEF,
4399 PUSHB_1,
4401 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4403 PUSHB_1,
4405 CINDEX, /* s: [...] after edge before after */
4406 PUSHB_1,
4408 CINDEX, /* s: [...] after edge before after before */
4409 MD_orig_ZP2_0,
4410 PUSHB_1,
4412 EQ, /* after_orig_pos == before_orig_pos */
4413 IF, /* s: [...] after edge before */
4414 MDAP_noround, /* set rp0 and rp1 to `before' */
4415 DUP,
4416 ALIGNRP, /* align `edge' with `before' */
4417 SWAP,
4418 POP,
4420 ELSE,
4421 /* we have to execute `a*b/c', with b/c very near to 1: */
4422 /* to avoid overflow while retaining precision, */
4423 /* we transform this to `a + a * (b-c)/c' */
4425 PUSHB_1,
4427 CINDEX, /* s: [...] after edge before edge */
4428 PUSHB_1,
4430 CINDEX, /* s: [...] after edge before edge before */
4431 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4433 DUP,
4434 PUSHB_1,
4436 CINDEX, /* s: [...] after edge before a a after */
4437 PUSHB_1,
4439 CINDEX, /* s: [...] after edge before a a after before */
4440 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4442 PUSHB_1,
4444 CINDEX, /* s: [...] after edge before a a c after */
4445 PUSHB_1,
4447 CINDEX, /* s: [...] after edge before a a c after before */
4448 MD_cur, /* b = after_pos - before_pos */
4450 PUSHB_1,
4452 CINDEX, /* s: [...] after edge before a a c b c */
4453 SUB, /* b-c */
4455 PUSHB_1,
4456 cvtl_0x10000,
4457 RCVT,
4458 MUL, /* (b-c) in 16.16 format */
4459 SWAP,
4460 DIV, /* s: [...] after edge before a a (b-c)/c */
4462 MUL, /* a * (b-c)/c * 2^10 */
4463 PUSHB_1,
4464 cvtl_0x10000,
4465 RCVT,
4466 DIV, /* a * (b-c)/c */
4467 ADD, /* a*b/c */
4469 SWAP,
4470 MDAP_noround, /* set rp0 and rp1 to `before' */
4471 SWAP, /* s: [...] after a*b/c edge */
4472 DUP,
4473 DUP,
4474 ALIGNRP, /* align `edge' with `before' */
4475 ROLL,
4476 SHPIX, /* shift `edge' by `a*b/c' */
4478 SWAP, /* s: [...] edge after */
4479 POP,
4480 EIF,
4482 ENDF,
4488 * bci_action_serif_link1
4490 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4491 * before and after.
4493 * in: before_point (in twilight zone)
4494 * edge_point (in twilight zone)
4495 * after_point (in twilight zone)
4496 * ... stuff for bci_align_segments (edge) ...
4498 * uses: bci_serif_link1_common
4501 unsigned char FPGM(bci_action_serif_link1) [] =
4504 PUSHB_1,
4505 bci_action_serif_link1,
4506 FDEF,
4508 PUSHB_1,
4509 bci_serif_link1_common,
4510 CALL,
4512 MDAP_noround, /* set rp0 and rp1 to `edge' */
4514 PUSHB_2,
4515 bci_align_segments,
4517 SZP1, /* set zp1 to normal zone 1 */
4518 CALL,
4520 ENDF,
4526 * bci_action_serif_link1_lower_bound
4528 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4529 * before and after. Additionally, move the serif again if necessary to
4530 * stay within a lower bound.
4532 * in: before_point (in twilight zone)
4533 * edge_point (in twilight zone)
4534 * after_point (in twilight zone)
4535 * edge[-1] (in twilight zone)
4536 * ... stuff for bci_align_segments (edge) ...
4538 * uses: bci_serif_link1_common
4539 * bci_lower_bound
4542 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
4545 PUSHB_1,
4546 bci_action_serif_link1_lower_bound,
4547 FDEF,
4549 PUSHB_1,
4550 bci_serif_link1_common,
4551 CALL,
4553 PUSHB_1,
4554 bci_lower_bound,
4555 CALL,
4557 ENDF,
4563 * bci_action_serif_link1_upper_bound
4565 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4566 * before and after. Additionally, move the serif again if necessary to
4567 * stay within an upper bound.
4569 * in: before_point (in twilight zone)
4570 * edge_point (in twilight zone)
4571 * after_point (in twilight zone)
4572 * edge[1] (in twilight zone)
4573 * ... stuff for bci_align_segments (edge) ...
4575 * uses: bci_serif_link1_common
4576 * bci_upper_bound
4579 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
4582 PUSHB_1,
4583 bci_action_serif_link1_upper_bound,
4584 FDEF,
4586 PUSHB_1,
4587 bci_serif_link1_common,
4588 CALL,
4590 PUSHB_1,
4591 bci_upper_bound,
4592 CALL,
4594 ENDF,
4600 * bci_action_serif_link1_upper_lower_bound
4602 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4603 * before and after. Additionally, move the serif again if necessary to
4604 * stay within a lower and upper bound.
4606 * in: before_point (in twilight zone)
4607 * edge_point (in twilight zone)
4608 * after_point (in twilight zone)
4609 * edge[-1] (in twilight zone)
4610 * edge[1] (in twilight zone)
4611 * ... stuff for bci_align_segments (edge) ...
4613 * uses: bci_serif_link1_common
4614 * bci_upper_lower_bound
4617 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
4620 PUSHB_1,
4621 bci_action_serif_link1_upper_lower_bound,
4622 FDEF,
4624 PUSHB_1,
4625 bci_serif_link1_common,
4626 CALL,
4628 PUSHB_1,
4629 bci_upper_lower_bound,
4630 CALL,
4632 ENDF,
4638 * bci_serif_link2_common
4640 * Common code for bci_action_serif_link2 routines.
4643 unsigned char FPGM(bci_serif_link2_common) [] =
4646 PUSHB_1,
4647 bci_serif_link2_common,
4648 FDEF,
4650 PUSHB_1,
4652 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4654 DUP, /* s: [...] edge edge */
4655 PUSHB_1,
4656 sal_anchor,
4658 DUP, /* s: [...] edge edge anchor anchor */
4659 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
4661 MD_orig_ZP2_0,
4662 DUP,
4663 ADD,
4664 PUSHB_1,
4666 ADD,
4667 FLOOR,
4668 PUSHB_1,
4669 2*64,
4670 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4672 SWAP,
4673 DUP,
4674 DUP,
4675 ALIGNRP, /* align `edge' with `sal_anchor' */
4676 ROLL,
4677 SHPIX, /* shift `edge' by `delta' */
4679 ENDF,
4685 * bci_action_serif_link2
4687 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4689 * in: edge_point (in twilight zone)
4690 * ... stuff for bci_align_segments (edge) ...
4692 * uses: bci_serif_link2_common
4695 unsigned char FPGM(bci_action_serif_link2) [] =
4698 PUSHB_1,
4699 bci_action_serif_link2,
4700 FDEF,
4702 PUSHB_1,
4703 bci_serif_link2_common,
4704 CALL,
4706 MDAP_noround, /* set rp0 and rp1 to `edge' */
4708 PUSHB_2,
4709 bci_align_segments,
4711 SZP1, /* set zp1 to normal zone 1 */
4712 CALL,
4714 ENDF,
4720 * bci_action_serif_link2_lower_bound
4722 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4723 * Additionally, move the serif again if necessary to stay within a lower
4724 * bound.
4726 * in: edge_point (in twilight zone)
4727 * edge[-1] (in twilight zone)
4728 * ... stuff for bci_align_segments (edge) ...
4730 * uses: bci_serif_link2_common
4731 * bci_lower_bound
4734 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
4737 PUSHB_1,
4738 bci_action_serif_link2_lower_bound,
4739 FDEF,
4741 PUSHB_1,
4742 bci_serif_link2_common,
4743 CALL,
4745 PUSHB_1,
4746 bci_lower_bound,
4747 CALL,
4749 ENDF,
4755 * bci_action_serif_link2_upper_bound
4757 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4758 * Additionally, move the serif again if necessary to stay within an upper
4759 * bound.
4761 * in: edge_point (in twilight zone)
4762 * edge[1] (in twilight zone)
4763 * ... stuff for bci_align_segments (edge) ...
4765 * uses: bci_serif_link2_common
4766 * bci_upper_bound
4769 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
4772 PUSHB_1,
4773 bci_action_serif_link2_upper_bound,
4774 FDEF,
4776 PUSHB_1,
4777 bci_serif_link2_common,
4778 CALL,
4780 PUSHB_1,
4781 bci_upper_bound,
4782 CALL,
4784 ENDF,
4790 * bci_action_serif_link2_upper_lower_bound
4792 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4793 * Additionally, move the serif again if necessary to stay within a lower
4794 * and upper bound.
4796 * in: edge_point (in twilight zone)
4797 * edge[-1] (in twilight zone)
4798 * edge[1] (in twilight zone)
4799 * ... stuff for bci_align_segments (edge) ...
4801 * uses: bci_serif_link2_common
4802 * bci_upper_lower_bound
4805 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
4808 PUSHB_1,
4809 bci_action_serif_link2_upper_lower_bound,
4810 FDEF,
4812 PUSHB_1,
4813 bci_serif_link2_common,
4814 CALL,
4816 PUSHB_1,
4817 bci_upper_lower_bound,
4818 CALL,
4820 ENDF,
4826 * bci_hint_glyph
4828 * This is the top-level glyph hinting function which parses the arguments
4829 * on the stack and calls subroutines.
4831 * in: action_0_func_idx
4832 * ... data ...
4833 * action_1_func_idx
4834 * ... data ...
4835 * ...
4837 * uses: bci_action_ip_before
4838 * bci_action_ip_after
4839 * bci_action_ip_on
4840 * bci_action_ip_between
4842 * bci_action_adjust_bound
4843 * bci_action_adjust_bound_serif
4844 * bci_action_adjust_bound_round
4845 * bci_action_adjust_bound_round_serif
4847 * bci_action_stem_bound
4848 * bci_action_stem_bound_serif
4849 * bci_action_stem_bound_round
4850 * bci_action_stem_bound_round_serif
4852 * bci_action_link
4853 * bci_action_link_serif
4854 * bci_action_link_round
4855 * bci_action_link_round_serif
4857 * bci_action_anchor
4858 * bci_action_anchor_serif
4859 * bci_action_anchor_round
4860 * bci_action_anchor_round_serif
4862 * bci_action_blue_anchor
4864 * bci_action_adjust
4865 * bci_action_adjust_serif
4866 * bci_action_adjust_round
4867 * bci_action_adjust_round_serif
4869 * bci_action_stem
4870 * bci_action_stem_serif
4871 * bci_action_stem_round
4872 * bci_action_stem_round_serif
4874 * bci_action_blue
4876 * bci_action_serif
4877 * bci_action_serif_lower_bound
4878 * bci_action_serif_upper_bound
4879 * bci_action_serif_upper_lower_bound
4881 * bci_action_serif_anchor
4882 * bci_action_serif_anchor_lower_bound
4883 * bci_action_serif_anchor_upper_bound
4884 * bci_action_serif_anchor_upper_lower_bound
4886 * bci_action_serif_link1
4887 * bci_action_serif_link1_lower_bound
4888 * bci_action_serif_link1_upper_bound
4889 * bci_action_serif_link1_upper_lower_bound
4891 * bci_action_serif_link2
4892 * bci_action_serif_link2_lower_bound
4893 * bci_action_serif_link2_upper_bound
4894 * bci_action_serif_link2_upper_lower_bound
4896 * CVT: cvtl_is_subglyph
4899 unsigned char FPGM(bci_hint_glyph) [] =
4902 PUSHB_1,
4903 bci_hint_glyph,
4904 FDEF,
4906 /* start_loop: */
4907 /* loop until all data on stack is used */
4908 CALL,
4909 PUSHB_1,
4911 NEG,
4912 PUSHB_1,
4914 DEPTH,
4916 JROT, /* goto start_loop */
4918 PUSHB_1,
4920 SZP2, /* set zp2 to normal zone 1 */
4921 IUP_y,
4923 ENDF,
4928 #define COPY_FPGM(func_name) \
4929 memcpy(buf_p, fpgm_ ## func_name, \
4930 sizeof (fpgm_ ## func_name)); \
4931 buf_p += sizeof (fpgm_ ## func_name) \
4933 static FT_Error
4934 TA_table_build_fpgm(FT_Byte** fpgm,
4935 FT_ULong* fpgm_len,
4936 FONT* font)
4938 FT_UInt buf_len;
4939 FT_UInt len;
4940 FT_Byte* buf;
4941 FT_Byte* buf_p;
4944 /* for compatibility with dumb bytecode interpreters or analyzers, */
4945 /* FDEFs are stored in ascending index order, without holes -- */
4946 /* note that some FDEFs are not always needed */
4947 /* (depending on options of `TTFautohint'), */
4948 /* but implementing dynamic FDEF indices would be a lot of work */
4950 buf_len = sizeof (FPGM(bci_round))
4951 + sizeof (FPGM(bci_smooth_stem_width_a))
4953 + sizeof (FPGM(bci_smooth_stem_width_b))
4955 + sizeof (FPGM(bci_smooth_stem_width_c))
4956 + sizeof (FPGM(bci_get_best_width))
4957 + sizeof (FPGM(bci_strong_stem_width_a))
4959 + sizeof (FPGM(bci_strong_stem_width_b))
4960 + sizeof (FPGM(bci_loop))
4961 + sizeof (FPGM(bci_cvt_rescale))
4962 + sizeof (FPGM(bci_blue_round_a))
4964 + sizeof (FPGM(bci_blue_round_b))
4965 + sizeof (FPGM(bci_decrement_component_counter))
4966 + sizeof (FPGM(bci_get_point_extrema))
4967 + sizeof (FPGM(bci_nibbles))
4968 + sizeof (FPGM(bci_number_set_is_element))
4969 + sizeof (FPGM(bci_number_set_is_element2))
4971 + sizeof (FPGM(bci_create_segment))
4972 + sizeof (FPGM(bci_create_segments))
4974 + sizeof (FPGM(bci_create_segments_0))
4975 + sizeof (FPGM(bci_create_segments_1))
4976 + sizeof (FPGM(bci_create_segments_2))
4977 + sizeof (FPGM(bci_create_segments_3))
4978 + sizeof (FPGM(bci_create_segments_4))
4979 + sizeof (FPGM(bci_create_segments_5))
4980 + sizeof (FPGM(bci_create_segments_6))
4981 + sizeof (FPGM(bci_create_segments_7))
4982 + sizeof (FPGM(bci_create_segments_8))
4983 + sizeof (FPGM(bci_create_segments_9))
4985 + sizeof (FPGM(bci_create_segments_composite))
4987 + sizeof (FPGM(bci_create_segments_composite_0))
4988 + sizeof (FPGM(bci_create_segments_composite_1))
4989 + sizeof (FPGM(bci_create_segments_composite_2))
4990 + sizeof (FPGM(bci_create_segments_composite_3))
4991 + sizeof (FPGM(bci_create_segments_composite_4))
4992 + sizeof (FPGM(bci_create_segments_composite_5))
4993 + sizeof (FPGM(bci_create_segments_composite_6))
4994 + sizeof (FPGM(bci_create_segments_composite_7))
4995 + sizeof (FPGM(bci_create_segments_composite_8))
4996 + sizeof (FPGM(bci_create_segments_composite_9))
4998 + sizeof (FPGM(bci_align_segment))
4999 + sizeof (FPGM(bci_align_segments))
5001 + sizeof (FPGM(bci_scale_contour))
5002 + sizeof (FPGM(bci_scale_glyph))
5003 + sizeof (FPGM(bci_scale_composite_glyph))
5004 + sizeof (FPGM(bci_shift_contour))
5005 + sizeof (FPGM(bci_shift_subglyph))
5007 + sizeof (FPGM(bci_ip_outer_align_point))
5008 + sizeof (FPGM(bci_ip_on_align_points))
5009 + sizeof (FPGM(bci_ip_between_align_point))
5010 + sizeof (FPGM(bci_ip_between_align_points))
5012 + sizeof (FPGM(bci_adjust_common))
5013 + sizeof (FPGM(bci_stem_common))
5014 + sizeof (FPGM(bci_serif_common))
5015 + sizeof (FPGM(bci_serif_anchor_common))
5016 + sizeof (FPGM(bci_serif_link1_common))
5017 + sizeof (FPGM(bci_serif_link2_common))
5019 + sizeof (FPGM(bci_lower_bound))
5020 + sizeof (FPGM(bci_upper_bound))
5021 + sizeof (FPGM(bci_upper_lower_bound))
5023 + sizeof (FPGM(bci_adjust_bound))
5024 + sizeof (FPGM(bci_stem_bound))
5025 + sizeof (FPGM(bci_link))
5026 + sizeof (FPGM(bci_anchor))
5027 + sizeof (FPGM(bci_adjust))
5028 + sizeof (FPGM(bci_stem))
5030 + sizeof (FPGM(bci_action_ip_before))
5031 + sizeof (FPGM(bci_action_ip_after))
5032 + sizeof (FPGM(bci_action_ip_on))
5033 + sizeof (FPGM(bci_action_ip_between))
5035 + sizeof (FPGM(bci_action_blue))
5036 + sizeof (FPGM(bci_action_blue_anchor))
5038 + sizeof (FPGM(bci_action_anchor))
5039 + sizeof (FPGM(bci_action_anchor_serif))
5040 + sizeof (FPGM(bci_action_anchor_round))
5041 + sizeof (FPGM(bci_action_anchor_round_serif))
5043 + sizeof (FPGM(bci_action_adjust))
5044 + sizeof (FPGM(bci_action_adjust_serif))
5045 + sizeof (FPGM(bci_action_adjust_round))
5046 + sizeof (FPGM(bci_action_adjust_round_serif))
5047 + sizeof (FPGM(bci_action_adjust_bound))
5048 + sizeof (FPGM(bci_action_adjust_bound_serif))
5049 + sizeof (FPGM(bci_action_adjust_bound_round))
5050 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5052 + sizeof (FPGM(bci_action_link))
5053 + sizeof (FPGM(bci_action_link_serif))
5054 + sizeof (FPGM(bci_action_link_round))
5055 + sizeof (FPGM(bci_action_link_round_serif))
5057 + sizeof (FPGM(bci_action_stem))
5058 + sizeof (FPGM(bci_action_stem_serif))
5059 + sizeof (FPGM(bci_action_stem_round))
5060 + sizeof (FPGM(bci_action_stem_round_serif))
5061 + sizeof (FPGM(bci_action_stem_bound))
5062 + sizeof (FPGM(bci_action_stem_bound_serif))
5063 + sizeof (FPGM(bci_action_stem_bound_round))
5064 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5066 + sizeof (FPGM(bci_action_serif))
5067 + sizeof (FPGM(bci_action_serif_lower_bound))
5068 + sizeof (FPGM(bci_action_serif_upper_bound))
5069 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5071 + sizeof (FPGM(bci_action_serif_anchor))
5072 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5073 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5074 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5076 + sizeof (FPGM(bci_action_serif_link1))
5077 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5078 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5079 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5081 + sizeof (FPGM(bci_action_serif_link2))
5082 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5083 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5084 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5086 + sizeof (FPGM(bci_hint_glyph));
5088 /* buffer length must be a multiple of four */
5089 len = (buf_len + 3) & ~3;
5090 buf = (FT_Byte*)malloc(len);
5091 if (!buf)
5092 return FT_Err_Out_Of_Memory;
5094 /* pad end of buffer with zeros */
5095 buf[len - 1] = 0x00;
5096 buf[len - 2] = 0x00;
5097 buf[len - 3] = 0x00;
5099 /* copy font program into buffer and fill in the missing variables */
5100 buf_p = buf;
5102 COPY_FPGM(bci_round);
5103 COPY_FPGM(bci_smooth_stem_width_a);
5104 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5105 COPY_FPGM(bci_smooth_stem_width_b);
5106 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5107 COPY_FPGM(bci_smooth_stem_width_c);
5108 COPY_FPGM(bci_get_best_width);
5109 COPY_FPGM(bci_strong_stem_width_a);
5110 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
5111 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font);
5112 COPY_FPGM(bci_strong_stem_width_b);
5113 COPY_FPGM(bci_loop);
5114 COPY_FPGM(bci_cvt_rescale);
5115 COPY_FPGM(bci_blue_round_a);
5116 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
5117 COPY_FPGM(bci_blue_round_b);
5118 COPY_FPGM(bci_decrement_component_counter);
5119 COPY_FPGM(bci_get_point_extrema);
5120 COPY_FPGM(bci_nibbles);
5121 COPY_FPGM(bci_number_set_is_element);
5122 COPY_FPGM(bci_number_set_is_element2);
5124 COPY_FPGM(bci_create_segment);
5125 COPY_FPGM(bci_create_segments);
5127 COPY_FPGM(bci_create_segments_0);
5128 COPY_FPGM(bci_create_segments_1);
5129 COPY_FPGM(bci_create_segments_2);
5130 COPY_FPGM(bci_create_segments_3);
5131 COPY_FPGM(bci_create_segments_4);
5132 COPY_FPGM(bci_create_segments_5);
5133 COPY_FPGM(bci_create_segments_6);
5134 COPY_FPGM(bci_create_segments_7);
5135 COPY_FPGM(bci_create_segments_8);
5136 COPY_FPGM(bci_create_segments_9);
5138 COPY_FPGM(bci_create_segments_composite);
5140 COPY_FPGM(bci_create_segments_composite_0);
5141 COPY_FPGM(bci_create_segments_composite_1);
5142 COPY_FPGM(bci_create_segments_composite_2);
5143 COPY_FPGM(bci_create_segments_composite_3);
5144 COPY_FPGM(bci_create_segments_composite_4);
5145 COPY_FPGM(bci_create_segments_composite_5);
5146 COPY_FPGM(bci_create_segments_composite_6);
5147 COPY_FPGM(bci_create_segments_composite_7);
5148 COPY_FPGM(bci_create_segments_composite_8);
5149 COPY_FPGM(bci_create_segments_composite_9);
5151 COPY_FPGM(bci_align_segment);
5152 COPY_FPGM(bci_align_segments);
5154 COPY_FPGM(bci_scale_contour);
5155 COPY_FPGM(bci_scale_glyph);
5156 COPY_FPGM(bci_scale_composite_glyph);
5157 COPY_FPGM(bci_shift_contour);
5158 COPY_FPGM(bci_shift_subglyph);
5160 COPY_FPGM(bci_ip_outer_align_point);
5161 COPY_FPGM(bci_ip_on_align_points);
5162 COPY_FPGM(bci_ip_between_align_point);
5163 COPY_FPGM(bci_ip_between_align_points);
5165 COPY_FPGM(bci_adjust_common);
5166 COPY_FPGM(bci_stem_common);
5167 COPY_FPGM(bci_serif_common);
5168 COPY_FPGM(bci_serif_anchor_common);
5169 COPY_FPGM(bci_serif_link1_common);
5170 COPY_FPGM(bci_serif_link2_common);
5172 COPY_FPGM(bci_lower_bound);
5173 COPY_FPGM(bci_upper_bound);
5174 COPY_FPGM(bci_upper_lower_bound);
5176 COPY_FPGM(bci_adjust_bound);
5177 COPY_FPGM(bci_stem_bound);
5178 COPY_FPGM(bci_link);
5179 COPY_FPGM(bci_anchor);
5180 COPY_FPGM(bci_adjust);
5181 COPY_FPGM(bci_stem);
5183 COPY_FPGM(bci_action_ip_before);
5184 COPY_FPGM(bci_action_ip_after);
5185 COPY_FPGM(bci_action_ip_on);
5186 COPY_FPGM(bci_action_ip_between);
5188 COPY_FPGM(bci_action_blue);
5189 COPY_FPGM(bci_action_blue_anchor);
5191 COPY_FPGM(bci_action_anchor);
5192 COPY_FPGM(bci_action_anchor_serif);
5193 COPY_FPGM(bci_action_anchor_round);
5194 COPY_FPGM(bci_action_anchor_round_serif);
5196 COPY_FPGM(bci_action_adjust);
5197 COPY_FPGM(bci_action_adjust_serif);
5198 COPY_FPGM(bci_action_adjust_round);
5199 COPY_FPGM(bci_action_adjust_round_serif);
5200 COPY_FPGM(bci_action_adjust_bound);
5201 COPY_FPGM(bci_action_adjust_bound_serif);
5202 COPY_FPGM(bci_action_adjust_bound_round);
5203 COPY_FPGM(bci_action_adjust_bound_round_serif);
5205 COPY_FPGM(bci_action_link);
5206 COPY_FPGM(bci_action_link_serif);
5207 COPY_FPGM(bci_action_link_round);
5208 COPY_FPGM(bci_action_link_round_serif);
5210 COPY_FPGM(bci_action_stem);
5211 COPY_FPGM(bci_action_stem_serif);
5212 COPY_FPGM(bci_action_stem_round);
5213 COPY_FPGM(bci_action_stem_round_serif);
5214 COPY_FPGM(bci_action_stem_bound);
5215 COPY_FPGM(bci_action_stem_bound_serif);
5216 COPY_FPGM(bci_action_stem_bound_round);
5217 COPY_FPGM(bci_action_stem_bound_round_serif);
5219 COPY_FPGM(bci_action_serif);
5220 COPY_FPGM(bci_action_serif_lower_bound);
5221 COPY_FPGM(bci_action_serif_upper_bound);
5222 COPY_FPGM(bci_action_serif_upper_lower_bound);
5224 COPY_FPGM(bci_action_serif_anchor);
5225 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5226 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5227 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5229 COPY_FPGM(bci_action_serif_link1);
5230 COPY_FPGM(bci_action_serif_link1_lower_bound);
5231 COPY_FPGM(bci_action_serif_link1_upper_bound);
5232 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5234 COPY_FPGM(bci_action_serif_link2);
5235 COPY_FPGM(bci_action_serif_link2_lower_bound);
5236 COPY_FPGM(bci_action_serif_link2_upper_bound);
5237 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5239 COPY_FPGM(bci_hint_glyph);
5241 *fpgm = buf;
5242 *fpgm_len = buf_len;
5244 return FT_Err_Ok;
5248 FT_Error
5249 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5250 FONT* font)
5252 FT_Error error = FT_Err_Ok;
5254 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5255 glyf_Data* data = (glyf_Data*)glyf_table->data;
5257 FT_Byte* fpgm_buf;
5258 FT_ULong fpgm_len;
5261 error = TA_sfnt_add_table_info(sfnt);
5262 if (error)
5263 goto Exit;
5265 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5266 if (glyf_table->processed)
5268 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5269 goto Exit;
5272 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
5273 if (error)
5274 goto Exit;
5276 if (fpgm_len > sfnt->max_instructions)
5277 sfnt->max_instructions = fpgm_len;
5279 /* in case of success, `fpgm_buf' gets linked */
5280 /* and is eventually freed in `TA_font_unload' */
5281 error = TA_font_add_table(font,
5282 &sfnt->table_infos[sfnt->num_table_infos - 1],
5283 TTAG_fpgm, fpgm_len, fpgm_buf);
5284 if (error)
5285 free(fpgm_buf);
5286 else
5287 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5289 Exit:
5290 return error;
5293 /* end of tafpgm.c */