Add `static' keywords where appropriate.
[ttfautohint.git] / lib / tafpgm.c
blob3853cf418d20ad2ef5f378b4c96275aa5c96e9dd
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2015 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
52 * Older versions of Monotype's `iType' bytecode interpreter have a serious
53 * bug: The DIV instruction rounds the result, while the correct operation
54 * is truncation. (Note, however, that MUL always rounds the result.)
55 * Since many printers contain this rasterizer without any possibility to
56 * update to a non-buggy version, we have to work around the problem.
58 * DIV and MUL work on 26.6 numbers which means that the numerator gets
59 * multiplied by 64 before the division, and the product gets divided by 64
60 * after the multiplication, respectively. For example, to divide 2 by 3,
61 * you have to write
63 * PUSHB_1,
64 * 2,
65 * 3*64,
66 * DIV
68 * The correct formula to divide two values in 26.6 format with truncation
69 * is
71 * a*64 / b ,
73 * while older `iType' versions incorrectly apply rounding by using
75 * (a*64 + b/2) / b .
77 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
79 * (2*64 + (3*64)/2) / (3*64) = 1
81 * instead of the correct result 0.
83 * The solution to the rounding issue is to use a 26.6 value as an
84 * intermediate result so that we can truncate to the nearest integer (in
85 * 26.6 format) with the FLOOR operator before converting back to a plain
86 * integer (in 32.0 format).
88 * For the common divisions by 2 and 2^10 we define macros.
90 #define DIV_POS_BY_2 \
91 PUSHB_1, \
92 2, \
93 DIV, /* multiply by 64, then divide by 2 */ \
94 FLOOR, \
95 PUSHB_1, \
96 1, \
97 MUL /* multiply by 1, then divide by 64 */
99 #define DIV_BY_2 \
100 PUSHB_1, \
101 2, \
102 DIV, \
103 DUP, \
104 PUSHB_1, \
105 0, \
106 LT, \
107 IF, \
108 PUSHB_1, \
109 64, \
110 ADD, /* add 1 if value is negative */ \
111 EIF, \
112 FLOOR, \
113 PUSHB_1, \
114 1, \
117 #define DIV_BY_1024 \
118 PUSHW_1, \
119 0x04, /* 2^10 */ \
120 0x00, \
121 DIV, \
122 DUP, \
123 PUSHB_1, \
124 0, \
125 LT, \
126 IF, \
127 PUSHB_1, \
128 64, \
129 ADD, \
130 EIF, \
131 FLOOR, \
132 PUSHB_1, \
133 1, \
137 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
138 #define DO_SCALE \
139 DUP, /* s: a a */ \
140 PUSHB_1, \
141 sal_scale, \
142 RS, \
143 MUL, /* delta * 2^10 */ \
144 DIV_BY_1024, /* delta */ \
145 ADD /* a + delta */
148 /* in the comments below, the top of the stack (`s:') */
149 /* is the rightmost element; the stack is shown */
150 /* after the instruction on the same line has been executed */
154 * bci_align_top
156 * Optimize the alignment of the top of small letters to the pixel grid.
158 * This function gets used in the `prep' table.
160 * in: blue_idx (CVT index for the style's top of small letters blue zone)
162 * sal: sal_i (CVT index of the style's scaling value;
163 * gets incremented by 1 after execution)
166 static const unsigned char FPGM(bci_align_top_a) [] =
169 PUSHB_1,
170 bci_align_top,
171 FDEF,
173 /* only get CVT value for non-zero index */
174 DUP,
175 PUSHB_1,
177 NEQ,
179 RCVT,
180 EIF,
181 DUP,
182 DUP, /* s: blue blue blue */
186 /* if (font->increase_x_height) */
187 /* { */
189 static const unsigned char FPGM(bci_align_top_b1a) [] =
192 /* apply much `stronger' rounding up of x height for */
193 /* 6 <= PPEM <= increase_x_height */
194 MPPEM,
195 PUSHW_1,
199 /* %d, x height increase limit */
201 static const unsigned char FPGM(bci_align_top_b1b) [] =
204 LTEQ,
205 MPPEM,
206 PUSHB_1,
208 GTEQ,
209 AND,
211 PUSHB_1,
212 52, /* threshold = 52 */
214 ELSE,
215 PUSHB_1,
216 40, /* threshold = 40 */
218 EIF,
219 ADD,
220 FLOOR, /* fitted = FLOOR(blue + threshold) */
224 /* } */
226 /* if (!font->increase_x_height) */
227 /* { */
229 static const unsigned char FPGM(bci_align_top_b2) [] =
232 PUSHB_1,
234 ADD,
235 FLOOR, /* fitted = FLOOR(blue + 40) */
239 /* } */
241 static const unsigned char FPGM(bci_align_top_c) [] =
244 DUP, /* s: blue blue fitted fitted */
245 ROLL,
246 NEQ,
247 IF, /* s: blue fitted */
248 PUSHB_1,
250 CINDEX,
251 SUB, /* s: blue (fitted-blue) */
252 PUSHW_2,
253 0x08, /* 0x800 */
254 0x00,
255 0x08, /* 0x800 */
256 0x00,
257 MUL, /* 0x10000 */
258 MUL, /* (fitted-blue) in 16.16 format */
259 SWAP,
260 DIV, /* factor = ((fitted-blue) / blue) in 16.16 format */
262 ELSE,
263 POP,
264 POP,
265 PUSHB_1,
266 0, /* factor = 0 */
268 EIF,
270 PUSHB_1,
271 sal_i,
272 RS, /* s: factor idx */
273 SWAP,
274 WCVTP,
276 PUSHB_3,
277 sal_i,
279 sal_i,
281 ADD, /* sal_i = sal_i + 1 */
284 ENDF,
290 * bci_round
292 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
293 * engine specific corrections are applied.
295 * in: val
297 * out: ROUND(val)
300 static const unsigned char FPGM(bci_round) [] =
303 PUSHB_1,
304 bci_round,
305 FDEF,
307 PUSHB_1,
309 ADD,
310 FLOOR,
312 ENDF,
318 * bci_smooth_stem_width
320 * This is the equivalent to the following code from function
321 * `ta_latin_compute_stem_width':
323 * dist = ABS(width)
325 * if (stem_is_serif
326 * && dist < 3*64)
327 * || std_width < 40:
328 * return width
329 * else if base_is_round:
330 * if dist < 80:
331 * dist = 64
332 * else if dist < 56:
333 * dist = 56
335 * delta = ABS(dist - std_width)
337 * if delta < 40:
338 * dist = std_width
339 * if dist < 48:
340 * dist = 48
341 * goto End
343 * if dist < 3*64:
344 * delta = dist
345 * dist = FLOOR(dist)
346 * delta = delta - dist
348 * if delta < 10:
349 * dist = dist + delta
350 * else if delta < 32:
351 * dist = dist + 10
352 * else if delta < 54:
353 * dist = dist + 54
354 * else:
355 * dist = dist + delta
356 * else:
357 * dist = ROUND(dist)
359 * End:
360 * if width < 0:
361 * dist = -dist
362 * return dist
364 * in: width
365 * stem_is_serif
366 * base_is_round
368 * out: new_width
370 * sal: sal_vwidth_data_offset
372 * CVT: std_width
374 * uses: bci_round
377 static const unsigned char FPGM(bci_smooth_stem_width) [] =
380 PUSHB_1,
381 bci_smooth_stem_width,
382 FDEF,
384 DUP,
385 ABS, /* s: base_is_round stem_is_serif width dist */
387 DUP,
388 PUSHB_1,
389 3*64,
390 LT, /* dist < 3*64 */
392 PUSHB_1,
394 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
395 AND, /* stem_is_serif && dist < 3*64 */
397 PUSHB_3,
400 sal_vwidth_data_offset,
402 RCVT, /* first indirection */
403 MUL, /* divide by 64 */
404 RCVT, /* second indirection */
405 GT, /* standard_width < 40 */
406 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
408 IF, /* s: base_is_round width dist */
409 POP,
410 SWAP,
411 POP, /* s: width */
413 ELSE,
414 ROLL, /* s: width dist base_is_round */
415 IF, /* s: width dist */
416 DUP,
417 PUSHB_1,
419 LT, /* dist < 80 */
420 IF, /* s: width dist */
421 POP,
422 PUSHB_1,
423 64, /* dist = 64 */
424 EIF,
426 ELSE,
427 DUP,
428 PUSHB_1,
430 LT, /* dist < 56 */
431 IF, /* s: width dist */
432 POP,
433 PUSHB_1,
434 56, /* dist = 56 */
435 EIF,
436 EIF,
438 DUP, /* s: width dist dist */
439 PUSHB_2,
441 sal_vwidth_data_offset,
443 RCVT, /* first indirection */
444 MUL, /* divide by 64 */
445 RCVT, /* second indirection */
446 SUB,
447 ABS, /* s: width dist delta */
449 PUSHB_1,
451 LT, /* delta < 40 */
452 IF, /* s: width dist */
453 POP,
454 PUSHB_2,
456 sal_vwidth_data_offset,
458 RCVT, /* first indirection */
459 MUL, /* divide by 64 */
460 RCVT, /* second indirection; dist = std_width */
461 DUP,
462 PUSHB_1,
464 LT, /* dist < 48 */
466 POP,
467 PUSHB_1,
468 48, /* dist = 48 */
469 EIF,
471 ELSE,
472 DUP, /* s: width dist dist */
473 PUSHB_1,
474 3*64,
475 LT, /* dist < 3*64 */
477 DUP, /* s: width delta dist */
478 FLOOR, /* dist = FLOOR(dist) */
479 DUP, /* s: width delta dist dist */
480 ROLL,
481 ROLL, /* s: width dist delta dist */
482 SUB, /* delta = delta - dist */
484 DUP, /* s: width dist delta delta */
485 PUSHB_1,
487 LT, /* delta < 10 */
488 IF, /* s: width dist delta */
489 ADD, /* dist = dist + delta */
491 ELSE,
492 DUP,
493 PUSHB_1,
495 LT, /* delta < 32 */
497 POP,
498 PUSHB_1,
500 ADD, /* dist = dist + 10 */
502 ELSE,
503 DUP,
504 PUSHB_1,
506 LT, /* delta < 54 */
508 POP,
509 PUSHB_1,
511 ADD, /* dist = dist + 54 */
513 ELSE,
514 ADD, /* dist = dist + delta */
516 EIF,
517 EIF,
518 EIF,
520 ELSE,
521 PUSHB_1,
522 bci_round,
523 CALL, /* dist = round(dist) */
525 EIF,
526 EIF,
528 SWAP, /* s: dist width */
529 PUSHB_1,
531 LT, /* width < 0 */
533 NEG, /* dist = -dist */
534 EIF,
535 EIF,
537 ENDF,
543 * bci_get_best_width
545 * An auxiliary function for `bci_strong_stem_width'.
547 * in: n (initialized with CVT index for first vertical width)
548 * dist
550 * out: n+1
551 * dist
553 * sal: sal_best
554 * sal_ref
556 * CVT: widths[]
559 static const unsigned char FPGM(bci_get_best_width) [] =
562 PUSHB_1,
563 bci_get_best_width,
564 FDEF,
566 DUP,
567 RCVT, /* s: dist n w */
568 DUP,
569 PUSHB_1,
571 CINDEX, /* s: dist n w w dist */
572 SUB,
573 ABS, /* s: dist n w d */
574 DUP,
575 PUSHB_1,
576 sal_best,
577 RS, /* s: dist n w d d best */
578 LT, /* d < best */
580 PUSHB_1,
581 sal_best,
582 SWAP,
583 WS, /* best = d */
584 PUSHB_1,
585 sal_ref,
586 SWAP,
587 WS, /* reference = w */
589 ELSE,
590 POP,
591 POP,
592 EIF,
594 PUSHB_1,
596 ADD, /* n = n + 1 */
598 ENDF,
604 * bci_strong_stem_width
606 * This is the equivalent to the following code (function
607 * `ta_latin_snap_width' and some lines from
608 * `ta_latin_compute_stem_width'):
610 * best = 64 + 32 + 2
611 * reference = width
612 * dist = ABS(width)
614 * for n in 0 .. num_widths:
615 * w = widths[n]
616 * d = ABS(dist - w)
618 * if d < best:
619 * best = d
620 * reference = w
622 * if dist >= reference:
623 * if dist < ROUND(reference) + 48:
624 * dist = reference
625 * else:
626 * if dist > ROUND(reference) - 48:
627 * dist = reference
629 * if dist >= 64:
630 * dist = ROUND(dist)
631 * else:
632 * dist = 64
634 * if width < 0:
635 * dist = -dist
636 * return dist
638 * in: width
639 * stem_is_serif (unused)
640 * base_is_round (unused)
642 * out: new_width
644 * sal: sal_best
645 * sal_ref
646 * sal_vwidth_data_offset
648 * CVT: widths[]
650 * uses: bci_get_best_width
651 * bci_round
654 static const unsigned char FPGM(bci_strong_stem_width_a) [] =
657 PUSHB_1,
658 bci_strong_stem_width,
659 FDEF,
661 SWAP,
662 POP,
663 SWAP,
664 POP,
665 DUP,
666 ABS, /* s: width dist */
668 PUSHB_2,
669 sal_best,
670 64 + 32 + 2,
671 WS, /* sal_best = 98 */
673 DUP,
674 PUSHB_1,
675 sal_ref,
676 SWAP,
677 WS, /* sal_ref = width */
679 PUSHB_2,
681 sal_vwidth_data_offset,
683 RCVT,
684 MUL, /* divide by 64; first index of vertical widths */
686 PUSHB_2,
688 sal_vwidth_data_offset,
690 PUSHB_1,
694 /* %c, number of used styles */
696 static const unsigned char FPGM(bci_strong_stem_width_b) [] =
699 ADD,
700 RCVT, /* number of vertical widths */
701 MUL, /* divide by 64 */
703 PUSHB_1,
704 bci_get_best_width,
705 LOOPCALL,
707 POP, /* s: width dist */
708 DUP,
709 PUSHB_1,
710 sal_ref,
711 RS, /* s: width dist dist reference */
712 DUP,
713 ROLL,
714 DUP,
715 ROLL,
716 PUSHB_1,
717 bci_round,
718 CALL, /* s: width dist reference dist dist ROUND(reference) */
719 PUSHB_2,
722 CINDEX, /* s: width dist reference dist dist ROUND(reference) 48 reference */
723 PUSHB_1,
725 MINDEX, /* s: width dist reference dist ROUND(reference) 48 reference dist */
727 LTEQ, /* dist >= reference */
728 IF, /* s: width dist reference dist ROUND(reference) 48 */
729 ADD,
730 LT, /* dist < ROUND(reference) + 48 */
732 ELSE,
733 SUB,
734 GT, /* dist > ROUND(reference) - 48 */
735 EIF,
738 SWAP, /* s: width reference dist */
739 EIF,
740 POP,
742 DUP,
743 PUSHB_1,
745 GTEQ, /* dist >= 64 */
747 PUSHB_1,
748 bci_round,
749 CALL, /* dist = ROUND(dist) */
751 ELSE,
752 POP,
753 PUSHB_1,
754 64, /* dist = 64 */
755 EIF,
757 SWAP, /* s: dist width */
758 PUSHB_1,
760 LT, /* width < 0 */
762 NEG, /* dist = -dist */
763 EIF,
765 ENDF,
771 * bci_do_loop
773 * An auxiliary function for `bci_loop'.
775 * sal: sal_i (gets incremented by 2 after execution)
776 * sal_func
778 * uses: func[sal_func]
781 static const unsigned char FPGM(bci_loop_do) [] =
784 PUSHB_1,
785 bci_loop_do,
786 FDEF,
788 PUSHB_1,
789 sal_func,
791 CALL,
793 PUSHB_3,
794 sal_i,
796 sal_i,
798 ADD, /* sal_i = sal_i + 2 */
801 ENDF,
807 * bci_loop
809 * Take a range `start'..`end' and a function number and apply the
810 * associated function to the range elements `start', `start+2',
811 * `start+4', ...
813 * in: func_num
814 * end
815 * start
817 * sal: sal_i (counter initialized with `start')
818 * sal_func (`func_num')
820 * uses: bci_loop_do
823 static const unsigned char FPGM(bci_loop) [] =
826 PUSHB_1,
827 bci_loop,
828 FDEF,
830 PUSHB_1,
831 sal_func,
832 SWAP,
833 WS, /* sal_func = func_num */
835 SWAP,
836 DUP,
837 PUSHB_1,
838 sal_i,
839 SWAP,
840 WS, /* sal_i = start */
842 SUB,
843 DIV_POS_BY_2,
844 PUSHB_1,
846 ADD, /* number of loops ((end - start) / 2 + 1) */
848 PUSHB_1,
849 bci_loop_do,
850 LOOPCALL,
852 ENDF,
858 * bci_cvt_rescale
860 * Rescale CVT value by `sal_scale' (in 16.16 format).
862 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
863 * consequently, the calculation `a * b/c' is done as `a + delta' with
864 * `delta = a * (b-c)/c'. This avoids overflow.
866 * in: cvt_idx
868 * out: cvt_idx+1
870 * sal: sal_scale
873 static const unsigned char FPGM(bci_cvt_rescale) [] =
876 PUSHB_1,
877 bci_cvt_rescale,
878 FDEF,
880 DUP,
881 DUP,
882 RCVT,
883 DO_SCALE,
884 WCVTP,
886 PUSHB_1,
888 ADD,
890 ENDF,
896 * bci_cvt_rescale_range
898 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
899 * scaling value.
901 * This function gets used in the `prep' table.
903 * in: num_cvt
904 * cvt_start_idx
906 * sal: sal_i (CVT index of the style's scaling value;
907 * gets incremented by 1 after execution)
908 * sal_scale
910 * uses: bci_cvt_rescale
913 static const unsigned char FPGM(bci_cvt_rescale_range) [] =
916 PUSHB_1,
917 bci_cvt_rescale_range,
918 FDEF,
920 /* store scaling value in `sal_scale' */
921 PUSHB_3,
922 bci_cvt_rescale,
923 sal_scale,
924 sal_i,
926 RCVT,
927 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
929 LOOPCALL,
930 POP,
932 PUSHB_3,
933 sal_i,
935 sal_i,
937 ADD, /* sal_i = sal_i + 1 */
940 ENDF,
946 * bci_vwidth_data_store
948 * Store a vertical width array value.
950 * This function gets used in the `prep' table.
952 * in: value
954 * sal: sal_i (CVT index of the style's vwidth data;
955 * gets incremented by 1 after execution)
958 static const unsigned char FPGM(bci_vwidth_data_store) [] =
961 PUSHB_1,
962 bci_vwidth_data_store,
963 FDEF,
965 PUSHB_1,
966 sal_i,
968 SWAP,
969 WCVTP,
971 PUSHB_3,
972 sal_i,
974 sal_i,
976 ADD, /* sal_i = sal_i + 1 */
979 ENDF,
985 * bci_smooth_blue_round
987 * Round a blue ref value and adjust its corresponding shoot value.
989 * This is the equivalent to the following code (function
990 * `ta_latin_metrics_scale_dim':
992 * delta = dist
993 * if dist < 0:
994 * delta = -delta
996 * if delta < 32:
997 * delta = 0
998 * else if delta < 48:
999 * delta = 32
1000 * else:
1001 * delta = 64
1003 * if dist < 0:
1004 * delta = -delta
1006 * in: ref_idx
1008 * sal: sal_i (number of blue zones)
1010 * out: ref_idx+1
1012 * uses: bci_round
1015 static const unsigned char FPGM(bci_smooth_blue_round) [] =
1018 PUSHB_1,
1019 bci_smooth_blue_round,
1020 FDEF,
1022 DUP,
1023 DUP,
1024 RCVT, /* s: ref_idx ref_idx ref */
1026 DUP,
1027 PUSHB_1,
1028 bci_round,
1029 CALL,
1030 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1032 PUSHB_1,
1033 sal_i,
1035 PUSHB_1,
1037 CINDEX,
1038 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1039 DUP,
1040 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1042 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1043 SWAP,
1044 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1045 DUP,
1046 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1048 DUP,
1049 PUSHB_1,
1051 LT, /* delta < 32 */
1053 POP,
1054 PUSHB_1,
1055 0, /* delta = 0 */
1057 ELSE,
1058 PUSHB_1,
1060 LT, /* delta < 48 */
1062 PUSHB_1,
1063 32, /* delta = 32 */
1065 ELSE,
1066 PUSHB_1,
1067 64, /* delta = 64 */
1068 EIF,
1069 EIF,
1071 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1072 PUSHB_1,
1074 LT, /* dist < 0 */
1076 NEG, /* delta = -delta */
1077 EIF,
1079 PUSHB_1,
1081 CINDEX,
1082 SWAP,
1083 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1085 WCVTP,
1086 WCVTP,
1088 PUSHB_1,
1090 ADD, /* s: (ref_idx + 1) */
1092 ENDF,
1098 * bci_strong_blue_round
1100 * Round a blue ref value and adjust its corresponding shoot value.
1102 * This is the equivalent to the following code:
1104 * delta = dist
1105 * if dist < 0:
1106 * delta = -delta
1108 * if delta < 36:
1109 * delta = 0
1110 * else:
1111 * delta = 64
1113 * if dist < 0:
1114 * delta = -delta
1116 * It doesn't have corresponding code in talatin.c; however, some tests
1117 * have shown that the `smooth' code works just fine for this case also.
1119 * in: ref_idx
1121 * sal: sal_i (number of blue zones)
1123 * out: ref_idx+1
1125 * uses: bci_round
1128 static const unsigned char FPGM(bci_strong_blue_round) [] =
1131 PUSHB_1,
1132 bci_strong_blue_round,
1133 FDEF,
1135 DUP,
1136 DUP,
1137 RCVT, /* s: ref_idx ref_idx ref */
1139 DUP,
1140 PUSHB_1,
1141 bci_round,
1142 CALL,
1143 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1145 PUSHB_1,
1146 sal_i,
1148 PUSHB_1,
1150 CINDEX,
1151 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1152 DUP,
1153 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1155 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1156 SWAP,
1157 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1158 DUP,
1159 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1161 PUSHB_1,
1163 LT, /* delta < 36 */
1165 PUSHB_1,
1166 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1168 ELSE,
1169 PUSHB_1,
1170 64, /* delta = 64 (one pixel unit) */
1171 EIF,
1173 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1174 PUSHB_1,
1176 LT, /* dist < 0 */
1178 NEG, /* delta = -delta */
1179 EIF,
1181 PUSHB_1,
1183 CINDEX,
1184 SWAP,
1185 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1187 WCVTP,
1188 WCVTP,
1190 PUSHB_1,
1192 ADD, /* s: (ref_idx + 1) */
1194 ENDF,
1200 * bci_blue_round_range
1202 * Round a range of blue zones (both reference and shoot values).
1204 * This function gets used in the `prep' table.
1206 * in: num_blue_zones
1207 * blue_ref_idx
1209 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1211 * uses: bci_smooth_blue_round
1212 * bci_strong_blue_round
1215 static const unsigned char FPGM(bci_blue_round_range) [] =
1218 PUSHB_1,
1219 bci_blue_round_range,
1220 FDEF,
1222 DUP,
1223 PUSHB_1,
1224 sal_i,
1225 SWAP,
1228 /* select blue rounding function based on flag in CVT */
1229 PUSHB_3,
1230 bci_strong_blue_round,
1231 bci_smooth_blue_round,
1232 cvtl_use_strong_functions,
1233 RCVT,
1235 POP,
1237 ELSE,
1238 SWAP,
1239 POP,
1241 EIF,
1242 LOOPCALL,
1243 POP,
1245 ENDF,
1251 * bci_decrement_component_counter
1253 * An auxiliary function for composite glyphs.
1255 * CVT: cvtl_is_subglyph
1258 static const unsigned char FPGM(bci_decrement_component_counter) [] =
1261 PUSHB_1,
1262 bci_decrement_component_counter,
1263 FDEF,
1265 /* decrement `cvtl_is_subglyph' counter */
1266 PUSHB_2,
1267 cvtl_is_subglyph,
1268 cvtl_is_subglyph,
1269 RCVT,
1270 PUSHB_1,
1271 100,
1272 SUB,
1273 WCVTP,
1275 ENDF,
1281 * bci_get_point_extrema
1283 * An auxiliary function for `bci_create_segment'.
1285 * in: point-1
1287 * out: point
1289 * sal: sal_point_min
1290 * sal_point_max
1293 static const unsigned char FPGM(bci_get_point_extrema) [] =
1296 PUSHB_1,
1297 bci_get_point_extrema,
1298 FDEF,
1300 PUSHB_1,
1302 ADD, /* s: point */
1303 DUP,
1304 DUP,
1306 /* check whether `point' is a new minimum */
1307 PUSHB_1,
1308 sal_point_min,
1309 RS, /* s: point point point point_min */
1310 MD_orig,
1311 /* if distance is negative, we have a new minimum */
1312 PUSHB_1,
1315 IF, /* s: point point */
1316 DUP,
1317 PUSHB_1,
1318 sal_point_min,
1319 SWAP,
1321 EIF,
1323 /* check whether `point' is a new maximum */
1324 PUSHB_1,
1325 sal_point_max,
1326 RS, /* s: point point point_max */
1327 MD_orig,
1328 /* if distance is positive, we have a new maximum */
1329 PUSHB_1,
1332 IF, /* s: point */
1333 DUP,
1334 PUSHB_1,
1335 sal_point_max,
1336 SWAP,
1338 EIF, /* s: point */
1340 ENDF,
1346 * bci_nibbles
1348 * Pop a byte with two delta arguments in its nibbles and push the
1349 * expanded arguments separately as two bytes.
1351 * in: 16 * (end - start) + (start - base)
1353 * out: start
1354 * end
1356 * sal: sal_base (set to `end' at return)
1360 static const unsigned char FPGM(bci_nibbles) [] =
1362 PUSHB_1,
1363 bci_nibbles,
1364 FDEF,
1366 DUP,
1367 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1369 DIV,
1370 FLOOR,
1371 PUSHB_1,
1373 MUL, /* s: in hnibble */
1374 DUP,
1375 PUSHW_1,
1376 0x04, /* 16*64 */
1377 0x00,
1378 MUL, /* s: in hnibble (hnibble * 16) */
1379 ROLL,
1380 SWAP,
1381 SUB, /* s: hnibble lnibble */
1383 PUSHB_1,
1384 sal_base,
1386 ADD, /* s: hnibble start */
1387 DUP,
1388 ROLL,
1389 ADD, /* s: start end */
1391 DUP,
1392 PUSHB_1,
1393 sal_base,
1394 SWAP,
1395 WS, /* sal_base = end */
1397 SWAP,
1399 ENDF,
1405 * bci_number_set_is_element
1407 * Pop values from stack until it is empty. If one of them is equal to
1408 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1409 * otherwise).
1411 * in: ppem_value_1
1412 * ppem_value_2
1413 * ...
1415 * CVT: cvtl_is_element
1418 static const unsigned char FPGM(bci_number_set_is_element) [] =
1421 PUSHB_1,
1422 bci_number_set_is_element,
1423 FDEF,
1425 /* start_loop: */
1426 MPPEM,
1429 PUSHB_2,
1430 cvtl_is_element,
1431 100,
1432 WCVTP,
1433 EIF,
1435 DEPTH,
1436 PUSHB_1,
1438 NEG,
1439 SWAP,
1440 JROT, /* goto start_loop if stack depth != 0 */
1442 ENDF,
1448 * bci_number_set_is_element2
1450 * Pop value ranges from stack until it is empty. If one of them contains
1451 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1452 * otherwise).
1454 * in: ppem_range_1_start
1455 * ppem_range_1_end
1456 * ppem_range_2_start
1457 * ppem_range_2_end
1458 * ...
1460 * CVT: cvtl_is_element
1463 static const unsigned char FPGM(bci_number_set_is_element2) [] =
1466 PUSHB_1,
1467 bci_number_set_is_element2,
1468 FDEF,
1470 /* start_loop: */
1471 MPPEM,
1472 LTEQ,
1474 MPPEM,
1475 GTEQ,
1477 PUSHB_2,
1478 cvtl_is_element,
1479 100,
1480 WCVTP,
1481 EIF,
1482 ELSE,
1483 POP,
1484 EIF,
1486 DEPTH,
1487 PUSHB_1,
1489 NEG,
1490 SWAP,
1491 JROT, /* goto start_loop if stack depth != 0 */
1493 ENDF,
1499 * bci_create_segment
1501 * Store start and end point of a segment in the storage area,
1502 * then construct a point in the twilight zone to represent it.
1504 * This function is used by `bci_create_segments'.
1506 * in: start
1507 * end
1508 * [last (if wrap-around segment)]
1509 * [first (if wrap-around segment)]
1511 * sal: sal_i (start of current segment)
1512 * sal_j (current twilight point)
1513 * sal_point_min
1514 * sal_point_max
1515 * sal_base
1516 * sal_num_packed_segments
1517 * sal_scale
1519 * CVT: cvtl_temp
1521 * uses: bci_get_point_extrema
1522 * bci_nibbles
1524 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1525 * delta values in nibbles (without a wrap-around segment).
1528 static const unsigned char FPGM(bci_create_segment) [] =
1531 PUSHB_1,
1532 bci_create_segment,
1533 FDEF,
1535 PUSHB_2,
1537 sal_num_packed_segments,
1539 NEQ,
1541 PUSHB_2,
1542 sal_num_packed_segments,
1543 sal_num_packed_segments,
1545 PUSHB_1,
1547 SUB,
1548 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1550 PUSHB_1,
1551 bci_nibbles,
1552 CALL,
1553 EIF,
1555 PUSHB_1,
1556 sal_i,
1558 PUSHB_1,
1560 CINDEX,
1561 WS, /* sal[sal_i] = start */
1563 /* initialize inner loop(s) */
1564 PUSHB_2,
1565 sal_point_min,
1567 CINDEX,
1568 WS, /* sal_point_min = start */
1569 PUSHB_2,
1570 sal_point_max,
1572 CINDEX,
1573 WS, /* sal_point_max = start */
1575 PUSHB_1,
1577 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1579 SWAP,
1580 DUP,
1581 PUSHB_1,
1583 CINDEX, /* s: start end end start */
1584 LT, /* start > end */
1586 /* we have a wrap-around segment with two more arguments */
1587 /* to give the last and first point of the contour, respectively; */
1588 /* our job is to store a segment `start'-`last', */
1589 /* and to get extrema for the two segments */
1590 /* `start'-`last' and `first'-`end' */
1592 /* s: first last start end */
1593 PUSHB_2,
1595 sal_i,
1597 ADD,
1598 PUSHB_1,
1600 CINDEX,
1601 WS, /* sal[sal_i + 1] = last */
1603 ROLL,
1604 ROLL, /* s: first end last start */
1605 DUP,
1606 ROLL,
1607 SWAP, /* s: first end start last start */
1608 SUB, /* s: first end start loop_count */
1610 PUSHB_1,
1611 bci_get_point_extrema,
1612 LOOPCALL,
1613 /* clean up stack */
1614 POP,
1616 SWAP, /* s: end first */
1617 PUSHB_1,
1619 SUB,
1620 DUP,
1621 ROLL, /* s: (first - 1) (first - 1) end */
1622 SWAP,
1623 SUB, /* s: (first - 1) loop_count */
1625 PUSHB_1,
1626 bci_get_point_extrema,
1627 LOOPCALL,
1628 /* clean up stack */
1629 POP,
1631 ELSE, /* s: start end */
1632 PUSHB_2,
1634 sal_i,
1636 ADD,
1637 PUSHB_1,
1639 CINDEX,
1640 WS, /* sal[sal_i + 1] = end */
1642 PUSHB_1,
1644 CINDEX,
1645 SUB, /* s: start loop_count */
1647 PUSHB_1,
1648 bci_get_point_extrema,
1649 LOOPCALL,
1650 /* clean up stack */
1651 POP,
1652 EIF,
1654 /* the twilight point representing a segment */
1655 /* is in the middle between the minimum and maximum */
1656 PUSHB_1,
1657 sal_point_min,
1659 GC_orig,
1660 PUSHB_1,
1661 sal_point_max,
1663 GC_orig,
1664 ADD,
1665 DIV_BY_2, /* s: middle_pos */
1667 DO_SCALE, /* middle_pos = middle_pos * scale */
1669 /* write it to temporary CVT location */
1670 PUSHB_2,
1671 cvtl_temp,
1673 SZP0, /* set zp0 to twilight zone 0 */
1674 SWAP,
1675 WCVTP,
1677 /* create twilight point with index `sal_j' */
1678 PUSHB_1,
1679 sal_j,
1681 PUSHB_1,
1682 cvtl_temp,
1683 MIAP_noround,
1685 PUSHB_3,
1686 sal_j,
1688 sal_j,
1690 ADD, /* twilight_point = twilight_point + 1 */
1693 ENDF,
1699 * bci_create_segments
1701 * This is the top-level entry function.
1703 * It pops point ranges from the stack to define segments, computes
1704 * twilight points to represent segments, and finally calls
1705 * `bci_hint_glyph' to handle the rest.
1707 * The second argument (`data_offset') addresses three CVT arrays in
1708 * parallel:
1710 * CVT(data_offset):
1711 * the current style's scaling value (stored in `sal_scale')
1713 * data_offset + num_used_styles:
1714 * offset to the current style's vwidth index array (this value gets
1715 * stored in `sal_vwidth_data_offset')
1717 * data_offset + 2*num_used_styles:
1718 * offset to the current style's vwidth size
1720 * This addressing scheme ensures that (a) we only need a single argument,
1721 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1722 * which should be sufficient for a long time.
1724 * in: num_packed_segments
1725 * data_offset
1726 * num_segments (N)
1727 * segment_start_0
1728 * segment_end_0
1729 * [contour_last 0 (if wrap-around segment)]
1730 * [contour_first 0 (if wrap-around segment)]
1731 * segment_start_1
1732 * segment_end_1
1733 * [contour_last 0 (if wrap-around segment)]
1734 * [contour_first 0 (if wrap-around segment)]
1735 * ...
1736 * segment_start_(N-1)
1737 * segment_end_(N-1)
1738 * [contour_last (N-1) (if wrap-around segment)]
1739 * [contour_first (N-1) (if wrap-around segment)]
1740 * ... stuff for bci_hint_glyph ...
1742 * sal: sal_i (start of current segment)
1743 * sal_j (current twilight point)
1744 * sal_num_packed_segments
1745 * sal_base (the base for delta values in nibbles)
1746 * sal_vwidth_data_offset
1747 * sal_scale
1749 * CVT: cvtl_is_subglyph
1751 * uses: bci_create_segment
1752 * bci_loop
1753 * bci_hint_glyph
1755 * If `num_packed_segments' is set to p, the first p start/end pairs are
1756 * stored as delta values in nibbles, with the `start' delta in the lower
1757 * nibble (and there are no wrap-around segments). For example, if the
1758 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1759 * stack are 0x21, 0x32, and 0x14.
1763 static const unsigned char FPGM(bci_create_segments_a) [] =
1766 PUSHB_1,
1767 bci_create_segments,
1768 FDEF,
1770 /* all our measurements are taken along the y axis */
1771 SVTCA_y,
1773 /* only do something if we are not a subglyph */
1774 PUSHB_2,
1776 cvtl_is_subglyph,
1777 RCVT,
1780 PUSHB_1,
1781 sal_num_packed_segments,
1782 SWAP,
1785 DUP,
1786 RCVT,
1787 PUSHB_1,
1788 sal_scale, /* sal_scale = CVT(data_offset) */
1789 SWAP,
1792 PUSHB_1,
1793 sal_vwidth_data_offset,
1794 SWAP,
1795 PUSHB_1,
1799 /* %c, number of used styles */
1801 static const unsigned char FPGM(bci_create_segments_b) [] =
1804 ADD,
1805 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1807 DUP,
1808 ADD,
1809 PUSHB_1,
1811 SUB, /* delta = (2*num_segments - 1) */
1813 PUSHB_6,
1814 sal_segment_offset,
1815 sal_segment_offset,
1817 sal_j,
1819 sal_base,
1821 WS, /* sal_base = 0 */
1822 WS, /* sal_j = 0 (point offset) */
1824 ROLL,
1825 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1827 PUSHB_2,
1828 bci_create_segment,
1829 bci_loop,
1830 CALL,
1832 PUSHB_1,
1833 bci_hint_glyph,
1834 CALL,
1838 /* used if we have delta exceptions */
1840 static const unsigned char FPGM(bci_create_segments_c) [] =
1843 PUSHB_1,
1845 SZPS,
1849 static const unsigned char FPGM(bci_create_segments_d) [] =
1852 ELSE,
1853 CLEAR,
1854 EIF,
1856 ENDF,
1862 * bci_create_segments_X
1864 * Top-level routines for calling `bci_create_segments'.
1867 static const unsigned char FPGM(bci_create_segments_0) [] =
1870 PUSHB_1,
1871 bci_create_segments_0,
1872 FDEF,
1874 PUSHB_2,
1876 bci_create_segments,
1877 CALL,
1879 ENDF,
1883 static const unsigned char FPGM(bci_create_segments_1) [] =
1886 PUSHB_1,
1887 bci_create_segments_1,
1888 FDEF,
1890 PUSHB_2,
1892 bci_create_segments,
1893 CALL,
1895 ENDF,
1899 static const unsigned char FPGM(bci_create_segments_2) [] =
1902 PUSHB_1,
1903 bci_create_segments_2,
1904 FDEF,
1906 PUSHB_2,
1908 bci_create_segments,
1909 CALL,
1911 ENDF,
1915 static const unsigned char FPGM(bci_create_segments_3) [] =
1918 PUSHB_1,
1919 bci_create_segments_3,
1920 FDEF,
1922 PUSHB_2,
1924 bci_create_segments,
1925 CALL,
1927 ENDF,
1931 static const unsigned char FPGM(bci_create_segments_4) [] =
1934 PUSHB_1,
1935 bci_create_segments_4,
1936 FDEF,
1938 PUSHB_2,
1940 bci_create_segments,
1941 CALL,
1943 ENDF,
1947 static const unsigned char FPGM(bci_create_segments_5) [] =
1950 PUSHB_1,
1951 bci_create_segments_5,
1952 FDEF,
1954 PUSHB_2,
1956 bci_create_segments,
1957 CALL,
1959 ENDF,
1963 static const unsigned char FPGM(bci_create_segments_6) [] =
1966 PUSHB_1,
1967 bci_create_segments_6,
1968 FDEF,
1970 PUSHB_2,
1972 bci_create_segments,
1973 CALL,
1975 ENDF,
1979 static const unsigned char FPGM(bci_create_segments_7) [] =
1982 PUSHB_1,
1983 bci_create_segments_7,
1984 FDEF,
1986 PUSHB_2,
1988 bci_create_segments,
1989 CALL,
1991 ENDF,
1995 static const unsigned char FPGM(bci_create_segments_8) [] =
1998 PUSHB_1,
1999 bci_create_segments_8,
2000 FDEF,
2002 PUSHB_2,
2004 bci_create_segments,
2005 CALL,
2007 ENDF,
2011 static const unsigned char FPGM(bci_create_segments_9) [] =
2014 PUSHB_1,
2015 bci_create_segments_9,
2016 FDEF,
2018 PUSHB_2,
2020 bci_create_segments,
2021 CALL,
2023 ENDF,
2029 * bci_deltapX
2031 * Wrapper functions around DELTAP[123] that touch the affected points
2032 * before applying the delta. This is necessary for ClearType.
2034 * While DELTAP[123] implicitly do a loop, we have to process the
2035 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2037 * in: point
2038 * arg
2041 static const unsigned char FPGM(bci_deltap1) [] =
2044 PUSHB_1,
2045 bci_deltap1,
2046 FDEF,
2048 DUP,
2049 MDAP_noround, /* touch `point' */
2051 PUSHB_1,
2053 DELTAP1, /* process one `(point,arg)' pair */
2055 ENDF,
2059 static const unsigned char FPGM(bci_deltap2) [] =
2062 PUSHB_1,
2063 bci_deltap2,
2064 FDEF,
2066 DUP,
2067 MDAP_noround, /* touch `point' */
2069 PUSHB_1,
2071 DELTAP2, /* process one `(point,arg)' pair */
2073 ENDF,
2077 static const unsigned char FPGM(bci_deltap3) [] =
2080 PUSHB_1,
2081 bci_deltap3,
2082 FDEF,
2084 DUP,
2085 MDAP_noround, /* touch `point' */
2087 PUSHB_1,
2089 DELTAP3, /* process one `(point,arg)' pair */
2091 ENDF,
2097 * bci_create_segments_composite
2099 * The same as `bci_create_segments'.
2100 * It also decrements the composite component counter.
2102 * sal: sal_num_packed_segments
2103 * sal_segment_offset
2104 * sal_vwidth_data_offset
2106 * CVT: cvtl_is_subglyph
2108 * uses: bci_decrement_component_counter
2109 * bci_create_segment
2110 * bci_loop
2111 * bci_hint_glyph
2114 static const unsigned char FPGM(bci_create_segments_composite_a) [] =
2117 PUSHB_1,
2118 bci_create_segments_composite,
2119 FDEF,
2121 /* all our measurements are taken along the y axis */
2122 SVTCA_y,
2124 PUSHB_1,
2125 bci_decrement_component_counter,
2126 CALL,
2128 /* only do something if we are not a subglyph */
2129 PUSHB_2,
2131 cvtl_is_subglyph,
2132 RCVT,
2135 PUSHB_1,
2136 sal_num_packed_segments,
2137 SWAP,
2140 DUP,
2141 RCVT,
2142 PUSHB_1,
2143 sal_scale, /* sal_scale = CVT(data_offset) */
2144 SWAP,
2147 PUSHB_1,
2148 sal_vwidth_data_offset,
2149 SWAP,
2150 PUSHB_1,
2154 /* %c, number of used styles */
2156 static const unsigned char FPGM(bci_create_segments_composite_b) [] =
2159 ADD,
2160 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2162 DUP,
2163 ADD,
2164 PUSHB_1,
2166 SUB, /* delta = (2*num_segments - 1) */
2168 PUSHB_6,
2169 sal_segment_offset,
2170 sal_segment_offset,
2172 sal_j,
2174 sal_base,
2176 WS, /* sal_base = 0 */
2177 WS, /* sal_j = 0 (point offset) */
2179 ROLL,
2180 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2182 PUSHB_2,
2183 bci_create_segment,
2184 bci_loop,
2185 CALL,
2187 PUSHB_1,
2188 bci_hint_glyph,
2189 CALL,
2193 /* used if we have delta exceptions */
2195 static const unsigned char FPGM(bci_create_segments_composite_c) [] =
2198 PUSHB_1,
2200 SZPS,
2204 static const unsigned char FPGM(bci_create_segments_composite_d) [] =
2207 ELSE,
2208 CLEAR,
2209 EIF,
2211 ENDF,
2217 * bci_create_segments_composite_X
2219 * Top-level routines for calling `bci_create_segments_composite'.
2222 static const unsigned char FPGM(bci_create_segments_composite_0) [] =
2225 PUSHB_1,
2226 bci_create_segments_composite_0,
2227 FDEF,
2229 PUSHB_2,
2231 bci_create_segments_composite,
2232 CALL,
2234 ENDF,
2238 static const unsigned char FPGM(bci_create_segments_composite_1) [] =
2241 PUSHB_1,
2242 bci_create_segments_composite_1,
2243 FDEF,
2245 PUSHB_2,
2247 bci_create_segments_composite,
2248 CALL,
2250 ENDF,
2254 static const unsigned char FPGM(bci_create_segments_composite_2) [] =
2257 PUSHB_1,
2258 bci_create_segments_composite_2,
2259 FDEF,
2261 PUSHB_2,
2263 bci_create_segments_composite,
2264 CALL,
2266 ENDF,
2270 static const unsigned char FPGM(bci_create_segments_composite_3) [] =
2273 PUSHB_1,
2274 bci_create_segments_composite_3,
2275 FDEF,
2277 PUSHB_2,
2279 bci_create_segments_composite,
2280 CALL,
2282 ENDF,
2286 static const unsigned char FPGM(bci_create_segments_composite_4) [] =
2289 PUSHB_1,
2290 bci_create_segments_composite_4,
2291 FDEF,
2293 PUSHB_2,
2295 bci_create_segments_composite,
2296 CALL,
2298 ENDF,
2302 static const unsigned char FPGM(bci_create_segments_composite_5) [] =
2305 PUSHB_1,
2306 bci_create_segments_composite_5,
2307 FDEF,
2309 PUSHB_2,
2311 bci_create_segments_composite,
2312 CALL,
2314 ENDF,
2318 static const unsigned char FPGM(bci_create_segments_composite_6) [] =
2321 PUSHB_1,
2322 bci_create_segments_composite_6,
2323 FDEF,
2325 PUSHB_2,
2327 bci_create_segments_composite,
2328 CALL,
2330 ENDF,
2334 static const unsigned char FPGM(bci_create_segments_composite_7) [] =
2337 PUSHB_1,
2338 bci_create_segments_composite_7,
2339 FDEF,
2341 PUSHB_2,
2343 bci_create_segments_composite,
2344 CALL,
2346 ENDF,
2350 static const unsigned char FPGM(bci_create_segments_composite_8) [] =
2353 PUSHB_1,
2354 bci_create_segments_composite_8,
2355 FDEF,
2357 PUSHB_2,
2359 bci_create_segments_composite,
2360 CALL,
2362 ENDF,
2366 static const unsigned char FPGM(bci_create_segments_composite_9) [] =
2369 PUSHB_1,
2370 bci_create_segments_composite_9,
2371 FDEF,
2373 PUSHB_2,
2375 bci_create_segments_composite,
2376 CALL,
2378 ENDF,
2384 * bci_align_point
2386 * An auxiliary function for `bci_align_segment'.
2388 * in: point
2390 * out: point+1
2393 static const unsigned char FPGM(bci_align_point) [] =
2396 PUSHB_1,
2397 bci_align_point,
2398 FDEF,
2400 DUP,
2401 ALIGNRP, /* align point with rp0 */
2403 PUSHB_1,
2405 ADD,
2407 ENDF,
2413 * bci_align_segment
2415 * Align all points in a segment to the twilight point in rp0.
2416 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2418 * in: segment_index
2420 * sal: sal_segment_offset
2422 * uses: bci_align_point
2425 static const unsigned char FPGM(bci_align_segment) [] =
2428 PUSHB_1,
2429 bci_align_segment,
2430 FDEF,
2432 /* we need the values of `sal_segment_offset + 2*segment_index' */
2433 /* and `sal_segment_offset + 2*segment_index + 1' */
2434 DUP,
2435 ADD,
2436 PUSHB_1,
2437 sal_segment_offset,
2438 ADD,
2439 DUP,
2441 SWAP,
2442 PUSHB_1,
2444 ADD,
2445 RS, /* s: first last */
2447 PUSHB_1,
2449 CINDEX, /* s: first last first */
2450 SUB,
2451 PUSHB_1,
2453 ADD, /* s: first loop_count */
2455 PUSHB_1,
2456 bci_align_point,
2457 LOOPCALL,
2458 /* clean up stack */
2459 POP,
2461 ENDF,
2467 * bci_align_segments
2469 * Align segments to the twilight point in rp0.
2470 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2472 * in: first_segment
2473 * loop_counter (N)
2474 * segment_1
2475 * segment_2
2476 * ...
2477 * segment_N
2479 * uses: bci_align_segment
2482 static const unsigned char FPGM(bci_align_segments) [] =
2485 PUSHB_1,
2486 bci_align_segments,
2487 FDEF,
2489 PUSHB_1,
2490 bci_align_segment,
2491 CALL,
2493 PUSHB_1,
2494 bci_align_segment,
2495 LOOPCALL,
2497 ENDF,
2503 * bci_scale_contour
2505 * Scale a contour using two points giving the maximum and minimum
2506 * coordinates.
2508 * It expects that no point on the contour is touched.
2510 * in: min_point
2511 * max_point
2513 * sal: sal_scale
2516 static const unsigned char FPGM(bci_scale_contour) [] =
2519 PUSHB_1,
2520 bci_scale_contour,
2521 FDEF,
2523 DUP,
2524 DUP,
2525 GC_orig,
2526 DUP,
2527 DO_SCALE, /* min_pos_new = min_pos * scale */
2528 SWAP,
2529 SUB,
2530 SHPIX,
2532 /* don't scale a single-point contour twice */
2533 SWAP,
2534 DUP,
2535 ROLL,
2536 NEQ,
2538 DUP,
2539 GC_orig,
2540 DUP,
2541 DO_SCALE, /* max_pos_new = max_pos * scale */
2542 SWAP,
2543 SUB,
2544 SHPIX,
2546 ELSE,
2547 POP,
2548 EIF,
2550 ENDF,
2556 * bci_scale_glyph
2558 * Scale a glyph using a list of points (two points per contour, giving
2559 * the maximum and mininum coordinates).
2561 * It expects that no point in the glyph is touched.
2563 * Note that the point numbers are sorted in ascending order;
2564 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2565 * contour without specifying which one is the minimum and maximum.
2567 * in: num_contours (N)
2568 * min_point_1
2569 * max_point_1
2570 * min_point_2
2571 * max_point_2
2572 * ...
2573 * min_point_N
2574 * max_point_N
2576 * CVT: cvtl_is_subglyph
2577 * cvtl_do_iup_y
2579 * uses: bci_scale_contour
2582 static const unsigned char FPGM(bci_scale_glyph) [] =
2585 PUSHB_1,
2586 bci_scale_glyph,
2587 FDEF,
2589 /* all our measurements are taken along the y axis */
2590 SVTCA_y,
2592 /* only do something if we are not a subglyph */
2593 PUSHB_2,
2595 cvtl_is_subglyph,
2596 RCVT,
2599 PUSHB_1,
2601 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2603 PUSHB_1,
2604 bci_scale_contour,
2605 LOOPCALL,
2607 PUSHB_2,
2608 cvtl_do_iup_y,
2610 SZP2, /* set zp2 to normal zone 1 */
2611 RCVT,
2613 IUP_y,
2614 EIF,
2616 ELSE,
2617 CLEAR,
2618 EIF,
2620 ENDF,
2626 * bci_scale_composite_glyph
2628 * The same as `bci_scale_glyph'.
2629 * It also decrements the composite component counter.
2631 * CVT: cvtl_is_subglyph
2632 * cvtl_do_iup_y
2634 * uses: bci_decrement_component_counter
2635 * bci_scale_contour
2638 static const unsigned char FPGM(bci_scale_composite_glyph) [] =
2641 PUSHB_1,
2642 bci_scale_composite_glyph,
2643 FDEF,
2645 /* all our measurements are taken along the y axis */
2646 SVTCA_y,
2648 PUSHB_1,
2649 bci_decrement_component_counter,
2650 CALL,
2652 /* only do something if we are not a subglyph */
2653 PUSHB_2,
2655 cvtl_is_subglyph,
2656 RCVT,
2659 PUSHB_1,
2661 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2663 PUSHB_1,
2664 bci_scale_contour,
2665 LOOPCALL,
2667 PUSHB_2,
2668 cvtl_do_iup_y,
2670 SZP2, /* set zp2 to normal zone 1 */
2671 RCVT,
2673 IUP_y,
2674 EIF,
2676 ELSE,
2677 CLEAR,
2678 EIF,
2680 ENDF,
2686 * bci_shift_contour
2688 * Shift a contour by a given amount.
2690 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2691 * point to the normal zone 1.
2693 * in: contour
2695 * out: contour+1
2698 static const unsigned char FPGM(bci_shift_contour) [] =
2701 PUSHB_1,
2702 bci_shift_contour,
2703 FDEF,
2705 DUP,
2706 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2708 PUSHB_1,
2710 ADD,
2712 ENDF,
2718 * bci_shift_subglyph
2720 * Shift a subglyph. To be more specific, it corrects the already applied
2721 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2722 * also.
2724 * If this function is called, a point `x' in the subglyph has been scaled
2725 * already (during the hinting of the subglyph itself), and `offset' has
2726 * been applied also:
2728 * x -> x * scale + offset (1)
2730 * However, the offset should be applied first, then the scaling:
2732 * x -> (x + offset) * scale (2)
2734 * Our job is now to transform (1) to (2); a simple calculation shows that
2735 * we have to shift all points of the subglyph by
2737 * offset * scale - offset = offset * (scale - 1)
2739 * Note that `sal_scale' is equal to the above `scale - 1'.
2741 * in: offset (in FUnits)
2742 * num_contours
2743 * first_contour
2745 * CVT: cvtl_funits_to_pixels
2747 * sal: sal_scale
2749 * uses: bci_round
2750 * bci_shift_contour
2753 static const unsigned char FPGM(bci_shift_subglyph_a) [] =
2756 PUSHB_1,
2757 bci_shift_subglyph,
2758 FDEF,
2760 /* all our measurements are taken along the y axis */
2761 SVTCA_y,
2763 PUSHB_1,
2764 cvtl_funits_to_pixels,
2765 RCVT, /* scaling factor FUnits -> pixels */
2766 MUL,
2767 DIV_BY_1024,
2769 /* the autohinter always rounds offsets */
2770 PUSHB_1,
2771 bci_round,
2772 CALL, /* offset = round(offset) */
2774 PUSHB_1,
2775 sal_scale,
2777 MUL,
2778 DIV_BY_1024, /* delta = offset * (scale - 1) */
2780 /* and round again */
2781 PUSHB_1,
2782 bci_round,
2783 CALL, /* offset = round(offset) */
2785 PUSHB_1,
2787 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2789 /* we create twilight point 0 as a reference point, */
2790 /* setting the original position to zero (using `cvtl_temp') */
2791 PUSHB_5,
2794 cvtl_temp,
2795 cvtl_temp,
2797 WCVTP,
2798 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2800 SWAP, /* s: first_contour num_contours 0 delta */
2801 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2803 PUSHB_2,
2804 bci_shift_contour,
2806 SZP2, /* set zp2 to normal zone 1 */
2807 LOOPCALL,
2811 /* used if we have delta exceptions */
2813 static const unsigned char FPGM(bci_shift_subglyph_b) [] =
2816 PUSHB_1,
2818 SZPS,
2822 static const unsigned char FPGM(bci_shift_subglyph_c) [] =
2825 ENDF,
2831 * bci_ip_outer_align_point
2833 * Auxiliary function for `bci_action_ip_before' and
2834 * `bci_action_ip_after'.
2836 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2837 * zone, and both zp1 and zp2 set to normal zone.
2839 * in: point
2841 * sal: sal_i (edge_orig_pos)
2842 * sal_scale
2845 static const unsigned char FPGM(bci_ip_outer_align_point) [] =
2848 PUSHB_1,
2849 bci_ip_outer_align_point,
2850 FDEF,
2852 DUP,
2853 ALIGNRP, /* align `point' with `edge' */
2854 DUP,
2855 GC_orig,
2856 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2858 PUSHB_1,
2859 sal_i,
2861 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2862 SHPIX,
2864 ENDF,
2870 * bci_ip_on_align_points
2872 * Auxiliary function for `bci_action_ip_on'.
2874 * in: edge (in twilight zone)
2875 * loop_counter (N)
2876 * point_1
2877 * point_2
2878 * ...
2879 * point_N
2882 static const unsigned char FPGM(bci_ip_on_align_points) [] =
2885 PUSHB_1,
2886 bci_ip_on_align_points,
2887 FDEF,
2889 MDAP_noround, /* set rp0 and rp1 to `edge' */
2891 SLOOP,
2892 ALIGNRP,
2894 ENDF,
2900 * bci_ip_between_align_point
2902 * Auxiliary function for `bci_ip_between_align_points'.
2904 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2905 * zone, and both zp1 and zp2 set to normal zone.
2907 * in: point
2909 * sal: sal_i (edge_orig_pos)
2910 * sal_j (stretch_factor)
2911 * sal_scale
2914 static const unsigned char FPGM(bci_ip_between_align_point) [] =
2917 PUSHB_1,
2918 bci_ip_between_align_point,
2919 FDEF,
2921 DUP,
2922 ALIGNRP, /* align `point' with `edge' */
2923 DUP,
2924 GC_orig,
2925 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2927 PUSHB_1,
2928 sal_i,
2930 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2931 PUSHB_1,
2932 sal_j,
2934 MUL, /* s: point delta */
2935 SHPIX,
2937 ENDF,
2943 * bci_ip_between_align_points
2945 * Auxiliary function for `bci_action_ip_between'.
2947 * in: after_edge (in twilight zone)
2948 * before_edge (in twilight zone)
2949 * loop_counter (N)
2950 * point_1
2951 * point_2
2952 * ...
2953 * point_N
2955 * sal: sal_i (before_orig_pos)
2956 * sal_j (stretch_factor)
2958 * uses: bci_ip_between_align_point
2961 static const unsigned char FPGM(bci_ip_between_align_points) [] =
2964 PUSHB_1,
2965 bci_ip_between_align_points,
2966 FDEF,
2968 PUSHB_2,
2971 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2972 CINDEX,
2973 DUP, /* s: ... before after before before */
2974 MDAP_noround, /* set rp0 and rp1 to `before' */
2975 DUP,
2976 GC_orig, /* s: ... before after before before_orig_pos */
2977 PUSHB_1,
2978 sal_i,
2979 SWAP,
2980 WS, /* sal_i = before_orig_pos */
2981 PUSHB_1,
2983 CINDEX, /* s: ... before after before after */
2984 MD_cur, /* a = after_pos - before_pos */
2985 ROLL,
2986 ROLL,
2987 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2989 DUP,
2990 IF, /* b != 0 ? */
2991 DIV, /* s: a/b */
2992 ELSE,
2993 POP, /* avoid division by zero */
2994 EIF,
2996 PUSHB_1,
2997 sal_j,
2998 SWAP,
2999 WS, /* sal_j = stretch_factor */
3001 PUSHB_3,
3002 bci_ip_between_align_point,
3005 SZP2, /* set zp2 to normal zone 1 */
3006 SZP1, /* set zp1 to normal zone 1 */
3007 LOOPCALL,
3009 ENDF,
3015 * bci_action_ip_before
3017 * Handle `ip_before' data to align points located before the first edge.
3019 * in: first_edge (in twilight zone)
3020 * loop_counter (N)
3021 * point_1
3022 * point_2
3023 * ...
3024 * point_N
3026 * sal: sal_i (first_edge_orig_pos)
3028 * uses: bci_ip_outer_align_point
3031 static const unsigned char FPGM(bci_action_ip_before) [] =
3034 PUSHB_1,
3035 bci_action_ip_before,
3036 FDEF,
3038 PUSHB_1,
3040 SZP2, /* set zp2 to twilight zone 0 */
3042 DUP,
3043 GC_orig,
3044 PUSHB_1,
3045 sal_i,
3046 SWAP,
3047 WS, /* sal_i = first_edge_orig_pos */
3049 PUSHB_3,
3053 SZP2, /* set zp2 to normal zone 1 */
3054 SZP1, /* set zp1 to normal zone 1 */
3055 SZP0, /* set zp0 to twilight zone 0 */
3057 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
3059 PUSHB_1,
3060 bci_ip_outer_align_point,
3061 LOOPCALL,
3063 ENDF,
3069 * bci_action_ip_after
3071 * Handle `ip_after' data to align points located after the last edge.
3073 * in: last_edge (in twilight zone)
3074 * loop_counter (N)
3075 * point_1
3076 * point_2
3077 * ...
3078 * point_N
3080 * sal: sal_i (last_edge_orig_pos)
3082 * uses: bci_ip_outer_align_point
3085 static const unsigned char FPGM(bci_action_ip_after) [] =
3088 PUSHB_1,
3089 bci_action_ip_after,
3090 FDEF,
3092 PUSHB_1,
3094 SZP2, /* set zp2 to twilight zone 0 */
3096 DUP,
3097 GC_orig,
3098 PUSHB_1,
3099 sal_i,
3100 SWAP,
3101 WS, /* sal_i = last_edge_orig_pos */
3103 PUSHB_3,
3107 SZP2, /* set zp2 to normal zone 1 */
3108 SZP1, /* set zp1 to normal zone 1 */
3109 SZP0, /* set zp0 to twilight zone 0 */
3111 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3113 PUSHB_1,
3114 bci_ip_outer_align_point,
3115 LOOPCALL,
3117 ENDF,
3123 * bci_action_ip_on
3125 * Handle `ip_on' data to align points located on an edge coordinate (but
3126 * not part of an edge).
3128 * in: loop_counter (M)
3129 * edge_1 (in twilight zone)
3130 * loop_counter (N_1)
3131 * point_1
3132 * point_2
3133 * ...
3134 * point_N_1
3135 * edge_2 (in twilight zone)
3136 * loop_counter (N_2)
3137 * point_1
3138 * point_2
3139 * ...
3140 * point_N_2
3141 * ...
3142 * edge_M (in twilight zone)
3143 * loop_counter (N_M)
3144 * point_1
3145 * point_2
3146 * ...
3147 * point_N_M
3149 * uses: bci_ip_on_align_points
3152 static const unsigned char FPGM(bci_action_ip_on) [] =
3155 PUSHB_1,
3156 bci_action_ip_on,
3157 FDEF,
3159 PUSHB_2,
3162 SZP1, /* set zp1 to normal zone 1 */
3163 SZP0, /* set zp0 to twilight zone 0 */
3165 PUSHB_1,
3166 bci_ip_on_align_points,
3167 LOOPCALL,
3169 ENDF,
3175 * bci_action_ip_between
3177 * Handle `ip_between' data to align points located between two edges.
3179 * in: loop_counter (M)
3180 * before_edge_1 (in twilight zone)
3181 * after_edge_1 (in twilight zone)
3182 * loop_counter (N_1)
3183 * point_1
3184 * point_2
3185 * ...
3186 * point_N_1
3187 * before_edge_2 (in twilight zone)
3188 * after_edge_2 (in twilight zone)
3189 * loop_counter (N_2)
3190 * point_1
3191 * point_2
3192 * ...
3193 * point_N_2
3194 * ...
3195 * before_edge_M (in twilight zone)
3196 * after_edge_M (in twilight zone)
3197 * loop_counter (N_M)
3198 * point_1
3199 * point_2
3200 * ...
3201 * point_N_M
3203 * uses: bci_ip_between_align_points
3206 static const unsigned char FPGM(bci_action_ip_between) [] =
3209 PUSHB_1,
3210 bci_action_ip_between,
3211 FDEF,
3213 PUSHB_1,
3214 bci_ip_between_align_points,
3215 LOOPCALL,
3217 ENDF,
3223 * bci_adjust_common
3225 * Common code for bci_action_adjust routines.
3227 * uses: func[sal_stem_width_function]
3230 static const unsigned char FPGM(bci_adjust_common) [] =
3233 PUSHB_1,
3234 bci_adjust_common,
3235 FDEF,
3237 PUSHB_1,
3239 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3241 PUSHB_1,
3243 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3244 PUSHB_1,
3246 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3247 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3249 PUSHB_1,
3250 sal_stem_width_function,
3252 CALL,
3253 NEG, /* s: [...] edge2 edge -cur_len */
3255 ROLL, /* s: [...] edge -cur_len edge2 */
3256 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3257 SWAP,
3258 DUP,
3259 DUP, /* s: [...] -cur_len edge edge edge */
3260 ALIGNRP, /* align `edge' with `edge2' */
3261 ROLL,
3262 SHPIX, /* shift `edge' by -cur_len */
3264 ENDF,
3270 * bci_adjust_bound
3272 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3273 * edge of the stem has already been moved, then moving it again if
3274 * necessary to stay bound.
3276 * in: edge2_is_serif
3277 * edge_is_round
3278 * edge_point (in twilight zone)
3279 * edge2_point (in twilight zone)
3280 * edge[-1] (in twilight zone)
3281 * ... stuff for bci_align_segments (edge) ...
3283 * uses: bci_adjust_common
3284 * bci_align_segments
3287 static const unsigned char FPGM(bci_adjust_bound) [] =
3290 PUSHB_1,
3291 bci_adjust_bound,
3292 FDEF,
3294 PUSHB_1,
3295 bci_adjust_common,
3296 CALL,
3298 SWAP, /* s: edge edge[-1] */
3299 DUP,
3300 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3301 GC_cur,
3302 PUSHB_1,
3304 CINDEX,
3305 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3306 GT, /* edge_pos < edge[-1]_pos */
3308 DUP,
3309 ALIGNRP, /* align `edge' to `edge[-1]' */
3310 EIF,
3312 MDAP_noround, /* set rp0 and rp1 to `edge' */
3314 PUSHB_2,
3315 bci_align_segments,
3317 SZP1, /* set zp1 to normal zone 1 */
3318 CALL,
3320 ENDF,
3326 * bci_action_adjust_bound
3327 * bci_action_adjust_bound_serif
3328 * bci_action_adjust_bound_round
3329 * bci_action_adjust_bound_round_serif
3331 * Higher-level routines for calling `bci_adjust_bound'.
3334 static const unsigned char FPGM(bci_action_adjust_bound) [] =
3337 PUSHB_1,
3338 bci_action_adjust_bound,
3339 FDEF,
3341 PUSHB_3,
3344 bci_adjust_bound,
3345 CALL,
3347 ENDF,
3351 static const unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3354 PUSHB_1,
3355 bci_action_adjust_bound_serif,
3356 FDEF,
3358 PUSHB_3,
3361 bci_adjust_bound,
3362 CALL,
3364 ENDF,
3368 static const unsigned char FPGM(bci_action_adjust_bound_round) [] =
3371 PUSHB_1,
3372 bci_action_adjust_bound_round,
3373 FDEF,
3375 PUSHB_3,
3378 bci_adjust_bound,
3379 CALL,
3381 ENDF,
3385 static const unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3388 PUSHB_1,
3389 bci_action_adjust_bound_round_serif,
3390 FDEF,
3392 PUSHB_3,
3395 bci_adjust_bound,
3396 CALL,
3398 ENDF,
3404 * bci_adjust
3406 * Handle the ADJUST action to align an edge of a stem if the other edge
3407 * of the stem has already been moved.
3409 * in: edge2_is_serif
3410 * edge_is_round
3411 * edge_point (in twilight zone)
3412 * edge2_point (in twilight zone)
3413 * ... stuff for bci_align_segments (edge) ...
3415 * uses: bci_adjust_common
3416 * bci_align_segments
3419 static const unsigned char FPGM(bci_adjust) [] =
3422 PUSHB_1,
3423 bci_adjust,
3424 FDEF,
3426 PUSHB_1,
3427 bci_adjust_common,
3428 CALL,
3430 MDAP_noround, /* set rp0 and rp1 to `edge' */
3432 PUSHB_2,
3433 bci_align_segments,
3435 SZP1, /* set zp1 to normal zone 1 */
3436 CALL,
3438 ENDF,
3444 * bci_action_adjust
3445 * bci_action_adjust_serif
3446 * bci_action_adjust_round
3447 * bci_action_adjust_round_serif
3449 * Higher-level routines for calling `bci_adjust'.
3452 static const unsigned char FPGM(bci_action_adjust) [] =
3455 PUSHB_1,
3456 bci_action_adjust,
3457 FDEF,
3459 PUSHB_3,
3462 bci_adjust,
3463 CALL,
3465 ENDF,
3469 static const unsigned char FPGM(bci_action_adjust_serif) [] =
3472 PUSHB_1,
3473 bci_action_adjust_serif,
3474 FDEF,
3476 PUSHB_3,
3479 bci_adjust,
3480 CALL,
3482 ENDF,
3486 static const unsigned char FPGM(bci_action_adjust_round) [] =
3489 PUSHB_1,
3490 bci_action_adjust_round,
3491 FDEF,
3493 PUSHB_3,
3496 bci_adjust,
3497 CALL,
3499 ENDF,
3503 static const unsigned char FPGM(bci_action_adjust_round_serif) [] =
3506 PUSHB_1,
3507 bci_action_adjust_round_serif,
3508 FDEF,
3510 PUSHB_3,
3513 bci_adjust,
3514 CALL,
3516 ENDF,
3522 * bci_stem_common
3524 * Common code for bci_action_stem routines.
3526 * sal: sal_anchor
3527 * sal_temp1
3528 * sal_temp2
3529 * sal_temp3
3531 * uses: func[sal_stem_width_function]
3532 * bci_round
3535 #undef sal_u_off
3536 #define sal_u_off sal_temp1
3537 #undef sal_d_off
3538 #define sal_d_off sal_temp2
3539 #undef sal_org_len
3540 #define sal_org_len sal_temp3
3541 #undef sal_edge2
3542 #define sal_edge2 sal_temp3
3544 static const unsigned char FPGM(bci_stem_common) [] =
3547 PUSHB_1,
3548 bci_stem_common,
3549 FDEF,
3551 PUSHB_1,
3553 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3555 PUSHB_1,
3557 CINDEX,
3558 PUSHB_1,
3560 CINDEX,
3561 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3562 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3564 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3565 DUP,
3566 PUSHB_1,
3567 sal_org_len,
3568 SWAP,
3571 PUSHB_1,
3572 sal_stem_width_function,
3574 CALL, /* s: [...] edge2 edge cur_len */
3576 DUP,
3577 PUSHB_1,
3579 LT, /* cur_len < 96 */
3581 DUP,
3582 PUSHB_1,
3584 LTEQ, /* cur_len <= 64 */
3586 PUSHB_4,
3587 sal_u_off,
3589 sal_d_off,
3592 ELSE,
3593 PUSHB_4,
3594 sal_u_off,
3596 sal_d_off,
3598 EIF,
3602 SWAP, /* s: [...] edge2 cur_len edge */
3603 DUP,
3604 PUSHB_1,
3605 sal_anchor,
3607 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3608 ROLL,
3609 SWAP,
3610 MD_orig_ZP2_0,
3611 SWAP,
3612 GC_cur,
3613 ADD, /* s: [...] edge2 cur_len edge org_pos */
3614 PUSHB_1,
3615 sal_org_len,
3617 DIV_BY_2,
3618 ADD, /* s: [...] edge2 cur_len edge org_center */
3620 DUP,
3621 PUSHB_1,
3622 bci_round,
3623 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3625 DUP,
3626 ROLL,
3627 ROLL,
3628 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3630 DUP,
3631 PUSHB_1,
3632 sal_u_off,
3634 ADD,
3635 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3637 SWAP,
3638 PUSHB_1,
3639 sal_d_off,
3641 SUB,
3642 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3644 LT, /* delta1 < delta2 */
3646 PUSHB_1,
3647 sal_u_off,
3649 SUB, /* cur_pos1 = cur_pos1 - u_off */
3651 ELSE,
3652 PUSHB_1,
3653 sal_d_off,
3655 ADD, /* cur_pos1 = cur_pos1 + d_off */
3656 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3658 PUSHB_1,
3660 CINDEX,
3661 DIV_BY_2,
3662 SUB, /* arg = cur_pos1 - cur_len/2 */
3664 SWAP, /* s: [...] edge2 cur_len arg edge */
3665 DUP,
3666 DUP,
3667 PUSHB_1,
3669 MINDEX,
3670 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3671 GC_cur,
3672 SUB,
3673 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3675 ELSE,
3676 SWAP, /* s: [...] edge2 cur_len edge */
3677 PUSHB_1,
3678 sal_anchor,
3680 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3681 PUSHB_1,
3683 CINDEX,
3684 PUSHB_1,
3685 sal_anchor,
3687 MD_orig_ZP2_0,
3688 ADD, /* s: [...] edge2 cur_len edge org_pos */
3690 DUP,
3691 PUSHB_1,
3692 sal_org_len,
3694 DIV_BY_2,
3695 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3697 SWAP,
3698 DUP,
3699 PUSHB_1,
3700 bci_round,
3701 CALL, /* cur_pos1 = ROUND(org_pos) */
3702 SWAP,
3703 PUSHB_1,
3704 sal_org_len,
3706 ADD,
3707 PUSHB_1,
3708 bci_round,
3709 CALL,
3710 PUSHB_1,
3712 CINDEX,
3713 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3715 PUSHB_1,
3717 CINDEX,
3718 DIV_BY_2,
3719 PUSHB_1,
3721 MINDEX,
3722 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3724 DUP,
3725 PUSHB_1,
3727 CINDEX,
3728 ADD,
3729 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3730 SWAP,
3731 PUSHB_1,
3733 CINDEX,
3734 ADD,
3735 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3736 LT, /* delta1 < delta2 */
3738 POP, /* arg = cur_pos1 */
3740 ELSE,
3741 SWAP,
3742 POP, /* arg = cur_pos2 */
3743 EIF, /* s: [...] edge2 cur_len edge arg */
3744 SWAP,
3745 DUP,
3746 DUP,
3747 PUSHB_1,
3749 MINDEX,
3750 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3751 GC_cur,
3752 SUB,
3753 SHPIX, /* edge = arg */
3754 EIF, /* s: [...] edge2 cur_len edge */
3756 ENDF,
3762 * bci_stem_bound
3764 * Handle the STEM action to align two edges of a stem, then moving one
3765 * edge again if necessary to stay bound.
3767 * The code after computing `cur_len' to shift `edge' and `edge2'
3768 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3770 * if cur_len < 96:
3771 * if cur_len < = 64:
3772 * u_off = 32
3773 * d_off = 32
3774 * else:
3775 * u_off = 38
3776 * d_off = 26
3778 * org_pos = anchor + (edge_orig - anchor_orig)
3779 * org_center = org_pos + org_len / 2
3781 * cur_pos1 = ROUND(org_center)
3782 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3783 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3784 * if (delta1 < delta2):
3785 * cur_pos1 = cur_pos1 - u_off
3786 * else:
3787 * cur_pos1 = cur_pos1 + d_off
3789 * edge = cur_pos1 - cur_len / 2
3791 * else:
3792 * org_pos = anchor + (edge_orig - anchor_orig)
3793 * org_center = org_pos + org_len / 2
3795 * cur_pos1 = ROUND(org_pos)
3796 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3797 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3798 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3800 * if (delta1 < delta2):
3801 * edge = cur_pos1
3802 * else:
3803 * edge = cur_pos2
3805 * edge2 = edge + cur_len
3807 * in: edge2_is_serif
3808 * edge_is_round
3809 * edge_point (in twilight zone)
3810 * edge2_point (in twilight zone)
3811 * edge[-1] (in twilight zone)
3812 * ... stuff for bci_align_segments (edge) ...
3813 * ... stuff for bci_align_segments (edge2)...
3815 * sal: sal_anchor
3816 * sal_temp1
3817 * sal_temp2
3818 * sal_temp3
3820 * uses: bci_stem_common
3821 * bci_align_segments
3824 static const unsigned char FPGM(bci_stem_bound) [] =
3827 PUSHB_1,
3828 bci_stem_bound,
3829 FDEF,
3831 PUSHB_1,
3832 bci_stem_common,
3833 CALL,
3835 ROLL, /* s: edge[-1] cur_len edge edge2 */
3836 DUP,
3837 DUP,
3838 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3839 PUSHB_1,
3840 sal_edge2,
3841 SWAP,
3842 WS, /* s: edge[-1] cur_len edge edge2 */
3843 ROLL,
3844 SHPIX, /* edge2 = edge + cur_len */
3846 SWAP, /* s: edge edge[-1] */
3847 DUP,
3848 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3849 GC_cur,
3850 PUSHB_1,
3852 CINDEX,
3853 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3854 GT, /* edge_pos < edge[-1]_pos */
3856 DUP,
3857 ALIGNRP, /* align `edge' to `edge[-1]' */
3858 EIF,
3860 MDAP_noround, /* set rp0 and rp1 to `edge' */
3862 PUSHB_2,
3863 bci_align_segments,
3865 SZP1, /* set zp1 to normal zone 1 */
3866 CALL,
3868 PUSHB_1,
3869 sal_edge2,
3871 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3873 PUSHB_1,
3874 bci_align_segments,
3875 CALL,
3877 ENDF,
3883 * bci_action_stem_bound
3884 * bci_action_stem_bound_serif
3885 * bci_action_stem_bound_round
3886 * bci_action_stem_bound_round_serif
3888 * Higher-level routines for calling `bci_stem_bound'.
3891 static const unsigned char FPGM(bci_action_stem_bound) [] =
3894 PUSHB_1,
3895 bci_action_stem_bound,
3896 FDEF,
3898 PUSHB_3,
3901 bci_stem_bound,
3902 CALL,
3904 ENDF,
3908 static const unsigned char FPGM(bci_action_stem_bound_serif) [] =
3911 PUSHB_1,
3912 bci_action_stem_bound_serif,
3913 FDEF,
3915 PUSHB_3,
3918 bci_stem_bound,
3919 CALL,
3921 ENDF,
3925 static const unsigned char FPGM(bci_action_stem_bound_round) [] =
3928 PUSHB_1,
3929 bci_action_stem_bound_round,
3930 FDEF,
3932 PUSHB_3,
3935 bci_stem_bound,
3936 CALL,
3938 ENDF,
3942 static const unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3945 PUSHB_1,
3946 bci_action_stem_bound_round_serif,
3947 FDEF,
3949 PUSHB_3,
3952 bci_stem_bound,
3953 CALL,
3955 ENDF,
3961 * bci_stem
3963 * Handle the STEM action to align two edges of a stem.
3965 * See `bci_stem_bound' for more details.
3967 * in: edge2_is_serif
3968 * edge_is_round
3969 * edge_point (in twilight zone)
3970 * edge2_point (in twilight zone)
3971 * ... stuff for bci_align_segments (edge) ...
3972 * ... stuff for bci_align_segments (edge2)...
3974 * sal: sal_anchor
3975 * sal_temp1
3976 * sal_temp2
3977 * sal_temp3
3979 * uses: bci_stem_common
3980 * bci_align_segments
3983 static const unsigned char FPGM(bci_stem) [] =
3986 PUSHB_1,
3987 bci_stem,
3988 FDEF,
3990 PUSHB_1,
3991 bci_stem_common,
3992 CALL,
3994 POP,
3995 SWAP, /* s: cur_len edge2 */
3996 DUP,
3997 DUP,
3998 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3999 PUSHB_1,
4000 sal_edge2,
4001 SWAP,
4002 WS, /* s: cur_len edge2 */
4003 SWAP,
4004 SHPIX, /* edge2 = edge + cur_len */
4006 PUSHB_2,
4007 bci_align_segments,
4009 SZP1, /* set zp1 to normal zone 1 */
4010 CALL,
4012 PUSHB_1,
4013 sal_edge2,
4015 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4017 PUSHB_1,
4018 bci_align_segments,
4019 CALL,
4020 ENDF,
4026 * bci_action_stem
4027 * bci_action_stem_serif
4028 * bci_action_stem_round
4029 * bci_action_stem_round_serif
4031 * Higher-level routines for calling `bci_stem'.
4034 static const unsigned char FPGM(bci_action_stem) [] =
4037 PUSHB_1,
4038 bci_action_stem,
4039 FDEF,
4041 PUSHB_3,
4044 bci_stem,
4045 CALL,
4047 ENDF,
4051 static const unsigned char FPGM(bci_action_stem_serif) [] =
4054 PUSHB_1,
4055 bci_action_stem_serif,
4056 FDEF,
4058 PUSHB_3,
4061 bci_stem,
4062 CALL,
4064 ENDF,
4068 static const unsigned char FPGM(bci_action_stem_round) [] =
4071 PUSHB_1,
4072 bci_action_stem_round,
4073 FDEF,
4075 PUSHB_3,
4078 bci_stem,
4079 CALL,
4081 ENDF,
4085 static const unsigned char FPGM(bci_action_stem_round_serif) [] =
4088 PUSHB_1,
4089 bci_action_stem_round_serif,
4090 FDEF,
4092 PUSHB_3,
4095 bci_stem,
4096 CALL,
4098 ENDF,
4104 * bci_link
4106 * Handle the LINK action to link an edge to another one.
4108 * in: stem_is_serif
4109 * base_is_round
4110 * base_point (in twilight zone)
4111 * stem_point (in twilight zone)
4112 * ... stuff for bci_align_segments (base) ...
4114 * uses: func[sal_stem_width_function]
4115 * bci_align_segments
4118 static const unsigned char FPGM(bci_link) [] =
4121 PUSHB_1,
4122 bci_link,
4123 FDEF,
4125 PUSHB_1,
4127 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4129 PUSHB_1,
4131 CINDEX,
4132 PUSHB_1,
4134 MINDEX,
4135 DUP, /* s: stem is_round is_serif stem base base */
4136 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4138 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4140 PUSHB_1,
4141 sal_stem_width_function,
4143 CALL, /* s: stem new_dist */
4145 SWAP,
4146 DUP,
4147 ALIGNRP, /* align `stem_point' with `base_point' */
4148 DUP,
4149 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4150 SWAP,
4151 SHPIX, /* stem_point = base_point + new_dist */
4153 PUSHB_2,
4154 bci_align_segments,
4156 SZP1, /* set zp1 to normal zone 1 */
4157 CALL,
4159 ENDF,
4165 * bci_action_link
4166 * bci_action_link_serif
4167 * bci_action_link_round
4168 * bci_action_link_round_serif
4170 * Higher-level routines for calling `bci_link'.
4173 static const unsigned char FPGM(bci_action_link) [] =
4176 PUSHB_1,
4177 bci_action_link,
4178 FDEF,
4180 PUSHB_3,
4183 bci_link,
4184 CALL,
4186 ENDF,
4190 static const unsigned char FPGM(bci_action_link_serif) [] =
4193 PUSHB_1,
4194 bci_action_link_serif,
4195 FDEF,
4197 PUSHB_3,
4200 bci_link,
4201 CALL,
4203 ENDF,
4207 static const unsigned char FPGM(bci_action_link_round) [] =
4210 PUSHB_1,
4211 bci_action_link_round,
4212 FDEF,
4214 PUSHB_3,
4217 bci_link,
4218 CALL,
4220 ENDF,
4224 static const unsigned char FPGM(bci_action_link_round_serif) [] =
4227 PUSHB_1,
4228 bci_action_link_round_serif,
4229 FDEF,
4231 PUSHB_3,
4234 bci_link,
4235 CALL,
4237 ENDF,
4243 * bci_anchor
4245 * Handle the ANCHOR action to align two edges
4246 * and to set the edge anchor.
4248 * The code after computing `cur_len' to shift `edge' and `edge2'
4249 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4251 * if cur_len < 96:
4252 * if cur_len < = 64:
4253 * u_off = 32
4254 * d_off = 32
4255 * else:
4256 * u_off = 38
4257 * d_off = 26
4259 * org_center = edge_orig + org_len / 2
4260 * cur_pos1 = ROUND(org_center)
4262 * error1 = ABS(org_center - (cur_pos1 - u_off))
4263 * error2 = ABS(org_center - (cur_pos1 + d_off))
4264 * if (error1 < error2):
4265 * cur_pos1 = cur_pos1 - u_off
4266 * else:
4267 * cur_pos1 = cur_pos1 + d_off
4269 * edge = cur_pos1 - cur_len / 2
4270 * edge2 = edge + cur_len
4272 * else:
4273 * edge = ROUND(edge_orig)
4275 * in: edge2_is_serif
4276 * edge_is_round
4277 * edge_point (in twilight zone)
4278 * edge2_point (in twilight zone)
4279 * ... stuff for bci_align_segments (edge) ...
4281 * sal: sal_anchor
4282 * sal_temp1
4283 * sal_temp2
4284 * sal_temp3
4286 * uses: func[sal_stem_width_function]
4287 * bci_round
4288 * bci_align_segments
4291 #undef sal_u_off
4292 #define sal_u_off sal_temp1
4293 #undef sal_d_off
4294 #define sal_d_off sal_temp2
4295 #undef sal_org_len
4296 #define sal_org_len sal_temp3
4298 static const unsigned char FPGM(bci_anchor) [] =
4301 PUSHB_1,
4302 bci_anchor,
4303 FDEF,
4305 /* store anchor point number in `sal_anchor' */
4306 PUSHB_2,
4307 sal_anchor,
4309 CINDEX,
4310 WS, /* sal_anchor = edge_point */
4312 PUSHB_1,
4314 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4316 PUSHB_1,
4318 CINDEX,
4319 PUSHB_1,
4321 CINDEX,
4322 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4323 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4325 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4326 DUP,
4327 PUSHB_1,
4328 sal_org_len,
4329 SWAP,
4332 PUSHB_1,
4333 sal_stem_width_function,
4335 CALL, /* s: edge2 edge cur_len */
4337 DUP,
4338 PUSHB_1,
4340 LT, /* cur_len < 96 */
4342 DUP,
4343 PUSHB_1,
4345 LTEQ, /* cur_len <= 64 */
4347 PUSHB_4,
4348 sal_u_off,
4350 sal_d_off,
4353 ELSE,
4354 PUSHB_4,
4355 sal_u_off,
4357 sal_d_off,
4359 EIF,
4363 SWAP, /* s: edge2 cur_len edge */
4364 DUP, /* s: edge2 cur_len edge edge */
4366 GC_orig,
4367 PUSHB_1,
4368 sal_org_len,
4370 DIV_BY_2,
4371 ADD, /* s: edge2 cur_len edge org_center */
4373 DUP,
4374 PUSHB_1,
4375 bci_round,
4376 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4378 DUP,
4379 ROLL,
4380 ROLL,
4381 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4383 DUP,
4384 PUSHB_1,
4385 sal_u_off,
4387 ADD,
4388 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4390 SWAP,
4391 PUSHB_1,
4392 sal_d_off,
4394 SUB,
4395 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4397 LT, /* error1 < error2 */
4399 PUSHB_1,
4400 sal_u_off,
4402 SUB, /* cur_pos1 = cur_pos1 - u_off */
4404 ELSE,
4405 PUSHB_1,
4406 sal_d_off,
4408 ADD, /* cur_pos1 = cur_pos1 + d_off */
4409 EIF, /* s: edge2 cur_len edge cur_pos1 */
4411 PUSHB_1,
4413 CINDEX,
4414 DIV_BY_2,
4415 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4417 PUSHB_1,
4419 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4420 GC_cur,
4421 SUB,
4422 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4424 SWAP, /* s: cur_len edge2 */
4425 DUP,
4426 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4427 SWAP,
4428 SHPIX, /* edge2 = edge1 + cur_len */
4430 ELSE,
4431 POP, /* s: edge2 edge */
4432 DUP,
4433 DUP,
4434 GC_cur,
4435 SWAP,
4436 GC_orig,
4437 PUSHB_1,
4438 bci_round,
4439 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4440 SWAP,
4441 SUB,
4442 SHPIX, /* edge = round(edge_orig) */
4444 /* clean up stack */
4445 POP,
4446 EIF,
4448 PUSHB_2,
4449 bci_align_segments,
4451 SZP1, /* set zp1 to normal zone 1 */
4452 CALL,
4454 ENDF,
4460 * bci_action_anchor
4461 * bci_action_anchor_serif
4462 * bci_action_anchor_round
4463 * bci_action_anchor_round_serif
4465 * Higher-level routines for calling `bci_anchor'.
4468 static const unsigned char FPGM(bci_action_anchor) [] =
4471 PUSHB_1,
4472 bci_action_anchor,
4473 FDEF,
4475 PUSHB_3,
4478 bci_anchor,
4479 CALL,
4481 ENDF,
4485 static const unsigned char FPGM(bci_action_anchor_serif) [] =
4488 PUSHB_1,
4489 bci_action_anchor_serif,
4490 FDEF,
4492 PUSHB_3,
4495 bci_anchor,
4496 CALL,
4498 ENDF,
4502 static const unsigned char FPGM(bci_action_anchor_round) [] =
4505 PUSHB_1,
4506 bci_action_anchor_round,
4507 FDEF,
4509 PUSHB_3,
4512 bci_anchor,
4513 CALL,
4515 ENDF,
4519 static const unsigned char FPGM(bci_action_anchor_round_serif) [] =
4522 PUSHB_1,
4523 bci_action_anchor_round_serif,
4524 FDEF,
4526 PUSHB_3,
4529 bci_anchor,
4530 CALL,
4532 ENDF,
4538 * bci_action_blue_anchor
4540 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4541 * and to set the edge anchor.
4543 * in: anchor_point (in twilight zone)
4544 * blue_cvt_idx
4545 * edge_point (in twilight zone)
4546 * ... stuff for bci_align_segments (edge) ...
4548 * sal: sal_anchor
4550 * uses: bci_action_blue
4553 static const unsigned char FPGM(bci_action_blue_anchor) [] =
4556 PUSHB_1,
4557 bci_action_blue_anchor,
4558 FDEF,
4560 /* store anchor point number in `sal_anchor' */
4561 PUSHB_1,
4562 sal_anchor,
4563 SWAP,
4566 PUSHB_1,
4567 bci_action_blue,
4568 CALL,
4570 ENDF,
4576 * bci_action_blue
4578 * Handle the BLUE action to align an edge with a blue zone.
4580 * in: blue_cvt_idx
4581 * edge_point (in twilight zone)
4582 * ... stuff for bci_align_segments (edge) ...
4584 * uses: bci_align_segments
4587 static const unsigned char FPGM(bci_action_blue) [] =
4590 PUSHB_1,
4591 bci_action_blue,
4592 FDEF,
4594 PUSHB_1,
4596 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4598 /* move `edge_point' to `blue_cvt_idx' position; */
4599 /* note that we can't use MIAP since this would modify */
4600 /* the twilight point's original coordinates also */
4601 RCVT,
4602 SWAP,
4603 DUP,
4604 MDAP_noround, /* set rp0 and rp1 to `edge' */
4605 DUP,
4606 GC_cur, /* s: new_pos edge edge_pos */
4607 ROLL,
4608 SWAP,
4609 SUB, /* s: edge (new_pos - edge_pos) */
4610 SHPIX,
4612 PUSHB_2,
4613 bci_align_segments,
4615 SZP1, /* set zp1 to normal zone 1 */
4616 CALL,
4618 ENDF,
4624 * bci_serif_common
4626 * Common code for bci_action_serif routines.
4629 static const unsigned char FPGM(bci_serif_common) [] =
4632 PUSHB_1,
4633 bci_serif_common,
4634 FDEF,
4636 PUSHB_1,
4638 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4640 DUP,
4641 DUP,
4642 DUP,
4643 PUSHB_1,
4645 MINDEX, /* s: [...] serif serif serif serif base */
4646 DUP,
4647 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4648 MD_orig_ZP2_0,
4649 SWAP,
4650 ALIGNRP, /* align `serif_point' with `base_point' */
4651 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4653 ENDF,
4659 * bci_lower_bound
4661 * Move an edge if necessary to stay within a lower bound.
4663 * in: edge
4664 * bound
4666 * uses: bci_align_segments
4669 static const unsigned char FPGM(bci_lower_bound) [] =
4672 PUSHB_1,
4673 bci_lower_bound,
4674 FDEF,
4676 SWAP, /* s: edge bound */
4677 DUP,
4678 MDAP_noround, /* set rp0 and rp1 to `bound' */
4679 GC_cur,
4680 PUSHB_1,
4682 CINDEX,
4683 GC_cur, /* s: edge bound_pos edge_pos */
4684 GT, /* edge_pos < bound_pos */
4686 DUP,
4687 ALIGNRP, /* align `edge' to `bound' */
4688 EIF,
4690 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4692 PUSHB_2,
4693 bci_align_segments,
4695 SZP1, /* set zp1 to normal zone 1 */
4696 CALL,
4698 ENDF,
4704 * bci_upper_bound
4706 * Move an edge if necessary to stay within an upper bound.
4708 * in: edge
4709 * bound
4711 * uses: bci_align_segments
4714 static const unsigned char FPGM(bci_upper_bound) [] =
4717 PUSHB_1,
4718 bci_upper_bound,
4719 FDEF,
4721 SWAP, /* s: edge bound */
4722 DUP,
4723 MDAP_noround, /* set rp0 and rp1 to `bound' */
4724 GC_cur,
4725 PUSHB_1,
4727 CINDEX,
4728 GC_cur, /* s: edge bound_pos edge_pos */
4729 LT, /* edge_pos > bound_pos */
4731 DUP,
4732 ALIGNRP, /* align `edge' to `bound' */
4733 EIF,
4735 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4737 PUSHB_2,
4738 bci_align_segments,
4740 SZP1, /* set zp1 to normal zone 1 */
4741 CALL,
4743 ENDF,
4749 * bci_upper_lower_bound
4751 * Move an edge if necessary to stay within a lower and lower bound.
4753 * in: edge
4754 * lower
4755 * upper
4757 * uses: bci_align_segments
4760 static const unsigned char FPGM(bci_upper_lower_bound) [] =
4763 PUSHB_1,
4764 bci_upper_lower_bound,
4765 FDEF,
4767 SWAP, /* s: upper serif lower */
4768 DUP,
4769 MDAP_noround, /* set rp0 and rp1 to `lower' */
4770 GC_cur,
4771 PUSHB_1,
4773 CINDEX,
4774 GC_cur, /* s: upper serif lower_pos serif_pos */
4775 GT, /* serif_pos < lower_pos */
4777 DUP,
4778 ALIGNRP, /* align `serif' to `lower' */
4779 EIF,
4781 SWAP, /* s: serif upper */
4782 DUP,
4783 MDAP_noround, /* set rp0 and rp1 to `upper' */
4784 GC_cur,
4785 PUSHB_1,
4787 CINDEX,
4788 GC_cur, /* s: serif upper_pos serif_pos */
4789 LT, /* serif_pos > upper_pos */
4791 DUP,
4792 ALIGNRP, /* align `serif' to `upper' */
4793 EIF,
4795 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4797 PUSHB_2,
4798 bci_align_segments,
4800 SZP1, /* set zp1 to normal zone 1 */
4801 CALL,
4803 ENDF,
4809 * bci_action_serif
4811 * Handle the SERIF action to align a serif with its base.
4813 * in: serif_point (in twilight zone)
4814 * base_point (in twilight zone)
4815 * ... stuff for bci_align_segments (serif) ...
4817 * uses: bci_serif_common
4818 * bci_align_segments
4821 static const unsigned char FPGM(bci_action_serif) [] =
4824 PUSHB_1,
4825 bci_action_serif,
4826 FDEF,
4828 PUSHB_1,
4829 bci_serif_common,
4830 CALL,
4832 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4834 PUSHB_2,
4835 bci_align_segments,
4837 SZP1, /* set zp1 to normal zone 1 */
4838 CALL,
4840 ENDF,
4846 * bci_action_serif_lower_bound
4848 * Handle the SERIF action to align a serif with its base, then moving it
4849 * again if necessary to stay within a lower bound.
4851 * in: serif_point (in twilight zone)
4852 * base_point (in twilight zone)
4853 * edge[-1] (in twilight zone)
4854 * ... stuff for bci_align_segments (serif) ...
4856 * uses: bci_serif_common
4857 * bci_lower_bound
4860 static const unsigned char FPGM(bci_action_serif_lower_bound) [] =
4863 PUSHB_1,
4864 bci_action_serif_lower_bound,
4865 FDEF,
4867 PUSHB_1,
4868 bci_serif_common,
4869 CALL,
4871 PUSHB_1,
4872 bci_lower_bound,
4873 CALL,
4875 ENDF,
4881 * bci_action_serif_upper_bound
4883 * Handle the SERIF action to align a serif with its base, then moving it
4884 * again if necessary to stay within an upper bound.
4886 * in: serif_point (in twilight zone)
4887 * base_point (in twilight zone)
4888 * edge[1] (in twilight zone)
4889 * ... stuff for bci_align_segments (serif) ...
4891 * uses: bci_serif_common
4892 * bci_upper_bound
4895 static const unsigned char FPGM(bci_action_serif_upper_bound) [] =
4898 PUSHB_1,
4899 bci_action_serif_upper_bound,
4900 FDEF,
4902 PUSHB_1,
4903 bci_serif_common,
4904 CALL,
4906 PUSHB_1,
4907 bci_upper_bound,
4908 CALL,
4910 ENDF,
4916 * bci_action_serif_upper_lower_bound
4918 * Handle the SERIF action to align a serif with its base, then moving it
4919 * again if necessary to stay within a lower and upper bound.
4921 * in: serif_point (in twilight zone)
4922 * base_point (in twilight zone)
4923 * edge[-1] (in twilight zone)
4924 * edge[1] (in twilight zone)
4925 * ... stuff for bci_align_segments (serif) ...
4927 * uses: bci_serif_common
4928 * bci_upper_lower_bound
4931 static const unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4934 PUSHB_1,
4935 bci_action_serif_upper_lower_bound,
4936 FDEF,
4938 PUSHB_1,
4940 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4942 PUSHB_1,
4943 bci_serif_common,
4944 CALL,
4946 PUSHB_1,
4947 bci_upper_lower_bound,
4948 CALL,
4950 ENDF,
4956 * bci_serif_anchor_common
4958 * Common code for bci_action_serif_anchor routines.
4960 * sal: sal_anchor
4962 * uses: bci_round
4965 static const unsigned char FPGM(bci_serif_anchor_common) [] =
4968 PUSHB_1,
4969 bci_serif_anchor_common,
4970 FDEF,
4972 PUSHB_1,
4974 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4976 DUP,
4977 PUSHB_1,
4978 sal_anchor,
4979 SWAP,
4980 WS, /* sal_anchor = edge_point */
4982 DUP,
4983 DUP,
4984 DUP,
4985 GC_cur,
4986 SWAP,
4987 GC_orig,
4988 PUSHB_1,
4989 bci_round,
4990 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4991 SWAP,
4992 SUB,
4993 SHPIX, /* edge = round(edge_orig) */
4995 ENDF,
5001 * bci_action_serif_anchor
5003 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5004 * anchor.
5006 * in: edge_point (in twilight zone)
5007 * ... stuff for bci_align_segments (edge) ...
5009 * uses: bci_serif_anchor_common
5010 * bci_align_segments
5013 static const unsigned char FPGM(bci_action_serif_anchor) [] =
5016 PUSHB_1,
5017 bci_action_serif_anchor,
5018 FDEF,
5020 PUSHB_1,
5021 bci_serif_anchor_common,
5022 CALL,
5024 MDAP_noround, /* set rp0 and rp1 to `edge' */
5026 PUSHB_2,
5027 bci_align_segments,
5029 SZP1, /* set zp1 to normal zone 1 */
5030 CALL,
5032 ENDF,
5038 * bci_action_serif_anchor_lower_bound
5040 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5041 * anchor, then moving it again if necessary to stay within a lower
5042 * bound.
5044 * in: edge_point (in twilight zone)
5045 * edge[-1] (in twilight zone)
5046 * ... stuff for bci_align_segments (edge) ...
5048 * uses: bci_serif_anchor_common
5049 * bci_lower_bound
5052 static const unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
5055 PUSHB_1,
5056 bci_action_serif_anchor_lower_bound,
5057 FDEF,
5059 PUSHB_1,
5060 bci_serif_anchor_common,
5061 CALL,
5063 PUSHB_1,
5064 bci_lower_bound,
5065 CALL,
5067 ENDF,
5073 * bci_action_serif_anchor_upper_bound
5075 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5076 * anchor, then moving it again if necessary to stay within an upper
5077 * bound.
5079 * in: edge_point (in twilight zone)
5080 * edge[1] (in twilight zone)
5081 * ... stuff for bci_align_segments (edge) ...
5083 * uses: bci_serif_anchor_common
5084 * bci_upper_bound
5087 static const unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5090 PUSHB_1,
5091 bci_action_serif_anchor_upper_bound,
5092 FDEF,
5094 PUSHB_1,
5095 bci_serif_anchor_common,
5096 CALL,
5098 PUSHB_1,
5099 bci_upper_bound,
5100 CALL,
5102 ENDF,
5108 * bci_action_serif_anchor_upper_lower_bound
5110 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5111 * anchor, then moving it again if necessary to stay within a lower and
5112 * upper bound.
5114 * in: edge_point (in twilight zone)
5115 * edge[-1] (in twilight zone)
5116 * edge[1] (in twilight zone)
5117 * ... stuff for bci_align_segments (edge) ...
5119 * uses: bci_serif_anchor_common
5120 * bci_upper_lower_bound
5123 static const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5126 PUSHB_1,
5127 bci_action_serif_anchor_upper_lower_bound,
5128 FDEF,
5130 PUSHB_1,
5131 bci_serif_anchor_common,
5132 CALL,
5134 PUSHB_1,
5135 bci_upper_lower_bound,
5136 CALL,
5138 ENDF,
5144 * bci_serif_link1_common
5146 * Common code for bci_action_serif_link1 routines.
5149 static const unsigned char FPGM(bci_serif_link1_common) [] =
5152 PUSHB_1,
5153 bci_serif_link1_common,
5154 FDEF,
5156 PUSHB_1,
5158 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5160 PUSHB_1,
5162 CINDEX, /* s: [...] after edge before after */
5163 PUSHB_1,
5165 CINDEX, /* s: [...] after edge before after before */
5166 MD_orig_ZP2_0,
5167 PUSHB_1,
5169 EQ, /* after_orig_pos == before_orig_pos */
5170 IF, /* s: [...] after edge before */
5171 MDAP_noround, /* set rp0 and rp1 to `before' */
5172 DUP,
5173 ALIGNRP, /* align `edge' with `before' */
5174 SWAP,
5175 POP,
5177 ELSE,
5178 /* we have to execute `a*b/c', with b/c very near to 1: */
5179 /* to avoid overflow while retaining precision, */
5180 /* we transform this to `a + a * (b-c)/c' */
5182 PUSHB_1,
5184 CINDEX, /* s: [...] after edge before edge */
5185 PUSHB_1,
5187 CINDEX, /* s: [...] after edge before edge before */
5188 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
5190 DUP,
5191 PUSHB_1,
5193 CINDEX, /* s: [...] after edge before a a after */
5194 PUSHB_1,
5196 CINDEX, /* s: [...] after edge before a a after before */
5197 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
5199 PUSHB_1,
5201 CINDEX, /* s: [...] after edge before a a c after */
5202 PUSHB_1,
5204 CINDEX, /* s: [...] after edge before a a c after before */
5205 MD_cur, /* b = after_pos - before_pos */
5207 PUSHB_1,
5209 CINDEX, /* s: [...] after edge before a a c b c */
5210 SUB, /* b-c */
5212 PUSHW_2,
5213 0x08, /* 0x800 */
5214 0x00,
5215 0x08, /* 0x800 */
5216 0x00,
5217 MUL, /* 0x10000 */
5218 MUL, /* (b-c) in 16.16 format */
5219 SWAP,
5221 DUP,
5222 IF, /* c != 0 ? */
5223 DIV, /* s: [...] after edge before a a (b-c)/c */
5224 ELSE,
5225 POP, /* avoid division by zero */
5226 EIF,
5228 MUL, /* a * (b-c)/c * 2^10 */
5229 DIV_BY_1024, /* a * (b-c)/c */
5230 ADD, /* a*b/c */
5232 SWAP,
5233 MDAP_noround, /* set rp0 and rp1 to `before' */
5234 SWAP, /* s: [...] after a*b/c edge */
5235 DUP,
5236 DUP,
5237 ALIGNRP, /* align `edge' with `before' */
5238 ROLL,
5239 SHPIX, /* shift `edge' by `a*b/c' */
5241 SWAP, /* s: [...] edge after */
5242 POP,
5243 EIF,
5245 ENDF,
5251 * bci_action_serif_link1
5253 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5254 * before and after.
5256 * in: before_point (in twilight zone)
5257 * edge_point (in twilight zone)
5258 * after_point (in twilight zone)
5259 * ... stuff for bci_align_segments (edge) ...
5261 * uses: bci_serif_link1_common
5262 * bci_align_segments
5265 static const unsigned char FPGM(bci_action_serif_link1) [] =
5268 PUSHB_1,
5269 bci_action_serif_link1,
5270 FDEF,
5272 PUSHB_1,
5273 bci_serif_link1_common,
5274 CALL,
5276 MDAP_noround, /* set rp0 and rp1 to `edge' */
5278 PUSHB_2,
5279 bci_align_segments,
5281 SZP1, /* set zp1 to normal zone 1 */
5282 CALL,
5284 ENDF,
5290 * bci_action_serif_link1_lower_bound
5292 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5293 * before and after. Additionally, move the serif again if necessary to
5294 * stay within a lower bound.
5296 * in: before_point (in twilight zone)
5297 * edge_point (in twilight zone)
5298 * after_point (in twilight zone)
5299 * edge[-1] (in twilight zone)
5300 * ... stuff for bci_align_segments (edge) ...
5302 * uses: bci_serif_link1_common
5303 * bci_lower_bound
5306 static const unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
5309 PUSHB_1,
5310 bci_action_serif_link1_lower_bound,
5311 FDEF,
5313 PUSHB_1,
5314 bci_serif_link1_common,
5315 CALL,
5317 PUSHB_1,
5318 bci_lower_bound,
5319 CALL,
5321 ENDF,
5327 * bci_action_serif_link1_upper_bound
5329 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5330 * before and after. Additionally, move the serif again if necessary to
5331 * stay within an upper bound.
5333 * in: before_point (in twilight zone)
5334 * edge_point (in twilight zone)
5335 * after_point (in twilight zone)
5336 * edge[1] (in twilight zone)
5337 * ... stuff for bci_align_segments (edge) ...
5339 * uses: bci_serif_link1_common
5340 * bci_upper_bound
5343 static const unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
5346 PUSHB_1,
5347 bci_action_serif_link1_upper_bound,
5348 FDEF,
5350 PUSHB_1,
5351 bci_serif_link1_common,
5352 CALL,
5354 PUSHB_1,
5355 bci_upper_bound,
5356 CALL,
5358 ENDF,
5364 * bci_action_serif_link1_upper_lower_bound
5366 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5367 * before and after. Additionally, move the serif again if necessary to
5368 * stay within a lower and upper bound.
5370 * in: before_point (in twilight zone)
5371 * edge_point (in twilight zone)
5372 * after_point (in twilight zone)
5373 * edge[-1] (in twilight zone)
5374 * edge[1] (in twilight zone)
5375 * ... stuff for bci_align_segments (edge) ...
5377 * uses: bci_serif_link1_common
5378 * bci_upper_lower_bound
5381 static const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
5384 PUSHB_1,
5385 bci_action_serif_link1_upper_lower_bound,
5386 FDEF,
5388 PUSHB_1,
5389 bci_serif_link1_common,
5390 CALL,
5392 PUSHB_1,
5393 bci_upper_lower_bound,
5394 CALL,
5396 ENDF,
5402 * bci_serif_link2_common
5404 * Common code for bci_action_serif_link2 routines.
5406 * sal: sal_anchor
5409 static const unsigned char FPGM(bci_serif_link2_common) [] =
5412 PUSHB_1,
5413 bci_serif_link2_common,
5414 FDEF,
5416 PUSHB_1,
5418 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5420 DUP, /* s: [...] edge edge */
5421 PUSHB_1,
5422 sal_anchor,
5424 DUP, /* s: [...] edge edge anchor anchor */
5425 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
5427 MD_orig_ZP2_0,
5428 DUP,
5429 ADD,
5430 PUSHB_1,
5432 ADD,
5433 FLOOR,
5434 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5436 SWAP,
5437 DUP,
5438 DUP,
5439 ALIGNRP, /* align `edge' with `sal_anchor' */
5440 ROLL,
5441 SHPIX, /* shift `edge' by `delta' */
5443 ENDF,
5449 * bci_action_serif_link2
5451 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5453 * in: edge_point (in twilight zone)
5454 * ... stuff for bci_align_segments (edge) ...
5456 * uses: bci_serif_link2_common
5457 * bci_align_segments
5460 static const unsigned char FPGM(bci_action_serif_link2) [] =
5463 PUSHB_1,
5464 bci_action_serif_link2,
5465 FDEF,
5467 PUSHB_1,
5468 bci_serif_link2_common,
5469 CALL,
5471 MDAP_noround, /* set rp0 and rp1 to `edge' */
5473 PUSHB_2,
5474 bci_align_segments,
5476 SZP1, /* set zp1 to normal zone 1 */
5477 CALL,
5479 ENDF,
5485 * bci_action_serif_link2_lower_bound
5487 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5488 * Additionally, move the serif again if necessary to stay within a lower
5489 * bound.
5491 * in: edge_point (in twilight zone)
5492 * edge[-1] (in twilight zone)
5493 * ... stuff for bci_align_segments (edge) ...
5495 * uses: bci_serif_link2_common
5496 * bci_lower_bound
5499 static const unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
5502 PUSHB_1,
5503 bci_action_serif_link2_lower_bound,
5504 FDEF,
5506 PUSHB_1,
5507 bci_serif_link2_common,
5508 CALL,
5510 PUSHB_1,
5511 bci_lower_bound,
5512 CALL,
5514 ENDF,
5520 * bci_action_serif_link2_upper_bound
5522 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5523 * Additionally, move the serif again if necessary to stay within an upper
5524 * bound.
5526 * in: edge_point (in twilight zone)
5527 * edge[1] (in twilight zone)
5528 * ... stuff for bci_align_segments (edge) ...
5530 * uses: bci_serif_link2_common
5531 * bci_upper_bound
5534 static const unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
5537 PUSHB_1,
5538 bci_action_serif_link2_upper_bound,
5539 FDEF,
5541 PUSHB_1,
5542 bci_serif_link2_common,
5543 CALL,
5545 PUSHB_1,
5546 bci_upper_bound,
5547 CALL,
5549 ENDF,
5555 * bci_action_serif_link2_upper_lower_bound
5557 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5558 * Additionally, move the serif again if necessary to stay within a lower
5559 * and upper bound.
5561 * in: edge_point (in twilight zone)
5562 * edge[-1] (in twilight zone)
5563 * edge[1] (in twilight zone)
5564 * ... stuff for bci_align_segments (edge) ...
5566 * uses: bci_serif_link2_common
5567 * bci_upper_lower_bound
5570 static const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
5573 PUSHB_1,
5574 bci_action_serif_link2_upper_lower_bound,
5575 FDEF,
5577 PUSHB_1,
5578 bci_serif_link2_common,
5579 CALL,
5581 PUSHB_1,
5582 bci_upper_lower_bound,
5583 CALL,
5585 ENDF,
5591 * bci_hint_glyph
5593 * This is the top-level glyph hinting function which parses the arguments
5594 * on the stack and calls subroutines.
5596 * in: action_0_func_idx
5597 * ... data ...
5598 * action_1_func_idx
5599 * ... data ...
5600 * ...
5602 * CVT: cvtl_is_subglyph
5603 * cvtl_use_strong_functions
5604 * cvtl_do_iup_y
5606 * sal: sal_stem_width_function
5608 * uses: bci_action_ip_before
5609 * bci_action_ip_after
5610 * bci_action_ip_on
5611 * bci_action_ip_between
5613 * bci_action_adjust_bound
5614 * bci_action_adjust_bound_serif
5615 * bci_action_adjust_bound_round
5616 * bci_action_adjust_bound_round_serif
5618 * bci_action_stem_bound
5619 * bci_action_stem_bound_serif
5620 * bci_action_stem_bound_round
5621 * bci_action_stem_bound_round_serif
5623 * bci_action_link
5624 * bci_action_link_serif
5625 * bci_action_link_round
5626 * bci_action_link_round_serif
5628 * bci_action_anchor
5629 * bci_action_anchor_serif
5630 * bci_action_anchor_round
5631 * bci_action_anchor_round_serif
5633 * bci_action_blue_anchor
5635 * bci_action_adjust
5636 * bci_action_adjust_serif
5637 * bci_action_adjust_round
5638 * bci_action_adjust_round_serif
5640 * bci_action_stem
5641 * bci_action_stem_serif
5642 * bci_action_stem_round
5643 * bci_action_stem_round_serif
5645 * bci_action_blue
5647 * bci_action_serif
5648 * bci_action_serif_lower_bound
5649 * bci_action_serif_upper_bound
5650 * bci_action_serif_upper_lower_bound
5652 * bci_action_serif_anchor
5653 * bci_action_serif_anchor_lower_bound
5654 * bci_action_serif_anchor_upper_bound
5655 * bci_action_serif_anchor_upper_lower_bound
5657 * bci_action_serif_link1
5658 * bci_action_serif_link1_lower_bound
5659 * bci_action_serif_link1_upper_bound
5660 * bci_action_serif_link1_upper_lower_bound
5662 * bci_action_serif_link2
5663 * bci_action_serif_link2_lower_bound
5664 * bci_action_serif_link2_upper_bound
5665 * bci_action_serif_link2_upper_lower_bound
5668 static const unsigned char FPGM(bci_hint_glyph) [] =
5671 PUSHB_1,
5672 bci_hint_glyph,
5673 FDEF,
5675 /* set up stem width function based on flag in CVT */
5676 PUSHB_4,
5677 sal_stem_width_function,
5678 bci_strong_stem_width,
5679 bci_smooth_stem_width,
5680 cvtl_use_strong_functions,
5681 RCVT,
5683 POP,
5685 ELSE,
5686 SWAP,
5687 POP,
5689 EIF,
5692 /* start_loop: */
5693 /* loop until all data on stack is used */
5694 CALL,
5695 PUSHB_1,
5697 NEG,
5698 PUSHB_1,
5700 DEPTH,
5702 JROT, /* goto start_loop */
5704 PUSHB_2,
5705 cvtl_do_iup_y,
5707 SZP2, /* set zp2 to normal zone 1 */
5708 RCVT,
5710 IUP_y,
5711 EIF,
5713 ENDF,
5718 #define COPY_FPGM(func_name) \
5719 do \
5721 memcpy(bufp, fpgm_ ## func_name, \
5722 sizeof (fpgm_ ## func_name)); \
5723 bufp += sizeof (fpgm_ ## func_name); \
5724 } while (0)
5726 static FT_Error
5727 TA_table_build_fpgm(FT_Byte** fpgm,
5728 FT_ULong* fpgm_len,
5729 SFNT* sfnt,
5730 FONT* font)
5732 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5733 glyf_Data* data = (glyf_Data*)glyf_table->data;
5735 FT_UInt buf_len;
5736 FT_UInt len;
5737 FT_Byte* buf;
5738 FT_Byte* bufp;
5741 /* for compatibility with dumb bytecode interpreters or analyzers, */
5742 /* FDEFs are stored in ascending index order, without holes -- */
5743 /* note that some FDEFs are not always needed */
5744 /* (depending on options of `TTFautohint'), */
5745 /* but implementing dynamic FDEF indices would be a lot of work */
5747 buf_len = sizeof (FPGM(bci_align_top_a))
5748 + (font->increase_x_height
5749 ? (sizeof (FPGM(bci_align_top_b1a))
5751 + sizeof (FPGM(bci_align_top_b1b)))
5752 : sizeof (FPGM(bci_align_top_b2)))
5753 + sizeof (FPGM(bci_align_top_c))
5754 + sizeof (FPGM(bci_round))
5755 + sizeof (FPGM(bci_smooth_stem_width))
5756 + sizeof (FPGM(bci_get_best_width))
5757 + sizeof (FPGM(bci_strong_stem_width_a))
5759 + sizeof (FPGM(bci_strong_stem_width_b))
5760 + sizeof (FPGM(bci_loop_do))
5761 + sizeof (FPGM(bci_loop))
5762 + sizeof (FPGM(bci_cvt_rescale))
5763 + sizeof (FPGM(bci_cvt_rescale_range))
5764 + sizeof (FPGM(bci_vwidth_data_store))
5765 + sizeof (FPGM(bci_smooth_blue_round))
5766 + sizeof (FPGM(bci_strong_blue_round))
5767 + sizeof (FPGM(bci_blue_round_range))
5768 + sizeof (FPGM(bci_decrement_component_counter))
5769 + sizeof (FPGM(bci_get_point_extrema))
5770 + sizeof (FPGM(bci_nibbles))
5771 + sizeof (FPGM(bci_number_set_is_element))
5772 + sizeof (FPGM(bci_number_set_is_element2))
5774 + sizeof (FPGM(bci_create_segment))
5775 + sizeof (FPGM(bci_create_segments_a))
5777 + sizeof (FPGM(bci_create_segments_b))
5778 + (font->control_data_head != 0
5779 ? sizeof (FPGM(bci_create_segments_c))
5780 : 0)
5781 + sizeof (FPGM(bci_create_segments_d))
5783 + sizeof (FPGM(bci_create_segments_0))
5784 + sizeof (FPGM(bci_create_segments_1))
5785 + sizeof (FPGM(bci_create_segments_2))
5786 + sizeof (FPGM(bci_create_segments_3))
5787 + sizeof (FPGM(bci_create_segments_4))
5788 + sizeof (FPGM(bci_create_segments_5))
5789 + sizeof (FPGM(bci_create_segments_6))
5790 + sizeof (FPGM(bci_create_segments_7))
5791 + sizeof (FPGM(bci_create_segments_8))
5792 + sizeof (FPGM(bci_create_segments_9))
5794 + sizeof (FPGM(bci_deltap1))
5795 + sizeof (FPGM(bci_deltap2))
5796 + sizeof (FPGM(bci_deltap3))
5798 + sizeof (FPGM(bci_create_segments_composite_a))
5800 + sizeof (FPGM(bci_create_segments_composite_b))
5801 + (font->control_data_head != 0
5802 ? sizeof (FPGM(bci_create_segments_composite_c))
5803 : 0)
5804 + sizeof (FPGM(bci_create_segments_composite_d))
5806 + sizeof (FPGM(bci_create_segments_composite_0))
5807 + sizeof (FPGM(bci_create_segments_composite_1))
5808 + sizeof (FPGM(bci_create_segments_composite_2))
5809 + sizeof (FPGM(bci_create_segments_composite_3))
5810 + sizeof (FPGM(bci_create_segments_composite_4))
5811 + sizeof (FPGM(bci_create_segments_composite_5))
5812 + sizeof (FPGM(bci_create_segments_composite_6))
5813 + sizeof (FPGM(bci_create_segments_composite_7))
5814 + sizeof (FPGM(bci_create_segments_composite_8))
5815 + sizeof (FPGM(bci_create_segments_composite_9))
5817 + sizeof (FPGM(bci_align_point))
5818 + sizeof (FPGM(bci_align_segment))
5819 + sizeof (FPGM(bci_align_segments))
5821 + sizeof (FPGM(bci_scale_contour))
5822 + sizeof (FPGM(bci_scale_glyph))
5823 + sizeof (FPGM(bci_scale_composite_glyph))
5824 + sizeof (FPGM(bci_shift_contour))
5825 + sizeof (FPGM(bci_shift_subglyph_a))
5826 + (font->control_data_head != 0
5827 ? sizeof (FPGM(bci_shift_subglyph_b))
5828 : 0)
5829 + sizeof (FPGM(bci_shift_subglyph_c))
5831 + sizeof (FPGM(bci_ip_outer_align_point))
5832 + sizeof (FPGM(bci_ip_on_align_points))
5833 + sizeof (FPGM(bci_ip_between_align_point))
5834 + sizeof (FPGM(bci_ip_between_align_points))
5836 + sizeof (FPGM(bci_adjust_common))
5837 + sizeof (FPGM(bci_stem_common))
5838 + sizeof (FPGM(bci_serif_common))
5839 + sizeof (FPGM(bci_serif_anchor_common))
5840 + sizeof (FPGM(bci_serif_link1_common))
5841 + sizeof (FPGM(bci_serif_link2_common))
5843 + sizeof (FPGM(bci_lower_bound))
5844 + sizeof (FPGM(bci_upper_bound))
5845 + sizeof (FPGM(bci_upper_lower_bound))
5847 + sizeof (FPGM(bci_adjust_bound))
5848 + sizeof (FPGM(bci_stem_bound))
5849 + sizeof (FPGM(bci_link))
5850 + sizeof (FPGM(bci_anchor))
5851 + sizeof (FPGM(bci_adjust))
5852 + sizeof (FPGM(bci_stem))
5854 + sizeof (FPGM(bci_action_ip_before))
5855 + sizeof (FPGM(bci_action_ip_after))
5856 + sizeof (FPGM(bci_action_ip_on))
5857 + sizeof (FPGM(bci_action_ip_between))
5859 + sizeof (FPGM(bci_action_blue))
5860 + sizeof (FPGM(bci_action_blue_anchor))
5862 + sizeof (FPGM(bci_action_anchor))
5863 + sizeof (FPGM(bci_action_anchor_serif))
5864 + sizeof (FPGM(bci_action_anchor_round))
5865 + sizeof (FPGM(bci_action_anchor_round_serif))
5867 + sizeof (FPGM(bci_action_adjust))
5868 + sizeof (FPGM(bci_action_adjust_serif))
5869 + sizeof (FPGM(bci_action_adjust_round))
5870 + sizeof (FPGM(bci_action_adjust_round_serif))
5871 + sizeof (FPGM(bci_action_adjust_bound))
5872 + sizeof (FPGM(bci_action_adjust_bound_serif))
5873 + sizeof (FPGM(bci_action_adjust_bound_round))
5874 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5876 + sizeof (FPGM(bci_action_link))
5877 + sizeof (FPGM(bci_action_link_serif))
5878 + sizeof (FPGM(bci_action_link_round))
5879 + sizeof (FPGM(bci_action_link_round_serif))
5881 + sizeof (FPGM(bci_action_stem))
5882 + sizeof (FPGM(bci_action_stem_serif))
5883 + sizeof (FPGM(bci_action_stem_round))
5884 + sizeof (FPGM(bci_action_stem_round_serif))
5885 + sizeof (FPGM(bci_action_stem_bound))
5886 + sizeof (FPGM(bci_action_stem_bound_serif))
5887 + sizeof (FPGM(bci_action_stem_bound_round))
5888 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5890 + sizeof (FPGM(bci_action_serif))
5891 + sizeof (FPGM(bci_action_serif_lower_bound))
5892 + sizeof (FPGM(bci_action_serif_upper_bound))
5893 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5895 + sizeof (FPGM(bci_action_serif_anchor))
5896 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5897 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5898 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5900 + sizeof (FPGM(bci_action_serif_link1))
5901 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5902 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5903 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5905 + sizeof (FPGM(bci_action_serif_link2))
5906 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5907 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5908 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5910 + sizeof (FPGM(bci_hint_glyph));
5912 /* buffer length must be a multiple of four */
5913 len = (buf_len + 3) & ~3;
5914 buf = (FT_Byte*)malloc(len);
5915 if (!buf)
5916 return FT_Err_Out_Of_Memory;
5918 /* pad end of buffer with zeros */
5919 buf[len - 1] = 0x00;
5920 buf[len - 2] = 0x00;
5921 buf[len - 3] = 0x00;
5923 /* copy font program into buffer and fill in the missing variables */
5924 bufp = buf;
5926 COPY_FPGM(bci_align_top_a);
5927 if (font->increase_x_height)
5929 COPY_FPGM(bci_align_top_b1a);
5930 *(bufp++) = HIGH(font->increase_x_height);
5931 *(bufp++) = LOW(font->increase_x_height);
5932 COPY_FPGM(bci_align_top_b1b);
5934 else
5935 COPY_FPGM(bci_align_top_b2);
5936 COPY_FPGM(bci_align_top_c);
5938 COPY_FPGM(bci_round);
5939 COPY_FPGM(bci_smooth_stem_width);
5940 COPY_FPGM(bci_get_best_width);
5941 COPY_FPGM(bci_strong_stem_width_a);
5942 *(bufp++) = (unsigned char)data->num_used_styles;
5943 COPY_FPGM(bci_strong_stem_width_b);
5944 COPY_FPGM(bci_loop_do);
5945 COPY_FPGM(bci_loop);
5946 COPY_FPGM(bci_cvt_rescale);
5947 COPY_FPGM(bci_cvt_rescale_range);
5948 COPY_FPGM(bci_vwidth_data_store);
5949 COPY_FPGM(bci_smooth_blue_round);
5950 COPY_FPGM(bci_strong_blue_round);
5951 COPY_FPGM(bci_blue_round_range);
5952 COPY_FPGM(bci_decrement_component_counter);
5953 COPY_FPGM(bci_get_point_extrema);
5954 COPY_FPGM(bci_nibbles);
5955 COPY_FPGM(bci_number_set_is_element);
5956 COPY_FPGM(bci_number_set_is_element2);
5958 COPY_FPGM(bci_create_segment);
5959 COPY_FPGM(bci_create_segments_a);
5960 *(bufp++) = (unsigned char)data->num_used_styles;
5961 COPY_FPGM(bci_create_segments_b);
5962 if (font->control_data_head)
5963 COPY_FPGM(bci_create_segments_c);
5964 COPY_FPGM(bci_create_segments_d);
5966 COPY_FPGM(bci_create_segments_0);
5967 COPY_FPGM(bci_create_segments_1);
5968 COPY_FPGM(bci_create_segments_2);
5969 COPY_FPGM(bci_create_segments_3);
5970 COPY_FPGM(bci_create_segments_4);
5971 COPY_FPGM(bci_create_segments_5);
5972 COPY_FPGM(bci_create_segments_6);
5973 COPY_FPGM(bci_create_segments_7);
5974 COPY_FPGM(bci_create_segments_8);
5975 COPY_FPGM(bci_create_segments_9);
5977 COPY_FPGM(bci_deltap1);
5978 COPY_FPGM(bci_deltap2);
5979 COPY_FPGM(bci_deltap3);
5981 COPY_FPGM(bci_create_segments_composite_a);
5982 *(bufp++) = (unsigned char)data->num_used_styles;
5983 COPY_FPGM(bci_create_segments_composite_b);
5984 if (font->control_data_head)
5985 COPY_FPGM(bci_create_segments_composite_c);
5986 COPY_FPGM(bci_create_segments_composite_d);
5988 COPY_FPGM(bci_create_segments_composite_0);
5989 COPY_FPGM(bci_create_segments_composite_1);
5990 COPY_FPGM(bci_create_segments_composite_2);
5991 COPY_FPGM(bci_create_segments_composite_3);
5992 COPY_FPGM(bci_create_segments_composite_4);
5993 COPY_FPGM(bci_create_segments_composite_5);
5994 COPY_FPGM(bci_create_segments_composite_6);
5995 COPY_FPGM(bci_create_segments_composite_7);
5996 COPY_FPGM(bci_create_segments_composite_8);
5997 COPY_FPGM(bci_create_segments_composite_9);
5999 COPY_FPGM(bci_align_point);
6000 COPY_FPGM(bci_align_segment);
6001 COPY_FPGM(bci_align_segments);
6003 COPY_FPGM(bci_scale_contour);
6004 COPY_FPGM(bci_scale_glyph);
6005 COPY_FPGM(bci_scale_composite_glyph);
6006 COPY_FPGM(bci_shift_contour);
6007 COPY_FPGM(bci_shift_subglyph_a);
6008 if (font->control_data_head)
6009 COPY_FPGM(bci_shift_subglyph_b);
6010 COPY_FPGM(bci_shift_subglyph_c);
6012 COPY_FPGM(bci_ip_outer_align_point);
6013 COPY_FPGM(bci_ip_on_align_points);
6014 COPY_FPGM(bci_ip_between_align_point);
6015 COPY_FPGM(bci_ip_between_align_points);
6017 COPY_FPGM(bci_adjust_common);
6018 COPY_FPGM(bci_stem_common);
6019 COPY_FPGM(bci_serif_common);
6020 COPY_FPGM(bci_serif_anchor_common);
6021 COPY_FPGM(bci_serif_link1_common);
6022 COPY_FPGM(bci_serif_link2_common);
6024 COPY_FPGM(bci_lower_bound);
6025 COPY_FPGM(bci_upper_bound);
6026 COPY_FPGM(bci_upper_lower_bound);
6028 COPY_FPGM(bci_adjust_bound);
6029 COPY_FPGM(bci_stem_bound);
6030 COPY_FPGM(bci_link);
6031 COPY_FPGM(bci_anchor);
6032 COPY_FPGM(bci_adjust);
6033 COPY_FPGM(bci_stem);
6035 COPY_FPGM(bci_action_ip_before);
6036 COPY_FPGM(bci_action_ip_after);
6037 COPY_FPGM(bci_action_ip_on);
6038 COPY_FPGM(bci_action_ip_between);
6040 COPY_FPGM(bci_action_blue);
6041 COPY_FPGM(bci_action_blue_anchor);
6043 COPY_FPGM(bci_action_anchor);
6044 COPY_FPGM(bci_action_anchor_serif);
6045 COPY_FPGM(bci_action_anchor_round);
6046 COPY_FPGM(bci_action_anchor_round_serif);
6048 COPY_FPGM(bci_action_adjust);
6049 COPY_FPGM(bci_action_adjust_serif);
6050 COPY_FPGM(bci_action_adjust_round);
6051 COPY_FPGM(bci_action_adjust_round_serif);
6052 COPY_FPGM(bci_action_adjust_bound);
6053 COPY_FPGM(bci_action_adjust_bound_serif);
6054 COPY_FPGM(bci_action_adjust_bound_round);
6055 COPY_FPGM(bci_action_adjust_bound_round_serif);
6057 COPY_FPGM(bci_action_link);
6058 COPY_FPGM(bci_action_link_serif);
6059 COPY_FPGM(bci_action_link_round);
6060 COPY_FPGM(bci_action_link_round_serif);
6062 COPY_FPGM(bci_action_stem);
6063 COPY_FPGM(bci_action_stem_serif);
6064 COPY_FPGM(bci_action_stem_round);
6065 COPY_FPGM(bci_action_stem_round_serif);
6066 COPY_FPGM(bci_action_stem_bound);
6067 COPY_FPGM(bci_action_stem_bound_serif);
6068 COPY_FPGM(bci_action_stem_bound_round);
6069 COPY_FPGM(bci_action_stem_bound_round_serif);
6071 COPY_FPGM(bci_action_serif);
6072 COPY_FPGM(bci_action_serif_lower_bound);
6073 COPY_FPGM(bci_action_serif_upper_bound);
6074 COPY_FPGM(bci_action_serif_upper_lower_bound);
6076 COPY_FPGM(bci_action_serif_anchor);
6077 COPY_FPGM(bci_action_serif_anchor_lower_bound);
6078 COPY_FPGM(bci_action_serif_anchor_upper_bound);
6079 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
6081 COPY_FPGM(bci_action_serif_link1);
6082 COPY_FPGM(bci_action_serif_link1_lower_bound);
6083 COPY_FPGM(bci_action_serif_link1_upper_bound);
6084 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
6086 COPY_FPGM(bci_action_serif_link2);
6087 COPY_FPGM(bci_action_serif_link2_lower_bound);
6088 COPY_FPGM(bci_action_serif_link2_upper_bound);
6089 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
6091 COPY_FPGM(bci_hint_glyph);
6093 *fpgm = buf;
6094 *fpgm_len = buf_len;
6096 return FT_Err_Ok;
6100 FT_Error
6101 TA_sfnt_build_fpgm_table(SFNT* sfnt,
6102 FONT* font)
6104 FT_Error error;
6106 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6107 glyf_Data* data = (glyf_Data*)glyf_table->data;
6109 FT_Byte* fpgm_buf;
6110 FT_ULong fpgm_len;
6113 error = TA_sfnt_add_table_info(sfnt);
6114 if (error)
6115 goto Exit;
6117 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
6118 if (glyf_table->processed)
6120 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
6121 goto Exit;
6124 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
6125 if (error)
6126 goto Exit;
6128 if (fpgm_len > sfnt->max_instructions)
6129 sfnt->max_instructions = fpgm_len;
6131 /* in case of success, `fpgm_buf' gets linked */
6132 /* and is eventually freed in `TA_font_unload' */
6133 error = TA_font_add_table(font,
6134 &sfnt->table_infos[sfnt->num_table_infos - 1],
6135 TTAG_fpgm, fpgm_len, fpgm_buf);
6136 if (error)
6137 free(fpgm_buf);
6138 else
6139 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
6141 Exit:
6142 return error;
6145 /* end of tafpgm.c */