Use constants for default values.
[ttfautohint.git] / lib / tafpgm.c
blob8f4113a327fe06627069ffbddf73c32dc5d6e09a
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
32 GC_orig, \
33 SWAP, \
34 GC_orig, \
35 SWAP, \
36 SUB
38 #define MD_orig_ZP2_0 \
39 MD_orig_fixed
41 #define MD_orig_ZP2_1 \
42 PUSHB_1, \
43 0, \
44 SZP2, \
45 MD_orig_fixed, \
46 PUSHB_1, \
47 1, \
48 SZP2
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
52 #define DO_SCALE \
53 DUP, /* s: a a */ \
54 PUSHB_1, \
55 cvtl_scale, \
56 RCVT, \
57 MUL, /* delta * 2^10 */ \
58 PUSHB_1, \
59 cvtl_0x10000, \
60 RCVT, \
61 DIV, /* delta */ \
62 ADD /* a + delta */
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
71 * bci_round
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
76 * in: val
77 * out: ROUND(val)
80 unsigned char FPGM(bci_round) [] =
83 PUSHB_1,
84 bci_round,
85 FDEF,
87 DUP,
88 ABS,
89 PUSHB_1,
90 32,
91 ADD,
92 FLOOR,
93 SWAP,
94 PUSHB_1,
96 LT,
97 IF,
98 NEG,
99 EIF,
101 ENDF,
107 * bci_compute_stem_width
109 * This is the equivalent to the following code from function
110 * `ta_latin_compute_stem_width':
112 * dist = ABS(width)
114 * if (stem_is_serif
115 * && dist < 3*64)
116 * || is_extra_light:
117 * return width
118 * else if base_is_round:
119 * if dist < 80
120 * dist = 64
121 * else if dist < 56:
122 * dist = 56
124 * delta = ABS(dist - std_width)
126 * if delta < 40:
127 * dist = std_width
128 * if dist < 48
129 * dist = 48
130 * goto End
132 * if dist < 3*64:
133 * delta = dist
134 * dist = FLOOR(dist)
135 * delta = delta - dist
137 * if delta < 10:
138 * dist = dist + delta
139 * else if delta < 32:
140 * dist = dist + 10
141 * else if delta < 54:
142 * dist = dist + 54
143 * else
144 * dist = dist + delta
145 * else
146 * dist = ROUND(dist)
148 * End:
149 * if width < 0:
150 * dist = -dist
151 * return dist
154 * in: width
155 * stem_is_serif
156 * base_is_round
158 * out: new_width
160 * CVT: cvtl_is_extra_light
161 * std_width
164 unsigned char FPGM(bci_compute_stem_width_a) [] =
167 PUSHB_1,
168 bci_compute_stem_width,
169 FDEF,
171 DUP,
172 ABS, /* s: base_is_round stem_is_serif width dist */
174 DUP,
175 PUSHB_1,
176 3*64,
177 LT, /* dist < 3*64 */
179 PUSHB_1,
181 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
182 AND, /* stem_is_serif && dist < 3*64 */
184 PUSHB_1,
185 cvtl_is_extra_light,
186 RCVT,
187 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
189 IF, /* s: base_is_round width dist */
190 POP,
191 SWAP,
192 POP, /* s: width */
194 ELSE,
195 ROLL, /* s: width dist base_is_round */
196 IF, /* s: width dist */
197 DUP,
198 PUSHB_1,
200 LT, /* dist < 80 */
201 IF, /* s: width dist */
202 POP,
203 PUSHB_1,
204 64, /* dist = 64 */
205 EIF,
207 ELSE,
208 DUP,
209 PUSHB_1,
211 LT, /* dist < 56 */
212 IF, /* s: width dist */
213 POP,
214 PUSHB_1,
215 56, /* dist = 56 */
216 EIF,
217 EIF,
219 DUP, /* s: width dist dist */
220 PUSHB_1,
224 /* %c, index of std_width */
226 unsigned char FPGM(bci_compute_stem_width_b) [] =
229 RCVT,
230 SUB,
231 ABS, /* s: width dist delta */
233 PUSHB_1,
235 LT, /* delta < 40 */
236 IF, /* s: width dist */
237 POP,
238 PUSHB_1,
242 /* %c, index of std_width */
244 unsigned char FPGM(bci_compute_stem_width_c) [] =
247 RCVT, /* dist = std_width */
248 DUP,
249 PUSHB_1,
251 LT, /* dist < 48 */
253 POP,
254 PUSHB_1,
255 48, /* dist = 48 */
256 EIF,
258 ELSE,
259 DUP, /* s: width dist dist */
260 PUSHB_1,
261 3*64,
262 LT, /* dist < 3*64 */
264 DUP, /* s: width delta dist */
265 FLOOR, /* dist = FLOOR(dist) */
266 DUP, /* s: width delta dist dist */
267 ROLL,
268 ROLL, /* s: width dist delta dist */
269 SUB, /* delta = delta - dist */
271 DUP, /* s: width dist delta delta */
272 PUSHB_1,
274 LT, /* delta < 10 */
275 IF, /* s: width dist delta */
276 ADD, /* dist = dist + delta */
278 ELSE,
279 DUP,
280 PUSHB_1,
282 LT, /* delta < 32 */
284 POP,
285 PUSHB_1,
287 ADD, /* dist = dist + 10 */
289 ELSE,
290 DUP,
291 PUSHB_1,
293 LT, /* delta < 54 */
295 POP,
296 PUSHB_1,
298 ADD, /* dist = dist + 54 */
300 ELSE,
301 ADD, /* dist = dist + delta */
303 EIF,
304 EIF,
305 EIF,
307 ELSE,
308 PUSHB_1,
309 bci_round,
310 CALL, /* dist = round(dist) */
312 EIF,
313 EIF,
315 SWAP, /* s: dist width */
316 PUSHB_1,
318 LT, /* width < 0 */
320 NEG, /* dist = -dist */
321 EIF,
322 EIF,
324 ENDF,
330 * bci_loop
332 * Take a range and a function number and apply the function to all
333 * elements of the range.
335 * in: func_num
336 * end
337 * start
339 * sal: sal_i (counter initialized with `start')
340 * sal_limit (`end')
341 * sal_func (`func_num')
344 unsigned char FPGM(bci_loop) [] =
347 PUSHB_1,
348 bci_loop,
349 FDEF,
351 PUSHB_1,
352 sal_func,
353 SWAP,
354 WS, /* sal_func = func_num */
355 PUSHB_1,
356 sal_limit,
357 SWAP,
358 WS, /* sal_limit = end */
359 PUSHB_1,
360 sal_i,
361 SWAP,
362 WS, /* sal_i = start */
364 /* start_loop: */
365 PUSHB_1,
366 sal_i,
368 PUSHB_1,
369 sal_limit,
371 LTEQ, /* start <= end */
373 PUSHB_1,
374 sal_func,
376 CALL,
377 PUSHB_3,
378 sal_i,
380 sal_i,
382 ADD, /* start = start + 1 */
385 PUSHB_1,
387 NEG,
388 JMPR, /* goto start_loop */
389 EIF,
391 ENDF,
397 * bci_cvt_rescale
399 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
401 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
402 * consequently, the calculation `a * b/c' is done as `a + delta' with
403 * `delta = a * (b-c)/c'. This avoids overflow.
405 * sal: sal_i (CVT index)
407 * CVT: cvtl_scale
408 * cvtl_0x10000
411 unsigned char FPGM(bci_cvt_rescale) [] =
414 PUSHB_1,
415 bci_cvt_rescale,
416 FDEF,
418 PUSHB_1,
419 sal_i,
421 DUP,
422 RCVT,
423 DO_SCALE,
424 WCVTP,
426 ENDF,
432 * bci_blue_round
434 * Round a blue ref value and adjust its corresponding shoot value.
436 * sal: sal_i (CVT index)
440 unsigned char FPGM(bci_blue_round_a) [] =
443 PUSHB_1,
444 bci_blue_round,
445 FDEF,
447 PUSHB_1,
448 sal_i,
450 DUP,
451 RCVT, /* s: ref_idx ref */
453 DUP,
454 PUSHB_1,
455 bci_round,
456 CALL,
457 SWAP, /* s: ref_idx round(ref) ref */
459 PUSHB_2,
463 /* %c, blue_count */
465 unsigned char FPGM(bci_blue_round_b) [] =
469 CINDEX,
470 ADD, /* s: ref_idx round(ref) ref shoot_idx */
471 DUP,
472 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
474 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
475 SWAP,
476 SUB, /* s: ref_idx round(ref) shoot_idx dist */
477 DUP,
478 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
480 DUP,
481 PUSHB_1,
483 LT, /* delta < 32 */
485 POP,
486 PUSHB_1,
487 0, /* delta = 0 */
489 ELSE,
490 PUSHB_1,
492 LT, /* delta < 48 */
494 PUSHB_1,
495 32, /* delta = 32 */
497 ELSE,
498 PUSHB_1,
499 64, /* delta = 64 */
500 EIF,
501 EIF,
503 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
504 PUSHB_1,
506 LT, /* dist < 0 */
508 NEG, /* delta = -delta */
509 EIF,
511 PUSHB_1,
513 CINDEX,
514 SWAP,
515 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
517 WCVTP,
518 WCVTP,
520 ENDF,
526 * bci_decrement_component_counter
528 * An auxiliary function for composite glyphs.
530 * CVT: cvtl_is_subglyph
533 unsigned char FPGM(bci_decrement_component_counter) [] =
536 PUSHB_1,
537 bci_decrement_component_counter,
538 FDEF,
540 /* decrement `cvtl_is_subglyph' counter */
541 PUSHB_2,
542 cvtl_is_subglyph,
543 cvtl_is_subglyph,
544 RCVT,
545 PUSHB_1,
547 SUB,
548 WCVTP,
550 ENDF,
556 * bci_get_point_extrema
558 * An auxiliary function for `bci_create_segment'.
560 * in: point-1
561 * out: point
563 * sal: sal_point_min
564 * sal_point_max
567 unsigned char FPGM(bci_get_point_extrema) [] =
570 PUSHB_1,
571 bci_get_point_extrema,
572 FDEF,
574 PUSHB_1,
576 ADD, /* s: point */
577 DUP,
578 DUP,
580 /* check whether `point' is a new minimum */
581 PUSHB_1,
582 sal_point_min,
583 RS, /* s: point point point point_min */
584 MD_orig,
585 /* if distance is negative, we have a new minimum */
586 PUSHB_1,
589 IF, /* s: point point */
590 DUP,
591 PUSHB_1,
592 sal_point_min,
593 SWAP,
595 EIF,
597 /* check whether `point' is a new maximum */
598 PUSHB_1,
599 sal_point_max,
600 RS, /* s: point point point_max */
601 MD_orig,
602 /* if distance is positive, we have a new maximum */
603 PUSHB_1,
606 IF, /* s: point */
607 DUP,
608 PUSHB_1,
609 sal_point_max,
610 SWAP,
612 EIF, /* s: point */
614 ENDF,
620 * bci_create_segment
622 * Store start and end point of a segment in the storage area,
623 * then construct a point in the twilight zone to represent it.
625 * This function is used by `bci_create_segment_points'.
627 * in: start
628 * end
629 * [last (if wrap-around segment)]
630 * [first (if wrap-around segment)]
632 * uses: bci_get_point_extrema
634 * sal: sal_i (start of current segment)
635 * sal_j (current twilight point)
636 * sal_point_min
637 * sal_point_max
639 * CVT: cvtl_scale
640 * cvtl_0x10000
641 * cvtl_temp
644 unsigned char FPGM(bci_create_segment) [] =
647 PUSHB_1,
648 bci_create_segment,
649 FDEF,
651 PUSHB_1,
652 sal_i,
654 PUSHB_1,
656 CINDEX,
657 WS, /* sal[sal_i] = start */
659 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
660 PUSHB_3,
661 sal_i,
663 sal_i,
665 ADD, /* sal_i = sal_i + 1 */
668 /* initialize inner loop(s) */
669 PUSHB_2,
670 sal_point_min,
672 CINDEX,
673 WS, /* sal_point_min = start */
674 PUSHB_2,
675 sal_point_max,
677 CINDEX,
678 WS, /* sal_point_max = start */
680 PUSHB_1,
682 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
684 SWAP,
685 DUP,
686 PUSHB_1,
688 CINDEX, /* s: start end end start */
689 LT, /* start > end */
691 /* we have a wrap-around segment with two more arguments */
692 /* to give the last and first point of the contour, respectively; */
693 /* our job is to store a segment `start'-`last', */
694 /* and to get extrema for the two segments */
695 /* `start'-`last' and `first'-`end' */
697 /* s: first last start end */
698 PUSHB_1,
699 sal_i,
701 PUSHB_1,
703 CINDEX,
704 WS, /* sal[sal_i] = last */
706 ROLL,
707 ROLL, /* s: first end last start */
708 DUP,
709 ROLL,
710 SWAP, /* s: first end start last start */
711 SUB, /* s: first end start loop_count */
713 PUSHB_1,
714 bci_get_point_extrema,
715 LOOPCALL,
716 /* clean up stack */
717 POP,
719 SWAP, /* s: end first */
720 PUSHB_1,
722 SUB,
723 DUP,
724 ROLL, /* s: (first - 1) (first - 1) end */
725 SWAP,
726 SUB, /* s: (first - 1) loop_count */
728 PUSHB_1,
729 bci_get_point_extrema,
730 LOOPCALL,
731 /* clean up stack */
732 POP,
734 ELSE, /* s: start end */
735 PUSHB_1,
736 sal_i,
738 PUSHB_1,
740 CINDEX,
741 WS, /* sal[sal_i] = end */
743 PUSHB_1,
745 CINDEX,
746 SUB, /* s: start loop_count */
748 PUSHB_1,
749 bci_get_point_extrema,
750 LOOPCALL,
751 /* clean up stack */
752 POP,
753 EIF,
755 /* the twilight point representing a segment */
756 /* is in the middle between the minimum and maximum */
757 PUSHB_1,
758 sal_point_min,
760 GC_orig,
761 PUSHB_1,
762 sal_point_max,
764 GC_orig,
765 ADD,
766 PUSHB_1,
767 2*64,
768 DIV, /* s: middle_pos */
770 DO_SCALE, /* middle_pos = middle_pos * scale */
772 /* write it to temporary CVT location */
773 PUSHB_2,
774 cvtl_temp,
776 SZP0, /* set zp0 to twilight zone 0 */
777 SWAP,
778 WCVTP,
780 /* create twilight point with index `sal_j' */
781 PUSHB_1,
782 sal_j,
784 PUSHB_1,
785 cvtl_temp,
786 MIAP_noround,
788 PUSHB_3,
789 sal_j,
791 sal_j,
793 ADD, /* twilight_point = twilight_point + 1 */
796 ENDF,
802 * bci_create_segments
804 * Set up segments by defining point ranges which defines them
805 * and computing twilight points to represent them.
807 * in: num_segments (N)
808 * segment_start_0
809 * segment_end_0
810 * [contour_last 0 (if wrap-around segment)]
811 * [contour_first 0 (if wrap-around segment)]
812 * segment_start_1
813 * segment_end_1
814 * [contour_last 0 (if wrap-around segment)]
815 * [contour_first 0 (if wrap-around segment)]
816 * ...
817 * segment_start_(N-1)
818 * segment_end_(N-1)
819 * [contour_last (N-1) (if wrap-around segment)]
820 * [contour_first (N-1) (if wrap-around segment)]
822 * uses: bci_create_segment
824 * sal: sal_i (start of current segment)
825 * sal_j (current twilight point)
827 * CVT: cvtl_is_subglyph
830 unsigned char FPGM(bci_create_segments) [] =
833 PUSHB_1,
834 bci_create_segments,
835 FDEF,
837 /* only do something if we are not a subglyph */
838 PUSHB_2,
840 cvtl_is_subglyph,
841 RCVT,
844 /* all our measurements are taken along the y axis */
845 SVTCA_y,
847 DUP,
848 ADD,
849 PUSHB_1,
851 SUB, /* delta = (2*num_segments - 1) */
853 PUSHB_4,
854 sal_segment_offset,
855 sal_segment_offset,
857 sal_j,
859 WS, /* sal_j = 0 (point offset) */
861 ROLL,
862 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
864 /* `bci_create_segment_point' also increases the loop counter by 1; */
865 /* this effectively means we have a loop step of 2 */
866 PUSHB_2,
867 bci_create_segment,
868 bci_loop,
869 CALL,
871 ELSE,
872 CLEAR,
873 EIF,
875 ENDF,
881 * bci_create_segments_composite
883 * The same as `bci_create_composite'.
884 * It also decrements the composite component counter.
886 * uses: bci_decrement_composite_counter
888 * CVT: cvtl_is_subglyph
891 unsigned char FPGM(bci_create_segments_composite) [] =
894 PUSHB_1,
895 bci_create_segments_composite,
896 FDEF,
898 PUSHB_1,
899 bci_decrement_component_counter,
900 CALL,
902 /* only do something if we are not a subglyph */
903 PUSHB_2,
905 cvtl_is_subglyph,
906 RCVT,
909 /* all our measurements are taken along the y axis */
910 SVTCA_y,
912 DUP,
913 ADD,
914 PUSHB_1,
916 SUB, /* delta = (2*num_segments - 1) */
918 PUSHB_4,
919 sal_segment_offset,
920 sal_segment_offset,
922 sal_j,
924 WS, /* sal_j = 0 (point offset) */
926 ROLL,
927 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
929 /* `bci_create_segment_point' also increases the loop counter by 1; */
930 /* this effectively means we have a loop step of 2 */
931 PUSHB_2,
932 bci_create_segment,
933 bci_loop,
934 CALL,
936 ELSE,
937 CLEAR,
938 EIF,
940 ENDF,
946 * bci_align_segment
948 * Align all points in a segment to the twilight point in rp0.
949 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
951 * in: segment_index
954 unsigned char FPGM(bci_align_segment) [] =
957 PUSHB_1,
958 bci_align_segment,
959 FDEF,
961 /* we need the values of `sal_segment_offset + 2*segment_index' */
962 /* and `sal_segment_offset + 2*segment_index + 1' */
963 DUP,
964 ADD,
965 PUSHB_1,
966 sal_segment_offset,
967 ADD,
968 DUP,
970 SWAP,
971 PUSHB_1,
973 ADD,
974 RS, /* s: first last */
976 /* start_loop: */
977 PUSHB_1,
979 CINDEX, /* s: first last first */
980 PUSHB_1,
982 CINDEX, /* s: first last first last */
983 LTEQ, /* first <= end */
984 IF, /* s: first last */
985 SWAP,
986 DUP, /* s: last first first */
987 ALIGNRP, /* align point with index `first' with rp0 */
989 PUSHB_1,
991 ADD, /* first = first + 1 */
992 SWAP, /* s: first last */
994 PUSHB_1,
996 NEG,
997 JMPR, /* goto start_loop */
999 ELSE,
1000 POP,
1001 POP,
1002 EIF,
1004 ENDF,
1010 * bci_align_segments
1012 * Align segments to the twilight point in rp0.
1013 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1015 * in: first_segment
1016 * loop_counter (N)
1017 * segment_1
1018 * segment_2
1019 * ...
1020 * segment_N
1022 * uses: handle_segment
1026 unsigned char FPGM(bci_align_segments) [] =
1029 PUSHB_1,
1030 bci_align_segments,
1031 FDEF,
1033 PUSHB_1,
1034 bci_align_segment,
1035 CALL,
1037 PUSHB_1,
1038 bci_align_segment,
1039 LOOPCALL,
1041 ENDF,
1047 * bci_scale_contour
1049 * Scale a contour using two points giving the maximum and minimum
1050 * coordinates.
1052 * It expects that no point on the contour is touched.
1054 * in: min_point
1055 * max_point
1057 * CVT: cvtl_scale
1058 * cvtl_0x10000
1061 unsigned char FPGM(bci_scale_contour) [] =
1064 PUSHB_1,
1065 bci_scale_contour,
1066 FDEF,
1068 DUP,
1069 DUP,
1070 GC_orig,
1071 DUP,
1072 DO_SCALE, /* min_pos_new = min_pos * scale */
1073 SWAP,
1074 SUB,
1075 SHPIX,
1077 /* don't scale a single-point contour twice */
1078 SWAP,
1079 DUP,
1080 ROLL,
1081 NEQ,
1083 DUP,
1084 GC_orig,
1085 DUP,
1086 DO_SCALE, /* max_pos_new = max_pos * scale */
1087 SWAP,
1088 SUB,
1089 SHPIX,
1091 ELSE,
1092 POP,
1093 EIF,
1095 ENDF,
1101 * bci_scale_glyph
1103 * Scale a glyph using a list of points (two points per contour, giving
1104 * the maximum and mininum coordinates).
1106 * It expects that no point in the glyph is touched.
1108 * in: num_contours (N)
1109 * min_point_1
1110 * max_point_1
1111 * min_point_2
1112 * max_point_2
1113 * ...
1114 * min_point_N
1115 * max_point_N
1117 * uses: bci_scale_contour
1119 * CVT: cvtl_is_subglyph
1122 unsigned char FPGM(bci_scale_glyph) [] =
1125 PUSHB_1,
1126 bci_scale_glyph,
1127 FDEF,
1129 /* only do something if we are not a subglyph */
1130 PUSHB_2,
1132 cvtl_is_subglyph,
1133 RCVT,
1136 /* all our measurements are taken along the y axis */
1137 SVTCA_y,
1139 PUSHB_1,
1141 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1143 PUSHB_1,
1144 bci_scale_contour,
1145 LOOPCALL,
1147 PUSHB_1,
1149 SZP2, /* set zp2 to normal zone 1 */
1150 IUP_y,
1152 ELSE,
1153 CLEAR,
1154 EIF,
1156 ENDF,
1162 * bci_scale_composite_glyph
1164 * The same as `bci_scale_composite_glyph'.
1165 * It also decrements the composite component counter.
1167 * uses: bci_decrement_component_counter
1169 * CVT: cvtl_is_subglyph
1172 unsigned char FPGM(bci_scale_composite_glyph) [] =
1175 PUSHB_1,
1176 bci_scale_composite_glyph,
1177 FDEF,
1179 PUSHB_1,
1180 bci_decrement_component_counter,
1181 CALL,
1183 /* only do something if we are not a subglyph */
1184 PUSHB_2,
1186 cvtl_is_subglyph,
1187 RCVT,
1190 /* all our measurements are taken along the y axis */
1191 SVTCA_y,
1193 PUSHB_1,
1195 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1197 PUSHB_1,
1198 bci_scale_contour,
1199 LOOPCALL,
1201 PUSHB_1,
1203 SZP2, /* set zp2 to normal zone 1 */
1204 IUP_y,
1206 ELSE,
1207 CLEAR,
1208 EIF,
1210 ENDF,
1216 * bci_shift_contour
1218 * Shift a contour by a given amount.
1220 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1221 * point to the normal zone 1.
1223 * in: contour
1224 * out: contour + 1
1227 unsigned char FPGM(bci_shift_contour) [] =
1230 PUSHB_1,
1231 bci_shift_contour,
1232 FDEF,
1234 DUP,
1235 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1237 PUSHB_1,
1239 ADD,
1241 ENDF,
1247 * bci_shift_subglyph
1249 * Shift a subglyph. To be more specific, it corrects the already applied
1250 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1251 * also.
1253 * If this function is called, a point `x' in the subglyph has been scaled
1254 * already (during the hinting of the subglyph itself), and `offset' has
1255 * been applied also:
1257 * x -> x * scale + offset (1)
1259 * However, the offset should be applied first, then the scaling:
1261 * x -> (x + offset) * scale (2)
1263 * Our job is now to transform (1) to (2); a simple calculation shows that
1264 * we have to shift all points of the subglyph by
1266 * offset * scale - offset = offset * (scale - 1)
1268 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1270 * in: offset (in FUnits)
1271 * num_contours
1272 * first_contour
1274 * CVT: cvtl_funits_to_pixels
1275 * cvtl_0x10000
1276 * cvtl_scale
1279 unsigned char FPGM(bci_shift_subglyph) [] =
1282 PUSHB_1,
1283 bci_shift_subglyph,
1284 FDEF,
1286 SVTCA_y,
1288 PUSHB_1,
1289 cvtl_funits_to_pixels,
1290 RCVT, /* scaling factor FUnits -> pixels */
1291 MUL,
1292 PUSHB_1,
1293 cvtl_0x10000,
1294 RCVT,
1295 DIV,
1297 /* the autohinter always rounds offsets */
1298 PUSHB_1,
1299 bci_round,
1300 CALL, /* offset = round(offset) */
1302 PUSHB_1,
1303 cvtl_scale,
1304 RCVT,
1305 MUL,
1306 PUSHB_1,
1307 cvtl_0x10000,
1308 RCVT,
1309 DIV, /* delta = offset * (scale - 1) */
1311 /* and round again */
1312 PUSHB_1,
1313 bci_round,
1314 CALL, /* offset = round(offset) */
1316 PUSHB_1,
1318 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1320 /* we create twilight point 0 as a reference point, */
1321 /* setting the original position to zero (using `cvtl_temp') */
1322 PUSHB_5,
1325 cvtl_temp,
1326 cvtl_temp,
1328 WCVTP,
1329 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1331 SWAP, /* s: first_contour num_contours 0 delta */
1332 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1334 PUSHB_2,
1335 bci_shift_contour,
1337 SZP2, /* set zp2 to normal zone 1 */
1338 LOOPCALL,
1340 ENDF,
1346 * bci_ip_outer_align_point
1348 * Auxiliary function for `bci_action_ip_before' and
1349 * `bci_action_ip_after'.
1351 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1352 * zone, and both zp1 and zp2 set to normal zone.
1354 * in: point
1356 * sal: sal_i (edge_orig_pos)
1358 * CVT: cvtl_scale
1359 * cvtl_0x10000
1362 unsigned char FPGM(bci_ip_outer_align_point) [] =
1365 PUSHB_1,
1366 bci_ip_outer_align_point,
1367 FDEF,
1369 DUP,
1370 ALIGNRP, /* align `point' with `edge' */
1371 DUP,
1372 GC_orig,
1373 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1375 PUSHB_1,
1376 sal_i,
1378 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1379 SHPIX,
1381 ENDF,
1387 * bci_ip_on_align_points
1389 * Auxiliary function for `bci_action_ip_on'.
1391 * in: edge (in twilight zone)
1392 * loop_counter (N)
1393 * point_1
1394 * point_2
1395 * ...
1396 * point_N
1399 unsigned char FPGM(bci_ip_on_align_points) [] =
1402 PUSHB_1,
1403 bci_ip_on_align_points,
1404 FDEF,
1406 MDAP_noround, /* set rp0 and rp1 to `edge' */
1408 SLOOP,
1409 ALIGNRP,
1411 ENDF,
1417 * bci_ip_between_align_point
1419 * Auxiliary function for `bci_ip_between_align_points'.
1421 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1422 * zone, and both zp1 and zp2 set to normal zone.
1424 * in: point
1426 * sal: sal_i (edge_orig_pos)
1427 * sal_j (stretch_factor)
1429 * CVT: cvtl_scale
1430 * cvtl_0x10000
1433 unsigned char FPGM(bci_ip_between_align_point) [] =
1436 PUSHB_1,
1437 bci_ip_between_align_point,
1438 FDEF,
1440 DUP,
1441 ALIGNRP, /* align `point' with `edge' */
1442 DUP,
1443 GC_orig,
1444 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1446 PUSHB_1,
1447 sal_i,
1449 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1450 PUSHB_1,
1451 sal_j,
1453 MUL, /* s: point delta */
1454 SHPIX,
1456 ENDF,
1462 * bci_ip_between_align_points
1464 * Auxiliary function for `bci_action_ip_between'.
1466 * in: after_edge (in twilight zone)
1467 * before_edge (in twilight zone)
1468 * loop_counter (N)
1469 * point_1
1470 * point_2
1471 * ...
1472 * point_N
1474 * sal: sal_i (before_orig_pos)
1475 * sal_j (stretch_factor)
1477 * uses: bci_ip_between_align_point
1480 unsigned char FPGM(bci_ip_between_align_points) [] =
1483 PUSHB_1,
1484 bci_ip_between_align_points,
1485 FDEF,
1487 PUSHB_2,
1490 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1491 CINDEX,
1492 DUP, /* s: ... before after before before */
1493 MDAP_noround, /* set rp0 and rp1 to `before' */
1494 DUP,
1495 GC_orig, /* s: ... before after before before_orig_pos */
1496 PUSHB_1,
1497 sal_i,
1498 SWAP,
1499 WS, /* sal_i = before_orig_pos */
1500 PUSHB_1,
1502 CINDEX, /* s: ... before after before after */
1503 MD_cur, /* b = after_pos - before_pos */
1504 ROLL,
1505 ROLL,
1506 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
1507 DIV, /* s: a/b */
1508 PUSHB_1,
1509 sal_j,
1510 SWAP,
1511 WS, /* sal_j = stretch_factor */
1513 PUSHB_3,
1514 bci_ip_between_align_point,
1517 SZP2, /* set zp2 to normal zone 1 */
1518 SZP1, /* set zp1 to normal zone 1 */
1519 LOOPCALL,
1521 ENDF,
1527 * bci_action_ip_before
1529 * Handle `ip_before' data to align points located before the first edge.
1531 * in: first_edge (in twilight zone)
1532 * loop_counter (N)
1533 * point_1
1534 * point_2
1535 * ...
1536 * point_N
1538 * sal: sal_i (first_edge_orig_pos)
1540 * uses: bci_ip_outer_align_point
1543 unsigned char FPGM(bci_action_ip_before) [] =
1546 PUSHB_1,
1547 bci_action_ip_before,
1548 FDEF,
1550 PUSHB_1,
1552 SZP2, /* set zp2 to twilight zone 0 */
1554 DUP,
1555 GC_orig,
1556 PUSHB_1,
1557 sal_i,
1558 SWAP,
1559 WS, /* sal_i = first_edge_orig_pos */
1561 PUSHB_3,
1565 SZP2, /* set zp2 to normal zone 1 */
1566 SZP1, /* set zp1 to normal zone 1 */
1567 SZP0, /* set zp0 to twilight zone 0 */
1569 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
1571 PUSHB_1,
1572 bci_ip_outer_align_point,
1573 LOOPCALL,
1575 ENDF,
1581 * bci_action_ip_after
1583 * Handle `ip_after' data to align points located after the last edge.
1585 * in: last_edge (in twilight zone)
1586 * loop_counter (N)
1587 * point_1
1588 * point_2
1589 * ...
1590 * point_N
1592 * sal: sal_i (last_edge_orig_pos)
1594 * uses: bci_ip_outer_align_point
1597 unsigned char FPGM(bci_action_ip_after) [] =
1600 PUSHB_1,
1601 bci_action_ip_after,
1602 FDEF,
1604 PUSHB_1,
1606 SZP2, /* set zp2 to twilight zone 0 */
1608 DUP,
1609 GC_orig,
1610 PUSHB_1,
1611 sal_i,
1612 SWAP,
1613 WS, /* sal_i = last_edge_orig_pos */
1615 PUSHB_3,
1619 SZP2, /* set zp2 to normal zone 1 */
1620 SZP1, /* set zp1 to normal zone 1 */
1621 SZP0, /* set zp0 to twilight zone 0 */
1623 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
1625 PUSHB_1,
1626 bci_ip_outer_align_point,
1627 LOOPCALL,
1629 ENDF,
1635 * bci_action_ip_on
1637 * Handle `ip_on' data to align points located on an edge coordinate (but
1638 * not part of an edge).
1640 * in: loop_counter (M)
1641 * edge_1 (in twilight zone)
1642 * loop_counter (N_1)
1643 * point_1
1644 * point_2
1645 * ...
1646 * point_N_1
1647 * edge_2 (in twilight zone)
1648 * loop_counter (N_2)
1649 * point_1
1650 * point_2
1651 * ...
1652 * point_N_2
1653 * ...
1654 * edge_M (in twilight zone)
1655 * loop_counter (N_M)
1656 * point_1
1657 * point_2
1658 * ...
1659 * point_N_M
1661 * uses: bci_ip_on_align_points
1664 unsigned char FPGM(bci_action_ip_on) [] =
1667 PUSHB_1,
1668 bci_action_ip_on,
1669 FDEF,
1671 PUSHB_2,
1674 SZP1, /* set zp1 to normal zone 1 */
1675 SZP0, /* set zp0 to twilight zone 0 */
1677 PUSHB_1,
1678 bci_ip_on_align_points,
1679 LOOPCALL,
1681 ENDF,
1687 * bci_action_ip_between
1689 * Handle `ip_between' data to align points located between two edges.
1691 * in: loop_counter (M)
1692 * before_edge_1 (in twilight zone)
1693 * after_edge_1 (in twilight zone)
1694 * loop_counter (N_1)
1695 * point_1
1696 * point_2
1697 * ...
1698 * point_N_1
1699 * before_edge_2 (in twilight zone)
1700 * after_edge_2 (in twilight zone)
1701 * loop_counter (N_2)
1702 * point_1
1703 * point_2
1704 * ...
1705 * point_N_2
1706 * ...
1707 * before_edge_M (in twilight zone)
1708 * after_edge_M (in twilight zone)
1709 * loop_counter (N_M)
1710 * point_1
1711 * point_2
1712 * ...
1713 * point_N_M
1715 * uses: bci_ip_between_align_points
1718 unsigned char FPGM(bci_action_ip_between) [] =
1721 PUSHB_1,
1722 bci_action_ip_between,
1723 FDEF,
1725 PUSHB_1,
1726 bci_ip_between_align_points,
1727 LOOPCALL,
1729 ENDF,
1735 * bci_action_adjust_common
1737 * Common code for bci_action_adjust routines.
1740 unsigned char FPGM(bci_action_adjust_common) [] =
1743 PUSHB_1,
1744 bci_action_adjust_common,
1745 FDEF,
1747 PUSHB_1,
1749 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1751 PUSHB_1,
1753 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
1754 PUSHB_1,
1756 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1757 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1759 PUSHB_1,
1760 bci_compute_stem_width,
1761 CALL,
1762 NEG, /* s: [...] edge2 edge -cur_len */
1764 ROLL, /* s: [...] edge -cur_len edge2 */
1765 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1766 SWAP,
1767 DUP,
1768 DUP, /* s: [...] -cur_len edge edge edge */
1769 ALIGNRP, /* align `edge' with `edge2' */
1770 ROLL,
1771 SHPIX, /* shift `edge' by -cur_len */
1773 ENDF,
1779 * bci_action_adjust_bound
1781 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1782 * edge of the stem has already been moved, then moving it again if
1783 * necessary to stay bound.
1785 * in: edge2_is_serif
1786 * edge_is_round
1787 * edge_point (in twilight zone)
1788 * edge2_point (in twilight zone)
1789 * edge[-1] (in twilight zone)
1790 * ... stuff for bci_align_segments (edge) ...
1792 * uses: bci_action_adjust_common
1795 unsigned char FPGM(bci_action_adjust_bound) [] =
1798 PUSHB_1,
1799 bci_action_adjust_bound,
1800 FDEF,
1802 PUSHB_1,
1803 bci_action_adjust_common,
1804 CALL,
1806 SWAP, /* s: edge edge[-1] */
1807 DUP,
1808 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1809 GC_cur,
1810 PUSHB_1,
1812 CINDEX,
1813 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1814 GT, /* edge_pos < edge[-1]_pos */
1816 DUP,
1817 ALIGNRP, /* align `edge' to `edge[-1]' */
1818 EIF,
1820 MDAP_noround, /* set rp0 and rp1 to `edge' */
1822 PUSHB_2,
1823 bci_align_segments,
1825 SZP1, /* set zp1 to normal zone 1 */
1826 CALL,
1828 ENDF,
1834 * bci_action_adjust
1836 * Handle the ADJUST action to align an edge of a stem if the other edge
1837 * of the stem has already been moved.
1839 * in: edge2_is_serif
1840 * edge_is_round
1841 * edge_point (in twilight zone)
1842 * edge2_point (in twilight zone)
1843 * ... stuff for bci_align_segments (edge) ...
1845 * uses: bci_action_adjust_common
1848 unsigned char FPGM(bci_action_adjust) [] =
1851 PUSHB_1,
1852 bci_action_adjust,
1853 FDEF,
1855 PUSHB_1,
1856 bci_action_adjust_common,
1857 CALL,
1859 MDAP_noround, /* set rp0 and rp1 to `edge' */
1861 PUSHB_2,
1862 bci_align_segments,
1864 SZP1, /* set zp1 to normal zone 1 */
1865 CALL,
1867 ENDF,
1873 * bci_action_stem_common
1875 * Common code for bci_action_stem routines.
1878 #undef sal_u_off
1879 #define sal_u_off sal_temp1
1880 #undef sal_d_off
1881 #define sal_d_off sal_temp2
1882 #undef sal_org_len
1883 #define sal_org_len sal_temp3
1884 #undef sal_edge2
1885 #define sal_edge2 sal_temp3
1887 unsigned char FPGM(bci_action_stem_common) [] =
1890 PUSHB_1,
1891 bci_action_stem_common,
1892 FDEF,
1894 PUSHB_1,
1896 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1898 PUSHB_1,
1900 CINDEX,
1901 PUSHB_1,
1903 CINDEX,
1904 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1905 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1907 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1908 DUP,
1909 PUSHB_1,
1910 sal_org_len,
1911 SWAP,
1914 PUSHB_1,
1915 bci_compute_stem_width,
1916 CALL, /* s: [...] edge2 edge cur_len */
1918 DUP,
1919 PUSHB_1,
1921 LT, /* cur_len < 96 */
1923 DUP,
1924 PUSHB_1,
1926 LTEQ, /* cur_len <= 64 */
1928 PUSHB_4,
1929 sal_u_off,
1931 sal_d_off,
1934 ELSE,
1935 PUSHB_4,
1936 sal_u_off,
1938 sal_d_off,
1940 EIF,
1944 SWAP, /* s: [...] edge2 cur_len edge */
1945 DUP,
1946 PUSHB_1,
1947 sal_anchor,
1949 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
1950 ROLL,
1951 SWAP,
1952 MD_orig_ZP2_0,
1953 SWAP,
1954 GC_cur,
1955 ADD, /* s: [...] edge2 cur_len edge org_pos */
1956 PUSHB_1,
1957 sal_org_len,
1959 PUSHB_1,
1960 2*64,
1961 DIV,
1962 ADD, /* s: [...] edge2 cur_len edge org_center */
1964 DUP,
1965 PUSHB_1,
1966 bci_round,
1967 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1969 DUP,
1970 ROLL,
1971 ROLL,
1972 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1974 DUP,
1975 PUSHB_1,
1976 sal_u_off,
1978 ADD,
1979 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1981 SWAP,
1982 PUSHB_1,
1983 sal_d_off,
1985 SUB,
1986 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1988 LT, /* delta1 < delta2 */
1990 PUSHB_1,
1991 sal_u_off,
1993 SUB, /* cur_pos1 = cur_pos1 - u_off */
1995 ELSE,
1996 PUSHB_1,
1997 sal_d_off,
1999 ADD, /* cur_pos1 = cur_pos1 + d_off */
2000 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
2002 PUSHB_1,
2004 CINDEX,
2005 PUSHB_1,
2006 2*64,
2007 DIV,
2008 SUB, /* arg = cur_pos1 - cur_len/2 */
2010 SWAP, /* s: [...] edge2 cur_len arg edge */
2011 DUP,
2012 DUP,
2013 PUSHB_1,
2015 MINDEX,
2016 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2017 GC_cur,
2018 SUB,
2019 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2021 ELSE,
2022 SWAP, /* s: [...] edge2 cur_len edge */
2023 PUSHB_1,
2024 sal_anchor,
2026 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
2027 PUSHB_1,
2029 CINDEX,
2030 PUSHB_1,
2031 sal_anchor,
2033 MD_orig_ZP2_0,
2034 ADD, /* s: [...] edge2 cur_len edge org_pos */
2036 DUP,
2037 PUSHB_1,
2038 sal_org_len,
2040 PUSHB_1,
2041 2*64,
2042 DIV,
2043 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2045 SWAP,
2046 DUP,
2047 PUSHB_1,
2048 bci_round,
2049 CALL, /* cur_pos1 = ROUND(org_pos) */
2050 SWAP,
2051 PUSHB_1,
2052 sal_org_len,
2054 ADD,
2055 PUSHB_1,
2056 bci_round,
2057 CALL,
2058 PUSHB_1,
2060 CINDEX,
2061 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2063 PUSHB_1,
2065 CINDEX,
2066 PUSHB_1,
2067 2*64,
2068 DIV,
2069 PUSHB_1,
2071 MINDEX,
2072 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2074 DUP,
2075 PUSHB_1,
2077 CINDEX,
2078 ADD,
2079 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2080 SWAP,
2081 PUSHB_1,
2083 CINDEX,
2084 ADD,
2085 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2086 LT, /* delta1 < delta2 */
2088 POP, /* arg = cur_pos1 */
2090 ELSE,
2091 SWAP,
2092 POP, /* arg = cur_pos2 */
2093 EIF, /* s: [...] edge2 cur_len edge arg */
2094 SWAP,
2095 DUP,
2096 DUP,
2097 PUSHB_1,
2099 MINDEX,
2100 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2101 GC_cur,
2102 SUB,
2103 SHPIX, /* edge = arg */
2104 EIF, /* s: [...] edge2 cur_len edge */
2106 ENDF,
2112 * bci_action_stem_bound
2114 * Handle the STEM action to align two edges of a stem, then moving one
2115 * edge again if necessary to stay bound.
2117 * The code after computing `cur_len' to shift `edge' and `edge2'
2118 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2120 * if cur_len < 96:
2121 * if cur_len < = 64:
2122 * u_off = 32
2123 * d_off = 32
2124 * else:
2125 * u_off = 38
2126 * d_off = 26
2128 * org_pos = anchor + (edge_orig - anchor_orig);
2129 * org_center = org_pos + org_len / 2;
2131 * cur_pos1 = ROUND(org_center)
2132 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2133 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2134 * if (delta1 < delta2):
2135 * cur_pos1 = cur_pos1 - u_off
2136 * else:
2137 * cur_pos1 = cur_pos1 + d_off
2139 * edge = cur_pos1 - cur_len / 2
2141 * else:
2142 * org_pos = anchor + (edge_orig - anchor_orig)
2143 * org_center = org_pos + org_len / 2;
2145 * cur_pos1 = ROUND(org_pos)
2146 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2147 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2148 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2150 * if (delta1 < delta2):
2151 * edge = cur_pos1
2152 * else:
2153 * edge = cur_pos2
2155 * edge2 = edge + cur_len
2157 * in: edge2_is_serif
2158 * edge_is_round
2159 * edge_point (in twilight zone)
2160 * edge2_point (in twilight zone)
2161 * edge[-1] (in twilight zone)
2162 * ... stuff for bci_align_segments (edge) ...
2163 * ... stuff for bci_align_segments (edge2)...
2165 * sal: sal_anchor
2166 * sal_temp1
2167 * sal_temp2
2168 * sal_temp3
2170 * uses: bci_action_stem_common
2173 unsigned char FPGM(bci_action_stem_bound) [] =
2176 PUSHB_1,
2177 bci_action_stem_bound,
2178 FDEF,
2180 PUSHB_1,
2181 bci_action_stem_common,
2182 CALL,
2184 ROLL, /* s: edge[-1] cur_len edge edge2 */
2185 DUP,
2186 DUP,
2187 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2188 PUSHB_1,
2189 sal_edge2,
2190 SWAP,
2191 WS, /* s: edge[-1] cur_len edge edge2 */
2192 ROLL,
2193 SHPIX, /* edge2 = edge + cur_len */
2195 SWAP, /* s: edge edge[-1] */
2196 DUP,
2197 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2198 GC_cur,
2199 PUSHB_1,
2201 CINDEX,
2202 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2203 GT, /* edge_pos < edge[-1]_pos */
2205 DUP,
2206 ALIGNRP, /* align `edge' to `edge[-1]' */
2207 EIF,
2209 MDAP_noround, /* set rp0 and rp1 to `edge' */
2211 PUSHB_2,
2212 bci_align_segments,
2214 SZP1, /* set zp1 to normal zone 1 */
2215 CALL,
2217 PUSHB_1,
2218 sal_edge2,
2220 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2222 PUSHB_1,
2223 bci_align_segments,
2224 CALL,
2226 ENDF,
2232 * bci_action_stem
2234 * Handle the STEM action to align two edges of a stem.
2236 * See `bci_action_stem_bound' for more details.
2238 * in: edge2_is_serif
2239 * edge_is_round
2240 * edge_point (in twilight zone)
2241 * edge2_point (in twilight zone)
2242 * ... stuff for bci_align_segments (edge) ...
2243 * ... stuff for bci_align_segments (edge2)...
2245 * sal: sal_anchor
2246 * sal_temp1
2247 * sal_temp2
2248 * sal_temp3
2250 * uses: bci_action_stem_common
2253 unsigned char FPGM(bci_action_stem) [] =
2256 PUSHB_1,
2257 bci_action_stem,
2258 FDEF,
2260 PUSHB_1,
2261 bci_action_stem_common,
2262 CALL,
2264 POP,
2265 SWAP, /* s: cur_len edge2 */
2266 DUP,
2267 DUP,
2268 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2269 PUSHB_1,
2270 sal_edge2,
2271 SWAP,
2272 WS, /* s: cur_len edge2 */
2273 SWAP,
2274 SHPIX, /* edge2 = edge + cur_len */
2276 PUSHB_2,
2277 bci_align_segments,
2279 SZP1, /* set zp1 to normal zone 1 */
2280 CALL,
2282 PUSHB_1,
2283 sal_edge2,
2285 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2287 PUSHB_1,
2288 bci_align_segments,
2289 CALL,
2290 ENDF,
2296 * bci_action_link
2298 * Handle the LINK action to link an edge to another one.
2300 * in: stem_is_serif
2301 * base_is_round
2302 * base_point (in twilight zone)
2303 * stem_point (in twilight zone)
2304 * ... stuff for bci_align_segments (base) ...
2307 unsigned char FPGM(bci_action_link) [] =
2310 PUSHB_1,
2311 bci_action_link,
2312 FDEF,
2314 PUSHB_1,
2316 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2318 PUSHB_1,
2320 CINDEX,
2321 PUSHB_1,
2323 MINDEX,
2324 DUP, /* s: stem is_round is_serif stem base base */
2325 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2327 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
2329 PUSHB_1,
2330 bci_compute_stem_width,
2331 CALL, /* s: stem new_dist */
2333 SWAP,
2334 DUP,
2335 ALIGNRP, /* align `stem_point' with `base_point' */
2336 DUP,
2337 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
2338 SWAP,
2339 SHPIX, /* stem_point = base_point + new_dist */
2341 PUSHB_2,
2342 bci_align_segments,
2344 SZP1, /* set zp1 to normal zone 1 */
2345 CALL,
2347 ENDF,
2353 * bci_action_anchor
2355 * Handle the ANCHOR action to align two edges
2356 * and to set the edge anchor.
2358 * The code after computing `cur_len' to shift `edge' and `edge2'
2359 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2361 * if cur_len < 96:
2362 * if cur_len < = 64:
2363 * u_off = 32
2364 * d_off = 32
2365 * else:
2366 * u_off = 38
2367 * d_off = 26
2369 * org_center = edge_orig + org_len / 2
2370 * cur_pos1 = ROUND(org_center)
2372 * error1 = ABS(org_center - (cur_pos1 - u_off))
2373 * error2 = ABS(org_center - (cur_pos1 + d_off))
2374 * if (error1 < error2):
2375 * cur_pos1 = cur_pos1 - u_off
2376 * else:
2377 * cur_pos1 = cur_pos1 + d_off
2379 * edge = cur_pos1 - cur_len / 2
2380 * edge2 = edge + cur_len
2382 * else:
2383 * edge = ROUND(edge_orig)
2385 * in: edge2_is_serif
2386 * edge_is_round
2387 * edge_point (in twilight zone)
2388 * edge2_point (in twilight zone)
2389 * ... stuff for bci_align_segments (edge) ...
2391 * sal: sal_anchor
2392 * sal_temp1
2393 * sal_temp2
2394 * sal_temp3
2397 #undef sal_u_off
2398 #define sal_u_off sal_temp1
2399 #undef sal_d_off
2400 #define sal_d_off sal_temp2
2401 #undef sal_org_len
2402 #define sal_org_len sal_temp3
2404 unsigned char FPGM(bci_action_anchor) [] =
2407 PUSHB_1,
2408 bci_action_anchor,
2409 FDEF,
2411 /* store anchor point number in `sal_anchor' */
2412 PUSHB_2,
2413 sal_anchor,
2415 CINDEX,
2416 WS, /* sal_anchor = edge_point */
2418 PUSHB_1,
2420 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2422 PUSHB_1,
2424 CINDEX,
2425 PUSHB_1,
2427 CINDEX,
2428 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
2429 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2431 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2432 DUP,
2433 PUSHB_1,
2434 sal_org_len,
2435 SWAP,
2438 PUSHB_1,
2439 bci_compute_stem_width,
2440 CALL, /* s: edge2 edge cur_len */
2442 DUP,
2443 PUSHB_1,
2445 LT, /* cur_len < 96 */
2447 DUP,
2448 PUSHB_1,
2450 LTEQ, /* cur_len <= 64 */
2452 PUSHB_4,
2453 sal_u_off,
2455 sal_d_off,
2458 ELSE,
2459 PUSHB_4,
2460 sal_u_off,
2462 sal_d_off,
2464 EIF,
2468 SWAP, /* s: edge2 cur_len edge */
2469 DUP, /* s: edge2 cur_len edge edge */
2471 GC_orig,
2472 PUSHB_1,
2473 sal_org_len,
2475 PUSHB_1,
2476 2*64,
2477 DIV,
2478 ADD, /* s: edge2 cur_len edge org_center */
2480 DUP,
2481 PUSHB_1,
2482 bci_round,
2483 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2485 DUP,
2486 ROLL,
2487 ROLL,
2488 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2490 DUP,
2491 PUSHB_1,
2492 sal_u_off,
2494 ADD,
2495 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2497 SWAP,
2498 PUSHB_1,
2499 sal_d_off,
2501 SUB,
2502 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2504 LT, /* error1 < error2 */
2506 PUSHB_1,
2507 sal_u_off,
2509 SUB, /* cur_pos1 = cur_pos1 - u_off */
2511 ELSE,
2512 PUSHB_1,
2513 sal_d_off,
2515 ADD, /* cur_pos1 = cur_pos1 + d_off */
2516 EIF, /* s: edge2 cur_len edge cur_pos1 */
2518 PUSHB_1,
2520 CINDEX,
2521 PUSHB_1,
2522 2*64,
2523 DIV,
2524 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2526 PUSHB_1,
2528 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2529 GC_cur,
2530 SUB,
2531 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2533 SWAP, /* s: cur_len edge2 */
2534 DUP,
2535 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2536 SWAP,
2537 SHPIX, /* edge2 = edge1 + cur_len */
2539 ELSE,
2540 POP, /* s: edge2 edge */
2541 DUP,
2542 DUP,
2543 GC_cur,
2544 SWAP,
2545 GC_orig,
2546 PUSHB_1,
2547 bci_round,
2548 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2549 SWAP,
2550 SUB,
2551 SHPIX, /* edge = round(edge_orig) */
2553 /* clean up stack */
2554 POP,
2555 EIF,
2557 PUSHB_2,
2558 bci_align_segments,
2560 SZP1, /* set zp1 to normal zone 1 */
2561 CALL,
2563 ENDF,
2569 * bci_action_blue_anchor
2571 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2572 * and to set the edge anchor.
2574 * in: anchor_point (in twilight zone)
2575 * blue_cvt_idx
2576 * edge_point (in twilight zone)
2577 * ... stuff for bci_align_segments (edge) ...
2579 * sal: sal_anchor
2581 * uses: bci_action_blue
2584 unsigned char FPGM(bci_action_blue_anchor) [] =
2587 PUSHB_1,
2588 bci_action_blue_anchor,
2589 FDEF,
2591 /* store anchor point number in `sal_anchor' */
2592 PUSHB_1,
2593 sal_anchor,
2594 SWAP,
2597 PUSHB_1,
2598 bci_action_blue,
2599 CALL,
2601 ENDF,
2607 * bci_action_blue
2609 * Handle the BLUE action to align an edge with a blue zone.
2611 * in: blue_cvt_idx
2612 * edge_point (in twilight zone)
2613 * ... stuff for bci_align_segments (edge) ...
2616 unsigned char FPGM(bci_action_blue) [] =
2619 PUSHB_1,
2620 bci_action_blue,
2621 FDEF,
2623 PUSHB_1,
2625 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2627 /* move `edge_point' to `blue_cvt_idx' position; */
2628 /* note that we can't use MIAP since this would modify */
2629 /* the twilight point's original coordinates also */
2630 RCVT,
2631 SWAP,
2632 DUP,
2633 MDAP_noround, /* set rp0 and rp1 to `edge' */
2634 DUP,
2635 GC_cur, /* s: new_pos edge edge_pos */
2636 ROLL,
2637 SWAP,
2638 SUB, /* s: edge (new_pos - edge_pos) */
2639 SHPIX,
2641 PUSHB_2,
2642 bci_align_segments,
2644 SZP1, /* set zp1 to normal zone 1 */
2645 CALL,
2647 ENDF,
2653 * bci_action_serif_common
2655 * Common code for bci_action_serif routines.
2658 unsigned char FPGM(bci_action_serif_common) [] =
2661 PUSHB_1,
2662 bci_action_serif_common,
2663 FDEF,
2665 PUSHB_1,
2667 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2669 DUP,
2670 DUP,
2671 DUP,
2672 PUSHB_1,
2674 MINDEX, /* s: [...] serif serif serif serif base */
2675 DUP,
2676 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2677 MD_orig_ZP2_0,
2678 SWAP,
2679 ALIGNRP, /* align `serif_point' with `base_point' */
2680 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2682 ENDF,
2688 * bci_lower_bound
2690 * Move an edge if necessary to stay within a lower bound.
2692 * in: edge
2693 * bound
2696 unsigned char FPGM(bci_lower_bound) [] =
2699 PUSHB_1,
2700 bci_lower_bound,
2701 FDEF,
2703 SWAP, /* s: edge bound */
2704 DUP,
2705 MDAP_noround, /* set rp0 and rp1 to `bound' */
2706 GC_cur,
2707 PUSHB_1,
2709 CINDEX,
2710 GC_cur, /* s: edge bound_pos edge_pos */
2711 GT, /* edge_pos < bound_pos */
2713 DUP,
2714 ALIGNRP, /* align `edge' to `bound' */
2715 EIF,
2717 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2719 PUSHB_2,
2720 bci_align_segments,
2722 SZP1, /* set zp1 to normal zone 1 */
2723 CALL,
2725 ENDF,
2731 * bci_upper_bound
2733 * Move an edge if necessary to stay within an upper bound.
2735 * in: edge
2736 * bound
2739 unsigned char FPGM(bci_upper_bound) [] =
2742 PUSHB_1,
2743 bci_upper_bound,
2744 FDEF,
2746 SWAP, /* s: edge bound */
2747 DUP,
2748 MDAP_noround, /* set rp0 and rp1 to `bound' */
2749 GC_cur,
2750 PUSHB_1,
2752 CINDEX,
2753 GC_cur, /* s: edge bound_pos edge_pos */
2754 LT, /* edge_pos > bound_pos */
2756 DUP,
2757 ALIGNRP, /* align `edge' to `bound' */
2758 EIF,
2760 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2762 PUSHB_2,
2763 bci_align_segments,
2765 SZP1, /* set zp1 to normal zone 1 */
2766 CALL,
2768 ENDF,
2774 * bci_lower_upper_bound
2776 * Move an edge if necessary to stay within a lower and lower bound.
2778 * in: edge
2779 * lower
2780 * upper
2783 unsigned char FPGM(bci_lower_upper_bound) [] =
2786 PUSHB_1,
2787 bci_lower_upper_bound,
2788 FDEF,
2790 SWAP, /* s: upper serif lower */
2791 DUP,
2792 MDAP_noround, /* set rp0 and rp1 to `lower' */
2793 GC_cur,
2794 PUSHB_1,
2796 CINDEX,
2797 GC_cur, /* s: upper serif lower_pos serif_pos */
2798 GT, /* serif_pos < lower_pos */
2800 DUP,
2801 ALIGNRP, /* align `serif' to `lower' */
2802 EIF,
2804 SWAP, /* s: serif upper */
2805 DUP,
2806 MDAP_noround, /* set rp0 and rp1 to `upper' */
2807 GC_cur,
2808 PUSHB_1,
2810 CINDEX,
2811 GC_cur, /* s: serif upper_pos serif_pos */
2812 LT, /* serif_pos > upper_pos */
2814 DUP,
2815 ALIGNRP, /* align `serif' to `upper' */
2816 EIF,
2818 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2820 PUSHB_2,
2821 bci_align_segments,
2823 SZP1, /* set zp1 to normal zone 1 */
2824 CALL,
2826 ENDF,
2832 * bci_action_serif
2834 * Handle the SERIF action to align a serif with its base.
2836 * in: serif_point (in twilight zone)
2837 * base_point (in twilight zone)
2838 * ... stuff for bci_align_segments (serif) ...
2840 * uses: bci_action_serif_common
2843 unsigned char FPGM(bci_action_serif) [] =
2846 PUSHB_1,
2847 bci_action_serif,
2848 FDEF,
2850 PUSHB_1,
2851 bci_action_serif_common,
2852 CALL,
2854 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2856 PUSHB_2,
2857 bci_align_segments,
2859 SZP1, /* set zp1 to normal zone 1 */
2860 CALL,
2862 ENDF,
2868 * bci_action_serif_lower_bound
2870 * Handle the SERIF action to align a serif with its base, then moving it
2871 * again if necessary to stay within a lower bound.
2873 * in: serif_point (in twilight zone)
2874 * base_point (in twilight zone)
2875 * edge[-1] (in twilight zone)
2876 * ... stuff for bci_align_segments (serif) ...
2878 * uses: bci_action_serif_common
2879 * bci_lower_bound
2882 unsigned char FPGM(bci_action_serif_lower_bound) [] =
2885 PUSHB_1,
2886 bci_action_serif_lower_bound,
2887 FDEF,
2889 PUSHB_1,
2890 bci_action_serif_common,
2891 CALL,
2893 PUSHB_1,
2894 bci_lower_bound,
2895 CALL,
2897 ENDF,
2903 * bci_action_serif_upper_bound
2905 * Handle the SERIF action to align a serif with its base, then moving it
2906 * again if necessary to stay within an upper bound.
2908 * in: serif_point (in twilight zone)
2909 * base_point (in twilight zone)
2910 * edge[1] (in twilight zone)
2911 * ... stuff for bci_align_segments (serif) ...
2913 * uses: bci_action_serif_common
2914 * bci_upper_bound
2917 unsigned char FPGM(bci_action_serif_upper_bound) [] =
2920 PUSHB_1,
2921 bci_action_serif_upper_bound,
2922 FDEF,
2924 PUSHB_1,
2925 bci_action_serif_common,
2926 CALL,
2928 PUSHB_1,
2929 bci_upper_bound,
2930 CALL,
2932 ENDF,
2938 * bci_action_serif_lower_upper_bound
2940 * Handle the SERIF action to align a serif with its base, then moving it
2941 * again if necessary to stay within a lower and upper bound.
2943 * in: serif_point (in twilight zone)
2944 * base_point (in twilight zone)
2945 * edge[-1] (in twilight zone)
2946 * edge[1] (in twilight zone)
2947 * ... stuff for bci_align_segments (serif) ...
2949 * uses: bci_action_serif_common
2950 * bci_lower_upper_bound
2953 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] =
2956 PUSHB_1,
2957 bci_action_serif_lower_upper_bound,
2958 FDEF,
2960 PUSHB_1,
2962 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2964 PUSHB_1,
2965 bci_action_serif_common,
2966 CALL,
2968 PUSHB_1,
2969 bci_lower_upper_bound,
2970 CALL,
2972 ENDF,
2978 * bci_action_serif_anchor_common
2980 * Common code for bci_action_serif_anchor routines.
2983 unsigned char FPGM(bci_action_serif_anchor_common) [] =
2986 PUSHB_1,
2987 bci_action_serif_anchor_common,
2988 FDEF,
2990 PUSHB_1,
2992 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2994 DUP,
2995 PUSHB_1,
2996 sal_anchor,
2997 SWAP,
2998 WS, /* sal_anchor = edge_point */
3000 DUP,
3001 DUP,
3002 DUP,
3003 GC_cur,
3004 SWAP,
3005 GC_orig,
3006 PUSHB_1,
3007 bci_round,
3008 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
3009 SWAP,
3010 SUB,
3011 SHPIX, /* edge = round(edge_orig) */
3013 ENDF,
3019 * bci_action_serif_anchor
3021 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3022 * anchor.
3024 * in: edge_point (in twilight zone)
3025 * ... stuff for bci_align_segments (edge) ...
3027 * uses: bci_action_serif_anchor_common
3030 unsigned char FPGM(bci_action_serif_anchor) [] =
3033 PUSHB_1,
3034 bci_action_serif_anchor,
3035 FDEF,
3037 PUSHB_1,
3038 bci_action_serif_anchor_common,
3039 CALL,
3041 MDAP_noround, /* set rp0 and rp1 to `edge' */
3043 PUSHB_2,
3044 bci_align_segments,
3046 SZP1, /* set zp1 to normal zone 1 */
3047 CALL,
3049 ENDF,
3055 * bci_action_serif_anchor_lower_bound
3057 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3058 * anchor, then moving it again if necessary to stay within a lower
3059 * bound.
3061 * in: edge_point (in twilight zone)
3062 * edge[-1] (in twilight zone)
3063 * ... stuff for bci_align_segments (edge) ...
3065 * uses: bci_action_serif_anchor_common
3066 * bci_lower_bound
3069 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
3072 PUSHB_1,
3073 bci_action_serif_anchor_lower_bound,
3074 FDEF,
3076 PUSHB_1,
3077 bci_action_serif_anchor_common,
3078 CALL,
3080 PUSHB_1,
3081 bci_lower_bound,
3082 CALL,
3084 ENDF,
3090 * bci_action_serif_anchor_upper_bound
3092 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3093 * anchor, then moving it again if necessary to stay within an upper
3094 * bound.
3096 * in: edge_point (in twilight zone)
3097 * edge[1] (in twilight zone)
3098 * ... stuff for bci_align_segments (edge) ...
3100 * uses: bci_action_serif_anchor_common
3101 * bci_upper_bound
3104 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
3107 PUSHB_1,
3108 bci_action_serif_anchor_upper_bound,
3109 FDEF,
3111 PUSHB_1,
3112 bci_action_serif_anchor_common,
3113 CALL,
3115 PUSHB_1,
3116 bci_upper_bound,
3117 CALL,
3119 ENDF,
3125 * bci_action_serif_anchor_lower_upper_bound
3127 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3128 * anchor, then moving it again if necessary to stay within a lower and
3129 * upper bound.
3131 * in: edge_point (in twilight zone)
3132 * edge[-1] (in twilight zone)
3133 * edge[1] (in twilight zone)
3134 * ... stuff for bci_align_segments (edge) ...
3136 * uses: bci_action_serif_anchor_common
3137 * bci_lower_upper_bound
3140 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] =
3143 PUSHB_1,
3144 bci_action_serif_anchor_lower_upper_bound,
3145 FDEF,
3147 PUSHB_1,
3148 bci_action_serif_anchor_common,
3149 CALL,
3151 PUSHB_1,
3152 bci_lower_upper_bound,
3153 CALL,
3155 ENDF,
3161 * bci_action_serif_link1_common
3163 * Common code for bci_action_serif_link1 routines.
3166 unsigned char FPGM(bci_action_serif_link1_common) [] =
3169 PUSHB_1,
3170 bci_action_serif_link1_common,
3171 FDEF,
3173 PUSHB_1,
3175 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3177 PUSHB_1,
3179 CINDEX, /* s: [...] after edge before after */
3180 PUSHB_1,
3182 CINDEX, /* s: [...] after edge before after before */
3183 MD_orig_ZP2_0,
3184 PUSHB_1,
3186 EQ, /* after_orig_pos == before_orig_pos */
3187 IF, /* s: [...] after edge before */
3188 MDAP_noround, /* set rp0 and rp1 to `before' */
3189 DUP,
3190 ALIGNRP, /* align `edge' with `before' */
3191 SWAP,
3192 POP,
3194 ELSE,
3195 /* we have to execute `a*b/c', with b/c very near to 1: */
3196 /* to avoid overflow while retaining precision, */
3197 /* we transform this to `a + a * (b-c)/c' */
3199 PUSHB_1,
3201 CINDEX, /* s: [...] after edge before edge */
3202 PUSHB_1,
3204 CINDEX, /* s: [...] after edge before edge before */
3205 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3207 DUP,
3208 PUSHB_1,
3210 CINDEX, /* s: [...] after edge before a a after */
3211 PUSHB_1,
3213 CINDEX, /* s: [...] after edge before a a after before */
3214 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3216 PUSHB_1,
3218 CINDEX, /* s: [...] after edge before a a c after */
3219 PUSHB_1,
3221 CINDEX, /* s: [...] after edge before a a c after before */
3222 MD_cur, /* b = after_pos - before_pos */
3224 PUSHB_1,
3226 CINDEX, /* s: [...] after edge before a a c b c */
3227 SUB, /* b-c */
3229 PUSHB_1,
3230 cvtl_0x10000,
3231 RCVT,
3232 MUL, /* (b-c) in 16.16 format */
3233 SWAP,
3234 DIV, /* s: [...] after edge before a a (b-c)/c */
3236 MUL, /* a * (b-c)/c * 2^10 */
3237 PUSHB_1,
3238 cvtl_0x10000,
3239 RCVT,
3240 DIV, /* a * (b-c)/c */
3241 ADD, /* a*b/c */
3243 SWAP,
3244 MDAP_noround, /* set rp0 and rp1 to `before' */
3245 SWAP, /* s: [...] after a*b/c edge */
3246 DUP,
3247 DUP,
3248 ALIGNRP, /* align `edge' with `before' */
3249 ROLL,
3250 SHPIX, /* shift `edge' by `a*b/c' */
3252 SWAP, /* s: [...] edge after */
3253 POP,
3254 EIF,
3256 ENDF,
3262 * bci_action_serif_link1
3264 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3265 * before and after.
3267 * in: before_point (in twilight zone)
3268 * edge_point (in twilight zone)
3269 * after_point (in twilight zone)
3270 * ... stuff for bci_align_segments (edge) ...
3272 * uses: bci_action_serif_link1_common
3275 unsigned char FPGM(bci_action_serif_link1) [] =
3278 PUSHB_1,
3279 bci_action_serif_link1,
3280 FDEF,
3282 PUSHB_1,
3283 bci_action_serif_link1_common,
3284 CALL,
3286 MDAP_noround, /* set rp0 and rp1 to `edge' */
3288 PUSHB_2,
3289 bci_align_segments,
3291 SZP1, /* set zp1 to normal zone 1 */
3292 CALL,
3294 ENDF,
3300 * bci_action_serif_link1_lower_bound
3302 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3303 * before and after. Additionally, move the serif again if necessary to
3304 * stay within a lower bound.
3306 * in: before_point (in twilight zone)
3307 * edge_point (in twilight zone)
3308 * after_point (in twilight zone)
3309 * edge[-1] (in twilight zone)
3310 * ... stuff for bci_align_segments (edge) ...
3312 * uses: bci_action_serif_link1_common
3313 * bci_lower_bound
3316 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
3319 PUSHB_1,
3320 bci_action_serif_link1_lower_bound,
3321 FDEF,
3323 PUSHB_1,
3324 bci_action_serif_link1_common,
3325 CALL,
3327 PUSHB_1,
3328 bci_lower_bound,
3329 CALL,
3331 ENDF,
3337 * bci_action_serif_link1_upper_bound
3339 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3340 * before and after. Additionally, move the serif again if necessary to
3341 * stay within an upper bound.
3343 * in: before_point (in twilight zone)
3344 * edge_point (in twilight zone)
3345 * after_point (in twilight zone)
3346 * edge[1] (in twilight zone)
3347 * ... stuff for bci_align_segments (edge) ...
3349 * uses: bci_action_serif_link1_common
3350 * bci_upper_bound
3353 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
3356 PUSHB_1,
3357 bci_action_serif_link1_upper_bound,
3358 FDEF,
3360 PUSHB_1,
3361 bci_action_serif_link1_common,
3362 CALL,
3364 PUSHB_1,
3365 bci_upper_bound,
3366 CALL,
3368 ENDF,
3374 * bci_action_serif_link1_lower_upper_bound
3376 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3377 * before and after. Additionally, move the serif again if necessary to
3378 * stay within a lower and upper bound.
3380 * in: before_point (in twilight zone)
3381 * edge_point (in twilight zone)
3382 * after_point (in twilight zone)
3383 * edge[-1] (in twilight zone)
3384 * edge[1] (in twilight zone)
3385 * ... stuff for bci_align_segments (edge) ...
3387 * uses: bci_action_serif_link1_common
3388 * bci_lower_upper_bound
3391 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] =
3394 PUSHB_1,
3395 bci_action_serif_link1_lower_upper_bound,
3396 FDEF,
3398 PUSHB_1,
3399 bci_action_serif_link1_common,
3400 CALL,
3402 PUSHB_1,
3403 bci_lower_upper_bound,
3404 CALL,
3406 ENDF,
3412 * bci_action_serif_link2_common
3414 * Common code for bci_action_serif_link2 routines.
3417 unsigned char FPGM(bci_action_serif_link2_common) [] =
3420 PUSHB_1,
3421 bci_action_serif_link2_common,
3422 FDEF,
3424 PUSHB_1,
3426 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3428 DUP, /* s: [...] edge edge */
3429 PUSHB_1,
3430 sal_anchor,
3432 DUP, /* s: [...] edge edge anchor anchor */
3433 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3435 MD_orig_ZP2_0,
3436 DUP,
3437 ADD,
3438 PUSHB_1,
3440 ADD,
3441 FLOOR,
3442 PUSHB_1,
3443 2*64,
3444 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3446 SWAP,
3447 DUP,
3448 DUP,
3449 ALIGNRP, /* align `edge' with `sal_anchor' */
3450 ROLL,
3451 SHPIX, /* shift `edge' by `delta' */
3453 ENDF,
3459 * bci_action_serif_link2
3461 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3463 * in: edge_point (in twilight zone)
3464 * ... stuff for bci_align_segments (edge) ...
3466 * uses: bci_action_serif_link2_common
3469 unsigned char FPGM(bci_action_serif_link2) [] =
3472 PUSHB_1,
3473 bci_action_serif_link2,
3474 FDEF,
3476 PUSHB_1,
3477 bci_action_serif_link2_common,
3478 CALL,
3480 MDAP_noround, /* set rp0 and rp1 to `edge' */
3482 PUSHB_2,
3483 bci_align_segments,
3485 SZP1, /* set zp1 to normal zone 1 */
3486 CALL,
3488 ENDF,
3494 * bci_action_serif_link2_lower_bound
3496 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3497 * Additionally, move the serif again if necessary to stay within a lower
3498 * bound.
3500 * in: edge_point (in twilight zone)
3501 * edge[-1] (in twilight zone)
3502 * ... stuff for bci_align_segments (edge) ...
3504 * uses: bci_action_serif_link2_common
3505 * bci_lower_bound
3508 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
3511 PUSHB_1,
3512 bci_action_serif_link2_lower_bound,
3513 FDEF,
3515 PUSHB_1,
3516 bci_action_serif_link2_common,
3517 CALL,
3519 PUSHB_1,
3520 bci_lower_bound,
3521 CALL,
3523 ENDF,
3529 * bci_action_serif_link2_upper_bound
3531 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3532 * Additionally, move the serif again if necessary to stay within an upper
3533 * bound.
3535 * in: edge_point (in twilight zone)
3536 * edge[1] (in twilight zone)
3537 * ... stuff for bci_align_segments (edge) ...
3539 * uses: bci_action_serif_link2_common
3540 * bci_upper_bound
3543 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
3546 PUSHB_1,
3547 bci_action_serif_link2_upper_bound,
3548 FDEF,
3550 PUSHB_1,
3551 bci_action_serif_link2_common,
3552 CALL,
3554 PUSHB_1,
3555 bci_upper_bound,
3556 CALL,
3558 ENDF,
3564 * bci_action_serif_link2_lower_upper_bound
3566 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3567 * Additionally, move the serif again if necessary to stay within a lower
3568 * and upper bound.
3570 * in: edge_point (in twilight zone)
3571 * edge[-1] (in twilight zone)
3572 * edge[1] (in twilight zone)
3573 * ... stuff for bci_align_segments (edge) ...
3575 * uses: bci_action_serif_link2_common
3576 * bci_lower_upper_bound
3579 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] =
3582 PUSHB_1,
3583 bci_action_serif_link2_lower_upper_bound,
3584 FDEF,
3586 PUSHB_1,
3587 bci_action_serif_link2_common,
3588 CALL,
3590 PUSHB_1,
3591 bci_lower_upper_bound,
3592 CALL,
3594 ENDF,
3600 * bci_handle_action
3602 * Execute function.
3604 * in: function_index
3607 unsigned char FPGM(bci_handle_action) [] =
3610 PUSHB_1,
3611 bci_handle_action,
3612 FDEF,
3614 CALL,
3616 ENDF,
3622 * bci_hint_glyph
3624 * This is the top-level glyph hinting function
3625 * which parses the arguments on the stack and calls subroutines.
3627 * in: num_actions (M)
3628 * action_0_func_idx
3629 * ... data ...
3630 * action_1_func_idx
3631 * ... data ...
3632 * ...
3633 * action_M_func_idx
3634 * ... data ...
3636 * uses: bci_handle_action
3638 * bci_action_ip_before
3639 * bci_action_ip_after
3640 * bci_action_ip_on
3641 * bci_action_ip_between
3643 * bci_action_adjust_bound
3644 * bci_action_stem_bound
3646 * bci_action_link
3647 * bci_action_anchor
3648 * bci_action_blue_anchor
3649 * bci_action_adjust
3650 * bci_action_stem
3651 * bci_action_blue
3653 * bci_action_serif
3654 * bci_action_serif_lower_bound
3655 * bci_action_serif_upper_bound
3656 * bci_action_serif_lower_upper_bound
3658 * bci_action_serif_anchor
3659 * bci_action_serif_anchor_lower_bound
3660 * bci_action_serif_anchor_upper_bound
3661 * bci_action_serif_anchor_lower_upper_bound
3663 * bci_action_serif_link1
3664 * bci_action_serif_link1_lower_bound
3665 * bci_action_serif_link1_upper_bound
3666 * bci_action_serif_link1_lower_upper_bound
3668 * bci_action_serif_link2
3669 * bci_action_serif_link2_lower_bound
3670 * bci_action_serif_link2_upper_bound
3671 * bci_action_serif_link2_lower_upper_bound
3673 * CVT: cvtl_is_subglyph
3676 unsigned char FPGM(bci_hint_glyph) [] =
3679 PUSHB_1,
3680 bci_hint_glyph,
3681 FDEF,
3683 PUSHB_2,
3685 cvtl_is_subglyph,
3686 RCVT,
3689 /* only do something if we are not a subglyph */
3690 PUSHB_1,
3691 bci_handle_action,
3692 LOOPCALL,
3694 PUSHB_1,
3696 SZP2, /* set zp2 to normal zone 1 */
3697 IUP_y,
3699 ELSE,
3700 CLEAR,
3701 EIF,
3703 ENDF,
3708 #define COPY_FPGM(func_name) \
3709 memcpy(buf_p, fpgm_ ## func_name, \
3710 sizeof (fpgm_ ## func_name)); \
3711 buf_p += sizeof (fpgm_ ## func_name) \
3713 static FT_Error
3714 TA_table_build_fpgm(FT_Byte** fpgm,
3715 FT_ULong* fpgm_len,
3716 FONT* font)
3718 FT_UInt buf_len;
3719 FT_UInt len;
3720 FT_Byte* buf;
3721 FT_Byte* buf_p;
3724 buf_len = sizeof (FPGM(bci_round))
3725 + sizeof (FPGM(bci_compute_stem_width_a))
3727 + sizeof (FPGM(bci_compute_stem_width_b))
3729 + sizeof (FPGM(bci_compute_stem_width_c))
3730 + sizeof (FPGM(bci_loop))
3731 + sizeof (FPGM(bci_cvt_rescale))
3732 + sizeof (FPGM(bci_blue_round_a))
3734 + sizeof (FPGM(bci_blue_round_b))
3735 + sizeof (FPGM(bci_decrement_component_counter))
3736 + sizeof (FPGM(bci_get_point_extrema))
3738 + sizeof (FPGM(bci_create_segment))
3739 + sizeof (FPGM(bci_create_segments))
3740 + sizeof (FPGM(bci_create_segments_composite))
3741 + sizeof (FPGM(bci_align_segment))
3742 + sizeof (FPGM(bci_align_segments))
3744 + sizeof (FPGM(bci_scale_contour))
3745 + sizeof (FPGM(bci_scale_glyph))
3746 + sizeof (FPGM(bci_scale_composite_glyph))
3747 + sizeof (FPGM(bci_shift_contour))
3748 + sizeof (FPGM(bci_shift_subglyph))
3750 + sizeof (FPGM(bci_ip_outer_align_point))
3751 + sizeof (FPGM(bci_ip_on_align_points))
3752 + sizeof (FPGM(bci_ip_between_align_point))
3753 + sizeof (FPGM(bci_ip_between_align_points))
3755 + sizeof (FPGM(bci_action_adjust_common))
3756 + sizeof (FPGM(bci_action_stem_common))
3757 + sizeof (FPGM(bci_action_serif_common))
3758 + sizeof (FPGM(bci_action_serif_anchor_common))
3759 + sizeof (FPGM(bci_action_serif_link1_common))
3760 + sizeof (FPGM(bci_action_serif_link2_common))
3762 + sizeof (FPGM(bci_lower_bound))
3763 + sizeof (FPGM(bci_upper_bound))
3764 + sizeof (FPGM(bci_lower_upper_bound))
3766 + sizeof (FPGM(bci_action_ip_before))
3767 + sizeof (FPGM(bci_action_ip_after))
3768 + sizeof (FPGM(bci_action_ip_on))
3769 + sizeof (FPGM(bci_action_ip_between))
3771 + sizeof (FPGM(bci_action_adjust_bound))
3772 + sizeof (FPGM(bci_action_stem_bound))
3773 + sizeof (FPGM(bci_action_link))
3774 + sizeof (FPGM(bci_action_anchor))
3775 + sizeof (FPGM(bci_action_blue_anchor))
3776 + sizeof (FPGM(bci_action_adjust))
3777 + sizeof (FPGM(bci_action_stem))
3778 + sizeof (FPGM(bci_action_blue))
3779 + sizeof (FPGM(bci_action_serif))
3780 + sizeof (FPGM(bci_action_serif_lower_bound))
3781 + sizeof (FPGM(bci_action_serif_upper_bound))
3782 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
3783 + sizeof (FPGM(bci_action_serif_anchor))
3784 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
3785 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
3786 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
3787 + sizeof (FPGM(bci_action_serif_link1))
3788 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
3789 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
3790 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
3791 + sizeof (FPGM(bci_action_serif_link2))
3792 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
3793 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
3794 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
3796 + sizeof (FPGM(bci_handle_action))
3797 + sizeof (FPGM(bci_hint_glyph));
3799 /* buffer length must be a multiple of four */
3800 len = (buf_len + 3) & ~3;
3801 buf = (FT_Byte*)malloc(len);
3802 if (!buf)
3803 return FT_Err_Out_Of_Memory;
3805 /* pad end of buffer with zeros */
3806 buf[len - 1] = 0x00;
3807 buf[len - 2] = 0x00;
3808 buf[len - 3] = 0x00;
3810 /* copy font program into buffer and fill in the missing variables */
3811 buf_p = buf;
3813 COPY_FPGM(bci_round);
3814 COPY_FPGM(bci_compute_stem_width_a);
3815 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3816 COPY_FPGM(bci_compute_stem_width_b);
3817 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3818 COPY_FPGM(bci_compute_stem_width_c);
3819 COPY_FPGM(bci_loop);
3820 COPY_FPGM(bci_cvt_rescale);
3821 COPY_FPGM(bci_blue_round_a);
3822 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
3823 COPY_FPGM(bci_blue_round_b);
3824 COPY_FPGM(bci_decrement_component_counter);
3825 COPY_FPGM(bci_get_point_extrema);
3827 COPY_FPGM(bci_create_segment);
3828 COPY_FPGM(bci_create_segments);
3829 COPY_FPGM(bci_create_segments_composite);
3830 COPY_FPGM(bci_align_segment);
3831 COPY_FPGM(bci_align_segments);
3833 COPY_FPGM(bci_scale_contour);
3834 COPY_FPGM(bci_scale_glyph);
3835 COPY_FPGM(bci_scale_composite_glyph);
3836 COPY_FPGM(bci_shift_contour);
3837 COPY_FPGM(bci_shift_subglyph);
3839 COPY_FPGM(bci_ip_outer_align_point);
3840 COPY_FPGM(bci_ip_on_align_points);
3841 COPY_FPGM(bci_ip_between_align_point);
3842 COPY_FPGM(bci_ip_between_align_points);
3844 COPY_FPGM(bci_action_adjust_common);
3845 COPY_FPGM(bci_action_stem_common);
3846 COPY_FPGM(bci_action_serif_common);
3847 COPY_FPGM(bci_action_serif_anchor_common);
3848 COPY_FPGM(bci_action_serif_link1_common);
3849 COPY_FPGM(bci_action_serif_link2_common);
3851 COPY_FPGM(bci_lower_bound);
3852 COPY_FPGM(bci_upper_bound);
3853 COPY_FPGM(bci_lower_upper_bound);
3855 COPY_FPGM(bci_action_ip_before);
3856 COPY_FPGM(bci_action_ip_after);
3857 COPY_FPGM(bci_action_ip_on);
3858 COPY_FPGM(bci_action_ip_between);
3860 COPY_FPGM(bci_action_adjust_bound);
3861 COPY_FPGM(bci_action_stem_bound);
3862 COPY_FPGM(bci_action_link);
3863 COPY_FPGM(bci_action_anchor);
3864 COPY_FPGM(bci_action_blue_anchor);
3865 COPY_FPGM(bci_action_adjust);
3866 COPY_FPGM(bci_action_stem);
3867 COPY_FPGM(bci_action_blue);
3868 COPY_FPGM(bci_action_serif);
3869 COPY_FPGM(bci_action_serif_lower_bound);
3870 COPY_FPGM(bci_action_serif_upper_bound);
3871 COPY_FPGM(bci_action_serif_lower_upper_bound);
3872 COPY_FPGM(bci_action_serif_anchor);
3873 COPY_FPGM(bci_action_serif_anchor_lower_bound);
3874 COPY_FPGM(bci_action_serif_anchor_upper_bound);
3875 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
3876 COPY_FPGM(bci_action_serif_link1);
3877 COPY_FPGM(bci_action_serif_link1_lower_bound);
3878 COPY_FPGM(bci_action_serif_link1_upper_bound);
3879 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
3880 COPY_FPGM(bci_action_serif_link2);
3881 COPY_FPGM(bci_action_serif_link2_lower_bound);
3882 COPY_FPGM(bci_action_serif_link2_upper_bound);
3883 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
3885 COPY_FPGM(bci_handle_action);
3886 COPY_FPGM(bci_hint_glyph);
3888 *fpgm = buf;
3889 *fpgm_len = buf_len;
3891 return FT_Err_Ok;
3895 FT_Error
3896 TA_sfnt_build_fpgm_table(SFNT* sfnt,
3897 FONT* font)
3899 FT_Error error;
3901 FT_Byte* fpgm_buf;
3902 FT_ULong fpgm_len;
3905 error = TA_sfnt_add_table_info(sfnt);
3906 if (error)
3907 return error;
3909 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
3910 if (error)
3911 return error;
3913 if (fpgm_len > sfnt->max_instructions)
3914 sfnt->max_instructions = fpgm_len;
3916 /* in case of success, `fpgm_buf' gets linked */
3917 /* and is eventually freed in `TA_font_unload' */
3918 error = TA_font_add_table(font,
3919 &sfnt->table_infos[sfnt->num_table_infos - 1],
3920 TTAG_fpgm, fpgm_len, fpgm_buf);
3921 if (error)
3923 free(fpgm_buf);
3924 return error;
3927 return FT_Err_Ok;
3930 /* end of tafpgm.c */