Shuffle code block.
[ttfautohint.git] / src / tafpgm.c
blob872a575a4c7dbf87566ef47c27bdfbb1f7a09a17
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
143 * out: new_width
145 * CVT: cvtl_is_extra_light
146 * std_width
149 unsigned char FPGM(bci_compute_stem_width_a) [] = {
151 PUSHB_1,
152 bci_compute_stem_width,
153 FDEF,
155 DUP,
156 ABS, /* s: base_is_round stem_is_serif width dist */
158 DUP,
159 PUSHB_1,
160 3*64,
161 LT, /* dist < 3*64 */
163 PUSHB_1,
165 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
166 AND, /* stem_is_serif && dist < 3*64 */
168 PUSHB_1,
169 cvtl_is_extra_light,
170 RCVT,
171 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
173 IF, /* s: base_is_round width dist */
174 POP,
175 SWAP,
176 POP, /* s: width */
178 ELSE,
179 ROLL, /* s: width dist base_is_round */
180 IF, /* s: width dist */
181 DUP,
182 PUSHB_1,
184 LT, /* dist < 80 */
185 IF, /* s: width dist */
186 POP,
187 PUSHB_1,
188 64, /* dist = 64 */
189 EIF,
191 ELSE,
192 DUP,
193 PUSHB_1,
195 LT, /* dist < 56 */
196 IF, /* s: width dist */
197 POP,
198 PUSHB_1,
199 56, /* dist = 56 */
200 EIF,
201 EIF,
203 DUP, /* s: width dist dist */
204 PUSHB_1,
208 /* %c, index of std_width */
210 unsigned char FPGM(bci_compute_stem_width_b) [] = {
212 RCVT,
213 SUB,
214 ABS, /* s: width dist delta */
216 PUSHB_1,
218 LT, /* delta < 40 */
219 IF, /* s: width dist */
220 POP,
221 PUSHB_1,
225 /* %c, index of std_width */
227 unsigned char FPGM(bci_compute_stem_width_c) [] = {
229 RCVT, /* dist = std_width */
230 DUP,
231 PUSHB_1,
233 LT, /* dist < 48 */
235 POP,
236 PUSHB_1,
237 48, /* dist = 48 */
238 EIF,
240 ELSE,
241 DUP, /* s: width dist dist */
242 PUSHB_1,
243 3*64,
244 LT, /* dist < 3*64 */
246 DUP, /* s: width delta dist */
247 FLOOR, /* dist = FLOOR(dist) */
248 DUP, /* s: width delta dist dist */
249 ROLL,
250 ROLL, /* s: width dist delta dist */
251 SUB, /* delta = delta - dist */
253 DUP, /* s: width dist delta delta */
254 PUSHB_1,
256 LT, /* delta < 10 */
257 IF, /* s: width dist delta */
258 ADD, /* dist = dist + delta */
260 ELSE,
261 DUP,
262 PUSHB_1,
264 LT, /* delta < 32 */
266 POP,
267 PUSHB_1,
269 ADD, /* dist = dist + 10 */
271 ELSE,
272 DUP,
273 PUSHB_1,
275 LT, /* delta < 54 */
277 POP,
278 PUSHB_1,
280 ADD, /* dist = dist + 54 */
282 ELSE,
283 ADD, /* dist = dist + delta */
285 EIF,
286 EIF,
287 EIF,
289 ELSE,
290 PUSHB_1,
291 bci_round,
292 CALL, /* dist = round(dist) */
294 EIF,
295 EIF,
297 SWAP, /* s: dist width */
298 PUSHB_1,
300 LT, /* width < 0 */
302 NEG, /* dist = -dist */
303 EIF,
304 EIF,
306 ENDF,
312 * bci_loop
314 * Take a range and a function number and apply the function to all
315 * elements of the range.
317 * in: func_num
318 * end
319 * start
321 * sal: sal_i (counter initialized with `start')
322 * sal_limit (`end')
323 * sal_func (`func_num')
326 unsigned char FPGM(bci_loop) [] = {
328 PUSHB_1,
329 bci_loop,
330 FDEF,
332 PUSHB_1,
333 sal_func,
334 SWAP,
335 WS, /* sal_func = func_num */
336 PUSHB_1,
337 sal_limit,
338 SWAP,
339 WS, /* sal_limit = end */
340 PUSHB_1,
341 sal_i,
342 SWAP,
343 WS, /* sal_i = start */
345 /* start_loop: */
346 PUSHB_1,
347 sal_i,
349 PUSHB_1,
350 sal_limit,
352 LTEQ, /* start <= end */
354 PUSHB_1,
355 sal_func,
357 CALL,
358 PUSHB_3,
359 sal_i,
361 sal_i,
363 ADD, /* start = start + 1 */
366 PUSHB_1,
368 NEG,
369 JMPR, /* goto start_loop */
370 EIF,
372 ENDF,
378 * bci_cvt_rescale
380 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
382 * sal: sal_i (CVT index)
384 * CVT: cvtl_scale
385 * cvtl_0x10000
388 unsigned char FPGM(bci_cvt_rescale) [] = {
390 PUSHB_1,
391 bci_cvt_rescale,
392 FDEF,
394 PUSHB_1,
395 sal_i,
397 DUP,
398 RCVT,
399 PUSHB_1,
400 cvtl_scale,
401 RCVT,
402 MUL, /* CVT * scale * 2^10 */
403 PUSHB_1,
404 cvtl_0x10000,
405 RCVT,
406 DIV, /* CVT * scale */
408 WCVTP,
410 ENDF,
416 * bci_blue_round
418 * Round a blue ref value and adjust its corresponding shoot value.
420 * sal: sal_i (CVT index)
424 unsigned char FPGM(bci_blue_round_a) [] = {
426 PUSHB_1,
427 bci_blue_round,
428 FDEF,
430 PUSHB_1,
431 sal_i,
433 DUP,
434 RCVT, /* s: ref_idx ref */
436 DUP,
437 PUSHB_1,
438 bci_round,
439 CALL,
440 SWAP, /* s: ref_idx round(ref) ref */
442 PUSHB_2,
446 /* %c, blue_count */
448 unsigned char FPGM(bci_blue_round_b) [] = {
451 CINDEX,
452 ADD, /* s: ref_idx round(ref) ref shoot_idx */
453 DUP,
454 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
456 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
457 SWAP,
458 SUB, /* s: ref_idx round(ref) shoot_idx dist */
459 DUP,
460 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
462 DUP,
463 PUSHB_1,
465 LT, /* delta < 32 */
467 POP,
468 PUSHB_1,
469 0, /* delta = 0 */
471 ELSE,
472 PUSHB_1,
474 LT, /* delta < 48 */
476 PUSHB_1,
477 32, /* delta = 32 */
479 ELSE,
480 PUSHB_1,
481 64, /* delta = 64 */
482 EIF,
483 EIF,
485 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
486 PUSHB_1,
488 LT, /* dist < 0 */
490 NEG, /* delta = -delta */
491 EIF,
493 PUSHB_1,
495 CINDEX,
496 SWAP,
497 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
499 WCVTP,
500 WCVTP,
502 ENDF,
508 * bci_get_point_extrema
510 * An auxiliary function for `bci_create_segment'.
512 * in: point-1
513 * out: point
515 * sal: sal_point_min
516 * sal_point_max
519 unsigned char FPGM(bci_get_point_extrema) [] = {
521 PUSHB_1,
522 bci_get_point_extrema,
523 FDEF,
525 PUSHB_1,
527 ADD, /* s: point */
528 DUP,
529 DUP,
531 /* check whether `point' is a new minimum */
532 PUSHB_1,
533 sal_point_min,
534 RS, /* s: point point point point_min */
535 MD_orig,
536 /* if distance is negative, we have a new minimum */
537 PUSHB_1,
540 IF, /* s: point point */
541 DUP,
542 PUSHB_1,
543 sal_point_min,
544 SWAP,
546 EIF,
548 /* check whether `point' is a new maximum */
549 PUSHB_1,
550 sal_point_max,
551 RS, /* s: point point point_max */
552 MD_orig,
553 /* if distance is positive, we have a new maximum */
554 PUSHB_1,
557 IF, /* s: point */
558 DUP,
559 PUSHB_1,
560 sal_point_max,
561 SWAP,
563 EIF, /* s: point */
565 ENDF,
571 * bci_create_segment
573 * Store start and end point of a segment in the storage area,
574 * then construct a point in the twilight zone to represent it.
576 * This function is used by `bci_create_segment_points'.
578 * in: start
579 * end
580 * [last (if wrap-around segment)]
581 * [first (if wrap-around segment)]
583 * uses: bci_get_point_extrema
585 * sal: sal_i (start of current segment)
586 * sal_j (current twilight point)
587 * sal_point_min
588 * sal_point_max
590 * CVT: cvtl_scale
591 * cvtl_0x10000
592 * cvtl_temp
595 unsigned char FPGM(bci_create_segment) [] = {
597 PUSHB_1,
598 bci_create_segment,
599 FDEF,
601 PUSHB_1,
602 sal_i,
604 PUSHB_1,
606 CINDEX,
607 WS, /* sal[sal_i] = start */
609 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
610 PUSHB_3,
611 sal_i,
613 sal_i,
615 ADD, /* sal_i = sal_i + 1 */
618 /* initialize inner loop(s) */
619 PUSHB_2,
620 sal_point_min,
622 CINDEX,
623 WS, /* sal_point_min = start */
624 PUSHB_2,
625 sal_point_max,
627 CINDEX,
628 WS, /* sal_point_max = start */
630 PUSHB_1,
632 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
634 SWAP,
635 DUP,
636 PUSHB_1,
638 CINDEX, /* s: start end end start */
639 LT, /* start > end */
641 /* we have a wrap-around segment with two more arguments */
642 /* to give the last and first point of the contour, respectively; */
643 /* our job is to store a segment `start'-`last', */
644 /* and to get extrema for the two segments */
645 /* `start'-`last' and `first'-`end' */
647 /* s: first last start end */
648 PUSHB_1,
649 sal_i,
651 PUSHB_1,
653 CINDEX,
654 WS, /* sal[sal_i] = last */
656 ROLL,
657 ROLL, /* s: first end last start */
658 DUP,
659 ROLL,
660 SWAP, /* s: first end start last start */
661 SUB, /* s: first end start loop_count */
663 PUSHB_1,
664 bci_get_point_extrema,
665 LOOPCALL,
666 /* clean up stack */
667 POP,
669 SWAP, /* s: end first */
670 PUSHB_1,
672 SUB,
673 DUP,
674 ROLL, /* s: (first - 1) (first - 1) end */
675 SWAP,
676 SUB, /* s: (first - 1) loop_count */
678 PUSHB_1,
679 bci_get_point_extrema,
680 LOOPCALL,
681 /* clean up stack */
682 POP,
684 ELSE, /* s: start end */
685 PUSHB_1,
686 sal_i,
688 PUSHB_1,
690 CINDEX,
691 WS, /* sal[sal_i] = end */
693 PUSHB_1,
695 CINDEX,
696 SUB, /* s: start loop_count */
698 PUSHB_1,
699 bci_get_point_extrema,
700 LOOPCALL,
701 /* clean up stack */
702 POP,
703 EIF,
705 /* the twilight point representing a segment */
706 /* is in the middle between the minimum and maximum */
707 PUSHB_1,
708 sal_point_min,
710 GC_orig,
711 PUSHB_1,
712 sal_point_max,
714 GC_orig,
715 ADD,
716 PUSHB_1,
717 2*64,
718 DIV, /* s: middle_pos */
720 /* now scale it */
721 PUSHB_1,
722 cvtl_scale,
723 RCVT,
724 MUL, /* middle_pos * scale * 2^10 */
725 PUSHB_1,
726 cvtl_0x10000,
727 RCVT,
728 DIV, /* middle_pos = middle_pos * scale */
730 /* write it to temporary CVT location */
731 PUSHB_2,
732 cvtl_temp,
734 SZP0, /* set zp0 to twilight zone 0 */
735 SWAP,
736 WCVTP,
738 /* create twilight point with index `sal_j' */
739 PUSHB_1,
740 sal_j,
742 PUSHB_1,
743 cvtl_temp,
744 MIAP_noround,
746 PUSHB_3,
747 sal_j,
749 sal_j,
751 ADD, /* twilight_point = twilight_point + 1 */
754 ENDF,
760 * bci_create_segments
762 * Set up segments by defining point ranges which defines them
763 * and computing twilight points to represent them.
765 * in: num_segments (N)
766 * segment_start_0
767 * segment_end_0
768 * [contour_last 0 (if wrap-around segment)]
769 * [contour_first 0 (if wrap-around segment)]
770 * segment_start_1
771 * segment_end_1
772 * [contour_last 0 (if wrap-around segment)]
773 * [contour_first 0 (if wrap-around segment)]
774 * ...
775 * segment_start_(N-1)
776 * segment_end_(N-1)
777 * [contour_last (N-1) (if wrap-around segment)]
778 * [contour_first (N-1) (if wrap-around segment)]
780 * uses: bci_create_segment
782 * sal: sal_i (start of current segment)
783 * sal_j (current twilight point)
786 unsigned char FPGM(bci_create_segments) [] = {
788 PUSHB_1,
789 bci_create_segments,
790 FDEF,
792 /* all our measurements are taken along the y axis */
793 SVTCA_y,
795 DUP,
796 ADD,
797 PUSHB_1,
799 SUB, /* delta = (2*num_segments - 1) */
801 PUSHB_4,
802 sal_segment_offset,
803 sal_segment_offset,
805 sal_j,
807 WS, /* sal_j = 0 (point offset) */
809 ROLL,
810 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
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 * CVT: cvtl_scale
935 * cvtl_0x10000
938 unsigned char FPGM(bci_scale_contour) [] = {
940 PUSHB_1,
941 bci_scale_contour,
942 FDEF,
944 DUP,
945 DUP,
946 GC_orig,
947 DUP,
948 PUSHB_1,
949 cvtl_scale,
950 RCVT,
951 MUL, /* min_pos * scale * 2^10 */
952 PUSHB_1,
953 cvtl_0x10000,
954 RCVT,
955 DIV, /* min_pos_new = min_pos * scale */
956 SWAP,
957 SUB,
958 SHPIX,
960 /* don't scale a single-point contour twice */
961 SWAP,
962 DUP,
963 ROLL,
964 NEQ,
966 DUP,
967 GC_orig,
968 DUP,
969 PUSHB_1,
970 cvtl_scale,
971 RCVT,
972 MUL, /* max_pos * scale * 2^10 */
973 PUSHB_1,
974 cvtl_0x10000,
975 RCVT,
976 DIV, /* max_pos_new = max_pos * scale */
977 SWAP,
978 SUB,
979 SHPIX,
981 ELSE,
982 POP,
983 EIF,
985 ENDF,
991 * bci_scale_glyph
993 * Scale a glyph using a list of points (two points per contour, giving
994 * the maximum and mininum coordinates).
996 * It expects that no point in the glyph is touched.
998 * in: num_contours (N)
999 * min_point_1
1000 * max_point_1
1001 * min_point_2
1002 * max_point_2
1003 * ...
1004 * min_point_N
1005 * max_point_N
1007 * uses: bci_scale_contour
1010 unsigned char FPGM(bci_scale_glyph) [] = {
1012 PUSHB_1,
1013 bci_scale_glyph,
1014 FDEF,
1016 SVTCA_y,
1018 PUSHB_1,
1020 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1022 PUSHB_1,
1023 bci_scale_contour,
1024 LOOPCALL,
1026 PUSHB_1,
1028 SZP2, /* set zp2 to normal zone 1 */
1029 IUP_y,
1031 ENDF,
1037 * bci_shift_contour
1039 * Shift a contour by a given amount.
1041 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1042 * point to the normal zone 1.
1044 * in: contour
1045 * out: contour + 1
1048 unsigned char FPGM(bci_shift_contour) [] = {
1050 PUSHB_1,
1051 bci_shift_contour,
1052 FDEF,
1054 DUP,
1055 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1057 PUSHB_1,
1059 ADD,
1061 ENDF,
1067 * bci_shift_subglyph
1069 * Shift a subglyph. To be more specific, it corrects the already applied
1070 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1071 * also.
1073 * If this function is called, a point `x' in the subglyph has been scaled
1074 * by `cvtl_scale' already (during the hinting of the subglyph itself), and
1075 * `offset' has been applied also:
1077 * x -> x * scale + offset (1)
1079 * However, the offset should be applied first, then the scaling:
1081 * x -> (x + offset) * scale (2)
1083 * Our job is now to transform (1) to (2); a simple calculation shows that
1084 * we have to shift all points of the subglyph by
1086 * offset * scale - offset = offset * (scale - 1)
1088 * in: offset (in FUnits)
1089 * num_contours
1090 * first_contour
1092 * CVT: cvtl_funits_to_pixels
1093 * cvtl_0x10000
1094 * cvtl_scale
1097 unsigned char FPGM(bci_shift_subglyph) [] = {
1099 PUSHB_1,
1100 bci_shift_subglyph,
1101 FDEF,
1103 SVTCA_y,
1105 PUSHB_1,
1106 cvtl_funits_to_pixels,
1107 RCVT, /* scaling factor FUnits -> pixels */
1108 MUL,
1109 PUSHB_1,
1110 cvtl_0x10000,
1111 RCVT,
1112 DIV,
1114 /* the autohinter always rounds offsets */
1115 PUSHB_1,
1116 bci_round,
1117 CALL, /* offset = round(offset) */
1119 PUSHB_1,
1120 cvtl_scale,
1121 RCVT,
1122 PUSHB_1,
1123 cvtl_0x10000,
1124 RCVT,
1125 SUB, /* scale - 1 (in 16.16 format) */
1126 MUL,
1127 PUSHB_1,
1128 cvtl_0x10000,
1129 RCVT,
1130 DIV, /* delta = offset * (scale - 1) */
1132 /* and round again */
1133 PUSHB_1,
1134 bci_round,
1135 CALL, /* offset = round(offset) */
1137 PUSHB_1,
1139 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1141 /* we create twilight point 0 as a reference point, */
1142 /* setting the original position to zero (using `cvtl_temp') */
1143 PUSHB_5,
1146 cvtl_temp,
1147 cvtl_temp,
1149 WCVTP,
1150 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1152 SWAP, /* s: first_contour num_contours 0 delta */
1153 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1155 PUSHB_2,
1156 bci_shift_contour,
1158 SZP2, /* set zp2 to normal zone 1 */
1159 LOOPCALL,
1161 ENDF,
1167 * bci_ip_outer_align_point
1169 * Auxiliary function for `bci_action_ip_before' and
1170 * `bci_action_ip_after'.
1172 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1173 * zone, and both zp1 and zp2 set to normal zone.
1175 * in: point
1177 * sal: sal_i (edge_orig_pos)
1179 * CVT: cvtl_scale
1180 * cvtl_0x10000
1183 unsigned char FPGM(bci_ip_outer_align_point) [] = {
1185 PUSHB_1,
1186 bci_ip_outer_align_point,
1187 FDEF,
1189 DUP,
1190 ALIGNRP, /* align `point' with `edge' */
1191 DUP,
1192 GC_orig,
1193 /* now scale it */
1194 PUSHB_1,
1195 cvtl_scale,
1196 RCVT,
1197 MUL, /* point_orig_pos * scale * 2^10 */
1198 PUSHB_1,
1199 cvtl_0x10000,
1200 RCVT,
1201 DIV, /* point_orig_pos = point_orig_pos * scale */
1203 PUSHB_1,
1204 sal_i,
1206 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1207 SHPIX,
1209 ENDF,
1215 * bci_ip_on_align_points
1217 * Auxiliary function for `bci_action_ip_on'.
1219 * in: edge (in twilight zone)
1220 * loop_counter (N)
1221 * point_1
1222 * point_2
1223 * ...
1224 * point_N
1227 unsigned char FPGM(bci_ip_on_align_points) [] = {
1229 PUSHB_1,
1230 bci_ip_on_align_points,
1231 FDEF,
1233 MDAP_noround, /* set rp0 and rp1 to `edge' */
1235 SLOOP,
1236 ALIGNRP,
1238 ENDF,
1244 * bci_ip_between_align_point
1246 * Auxiliary function for `bci_ip_between_align_points'.
1248 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1249 * zone, and both zp1 and zp2 set to normal zone.
1251 * in: point
1253 * sal: sal_i (edge_orig_pos)
1254 * sal_j (stretch_factor)
1256 * CVT: cvtl_scale
1257 * cvtl_0x10000
1260 unsigned char FPGM(bci_ip_between_align_point) [] = {
1262 PUSHB_1,
1263 bci_ip_between_align_point,
1264 FDEF,
1266 DUP,
1267 ALIGNRP, /* align `point' with `edge' */
1268 DUP,
1269 GC_orig,
1270 /* now scale it */
1271 PUSHB_1,
1272 cvtl_scale,
1273 RCVT,
1274 MUL, /* point_orig_pos * scale * 2^10 */
1275 PUSHB_1,
1276 cvtl_0x10000,
1277 RCVT,
1278 DIV, /* point_orig_pos = point_orig_pos * scale */
1280 PUSHB_1,
1281 sal_i,
1283 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1284 PUSHB_1,
1285 sal_j,
1287 MUL, /* s: point delta */
1288 SHPIX,
1290 ENDF,
1296 * bci_ip_between_align_points
1298 * Auxiliary function for `bci_action_ip_between'.
1300 * in: after_edge (in twilight zone)
1301 * before_edge (in twilight zone)
1302 * loop_counter (N)
1303 * point_1
1304 * point_2
1305 * ...
1306 * point_N
1308 * sal: sal_i (before_orig_pos)
1309 * sal_j (stretch_factor)
1311 * uses: bci_ip_between_align_point
1314 unsigned char FPGM(bci_ip_between_align_points) [] = {
1316 PUSHB_1,
1317 bci_ip_between_align_points,
1318 FDEF,
1320 PUSHB_2,
1323 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1324 CINDEX,
1325 DUP, /* s: ... before after before before */
1326 MDAP_noround, /* set rp0 and rp1 to `before' */
1327 DUP,
1328 GC_orig, /* s: ... before after before before_orig_pos */
1329 PUSHB_1,
1330 sal_i,
1331 SWAP,
1332 WS, /* sal_i = before_orig_pos */
1333 PUSHB_1,
1335 CINDEX, /* s: ... before after before after */
1336 MD_cur, /* b = after_pos - before_pos */
1337 ROLL,
1338 ROLL,
1339 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
1340 DIV, /* s: a/b */
1341 PUSHB_1,
1342 sal_j,
1343 SWAP,
1344 WS, /* sal_j = stretch_factor */
1346 PUSHB_3,
1347 bci_ip_between_align_point,
1350 SZP2, /* set zp2 to normal zone 1 */
1351 SZP1, /* set zp1 to normal zone 1 */
1352 LOOPCALL,
1354 ENDF,
1360 * bci_action_ip_before
1362 * Handle `ip_before' data to align points located before the first edge.
1364 * in: first_edge (in twilight zone)
1365 * loop_counter (N)
1366 * point_1
1367 * point_2
1368 * ...
1369 * point_N
1371 * sal: sal_i (first_edge_orig_pos)
1373 * uses: bci_ip_outer_align_point
1376 unsigned char FPGM(bci_action_ip_before) [] = {
1378 PUSHB_1,
1379 bci_action_ip_before,
1380 FDEF,
1382 PUSHB_1,
1384 SZP2, /* set zp2 to twilight zone 0 */
1386 DUP,
1387 GC_orig,
1388 PUSHB_1,
1389 sal_i,
1390 SWAP,
1391 WS, /* sal_i = first_edge_orig_pos */
1393 PUSHB_3,
1397 SZP2, /* set zp2 to normal zone 1 */
1398 SZP1, /* set zp1 to normal zone 1 */
1399 SZP0, /* set zp0 to twilight zone 0 */
1401 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
1403 PUSHB_1,
1404 bci_ip_outer_align_point,
1405 LOOPCALL,
1407 ENDF,
1413 * bci_action_ip_after
1415 * Handle `ip_after' data to align points located after the last edge.
1417 * in: last_edge (in twilight zone)
1418 * loop_counter (N)
1419 * point_1
1420 * point_2
1421 * ...
1422 * point_N
1424 * sal: sal_i (last_edge_orig_pos)
1426 * uses: bci_ip_outer_align_point
1429 unsigned char FPGM(bci_action_ip_after) [] = {
1431 PUSHB_1,
1432 bci_action_ip_after,
1433 FDEF,
1435 PUSHB_1,
1437 SZP2, /* set zp2 to twilight zone 0 */
1439 DUP,
1440 GC_orig,
1441 PUSHB_1,
1442 sal_i,
1443 SWAP,
1444 WS, /* sal_i = last_edge_orig_pos */
1446 PUSHB_3,
1450 SZP2, /* set zp2 to normal zone 1 */
1451 SZP1, /* set zp1 to normal zone 1 */
1452 SZP0, /* set zp0 to twilight zone 0 */
1454 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
1456 PUSHB_1,
1457 bci_ip_outer_align_point,
1458 LOOPCALL,
1460 ENDF,
1466 * bci_action_ip_on
1468 * Handle `ip_on' data to align points located on an edge coordinate (but
1469 * not part of an edge).
1471 * in: loop_counter (M)
1472 * edge_1 (in twilight zone)
1473 * loop_counter (N_1)
1474 * point_1
1475 * point_2
1476 * ...
1477 * point_N_1
1478 * edge_2 (in twilight zone)
1479 * loop_counter (N_2)
1480 * point_1
1481 * point_2
1482 * ...
1483 * point_N_2
1484 * ...
1485 * edge_M (in twilight zone)
1486 * loop_counter (N_M)
1487 * point_1
1488 * point_2
1489 * ...
1490 * point_N_M
1492 * uses: bci_ip_on_align_points
1495 unsigned char FPGM(bci_action_ip_on) [] = {
1497 PUSHB_1,
1498 bci_action_ip_on,
1499 FDEF,
1501 PUSHB_2,
1504 SZP1, /* set zp1 to normal zone 1 */
1505 SZP0, /* set zp0 to twilight zone 0 */
1507 PUSHB_1,
1508 bci_ip_on_align_points,
1509 LOOPCALL,
1511 ENDF,
1517 * bci_action_ip_between
1519 * Handle `ip_between' data to align points located between two edges.
1521 * in: loop_counter (M)
1522 * before_edge_1 (in twilight zone)
1523 * after_edge_1 (in twilight zone)
1524 * loop_counter (N_1)
1525 * point_1
1526 * point_2
1527 * ...
1528 * point_N_1
1529 * before_edge_2 (in twilight zone)
1530 * after_edge_2 (in twilight zone)
1531 * loop_counter (N_2)
1532 * point_1
1533 * point_2
1534 * ...
1535 * point_N_2
1536 * ...
1537 * before_edge_M (in twilight zone)
1538 * after_edge_M (in twilight zone)
1539 * loop_counter (N_M)
1540 * point_1
1541 * point_2
1542 * ...
1543 * point_N_M
1545 * uses: bci_ip_between_align_points
1548 unsigned char FPGM(bci_action_ip_between) [] = {
1550 PUSHB_1,
1551 bci_action_ip_between,
1552 FDEF,
1554 PUSHB_1,
1555 bci_ip_between_align_points,
1556 LOOPCALL,
1558 ENDF,
1564 * bci_action_adjust_common
1566 * Common code for bci_action_adjust routines.
1569 unsigned char FPGM(bci_action_adjust_common) [] = {
1571 PUSHB_1,
1572 bci_action_adjust_common,
1573 FDEF,
1575 PUSHB_1,
1577 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1579 PUSHB_1,
1581 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
1582 PUSHB_1,
1584 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1585 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1587 PUSHB_1,
1588 bci_compute_stem_width,
1589 CALL,
1590 NEG, /* s: [...] edge2 edge -cur_len */
1592 ROLL, /* s: [...] edge -cur_len edge2 */
1593 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1594 SWAP,
1595 DUP,
1596 DUP, /* s: [...] -cur_len edge edge edge */
1597 ALIGNRP, /* align `edge' with `edge2' */
1598 ROLL,
1599 SHPIX, /* shift `edge' by -cur_len */
1601 ENDF,
1607 * bci_action_adjust_bound
1609 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1610 * edge of the stem has already been moved, then moving it again if
1611 * necessary to stay bound.
1613 * in: edge2_is_serif
1614 * edge_is_round
1615 * edge_point (in twilight zone)
1616 * edge2_point (in twilight zone)
1617 * edge[-1] (in twilight zone)
1618 * ... stuff for bci_align_segments (edge) ...
1620 * uses: bci_action_adjust_common
1623 unsigned char FPGM(bci_action_adjust_bound) [] = {
1625 PUSHB_1,
1626 bci_action_adjust_bound,
1627 FDEF,
1629 PUSHB_1,
1630 bci_action_adjust_common,
1631 CALL,
1633 SWAP, /* s: edge edge[-1] */
1634 DUP,
1635 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1636 GC_cur,
1637 PUSHB_1,
1639 CINDEX,
1640 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1641 GT, /* edge_pos < edge[-1]_pos */
1643 DUP,
1644 ALIGNRP, /* align `edge' to `edge[-1]' */
1645 EIF,
1647 MDAP_noround, /* set rp0 and rp1 to `edge' */
1649 PUSHB_2,
1650 bci_align_segments,
1652 SZP1, /* set zp1 to normal zone 1 */
1653 CALL,
1655 ENDF,
1661 * bci_action_adjust
1663 * Handle the ADJUST action to align an edge of a stem if the other edge
1664 * of the stem has already been moved.
1666 * in: edge2_is_serif
1667 * edge_is_round
1668 * edge_point (in twilight zone)
1669 * edge2_point (in twilight zone)
1670 * ... stuff for bci_align_segments (edge) ...
1672 * uses: bci_action_adjust_common
1675 unsigned char FPGM(bci_action_adjust) [] = {
1677 PUSHB_1,
1678 bci_action_adjust,
1679 FDEF,
1681 PUSHB_1,
1682 bci_action_adjust_common,
1683 CALL,
1685 MDAP_noround, /* set rp0 and rp1 to `edge' */
1687 PUSHB_2,
1688 bci_align_segments,
1690 SZP1, /* set zp1 to normal zone 1 */
1691 CALL,
1693 ENDF,
1699 * bci_action_stem_common
1701 * Common code for bci_action_stem routines.
1704 #undef sal_u_off
1705 #define sal_u_off sal_temp1
1706 #undef sal_d_off
1707 #define sal_d_off sal_temp2
1708 #undef sal_org_len
1709 #define sal_org_len sal_temp3
1710 #undef sal_edge2
1711 #define sal_edge2 sal_temp3
1713 unsigned char FPGM(bci_action_stem_common) [] = {
1715 PUSHB_1,
1716 bci_action_stem_common,
1717 FDEF,
1719 PUSHB_1,
1721 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1723 PUSHB_1,
1725 CINDEX,
1726 PUSHB_1,
1728 CINDEX,
1729 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1730 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1732 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1733 DUP,
1734 PUSHB_1,
1735 sal_org_len,
1736 SWAP,
1739 PUSHB_1,
1740 bci_compute_stem_width,
1741 CALL, /* s: [...] edge2 edge cur_len */
1743 DUP,
1744 PUSHB_1,
1746 LT, /* cur_len < 96 */
1748 DUP,
1749 PUSHB_1,
1751 LTEQ, /* cur_len <= 64 */
1753 PUSHB_4,
1754 sal_u_off,
1756 sal_d_off,
1759 ELSE,
1760 PUSHB_4,
1761 sal_u_off,
1763 sal_d_off,
1765 EIF,
1769 SWAP, /* s: [...] edge2 cur_len edge */
1770 DUP,
1771 PUSHB_1,
1772 sal_anchor,
1774 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
1775 ROLL,
1776 SWAP,
1777 MD_orig_ZP2_0,
1778 SWAP,
1779 GC_cur,
1780 ADD, /* s: [...] edge2 cur_len edge org_pos */
1781 PUSHB_1,
1782 sal_org_len,
1784 PUSHB_1,
1785 2*64,
1786 DIV,
1787 ADD, /* s: [...] edge2 cur_len edge org_center */
1789 DUP,
1790 PUSHB_1,
1791 bci_round,
1792 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1794 DUP,
1795 ROLL,
1796 ROLL,
1797 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1799 DUP,
1800 PUSHB_1,
1801 sal_u_off,
1803 ADD,
1804 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1806 SWAP,
1807 PUSHB_1,
1808 sal_d_off,
1810 SUB,
1811 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1813 LT, /* delta1 < delta2 */
1815 PUSHB_1,
1816 sal_u_off,
1818 SUB, /* cur_pos1 = cur_pos1 - u_off */
1820 ELSE,
1821 PUSHB_1,
1822 sal_d_off,
1824 ADD, /* cur_pos1 = cur_pos1 + d_off */
1825 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
1827 PUSHB_1,
1829 CINDEX,
1830 PUSHB_1,
1831 2*64,
1832 DIV,
1833 SUB, /* arg = cur_pos1 - cur_len/2 */
1835 SWAP, /* s: [...] edge2 cur_len arg edge */
1836 DUP,
1837 DUP,
1838 PUSHB_1,
1840 MINDEX,
1841 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
1842 GC_cur,
1843 SUB,
1844 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1846 ELSE,
1847 SWAP, /* s: [...] edge2 cur_len edge */
1848 PUSHB_1,
1849 sal_anchor,
1851 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
1852 PUSHB_1,
1854 CINDEX,
1855 PUSHB_1,
1856 sal_anchor,
1858 MD_orig_ZP2_0,
1859 ADD, /* s: [...] edge2 cur_len edge org_pos */
1861 DUP,
1862 PUSHB_1,
1863 sal_org_len,
1865 PUSHB_1,
1866 2*64,
1867 DIV,
1868 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
1870 SWAP,
1871 DUP,
1872 PUSHB_1,
1873 bci_round,
1874 CALL, /* cur_pos1 = ROUND(org_pos) */
1875 SWAP,
1876 PUSHB_1,
1877 sal_org_len,
1879 ADD,
1880 PUSHB_1,
1881 bci_round,
1882 CALL,
1883 PUSHB_1,
1885 CINDEX,
1886 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1888 PUSHB_1,
1890 CINDEX,
1891 PUSHB_1,
1892 2*64,
1893 DIV,
1894 PUSHB_1,
1896 MINDEX,
1897 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1899 DUP,
1900 PUSHB_1,
1902 CINDEX,
1903 ADD,
1904 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1905 SWAP,
1906 PUSHB_1,
1908 CINDEX,
1909 ADD,
1910 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1911 LT, /* delta1 < delta2 */
1913 POP, /* arg = cur_pos1 */
1915 ELSE,
1916 SWAP,
1917 POP, /* arg = cur_pos2 */
1918 EIF, /* s: [...] edge2 cur_len edge arg */
1919 SWAP,
1920 DUP,
1921 DUP,
1922 PUSHB_1,
1924 MINDEX,
1925 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
1926 GC_cur,
1927 SUB,
1928 SHPIX, /* edge = arg */
1929 EIF, /* s: [...] edge2 cur_len edge */
1931 ENDF,
1937 * bci_action_stem_bound
1939 * Handle the STEM action to align two edges of a stem, then moving one
1940 * edge again if necessary to stay bound.
1942 * The code after computing `cur_len' to shift `edge' and `edge2'
1943 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1945 * if cur_len < 96:
1946 * if cur_len < = 64:
1947 * u_off = 32
1948 * d_off = 32
1949 * else:
1950 * u_off = 38
1951 * d_off = 26
1953 * org_pos = anchor + (edge_orig - anchor_orig);
1954 * org_center = org_pos + org_len / 2;
1956 * cur_pos1 = ROUND(org_center)
1957 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1958 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1959 * if (delta1 < delta2):
1960 * cur_pos1 = cur_pos1 - u_off
1961 * else:
1962 * cur_pos1 = cur_pos1 + d_off
1964 * edge = cur_pos1 - cur_len / 2
1966 * else:
1967 * org_pos = anchor + (edge_orig - anchor_orig)
1968 * org_center = org_pos + org_len / 2;
1970 * cur_pos1 = ROUND(org_pos)
1971 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1972 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1973 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1975 * if (delta1 < delta2):
1976 * edge = cur_pos1
1977 * else:
1978 * edge = cur_pos2
1980 * edge2 = edge + cur_len
1982 * in: edge2_is_serif
1983 * edge_is_round
1984 * edge_point (in twilight zone)
1985 * edge2_point (in twilight zone)
1986 * edge[-1] (in twilight zone)
1987 * ... stuff for bci_align_segments (edge) ...
1988 * ... stuff for bci_align_segments (edge2)...
1990 * sal: sal_anchor
1991 * sal_temp1
1992 * sal_temp2
1993 * sal_temp3
1995 * uses: bci_action_stem_common
1998 unsigned char FPGM(bci_action_stem_bound) [] = {
2000 PUSHB_1,
2001 bci_action_stem_bound,
2002 FDEF,
2004 PUSHB_1,
2005 bci_action_stem_common,
2006 CALL,
2008 ROLL, /* s: edge[-1] cur_len edge edge2 */
2009 DUP,
2010 DUP,
2011 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2012 PUSHB_1,
2013 sal_edge2,
2014 SWAP,
2015 WS, /* s: edge[-1] cur_len edge edge2 */
2016 ROLL,
2017 SHPIX, /* edge2 = edge + cur_len */
2019 SWAP, /* s: edge edge[-1] */
2020 DUP,
2021 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2022 GC_cur,
2023 PUSHB_1,
2025 CINDEX,
2026 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2027 GT, /* edge_pos < edge[-1]_pos */
2029 DUP,
2030 ALIGNRP, /* align `edge' to `edge[-1]' */
2031 EIF,
2033 MDAP_noround, /* set rp0 and rp1 to `edge' */
2035 PUSHB_2,
2036 bci_align_segments,
2038 SZP1, /* set zp1 to normal zone 1 */
2039 CALL,
2041 PUSHB_1,
2042 sal_edge2,
2044 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2046 PUSHB_1,
2047 bci_align_segments,
2048 CALL,
2050 ENDF,
2056 * bci_action_stem
2058 * Handle the STEM action to align two edges of a stem.
2060 * See `bci_action_stem_bound' for more details.
2062 * in: edge2_is_serif
2063 * edge_is_round
2064 * edge_point (in twilight zone)
2065 * edge2_point (in twilight zone)
2066 * ... stuff for bci_align_segments (edge) ...
2067 * ... stuff for bci_align_segments (edge2)...
2069 * sal: sal_anchor
2070 * sal_temp1
2071 * sal_temp2
2072 * sal_temp3
2074 * uses: bci_action_stem_common
2077 unsigned char FPGM(bci_action_stem) [] = {
2079 PUSHB_1,
2080 bci_action_stem,
2081 FDEF,
2083 PUSHB_1,
2084 bci_action_stem_common,
2085 CALL,
2087 POP,
2088 SWAP, /* s: cur_len edge2 */
2089 DUP,
2090 DUP,
2091 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2092 PUSHB_1,
2093 sal_edge2,
2094 SWAP,
2095 WS, /* s: cur_len edge2 */
2096 SWAP,
2097 SHPIX, /* edge2 = edge + cur_len */
2099 PUSHB_2,
2100 bci_align_segments,
2102 SZP1, /* set zp1 to normal zone 1 */
2103 CALL,
2105 PUSHB_1,
2106 sal_edge2,
2108 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2110 PUSHB_1,
2111 bci_align_segments,
2112 CALL,
2113 ENDF,
2119 * bci_action_link
2121 * Handle the LINK action to link an edge to another one.
2123 * in: stem_is_serif
2124 * base_is_round
2125 * base_point (in twilight zone)
2126 * stem_point (in twilight zone)
2127 * ... stuff for bci_align_segments (base) ...
2130 unsigned char FPGM(bci_action_link) [] = {
2132 PUSHB_1,
2133 bci_action_link,
2134 FDEF,
2136 PUSHB_1,
2138 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2140 PUSHB_1,
2142 CINDEX,
2143 PUSHB_1,
2145 MINDEX,
2146 DUP, /* s: stem is_round is_serif stem base base */
2147 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2149 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
2151 PUSHB_1,
2152 bci_compute_stem_width,
2153 CALL, /* s: stem new_dist */
2155 SWAP,
2156 DUP,
2157 ALIGNRP, /* align `stem_point' with `base_point' */
2158 DUP,
2159 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
2160 SWAP,
2161 SHPIX, /* stem_point = base_point + new_dist */
2163 PUSHB_2,
2164 bci_align_segments,
2166 SZP1, /* set zp1 to normal zone 1 */
2167 CALL,
2169 ENDF,
2175 * bci_action_anchor
2177 * Handle the ANCHOR action to align two edges
2178 * and to set the edge anchor.
2180 * The code after computing `cur_len' to shift `edge' and `edge2'
2181 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2183 * if cur_len < 96:
2184 * if cur_len < = 64:
2185 * u_off = 32
2186 * d_off = 32
2187 * else:
2188 * u_off = 38
2189 * d_off = 26
2191 * org_center = edge_orig + org_len / 2
2192 * cur_pos1 = ROUND(org_center)
2194 * error1 = ABS(org_center - (cur_pos1 - u_off))
2195 * error2 = ABS(org_center - (cur_pos1 + d_off))
2196 * if (error1 < error2):
2197 * cur_pos1 = cur_pos1 - u_off
2198 * else:
2199 * cur_pos1 = cur_pos1 + d_off
2201 * edge = cur_pos1 - cur_len / 2
2202 * edge2 = edge + cur_len
2204 * else:
2205 * edge = ROUND(edge_orig)
2207 * in: edge2_is_serif
2208 * edge_is_round
2209 * edge_point (in twilight zone)
2210 * edge2_point (in twilight zone)
2211 * ... stuff for bci_align_segments (edge) ...
2213 * sal: sal_anchor
2214 * sal_temp1
2215 * sal_temp2
2216 * sal_temp3
2219 #undef sal_u_off
2220 #define sal_u_off sal_temp1
2221 #undef sal_d_off
2222 #define sal_d_off sal_temp2
2223 #undef sal_org_len
2224 #define sal_org_len sal_temp3
2226 unsigned char FPGM(bci_action_anchor) [] = {
2228 PUSHB_1,
2229 bci_action_anchor,
2230 FDEF,
2232 /* store anchor point number in `sal_anchor' */
2233 PUSHB_2,
2234 sal_anchor,
2236 CINDEX,
2237 WS, /* sal_anchor = edge_point */
2239 PUSHB_1,
2241 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2243 PUSHB_1,
2245 CINDEX,
2246 PUSHB_1,
2248 CINDEX,
2249 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
2250 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2252 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2253 DUP,
2254 PUSHB_1,
2255 sal_org_len,
2256 SWAP,
2259 PUSHB_1,
2260 bci_compute_stem_width,
2261 CALL, /* s: edge2 edge cur_len */
2263 DUP,
2264 PUSHB_1,
2266 LT, /* cur_len < 96 */
2268 DUP,
2269 PUSHB_1,
2271 LTEQ, /* cur_len <= 64 */
2273 PUSHB_4,
2274 sal_u_off,
2276 sal_d_off,
2279 ELSE,
2280 PUSHB_4,
2281 sal_u_off,
2283 sal_d_off,
2285 EIF,
2289 SWAP, /* s: edge2 cur_len edge */
2290 DUP, /* s: edge2 cur_len edge edge */
2292 GC_orig,
2293 PUSHB_1,
2294 sal_org_len,
2296 PUSHB_1,
2297 2*64,
2298 DIV,
2299 ADD, /* s: edge2 cur_len edge org_center */
2301 DUP,
2302 PUSHB_1,
2303 bci_round,
2304 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2306 DUP,
2307 ROLL,
2308 ROLL,
2309 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2311 DUP,
2312 PUSHB_1,
2313 sal_u_off,
2315 ADD,
2316 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2318 SWAP,
2319 PUSHB_1,
2320 sal_d_off,
2322 SUB,
2323 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2325 LT, /* error1 < error2 */
2327 PUSHB_1,
2328 sal_u_off,
2330 SUB, /* cur_pos1 = cur_pos1 - u_off */
2332 ELSE,
2333 PUSHB_1,
2334 sal_d_off,
2336 ADD, /* cur_pos1 = cur_pos1 + d_off */
2337 EIF, /* s: edge2 cur_len edge cur_pos1 */
2339 PUSHB_1,
2341 CINDEX,
2342 PUSHB_1,
2343 2*64,
2344 DIV,
2345 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2347 PUSHB_1,
2349 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2350 GC_cur,
2351 SUB,
2352 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2354 SWAP, /* s: cur_len edge2 */
2355 DUP,
2356 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2357 SWAP,
2358 SHPIX, /* edge2 = edge1 + cur_len */
2360 ELSE,
2361 POP, /* s: edge2 edge */
2362 DUP,
2363 DUP,
2364 GC_cur,
2365 SWAP,
2366 GC_orig,
2367 PUSHB_1,
2368 bci_round,
2369 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2370 SWAP,
2371 SUB,
2372 SHPIX, /* edge = round(edge_orig) */
2374 /* clean up stack */
2375 POP,
2376 EIF,
2378 PUSHB_2,
2379 bci_align_segments,
2381 SZP1, /* set zp1 to normal zone 1 */
2382 CALL,
2384 ENDF,
2390 * bci_action_blue_anchor
2392 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2393 * and to set the edge anchor.
2395 * in: anchor_point (in twilight zone)
2396 * blue_cvt_idx
2397 * edge_point (in twilight zone)
2398 * ... stuff for bci_align_segments (edge) ...
2400 * sal: sal_anchor
2402 * uses: bci_action_blue
2405 unsigned char FPGM(bci_action_blue_anchor) [] = {
2407 PUSHB_1,
2408 bci_action_blue_anchor,
2409 FDEF,
2411 /* store anchor point number in `sal_anchor' */
2412 PUSHB_1,
2413 sal_anchor,
2414 SWAP,
2417 PUSHB_1,
2418 bci_action_blue,
2419 CALL,
2421 ENDF,
2427 * bci_action_blue
2429 * Handle the BLUE action to align an edge with a blue zone.
2431 * in: blue_cvt_idx
2432 * edge_point (in twilight zone)
2433 * ... stuff for bci_align_segments (edge) ...
2436 unsigned char FPGM(bci_action_blue) [] = {
2438 PUSHB_1,
2439 bci_action_blue,
2440 FDEF,
2442 PUSHB_1,
2444 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2446 /* move `edge_point' to `blue_cvt_idx' position; */
2447 /* note that we can't use MIAP since this would modify */
2448 /* the twilight point's original coordinates also */
2449 RCVT,
2450 SWAP,
2451 DUP,
2452 MDAP_noround, /* set rp0 and rp1 to `edge' */
2453 DUP,
2454 GC_cur, /* s: new_pos edge edge_pos */
2455 ROLL,
2456 SWAP,
2457 SUB, /* s: edge (new_pos - edge_pos) */
2458 SHPIX,
2460 PUSHB_2,
2461 bci_align_segments,
2463 SZP1, /* set zp1 to normal zone 1 */
2464 CALL,
2466 ENDF,
2472 * bci_action_serif_common
2474 * Common code for bci_action_serif routines.
2477 unsigned char FPGM(bci_action_serif_common) [] = {
2479 PUSHB_1,
2480 bci_action_serif_common,
2481 FDEF,
2483 PUSHB_1,
2485 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2487 DUP,
2488 DUP,
2489 DUP,
2490 PUSHB_1,
2492 MINDEX, /* s: [...] serif serif serif serif base */
2493 DUP,
2494 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2495 MD_orig_ZP2_0,
2496 SWAP,
2497 ALIGNRP, /* align `serif_point' with `base_point' */
2498 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2500 ENDF,
2506 * bci_lower_bound
2508 * Move an edge if necessary to stay within a lower bound.
2510 * in: edge
2511 * bound
2514 unsigned char FPGM(bci_lower_bound) [] = {
2516 PUSHB_1,
2517 bci_lower_bound,
2518 FDEF,
2520 SWAP, /* s: edge bound */
2521 DUP,
2522 MDAP_noround, /* set rp0 and rp1 to `bound' */
2523 GC_cur,
2524 PUSHB_1,
2526 CINDEX,
2527 GC_cur, /* s: edge bound_pos edge_pos */
2528 GT, /* edge_pos < bound_pos */
2530 DUP,
2531 ALIGNRP, /* align `edge' to `bound' */
2532 EIF,
2534 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2536 PUSHB_2,
2537 bci_align_segments,
2539 SZP1, /* set zp1 to normal zone 1 */
2540 CALL,
2542 ENDF,
2548 * bci_upper_bound
2550 * Move an edge if necessary to stay within an upper bound.
2552 * in: edge
2553 * bound
2556 unsigned char FPGM(bci_upper_bound) [] = {
2558 PUSHB_1,
2559 bci_upper_bound,
2560 FDEF,
2562 SWAP, /* s: edge bound */
2563 DUP,
2564 MDAP_noround, /* set rp0 and rp1 to `bound' */
2565 GC_cur,
2566 PUSHB_1,
2568 CINDEX,
2569 GC_cur, /* s: edge bound_pos edge_pos */
2570 LT, /* edge_pos > bound_pos */
2572 DUP,
2573 ALIGNRP, /* align `edge' to `bound' */
2574 EIF,
2576 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2578 PUSHB_2,
2579 bci_align_segments,
2581 SZP1, /* set zp1 to normal zone 1 */
2582 CALL,
2584 ENDF,
2590 * bci_lower_upper_bound
2592 * Move an edge if necessary to stay within a lower and lower bound.
2594 * in: edge
2595 * lower
2596 * upper
2599 unsigned char FPGM(bci_lower_upper_bound) [] = {
2601 PUSHB_1,
2602 bci_lower_upper_bound,
2603 FDEF,
2605 SWAP, /* s: upper serif lower */
2606 DUP,
2607 MDAP_noround, /* set rp0 and rp1 to `lower' */
2608 GC_cur,
2609 PUSHB_1,
2611 CINDEX,
2612 GC_cur, /* s: upper serif lower_pos serif_pos */
2613 GT, /* serif_pos < lower_pos */
2615 DUP,
2616 ALIGNRP, /* align `serif' to `lower' */
2617 EIF,
2619 SWAP, /* s: serif upper */
2620 DUP,
2621 MDAP_noround, /* set rp0 and rp1 to `upper' */
2622 GC_cur,
2623 PUSHB_1,
2625 CINDEX,
2626 GC_cur, /* s: serif upper_pos serif_pos */
2627 LT, /* serif_pos > upper_pos */
2629 DUP,
2630 ALIGNRP, /* align `serif' to `upper' */
2631 EIF,
2633 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2635 PUSHB_2,
2636 bci_align_segments,
2638 SZP1, /* set zp1 to normal zone 1 */
2639 CALL,
2641 ENDF,
2647 * bci_action_serif
2649 * Handle the SERIF action to align a serif with its base.
2651 * in: serif_point (in twilight zone)
2652 * base_point (in twilight zone)
2653 * ... stuff for bci_align_segments (serif) ...
2655 * uses: bci_action_serif_common
2658 unsigned char FPGM(bci_action_serif) [] = {
2660 PUSHB_1,
2661 bci_action_serif,
2662 FDEF,
2664 PUSHB_1,
2665 bci_action_serif_common,
2666 CALL,
2668 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2670 PUSHB_2,
2671 bci_align_segments,
2673 SZP1, /* set zp1 to normal zone 1 */
2674 CALL,
2676 ENDF,
2682 * bci_action_serif_lower_bound
2684 * Handle the SERIF action to align a serif with its base, then moving it
2685 * again if necessary to stay within a lower bound.
2687 * in: serif_point (in twilight zone)
2688 * base_point (in twilight zone)
2689 * edge[-1] (in twilight zone)
2690 * ... stuff for bci_align_segments (serif) ...
2692 * uses: bci_action_serif_common
2693 * bci_lower_bound
2696 unsigned char FPGM(bci_action_serif_lower_bound) [] = {
2698 PUSHB_1,
2699 bci_action_serif_lower_bound,
2700 FDEF,
2702 PUSHB_1,
2703 bci_action_serif_common,
2704 CALL,
2706 PUSHB_1,
2707 bci_lower_bound,
2708 CALL,
2710 ENDF,
2716 * bci_action_serif_upper_bound
2718 * Handle the SERIF action to align a serif with its base, then moving it
2719 * again if necessary to stay within an upper bound.
2721 * in: serif_point (in twilight zone)
2722 * base_point (in twilight zone)
2723 * edge[1] (in twilight zone)
2724 * ... stuff for bci_align_segments (serif) ...
2726 * uses: bci_action_serif_common
2727 * bci_upper_bound
2730 unsigned char FPGM(bci_action_serif_upper_bound) [] = {
2732 PUSHB_1,
2733 bci_action_serif_upper_bound,
2734 FDEF,
2736 PUSHB_1,
2737 bci_action_serif_common,
2738 CALL,
2740 PUSHB_1,
2741 bci_upper_bound,
2742 CALL,
2744 ENDF,
2750 * bci_action_serif_lower_upper_bound
2752 * Handle the SERIF action to align a serif with its base, then moving it
2753 * again if necessary to stay within a lower and upper bound.
2755 * in: serif_point (in twilight zone)
2756 * base_point (in twilight zone)
2757 * edge[-1] (in twilight zone)
2758 * edge[1] (in twilight zone)
2759 * ... stuff for bci_align_segments (serif) ...
2761 * uses: bci_action_serif_common
2762 * bci_lower_upper_bound
2765 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] = {
2767 PUSHB_1,
2768 bci_action_serif_lower_upper_bound,
2769 FDEF,
2771 PUSHB_1,
2773 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2775 PUSHB_1,
2776 bci_action_serif_common,
2777 CALL,
2779 PUSHB_1,
2780 bci_lower_upper_bound,
2781 CALL,
2783 ENDF,
2789 * bci_action_serif_anchor_common
2791 * Common code for bci_action_serif_anchor routines.
2794 unsigned char FPGM(bci_action_serif_anchor_common) [] = {
2796 PUSHB_1,
2797 bci_action_serif_anchor_common,
2798 FDEF,
2800 PUSHB_1,
2802 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2804 DUP,
2805 PUSHB_1,
2806 sal_anchor,
2807 SWAP,
2808 WS, /* sal_anchor = edge_point */
2810 DUP,
2811 DUP,
2812 DUP,
2813 GC_cur,
2814 SWAP,
2815 GC_orig,
2816 PUSHB_1,
2817 bci_round,
2818 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
2819 SWAP,
2820 SUB,
2821 SHPIX, /* edge = round(edge_orig) */
2823 ENDF,
2829 * bci_action_serif_anchor
2831 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2832 * anchor.
2834 * in: edge_point (in twilight zone)
2835 * ... stuff for bci_align_segments (edge) ...
2837 * uses: bci_action_serif_anchor_common
2840 unsigned char FPGM(bci_action_serif_anchor) [] = {
2842 PUSHB_1,
2843 bci_action_serif_anchor,
2844 FDEF,
2846 PUSHB_1,
2847 bci_action_serif_anchor_common,
2848 CALL,
2850 MDAP_noround, /* set rp0 and rp1 to `edge' */
2852 PUSHB_2,
2853 bci_align_segments,
2855 SZP1, /* set zp1 to normal zone 1 */
2856 CALL,
2858 ENDF,
2864 * bci_action_serif_anchor_lower_bound
2866 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2867 * anchor, then moving it again if necessary to stay within a lower
2868 * bound.
2870 * in: edge_point (in twilight zone)
2871 * edge[-1] (in twilight zone)
2872 * ... stuff for bci_align_segments (edge) ...
2874 * uses: bci_action_serif_anchor_common
2875 * bci_lower_bound
2878 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] = {
2880 PUSHB_1,
2881 bci_action_serif_anchor_lower_bound,
2882 FDEF,
2884 PUSHB_1,
2885 bci_action_serif_anchor_common,
2886 CALL,
2888 PUSHB_1,
2889 bci_lower_bound,
2890 CALL,
2892 ENDF,
2898 * bci_action_serif_anchor_upper_bound
2900 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2901 * anchor, then moving it again if necessary to stay within an upper
2902 * bound.
2904 * in: edge_point (in twilight zone)
2905 * edge[1] (in twilight zone)
2906 * ... stuff for bci_align_segments (edge) ...
2908 * uses: bci_action_serif_anchor_common
2909 * bci_upper_bound
2912 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] = {
2914 PUSHB_1,
2915 bci_action_serif_anchor_upper_bound,
2916 FDEF,
2918 PUSHB_1,
2919 bci_action_serif_anchor_common,
2920 CALL,
2922 PUSHB_1,
2923 bci_upper_bound,
2924 CALL,
2926 ENDF,
2932 * bci_action_serif_anchor_lower_upper_bound
2934 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2935 * anchor, then moving it again if necessary to stay within a lower and
2936 * upper bound.
2938 * in: edge_point (in twilight zone)
2939 * edge[-1] (in twilight zone)
2940 * edge[1] (in twilight zone)
2941 * ... stuff for bci_align_segments (edge) ...
2943 * uses: bci_action_serif_anchor_common
2944 * bci_lower_upper_bound
2947 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] = {
2949 PUSHB_1,
2950 bci_action_serif_anchor_lower_upper_bound,
2951 FDEF,
2953 PUSHB_1,
2954 bci_action_serif_anchor_common,
2955 CALL,
2957 PUSHB_1,
2958 bci_lower_upper_bound,
2959 CALL,
2961 ENDF,
2967 * bci_action_serif_link1_common
2969 * Common code for bci_action_serif_link1 routines.
2972 unsigned char FPGM(bci_action_serif_link1_common) [] = {
2974 PUSHB_1,
2975 bci_action_serif_link1_common,
2976 FDEF,
2978 PUSHB_1,
2980 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2982 PUSHB_1,
2984 CINDEX, /* s: [...] after edge before after */
2985 PUSHB_1,
2987 CINDEX, /* s: [...] after edge before after before */
2988 MD_orig_ZP2_0,
2989 PUSHB_1,
2991 EQ, /* after_orig_pos == before_orig_pos */
2992 IF, /* s: [...] after edge before */
2993 MDAP_noround, /* set rp0 and rp1 to `before' */
2994 DUP,
2995 ALIGNRP, /* align `edge' with `before' */
2996 SWAP,
2997 POP,
2999 ELSE,
3000 PUSHB_1,
3002 CINDEX, /* s: [...] after edge before edge */
3003 PUSHB_1,
3005 CINDEX, /* s: [...] after edge before edge before */
3006 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3007 PUSHW_1,
3008 0x10, /* 64*64 */
3009 0x00,
3010 MUL,
3012 PUSHB_1,
3014 CINDEX, /* s: [...] after edge before a*64 after */
3015 PUSHB_1,
3017 CINDEX, /* s: [...] after edge before a*64 after before */
3018 MD_cur, /* b = after_pos - before_pos */
3019 MUL, /* s: [...] after edge before a*b */
3021 PUSHB_1,
3023 CINDEX, /* s: [...] after edge before a*b after */
3024 PUSHB_1,
3026 CINDEX, /* s: [...] after edge before a*b after before */
3027 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3028 PUSHW_1,
3029 0x10, /* 64*64 */
3030 0x00,
3031 MUL,
3033 DIV, /* s: [...] after edge before a*b/c */
3035 SWAP,
3036 MDAP_noround, /* set rp0 and rp1 to `before' */
3037 SWAP, /* s: [...] after a*b/c edge */
3038 DUP,
3039 DUP,
3040 ALIGNRP, /* align `edge' with `before' */
3041 ROLL,
3042 SHPIX, /* shift `edge' by `a*b/c' */
3044 SWAP, /* s: [...] edge after */
3045 POP,
3046 EIF,
3048 ENDF,
3054 * bci_action_serif_link1
3056 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3057 * before and after.
3059 * in: before_point (in twilight zone)
3060 * edge_point (in twilight zone)
3061 * after_point (in twilight zone)
3062 * ... stuff for bci_align_segments (edge) ...
3064 * uses: bci_action_serif_link1_common
3067 unsigned char FPGM(bci_action_serif_link1) [] = {
3069 PUSHB_1,
3070 bci_action_serif_link1,
3071 FDEF,
3073 PUSHB_1,
3074 bci_action_serif_link1_common,
3075 CALL,
3077 MDAP_noround, /* set rp0 and rp1 to `edge' */
3079 PUSHB_2,
3080 bci_align_segments,
3082 SZP1, /* set zp1 to normal zone 1 */
3083 CALL,
3085 ENDF,
3091 * bci_action_serif_link1_lower_bound
3093 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3094 * before and after. Additionally, move the serif again if necessary to
3095 * stay within a lower bound.
3097 * in: before_point (in twilight zone)
3098 * edge_point (in twilight zone)
3099 * after_point (in twilight zone)
3100 * edge[-1] (in twilight zone)
3101 * ... stuff for bci_align_segments (edge) ...
3103 * uses: bci_action_serif_link1_common
3104 * bci_lower_bound
3107 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] = {
3109 PUSHB_1,
3110 bci_action_serif_link1_lower_bound,
3111 FDEF,
3113 PUSHB_1,
3114 bci_action_serif_link1_common,
3115 CALL,
3117 PUSHB_1,
3118 bci_lower_bound,
3119 CALL,
3121 ENDF,
3127 * bci_action_serif_link1_upper_bound
3129 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3130 * before and after. Additionally, move the serif again if necessary to
3131 * stay within an upper bound.
3133 * in: before_point (in twilight zone)
3134 * edge_point (in twilight zone)
3135 * after_point (in twilight zone)
3136 * edge[1] (in twilight zone)
3137 * ... stuff for bci_align_segments (edge) ...
3139 * uses: bci_action_serif_link1_common
3140 * bci_upper_bound
3143 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] = {
3145 PUSHB_1,
3146 bci_action_serif_link1_upper_bound,
3147 FDEF,
3149 PUSHB_1,
3150 bci_action_serif_link1_common,
3151 CALL,
3153 PUSHB_1,
3154 bci_upper_bound,
3155 CALL,
3157 ENDF,
3163 * bci_action_serif_link1_lower_upper_bound
3165 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3166 * before and after. Additionally, move the serif again if necessary to
3167 * stay within a lower and upper bound.
3169 * in: before_point (in twilight zone)
3170 * edge_point (in twilight zone)
3171 * after_point (in twilight zone)
3172 * edge[-1] (in twilight zone)
3173 * edge[1] (in twilight zone)
3174 * ... stuff for bci_align_segments (edge) ...
3176 * uses: bci_action_serif_link1_common
3177 * bci_lower_upper_bound
3180 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] = {
3182 PUSHB_1,
3183 bci_action_serif_link1_lower_upper_bound,
3184 FDEF,
3186 PUSHB_1,
3187 bci_action_serif_link1_common,
3188 CALL,
3190 PUSHB_1,
3191 bci_lower_upper_bound,
3192 CALL,
3194 ENDF,
3200 * bci_action_serif_link2_common
3202 * Common code for bci_action_serif_link2 routines.
3205 unsigned char FPGM(bci_action_serif_link2_common) [] = {
3207 PUSHB_1,
3208 bci_action_serif_link2_common,
3209 FDEF,
3211 PUSHB_1,
3213 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3215 DUP, /* s: [...] edge edge */
3216 PUSHB_1,
3217 sal_anchor,
3219 DUP, /* s: [...] edge edge anchor anchor */
3220 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3222 MD_orig_ZP2_0,
3223 DUP,
3224 ADD,
3225 PUSHB_1,
3227 ADD,
3228 FLOOR,
3229 PUSHB_1,
3230 2*64,
3231 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3233 SWAP,
3234 DUP,
3235 DUP,
3236 ALIGNRP, /* align `edge' with `sal_anchor' */
3237 ROLL,
3238 SHPIX, /* shift `edge' by `delta' */
3240 ENDF,
3246 * bci_action_serif_link2
3248 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3250 * in: edge_point (in twilight zone)
3251 * ... stuff for bci_align_segments (edge) ...
3253 * uses: bci_action_serif_link2_common
3256 unsigned char FPGM(bci_action_serif_link2) [] = {
3258 PUSHB_1,
3259 bci_action_serif_link2,
3260 FDEF,
3262 PUSHB_1,
3263 bci_action_serif_link2_common,
3264 CALL,
3266 MDAP_noround, /* set rp0 and rp1 to `edge' */
3268 PUSHB_2,
3269 bci_align_segments,
3271 SZP1, /* set zp1 to normal zone 1 */
3272 CALL,
3274 ENDF,
3280 * bci_action_serif_link2_lower_bound
3282 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3283 * Additionally, move the serif again if necessary to stay within a lower
3284 * bound.
3286 * in: edge_point (in twilight zone)
3287 * edge[-1] (in twilight zone)
3288 * ... stuff for bci_align_segments (edge) ...
3290 * uses: bci_action_serif_link2_common
3291 * bci_lower_bound
3294 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] = {
3296 PUSHB_1,
3297 bci_action_serif_link2_lower_bound,
3298 FDEF,
3300 PUSHB_1,
3301 bci_action_serif_link2_common,
3302 CALL,
3304 PUSHB_1,
3305 bci_lower_bound,
3306 CALL,
3308 ENDF,
3314 * bci_action_serif_link2_upper_bound
3316 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3317 * Additionally, move the serif again if necessary to stay within an upper
3318 * bound.
3320 * in: edge_point (in twilight zone)
3321 * edge[1] (in twilight zone)
3322 * ... stuff for bci_align_segments (edge) ...
3324 * uses: bci_action_serif_link2_common
3325 * bci_upper_bound
3328 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] = {
3330 PUSHB_1,
3331 bci_action_serif_link2_upper_bound,
3332 FDEF,
3334 PUSHB_1,
3335 bci_action_serif_link2_common,
3336 CALL,
3338 PUSHB_1,
3339 bci_upper_bound,
3340 CALL,
3342 ENDF,
3348 * bci_action_serif_link2_lower_upper_bound
3350 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3351 * Additionally, move the serif again if necessary to stay within a lower
3352 * and upper bound.
3354 * in: edge_point (in twilight zone)
3355 * edge[-1] (in twilight zone)
3356 * edge[1] (in twilight zone)
3357 * ... stuff for bci_align_segments (edge) ...
3359 * uses: bci_action_serif_link2_common
3360 * bci_lower_upper_bound
3363 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] = {
3365 PUSHB_1,
3366 bci_action_serif_link2_lower_upper_bound,
3367 FDEF,
3369 PUSHB_1,
3370 bci_action_serif_link2_common,
3371 CALL,
3373 PUSHB_1,
3374 bci_lower_upper_bound,
3375 CALL,
3377 ENDF,
3383 * bci_handle_action
3385 * Execute function.
3387 * in: function_index
3390 unsigned char FPGM(bci_handle_action) [] = {
3392 PUSHB_1,
3393 bci_handle_action,
3394 FDEF,
3396 CALL,
3398 ENDF,
3404 * bci_hint_glyph
3406 * This is the top-level glyph hinting function
3407 * which parses the arguments on the stack and calls subroutines.
3409 * in: num_actions (M)
3410 * action_0_func_idx
3411 * ... data ...
3412 * action_1_func_idx
3413 * ... data ...
3414 * ...
3415 * action_M_func_idx
3416 * ... data ...
3418 * uses: bci_handle_action
3420 * bci_action_ip_before
3421 * bci_action_ip_after
3422 * bci_action_ip_on
3423 * bci_action_ip_between
3425 * bci_action_adjust_bound
3426 * bci_action_stem_bound
3428 * bci_action_link
3429 * bci_action_anchor
3430 * bci_action_blue_anchor
3431 * bci_action_adjust
3432 * bci_action_stem
3433 * bci_action_blue
3435 * bci_action_serif
3436 * bci_action_serif_lower_bound
3437 * bci_action_serif_upper_bound
3438 * bci_action_serif_lower_upper_bound
3440 * bci_action_serif_anchor
3441 * bci_action_serif_anchor_lower_bound
3442 * bci_action_serif_anchor_upper_bound
3443 * bci_action_serif_anchor_lower_upper_bound
3445 * bci_action_serif_link1
3446 * bci_action_serif_link1_lower_bound
3447 * bci_action_serif_link1_upper_bound
3448 * bci_action_serif_link1_lower_upper_bound
3450 * bci_action_serif_link2
3451 * bci_action_serif_link2_lower_bound
3452 * bci_action_serif_link2_upper_bound
3453 * bci_action_serif_link2_lower_upper_bound
3456 unsigned char FPGM(bci_hint_glyph) [] = {
3458 PUSHB_1,
3459 bci_hint_glyph,
3460 FDEF,
3462 PUSHB_1,
3463 bci_handle_action,
3464 LOOPCALL,
3466 PUSHB_1,
3468 SZP2, /* set zp2 to normal zone 1 */
3469 IUP_y,
3471 ENDF,
3476 #define COPY_FPGM(func_name) \
3477 memcpy(buf_p, fpgm_ ## func_name, \
3478 sizeof (fpgm_ ## func_name)); \
3479 buf_p += sizeof (fpgm_ ## func_name) \
3481 static FT_Error
3482 TA_table_build_fpgm(FT_Byte** fpgm,
3483 FT_ULong* fpgm_len,
3484 FONT* font)
3486 FT_UInt buf_len;
3487 FT_UInt len;
3488 FT_Byte* buf;
3489 FT_Byte* buf_p;
3492 buf_len = sizeof (FPGM(bci_round))
3493 + sizeof (FPGM(bci_compute_stem_width_a))
3495 + sizeof (FPGM(bci_compute_stem_width_b))
3497 + sizeof (FPGM(bci_compute_stem_width_c))
3498 + sizeof (FPGM(bci_loop))
3499 + sizeof (FPGM(bci_cvt_rescale))
3500 + sizeof (FPGM(bci_blue_round_a))
3502 + sizeof (FPGM(bci_blue_round_b))
3503 + sizeof (FPGM(bci_get_point_extrema))
3505 + sizeof (FPGM(bci_create_segment))
3506 + sizeof (FPGM(bci_create_segments))
3507 + sizeof (FPGM(bci_align_segment))
3508 + sizeof (FPGM(bci_align_segments))
3510 + sizeof (FPGM(bci_scale_contour))
3511 + sizeof (FPGM(bci_scale_glyph))
3512 + sizeof (FPGM(bci_shift_contour))
3513 + sizeof (FPGM(bci_shift_subglyph))
3515 + sizeof (FPGM(bci_ip_outer_align_point))
3516 + sizeof (FPGM(bci_ip_on_align_points))
3517 + sizeof (FPGM(bci_ip_between_align_point))
3518 + sizeof (FPGM(bci_ip_between_align_points))
3520 + sizeof (FPGM(bci_action_adjust_common))
3521 + sizeof (FPGM(bci_action_stem_common))
3522 + sizeof (FPGM(bci_action_serif_common))
3523 + sizeof (FPGM(bci_action_serif_anchor_common))
3524 + sizeof (FPGM(bci_action_serif_link1_common))
3525 + sizeof (FPGM(bci_action_serif_link2_common))
3527 + sizeof (FPGM(bci_lower_bound))
3528 + sizeof (FPGM(bci_upper_bound))
3529 + sizeof (FPGM(bci_lower_upper_bound))
3531 + sizeof (FPGM(bci_action_ip_before))
3532 + sizeof (FPGM(bci_action_ip_after))
3533 + sizeof (FPGM(bci_action_ip_on))
3534 + sizeof (FPGM(bci_action_ip_between))
3536 + sizeof (FPGM(bci_action_adjust_bound))
3537 + sizeof (FPGM(bci_action_stem_bound))
3538 + sizeof (FPGM(bci_action_link))
3539 + sizeof (FPGM(bci_action_anchor))
3540 + sizeof (FPGM(bci_action_blue_anchor))
3541 + sizeof (FPGM(bci_action_adjust))
3542 + sizeof (FPGM(bci_action_stem))
3543 + sizeof (FPGM(bci_action_blue))
3544 + sizeof (FPGM(bci_action_serif))
3545 + sizeof (FPGM(bci_action_serif_lower_bound))
3546 + sizeof (FPGM(bci_action_serif_upper_bound))
3547 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
3548 + sizeof (FPGM(bci_action_serif_anchor))
3549 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
3550 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
3551 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
3552 + sizeof (FPGM(bci_action_serif_link1))
3553 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
3554 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
3555 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
3556 + sizeof (FPGM(bci_action_serif_link2))
3557 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
3558 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
3559 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
3561 + sizeof (FPGM(bci_handle_action))
3562 + sizeof (FPGM(bci_hint_glyph));
3563 /* buffer length must be a multiple of four */
3564 len = (buf_len + 3) & ~3;
3565 buf = (FT_Byte*)malloc(len);
3566 if (!buf)
3567 return FT_Err_Out_Of_Memory;
3569 /* pad end of buffer with zeros */
3570 buf[len - 1] = 0x00;
3571 buf[len - 2] = 0x00;
3572 buf[len - 3] = 0x00;
3574 /* copy font program into buffer and fill in the missing variables */
3575 buf_p = buf;
3577 COPY_FPGM(bci_round);
3578 COPY_FPGM(bci_compute_stem_width_a);
3579 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3580 COPY_FPGM(bci_compute_stem_width_b);
3581 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3582 COPY_FPGM(bci_compute_stem_width_c);
3583 COPY_FPGM(bci_loop);
3584 COPY_FPGM(bci_cvt_rescale);
3585 COPY_FPGM(bci_blue_round_a);
3586 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
3587 COPY_FPGM(bci_blue_round_b);
3588 COPY_FPGM(bci_get_point_extrema);
3590 COPY_FPGM(bci_create_segment);
3591 COPY_FPGM(bci_create_segments);
3592 COPY_FPGM(bci_align_segment);
3593 COPY_FPGM(bci_align_segments);
3595 COPY_FPGM(bci_scale_contour);
3596 COPY_FPGM(bci_scale_glyph);
3597 COPY_FPGM(bci_shift_contour);
3598 COPY_FPGM(bci_shift_subglyph);
3600 COPY_FPGM(bci_ip_outer_align_point);
3601 COPY_FPGM(bci_ip_on_align_points);
3602 COPY_FPGM(bci_ip_between_align_point);
3603 COPY_FPGM(bci_ip_between_align_points);
3605 COPY_FPGM(bci_action_adjust_common);
3606 COPY_FPGM(bci_action_stem_common);
3607 COPY_FPGM(bci_action_serif_common);
3608 COPY_FPGM(bci_action_serif_anchor_common);
3609 COPY_FPGM(bci_action_serif_link1_common);
3610 COPY_FPGM(bci_action_serif_link2_common);
3612 COPY_FPGM(bci_lower_bound);
3613 COPY_FPGM(bci_upper_bound);
3614 COPY_FPGM(bci_lower_upper_bound);
3616 COPY_FPGM(bci_action_ip_before);
3617 COPY_FPGM(bci_action_ip_after);
3618 COPY_FPGM(bci_action_ip_on);
3619 COPY_FPGM(bci_action_ip_between);
3621 COPY_FPGM(bci_action_adjust_bound);
3622 COPY_FPGM(bci_action_stem_bound);
3623 COPY_FPGM(bci_action_link);
3624 COPY_FPGM(bci_action_anchor);
3625 COPY_FPGM(bci_action_blue_anchor);
3626 COPY_FPGM(bci_action_adjust);
3627 COPY_FPGM(bci_action_stem);
3628 COPY_FPGM(bci_action_blue);
3629 COPY_FPGM(bci_action_serif);
3630 COPY_FPGM(bci_action_serif_lower_bound);
3631 COPY_FPGM(bci_action_serif_upper_bound);
3632 COPY_FPGM(bci_action_serif_lower_upper_bound);
3633 COPY_FPGM(bci_action_serif_anchor);
3634 COPY_FPGM(bci_action_serif_anchor_lower_bound);
3635 COPY_FPGM(bci_action_serif_anchor_upper_bound);
3636 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
3637 COPY_FPGM(bci_action_serif_link1);
3638 COPY_FPGM(bci_action_serif_link1_lower_bound);
3639 COPY_FPGM(bci_action_serif_link1_upper_bound);
3640 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
3641 COPY_FPGM(bci_action_serif_link2);
3642 COPY_FPGM(bci_action_serif_link2_lower_bound);
3643 COPY_FPGM(bci_action_serif_link2_upper_bound);
3644 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
3646 COPY_FPGM(bci_handle_action);
3647 COPY_FPGM(bci_hint_glyph);
3649 *fpgm = buf;
3650 *fpgm_len = buf_len;
3652 return FT_Err_Ok;
3656 FT_Error
3657 TA_sfnt_build_fpgm_table(SFNT* sfnt,
3658 FONT* font)
3660 FT_Error error;
3662 FT_Byte* fpgm_buf;
3663 FT_ULong fpgm_len;
3666 error = TA_sfnt_add_table_info(sfnt);
3667 if (error)
3668 return error;
3670 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
3671 if (error)
3672 return error;
3674 if (fpgm_len > sfnt->max_instructions)
3675 sfnt->max_instructions = fpgm_len;
3677 /* in case of success, `fpgm_buf' gets linked */
3678 /* and is eventually freed in `TA_font_unload' */
3679 error = TA_font_add_table(font,
3680 &sfnt->table_infos[sfnt->num_table_infos - 1],
3681 TTAG_fpgm, fpgm_len, fpgm_buf);
3682 if (error)
3684 free(fpgm_buf);
3685 return error;
3688 return FT_Err_Ok;
3691 /* end of tafpgm.c */