Version 0.6.1.
[ttfautohint.git] / src / tafpgm.c
blob93499fad70d5daffd80b70d05f018e65f6ca301b
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
32 GC_orig, \
33 SWAP, \
34 GC_orig, \
35 SWAP, \
36 SUB
38 #define MD_orig_ZP2_0 \
39 MD_orig_fixed
41 #define MD_orig_ZP2_1 \
42 PUSHB_1, \
43 0, \
44 SZP2, \
45 MD_orig_fixed, \
46 PUSHB_1, \
47 1, \
48 SZP2
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
52 #define DO_SCALE \
53 DUP, /* s: a a */ \
54 PUSHB_1, \
55 cvtl_scale, \
56 RCVT, \
57 MUL, /* delta * 2^10 */ \
58 PUSHB_1, \
59 cvtl_0x10000, \
60 RCVT, \
61 DIV, /* delta */ \
62 ADD /* a + delta */
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
71 * bci_round
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
76 * in: val
77 * out: ROUND(val)
80 unsigned char FPGM(bci_round) [] = {
82 PUSHB_1,
83 bci_round,
84 FDEF,
86 DUP,
87 ABS,
88 PUSHB_1,
89 32,
90 ADD,
91 FLOOR,
92 SWAP,
93 PUSHB_1,
95 LT,
96 IF,
97 NEG,
98 EIF,
100 ENDF,
106 * bci_compute_stem_width
108 * This is the equivalent to the following code from function
109 * `ta_latin_compute_stem_width':
111 * dist = ABS(width)
113 * if (stem_is_serif
114 * && dist < 3*64)
115 * || is_extra_light:
116 * return width
117 * else if base_is_round:
118 * if dist < 80
119 * dist = 64
120 * else if dist < 56:
121 * dist = 56
123 * delta = ABS(dist - std_width)
125 * if delta < 40:
126 * dist = std_width
127 * if dist < 48
128 * dist = 48
129 * goto End
131 * if dist < 3*64:
132 * delta = dist
133 * dist = FLOOR(dist)
134 * delta = delta - dist
136 * if delta < 10:
137 * dist = dist + delta
138 * else if delta < 32:
139 * dist = dist + 10
140 * else if delta < 54:
141 * dist = dist + 54
142 * else
143 * dist = dist + delta
144 * else
145 * dist = ROUND(dist)
147 * End:
148 * if width < 0:
149 * dist = -dist
150 * return dist
153 * in: width
154 * stem_is_serif
155 * base_is_round
157 * out: new_width
159 * CVT: cvtl_is_extra_light
160 * std_width
163 unsigned char FPGM(bci_compute_stem_width_a) [] = {
165 PUSHB_1,
166 bci_compute_stem_width,
167 FDEF,
169 DUP,
170 ABS, /* s: base_is_round stem_is_serif width dist */
172 DUP,
173 PUSHB_1,
174 3*64,
175 LT, /* dist < 3*64 */
177 PUSHB_1,
179 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
180 AND, /* stem_is_serif && dist < 3*64 */
182 PUSHB_1,
183 cvtl_is_extra_light,
184 RCVT,
185 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
187 IF, /* s: base_is_round width dist */
188 POP,
189 SWAP,
190 POP, /* s: width */
192 ELSE,
193 ROLL, /* s: width dist base_is_round */
194 IF, /* s: width dist */
195 DUP,
196 PUSHB_1,
198 LT, /* dist < 80 */
199 IF, /* s: width dist */
200 POP,
201 PUSHB_1,
202 64, /* dist = 64 */
203 EIF,
205 ELSE,
206 DUP,
207 PUSHB_1,
209 LT, /* dist < 56 */
210 IF, /* s: width dist */
211 POP,
212 PUSHB_1,
213 56, /* dist = 56 */
214 EIF,
215 EIF,
217 DUP, /* s: width dist dist */
218 PUSHB_1,
222 /* %c, index of std_width */
224 unsigned char FPGM(bci_compute_stem_width_b) [] = {
226 RCVT,
227 SUB,
228 ABS, /* s: width dist delta */
230 PUSHB_1,
232 LT, /* delta < 40 */
233 IF, /* s: width dist */
234 POP,
235 PUSHB_1,
239 /* %c, index of std_width */
241 unsigned char FPGM(bci_compute_stem_width_c) [] = {
243 RCVT, /* dist = std_width */
244 DUP,
245 PUSHB_1,
247 LT, /* dist < 48 */
249 POP,
250 PUSHB_1,
251 48, /* dist = 48 */
252 EIF,
254 ELSE,
255 DUP, /* s: width dist dist */
256 PUSHB_1,
257 3*64,
258 LT, /* dist < 3*64 */
260 DUP, /* s: width delta dist */
261 FLOOR, /* dist = FLOOR(dist) */
262 DUP, /* s: width delta dist dist */
263 ROLL,
264 ROLL, /* s: width dist delta dist */
265 SUB, /* delta = delta - dist */
267 DUP, /* s: width dist delta delta */
268 PUSHB_1,
270 LT, /* delta < 10 */
271 IF, /* s: width dist delta */
272 ADD, /* dist = dist + delta */
274 ELSE,
275 DUP,
276 PUSHB_1,
278 LT, /* delta < 32 */
280 POP,
281 PUSHB_1,
283 ADD, /* dist = dist + 10 */
285 ELSE,
286 DUP,
287 PUSHB_1,
289 LT, /* delta < 54 */
291 POP,
292 PUSHB_1,
294 ADD, /* dist = dist + 54 */
296 ELSE,
297 ADD, /* dist = dist + delta */
299 EIF,
300 EIF,
301 EIF,
303 ELSE,
304 PUSHB_1,
305 bci_round,
306 CALL, /* dist = round(dist) */
308 EIF,
309 EIF,
311 SWAP, /* s: dist width */
312 PUSHB_1,
314 LT, /* width < 0 */
316 NEG, /* dist = -dist */
317 EIF,
318 EIF,
320 ENDF,
326 * bci_loop
328 * Take a range and a function number and apply the function to all
329 * elements of the range.
331 * in: func_num
332 * end
333 * start
335 * sal: sal_i (counter initialized with `start')
336 * sal_limit (`end')
337 * sal_func (`func_num')
340 unsigned char FPGM(bci_loop) [] = {
342 PUSHB_1,
343 bci_loop,
344 FDEF,
346 PUSHB_1,
347 sal_func,
348 SWAP,
349 WS, /* sal_func = func_num */
350 PUSHB_1,
351 sal_limit,
352 SWAP,
353 WS, /* sal_limit = end */
354 PUSHB_1,
355 sal_i,
356 SWAP,
357 WS, /* sal_i = start */
359 /* start_loop: */
360 PUSHB_1,
361 sal_i,
363 PUSHB_1,
364 sal_limit,
366 LTEQ, /* start <= end */
368 PUSHB_1,
369 sal_func,
371 CALL,
372 PUSHB_3,
373 sal_i,
375 sal_i,
377 ADD, /* start = start + 1 */
380 PUSHB_1,
382 NEG,
383 JMPR, /* goto start_loop */
384 EIF,
386 ENDF,
392 * bci_cvt_rescale
394 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
396 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
397 * consequently, the calculation `a * b/c' is done as `a + delta' with
398 * `delta = a * (b-c)/c'. This avoids overflow.
400 * sal: sal_i (CVT index)
402 * CVT: cvtl_scale
403 * cvtl_0x10000
406 unsigned char FPGM(bci_cvt_rescale) [] = {
408 PUSHB_1,
409 bci_cvt_rescale,
410 FDEF,
412 PUSHB_1,
413 sal_i,
415 DUP,
416 RCVT,
417 DO_SCALE,
418 WCVTP,
420 ENDF,
426 * bci_blue_round
428 * Round a blue ref value and adjust its corresponding shoot value.
430 * sal: sal_i (CVT index)
434 unsigned char FPGM(bci_blue_round_a) [] = {
436 PUSHB_1,
437 bci_blue_round,
438 FDEF,
440 PUSHB_1,
441 sal_i,
443 DUP,
444 RCVT, /* s: ref_idx ref */
446 DUP,
447 PUSHB_1,
448 bci_round,
449 CALL,
450 SWAP, /* s: ref_idx round(ref) ref */
452 PUSHB_2,
456 /* %c, blue_count */
458 unsigned char FPGM(bci_blue_round_b) [] = {
461 CINDEX,
462 ADD, /* s: ref_idx round(ref) ref shoot_idx */
463 DUP,
464 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
466 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
467 SWAP,
468 SUB, /* s: ref_idx round(ref) shoot_idx dist */
469 DUP,
470 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
472 DUP,
473 PUSHB_1,
475 LT, /* delta < 32 */
477 POP,
478 PUSHB_1,
479 0, /* delta = 0 */
481 ELSE,
482 PUSHB_1,
484 LT, /* delta < 48 */
486 PUSHB_1,
487 32, /* delta = 32 */
489 ELSE,
490 PUSHB_1,
491 64, /* delta = 64 */
492 EIF,
493 EIF,
495 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
496 PUSHB_1,
498 LT, /* dist < 0 */
500 NEG, /* delta = -delta */
501 EIF,
503 PUSHB_1,
505 CINDEX,
506 SWAP,
507 SUB, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
509 WCVTP,
510 WCVTP,
512 ENDF,
518 * bci_decrement_component_counter
520 * An auxiliary function for composite glyphs.
522 * CVT: cvtl_is_subglyph
525 unsigned char FPGM(bci_decrement_component_counter) [] = {
527 PUSHB_1,
528 bci_decrement_component_counter,
529 FDEF,
531 /* decrement `cvtl_is_subglyph' counter */
532 PUSHB_2,
533 cvtl_is_subglyph,
534 cvtl_is_subglyph,
535 RCVT,
536 PUSHB_1,
538 SUB,
539 WCVTP,
541 ENDF,
547 * bci_get_point_extrema
549 * An auxiliary function for `bci_create_segment'.
551 * in: point-1
552 * out: point
554 * sal: sal_point_min
555 * sal_point_max
558 unsigned char FPGM(bci_get_point_extrema) [] = {
560 PUSHB_1,
561 bci_get_point_extrema,
562 FDEF,
564 PUSHB_1,
566 ADD, /* s: point */
567 DUP,
568 DUP,
570 /* check whether `point' is a new minimum */
571 PUSHB_1,
572 sal_point_min,
573 RS, /* s: point point point point_min */
574 MD_orig,
575 /* if distance is negative, we have a new minimum */
576 PUSHB_1,
579 IF, /* s: point point */
580 DUP,
581 PUSHB_1,
582 sal_point_min,
583 SWAP,
585 EIF,
587 /* check whether `point' is a new maximum */
588 PUSHB_1,
589 sal_point_max,
590 RS, /* s: point point point_max */
591 MD_orig,
592 /* if distance is positive, we have a new maximum */
593 PUSHB_1,
596 IF, /* s: point */
597 DUP,
598 PUSHB_1,
599 sal_point_max,
600 SWAP,
602 EIF, /* s: point */
604 ENDF,
610 * bci_create_segment
612 * Store start and end point of a segment in the storage area,
613 * then construct a point in the twilight zone to represent it.
615 * This function is used by `bci_create_segment_points'.
617 * in: start
618 * end
619 * [last (if wrap-around segment)]
620 * [first (if wrap-around segment)]
622 * uses: bci_get_point_extrema
624 * sal: sal_i (start of current segment)
625 * sal_j (current twilight point)
626 * sal_point_min
627 * sal_point_max
629 * CVT: cvtl_scale
630 * cvtl_0x10000
631 * cvtl_temp
634 unsigned char FPGM(bci_create_segment) [] = {
636 PUSHB_1,
637 bci_create_segment,
638 FDEF,
640 PUSHB_1,
641 sal_i,
643 PUSHB_1,
645 CINDEX,
646 WS, /* sal[sal_i] = start */
648 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
649 PUSHB_3,
650 sal_i,
652 sal_i,
654 ADD, /* sal_i = sal_i + 1 */
657 /* initialize inner loop(s) */
658 PUSHB_2,
659 sal_point_min,
661 CINDEX,
662 WS, /* sal_point_min = start */
663 PUSHB_2,
664 sal_point_max,
666 CINDEX,
667 WS, /* sal_point_max = start */
669 PUSHB_1,
671 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
673 SWAP,
674 DUP,
675 PUSHB_1,
677 CINDEX, /* s: start end end start */
678 LT, /* start > end */
680 /* we have a wrap-around segment with two more arguments */
681 /* to give the last and first point of the contour, respectively; */
682 /* our job is to store a segment `start'-`last', */
683 /* and to get extrema for the two segments */
684 /* `start'-`last' and `first'-`end' */
686 /* s: first last start end */
687 PUSHB_1,
688 sal_i,
690 PUSHB_1,
692 CINDEX,
693 WS, /* sal[sal_i] = last */
695 ROLL,
696 ROLL, /* s: first end last start */
697 DUP,
698 ROLL,
699 SWAP, /* s: first end start last start */
700 SUB, /* s: first end start loop_count */
702 PUSHB_1,
703 bci_get_point_extrema,
704 LOOPCALL,
705 /* clean up stack */
706 POP,
708 SWAP, /* s: end first */
709 PUSHB_1,
711 SUB,
712 DUP,
713 ROLL, /* s: (first - 1) (first - 1) end */
714 SWAP,
715 SUB, /* s: (first - 1) loop_count */
717 PUSHB_1,
718 bci_get_point_extrema,
719 LOOPCALL,
720 /* clean up stack */
721 POP,
723 ELSE, /* s: start end */
724 PUSHB_1,
725 sal_i,
727 PUSHB_1,
729 CINDEX,
730 WS, /* sal[sal_i] = end */
732 PUSHB_1,
734 CINDEX,
735 SUB, /* s: start loop_count */
737 PUSHB_1,
738 bci_get_point_extrema,
739 LOOPCALL,
740 /* clean up stack */
741 POP,
742 EIF,
744 /* the twilight point representing a segment */
745 /* is in the middle between the minimum and maximum */
746 PUSHB_1,
747 sal_point_min,
749 GC_orig,
750 PUSHB_1,
751 sal_point_max,
753 GC_orig,
754 ADD,
755 PUSHB_1,
756 2*64,
757 DIV, /* s: middle_pos */
759 DO_SCALE, /* middle_pos = middle_pos * scale */
761 /* write it to temporary CVT location */
762 PUSHB_2,
763 cvtl_temp,
765 SZP0, /* set zp0 to twilight zone 0 */
766 SWAP,
767 WCVTP,
769 /* create twilight point with index `sal_j' */
770 PUSHB_1,
771 sal_j,
773 PUSHB_1,
774 cvtl_temp,
775 MIAP_noround,
777 PUSHB_3,
778 sal_j,
780 sal_j,
782 ADD, /* twilight_point = twilight_point + 1 */
785 ENDF,
791 * bci_create_segments
793 * Set up segments by defining point ranges which defines them
794 * and computing twilight points to represent them.
796 * in: num_segments (N)
797 * segment_start_0
798 * segment_end_0
799 * [contour_last 0 (if wrap-around segment)]
800 * [contour_first 0 (if wrap-around segment)]
801 * segment_start_1
802 * segment_end_1
803 * [contour_last 0 (if wrap-around segment)]
804 * [contour_first 0 (if wrap-around segment)]
805 * ...
806 * segment_start_(N-1)
807 * segment_end_(N-1)
808 * [contour_last (N-1) (if wrap-around segment)]
809 * [contour_first (N-1) (if wrap-around segment)]
811 * uses: bci_create_segment
813 * sal: sal_i (start of current segment)
814 * sal_j (current twilight point)
816 * CVT: cvtl_is_subglyph
819 unsigned char FPGM(bci_create_segments) [] = {
821 PUSHB_1,
822 bci_create_segments,
823 FDEF,
825 /* only do something if we are not a subglyph */
826 PUSHB_2,
828 cvtl_is_subglyph,
829 RCVT,
832 /* all our measurements are taken along the y axis */
833 SVTCA_y,
835 DUP,
836 ADD,
837 PUSHB_1,
839 SUB, /* delta = (2*num_segments - 1) */
841 PUSHB_4,
842 sal_segment_offset,
843 sal_segment_offset,
845 sal_j,
847 WS, /* sal_j = 0 (point offset) */
849 ROLL,
850 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
852 /* `bci_create_segment_point' also increases the loop counter by 1; */
853 /* this effectively means we have a loop step of 2 */
854 PUSHB_2,
855 bci_create_segment,
856 bci_loop,
857 CALL,
859 ELSE,
860 CLEAR,
861 EIF,
863 ENDF,
869 * bci_create_segments_composite
871 * The same as `bci_create_composite'.
872 * It also decrements the composite component counter.
874 * uses: bci_decrement_composite_counter
876 * CVT: cvtl_is_subglyph
879 unsigned char FPGM(bci_create_segments_composite) [] = {
881 PUSHB_1,
882 bci_create_segments_composite,
883 FDEF,
885 PUSHB_1,
886 bci_decrement_component_counter,
887 CALL,
889 /* only do something if we are not a subglyph */
890 PUSHB_2,
892 cvtl_is_subglyph,
893 RCVT,
896 /* all our measurements are taken along the y axis */
897 SVTCA_y,
899 DUP,
900 ADD,
901 PUSHB_1,
903 SUB, /* delta = (2*num_segments - 1) */
905 PUSHB_4,
906 sal_segment_offset,
907 sal_segment_offset,
909 sal_j,
911 WS, /* sal_j = 0 (point offset) */
913 ROLL,
914 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
916 /* `bci_create_segment_point' also increases the loop counter by 1; */
917 /* this effectively means we have a loop step of 2 */
918 PUSHB_2,
919 bci_create_segment,
920 bci_loop,
921 CALL,
923 ELSE,
924 CLEAR,
925 EIF,
927 ENDF,
933 * bci_align_segment
935 * Align all points in a segment to the twilight point in rp0.
936 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
938 * in: segment_index
941 unsigned char FPGM(bci_align_segment) [] = {
943 PUSHB_1,
944 bci_align_segment,
945 FDEF,
947 /* we need the values of `sal_segment_offset + 2*segment_index' */
948 /* and `sal_segment_offset + 2*segment_index + 1' */
949 DUP,
950 ADD,
951 PUSHB_1,
952 sal_segment_offset,
953 ADD,
954 DUP,
956 SWAP,
957 PUSHB_1,
959 ADD,
960 RS, /* s: first last */
962 /* start_loop: */
963 PUSHB_1,
965 CINDEX, /* s: first last first */
966 PUSHB_1,
968 CINDEX, /* s: first last first last */
969 LTEQ, /* first <= end */
970 IF, /* s: first last */
971 SWAP,
972 DUP, /* s: last first first */
973 ALIGNRP, /* align point with index `first' with rp0 */
975 PUSHB_1,
977 ADD, /* first = first + 1 */
978 SWAP, /* s: first last */
980 PUSHB_1,
982 NEG,
983 JMPR, /* goto start_loop */
985 ELSE,
986 POP,
987 POP,
988 EIF,
990 ENDF,
996 * bci_align_segments
998 * Align segments to the twilight point in rp0.
999 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1001 * in: first_segment
1002 * loop_counter (N)
1003 * segment_1
1004 * segment_2
1005 * ...
1006 * segment_N
1008 * uses: handle_segment
1012 unsigned char FPGM(bci_align_segments) [] = {
1014 PUSHB_1,
1015 bci_align_segments,
1016 FDEF,
1018 PUSHB_1,
1019 bci_align_segment,
1020 CALL,
1022 PUSHB_1,
1023 bci_align_segment,
1024 LOOPCALL,
1026 ENDF,
1032 * bci_scale_contour
1034 * Scale a contour using two points giving the maximum and minimum
1035 * coordinates.
1037 * It expects that no point on the contour is touched.
1039 * in: min_point
1040 * max_point
1042 * CVT: cvtl_scale
1043 * cvtl_0x10000
1046 unsigned char FPGM(bci_scale_contour) [] = {
1048 PUSHB_1,
1049 bci_scale_contour,
1050 FDEF,
1052 DUP,
1053 DUP,
1054 GC_orig,
1055 DUP,
1056 DO_SCALE, /* min_pos_new = min_pos * scale */
1057 SWAP,
1058 SUB,
1059 SHPIX,
1061 /* don't scale a single-point contour twice */
1062 SWAP,
1063 DUP,
1064 ROLL,
1065 NEQ,
1067 DUP,
1068 GC_orig,
1069 DUP,
1070 DO_SCALE, /* max_pos_new = max_pos * scale */
1071 SWAP,
1072 SUB,
1073 SHPIX,
1075 ELSE,
1076 POP,
1077 EIF,
1079 ENDF,
1085 * bci_scale_glyph
1087 * Scale a glyph using a list of points (two points per contour, giving
1088 * the maximum and mininum coordinates).
1090 * It expects that no point in the glyph is touched.
1092 * in: num_contours (N)
1093 * min_point_1
1094 * max_point_1
1095 * min_point_2
1096 * max_point_2
1097 * ...
1098 * min_point_N
1099 * max_point_N
1101 * uses: bci_scale_contour
1103 * CVT: cvtl_is_subglyph
1106 unsigned char FPGM(bci_scale_glyph) [] = {
1108 PUSHB_1,
1109 bci_scale_glyph,
1110 FDEF,
1112 /* only do something if we are not a subglyph */
1113 PUSHB_2,
1115 cvtl_is_subglyph,
1116 RCVT,
1119 /* all our measurements are taken along the y axis */
1120 SVTCA_y,
1122 PUSHB_1,
1124 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1126 PUSHB_1,
1127 bci_scale_contour,
1128 LOOPCALL,
1130 PUSHB_1,
1132 SZP2, /* set zp2 to normal zone 1 */
1133 IUP_y,
1135 ELSE,
1136 CLEAR,
1137 EIF,
1139 ENDF,
1145 * bci_scale_composite_glyph
1147 * The same as `bci_scale_composite_glyph'.
1148 * It also decrements the composite component counter.
1150 * uses: bci_decrement_component_counter
1152 * CVT: cvtl_is_subglyph
1155 unsigned char FPGM(bci_scale_composite_glyph) [] = {
1157 PUSHB_1,
1158 bci_scale_composite_glyph,
1159 FDEF,
1161 PUSHB_1,
1162 bci_decrement_component_counter,
1163 CALL,
1165 /* only do something if we are not a subglyph */
1166 PUSHB_2,
1168 cvtl_is_subglyph,
1169 RCVT,
1172 /* all our measurements are taken along the y axis */
1173 SVTCA_y,
1175 PUSHB_1,
1177 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1179 PUSHB_1,
1180 bci_scale_contour,
1181 LOOPCALL,
1183 PUSHB_1,
1185 SZP2, /* set zp2 to normal zone 1 */
1186 IUP_y,
1188 ELSE,
1189 CLEAR,
1190 EIF,
1192 ENDF,
1198 * bci_shift_contour
1200 * Shift a contour by a given amount.
1202 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1203 * point to the normal zone 1.
1205 * in: contour
1206 * out: contour + 1
1209 unsigned char FPGM(bci_shift_contour) [] = {
1211 PUSHB_1,
1212 bci_shift_contour,
1213 FDEF,
1215 DUP,
1216 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1218 PUSHB_1,
1220 ADD,
1222 ENDF,
1228 * bci_shift_subglyph
1230 * Shift a subglyph. To be more specific, it corrects the already applied
1231 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1232 * also.
1234 * If this function is called, a point `x' in the subglyph has been scaled
1235 * already (during the hinting of the subglyph itself), and `offset' has
1236 * been applied also:
1238 * x -> x * scale + offset (1)
1240 * However, the offset should be applied first, then the scaling:
1242 * x -> (x + offset) * scale (2)
1244 * Our job is now to transform (1) to (2); a simple calculation shows that
1245 * we have to shift all points of the subglyph by
1247 * offset * scale - offset = offset * (scale - 1)
1249 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1251 * in: offset (in FUnits)
1252 * num_contours
1253 * first_contour
1255 * CVT: cvtl_funits_to_pixels
1256 * cvtl_0x10000
1257 * cvtl_scale
1260 unsigned char FPGM(bci_shift_subglyph) [] = {
1262 PUSHB_1,
1263 bci_shift_subglyph,
1264 FDEF,
1266 SVTCA_y,
1268 PUSHB_1,
1269 cvtl_funits_to_pixels,
1270 RCVT, /* scaling factor FUnits -> pixels */
1271 MUL,
1272 PUSHB_1,
1273 cvtl_0x10000,
1274 RCVT,
1275 DIV,
1277 /* the autohinter always rounds offsets */
1278 PUSHB_1,
1279 bci_round,
1280 CALL, /* offset = round(offset) */
1282 PUSHB_1,
1283 cvtl_scale,
1284 RCVT,
1285 MUL,
1286 PUSHB_1,
1287 cvtl_0x10000,
1288 RCVT,
1289 DIV, /* delta = offset * (scale - 1) */
1291 /* and round again */
1292 PUSHB_1,
1293 bci_round,
1294 CALL, /* offset = round(offset) */
1296 PUSHB_1,
1298 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1300 /* we create twilight point 0 as a reference point, */
1301 /* setting the original position to zero (using `cvtl_temp') */
1302 PUSHB_5,
1305 cvtl_temp,
1306 cvtl_temp,
1308 WCVTP,
1309 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
1311 SWAP, /* s: first_contour num_contours 0 delta */
1312 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
1314 PUSHB_2,
1315 bci_shift_contour,
1317 SZP2, /* set zp2 to normal zone 1 */
1318 LOOPCALL,
1320 ENDF,
1326 * bci_ip_outer_align_point
1328 * Auxiliary function for `bci_action_ip_before' and
1329 * `bci_action_ip_after'.
1331 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1332 * zone, and both zp1 and zp2 set to normal zone.
1334 * in: point
1336 * sal: sal_i (edge_orig_pos)
1338 * CVT: cvtl_scale
1339 * cvtl_0x10000
1342 unsigned char FPGM(bci_ip_outer_align_point) [] = {
1344 PUSHB_1,
1345 bci_ip_outer_align_point,
1346 FDEF,
1348 DUP,
1349 ALIGNRP, /* align `point' with `edge' */
1350 DUP,
1351 GC_orig,
1352 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1354 PUSHB_1,
1355 sal_i,
1357 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1358 SHPIX,
1360 ENDF,
1366 * bci_ip_on_align_points
1368 * Auxiliary function for `bci_action_ip_on'.
1370 * in: edge (in twilight zone)
1371 * loop_counter (N)
1372 * point_1
1373 * point_2
1374 * ...
1375 * point_N
1378 unsigned char FPGM(bci_ip_on_align_points) [] = {
1380 PUSHB_1,
1381 bci_ip_on_align_points,
1382 FDEF,
1384 MDAP_noround, /* set rp0 and rp1 to `edge' */
1386 SLOOP,
1387 ALIGNRP,
1389 ENDF,
1395 * bci_ip_between_align_point
1397 * Auxiliary function for `bci_ip_between_align_points'.
1399 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1400 * zone, and both zp1 and zp2 set to normal zone.
1402 * in: point
1404 * sal: sal_i (edge_orig_pos)
1405 * sal_j (stretch_factor)
1407 * CVT: cvtl_scale
1408 * cvtl_0x10000
1411 unsigned char FPGM(bci_ip_between_align_point) [] = {
1413 PUSHB_1,
1414 bci_ip_between_align_point,
1415 FDEF,
1417 DUP,
1418 ALIGNRP, /* align `point' with `edge' */
1419 DUP,
1420 GC_orig,
1421 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
1423 PUSHB_1,
1424 sal_i,
1426 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
1427 PUSHB_1,
1428 sal_j,
1430 MUL, /* s: point delta */
1431 SHPIX,
1433 ENDF,
1439 * bci_ip_between_align_points
1441 * Auxiliary function for `bci_action_ip_between'.
1443 * in: after_edge (in twilight zone)
1444 * before_edge (in twilight zone)
1445 * loop_counter (N)
1446 * point_1
1447 * point_2
1448 * ...
1449 * point_N
1451 * sal: sal_i (before_orig_pos)
1452 * sal_j (stretch_factor)
1454 * uses: bci_ip_between_align_point
1457 unsigned char FPGM(bci_ip_between_align_points) [] = {
1459 PUSHB_1,
1460 bci_ip_between_align_points,
1461 FDEF,
1463 PUSHB_2,
1466 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1467 CINDEX,
1468 DUP, /* s: ... before after before before */
1469 MDAP_noround, /* set rp0 and rp1 to `before' */
1470 DUP,
1471 GC_orig, /* s: ... before after before before_orig_pos */
1472 PUSHB_1,
1473 sal_i,
1474 SWAP,
1475 WS, /* sal_i = before_orig_pos */
1476 PUSHB_1,
1478 CINDEX, /* s: ... before after before after */
1479 MD_cur, /* b = after_pos - before_pos */
1480 ROLL,
1481 ROLL,
1482 MD_orig_ZP2_0, /* a = after_orig_pos - before_orig_pos */
1483 DIV, /* s: a/b */
1484 PUSHB_1,
1485 sal_j,
1486 SWAP,
1487 WS, /* sal_j = stretch_factor */
1489 PUSHB_3,
1490 bci_ip_between_align_point,
1493 SZP2, /* set zp2 to normal zone 1 */
1494 SZP1, /* set zp1 to normal zone 1 */
1495 LOOPCALL,
1497 ENDF,
1503 * bci_action_ip_before
1505 * Handle `ip_before' data to align points located before the first edge.
1507 * in: first_edge (in twilight zone)
1508 * loop_counter (N)
1509 * point_1
1510 * point_2
1511 * ...
1512 * point_N
1514 * sal: sal_i (first_edge_orig_pos)
1516 * uses: bci_ip_outer_align_point
1519 unsigned char FPGM(bci_action_ip_before) [] = {
1521 PUSHB_1,
1522 bci_action_ip_before,
1523 FDEF,
1525 PUSHB_1,
1527 SZP2, /* set zp2 to twilight zone 0 */
1529 DUP,
1530 GC_orig,
1531 PUSHB_1,
1532 sal_i,
1533 SWAP,
1534 WS, /* sal_i = first_edge_orig_pos */
1536 PUSHB_3,
1540 SZP2, /* set zp2 to normal zone 1 */
1541 SZP1, /* set zp1 to normal zone 1 */
1542 SZP0, /* set zp0 to twilight zone 0 */
1544 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
1546 PUSHB_1,
1547 bci_ip_outer_align_point,
1548 LOOPCALL,
1550 ENDF,
1556 * bci_action_ip_after
1558 * Handle `ip_after' data to align points located after the last edge.
1560 * in: last_edge (in twilight zone)
1561 * loop_counter (N)
1562 * point_1
1563 * point_2
1564 * ...
1565 * point_N
1567 * sal: sal_i (last_edge_orig_pos)
1569 * uses: bci_ip_outer_align_point
1572 unsigned char FPGM(bci_action_ip_after) [] = {
1574 PUSHB_1,
1575 bci_action_ip_after,
1576 FDEF,
1578 PUSHB_1,
1580 SZP2, /* set zp2 to twilight zone 0 */
1582 DUP,
1583 GC_orig,
1584 PUSHB_1,
1585 sal_i,
1586 SWAP,
1587 WS, /* sal_i = last_edge_orig_pos */
1589 PUSHB_3,
1593 SZP2, /* set zp2 to normal zone 1 */
1594 SZP1, /* set zp1 to normal zone 1 */
1595 SZP0, /* set zp0 to twilight zone 0 */
1597 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
1599 PUSHB_1,
1600 bci_ip_outer_align_point,
1601 LOOPCALL,
1603 ENDF,
1609 * bci_action_ip_on
1611 * Handle `ip_on' data to align points located on an edge coordinate (but
1612 * not part of an edge).
1614 * in: loop_counter (M)
1615 * edge_1 (in twilight zone)
1616 * loop_counter (N_1)
1617 * point_1
1618 * point_2
1619 * ...
1620 * point_N_1
1621 * edge_2 (in twilight zone)
1622 * loop_counter (N_2)
1623 * point_1
1624 * point_2
1625 * ...
1626 * point_N_2
1627 * ...
1628 * edge_M (in twilight zone)
1629 * loop_counter (N_M)
1630 * point_1
1631 * point_2
1632 * ...
1633 * point_N_M
1635 * uses: bci_ip_on_align_points
1638 unsigned char FPGM(bci_action_ip_on) [] = {
1640 PUSHB_1,
1641 bci_action_ip_on,
1642 FDEF,
1644 PUSHB_2,
1647 SZP1, /* set zp1 to normal zone 1 */
1648 SZP0, /* set zp0 to twilight zone 0 */
1650 PUSHB_1,
1651 bci_ip_on_align_points,
1652 LOOPCALL,
1654 ENDF,
1660 * bci_action_ip_between
1662 * Handle `ip_between' data to align points located between two edges.
1664 * in: loop_counter (M)
1665 * before_edge_1 (in twilight zone)
1666 * after_edge_1 (in twilight zone)
1667 * loop_counter (N_1)
1668 * point_1
1669 * point_2
1670 * ...
1671 * point_N_1
1672 * before_edge_2 (in twilight zone)
1673 * after_edge_2 (in twilight zone)
1674 * loop_counter (N_2)
1675 * point_1
1676 * point_2
1677 * ...
1678 * point_N_2
1679 * ...
1680 * before_edge_M (in twilight zone)
1681 * after_edge_M (in twilight zone)
1682 * loop_counter (N_M)
1683 * point_1
1684 * point_2
1685 * ...
1686 * point_N_M
1688 * uses: bci_ip_between_align_points
1691 unsigned char FPGM(bci_action_ip_between) [] = {
1693 PUSHB_1,
1694 bci_action_ip_between,
1695 FDEF,
1697 PUSHB_1,
1698 bci_ip_between_align_points,
1699 LOOPCALL,
1701 ENDF,
1707 * bci_action_adjust_common
1709 * Common code for bci_action_adjust routines.
1712 unsigned char FPGM(bci_action_adjust_common) [] = {
1714 PUSHB_1,
1715 bci_action_adjust_common,
1716 FDEF,
1718 PUSHB_1,
1720 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1722 PUSHB_1,
1724 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
1725 PUSHB_1,
1727 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1728 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1730 PUSHB_1,
1731 bci_compute_stem_width,
1732 CALL,
1733 NEG, /* s: [...] edge2 edge -cur_len */
1735 ROLL, /* s: [...] edge -cur_len edge2 */
1736 MDAP_noround, /* set rp0 and rp1 to `edge2' */
1737 SWAP,
1738 DUP,
1739 DUP, /* s: [...] -cur_len edge edge edge */
1740 ALIGNRP, /* align `edge' with `edge2' */
1741 ROLL,
1742 SHPIX, /* shift `edge' by -cur_len */
1744 ENDF,
1750 * bci_action_adjust_bound
1752 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1753 * edge of the stem has already been moved, then moving it again if
1754 * necessary to stay bound.
1756 * in: edge2_is_serif
1757 * edge_is_round
1758 * edge_point (in twilight zone)
1759 * edge2_point (in twilight zone)
1760 * edge[-1] (in twilight zone)
1761 * ... stuff for bci_align_segments (edge) ...
1763 * uses: bci_action_adjust_common
1766 unsigned char FPGM(bci_action_adjust_bound) [] = {
1768 PUSHB_1,
1769 bci_action_adjust_bound,
1770 FDEF,
1772 PUSHB_1,
1773 bci_action_adjust_common,
1774 CALL,
1776 SWAP, /* s: edge edge[-1] */
1777 DUP,
1778 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
1779 GC_cur,
1780 PUSHB_1,
1782 CINDEX,
1783 GC_cur, /* s: edge edge[-1]_pos edge_pos */
1784 GT, /* edge_pos < edge[-1]_pos */
1786 DUP,
1787 ALIGNRP, /* align `edge' to `edge[-1]' */
1788 EIF,
1790 MDAP_noround, /* set rp0 and rp1 to `edge' */
1792 PUSHB_2,
1793 bci_align_segments,
1795 SZP1, /* set zp1 to normal zone 1 */
1796 CALL,
1798 ENDF,
1804 * bci_action_adjust
1806 * Handle the ADJUST action to align an edge of a stem if the other edge
1807 * of the stem has already been moved.
1809 * in: edge2_is_serif
1810 * edge_is_round
1811 * edge_point (in twilight zone)
1812 * edge2_point (in twilight zone)
1813 * ... stuff for bci_align_segments (edge) ...
1815 * uses: bci_action_adjust_common
1818 unsigned char FPGM(bci_action_adjust) [] = {
1820 PUSHB_1,
1821 bci_action_adjust,
1822 FDEF,
1824 PUSHB_1,
1825 bci_action_adjust_common,
1826 CALL,
1828 MDAP_noround, /* set rp0 and rp1 to `edge' */
1830 PUSHB_2,
1831 bci_align_segments,
1833 SZP1, /* set zp1 to normal zone 1 */
1834 CALL,
1836 ENDF,
1842 * bci_action_stem_common
1844 * Common code for bci_action_stem routines.
1847 #undef sal_u_off
1848 #define sal_u_off sal_temp1
1849 #undef sal_d_off
1850 #define sal_d_off sal_temp2
1851 #undef sal_org_len
1852 #define sal_org_len sal_temp3
1853 #undef sal_edge2
1854 #define sal_edge2 sal_temp3
1856 unsigned char FPGM(bci_action_stem_common) [] = {
1858 PUSHB_1,
1859 bci_action_stem_common,
1860 FDEF,
1862 PUSHB_1,
1864 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1866 PUSHB_1,
1868 CINDEX,
1869 PUSHB_1,
1871 CINDEX,
1872 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1873 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1875 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
1876 DUP,
1877 PUSHB_1,
1878 sal_org_len,
1879 SWAP,
1882 PUSHB_1,
1883 bci_compute_stem_width,
1884 CALL, /* s: [...] edge2 edge cur_len */
1886 DUP,
1887 PUSHB_1,
1889 LT, /* cur_len < 96 */
1891 DUP,
1892 PUSHB_1,
1894 LTEQ, /* cur_len <= 64 */
1896 PUSHB_4,
1897 sal_u_off,
1899 sal_d_off,
1902 ELSE,
1903 PUSHB_4,
1904 sal_u_off,
1906 sal_d_off,
1908 EIF,
1912 SWAP, /* s: [...] edge2 cur_len edge */
1913 DUP,
1914 PUSHB_1,
1915 sal_anchor,
1917 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
1918 ROLL,
1919 SWAP,
1920 MD_orig_ZP2_0,
1921 SWAP,
1922 GC_cur,
1923 ADD, /* s: [...] edge2 cur_len edge org_pos */
1924 PUSHB_1,
1925 sal_org_len,
1927 PUSHB_1,
1928 2*64,
1929 DIV,
1930 ADD, /* s: [...] edge2 cur_len edge org_center */
1932 DUP,
1933 PUSHB_1,
1934 bci_round,
1935 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1937 DUP,
1938 ROLL,
1939 ROLL,
1940 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1942 DUP,
1943 PUSHB_1,
1944 sal_u_off,
1946 ADD,
1947 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1949 SWAP,
1950 PUSHB_1,
1951 sal_d_off,
1953 SUB,
1954 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1956 LT, /* delta1 < delta2 */
1958 PUSHB_1,
1959 sal_u_off,
1961 SUB, /* cur_pos1 = cur_pos1 - u_off */
1963 ELSE,
1964 PUSHB_1,
1965 sal_d_off,
1967 ADD, /* cur_pos1 = cur_pos1 + d_off */
1968 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
1970 PUSHB_1,
1972 CINDEX,
1973 PUSHB_1,
1974 2*64,
1975 DIV,
1976 SUB, /* arg = cur_pos1 - cur_len/2 */
1978 SWAP, /* s: [...] edge2 cur_len arg edge */
1979 DUP,
1980 DUP,
1981 PUSHB_1,
1983 MINDEX,
1984 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
1985 GC_cur,
1986 SUB,
1987 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1989 ELSE,
1990 SWAP, /* s: [...] edge2 cur_len edge */
1991 PUSHB_1,
1992 sal_anchor,
1994 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
1995 PUSHB_1,
1997 CINDEX,
1998 PUSHB_1,
1999 sal_anchor,
2001 MD_orig_ZP2_0,
2002 ADD, /* s: [...] edge2 cur_len edge org_pos */
2004 DUP,
2005 PUSHB_1,
2006 sal_org_len,
2008 PUSHB_1,
2009 2*64,
2010 DIV,
2011 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
2013 SWAP,
2014 DUP,
2015 PUSHB_1,
2016 bci_round,
2017 CALL, /* cur_pos1 = ROUND(org_pos) */
2018 SWAP,
2019 PUSHB_1,
2020 sal_org_len,
2022 ADD,
2023 PUSHB_1,
2024 bci_round,
2025 CALL,
2026 PUSHB_1,
2028 CINDEX,
2029 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2031 PUSHB_1,
2033 CINDEX,
2034 PUSHB_1,
2035 2*64,
2036 DIV,
2037 PUSHB_1,
2039 MINDEX,
2040 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2042 DUP,
2043 PUSHB_1,
2045 CINDEX,
2046 ADD,
2047 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2048 SWAP,
2049 PUSHB_1,
2051 CINDEX,
2052 ADD,
2053 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2054 LT, /* delta1 < delta2 */
2056 POP, /* arg = cur_pos1 */
2058 ELSE,
2059 SWAP,
2060 POP, /* arg = cur_pos2 */
2061 EIF, /* s: [...] edge2 cur_len edge arg */
2062 SWAP,
2063 DUP,
2064 DUP,
2065 PUSHB_1,
2067 MINDEX,
2068 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
2069 GC_cur,
2070 SUB,
2071 SHPIX, /* edge = arg */
2072 EIF, /* s: [...] edge2 cur_len edge */
2074 ENDF,
2080 * bci_action_stem_bound
2082 * Handle the STEM action to align two edges of a stem, then moving one
2083 * edge again if necessary to stay bound.
2085 * The code after computing `cur_len' to shift `edge' and `edge2'
2086 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2088 * if cur_len < 96:
2089 * if cur_len < = 64:
2090 * u_off = 32
2091 * d_off = 32
2092 * else:
2093 * u_off = 38
2094 * d_off = 26
2096 * org_pos = anchor + (edge_orig - anchor_orig);
2097 * org_center = org_pos + org_len / 2;
2099 * cur_pos1 = ROUND(org_center)
2100 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2101 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2102 * if (delta1 < delta2):
2103 * cur_pos1 = cur_pos1 - u_off
2104 * else:
2105 * cur_pos1 = cur_pos1 + d_off
2107 * edge = cur_pos1 - cur_len / 2
2109 * else:
2110 * org_pos = anchor + (edge_orig - anchor_orig)
2111 * org_center = org_pos + org_len / 2;
2113 * cur_pos1 = ROUND(org_pos)
2114 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2115 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2116 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2118 * if (delta1 < delta2):
2119 * edge = cur_pos1
2120 * else:
2121 * edge = cur_pos2
2123 * edge2 = edge + cur_len
2125 * in: edge2_is_serif
2126 * edge_is_round
2127 * edge_point (in twilight zone)
2128 * edge2_point (in twilight zone)
2129 * edge[-1] (in twilight zone)
2130 * ... stuff for bci_align_segments (edge) ...
2131 * ... stuff for bci_align_segments (edge2)...
2133 * sal: sal_anchor
2134 * sal_temp1
2135 * sal_temp2
2136 * sal_temp3
2138 * uses: bci_action_stem_common
2141 unsigned char FPGM(bci_action_stem_bound) [] = {
2143 PUSHB_1,
2144 bci_action_stem_bound,
2145 FDEF,
2147 PUSHB_1,
2148 bci_action_stem_common,
2149 CALL,
2151 ROLL, /* s: edge[-1] cur_len edge edge2 */
2152 DUP,
2153 DUP,
2154 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2155 PUSHB_1,
2156 sal_edge2,
2157 SWAP,
2158 WS, /* s: edge[-1] cur_len edge edge2 */
2159 ROLL,
2160 SHPIX, /* edge2 = edge + cur_len */
2162 SWAP, /* s: edge edge[-1] */
2163 DUP,
2164 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
2165 GC_cur,
2166 PUSHB_1,
2168 CINDEX,
2169 GC_cur, /* s: edge edge[-1]_pos edge_pos */
2170 GT, /* edge_pos < edge[-1]_pos */
2172 DUP,
2173 ALIGNRP, /* align `edge' to `edge[-1]' */
2174 EIF,
2176 MDAP_noround, /* set rp0 and rp1 to `edge' */
2178 PUSHB_2,
2179 bci_align_segments,
2181 SZP1, /* set zp1 to normal zone 1 */
2182 CALL,
2184 PUSHB_1,
2185 sal_edge2,
2187 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2189 PUSHB_1,
2190 bci_align_segments,
2191 CALL,
2193 ENDF,
2199 * bci_action_stem
2201 * Handle the STEM action to align two edges of a stem.
2203 * See `bci_action_stem_bound' for more details.
2205 * in: edge2_is_serif
2206 * edge_is_round
2207 * edge_point (in twilight zone)
2208 * edge2_point (in twilight zone)
2209 * ... stuff for bci_align_segments (edge) ...
2210 * ... stuff for bci_align_segments (edge2)...
2212 * sal: sal_anchor
2213 * sal_temp1
2214 * sal_temp2
2215 * sal_temp3
2217 * uses: bci_action_stem_common
2220 unsigned char FPGM(bci_action_stem) [] = {
2222 PUSHB_1,
2223 bci_action_stem,
2224 FDEF,
2226 PUSHB_1,
2227 bci_action_stem_common,
2228 CALL,
2230 POP,
2231 SWAP, /* s: cur_len edge2 */
2232 DUP,
2233 DUP,
2234 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2235 PUSHB_1,
2236 sal_edge2,
2237 SWAP,
2238 WS, /* s: cur_len edge2 */
2239 SWAP,
2240 SHPIX, /* edge2 = edge + cur_len */
2242 PUSHB_2,
2243 bci_align_segments,
2245 SZP1, /* set zp1 to normal zone 1 */
2246 CALL,
2248 PUSHB_1,
2249 sal_edge2,
2251 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2253 PUSHB_1,
2254 bci_align_segments,
2255 CALL,
2256 ENDF,
2262 * bci_action_link
2264 * Handle the LINK action to link an edge to another one.
2266 * in: stem_is_serif
2267 * base_is_round
2268 * base_point (in twilight zone)
2269 * stem_point (in twilight zone)
2270 * ... stuff for bci_align_segments (base) ...
2273 unsigned char FPGM(bci_action_link) [] = {
2275 PUSHB_1,
2276 bci_action_link,
2277 FDEF,
2279 PUSHB_1,
2281 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2283 PUSHB_1,
2285 CINDEX,
2286 PUSHB_1,
2288 MINDEX,
2289 DUP, /* s: stem is_round is_serif stem base base */
2290 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2292 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
2294 PUSHB_1,
2295 bci_compute_stem_width,
2296 CALL, /* s: stem new_dist */
2298 SWAP,
2299 DUP,
2300 ALIGNRP, /* align `stem_point' with `base_point' */
2301 DUP,
2302 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
2303 SWAP,
2304 SHPIX, /* stem_point = base_point + new_dist */
2306 PUSHB_2,
2307 bci_align_segments,
2309 SZP1, /* set zp1 to normal zone 1 */
2310 CALL,
2312 ENDF,
2318 * bci_action_anchor
2320 * Handle the ANCHOR action to align two edges
2321 * and to set the edge anchor.
2323 * The code after computing `cur_len' to shift `edge' and `edge2'
2324 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2326 * if cur_len < 96:
2327 * if cur_len < = 64:
2328 * u_off = 32
2329 * d_off = 32
2330 * else:
2331 * u_off = 38
2332 * d_off = 26
2334 * org_center = edge_orig + org_len / 2
2335 * cur_pos1 = ROUND(org_center)
2337 * error1 = ABS(org_center - (cur_pos1 - u_off))
2338 * error2 = ABS(org_center - (cur_pos1 + d_off))
2339 * if (error1 < error2):
2340 * cur_pos1 = cur_pos1 - u_off
2341 * else:
2342 * cur_pos1 = cur_pos1 + d_off
2344 * edge = cur_pos1 - cur_len / 2
2345 * edge2 = edge + cur_len
2347 * else:
2348 * edge = ROUND(edge_orig)
2350 * in: edge2_is_serif
2351 * edge_is_round
2352 * edge_point (in twilight zone)
2353 * edge2_point (in twilight zone)
2354 * ... stuff for bci_align_segments (edge) ...
2356 * sal: sal_anchor
2357 * sal_temp1
2358 * sal_temp2
2359 * sal_temp3
2362 #undef sal_u_off
2363 #define sal_u_off sal_temp1
2364 #undef sal_d_off
2365 #define sal_d_off sal_temp2
2366 #undef sal_org_len
2367 #define sal_org_len sal_temp3
2369 unsigned char FPGM(bci_action_anchor) [] = {
2371 PUSHB_1,
2372 bci_action_anchor,
2373 FDEF,
2375 /* store anchor point number in `sal_anchor' */
2376 PUSHB_2,
2377 sal_anchor,
2379 CINDEX,
2380 WS, /* sal_anchor = edge_point */
2382 PUSHB_1,
2384 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2386 PUSHB_1,
2388 CINDEX,
2389 PUSHB_1,
2391 CINDEX,
2392 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
2393 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2395 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
2396 DUP,
2397 PUSHB_1,
2398 sal_org_len,
2399 SWAP,
2402 PUSHB_1,
2403 bci_compute_stem_width,
2404 CALL, /* s: edge2 edge cur_len */
2406 DUP,
2407 PUSHB_1,
2409 LT, /* cur_len < 96 */
2411 DUP,
2412 PUSHB_1,
2414 LTEQ, /* cur_len <= 64 */
2416 PUSHB_4,
2417 sal_u_off,
2419 sal_d_off,
2422 ELSE,
2423 PUSHB_4,
2424 sal_u_off,
2426 sal_d_off,
2428 EIF,
2432 SWAP, /* s: edge2 cur_len edge */
2433 DUP, /* s: edge2 cur_len edge edge */
2435 GC_orig,
2436 PUSHB_1,
2437 sal_org_len,
2439 PUSHB_1,
2440 2*64,
2441 DIV,
2442 ADD, /* s: edge2 cur_len edge org_center */
2444 DUP,
2445 PUSHB_1,
2446 bci_round,
2447 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
2449 DUP,
2450 ROLL,
2451 ROLL,
2452 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2454 DUP,
2455 PUSHB_1,
2456 sal_u_off,
2458 ADD,
2459 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2461 SWAP,
2462 PUSHB_1,
2463 sal_d_off,
2465 SUB,
2466 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2468 LT, /* error1 < error2 */
2470 PUSHB_1,
2471 sal_u_off,
2473 SUB, /* cur_pos1 = cur_pos1 - u_off */
2475 ELSE,
2476 PUSHB_1,
2477 sal_d_off,
2479 ADD, /* cur_pos1 = cur_pos1 + d_off */
2480 EIF, /* s: edge2 cur_len edge cur_pos1 */
2482 PUSHB_1,
2484 CINDEX,
2485 PUSHB_1,
2486 2*64,
2487 DIV,
2488 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2490 PUSHB_1,
2492 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2493 GC_cur,
2494 SUB,
2495 SHPIX, /* edge = cur_pos1 - cur_len/2 */
2497 SWAP, /* s: cur_len edge2 */
2498 DUP,
2499 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
2500 SWAP,
2501 SHPIX, /* edge2 = edge1 + cur_len */
2503 ELSE,
2504 POP, /* s: edge2 edge */
2505 DUP,
2506 DUP,
2507 GC_cur,
2508 SWAP,
2509 GC_orig,
2510 PUSHB_1,
2511 bci_round,
2512 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2513 SWAP,
2514 SUB,
2515 SHPIX, /* edge = round(edge_orig) */
2517 /* clean up stack */
2518 POP,
2519 EIF,
2521 PUSHB_2,
2522 bci_align_segments,
2524 SZP1, /* set zp1 to normal zone 1 */
2525 CALL,
2527 ENDF,
2533 * bci_action_blue_anchor
2535 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2536 * and to set the edge anchor.
2538 * in: anchor_point (in twilight zone)
2539 * blue_cvt_idx
2540 * edge_point (in twilight zone)
2541 * ... stuff for bci_align_segments (edge) ...
2543 * sal: sal_anchor
2545 * uses: bci_action_blue
2548 unsigned char FPGM(bci_action_blue_anchor) [] = {
2550 PUSHB_1,
2551 bci_action_blue_anchor,
2552 FDEF,
2554 /* store anchor point number in `sal_anchor' */
2555 PUSHB_1,
2556 sal_anchor,
2557 SWAP,
2560 PUSHB_1,
2561 bci_action_blue,
2562 CALL,
2564 ENDF,
2570 * bci_action_blue
2572 * Handle the BLUE action to align an edge with a blue zone.
2574 * in: blue_cvt_idx
2575 * edge_point (in twilight zone)
2576 * ... stuff for bci_align_segments (edge) ...
2579 unsigned char FPGM(bci_action_blue) [] = {
2581 PUSHB_1,
2582 bci_action_blue,
2583 FDEF,
2585 PUSHB_1,
2587 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2589 /* move `edge_point' to `blue_cvt_idx' position; */
2590 /* note that we can't use MIAP since this would modify */
2591 /* the twilight point's original coordinates also */
2592 RCVT,
2593 SWAP,
2594 DUP,
2595 MDAP_noround, /* set rp0 and rp1 to `edge' */
2596 DUP,
2597 GC_cur, /* s: new_pos edge edge_pos */
2598 ROLL,
2599 SWAP,
2600 SUB, /* s: edge (new_pos - edge_pos) */
2601 SHPIX,
2603 PUSHB_2,
2604 bci_align_segments,
2606 SZP1, /* set zp1 to normal zone 1 */
2607 CALL,
2609 ENDF,
2615 * bci_action_serif_common
2617 * Common code for bci_action_serif routines.
2620 unsigned char FPGM(bci_action_serif_common) [] = {
2622 PUSHB_1,
2623 bci_action_serif_common,
2624 FDEF,
2626 PUSHB_1,
2628 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2630 DUP,
2631 DUP,
2632 DUP,
2633 PUSHB_1,
2635 MINDEX, /* s: [...] serif serif serif serif base */
2636 DUP,
2637 MDAP_noround, /* set rp0 and rp1 to `base_point' */
2638 MD_orig_ZP2_0,
2639 SWAP,
2640 ALIGNRP, /* align `serif_point' with `base_point' */
2641 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
2643 ENDF,
2649 * bci_lower_bound
2651 * Move an edge if necessary to stay within a lower bound.
2653 * in: edge
2654 * bound
2657 unsigned char FPGM(bci_lower_bound) [] = {
2659 PUSHB_1,
2660 bci_lower_bound,
2661 FDEF,
2663 SWAP, /* s: edge bound */
2664 DUP,
2665 MDAP_noround, /* set rp0 and rp1 to `bound' */
2666 GC_cur,
2667 PUSHB_1,
2669 CINDEX,
2670 GC_cur, /* s: edge bound_pos edge_pos */
2671 GT, /* edge_pos < bound_pos */
2673 DUP,
2674 ALIGNRP, /* align `edge' to `bound' */
2675 EIF,
2677 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2679 PUSHB_2,
2680 bci_align_segments,
2682 SZP1, /* set zp1 to normal zone 1 */
2683 CALL,
2685 ENDF,
2691 * bci_upper_bound
2693 * Move an edge if necessary to stay within an upper bound.
2695 * in: edge
2696 * bound
2699 unsigned char FPGM(bci_upper_bound) [] = {
2701 PUSHB_1,
2702 bci_upper_bound,
2703 FDEF,
2705 SWAP, /* s: edge bound */
2706 DUP,
2707 MDAP_noround, /* set rp0 and rp1 to `bound' */
2708 GC_cur,
2709 PUSHB_1,
2711 CINDEX,
2712 GC_cur, /* s: edge bound_pos edge_pos */
2713 LT, /* edge_pos > bound_pos */
2715 DUP,
2716 ALIGNRP, /* align `edge' to `bound' */
2717 EIF,
2719 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
2721 PUSHB_2,
2722 bci_align_segments,
2724 SZP1, /* set zp1 to normal zone 1 */
2725 CALL,
2727 ENDF,
2733 * bci_lower_upper_bound
2735 * Move an edge if necessary to stay within a lower and lower bound.
2737 * in: edge
2738 * lower
2739 * upper
2742 unsigned char FPGM(bci_lower_upper_bound) [] = {
2744 PUSHB_1,
2745 bci_lower_upper_bound,
2746 FDEF,
2748 SWAP, /* s: upper serif lower */
2749 DUP,
2750 MDAP_noround, /* set rp0 and rp1 to `lower' */
2751 GC_cur,
2752 PUSHB_1,
2754 CINDEX,
2755 GC_cur, /* s: upper serif lower_pos serif_pos */
2756 GT, /* serif_pos < lower_pos */
2758 DUP,
2759 ALIGNRP, /* align `serif' to `lower' */
2760 EIF,
2762 SWAP, /* s: serif upper */
2763 DUP,
2764 MDAP_noround, /* set rp0 and rp1 to `upper' */
2765 GC_cur,
2766 PUSHB_1,
2768 CINDEX,
2769 GC_cur, /* s: serif upper_pos serif_pos */
2770 LT, /* serif_pos > upper_pos */
2772 DUP,
2773 ALIGNRP, /* align `serif' to `upper' */
2774 EIF,
2776 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2778 PUSHB_2,
2779 bci_align_segments,
2781 SZP1, /* set zp1 to normal zone 1 */
2782 CALL,
2784 ENDF,
2790 * bci_action_serif
2792 * Handle the SERIF action to align a serif with its base.
2794 * in: serif_point (in twilight zone)
2795 * base_point (in twilight zone)
2796 * ... stuff for bci_align_segments (serif) ...
2798 * uses: bci_action_serif_common
2801 unsigned char FPGM(bci_action_serif) [] = {
2803 PUSHB_1,
2804 bci_action_serif,
2805 FDEF,
2807 PUSHB_1,
2808 bci_action_serif_common,
2809 CALL,
2811 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
2813 PUSHB_2,
2814 bci_align_segments,
2816 SZP1, /* set zp1 to normal zone 1 */
2817 CALL,
2819 ENDF,
2825 * bci_action_serif_lower_bound
2827 * Handle the SERIF action to align a serif with its base, then moving it
2828 * again if necessary to stay within a lower bound.
2830 * in: serif_point (in twilight zone)
2831 * base_point (in twilight zone)
2832 * edge[-1] (in twilight zone)
2833 * ... stuff for bci_align_segments (serif) ...
2835 * uses: bci_action_serif_common
2836 * bci_lower_bound
2839 unsigned char FPGM(bci_action_serif_lower_bound) [] = {
2841 PUSHB_1,
2842 bci_action_serif_lower_bound,
2843 FDEF,
2845 PUSHB_1,
2846 bci_action_serif_common,
2847 CALL,
2849 PUSHB_1,
2850 bci_lower_bound,
2851 CALL,
2853 ENDF,
2859 * bci_action_serif_upper_bound
2861 * Handle the SERIF action to align a serif with its base, then moving it
2862 * again if necessary to stay within an upper bound.
2864 * in: serif_point (in twilight zone)
2865 * base_point (in twilight zone)
2866 * edge[1] (in twilight zone)
2867 * ... stuff for bci_align_segments (serif) ...
2869 * uses: bci_action_serif_common
2870 * bci_upper_bound
2873 unsigned char FPGM(bci_action_serif_upper_bound) [] = {
2875 PUSHB_1,
2876 bci_action_serif_upper_bound,
2877 FDEF,
2879 PUSHB_1,
2880 bci_action_serif_common,
2881 CALL,
2883 PUSHB_1,
2884 bci_upper_bound,
2885 CALL,
2887 ENDF,
2893 * bci_action_serif_lower_upper_bound
2895 * Handle the SERIF action to align a serif with its base, then moving it
2896 * again if necessary to stay within a lower and upper bound.
2898 * in: serif_point (in twilight zone)
2899 * base_point (in twilight zone)
2900 * edge[-1] (in twilight zone)
2901 * edge[1] (in twilight zone)
2902 * ... stuff for bci_align_segments (serif) ...
2904 * uses: bci_action_serif_common
2905 * bci_lower_upper_bound
2908 unsigned char FPGM(bci_action_serif_lower_upper_bound) [] = {
2910 PUSHB_1,
2911 bci_action_serif_lower_upper_bound,
2912 FDEF,
2914 PUSHB_1,
2916 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2918 PUSHB_1,
2919 bci_action_serif_common,
2920 CALL,
2922 PUSHB_1,
2923 bci_lower_upper_bound,
2924 CALL,
2926 ENDF,
2932 * bci_action_serif_anchor_common
2934 * Common code for bci_action_serif_anchor routines.
2937 unsigned char FPGM(bci_action_serif_anchor_common) [] = {
2939 PUSHB_1,
2940 bci_action_serif_anchor_common,
2941 FDEF,
2943 PUSHB_1,
2945 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2947 DUP,
2948 PUSHB_1,
2949 sal_anchor,
2950 SWAP,
2951 WS, /* sal_anchor = edge_point */
2953 DUP,
2954 DUP,
2955 DUP,
2956 GC_cur,
2957 SWAP,
2958 GC_orig,
2959 PUSHB_1,
2960 bci_round,
2961 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
2962 SWAP,
2963 SUB,
2964 SHPIX, /* edge = round(edge_orig) */
2966 ENDF,
2972 * bci_action_serif_anchor
2974 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2975 * anchor.
2977 * in: edge_point (in twilight zone)
2978 * ... stuff for bci_align_segments (edge) ...
2980 * uses: bci_action_serif_anchor_common
2983 unsigned char FPGM(bci_action_serif_anchor) [] = {
2985 PUSHB_1,
2986 bci_action_serif_anchor,
2987 FDEF,
2989 PUSHB_1,
2990 bci_action_serif_anchor_common,
2991 CALL,
2993 MDAP_noround, /* set rp0 and rp1 to `edge' */
2995 PUSHB_2,
2996 bci_align_segments,
2998 SZP1, /* set zp1 to normal zone 1 */
2999 CALL,
3001 ENDF,
3007 * bci_action_serif_anchor_lower_bound
3009 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3010 * anchor, then moving it again if necessary to stay within a lower
3011 * bound.
3013 * in: edge_point (in twilight zone)
3014 * edge[-1] (in twilight zone)
3015 * ... stuff for bci_align_segments (edge) ...
3017 * uses: bci_action_serif_anchor_common
3018 * bci_lower_bound
3021 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] = {
3023 PUSHB_1,
3024 bci_action_serif_anchor_lower_bound,
3025 FDEF,
3027 PUSHB_1,
3028 bci_action_serif_anchor_common,
3029 CALL,
3031 PUSHB_1,
3032 bci_lower_bound,
3033 CALL,
3035 ENDF,
3041 * bci_action_serif_anchor_upper_bound
3043 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3044 * anchor, then moving it again if necessary to stay within an upper
3045 * bound.
3047 * in: edge_point (in twilight zone)
3048 * edge[1] (in twilight zone)
3049 * ... stuff for bci_align_segments (edge) ...
3051 * uses: bci_action_serif_anchor_common
3052 * bci_upper_bound
3055 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] = {
3057 PUSHB_1,
3058 bci_action_serif_anchor_upper_bound,
3059 FDEF,
3061 PUSHB_1,
3062 bci_action_serif_anchor_common,
3063 CALL,
3065 PUSHB_1,
3066 bci_upper_bound,
3067 CALL,
3069 ENDF,
3075 * bci_action_serif_anchor_lower_upper_bound
3077 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3078 * anchor, then moving it again if necessary to stay within a lower and
3079 * upper bound.
3081 * in: edge_point (in twilight zone)
3082 * edge[-1] (in twilight zone)
3083 * edge[1] (in twilight zone)
3084 * ... stuff for bci_align_segments (edge) ...
3086 * uses: bci_action_serif_anchor_common
3087 * bci_lower_upper_bound
3090 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound) [] = {
3092 PUSHB_1,
3093 bci_action_serif_anchor_lower_upper_bound,
3094 FDEF,
3096 PUSHB_1,
3097 bci_action_serif_anchor_common,
3098 CALL,
3100 PUSHB_1,
3101 bci_lower_upper_bound,
3102 CALL,
3104 ENDF,
3110 * bci_action_serif_link1_common
3112 * Common code for bci_action_serif_link1 routines.
3115 unsigned char FPGM(bci_action_serif_link1_common) [] = {
3117 PUSHB_1,
3118 bci_action_serif_link1_common,
3119 FDEF,
3121 PUSHB_1,
3123 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3125 PUSHB_1,
3127 CINDEX, /* s: [...] after edge before after */
3128 PUSHB_1,
3130 CINDEX, /* s: [...] after edge before after before */
3131 MD_orig_ZP2_0,
3132 PUSHB_1,
3134 EQ, /* after_orig_pos == before_orig_pos */
3135 IF, /* s: [...] after edge before */
3136 MDAP_noround, /* set rp0 and rp1 to `before' */
3137 DUP,
3138 ALIGNRP, /* align `edge' with `before' */
3139 SWAP,
3140 POP,
3142 ELSE,
3143 /* we have to execute `a*b/c', with b/c very near to 1: */
3144 /* to avoid overflow while retaining precision, */
3145 /* we transform this to `a + a * (b-c)/c' */
3147 PUSHB_1,
3149 CINDEX, /* s: [...] after edge before edge */
3150 PUSHB_1,
3152 CINDEX, /* s: [...] after edge before edge before */
3153 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
3155 DUP,
3156 PUSHB_1,
3158 CINDEX, /* s: [...] after edge before a a after */
3159 PUSHB_1,
3161 CINDEX, /* s: [...] after edge before a a after before */
3162 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
3164 PUSHB_1,
3166 CINDEX, /* s: [...] after edge before a a c after */
3167 PUSHB_1,
3169 CINDEX, /* s: [...] after edge before a a c after before */
3170 MD_cur, /* b = after_pos - before_pos */
3172 PUSHB_1,
3174 CINDEX, /* s: [...] after edge before a a c b c */
3175 SUB, /* b-c */
3177 PUSHB_1,
3178 cvtl_0x10000,
3179 RCVT,
3180 MUL, /* (b-c) in 16.16 format */
3181 SWAP,
3182 DIV, /* s: [...] after edge before a a (b-c)/c */
3184 MUL, /* a * (b-c)/c * 2^10 */
3185 PUSHB_1,
3186 cvtl_0x10000,
3187 RCVT,
3188 DIV, /* a * (b-c)/c */
3189 ADD, /* a*b/c */
3191 SWAP,
3192 MDAP_noround, /* set rp0 and rp1 to `before' */
3193 SWAP, /* s: [...] after a*b/c edge */
3194 DUP,
3195 DUP,
3196 ALIGNRP, /* align `edge' with `before' */
3197 ROLL,
3198 SHPIX, /* shift `edge' by `a*b/c' */
3200 SWAP, /* s: [...] edge after */
3201 POP,
3202 EIF,
3204 ENDF,
3210 * bci_action_serif_link1
3212 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3213 * before and after.
3215 * in: before_point (in twilight zone)
3216 * edge_point (in twilight zone)
3217 * after_point (in twilight zone)
3218 * ... stuff for bci_align_segments (edge) ...
3220 * uses: bci_action_serif_link1_common
3223 unsigned char FPGM(bci_action_serif_link1) [] = {
3225 PUSHB_1,
3226 bci_action_serif_link1,
3227 FDEF,
3229 PUSHB_1,
3230 bci_action_serif_link1_common,
3231 CALL,
3233 MDAP_noround, /* set rp0 and rp1 to `edge' */
3235 PUSHB_2,
3236 bci_align_segments,
3238 SZP1, /* set zp1 to normal zone 1 */
3239 CALL,
3241 ENDF,
3247 * bci_action_serif_link1_lower_bound
3249 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3250 * before and after. Additionally, move the serif again if necessary to
3251 * stay within a lower bound.
3253 * in: before_point (in twilight zone)
3254 * edge_point (in twilight zone)
3255 * after_point (in twilight zone)
3256 * edge[-1] (in twilight zone)
3257 * ... stuff for bci_align_segments (edge) ...
3259 * uses: bci_action_serif_link1_common
3260 * bci_lower_bound
3263 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] = {
3265 PUSHB_1,
3266 bci_action_serif_link1_lower_bound,
3267 FDEF,
3269 PUSHB_1,
3270 bci_action_serif_link1_common,
3271 CALL,
3273 PUSHB_1,
3274 bci_lower_bound,
3275 CALL,
3277 ENDF,
3283 * bci_action_serif_link1_upper_bound
3285 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3286 * before and after. Additionally, move the serif again if necessary to
3287 * stay within an upper bound.
3289 * in: before_point (in twilight zone)
3290 * edge_point (in twilight zone)
3291 * after_point (in twilight zone)
3292 * edge[1] (in twilight zone)
3293 * ... stuff for bci_align_segments (edge) ...
3295 * uses: bci_action_serif_link1_common
3296 * bci_upper_bound
3299 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] = {
3301 PUSHB_1,
3302 bci_action_serif_link1_upper_bound,
3303 FDEF,
3305 PUSHB_1,
3306 bci_action_serif_link1_common,
3307 CALL,
3309 PUSHB_1,
3310 bci_upper_bound,
3311 CALL,
3313 ENDF,
3319 * bci_action_serif_link1_lower_upper_bound
3321 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3322 * before and after. Additionally, move the serif again if necessary to
3323 * stay within a lower and upper bound.
3325 * in: before_point (in twilight zone)
3326 * edge_point (in twilight zone)
3327 * after_point (in twilight zone)
3328 * edge[-1] (in twilight zone)
3329 * edge[1] (in twilight zone)
3330 * ... stuff for bci_align_segments (edge) ...
3332 * uses: bci_action_serif_link1_common
3333 * bci_lower_upper_bound
3336 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound) [] = {
3338 PUSHB_1,
3339 bci_action_serif_link1_lower_upper_bound,
3340 FDEF,
3342 PUSHB_1,
3343 bci_action_serif_link1_common,
3344 CALL,
3346 PUSHB_1,
3347 bci_lower_upper_bound,
3348 CALL,
3350 ENDF,
3356 * bci_action_serif_link2_common
3358 * Common code for bci_action_serif_link2 routines.
3361 unsigned char FPGM(bci_action_serif_link2_common) [] = {
3363 PUSHB_1,
3364 bci_action_serif_link2_common,
3365 FDEF,
3367 PUSHB_1,
3369 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3371 DUP, /* s: [...] edge edge */
3372 PUSHB_1,
3373 sal_anchor,
3375 DUP, /* s: [...] edge edge anchor anchor */
3376 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
3378 MD_orig_ZP2_0,
3379 DUP,
3380 ADD,
3381 PUSHB_1,
3383 ADD,
3384 FLOOR,
3385 PUSHB_1,
3386 2*64,
3387 DIV, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3389 SWAP,
3390 DUP,
3391 DUP,
3392 ALIGNRP, /* align `edge' with `sal_anchor' */
3393 ROLL,
3394 SHPIX, /* shift `edge' by `delta' */
3396 ENDF,
3402 * bci_action_serif_link2
3404 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3406 * in: edge_point (in twilight zone)
3407 * ... stuff for bci_align_segments (edge) ...
3409 * uses: bci_action_serif_link2_common
3412 unsigned char FPGM(bci_action_serif_link2) [] = {
3414 PUSHB_1,
3415 bci_action_serif_link2,
3416 FDEF,
3418 PUSHB_1,
3419 bci_action_serif_link2_common,
3420 CALL,
3422 MDAP_noround, /* set rp0 and rp1 to `edge' */
3424 PUSHB_2,
3425 bci_align_segments,
3427 SZP1, /* set zp1 to normal zone 1 */
3428 CALL,
3430 ENDF,
3436 * bci_action_serif_link2_lower_bound
3438 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3439 * Additionally, move the serif again if necessary to stay within a lower
3440 * bound.
3442 * in: edge_point (in twilight zone)
3443 * edge[-1] (in twilight zone)
3444 * ... stuff for bci_align_segments (edge) ...
3446 * uses: bci_action_serif_link2_common
3447 * bci_lower_bound
3450 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] = {
3452 PUSHB_1,
3453 bci_action_serif_link2_lower_bound,
3454 FDEF,
3456 PUSHB_1,
3457 bci_action_serif_link2_common,
3458 CALL,
3460 PUSHB_1,
3461 bci_lower_bound,
3462 CALL,
3464 ENDF,
3470 * bci_action_serif_link2_upper_bound
3472 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3473 * Additionally, move the serif again if necessary to stay within an upper
3474 * bound.
3476 * in: edge_point (in twilight zone)
3477 * edge[1] (in twilight zone)
3478 * ... stuff for bci_align_segments (edge) ...
3480 * uses: bci_action_serif_link2_common
3481 * bci_upper_bound
3484 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] = {
3486 PUSHB_1,
3487 bci_action_serif_link2_upper_bound,
3488 FDEF,
3490 PUSHB_1,
3491 bci_action_serif_link2_common,
3492 CALL,
3494 PUSHB_1,
3495 bci_upper_bound,
3496 CALL,
3498 ENDF,
3504 * bci_action_serif_link2_lower_upper_bound
3506 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3507 * Additionally, move the serif again if necessary to stay within a lower
3508 * and upper bound.
3510 * in: edge_point (in twilight zone)
3511 * edge[-1] (in twilight zone)
3512 * edge[1] (in twilight zone)
3513 * ... stuff for bci_align_segments (edge) ...
3515 * uses: bci_action_serif_link2_common
3516 * bci_lower_upper_bound
3519 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound) [] = {
3521 PUSHB_1,
3522 bci_action_serif_link2_lower_upper_bound,
3523 FDEF,
3525 PUSHB_1,
3526 bci_action_serif_link2_common,
3527 CALL,
3529 PUSHB_1,
3530 bci_lower_upper_bound,
3531 CALL,
3533 ENDF,
3539 * bci_handle_action
3541 * Execute function.
3543 * in: function_index
3546 unsigned char FPGM(bci_handle_action) [] = {
3548 PUSHB_1,
3549 bci_handle_action,
3550 FDEF,
3552 CALL,
3554 ENDF,
3560 * bci_hint_glyph
3562 * This is the top-level glyph hinting function
3563 * which parses the arguments on the stack and calls subroutines.
3565 * in: num_actions (M)
3566 * action_0_func_idx
3567 * ... data ...
3568 * action_1_func_idx
3569 * ... data ...
3570 * ...
3571 * action_M_func_idx
3572 * ... data ...
3574 * uses: bci_handle_action
3576 * bci_action_ip_before
3577 * bci_action_ip_after
3578 * bci_action_ip_on
3579 * bci_action_ip_between
3581 * bci_action_adjust_bound
3582 * bci_action_stem_bound
3584 * bci_action_link
3585 * bci_action_anchor
3586 * bci_action_blue_anchor
3587 * bci_action_adjust
3588 * bci_action_stem
3589 * bci_action_blue
3591 * bci_action_serif
3592 * bci_action_serif_lower_bound
3593 * bci_action_serif_upper_bound
3594 * bci_action_serif_lower_upper_bound
3596 * bci_action_serif_anchor
3597 * bci_action_serif_anchor_lower_bound
3598 * bci_action_serif_anchor_upper_bound
3599 * bci_action_serif_anchor_lower_upper_bound
3601 * bci_action_serif_link1
3602 * bci_action_serif_link1_lower_bound
3603 * bci_action_serif_link1_upper_bound
3604 * bci_action_serif_link1_lower_upper_bound
3606 * bci_action_serif_link2
3607 * bci_action_serif_link2_lower_bound
3608 * bci_action_serif_link2_upper_bound
3609 * bci_action_serif_link2_lower_upper_bound
3611 * CVT: cvtl_is_subglyph
3614 unsigned char FPGM(bci_hint_glyph) [] = {
3616 PUSHB_1,
3617 bci_hint_glyph,
3618 FDEF,
3620 PUSHB_2,
3622 cvtl_is_subglyph,
3623 RCVT,
3626 /* only do something if we are not a subglyph */
3627 PUSHB_1,
3628 bci_handle_action,
3629 LOOPCALL,
3631 PUSHB_1,
3633 SZP2, /* set zp2 to normal zone 1 */
3634 IUP_y,
3636 ELSE,
3637 CLEAR,
3638 EIF,
3640 ENDF,
3645 #define COPY_FPGM(func_name) \
3646 memcpy(buf_p, fpgm_ ## func_name, \
3647 sizeof (fpgm_ ## func_name)); \
3648 buf_p += sizeof (fpgm_ ## func_name) \
3650 static FT_Error
3651 TA_table_build_fpgm(FT_Byte** fpgm,
3652 FT_ULong* fpgm_len,
3653 FONT* font)
3655 FT_UInt buf_len;
3656 FT_UInt len;
3657 FT_Byte* buf;
3658 FT_Byte* buf_p;
3661 buf_len = sizeof (FPGM(bci_round))
3662 + sizeof (FPGM(bci_compute_stem_width_a))
3664 + sizeof (FPGM(bci_compute_stem_width_b))
3666 + sizeof (FPGM(bci_compute_stem_width_c))
3667 + sizeof (FPGM(bci_loop))
3668 + sizeof (FPGM(bci_cvt_rescale))
3669 + sizeof (FPGM(bci_blue_round_a))
3671 + sizeof (FPGM(bci_blue_round_b))
3672 + sizeof (FPGM(bci_decrement_component_counter))
3673 + sizeof (FPGM(bci_get_point_extrema))
3675 + sizeof (FPGM(bci_create_segment))
3676 + sizeof (FPGM(bci_create_segments))
3677 + sizeof (FPGM(bci_create_segments_composite))
3678 + sizeof (FPGM(bci_align_segment))
3679 + sizeof (FPGM(bci_align_segments))
3681 + sizeof (FPGM(bci_scale_contour))
3682 + sizeof (FPGM(bci_scale_glyph))
3683 + sizeof (FPGM(bci_scale_composite_glyph))
3684 + sizeof (FPGM(bci_shift_contour))
3685 + sizeof (FPGM(bci_shift_subglyph))
3687 + sizeof (FPGM(bci_ip_outer_align_point))
3688 + sizeof (FPGM(bci_ip_on_align_points))
3689 + sizeof (FPGM(bci_ip_between_align_point))
3690 + sizeof (FPGM(bci_ip_between_align_points))
3692 + sizeof (FPGM(bci_action_adjust_common))
3693 + sizeof (FPGM(bci_action_stem_common))
3694 + sizeof (FPGM(bci_action_serif_common))
3695 + sizeof (FPGM(bci_action_serif_anchor_common))
3696 + sizeof (FPGM(bci_action_serif_link1_common))
3697 + sizeof (FPGM(bci_action_serif_link2_common))
3699 + sizeof (FPGM(bci_lower_bound))
3700 + sizeof (FPGM(bci_upper_bound))
3701 + sizeof (FPGM(bci_lower_upper_bound))
3703 + sizeof (FPGM(bci_action_ip_before))
3704 + sizeof (FPGM(bci_action_ip_after))
3705 + sizeof (FPGM(bci_action_ip_on))
3706 + sizeof (FPGM(bci_action_ip_between))
3708 + sizeof (FPGM(bci_action_adjust_bound))
3709 + sizeof (FPGM(bci_action_stem_bound))
3710 + sizeof (FPGM(bci_action_link))
3711 + sizeof (FPGM(bci_action_anchor))
3712 + sizeof (FPGM(bci_action_blue_anchor))
3713 + sizeof (FPGM(bci_action_adjust))
3714 + sizeof (FPGM(bci_action_stem))
3715 + sizeof (FPGM(bci_action_blue))
3716 + sizeof (FPGM(bci_action_serif))
3717 + sizeof (FPGM(bci_action_serif_lower_bound))
3718 + sizeof (FPGM(bci_action_serif_upper_bound))
3719 + sizeof (FPGM(bci_action_serif_lower_upper_bound))
3720 + sizeof (FPGM(bci_action_serif_anchor))
3721 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
3722 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
3723 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound))
3724 + sizeof (FPGM(bci_action_serif_link1))
3725 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
3726 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
3727 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound))
3728 + sizeof (FPGM(bci_action_serif_link2))
3729 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
3730 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
3731 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound))
3733 + sizeof (FPGM(bci_handle_action))
3734 + sizeof (FPGM(bci_hint_glyph));
3736 /* buffer length must be a multiple of four */
3737 len = (buf_len + 3) & ~3;
3738 buf = (FT_Byte*)malloc(len);
3739 if (!buf)
3740 return FT_Err_Out_Of_Memory;
3742 /* pad end of buffer with zeros */
3743 buf[len - 1] = 0x00;
3744 buf[len - 2] = 0x00;
3745 buf[len - 3] = 0x00;
3747 /* copy font program into buffer and fill in the missing variables */
3748 buf_p = buf;
3750 COPY_FPGM(bci_round);
3751 COPY_FPGM(bci_compute_stem_width_a);
3752 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3753 COPY_FPGM(bci_compute_stem_width_b);
3754 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
3755 COPY_FPGM(bci_compute_stem_width_c);
3756 COPY_FPGM(bci_loop);
3757 COPY_FPGM(bci_cvt_rescale);
3758 COPY_FPGM(bci_blue_round_a);
3759 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
3760 COPY_FPGM(bci_blue_round_b);
3761 COPY_FPGM(bci_decrement_component_counter);
3762 COPY_FPGM(bci_get_point_extrema);
3764 COPY_FPGM(bci_create_segment);
3765 COPY_FPGM(bci_create_segments);
3766 COPY_FPGM(bci_create_segments_composite);
3767 COPY_FPGM(bci_align_segment);
3768 COPY_FPGM(bci_align_segments);
3770 COPY_FPGM(bci_scale_contour);
3771 COPY_FPGM(bci_scale_glyph);
3772 COPY_FPGM(bci_scale_composite_glyph);
3773 COPY_FPGM(bci_shift_contour);
3774 COPY_FPGM(bci_shift_subglyph);
3776 COPY_FPGM(bci_ip_outer_align_point);
3777 COPY_FPGM(bci_ip_on_align_points);
3778 COPY_FPGM(bci_ip_between_align_point);
3779 COPY_FPGM(bci_ip_between_align_points);
3781 COPY_FPGM(bci_action_adjust_common);
3782 COPY_FPGM(bci_action_stem_common);
3783 COPY_FPGM(bci_action_serif_common);
3784 COPY_FPGM(bci_action_serif_anchor_common);
3785 COPY_FPGM(bci_action_serif_link1_common);
3786 COPY_FPGM(bci_action_serif_link2_common);
3788 COPY_FPGM(bci_lower_bound);
3789 COPY_FPGM(bci_upper_bound);
3790 COPY_FPGM(bci_lower_upper_bound);
3792 COPY_FPGM(bci_action_ip_before);
3793 COPY_FPGM(bci_action_ip_after);
3794 COPY_FPGM(bci_action_ip_on);
3795 COPY_FPGM(bci_action_ip_between);
3797 COPY_FPGM(bci_action_adjust_bound);
3798 COPY_FPGM(bci_action_stem_bound);
3799 COPY_FPGM(bci_action_link);
3800 COPY_FPGM(bci_action_anchor);
3801 COPY_FPGM(bci_action_blue_anchor);
3802 COPY_FPGM(bci_action_adjust);
3803 COPY_FPGM(bci_action_stem);
3804 COPY_FPGM(bci_action_blue);
3805 COPY_FPGM(bci_action_serif);
3806 COPY_FPGM(bci_action_serif_lower_bound);
3807 COPY_FPGM(bci_action_serif_upper_bound);
3808 COPY_FPGM(bci_action_serif_lower_upper_bound);
3809 COPY_FPGM(bci_action_serif_anchor);
3810 COPY_FPGM(bci_action_serif_anchor_lower_bound);
3811 COPY_FPGM(bci_action_serif_anchor_upper_bound);
3812 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound);
3813 COPY_FPGM(bci_action_serif_link1);
3814 COPY_FPGM(bci_action_serif_link1_lower_bound);
3815 COPY_FPGM(bci_action_serif_link1_upper_bound);
3816 COPY_FPGM(bci_action_serif_link1_lower_upper_bound);
3817 COPY_FPGM(bci_action_serif_link2);
3818 COPY_FPGM(bci_action_serif_link2_lower_bound);
3819 COPY_FPGM(bci_action_serif_link2_upper_bound);
3820 COPY_FPGM(bci_action_serif_link2_lower_upper_bound);
3822 COPY_FPGM(bci_handle_action);
3823 COPY_FPGM(bci_hint_glyph);
3825 *fpgm = buf;
3826 *fpgm_len = buf_len;
3828 return FT_Err_Ok;
3832 FT_Error
3833 TA_sfnt_build_fpgm_table(SFNT* sfnt,
3834 FONT* font)
3836 FT_Error error;
3838 FT_Byte* fpgm_buf;
3839 FT_ULong fpgm_len;
3842 error = TA_sfnt_add_table_info(sfnt);
3843 if (error)
3844 return error;
3846 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
3847 if (error)
3848 return error;
3850 if (fpgm_len > sfnt->max_instructions)
3851 sfnt->max_instructions = fpgm_len;
3853 /* in case of success, `fpgm_buf' gets linked */
3854 /* and is eventually freed in `TA_font_unload' */
3855 error = TA_font_add_table(font,
3856 &sfnt->table_infos[sfnt->num_table_infos - 1],
3857 TTAG_fpgm, fpgm_len, fpgm_buf);
3858 if (error)
3860 free(fpgm_buf);
3861 return error;
3864 return FT_Err_Ok;
3867 /* end of tafpgm.c */