Modify bytecode to create twilight points.
[ttfautohint.git] / src / tafpgm.c
blob681e7271fffa4f4822a9f154cf11648c6ff5c0fb
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011 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 "tabytecode.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 /* in the comments below, the top of the stack (`s:') */
52 /* is the rightmost element; the stack is shown */
53 /* after the instruction on the same line has been executed */
57 * bci_round
59 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
60 * engine specific corrections are applied.
62 * in: val
63 * out: ROUND(val)
66 unsigned char FPGM(bci_round) [] = {
68 PUSHB_1,
69 bci_round,
70 FDEF,
72 DUP,
73 ABS,
74 PUSHB_1,
75 32,
76 ADD,
77 FLOOR,
78 SWAP,
79 PUSHB_1,
81 LT,
82 IF,
83 NEG,
84 EIF,
86 ENDF,
92 * bci_compute_stem_width
94 * This is the equivalent to the following code from function
95 * `ta_latin_compute_stem_width':
97 * dist = ABS(width)
99 * if (stem_is_serif
100 * && dist < 3*64)
101 * || is_extra_light:
102 * return width
103 * else if base_is_round:
104 * if dist < 80
105 * dist = 64
106 * else if dist < 56:
107 * dist = 56
109 * delta = ABS(dist - std_width)
111 * if delta < 40:
112 * dist = std_width
113 * if dist < 48
114 * dist = 48
115 * goto End
117 * if dist < 3*64:
118 * delta = dist
119 * dist = FLOOR(dist)
120 * delta = delta - dist
122 * if delta < 10:
123 * dist = dist + delta
124 * else if delta < 32:
125 * dist = dist + 10
126 * else if delta < 54:
127 * dist = dist + 54
128 * else
129 * dist = dist + delta
130 * else
131 * dist = ROUND(dist)
133 * End:
134 * if width < 0:
135 * dist = -dist
136 * return dist
139 * in: width
140 * stem_is_serif
141 * base_is_round
142 * out: new_width
143 * sal: sal_is_extra_light
144 * CVT: std_width
147 unsigned char FPGM(bci_compute_stem_width_a) [] = {
149 PUSHB_1,
150 bci_compute_stem_width,
151 FDEF,
153 DUP,
154 ABS, /* s: base_is_round stem_is_serif width dist */
156 DUP,
157 PUSHB_1,
158 3*64,
159 LT, /* dist < 3*64 */
161 PUSHB_1,
163 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
164 AND, /* stem_is_serif && dist < 3*64 */
166 PUSHB_1,
167 sal_is_extra_light,
169 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
171 IF, /* s: base_is_round width dist */
172 POP,
173 SWAP,
174 POP, /* s: width */
176 ELSE,
177 ROLL, /* s: width dist base_is_round */
178 IF, /* s: width dist */
179 DUP,
180 PUSHB_1,
182 LT, /* dist < 80 */
183 IF, /* s: width dist */
184 POP,
185 PUSHB_1,
186 64, /* dist = 64 */
187 EIF,
189 ELSE,
190 DUP,
191 PUSHB_1,
193 LT, /* dist < 56 */
194 IF, /* s: width dist */
195 POP,
196 PUSHB_1,
197 56, /* dist = 56 */
198 EIF,
199 EIF,
201 DUP, /* s: width dist dist */
202 PUSHB_1,
206 /* %c, index of std_width */
208 unsigned char FPGM(bci_compute_stem_width_b) [] = {
210 RCVT,
211 SUB,
212 ABS, /* s: width dist delta */
214 PUSHB_1,
216 LT, /* delta < 40 */
217 IF, /* s: width dist */
218 POP,
219 PUSHB_1,
223 /* %c, index of std_width */
225 unsigned char FPGM(bci_compute_stem_width_c) [] = {
227 RCVT, /* dist = std_width */
228 DUP,
229 PUSHB_1,
231 LT, /* dist < 48 */
233 POP,
234 PUSHB_1,
235 48, /* dist = 48 */
236 EIF,
238 ELSE,
239 DUP, /* s: width dist dist */
240 PUSHB_1,
241 3*64,
242 LT, /* dist < 3*64 */
244 DUP, /* s: width delta dist */
245 FLOOR, /* dist = FLOOR(dist) */
246 DUP, /* s: width delta dist dist */
247 ROLL,
248 ROLL, /* s: width dist delta dist */
249 SUB, /* delta = delta - dist */
251 DUP, /* s: width dist delta delta */
252 PUSHB_1,
254 LT, /* delta < 10 */
255 IF, /* s: width dist delta */
256 ADD, /* dist = dist + delta */
258 ELSE,
259 DUP,
260 PUSHB_1,
262 LT, /* delta < 32 */
264 POP,
265 PUSHB_1,
267 ADD, /* dist = dist + 10 */
269 ELSE,
270 DUP,
271 PUSHB_1,
273 LT, /* delta < 54 */
275 POP,
276 PUSHB_1,
278 ADD, /* dist = dist + 54 */
280 ELSE,
281 ADD, /* dist = dist + delta */
283 EIF,
284 EIF,
285 EIF,
287 ELSE,
288 PUSHB_1,
289 bci_round,
290 CALL, /* dist = round(dist) */
292 EIF,
293 EIF,
295 SWAP, /* s: dist width */
296 PUSHB_1,
298 LT, /* width < 0 */
300 NEG, /* dist = -dist */
301 EIF,
302 EIF,
304 ENDF,
310 * bci_loop
312 * Take a range and a function number and apply the function to all
313 * elements of the range.
315 * in: func_num
316 * end
317 * start
319 * uses: sal_i (counter initialized with `start')
320 * sal_limit (`end')
321 * sal_func (`func_num')
324 unsigned char FPGM(bci_loop) [] = {
326 PUSHB_1,
327 bci_loop,
328 FDEF,
330 PUSHB_1,
331 sal_func,
332 SWAP,
333 WS, /* sal_func = func_num */
334 PUSHB_1,
335 sal_limit,
336 SWAP,
337 WS, /* sal_limit = end */
338 PUSHB_1,
339 sal_i,
340 SWAP,
341 WS, /* sal_i = start */
343 /* start_loop: */
344 PUSHB_1,
345 sal_i,
347 PUSHB_1,
348 sal_limit,
350 LTEQ, /* start <= end */
352 PUSHB_1,
353 sal_func,
355 CALL,
356 PUSHB_3,
357 sal_i,
359 sal_i,
361 ADD, /* start = start + 1 */
364 PUSHB_1,
366 NEG,
367 JMPR, /* goto start_loop */
368 EIF,
370 ENDF,
376 * bci_cvt_rescale
378 * Rescale CVT value by a given factor.
380 * uses: sal_i (CVT index)
381 * sal_scale (scale in 16.16 format)
384 unsigned char FPGM(bci_cvt_rescale) [] = {
386 PUSHB_1,
387 bci_cvt_rescale,
388 FDEF,
390 PUSHB_1,
391 sal_i,
393 DUP,
394 RCVT,
395 PUSHB_1,
396 sal_scale,
398 MUL, /* CVT * scale * 2^10 */
399 PUSHB_1,
400 sal_0x10000,
402 DIV, /* CVT * scale */
404 WCVTP,
406 ENDF,
412 * bci_blue_round
414 * Round a blue ref value and adjust its corresponding shoot value.
416 * uses: sal_i (CVT index)
420 unsigned char FPGM(bci_blue_round_a) [] = {
422 PUSHB_1,
423 bci_blue_round,
424 FDEF,
426 PUSHB_1,
427 sal_i,
429 DUP,
430 RCVT, /* s: ref_idx ref */
432 DUP,
433 PUSHB_1,
434 bci_round,
435 CALL,
436 SWAP, /* s: ref_idx round(ref) ref */
438 PUSHB_2,
442 /* %c, blue_count */
444 unsigned char FPGM(bci_blue_round_b) [] = {
447 CINDEX,
448 ADD, /* s: ref_idx round(ref) ref shoot_idx */
449 DUP,
450 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
452 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
453 SWAP,
454 SUB, /* s: ref_idx round(ref) shoot_idx dist */
455 DUP,
456 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
458 DUP,
459 PUSHB_1,
461 LT, /* delta < 32 */
463 POP,
464 PUSHB_1,
465 0, /* delta = 0 */
467 ELSE,
468 PUSHB_1,
470 LT, /* delta < 48 */
472 PUSHB_1,
473 32, /* delta = 32 */
475 ELSE,
476 PUSHB_1,
477 64, /* delta = 64 */
478 EIF,
479 EIF,
481 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
482 PUSHB_1,
484 LT, /* dist < 0 */
486 NEG, /* delta = -delta */
487 EIF,
489 PUSHB_1,
491 CINDEX,
492 SWAP,
493 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
495 WCVTP,
496 WCVTP,
498 ENDF,
504 * bci_get_point_extrema
506 * An auxiliary function for `bci_create_segment'.
508 * in: point-1
509 * out: point
511 * sal: sal_point_min
512 * sal_point_max
515 unsigned char FPGM(bci_get_point_extrema) [] = {
517 PUSHB_1,
518 bci_get_point_extrema,
519 FDEF,
521 PUSHB_1,
523 ADD, /* s: point */
524 DUP,
525 DUP,
527 /* check whether `point' is a new minimum */
528 PUSHB_1,
529 sal_point_min,
530 RS, /* s: point point point point_min */
531 MD_orig,
532 /* if distance is negative, we have a new minimum */
533 PUSHB_1,
536 IF, /* s: point point */
537 DUP,
538 PUSHB_1,
539 sal_point_min,
540 SWAP,
542 EIF,
544 /* check whether `point' is a new maximum */
545 PUSHB_1,
546 sal_point_max,
547 RS, /* s: point point point_max */
548 MD_orig,
549 /* if distance is positive, we have a new maximum */
550 PUSHB_1,
553 IF, /* s: point */
554 DUP,
555 PUSHB_1,
556 sal_point_max,
557 SWAP,
559 EIF, /* s: point */
561 ENDF,
567 * bci_create_segment
569 * Store start and end point of a segment in the storage area,
570 * then construct a point in the twilight zone to represent it.
572 * This function is used by `bci_create_segment_points'.
574 * in: start
575 * end
576 * [last (if wrap-around segment)]
577 * [first (if wrap-around segment)]
579 * uses: bci_get_point_extrema
581 * sal: sal_i (start of current segment)
582 * sal_j (current twilight point)
583 * sal_point_min
584 * sal_point_max
585 * sal_scale
588 unsigned char FPGM(bci_create_segment) [] = {
590 PUSHB_1,
591 bci_create_segment,
592 FDEF,
594 PUSHB_1,
595 sal_i,
597 PUSHB_1,
599 CINDEX,
600 WS, /* sal[sal_i] = start */
602 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
603 PUSHB_3,
604 sal_i,
606 sal_i,
608 ADD, /* sal_i = sal_i + 1 */
611 /* initialize inner loop(s) */
612 PUSHB_2,
613 sal_point_min,
615 CINDEX,
616 WS, /* sal_point_min = start */
617 PUSHB_2,
618 sal_point_max,
620 CINDEX,
621 WS, /* sal_point_max = start */
623 PUSHB_1,
625 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
627 SWAP,
628 DUP,
629 PUSHB_1,
631 CINDEX, /* s: start end end start */
632 LT, /* start > end */
634 /* we have a wrap-around segment with two more arguments */
635 /* to give the last and first point of the contour, respectively; */
636 /* our job is to store a segment `start'-`last', */
637 /* and to get extrema for the two segments */
638 /* `start'-`last' and `first'-`end' */
640 /* s: first last start end */
641 PUSHB_1,
642 sal_i,
644 PUSHB_1,
646 CINDEX,
647 WS, /* sal[sal_i] = last */
649 ROLL,
650 ROLL, /* s: first end last start */
651 DUP,
652 ROLL,
653 SWAP, /* s: first end start last start */
654 SUB, /* s: first end start loop_count */
656 PUSHB_1,
657 bci_get_point_extrema,
658 LOOPCALL,
659 /* clean up stack */
660 POP,
662 SWAP, /* s: end first */
663 PUSHB_1,
665 SUB,
666 DUP,
667 ROLL, /* s: (first - 1) (first - 1) end */
668 SWAP,
669 SUB, /* s: (first - 1) loop_count */
671 PUSHB_1,
672 bci_get_point_extrema,
673 LOOPCALL,
674 /* clean up stack */
675 POP,
677 ELSE, /* s: start end */
678 PUSHB_1,
679 sal_i,
681 PUSHB_1,
683 CINDEX,
684 WS, /* sal[sal_i] = end */
686 PUSHB_1,
688 CINDEX,
689 SUB, /* s: start loop_count */
691 PUSHB_1,
692 bci_get_point_extrema,
693 LOOPCALL,
694 /* clean up stack */
695 POP,
696 EIF,
698 /* the twilight point representing a segment */
699 /* is in the middle between the minimum and maximum */
700 PUSHB_1,
701 sal_point_min,
703 GC_orig,
704 PUSHB_1,
705 sal_point_max,
707 GC_orig,
708 ADD,
709 PUSHB_1,
710 2*64,
711 DIV, /* s: middle_pos */
713 /* now scale it */
714 PUSHB_1,
715 sal_scale,
717 MUL, /* middle_pos * scale * 2^10 */
718 PUSHB_1,
719 sal_0x10000,
721 DIV, /* middle_pos = middle_pos * scale */
723 /* write it to temporary CVT location */
724 PUSHB_2,
725 cvtl_temp,
727 SZP0, /* set zp0 to twilight zone 0 */
728 SWAP,
729 WCVTP,
731 /* create twilight point with index `sal_j' */
732 PUSHB_1,
733 sal_j,
735 PUSHB_1,
736 cvtl_temp,
737 MIAP_noround,
739 PUSHB_3,
740 sal_j,
742 sal_j,
744 ADD, /* twilight_point = twilight_point + 1 */
747 ENDF,
753 * bci_create_segments
755 * Set up segments by defining point ranges which defines them
756 * and computing twilight points to represent them.
758 * in: num_segments (N)
759 * segment_start_0
760 * segment_end_0
761 * [contour_last 0 (if wrap-around segment)]
762 * [contour_first 0 (if wrap-around segment)]
763 * segment_start_1
764 * segment_end_1
765 * [contour_last 0 (if wrap-around segment)]
766 * [contour_first 0 (if wrap-around segment)]
767 * ...
768 * segment_start_(N-1)
769 * segment_end_(N-1)
770 * [contour_last (N-1) (if wrap-around segment)]
771 * [contour_first (N-1) (if wrap-around segment)]
773 * uses: bci_create_segment
775 * sal: sal_i (start of current segment)
776 * sal_j (current twilight point)
777 * sal_num_segments
778 * sal_scale
781 unsigned char FPGM(bci_create_segments) [] = {
783 PUSHB_1,
784 bci_create_segments,
785 FDEF,
787 /* all our measurements are taken along the y axis */
788 SVTCA_y,
790 PUSHB_1,
791 sal_num_segments,
792 SWAP,
793 WS, /* sal_num_segments = num_segments */
795 PUSHB_5,
796 sal_segment_offset,
797 sal_segment_offset,
798 sal_num_segments,
800 sal_j,
802 WS, /* sal_j = 0 (point offset) */
805 DUP,
806 ADD,
807 ADD,
808 PUSHB_1,
810 SUB, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
812 /* `bci_create_segment_point' also increases the loop counter by 1; */
813 /* this effectively means we have a loop step of 2 */
814 PUSHB_2,
815 bci_create_segment,
816 bci_loop,
817 CALL,
819 ENDF,
825 * bci_align_segment
827 * Align all points in a segment to the twilight point in rp0.
828 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
830 * in: segment_index
833 unsigned char FPGM(bci_align_segment) [] = {
835 PUSHB_1,
836 bci_align_segment,
837 FDEF,
839 /* we need the values of `sal_segment_offset + 2*segment_index' */
840 /* and `sal_segment_offset + 2*segment_index + 1' */
841 DUP,
842 ADD,
843 PUSHB_1,
844 sal_segment_offset,
845 ADD,
846 DUP,
848 SWAP,
849 PUSHB_1,
851 ADD,
852 RS, /* s: first last */
854 /* start_loop: */
855 PUSHB_1,
857 CINDEX, /* s: first last first */
858 PUSHB_1,
860 CINDEX, /* s: first last first last */
861 LTEQ, /* first <= end */
862 IF, /* s: first last */
863 SWAP,
864 DUP, /* s: last first first */
865 ALIGNRP, /* align point with index `first' with rp0 */
867 PUSHB_1,
869 ADD, /* first = first + 1 */
870 SWAP, /* s: first last */
872 PUSHB_1,
874 NEG,
875 JMPR, /* goto start_loop */
877 ELSE,
878 POP,
879 POP,
880 EIF,
882 ENDF,
888 * bci_align_segments
890 * Align segments to the twilight point in rp0.
891 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
893 * in: first_segment
894 * loop_counter (N)
895 * segment_1
896 * segment_2
897 * ...
898 * segment_N
900 * uses: handle_segment
904 unsigned char FPGM(bci_align_segments) [] = {
906 PUSHB_1,
907 bci_align_segments,
908 FDEF,
910 PUSHB_1,
911 bci_align_segment,
912 CALL,
914 PUSHB_1,
915 bci_align_segment,
916 LOOPCALL,
918 ENDF,
924 * bci_scale_contour
926 * Scale a contour using two points giving the maximum and minimum
927 * coordinates.
929 * It expects that no point on the contour is touched.
931 * in: min_point
932 * max_point
934 * sal: sal_scale
937 unsigned char FPGM(bci_scale_contour) [] = {
939 PUSHB_1,
940 bci_scale_contour,
941 FDEF,
943 DUP,
944 DUP,
945 GC_orig,
946 DUP,
947 PUSHB_1,
948 sal_scale,
950 MUL, /* min_pos * scale * 2^10 */
951 PUSHB_1,
952 sal_0x10000,
954 DIV, /* min_pos_new = min_pos * scale */
955 SWAP,
956 SUB,
957 SHPIX,
959 /* don't scale a single-point contour twice */
960 SWAP,
961 DUP,
962 ROLL,
963 NEQ,
965 DUP,
966 GC_orig,
967 DUP,
968 PUSHB_1,
969 sal_scale,
971 MUL, /* max_pos * scale * 2^10 */
972 PUSHB_1,
973 sal_0x10000,
975 DIV, /* max_pos_new = max_pos * scale */
976 SWAP,
977 SUB,
978 SHPIX,
980 ELSE,
981 POP,
982 EIF,
984 ENDF,
990 * bci_scale_glyph
992 * Scale a glyph using a list of points (two points per contour, giving
993 * the maximum and mininum coordinates).
995 * It expects that no point in the glyph is touched.
997 * in: num_contours (N)
998 * min_point_1
999 * max_point_1
1000 * min_point_2
1001 * max_point_2
1002 * ...
1003 * min_point_N
1004 * max_point_N
1006 * sal: sal_scale
1008 * uses: bci_scale_contour
1011 unsigned char FPGM(bci_scale_glyph) [] = {
1013 PUSHB_1,
1014 bci_scale_glyph,
1015 FDEF,
1017 SVTCA_y,
1019 PUSHB_1,
1021 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1023 PUSHB_1,
1024 bci_scale_contour,
1025 LOOPCALL,
1027 PUSHB_1,
1029 SZP2, /* set zp2 to normal zone 1 */
1030 IUP_y,
1032 ENDF,
1038 * bci_shift_contour
1040 * Shift a contour by a given amount.
1042 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1043 * point to the normal zone 1.
1045 * in: contour
1046 * out: contour + 1
1049 unsigned char FPGM(bci_shift_contour) [] = {
1051 PUSHB_1,
1052 bci_shift_contour,
1053 FDEF,
1055 DUP,
1056 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1058 PUSHB_1,
1060 ADD,
1062 ENDF,
1068 * bci_shift_subglyph
1070 * Shift a subglyph. To be more specific, it corrects the already applied
1071 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1072 * also.
1074 * If this function is called, a point `x' in the subglyph has been scaled
1075 * by `sal_scale' already (during the hinting of the subglyph itself), and
1076 * `offset' has been applied also:
1078 * x -> x * scale + offset (1)
1080 * However, the offset should be applied first, then the scaling:
1082 * x -> (x + offset) * scale (2)
1084 * Our job is now to transform (1) to (2); a simple calculation shows that
1085 * we have to shift all points of the subglyph by
1087 * offset * scale - offset = offset * (scale - 1)
1089 * in: offset (in FUnits)
1090 * num_contours
1091 * first_contour
1093 * sal: sal_scale
1096 unsigned char FPGM(bci_shift_subglyph) [] = {
1098 PUSHB_1,
1099 bci_shift_subglyph,
1100 FDEF,
1102 SVTCA_y,
1104 PUSHB_1,
1105 cvtl_scale,
1106 RCVT, /* scaling factor FUnits -> pixels */
1107 MUL,
1108 PUSHB_1,
1109 sal_0x10000,
1111 DIV,
1113 /* the autohinter always rounds offsets */
1114 PUSHB_1,
1115 bci_round,
1116 CALL, /* offset = round(offset) */
1118 PUSHB_1,
1119 sal_scale,
1121 PUSHB_1,
1122 sal_0x10000,
1124 SUB, /* scale - 1 (in 16.16 format) */
1125 MUL,
1126 PUSHB_1,
1127 sal_0x10000,
1129 DIV, /* delta = offset * (scale - 1) */
1131 /* and round again */
1132 PUSHB_1,
1133 bci_round,
1134 CALL, /* offset = round(offset) */
1136 PUSHB_1,
1138 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1140 /* we create twilight point 0 as a reference point, */
1141 /* setting the original position to zero (using `cvtl_temp') */
1142 PUSHB_5,
1145 cvtl_temp,
1146 cvtl_temp,
1148 WCVTP,
1149 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1151 SWAP, /* s: first_contour num_contours 0 delta */
1152 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1154 PUSHB_2,
1155 bci_shift_contour,
1157 SZP2, /* set zp2 to normal zone 1 */
1158 LOOPCALL,
1160 ENDF,
1166 * bci_ip_outer_align_point
1168 * Auxiliary function for `bci_action_ip_before' and
1169 * `bci_action_ip_after'.
1171 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1172 * zone, and both zp1 and zp2 set to normal zone.
1174 * in: point
1176 * sal: sal_i (edge_orig_pos)
1179 unsigned char FPGM(bci_ip_outer_align_point) [] = {
1181 PUSHB_1,
1182 bci_ip_outer_align_point,
1183 FDEF,
1185 DUP,
1186 ALIGNRP, /* align `point' with `edge' */
1187 DUP,
1188 GC_orig,
1189 /* now scale it */
1190 PUSHB_1,
1191 sal_scale,
1193 MUL, /* point_orig_pos * scale * 2^10 */
1194 PUSHB_1,
1195 sal_0x10000,
1197 DIV, /* point_orig_pos = point_orig_pos * scale */
1199 PUSHB_1,
1200 sal_i,
1202 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1203 SHPIX,
1205 ENDF,
1211 * bci_ip_on_align_points
1213 * Auxiliary function for `bci_action_ip_on'.
1215 * in: edge (in twilight zone)
1216 * loop_counter (N)
1217 * point_1
1218 * point_2
1219 * ...
1220 * point_N
1223 unsigned char FPGM(bci_ip_on_align_points) [] = {
1225 PUSHB_1,
1226 bci_ip_on_align_points,
1227 FDEF,
1229 MDAP_noround, /* set rp0 and rp1 to `edge' */
1231 SLOOP,
1232 ALIGNRP,
1234 ENDF,
1240 * bci_ip_between_align_point
1242 * Auxiliary function for `bci_ip_between_align_points'.
1244 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1245 * zone, and both zp1 and zp2 set to normal zone.
1247 * in: point
1249 * sal: sal_i (edge_orig_pos)
1250 * sal_j (stretch_factor)
1253 unsigned char FPGM(bci_ip_between_align_point) [] = {
1255 PUSHB_1,
1256 bci_ip_between_align_point,
1257 FDEF,
1259 DUP,
1260 ALIGNRP, /* align `point' with `edge' */
1261 DUP,
1262 GC_orig,
1263 /* now scale it */
1264 PUSHB_1,
1265 sal_scale,
1267 MUL, /* point_orig_pos * scale * 2^10 */
1268 PUSHB_1,
1269 sal_0x10000,
1271 DIV, /* point_orig_pos = point_orig_pos * scale */
1273 PUSHB_1,
1274 sal_i,
1276 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1277 PUSHB_1,
1278 sal_j,
1280 MUL, /* s: point delta */
1281 SHPIX,
1283 ENDF,
1289 * bci_ip_between_align_points
1291 * Auxiliary function for `bci_action_ip_between'.
1293 * in: after_edge (in twilight zone)
1294 * before_edge (in twilight zone)
1295 * loop_counter (N)
1296 * point_1
1297 * point_2
1298 * ...
1299 * point_N
1301 * sal: sal_i (before_orig_pos)
1302 * sal_j (stretch_factor)
1304 * uses: bci_ip_between_align_point
1307 unsigned char FPGM(bci_ip_between_align_points) [] = {
1309 PUSHB_1,
1310 bci_ip_between_align_points,
1311 FDEF,
1313 PUSHB_2,
1316 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1317 CINDEX,
1318 DUP, /* s: ... before after before before */
1319 MDAP_noround, /* set rp0 and rp1 to `before' */
1320 DUP,
1321 GC_orig, /* s: ... before after before before_orig_pos */
1322 PUSHB_1,
1323 sal_i,
1324 SWAP,
1325 WS, /* sal_i = before_orig_pos */
1326 PUSHB_1,
1328 CINDEX, /* s: ... before after before after */
1329 MD_cur, /* b = after_pos - before_pos */
1330 ROLL,
1331 ROLL,
1332 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
1333 DIV, /* s: a/b */
1334 PUSHB_1,
1335 sal_j,
1336 SWAP,
1337 WS, /* sal_j = stretch_factor */
1339 PUSHB_3,
1340 bci_ip_between_align_point,
1343 SZP2, /* set zp2 to normal zone 1 */
1344 SZP1, /* set zp1 to normal zone 1 */
1345 LOOPCALL,
1347 ENDF,
1353 * bci_action_ip_before
1355 * Handle `ip_before' data to align points located before the first edge.
1357 * in: first_edge (in twilight zone)
1358 * loop_counter (N)
1359 * point_1
1360 * point_2
1361 * ...
1362 * point_N
1364 * sal: sal_i (first_edge_orig_pos)
1366 * uses: bci_ip_outer_align_point
1369 unsigned char FPGM(bci_action_ip_before) [] = {
1371 PUSHB_1,
1372 bci_action_ip_before,
1373 FDEF,
1375 PUSHB_1,
1377 SZP2, /* set zp2 to twilight zone 0 */
1379 DUP,
1380 GC_orig,
1381 PUSHB_1,
1382 sal_i,
1383 SWAP,
1384 WS, /* sal_i = first_edge_orig_pos */
1386 PUSHB_3,
1390 SZP2, /* set zp2 to normal zone 1 */
1391 SZP1, /* set zp1 to normal zone 1 */
1392 SZP0, /* set zp0 to twilight zone 0 */
1394 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
1396 PUSHB_1,
1397 bci_ip_outer_align_point,
1398 LOOPCALL,
1400 ENDF,
1406 * bci_action_ip_after
1408 * Handle `ip_after' data to align points located after the last edge.
1410 * in: last_edge (in twilight zone)
1411 * loop_counter (N)
1412 * point_1
1413 * point_2
1414 * ...
1415 * point_N
1417 * sal: sal_i (last_edge_orig_pos)
1419 * uses: bci_ip_outer_align_point
1422 unsigned char FPGM(bci_action_ip_after) [] = {
1424 PUSHB_1,
1425 bci_action_ip_after,
1426 FDEF,
1428 PUSHB_1,
1430 SZP2, /* set zp2 to twilight zone 0 */
1432 DUP,
1433 GC_orig,
1434 PUSHB_1,
1435 sal_i,
1436 SWAP,
1437 WS, /* sal_i = last_edge_orig_pos */
1439 PUSHB_3,
1443 SZP2, /* set zp2 to normal zone 1 */
1444 SZP1, /* set zp1 to normal zone 1 */
1445 SZP0, /* set zp0 to twilight zone 0 */
1447 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
1449 PUSHB_1,
1450 bci_ip_outer_align_point,
1451 LOOPCALL,
1453 ENDF,
1459 * bci_action_ip_on
1461 * Handle `ip_on' data to align points located on an edge coordinate (but
1462 * not part of an edge).
1464 * in: loop_counter (M)
1465 * edge_1 (in twilight zone)
1466 * loop_counter (N_1)
1467 * point_1
1468 * point_2
1469 * ...
1470 * point_N_1
1471 * edge_2 (in twilight zone)
1472 * loop_counter (N_2)
1473 * point_1
1474 * point_2
1475 * ...
1476 * point_N_2
1477 * ...
1478 * edge_M (in twilight zone)
1479 * loop_counter (N_M)
1480 * point_1
1481 * point_2
1482 * ...
1483 * point_N_M
1485 * uses: bci_ip_on_align_points
1488 unsigned char FPGM(bci_action_ip_on) [] = {
1490 PUSHB_1,
1491 bci_action_ip_on,
1492 FDEF,
1494 PUSHB_2,
1497 SZP1, /* set zp1 to normal zone 1 */
1498 SZP0, /* set zp0 to twilight zone 0 */
1500 PUSHB_1,
1501 bci_ip_on_align_points,
1502 LOOPCALL,
1504 ENDF,
1510 * bci_action_ip_between
1512 * Handle `ip_between' data to align points located between two edges.
1514 * in: loop_counter (M)
1515 * before_edge_1 (in twilight zone)
1516 * after_edge_1 (in twilight zone)
1517 * loop_counter (N_1)
1518 * point_1
1519 * point_2
1520 * ...
1521 * point_N_1
1522 * before_edge_2 (in twilight zone)
1523 * after_edge_2 (in twilight zone)
1524 * loop_counter (N_2)
1525 * point_1
1526 * point_2
1527 * ...
1528 * point_N_2
1529 * ...
1530 * before_edge_M (in twilight zone)
1531 * after_edge_M (in twilight zone)
1532 * loop_counter (N_M)
1533 * point_1
1534 * point_2
1535 * ...
1536 * point_N_M
1538 * uses: bci_ip_between_align_points
1541 unsigned char FPGM(bci_action_ip_between) [] = {
1543 PUSHB_1,
1544 bci_action_ip_between,
1545 FDEF,
1547 PUSHB_1,
1548 bci_ip_between_align_points,
1549 LOOPCALL,
1551 ENDF,
1557 * bci_action_adjust_bound
1559 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1560 * edge of the stem has already been moved, then moving it again if
1561 * necessary to stay bound.
1563 * in: edge2_is_serif
1564 * edge_is_round
1565 * edge_point (in twilight zone)
1566 * edge2_point (in twilight zone)
1567 * edge[-1] (in twilight zone)
1568 * ... stuff for bci_align_segments (edge) ...
1571 unsigned char FPGM(bci_action_adjust_bound) [] = {
1573 PUSHB_1,
1574 bci_action_adjust_bound,
1575 FDEF,
1577 PUSHB_1,
1579 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1581 PUSHB_1,
1583 CINDEX, /* s: edge[-1] edge2 edge is_round is_serif edge2 */
1584 PUSHB_1,
1586 CINDEX, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge */
1587 MD_orig_ZP2_0, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1589 PUSHB_1,
1590 bci_compute_stem_width,
1591 CALL,
1592 NEG, /* s: edge[-1] edge2 edge -cur_len */
1594 ROLL, /* s: edge[-1] edge -cur_len edge2 */
1595 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1596 SWAP,
1597 DUP,
1598 DUP, /* s: edge[-1] -cur_len edge edge edge */
1599 ALIGNRP, /* align `edge' with `edge2' */
1600 ROLL,
1601 SHPIX, /* shift `edge' by -cur_len */
1603 SWAP, /* s: edge edge[-1] */
1604 DUP,
1605 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1606 GC_cur,
1607 PUSHB_1,
1609 CINDEX,
1610 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1611 GT, /* edge_pos < edge[-1]_pos */
1613 DUP,
1614 ALIGNRP, /* align `edge' to `edge[-1]' */
1615 EIF,
1617 MDAP_noround, /* set rp0 and rp1 to `edge' */
1619 PUSHB_2,
1620 bci_align_segments,
1622 SZP1, /* set zp1 to normal zone 1 */
1623 CALL,
1625 ENDF,
1631 * bci_action_stem_bound
1633 * Handle the STEM action to align two edges of a stem, then moving one
1634 * edge again if necessary to stay bound.
1636 * The code after computing `cur_len' to shift `edge' and `edge2'
1637 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1639 * if cur_len < 96:
1640 * if cur_len < = 64:
1641 * u_off = 32
1642 * d_off = 32
1643 * else:
1644 * u_off = 38
1645 * d_off = 26
1647 * org_pos = anchor + (edge_orig - anchor_orig);
1648 * org_center = org_pos + org_len / 2;
1650 * cur_pos1 = ROUND(org_center)
1651 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1652 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1653 * if (delta1 < delta2):
1654 * cur_pos1 = cur_pos1 - u_off
1655 * else:
1656 * cur_pos1 = cur_pos1 + d_off
1658 * edge = cur_pos1 - cur_len / 2
1660 * else:
1661 * org_pos = anchor + (edge_orig - anchor_orig)
1662 * org_center = org_pos + org_len / 2;
1664 * cur_pos1 = ROUND(org_pos)
1665 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1666 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1667 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1669 * if (delta1 < delta2):
1670 * edge = cur_pos1
1671 * else:
1672 * edge = cur_pos2
1674 * edge2 = edge + cur_len
1676 * in: edge2_is_serif
1677 * edge_is_round
1678 * edge_point (in twilight zone)
1679 * edge2_point (in twilight zone)
1680 * edge[-1] (in twilight zone)
1681 * ... stuff for bci_align_segments (edge) ...
1682 * ... stuff for bci_align_segments (edge2)...
1684 * sal: sal_anchor
1685 * sal_temp1
1686 * sal_temp2
1687 * sal_temp3
1688 * sal_num_segments
1691 #undef sal_u_off
1692 #define sal_u_off sal_temp1
1693 #undef sal_d_off
1694 #define sal_d_off sal_temp2
1695 #undef sal_org_len
1696 #define sal_org_len sal_temp3
1697 #undef sal_edge2
1698 #define sal_edge2 sal_temp3
1700 unsigned char FPGM(bci_action_stem_bound) [] = {
1702 PUSHB_1,
1703 bci_action_stem_bound,
1704 FDEF,
1706 PUSHB_1,
1708 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1710 PUSHB_1,
1712 CINDEX,
1713 PUSHB_1,
1715 CINDEX,
1716 DUP, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge edge */
1717 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1719 MD_orig_ZP2_0, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1720 DUP,
1721 PUSHB_1,
1722 sal_org_len,
1723 SWAP,
1726 PUSHB_1,
1727 bci_compute_stem_width,
1728 CALL, /* s: edge[-1] edge2 edge cur_len */
1730 DUP,
1731 PUSHB_1,
1733 LT, /* cur_len < 96 */
1735 DUP,
1736 PUSHB_1,
1738 LTEQ, /* cur_len <= 64 */
1740 PUSHB_4,
1741 sal_u_off,
1743 sal_d_off,
1746 ELSE,
1747 PUSHB_4,
1748 sal_u_off,
1750 sal_d_off,
1752 EIF,
1756 SWAP, /* s: edge[-1] edge2 cur_len edge */
1757 DUP,
1758 PUSHB_1,
1759 sal_anchor,
1761 DUP, /* s: edge[-1] edge2 cur_len edge edge anchor anchor */
1762 ROLL,
1763 SWAP,
1764 MD_orig_ZP2_0,
1765 SWAP,
1766 GC_cur,
1767 ADD, /* s: edge[-1] edge2 cur_len edge org_pos */
1768 PUSHB_1,
1769 sal_org_len,
1771 PUSHB_1,
1772 2*64,
1773 DIV,
1774 ADD, /* s: edge[-1] edge2 cur_len edge org_center */
1776 DUP,
1777 PUSHB_1,
1778 bci_round,
1779 CALL, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1781 DUP,
1782 ROLL,
1783 ROLL,
1784 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1786 DUP,
1787 PUSHB_1,
1788 sal_u_off,
1790 ADD,
1791 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1793 SWAP,
1794 PUSHB_1,
1795 sal_d_off,
1797 SUB,
1798 ABS, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1800 LT, /* delta1 < delta2 */
1802 PUSHB_1,
1803 sal_u_off,
1805 SUB, /* cur_pos1 = cur_pos1 - u_off */
1807 ELSE,
1808 PUSHB_1,
1809 sal_d_off,
1811 ADD, /* cur_pos1 = cur_pos1 + d_off */
1812 EIF, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1814 PUSHB_1,
1816 CINDEX,
1817 PUSHB_1,
1818 2*64,
1819 DIV,
1820 SUB, /* arg = cur_pos1 - cur_len/2 */
1822 SWAP, /* s: edge[-1] edge2 cur_len arg edge */
1823 DUP,
1824 DUP,
1825 PUSHB_1,
1827 MINDEX,
1828 SWAP, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1829 GC_cur,
1830 SUB,
1831 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1833 ELSE,
1834 SWAP, /* s: edge[-1] edge2 cur_len edge */
1835 PUSHB_1,
1836 sal_anchor,
1838 GC_cur, /* s: edge[-1] edge2 cur_len edge anchor_pos */
1839 PUSHB_1,
1841 CINDEX,
1842 PUSHB_1,
1843 sal_anchor,
1845 MD_orig_ZP2_0,
1846 ADD, /* s: edge[-1] edge2 cur_len edge org_pos */
1848 DUP,
1849 PUSHB_1,
1850 sal_org_len,
1852 PUSHB_1,
1853 2*64,
1854 DIV,
1855 ADD, /* s: edge[-1] edge2 cur_len edge org_pos org_center */
1857 SWAP,
1858 DUP,
1859 PUSHB_1,
1860 bci_round,
1861 CALL, /* cur_pos1 = ROUND(org_pos) */
1862 SWAP,
1863 PUSHB_1,
1864 sal_org_len,
1866 ADD,
1867 PUSHB_1,
1868 bci_round,
1869 CALL,
1870 PUSHB_1,
1872 CINDEX,
1873 SUB, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1875 PUSHB_1,
1877 CINDEX,
1878 PUSHB_1,
1879 2*64,
1880 DIV,
1881 PUSHB_1,
1883 MINDEX,
1884 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1886 DUP,
1887 PUSHB_1,
1889 CINDEX,
1890 ADD,
1891 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1892 SWAP,
1893 PUSHB_1,
1895 CINDEX,
1896 ADD,
1897 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1898 LT, /* delta1 < delta2 */
1900 POP, /* arg = cur_pos1 */
1902 ELSE,
1903 SWAP,
1904 POP, /* arg = cur_pos2 */
1905 EIF, /* s: edge[-1] edge2 cur_len edge arg */
1906 SWAP,
1907 DUP,
1908 DUP,
1909 PUSHB_1,
1911 MINDEX,
1912 SWAP, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1913 GC_cur,
1914 SUB,
1915 SHPIX, /* edge = arg */
1916 EIF, /* s: edge[-1] edge2 cur_len edge */
1918 ROLL, /* s: edge[-1] cur_len edge edge2 */
1919 DUP,
1920 DUP,
1921 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
1922 PUSHB_1,
1923 sal_edge2,
1924 SWAP,
1925 WS, /* s: edge[-1] cur_len edge edge2 */
1926 ROLL,
1927 SHPIX, /* edge2 = edge + cur_len */
1929 SWAP, /* s: edge edge[-1] */
1930 DUP,
1931 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1932 GC_cur,
1933 PUSHB_1,
1935 CINDEX,
1936 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1937 GT, /* edge_pos < edge[-1]_pos */
1939 DUP,
1940 ALIGNRP, /* align `edge' to `edge[-1]' */
1941 EIF,
1943 MDAP_noround, /* set rp0 and rp1 to `edge' */
1945 PUSHB_2,
1946 bci_align_segments,
1948 SZP1, /* set zp1 to normal zone 1 */
1949 CALL,
1951 PUSHB_1,
1952 sal_edge2,
1954 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1956 PUSHB_1,
1957 bci_align_segments,
1958 CALL,
1960 ENDF,
1966 * bci_action_link
1968 * Handle the LINK action to link an edge to another one.
1970 * in: stem_is_serif
1971 * base_is_round
1972 * base_point (in twilight zone)
1973 * stem_point (in twilight zone)
1974 * ... stuff for bci_align_segments (base) ...
1977 unsigned char FPGM(bci_action_link) [] = {
1979 PUSHB_1,
1980 bci_action_link,
1981 FDEF,
1983 PUSHB_1,
1985 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1987 PUSHB_1,
1989 CINDEX,
1990 PUSHB_1,
1992 MINDEX,
1993 DUP, /* s: stem is_round is_serif stem base base */
1994 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1996 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
1998 PUSHB_1,
1999 bci_compute_stem_width,
2000 CALL, /* s: stem new_dist */
2002 SWAP,
2003 DUP,
2004 ALIGNRP, /* align `stem_point' with `base_point' */
2005 DUP,
2006 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
2007 SWAP,
2008 SHPIX, /* stem_point = base_point + new_dist */
2010 PUSHB_2,
2011 bci_align_segments,
2013 SZP1, /* set zp1 to normal zone 1 */
2014 CALL,
2016 ENDF,
2022 * bci_action_anchor
2024 * Handle the ANCHOR action to align two edges
2025 * and to set the edge anchor.
2027 * The code after computing `cur_len' to shift `edge' and `edge2'
2028 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2030 * if cur_len < 96:
2031 * if cur_len < = 64:
2032 * u_off = 32
2033 * d_off = 32
2034 * else:
2035 * u_off = 38
2036 * d_off = 26
2038 * org_center = edge_orig + org_len / 2
2039 * cur_pos1 = ROUND(org_center)
2041 * error1 = ABS(org_center - (cur_pos1 - u_off))
2042 * error2 = ABS(org_center - (cur_pos1 + d_off))
2043 * if (error1 < error2):
2044 * cur_pos1 = cur_pos1 - u_off
2045 * else:
2046 * cur_pos1 = cur_pos1 + d_off
2048 * edge = cur_pos1 - cur_len / 2
2049 * edge2 = edge + cur_len
2051 * else:
2052 * edge = ROUND(edge_orig)
2054 * in: edge2_is_serif
2055 * edge_is_round
2056 * edge_point (in twilight zone)
2057 * edge2_point (in twilight zone)
2058 * ... stuff for bci_align_segments (edge) ...
2060 * sal: sal_anchor
2061 * sal_temp1
2062 * sal_temp2
2063 * sal_temp3
2066 #undef sal_u_off
2067 #define sal_u_off sal_temp1
2068 #undef sal_d_off
2069 #define sal_d_off sal_temp2
2070 #undef sal_org_len
2071 #define sal_org_len sal_temp3
2073 unsigned char FPGM(bci_action_anchor) [] = {
2075 PUSHB_1,
2076 bci_action_anchor,
2077 FDEF,
2079 /* store anchor point number in `sal_anchor' */
2080 PUSHB_2,
2081 sal_anchor,
2083 CINDEX,
2084 WS, /* sal_anchor = edge_point */
2086 PUSHB_1,
2088 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2090 PUSHB_1,
2092 CINDEX,
2093 PUSHB_1,
2095 CINDEX,
2096 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
2097 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2099 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2100 DUP,
2101 PUSHB_1,
2102 sal_org_len,
2103 SWAP,
2106 PUSHB_1,
2107 bci_compute_stem_width,
2108 CALL, /* s: edge2 edge cur_len */
2110 DUP,
2111 PUSHB_1,
2113 LT, /* cur_len < 96 */
2115 DUP,
2116 PUSHB_1,
2118 LTEQ, /* cur_len <= 64 */
2120 PUSHB_4,
2121 sal_u_off,
2123 sal_d_off,
2126 ELSE,
2127 PUSHB_4,
2128 sal_u_off,
2130 sal_d_off,
2132 EIF,
2136 SWAP, /* s: edge2 cur_len edge */
2137 DUP, /* s: edge2 cur_len edge edge */
2139 GC_orig,
2140 PUSHB_1,
2141 sal_org_len,
2143 PUSHB_1,
2144 2*64,
2145 DIV,
2146 ADD, /* s: edge2 cur_len edge org_center */
2148 DUP,
2149 PUSHB_1,
2150 bci_round,
2151 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2153 DUP,
2154 ROLL,
2155 ROLL,
2156 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2158 DUP,
2159 PUSHB_1,
2160 sal_u_off,
2162 ADD,
2163 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2165 SWAP,
2166 PUSHB_1,
2167 sal_d_off,
2169 SUB,
2170 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2172 LT, /* error1 < error2 */
2174 PUSHB_1,
2175 sal_u_off,
2177 SUB, /* cur_pos1 = cur_pos1 - u_off */
2179 ELSE,
2180 PUSHB_1,
2181 sal_d_off,
2183 ADD, /* cur_pos1 = cur_pos1 + d_off */
2184 EIF, /* s: edge2 cur_len edge cur_pos1 */
2186 PUSHB_1,
2188 CINDEX,
2189 PUSHB_1,
2190 2*64,
2191 DIV,
2192 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2194 PUSHB_1,
2196 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2197 GC_cur,
2198 SUB,
2199 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2201 SWAP, /* s: cur_len edge2 */
2202 DUP,
2203 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2204 SWAP,
2205 SHPIX, /* edge2 = edge1 + cur_len */
2207 ELSE,
2208 POP, /* s: edge2 edge */
2209 DUP,
2210 DUP,
2211 GC_cur,
2212 SWAP,
2213 GC_orig,
2214 PUSHB_1,
2215 bci_round,
2216 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2217 SWAP,
2218 SUB,
2219 SHPIX, /* edge = round(edge_orig) */
2221 /* clean up stack */
2222 POP,
2223 EIF,
2225 PUSHB_2,
2226 bci_align_segments,
2228 SZP1, /* set zp1 to normal zone 1 */
2229 CALL,
2231 ENDF,
2237 * bci_action_blue_anchor
2239 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2240 * and to set the edge anchor.
2242 * in: anchor_point (in twilight zone)
2243 * blue_cvt_idx
2244 * edge_point (in twilight zone)
2245 * ... stuff for bci_align_segments (edge) ...
2247 * sal: sal_anchor
2250 unsigned char FPGM(bci_action_blue_anchor) [] = {
2252 PUSHB_1,
2253 bci_action_blue_anchor,
2254 FDEF,
2256 /* store anchor point number in `sal_anchor' */
2257 PUSHB_1,
2258 sal_anchor,
2259 SWAP,
2262 PUSHB_1,
2264 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2266 /* move `edge_point' to `blue_cvt_idx' position; */
2267 /* note that we can't use MIAP since this would modify */
2268 /* the twilight point's original coordinates also */
2269 RCVT,
2270 SWAP,
2271 DUP,
2272 MDAP_noround, /* set rp0 and rp1 to `edge' */
2273 DUP,
2274 GC_cur, /* s: new_pos edge edge_pos */
2275 ROLL,
2276 SWAP,
2277 SUB, /* s: edge (new_pos - edge_pos) */
2278 SHPIX,
2280 PUSHB_2,
2281 bci_align_segments,
2283 SZP1, /* set zp1 to normal zone 1 */
2284 CALL,
2286 ENDF,
2292 * bci_action_adjust
2294 * Handle the ADJUST action to align an edge of a stem if the other edge
2295 * of the stem has already been moved.
2297 * in: edge2_is_serif
2298 * edge_is_round
2299 * edge_point (in twilight zone)
2300 * edge2_point (in twilight zone)
2301 * ... stuff for bci_align_segments (edge) ...
2304 unsigned char FPGM(bci_action_adjust) [] = {
2306 PUSHB_1,
2307 bci_action_adjust,
2308 FDEF,
2310 PUSHB_1,
2312 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2314 PUSHB_1,
2316 CINDEX, /* s: edge2 edge is_round is_serif edge2 */
2317 PUSHB_1,
2319 CINDEX, /* s: edge2 edge is_round is_serif edge2 edge */
2320 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2322 PUSHB_1,
2323 bci_compute_stem_width,
2324 CALL,
2325 NEG, /* s: edge2 edge -cur_len */
2327 ROLL,
2328 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2329 SWAP,
2330 DUP,
2331 DUP, /* s: -cur_len edge edge edge */
2332 ALIGNRP, /* align `edge' with `edge2' */
2333 ROLL,
2334 SHPIX, /* shift `edge' by -cur_len */
2336 MDAP_noround, /* set rp0 and rp1 to `edge' */
2338 PUSHB_2,
2339 bci_align_segments,
2341 SZP1, /* set zp1 to normal zone 1 */
2342 CALL,
2344 ENDF,
2350 * bci_action_stem
2352 * Handle the STEM action to align two edges of a stem.
2354 * The code after computing `cur_len' to shift `edge' and `edge2'
2355 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2357 * if cur_len < 96:
2358 * if cur_len < = 64:
2359 * u_off = 32
2360 * d_off = 32
2361 * else:
2362 * u_off = 38
2363 * d_off = 26
2365 * org_pos = anchor + (edge_orig - anchor_orig);
2366 * org_center = org_pos + org_len / 2;
2368 * cur_pos1 = ROUND(org_center)
2369 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2370 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2371 * if (delta1 < delta2):
2372 * cur_pos1 = cur_pos1 - u_off
2373 * else:
2374 * cur_pos1 = cur_pos1 + d_off
2376 * edge = cur_pos1 - cur_len / 2
2378 * else:
2379 * org_pos = anchor + (edge_orig - anchor_orig)
2380 * org_center = org_pos + org_len / 2;
2382 * cur_pos1 = ROUND(org_pos)
2383 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2384 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2385 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2387 * if (delta1 < delta2):
2388 * edge = cur_pos1
2389 * else:
2390 * edge = cur_pos2
2392 * edge2 = edge + cur_len
2394 * in: edge2_is_serif
2395 * edge_is_round
2396 * edge_point (in twilight zone)
2397 * edge2_point (in twilight zone)
2398 * ... stuff for bci_align_segments (edge) ...
2399 * ... stuff for bci_align_segments (edge2)...
2401 * sal: sal_anchor
2402 * sal_temp1
2403 * sal_temp2
2404 * sal_temp3
2405 * sal_num_segments
2408 #undef sal_u_off
2409 #define sal_u_off sal_temp1
2410 #undef sal_d_off
2411 #define sal_d_off sal_temp2
2412 #undef sal_org_len
2413 #define sal_org_len sal_temp3
2414 #undef sal_edge2
2415 #define sal_edge2 sal_temp3
2417 unsigned char FPGM(bci_action_stem) [] = {
2419 PUSHB_1,
2420 bci_action_stem,
2421 FDEF,
2423 PUSHB_1,
2425 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2427 PUSHB_1,
2429 CINDEX,
2430 PUSHB_1,
2432 CINDEX,
2433 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
2434 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2436 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2437 DUP,
2438 PUSHB_1,
2439 sal_org_len,
2440 SWAP,
2443 PUSHB_1,
2444 bci_compute_stem_width,
2445 CALL, /* s: edge2 edge cur_len */
2447 DUP,
2448 PUSHB_1,
2450 LT, /* cur_len < 96 */
2452 DUP,
2453 PUSHB_1,
2455 LTEQ, /* cur_len <= 64 */
2457 PUSHB_4,
2458 sal_u_off,
2460 sal_d_off,
2463 ELSE,
2464 PUSHB_4,
2465 sal_u_off,
2467 sal_d_off,
2469 EIF,
2473 SWAP, /* s: edge2 cur_len edge */
2474 DUP,
2475 PUSHB_1,
2476 sal_anchor,
2478 DUP, /* s: edge2 cur_len edge edge anchor anchor */
2479 ROLL,
2480 SWAP,
2481 MD_orig_ZP2_0,
2482 SWAP,
2483 GC_cur,
2484 ADD, /* s: edge2 cur_len edge org_pos */
2485 PUSHB_1,
2486 sal_org_len,
2488 PUSHB_1,
2489 2*64,
2490 DIV,
2491 ADD, /* s: edge2 cur_len edge org_center */
2493 DUP,
2494 PUSHB_1,
2495 bci_round,
2496 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2498 DUP,
2499 ROLL,
2500 ROLL,
2501 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2503 DUP,
2504 PUSHB_1,
2505 sal_u_off,
2507 ADD,
2508 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2510 SWAP,
2511 PUSHB_1,
2512 sal_d_off,
2514 SUB,
2515 ABS, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2517 LT, /* delta1 < delta2 */
2519 PUSHB_1,
2520 sal_u_off,
2522 SUB, /* cur_pos1 = cur_pos1 - u_off */
2524 ELSE,
2525 PUSHB_1,
2526 sal_d_off,
2528 ADD, /* cur_pos1 = cur_pos1 + d_off */
2529 EIF, /* s: edge2 cur_len edge cur_pos1 */
2531 PUSHB_1,
2533 CINDEX,
2534 PUSHB_1,
2535 2*64,
2536 DIV,
2537 SUB, /* arg = cur_pos1 - cur_len/2 */
2539 SWAP, /* s: edge2 cur_len arg edge */
2540 DUP,
2541 PUSHB_1,
2543 MINDEX,
2544 SWAP, /* s: edge2 cur_len edge arg edge */
2545 GC_cur,
2546 SUB,
2547 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2549 ELSE,
2550 SWAP, /* s: edge2 cur_len edge */
2551 PUSHB_1,
2552 sal_anchor,
2554 GC_cur, /* s: edge2 cur_len edge anchor_pos */
2555 PUSHB_1,
2557 CINDEX,
2558 PUSHB_1,
2559 sal_anchor,
2561 MD_orig_ZP2_0,
2562 ADD, /* s: edge2 cur_len edge org_pos */
2564 DUP,
2565 PUSHB_1,
2566 sal_org_len,
2568 PUSHB_1,
2569 2*64,
2570 DIV,
2571 ADD, /* s: edge2 cur_len edge org_pos org_center */
2573 SWAP,
2574 DUP,
2575 PUSHB_1,
2576 bci_round,
2577 CALL, /* cur_pos1 = ROUND(org_pos) */
2578 SWAP,
2579 PUSHB_1,
2580 sal_org_len,
2582 ADD,
2583 PUSHB_1,
2584 bci_round,
2585 CALL,
2586 PUSHB_1,
2588 CINDEX,
2589 SUB, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2591 PUSHB_1,
2593 CINDEX,
2594 PUSHB_1,
2595 2*64,
2596 DIV,
2597 PUSHB_1,
2599 MINDEX,
2600 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2602 DUP,
2603 PUSHB_1,
2605 CINDEX,
2606 ADD,
2607 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2608 SWAP,
2609 PUSHB_1,
2611 CINDEX,
2612 ADD,
2613 ABS, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2614 LT, /* delta1 < delta2 */
2616 POP, /* arg = cur_pos1 */
2618 ELSE,
2619 SWAP,
2620 POP, /* arg = cur_pos2 */
2621 EIF, /* s: edge2 cur_len edge arg */
2622 SWAP,
2623 DUP,
2624 PUSHB_1,
2626 MINDEX,
2627 SWAP, /* s: edge2 cur_len edge arg edge */
2628 GC_cur,
2629 SUB,
2630 SHPIX, /* edge = arg */
2631 EIF, /* s: edge2 cur_len */
2633 SWAP, /* s: cur_len edge2 */
2634 DUP,
2635 DUP,
2636 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2637 PUSHB_1,
2638 sal_edge2,
2639 SWAP,
2640 WS, /* s: cur_len edge2 */
2641 SWAP,
2642 SHPIX, /* edge2 = edge + cur_len */
2644 PUSHB_2,
2645 bci_align_segments,
2647 SZP1, /* set zp1 to normal zone 1 */
2648 CALL,
2650 PUSHB_1,
2651 sal_edge2,
2653 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2655 PUSHB_1,
2656 bci_align_segments,
2657 CALL,
2658 ENDF,
2664 * bci_action_blue
2666 * Handle the BLUE action to align an edge with a blue zone.
2668 * in: blue_cvt_idx
2669 * edge_point (in twilight zone)
2670 * ... stuff for bci_align_segments (edge) ...
2673 unsigned char FPGM(bci_action_blue) [] = {
2675 PUSHB_1,
2676 bci_action_blue,
2677 FDEF,
2679 PUSHB_1,
2681 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2683 /* move `edge_point' to `blue_cvt_idx' position; */
2684 /* note that we can't use MIAP since this would modify */
2685 /* the twilight point's original coordinates also */
2686 RCVT,
2687 SWAP,
2688 DUP,
2689 MDAP_noround, /* set rp0 and rp1 to `edge' */
2690 DUP,
2691 GC_cur, /* s: new_pos edge edge_pos */
2692 ROLL,
2693 SWAP,
2694 SUB, /* s: edge (new_pos - edge_pos) */
2695 SHPIX,
2697 PUSHB_2,
2698 bci_align_segments,
2700 SZP1, /* set zp1 to normal zone 1 */
2701 CALL,
2703 ENDF,
2709 * bci_action_serif
2711 * Handle the SERIF action to align a serif with its base.
2713 * in: serif_point (in twilight zone)
2714 * base_point (in twilight zone)
2715 * ... stuff for bci_align_segments (serif) ...
2718 unsigned char FPGM(bci_action_serif) [] = {
2720 PUSHB_1,
2721 bci_action_serif,
2722 FDEF,
2724 PUSHB_1,
2726 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2728 DUP,
2729 DUP,
2730 DUP,
2731 PUSHB_1,
2733 MINDEX, /* s: serif serif serif serif base */
2734 DUP,
2735 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2736 MD_orig_ZP2_0,
2737 SWAP,
2738 ALIGNRP, /* align `serif_point' with `base_point' */
2739 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2741 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2743 PUSHB_2,
2744 bci_align_segments,
2746 SZP1, /* set zp1 to normal zone 1 */
2747 CALL,
2749 ENDF,
2755 * bci_action_serif_lower_bound
2757 * Handle the SERIF action to align a serif with its base, then moving it
2758 * again if necessary to stay within a lower bound.
2760 * in: serif_point (in twilight zone)
2761 * base_point (in twilight zone)
2762 * edge[-1] (in twilight zone)
2763 * ... stuff for bci_align_segments (serif) ...
2766 unsigned char FPGM(bci_action_serif_lower_bound) [] = {
2768 PUSHB_1,
2769 bci_action_serif_lower_bound,
2770 FDEF,
2772 PUSHB_1,
2774 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2776 DUP,
2777 DUP,
2778 DUP,
2779 PUSHB_1,
2781 MINDEX, /* s: edge[-1] serif serif serif serif base */
2782 DUP,
2783 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2784 MD_orig_ZP2_0,
2785 SWAP,
2786 ALIGNRP, /* align `serif_point' with `base_point' */
2787 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2789 SWAP, /* s: serif edge[-1] */
2790 DUP,
2791 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2792 GC_cur,
2793 PUSHB_1,
2795 CINDEX,
2796 GC_cur, /* s: serif edge[-1]_pos serif_pos */
2797 GT, /* serif_pos < edge[-1]_pos */
2799 DUP,
2800 ALIGNRP, /* align `serif' to `edge[-1]' */
2801 EIF,
2803 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2805 PUSHB_2,
2806 bci_align_segments,
2808 SZP1, /* set zp1 to normal zone 1 */
2809 CALL,
2811 ENDF,
2817 * bci_action_serif_upper_bound
2819 * Handle the SERIF action to align a serif with its base, then moving it
2820 * again if necessary to stay within an upper bound.
2822 * in: serif_point (in twilight zone)
2823 * base_point (in twilight zone)
2824 * edge[1] (in twilight zone)
2825 * ... stuff for bci_align_segments (serif) ...
2828 unsigned char FPGM(bci_action_serif_upper_bound) [] = {
2830 PUSHB_1,
2831 bci_action_serif_upper_bound,
2832 FDEF,
2834 PUSHB_1,
2836 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2838 DUP,
2839 DUP,
2840 DUP,
2841 PUSHB_1,
2843 MINDEX, /* s: edge[1] serif serif serif serif base */
2844 DUP,
2845 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2846 MD_orig_ZP2_0,
2847 SWAP,
2848 ALIGNRP, /* align `serif_point' with `base_point' */
2849 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2851 SWAP, /* s: serif edge[1] */
2852 DUP,
2853 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2854 GC_cur,
2855 PUSHB_1,
2857 CINDEX,
2858 GC_cur, /* s: serif edge[1]_pos serif_pos */
2859 LT, /* serif_pos > edge[1]_pos */
2861 DUP,
2862 ALIGNRP, /* align `serif' to `edge[1]' */
2863 EIF,
2865 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2867 PUSHB_2,
2868 bci_align_segments,
2870 SZP1, /* set zp1 to normal zone 1 */
2871 CALL,
2873 ENDF,
2879 * bci_action_serif_lower_upper_bound
2881 * Handle the SERIF action to align a serif with its base, then moving it
2882 * again if necessary to stay within a lower and upper bound.
2884 * in: serif_point (in twilight zone)
2885 * base_point (in twilight zone)
2886 * edge[-1] (in twilight zone)
2887 * edge[1] (in twilight zone)
2888 * ... stuff for bci_align_segments (serif) ...
2891 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] = {
2893 PUSHB_1,
2894 bci_action_serif_lower_upper_bound,
2895 FDEF,
2897 PUSHB_1,
2899 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2901 DUP,
2902 DUP,
2903 DUP,
2904 PUSHB_1,
2906 MINDEX, /* s: edge[1] edge[-1] serif serif serif serif base */
2907 DUP,
2908 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2909 MD_orig_ZP2_0,
2910 SWAP,
2911 ALIGNRP, /* align `serif_point' with `base_point' */
2912 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2914 SWAP, /* s: edge[1] serif edge[-1] */
2915 DUP,
2916 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2917 GC_cur,
2918 PUSHB_1,
2920 CINDEX,
2921 GC_cur, /* s: edge[1] serif edge[-1]_pos serif_pos */
2922 GT, /* serif_pos < edge[-1]_pos */
2924 DUP,
2925 ALIGNRP, /* align `serif' to `edge[-1]' */
2926 EIF,
2928 SWAP, /* s: serif edge[1] */
2929 DUP,
2930 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
2931 GC_cur,
2932 PUSHB_1,
2934 CINDEX,
2935 GC_cur, /* s: serif edge[1]_pos serif_pos */
2936 LT, /* serif_pos > edge[1]_pos */
2938 DUP,
2939 ALIGNRP, /* align `serif' to `edge[1]' */
2940 EIF,
2942 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2944 PUSHB_2,
2945 bci_align_segments,
2947 SZP1, /* set zp1 to normal zone 1 */
2948 CALL,
2950 ENDF,
2956 * bci_action_serif_anchor
2958 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2959 * anchor.
2961 * in: edge_point (in twilight zone)
2962 * ... stuff for bci_align_segments (edge) ...
2965 unsigned char FPGM(bci_action_serif_anchor) [] = {
2967 PUSHB_1,
2968 bci_action_serif_anchor,
2969 FDEF,
2971 PUSHB_1,
2973 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2975 DUP,
2976 PUSHB_1,
2977 sal_anchor,
2978 SWAP,
2979 WS, /* sal_anchor = edge_point */
2981 DUP,
2982 DUP,
2983 DUP,
2984 GC_cur,
2985 SWAP,
2986 GC_orig,
2987 PUSHB_1,
2988 bci_round,
2989 CALL, /* s: edge edge edge_pos round(edge_orig_pos) */
2990 SWAP,
2991 SUB,
2992 SHPIX, /* edge = round(edge_orig) */
2994 MDAP_noround, /* set rp0 and rp1 to `edge' */
2996 PUSHB_2,
2997 bci_align_segments,
2999 SZP1, /* set zp1 to normal zone 1 */
3000 CALL,
3002 ENDF,
3008 * bci_action_serif_anchor_lower_bound
3010 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3011 * anchor, then moving it again if necessary to stay within a lower
3012 * bound.
3014 * in: edge_point (in twilight zone)
3015 * edge[-1] (in twilight zone)
3016 * ... stuff for bci_align_segments (edge) ...
3019 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] = {
3021 PUSHB_1,
3022 bci_action_serif_anchor_lower_bound,
3023 FDEF,
3025 PUSHB_1,
3027 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3029 DUP,
3030 PUSHB_1,
3031 sal_anchor,
3032 SWAP,
3033 WS, /* sal_anchor = edge_point */
3035 DUP,
3036 DUP,
3037 DUP,
3038 GC_cur,
3039 SWAP,
3040 GC_orig,
3041 PUSHB_1,
3042 bci_round,
3043 CALL, /* s: edge[-1] edge edge edge_pos round(edge_orig_pos) */
3044 SWAP,
3045 SUB,
3046 SHPIX, /* edge = round(edge_orig) */
3048 SWAP, /* s: edge edge[-1] */
3049 DUP,
3050 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3051 GC_cur,
3052 PUSHB_1,
3054 CINDEX,
3055 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3056 GT, /* edge_pos < edge[-1]_pos */
3058 DUP,
3059 ALIGNRP, /* align `edge' to `edge[-1]' */
3060 EIF,
3062 MDAP_noround, /* set rp0 and rp1 to `edge' */
3064 PUSHB_2,
3065 bci_align_segments,
3067 SZP1, /* set zp1 to normal zone 1 */
3068 CALL,
3070 ENDF,
3076 * bci_action_serif_anchor_upper_bound
3078 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3079 * anchor, then moving it again if necessary to stay within an upper
3080 * bound.
3082 * in: edge_point (in twilight zone)
3083 * edge[1] (in twilight zone)
3084 * ... stuff for bci_align_segments (edge) ...
3087 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] = {
3089 PUSHB_1,
3090 bci_action_serif_anchor_upper_bound,
3091 FDEF,
3093 PUSHB_1,
3095 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3097 DUP,
3098 PUSHB_1,
3099 sal_anchor,
3100 SWAP,
3101 WS, /* sal_anchor = edge_point */
3103 DUP,
3104 DUP,
3105 DUP,
3106 GC_cur,
3107 SWAP,
3108 GC_orig,
3109 PUSHB_1,
3110 bci_round,
3111 CALL, /* s: edge[1] edge edge edge_pos round(edge_orig_pos) */
3112 SWAP,
3113 SUB,
3114 SHPIX, /* edge = round(edge_orig) */
3116 SWAP, /* s: edge edge[1] */
3117 DUP,
3118 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3119 GC_cur,
3120 PUSHB_1,
3122 CINDEX,
3123 GC_cur, /* s: edge edge[1]_pos edge_pos */
3124 LT, /* edge_pos > edge[1]_pos */
3126 DUP,
3127 ALIGNRP, /* align `edge' to `edge[1]' */
3128 EIF,
3130 MDAP_noround, /* set rp0 and rp1 to `edge' */
3132 PUSHB_2,
3133 bci_align_segments,
3135 SZP1, /* set zp1 to normal zone 1 */
3136 CALL,
3138 ENDF,
3144 * bci_action_serif_anchor_lower_upper_bound
3146 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3147 * anchor, then moving it again if necessary to stay within a lower and
3148 * upper bound.
3150 * in: edge_point (in twilight zone)
3151 * edge[-1] (in twilight zone)
3152 * edge[1] (in twilight zone)
3153 * ... stuff for bci_align_segments (edge) ...
3156 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] = {
3158 PUSHB_1,
3159 bci_action_serif_anchor_lower_upper_bound,
3160 FDEF,
3162 PUSHB_1,
3164 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3166 DUP,
3167 PUSHB_1,
3168 sal_anchor,
3169 SWAP,
3170 WS, /* sal_anchor = edge_point */
3172 DUP,
3173 DUP,
3174 DUP,
3175 GC_cur,
3176 SWAP,
3177 GC_orig,
3178 PUSHB_1,
3179 bci_round,
3180 CALL, /* s: edge[1] edge[-1] edge edge edge_pos round(edge_orig_pos) */
3181 SWAP,
3182 SUB,
3183 SHPIX, /* edge = round(edge_orig) */
3185 SWAP, /* s: edge[1] edge edge[-1] */
3186 DUP,
3187 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3188 GC_cur,
3189 PUSHB_1,
3191 CINDEX,
3192 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
3193 GT, /* edge_pos < edge[-1]_pos */
3195 DUP,
3196 ALIGNRP, /* align `edge' to `edge[-1]' */
3197 EIF,
3199 SWAP, /* s: edge edge[1] */
3200 DUP,
3201 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3202 GC_cur,
3203 PUSHB_1,
3205 CINDEX,
3206 GC_cur, /* s: edge edge[1]_pos edge_pos */
3207 LT, /* edge_pos > edge[1]_pos */
3209 DUP,
3210 ALIGNRP, /* align `edge' to `edge[1]' */
3211 EIF,
3213 MDAP_noround, /* set rp0 and rp1 to `edge' */
3215 PUSHB_2,
3216 bci_align_segments,
3218 SZP1, /* set zp1 to normal zone 1 */
3219 CALL,
3221 ENDF,
3227 * bci_action_serif_link1
3229 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3230 * before and after.
3232 * in: before_point (in twilight zone)
3233 * edge_point (in twilight zone)
3234 * after_point (in twilight zone)
3235 * ... stuff for bci_align_segments (edge) ...
3238 unsigned char FPGM(bci_action_serif_link1) [] = {
3240 PUSHB_1,
3241 bci_action_serif_link1,
3242 FDEF,
3244 PUSHB_1,
3246 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3248 PUSHB_1,
3250 CINDEX, /* s: after edge before after */
3251 PUSHB_1,
3253 CINDEX, /* s: after edge before after before */
3254 MD_orig_ZP2_0,
3255 PUSHB_1,
3257 EQ, /* after_orig_pos == before_orig_pos */
3258 IF, /* s: after edge before */
3259 MDAP_noround, /* set rp0 and rp1 to `before' */
3260 DUP,
3261 ALIGNRP, /* align `edge' with `before' */
3262 SWAP,
3263 POP,
3265 ELSE,
3266 PUSHB_1,
3268 CINDEX, /* s: ... after edge before edge */
3269 PUSHB_1,
3271 CINDEX, /* s: ... after edge before edge before */
3272 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3273 PUSHW_1,
3274 0x10, /* 64*64 */
3275 0x00,
3276 MUL,
3278 PUSHB_1,
3280 CINDEX, /* s: ... after edge before a*64 after */
3281 PUSHB_1,
3283 CINDEX, /* s: ... after edge before a*64 after before */
3284 MD_cur, /* b = after_pos - before_pos */
3285 MUL, /* s: ... after edge before a*b */
3287 PUSHB_1,
3289 CINDEX, /* s: ... after edge before a*b after */
3290 PUSHB_1,
3292 CINDEX, /* s: ... after edge before a*b after before */
3293 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3294 PUSHW_1,
3295 0x10, /* 64*64 */
3296 0x00,
3297 MUL,
3299 DIV, /* s: after edge before a*b/c */
3301 SWAP,
3302 MDAP_noround, /* set rp0 and rp1 to `before' */
3303 SWAP, /* s: after a*b/c edge */
3304 DUP,
3305 DUP,
3306 ALIGNRP, /* align `edge' with `before' */
3307 ROLL,
3308 SHPIX, /* shift `edge' by `a*b/c' */
3310 SWAP, /* s: edge after */
3311 POP,
3312 EIF,
3314 MDAP_noround, /* set rp0 and rp1 to `edge' */
3316 PUSHB_2,
3317 bci_align_segments,
3319 SZP1, /* set zp1 to normal zone 1 */
3320 CALL,
3322 ENDF,
3328 * bci_action_serif_link1_lower_bound
3330 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3331 * before and after. Additionally, move the serif again if necessary to
3332 * stay within a lower bound.
3334 * in: before_point (in twilight zone)
3335 * edge_point (in twilight zone)
3336 * after_point (in twilight zone)
3337 * edge[-1] (in twilight zone)
3338 * ... stuff for bci_align_segments (edge) ...
3341 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] = {
3343 PUSHB_1,
3344 bci_action_serif_link1_lower_bound,
3345 FDEF,
3347 PUSHB_1,
3349 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3351 PUSHB_1,
3353 CINDEX, /* s: edge[-1] after edge before after */
3354 PUSHB_1,
3356 CINDEX, /* s: edge[-1] after edge before after before */
3357 MD_orig_ZP2_0,
3358 PUSHB_1,
3360 EQ, /* after_orig_pos == before_orig_pos */
3361 IF, /* s: edge[-1] after edge before */
3362 MDAP_noround, /* set rp0 and rp1 to `before' */
3363 DUP,
3364 ALIGNRP, /* align `edge' with `before' */
3365 SWAP,
3366 POP,
3368 ELSE,
3369 PUSHB_1,
3371 CINDEX, /* s: ... after edge before edge */
3372 PUSHB_1,
3374 CINDEX, /* s: ... after edge before edge before */
3375 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3376 PUSHW_1,
3377 0x10, /* 64*64 */
3378 0x00,
3379 MUL,
3381 PUSHB_1,
3383 CINDEX, /* s: ... after edge before a*64 after */
3384 PUSHB_1,
3386 CINDEX, /* s: ... after edge before a*64 after before */
3387 MD_cur, /* b = after_pos - before_pos */
3388 MUL, /* s: ... after edge before a*b */
3390 PUSHB_1,
3392 CINDEX, /* s: ... after edge before a*b after */
3393 PUSHB_1,
3395 CINDEX, /* s: ... after edge before a*b after before */
3396 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3397 PUSHW_1,
3398 0x10, /* 64*64 */
3399 0x00,
3400 MUL,
3402 DIV, /* s: edge[-1] after edge before a*b/c */
3404 SWAP,
3405 MDAP_noround, /* set rp0 and rp1 to `before' */
3406 SWAP, /* s: edge[-1] after a*b/c edge */
3407 DUP,
3408 DUP,
3409 ALIGNRP, /* align `edge' with `before' */
3410 ROLL,
3411 SHPIX, /* shift `edge' by `a*b/c' */
3413 SWAP, /* s: edge[-1] edge after */
3414 POP,
3415 EIF,
3417 SWAP, /* s: edge edge[-1] */
3418 DUP,
3419 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3420 GC_cur,
3421 PUSHB_1,
3423 CINDEX,
3424 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3425 GT, /* edge_pos < edge[-1]_pos */
3427 DUP,
3428 ALIGNRP, /* align `edge' to `edge[-1]' */
3429 EIF,
3431 MDAP_noround, /* set rp0 and rp1 to `edge' */
3433 PUSHB_2,
3434 bci_align_segments,
3436 SZP1, /* set zp1 to normal zone 1 */
3437 CALL,
3438 ENDF,
3444 * bci_action_serif_link1_upper_bound
3446 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3447 * before and after. Additionally, move the serif again if necessary to
3448 * stay within an upper bound.
3450 * in: before_point (in twilight zone)
3451 * edge_point (in twilight zone)
3452 * after_point (in twilight zone)
3453 * edge[1] (in twilight zone)
3454 * ... stuff for bci_align_segments (edge) ...
3457 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] = {
3459 PUSHB_1,
3460 bci_action_serif_link1_upper_bound,
3461 FDEF,
3463 PUSHB_1,
3465 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3467 PUSHB_1,
3469 CINDEX, /* s: edge[1] after edge before after */
3470 PUSHB_1,
3472 CINDEX, /* s: edge[1] after edge before after before */
3473 MD_orig_ZP2_0,
3474 PUSHB_1,
3476 EQ, /* after_orig_pos == before_orig_pos */
3477 IF, /* s: edge[1] after edge before */
3478 MDAP_noround, /* set rp0 and rp1 to `before' */
3479 DUP,
3480 ALIGNRP, /* align `edge' with `before' */
3481 SWAP,
3482 POP,
3484 ELSE,
3485 PUSHB_1,
3487 CINDEX, /* s: ... after edge before edge */
3488 PUSHB_1,
3490 CINDEX, /* s: ... after edge before edge before */
3491 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3492 PUSHW_1,
3493 0x10, /* 64*64 */
3494 0x00,
3495 MUL,
3497 PUSHB_1,
3499 CINDEX, /* s: ... after edge before a*64 after */
3500 PUSHB_1,
3502 CINDEX, /* s: ... after edge before a*64 after before */
3503 MD_cur, /* b = after_pos - before_pos */
3504 MUL, /* s: ... after edge before a*b */
3506 PUSHB_1,
3508 CINDEX, /* s: ... after edge before a*b after */
3509 PUSHB_1,
3511 CINDEX, /* s: ... after edge before a*b after before */
3512 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3513 PUSHW_1,
3514 0x10, /* 64*64 */
3515 0x00,
3516 MUL,
3518 DIV, /* s: edge[1] after edge before a*b/c */
3520 SWAP,
3521 MDAP_noround, /* set rp0 and rp1 to `before' */
3522 SWAP, /* s: edge[1] after a*b/c edge */
3523 DUP,
3524 DUP,
3525 ALIGNRP, /* align `edge' with `before' */
3526 ROLL,
3527 SHPIX, /* shift `edge' by `a*b/c' */
3529 SWAP, /* s: edge[1] edge after */
3530 POP,
3531 EIF,
3533 SWAP, /* s: edge edge[1] */
3534 DUP,
3535 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3536 GC_cur,
3537 PUSHB_1,
3539 CINDEX,
3540 GC_cur, /* s: edge edge[1]_pos edge_pos */
3541 LT, /* edge_pos > edge[1]_pos */
3543 DUP,
3544 ALIGNRP, /* align `edge' to `edge[1]' */
3545 EIF,
3547 MDAP_noround, /* set rp0 and rp1 to `edge' */
3549 PUSHB_2,
3550 bci_align_segments,
3552 SZP1, /* set zp1 to normal zone 1 */
3553 CALL,
3555 ENDF,
3561 * bci_action_serif_link1_lower_upper_bound
3563 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3564 * before and after. Additionally, move the serif again if necessary to
3565 * stay within a lower and upper bound.
3567 * in: before_point (in twilight zone)
3568 * edge_point (in twilight zone)
3569 * after_point (in twilight zone)
3570 * edge[-1] (in twilight zone)
3571 * edge[1] (in twilight zone)
3572 * ... stuff for bci_align_segments (edge) ...
3575 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] = {
3577 PUSHB_1,
3578 bci_action_serif_link1_lower_upper_bound,
3579 FDEF,
3581 PUSHB_1,
3583 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3585 PUSHB_1,
3587 CINDEX, /* s: edge[1] edge[-1] after edge before after */
3588 PUSHB_1,
3590 CINDEX, /* s: edge[1] edge[-1] after edge before after before */
3591 MD_orig_ZP2_0,
3592 PUSHB_1,
3594 EQ, /* after_orig_pos == before_orig_pos */
3595 IF, /* s: edge[1] edge[-1] after edge before */
3596 MDAP_noround, /* set rp0 and rp1 to `before' */
3597 DUP,
3598 ALIGNRP, /* align `edge' with `before' */
3599 SWAP,
3600 POP,
3602 ELSE,
3603 PUSHB_1,
3605 CINDEX, /* s: ... after edge before edge */
3606 PUSHB_1,
3608 CINDEX, /* s: ... after edge before edge before */
3609 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3610 PUSHW_1,
3611 0x10, /* 64*64 */
3612 0x00,
3613 MUL,
3615 PUSHB_1,
3617 CINDEX, /* s: ... after edge before a*64 after */
3618 PUSHB_1,
3620 CINDEX, /* s: ... after edge before a*64 after before */
3621 MD_cur, /* b = after_pos - before_pos */
3622 MUL, /* s: ... after edge before a*b */
3624 PUSHB_1,
3626 CINDEX, /* s: ... after edge before a*b after */
3627 PUSHB_1,
3629 CINDEX, /* s: ... after edge before a*b after_orig before */
3630 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3631 PUSHW_1,
3632 0x10, /* 64*64 */
3633 0x00,
3634 MUL,
3636 DIV, /* s: edge[1] edge[-1] after edge before a*b/c */
3638 SWAP,
3639 MDAP_noround, /* set rp0 and rp1 to `before' */
3640 SWAP, /* s: edge[1] edge[-1] after a*b/c edge */
3641 DUP,
3642 DUP,
3643 ALIGNRP, /* align `edge' with `before' */
3644 ROLL,
3645 SHPIX, /* shift `edge' by `a*b/c' */
3647 SWAP, /* s: edge[1] edge[-1] edge after */
3648 POP,
3649 EIF,
3651 SWAP, /* s: edge[1] edge edge[-1] */
3652 DUP,
3653 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3654 GC_cur,
3655 PUSHB_1,
3657 CINDEX,
3658 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
3659 GT, /* edge_pos < edge[-1]_pos */
3661 DUP,
3662 ALIGNRP, /* align `edge' to `edge[-1]' */
3663 EIF,
3665 SWAP, /* s: edge edge[1] */
3666 DUP,
3667 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3668 GC_cur,
3669 PUSHB_1,
3671 CINDEX,
3672 GC_cur, /* s: edge edge[1]_pos edge_pos */
3673 LT, /* edge_pos > edge[1]_pos */
3675 DUP,
3676 ALIGNRP, /* align `edge' to `edge[1]' */
3677 EIF,
3679 MDAP_noround, /* set rp0 and rp1 to `edge' */
3681 PUSHB_2,
3682 bci_align_segments,
3684 SZP1, /* set zp1 to normal zone 1 */
3685 CALL,
3687 ENDF,
3693 * bci_action_serif_link2
3695 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3697 * in: edge_point (in twilight zone)
3698 * ... stuff for bci_align_segments (edge) ...
3701 unsigned char FPGM(bci_action_serif_link2) [] = {
3703 PUSHB_1,
3704 bci_action_serif_link2,
3705 FDEF,
3707 PUSHB_1,
3709 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3711 DUP, /* s: edge edge */
3712 PUSHB_1,
3713 sal_anchor,
3715 DUP, /* s: edge edge anchor anchor */
3716 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3718 MD_orig_ZP2_0,
3719 DUP,
3720 ADD,
3721 PUSHB_1,
3723 ADD,
3724 FLOOR,
3725 PUSHB_1,
3726 2*64,
3727 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3729 SWAP,
3730 DUP,
3731 DUP,
3732 ALIGNRP, /* align `edge' with `sal_anchor' */
3733 ROLL,
3734 SHPIX, /* shift `edge' by `delta' */
3736 MDAP_noround, /* set rp0 and rp1 to `edge' */
3738 PUSHB_2,
3739 bci_align_segments,
3741 SZP1, /* set zp1 to normal zone 1 */
3742 CALL,
3744 ENDF,
3750 * bci_action_serif_link2_lower_bound
3752 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3753 * Additionally, move the serif again if necessary to stay within a lower
3754 * bound.
3756 * in: edge_point (in twilight zone)
3757 * edge[-1] (in twilight zone)
3758 * ... stuff for bci_align_segments (edge) ...
3761 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] = {
3763 PUSHB_1,
3764 bci_action_serif_link2_lower_bound,
3765 FDEF,
3767 PUSHB_1,
3769 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3771 DUP, /* s: edge[-1] edge edge */
3772 PUSHB_1,
3773 sal_anchor,
3775 DUP, /* s: edge[-1] edge edge anchor anchor */
3776 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3778 MD_orig_ZP2_0,
3779 DUP,
3780 ADD,
3781 PUSHB_1,
3783 ADD,
3784 FLOOR,
3785 PUSHB_1,
3786 2*64,
3787 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3789 SWAP,
3790 DUP,
3791 DUP,
3792 ALIGNRP, /* align `edge' with `sal_anchor' */
3793 ROLL,
3794 SHPIX, /* shift `edge' by `delta' */
3796 SWAP, /* s: edge edge[-1] */
3797 DUP,
3798 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3799 GC_cur,
3800 PUSHB_1,
3802 CINDEX,
3803 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3804 GT, /* edge_pos < edge[-1]_pos */
3806 DUP,
3807 ALIGNRP, /* align `edge' to `edge[-1]' */
3808 EIF,
3810 MDAP_noround, /* set rp0 and rp1 to `edge' */
3812 PUSHB_2,
3813 bci_align_segments,
3815 SZP1, /* set zp1 to normal zone 1 */
3816 CALL,
3818 ENDF,
3824 * bci_action_serif_link2_upper_bound
3826 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3827 * Additionally, move the serif again if necessary to stay within an upper
3828 * bound.
3830 * in: edge_point (in twilight zone)
3831 * edge[1] (in twilight zone)
3832 * ... stuff for bci_align_segments (edge) ...
3835 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] = {
3837 PUSHB_1,
3838 bci_action_serif_link2_upper_bound,
3839 FDEF,
3841 PUSHB_1,
3843 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3845 DUP, /* s: edge[1] edge edge */
3846 PUSHB_1,
3847 sal_anchor,
3849 DUP, /* s: edge[1] edge edge anchor anchor */
3850 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3852 MD_orig_ZP2_0,
3853 DUP,
3854 ADD,
3855 PUSHB_1,
3857 ADD,
3858 FLOOR,
3859 PUSHB_1,
3860 2*64,
3861 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3863 SWAP,
3864 DUP,
3865 DUP,
3866 ALIGNRP, /* align `edge' with `sal_anchor' */
3867 ROLL,
3868 SHPIX, /* shift `edge' by `delta' */
3870 SWAP, /* s: edge edge[1] */
3871 DUP,
3872 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3873 GC_cur,
3874 PUSHB_1,
3876 CINDEX,
3877 GC_cur, /* s: edge edge[1]_pos edge_pos */
3878 LT, /* edge_pos > edge[1]_pos */
3880 DUP,
3881 ALIGNRP, /* align `edge' to `edge[1]' */
3882 EIF,
3884 MDAP_noround, /* set rp0 and rp1 to `edge' */
3886 PUSHB_2,
3887 bci_align_segments,
3889 SZP1, /* set zp1 to normal zone 1 */
3890 CALL,
3892 ENDF,
3898 * bci_action_serif_link2_lower_upper_bound
3900 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3901 * Additionally, move the serif again if necessary to stay within a lower
3902 * and upper bound.
3904 * in: edge_point (in twilight zone)
3905 * edge[-1] (in twilight zone)
3906 * edge[1] (in twilight zone)
3907 * ... stuff for bci_align_segments (edge) ...
3910 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] = {
3912 PUSHB_1,
3913 bci_action_serif_link2_lower_upper_bound,
3914 FDEF,
3916 PUSHB_1,
3918 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3920 DUP, /* s: edge[1] edge[-1] edge edge */
3921 PUSHB_1,
3922 sal_anchor,
3924 DUP, /* s: edge[1] edge[-1] edge edge anchor anchor */
3925 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3927 MD_orig_ZP2_0,
3928 DUP,
3929 ADD,
3930 PUSHB_1,
3932 ADD,
3933 FLOOR,
3934 PUSHB_1,
3935 2*64,
3936 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3938 SWAP,
3939 DUP,
3940 DUP,
3941 ALIGNRP, /* align `edge' with `sal_anchor' */
3942 ROLL,
3943 SHPIX, /* shift `edge' by `delta' */
3945 SWAP, /* s: edge[1] edge edge[-1] */
3946 DUP,
3947 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3948 GC_cur,
3949 PUSHB_1,
3951 CINDEX,
3952 GC_cur, /* s: edge[1] edge edge[-1]_pos edge_pos */
3953 GT, /* edge_pos < edge[-1]_pos */
3955 DUP,
3956 ALIGNRP, /* align `edge' to `edge[-1]' */
3957 EIF,
3959 SWAP, /* s: edge edge[1] */
3960 DUP,
3961 MDAP_noround, /* set rp0 and rp1 to `edge[1]' */
3962 GC_cur,
3963 PUSHB_1,
3965 CINDEX,
3966 GC_cur, /* s: edge edge[1]_pos edge_pos */
3967 LT, /* edge_pos > edge[1]_pos */
3969 DUP,
3970 ALIGNRP, /* align `edge' to `edge[1]' */
3971 EIF,
3973 MDAP_noround, /* set rp0 and rp1 to `edge' */
3975 PUSHB_2,
3976 bci_align_segments,
3978 SZP1, /* set zp1 to normal zone 1 */
3979 CALL,
3981 ENDF,
3987 * bci_handle_action
3989 * Execute function.
3991 * in: function_index
3994 unsigned char FPGM(bci_handle_action) [] = {
3996 PUSHB_1,
3997 bci_handle_action,
3998 FDEF,
4000 CALL,
4002 ENDF,
4008 * bci_hint_glyph
4010 * This is the top-level glyph hinting function
4011 * which parses the arguments on the stack and calls subroutines.
4013 * in: num_actions (M)
4014 * action_0_func_idx
4015 * ... data ...
4016 * action_1_func_idx
4017 * ... data ...
4018 * ...
4019 * action_M_func_idx
4020 * ... data ...
4022 * uses: bci_handle_action
4024 * bci_action_ip_before
4025 * bci_action_ip_after
4026 * bci_action_ip_on
4027 * bci_action_ip_between
4029 * bci_action_adjust_bound
4030 * bci_action_stem_bound
4032 * bci_action_link
4033 * bci_action_anchor
4034 * bci_action_blue_anchor
4035 * bci_action_adjust
4036 * bci_action_stem
4037 * bci_action_blue
4039 * bci_action_serif
4040 * bci_action_serif_lower_bound
4041 * bci_action_serif_upper_bound
4042 * bci_action_serif_lower_upper_bound
4044 * bci_action_serif_anchor
4045 * bci_action_serif_anchor_lower_bound
4046 * bci_action_serif_anchor_upper_bound
4047 * bci_action_serif_anchor_lower_upper_bound
4049 * bci_action_serif_link1
4050 * bci_action_serif_link1_lower_bound
4051 * bci_action_serif_link1_upper_bound
4052 * bci_action_serif_link1_lower_upper_bound
4054 * bci_action_serif_link2
4055 * bci_action_serif_link2_lower_bound
4056 * bci_action_serif_link2_upper_bound
4057 * bci_action_serif_link2_lower_upper_bound
4060 unsigned char FPGM(bci_hint_glyph) [] = {
4062 PUSHB_1,
4063 bci_hint_glyph,
4064 FDEF,
4066 PUSHB_1,
4067 bci_handle_action,
4068 LOOPCALL,
4070 PUSHB_1,
4072 SZP2, /* set zp2 to normal zone 1 */
4073 IUP_y,
4075 ENDF,
4080 #define COPY_FPGM(func_name) \
4081 memcpy(buf_p, fpgm_ ## func_name, \
4082 sizeof (fpgm_ ## func_name)); \
4083 buf_p += sizeof (fpgm_ ## func_name) \
4085 static FT_Error
4086 TA_table_build_fpgm(FT_Byte** fpgm,
4087 FT_ULong* fpgm_len,
4088 FONT* font)
4090 FT_UInt buf_len;
4091 FT_UInt len;
4092 FT_Byte* buf;
4093 FT_Byte* buf_p;
4096 buf_len = sizeof (FPGM(bci_round))
4097 + sizeof (FPGM(bci_compute_stem_width_a))
4099 + sizeof (FPGM(bci_compute_stem_width_b))
4101 + sizeof (FPGM(bci_compute_stem_width_c))
4102 + sizeof (FPGM(bci_loop))
4103 + sizeof (FPGM(bci_cvt_rescale))
4104 + sizeof (FPGM(bci_blue_round_a))
4106 + sizeof (FPGM(bci_blue_round_b))
4107 + sizeof (FPGM(bci_get_point_extrema))
4109 + sizeof (FPGM(bci_create_segment))
4110 + sizeof (FPGM(bci_create_segments))
4111 + sizeof (FPGM(bci_align_segment))
4112 + sizeof (FPGM(bci_align_segments))
4114 + sizeof (FPGM(bci_scale_contour))
4115 + sizeof (FPGM(bci_scale_glyph))
4116 + sizeof (FPGM(bci_shift_contour))
4117 + sizeof (FPGM(bci_shift_subglyph))
4119 + sizeof (FPGM(bci_ip_outer_align_point))
4120 + sizeof (FPGM(bci_ip_on_align_points))
4121 + sizeof (FPGM(bci_ip_between_align_point))
4122 + sizeof (FPGM(bci_ip_between_align_points))
4124 + sizeof (FPGM(bci_action_ip_before))
4125 + sizeof (FPGM(bci_action_ip_after))
4126 + sizeof (FPGM(bci_action_ip_on))
4127 + sizeof (FPGM(bci_action_ip_between))
4129 + sizeof (FPGM(bci_action_adjust_bound))
4130 + sizeof (FPGM(bci_action_stem_bound))
4131 + sizeof (FPGM(bci_action_link))
4132 + sizeof (FPGM(bci_action_anchor))
4133 + sizeof (FPGM(bci_action_blue_anchor))
4134 + sizeof (FPGM(bci_action_adjust))
4135 + sizeof (FPGM(bci_action_stem))
4136 + sizeof (FPGM(bci_action_blue))
4137 + sizeof (FPGM(bci_action_serif))
4138 + sizeof (FPGM(bci_action_serif_lower_bound))
4139 + sizeof (FPGM(bci_action_serif_upper_bound))
4140 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
4141 + sizeof (FPGM(bci_action_serif_anchor))
4142 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
4143 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
4144 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
4145 + sizeof (FPGM(bci_action_serif_link1))
4146 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
4147 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
4148 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
4149 + sizeof (FPGM(bci_action_serif_link2))
4150 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
4151 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
4152 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
4154 + sizeof (FPGM(bci_handle_action))
4155 + sizeof (FPGM(bci_hint_glyph));
4156 /* buffer length must be a multiple of four */
4157 len = (buf_len + 3) & ~3;
4158 buf = (FT_Byte*)malloc(len);
4159 if (!buf)
4160 return FT_Err_Out_Of_Memory;
4162 /* pad end of buffer with zeros */
4163 buf[len - 1] = 0x00;
4164 buf[len - 2] = 0x00;
4165 buf[len - 3] = 0x00;
4167 /* copy font program into buffer and fill in the missing variables */
4168 buf_p = buf;
4170 COPY_FPGM(bci_round);
4171 COPY_FPGM(bci_compute_stem_width_a);
4172 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4173 COPY_FPGM(bci_compute_stem_width_b);
4174 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
4175 COPY_FPGM(bci_compute_stem_width_c);
4176 COPY_FPGM(bci_loop);
4177 COPY_FPGM(bci_cvt_rescale);
4178 COPY_FPGM(bci_blue_round_a);
4179 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
4180 COPY_FPGM(bci_blue_round_b);
4181 COPY_FPGM(bci_get_point_extrema);
4183 COPY_FPGM(bci_create_segment);
4184 COPY_FPGM(bci_create_segments);
4185 COPY_FPGM(bci_align_segment);
4186 COPY_FPGM(bci_align_segments);
4188 COPY_FPGM(bci_scale_contour);
4189 COPY_FPGM(bci_scale_glyph);
4190 COPY_FPGM(bci_shift_contour);
4191 COPY_FPGM(bci_shift_subglyph);
4193 COPY_FPGM(bci_ip_outer_align_point);
4194 COPY_FPGM(bci_ip_on_align_points);
4195 COPY_FPGM(bci_ip_between_align_point);
4196 COPY_FPGM(bci_ip_between_align_points);
4198 COPY_FPGM(bci_action_ip_before);
4199 COPY_FPGM(bci_action_ip_after);
4200 COPY_FPGM(bci_action_ip_on);
4201 COPY_FPGM(bci_action_ip_between);
4203 COPY_FPGM(bci_action_adjust_bound);
4204 COPY_FPGM(bci_action_stem_bound);
4205 COPY_FPGM(bci_action_link);
4206 COPY_FPGM(bci_action_anchor);
4207 COPY_FPGM(bci_action_blue_anchor);
4208 COPY_FPGM(bci_action_adjust);
4209 COPY_FPGM(bci_action_stem);
4210 COPY_FPGM(bci_action_blue);
4211 COPY_FPGM(bci_action_serif);
4212 COPY_FPGM(bci_action_serif_lower_bound);
4213 COPY_FPGM(bci_action_serif_upper_bound);
4214 COPY_FPGM(bci_action_serif_lower_upper_bound);
4215 COPY_FPGM(bci_action_serif_anchor);
4216 COPY_FPGM(bci_action_serif_anchor_lower_bound);
4217 COPY_FPGM(bci_action_serif_anchor_upper_bound);
4218 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
4219 COPY_FPGM(bci_action_serif_link1);
4220 COPY_FPGM(bci_action_serif_link1_lower_bound);
4221 COPY_FPGM(bci_action_serif_link1_upper_bound);
4222 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
4223 COPY_FPGM(bci_action_serif_link2);
4224 COPY_FPGM(bci_action_serif_link2_lower_bound);
4225 COPY_FPGM(bci_action_serif_link2_upper_bound);
4226 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
4228 COPY_FPGM(bci_handle_action);
4229 COPY_FPGM(bci_hint_glyph);
4231 *fpgm = buf;
4232 *fpgm_len = buf_len;
4234 return FT_Err_Ok;
4238 FT_Error
4239 TA_sfnt_build_fpgm_table(SFNT* sfnt,
4240 FONT* font)
4242 FT_Error error;
4244 FT_Byte* fpgm_buf;
4245 FT_ULong fpgm_len;
4248 error = TA_sfnt_add_table_info(sfnt);
4249 if (error)
4250 return error;
4252 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
4253 if (error)
4254 return error;
4256 if (fpgm_len > sfnt->max_instructions)
4257 sfnt->max_instructions = fpgm_len;
4259 /* in case of success, `fpgm_buf' gets linked */
4260 /* and is eventually freed in `TA_font_unload' */
4261 error = TA_font_add_table(font,
4262 &sfnt->table_infos[sfnt->num_table_infos - 1],
4263 TTAG_fpgm, fpgm_len, fpgm_buf);
4264 if (error)
4266 free(fpgm_buf);
4267 return error;
4270 return FT_Err_Ok;
4273 /* end of tafpgm.c */