Synchronize with FreeType.
[ttfautohint.git] / lib / tafpgm.c
blobc592be0e3c8205e690e6f08732d6accc877fe253
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2014 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 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 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 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 unsigned char FPGM(bci_align_top_b2) [] =
232 PUSHB_1,
234 ADD,
235 FLOOR, /* fitted = FLOOR(blue + 40) */
239 /* } */
241 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 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 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 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 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_1,
687 sal_vwidth_data_offset,
689 PUSHB_1,
693 /* %c, number of used styles */
695 unsigned char FPGM(bci_strong_stem_width_b) [] =
698 ADD,
699 RCVT, /* number of vertical widths */
701 PUSHB_1,
702 bci_get_best_width,
703 LOOPCALL,
705 POP, /* s: width dist */
706 DUP,
707 PUSHB_1,
708 sal_ref,
709 RS, /* s: width dist dist reference */
710 DUP,
711 ROLL,
712 DUP,
713 ROLL,
714 PUSHB_1,
715 bci_round,
716 CALL, /* s: width dist reference dist dist ROUND(reference) */
717 PUSHB_2,
720 CINDEX,
721 ROLL, /* s: width dist reference dist ROUND(reference) 48 reference dist */
723 LTEQ, /* dist >= reference */
724 IF, /* s: width dist reference dist ROUND(reference) 48 */
725 ADD,
726 LT, /* dist < ROUND(reference) + 48 */
728 ELSE,
729 SUB,
730 GT, /* dist > ROUND(reference) - 48 */
731 EIF,
734 SWAP, /* s: width reference dist */
735 EIF,
736 POP,
738 DUP,
739 PUSHB_1,
741 GTEQ, /* dist >= 64 */
743 PUSHB_1,
744 bci_round,
745 CALL, /* dist = ROUND(dist) */
747 ELSE,
748 POP,
749 PUSHB_1,
750 64, /* dist = 64 */
751 EIF,
753 SWAP, /* s: dist width */
754 PUSHB_1,
756 LT, /* width < 0 */
758 NEG, /* dist = -dist */
759 EIF,
761 ENDF,
767 * bci_do_loop
769 * An auxiliary function for `bci_loop'.
771 * sal: sal_i (gets incremented by 2 after execution)
772 * sal_func
774 * uses: func[sal_func]
777 unsigned char FPGM(bci_loop_do) [] =
780 PUSHB_1,
781 bci_loop_do,
782 FDEF,
784 PUSHB_1,
785 sal_func,
787 CALL,
789 PUSHB_3,
790 sal_i,
792 sal_i,
794 ADD, /* sal_i = sal_i + 2 */
797 ENDF,
803 * bci_loop
805 * Take a range `start'..`end' and a function number and apply the
806 * associated function to the range elements `start', `start+2',
807 * `start+4', ...
809 * in: func_num
810 * end
811 * start
813 * sal: sal_i (counter initialized with `start')
814 * sal_func (`func_num')
816 * uses: bci_loop_do
819 unsigned char FPGM(bci_loop) [] =
822 PUSHB_1,
823 bci_loop,
824 FDEF,
826 PUSHB_1,
827 sal_func,
828 SWAP,
829 WS, /* sal_func = func_num */
831 SWAP,
832 DUP,
833 PUSHB_1,
834 sal_i,
835 SWAP,
836 WS, /* sal_i = start */
838 SUB,
839 DIV_POS_BY_2,
840 PUSHB_1,
842 ADD, /* number of loops ((end - start) / 2 + 1) */
844 PUSHB_1,
845 bci_loop_do,
846 LOOPCALL,
848 ENDF,
854 * bci_cvt_rescale
856 * Rescale CVT value by `sal_scale' (in 16.16 format).
858 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
859 * consequently, the calculation `a * b/c' is done as `a + delta' with
860 * `delta = a * (b-c)/c'. This avoids overflow.
862 * in: cvt_idx
864 * out: cvt_idx+1
866 * sal: sal_scale
869 unsigned char FPGM(bci_cvt_rescale) [] =
872 PUSHB_1,
873 bci_cvt_rescale,
874 FDEF,
876 DUP,
877 DUP,
878 RCVT,
879 DO_SCALE,
880 WCVTP,
882 PUSHB_1,
884 ADD,
886 ENDF,
892 * bci_cvt_rescale_range
894 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
895 * scaling value.
897 * This function gets used in the `prep' table.
899 * in: num_cvt
900 * cvt_start_idx
902 * sal: sal_i (CVT index of the style's scaling value;
903 * gets incremented by 1 after execution)
904 * sal_scale
906 * uses: bci_cvt_rescale
909 unsigned char FPGM(bci_cvt_rescale_range) [] =
912 PUSHB_1,
913 bci_cvt_rescale_range,
914 FDEF,
916 /* store scaling value in `sal_scale' */
917 PUSHB_3,
918 bci_cvt_rescale,
919 sal_scale,
920 sal_i,
922 RCVT,
923 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
925 LOOPCALL,
926 POP,
928 PUSHB_3,
929 sal_i,
931 sal_i,
933 ADD, /* sal_i = sal_i + 1 */
936 ENDF,
942 * bci_vwidth_data_store
944 * Store a vertical width array value.
946 * This function gets used in the `prep' table.
948 * in: value
950 * sal: sal_i (CVT index of the style's vwidth data;
951 * gets incremented by 1 after execution)
954 unsigned char FPGM(bci_vwidth_data_store) [] =
957 PUSHB_1,
958 bci_vwidth_data_store,
959 FDEF,
961 PUSHB_1,
962 sal_i,
964 SWAP,
965 WCVTP,
967 PUSHB_3,
968 sal_i,
970 sal_i,
972 ADD, /* sal_i = sal_i + 1 */
975 ENDF,
981 * bci_smooth_blue_round
983 * Round a blue ref value and adjust its corresponding shoot value.
985 * This is the equivalent to the following code (function
986 * `ta_latin_metrics_scale_dim':
988 * delta = dist;
989 * if (dist < 0)
990 * delta = -delta;
992 * if (delta < 32)
993 * delta = 0;
994 * else if (delta < 48)
995 * delta = 32;
996 * else
997 * delta = 64;
999 * if (dist < 0)
1000 * delta = -delta;
1002 * in: ref_idx
1004 * sal: sal_i (number of blue zones)
1006 * out: ref_idx+1
1008 * uses: bci_round
1011 unsigned char FPGM(bci_smooth_blue_round) [] =
1014 PUSHB_1,
1015 bci_smooth_blue_round,
1016 FDEF,
1018 DUP,
1019 DUP,
1020 RCVT, /* s: ref_idx ref_idx ref */
1022 DUP,
1023 PUSHB_1,
1024 bci_round,
1025 CALL,
1026 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1028 PUSHB_1,
1029 sal_i,
1031 PUSHB_1,
1033 CINDEX,
1034 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1035 DUP,
1036 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1038 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1039 SWAP,
1040 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1041 DUP,
1042 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1044 DUP,
1045 PUSHB_1,
1047 LT, /* delta < 32 */
1049 POP,
1050 PUSHB_1,
1051 0, /* delta = 0 */
1053 ELSE,
1054 PUSHB_1,
1056 LT, /* delta < 48 */
1058 PUSHB_1,
1059 32, /* delta = 32 */
1061 ELSE,
1062 PUSHB_1,
1063 64, /* delta = 64 */
1064 EIF,
1065 EIF,
1067 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1068 PUSHB_1,
1070 LT, /* dist < 0 */
1072 NEG, /* delta = -delta */
1073 EIF,
1075 PUSHB_1,
1077 CINDEX,
1078 SWAP,
1079 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1081 WCVTP,
1082 WCVTP,
1084 PUSHB_1,
1086 ADD, /* s: (ref_idx + 1) */
1088 ENDF,
1094 * bci_strong_blue_round
1096 * Round a blue ref value and adjust its corresponding shoot value.
1098 * This is the equivalent to the following code:
1100 * delta = dist;
1101 * if (dist < 0)
1102 * delta = -delta;
1104 * if (delta < 36)
1105 * delta = 0;
1106 * else
1107 * delta = 64;
1109 * if (dist < 0)
1110 * delta = -delta;
1112 * It doesn't have corresponding code in talatin.c; however, some tests
1113 * have shown that the `smooth' code works just fine for this case also.
1115 * in: ref_idx
1117 * sal: sal_i (number of blue zones)
1119 * out: ref_idx+1
1121 * uses: bci_round
1124 unsigned char FPGM(bci_strong_blue_round) [] =
1127 PUSHB_1,
1128 bci_strong_blue_round,
1129 FDEF,
1131 DUP,
1132 DUP,
1133 RCVT, /* s: ref_idx ref_idx ref */
1135 DUP,
1136 PUSHB_1,
1137 bci_round,
1138 CALL,
1139 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1141 PUSHB_1,
1142 sal_i,
1144 PUSHB_1,
1146 CINDEX,
1147 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1148 DUP,
1149 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1151 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1152 SWAP,
1153 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1154 DUP,
1155 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1157 PUSHB_1,
1159 LT, /* delta < 36 */
1161 PUSHB_1,
1162 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1164 ELSE,
1165 PUSHB_1,
1166 64, /* delta = 64 (one pixel unit) */
1167 EIF,
1169 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1170 PUSHB_1,
1172 LT, /* dist < 0 */
1174 NEG, /* delta = -delta */
1175 EIF,
1177 PUSHB_1,
1179 CINDEX,
1180 SWAP,
1181 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1183 WCVTP,
1184 WCVTP,
1186 PUSHB_1,
1188 ADD, /* s: (ref_idx + 1) */
1190 ENDF,
1196 * bci_blue_round_range
1198 * Round a range of blue zones (both reference and shoot values).
1200 * This function gets used in the `prep' table.
1202 * in: num_blue_zones
1203 * blue_ref_idx
1205 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1207 * uses: bci_smooth_blue_round
1208 * bci_strong_blue_round
1211 unsigned char FPGM(bci_blue_round_range) [] =
1214 PUSHB_1,
1215 bci_blue_round_range,
1216 FDEF,
1218 DUP,
1219 PUSHB_1,
1220 sal_i,
1221 SWAP,
1224 /* select blue rounding function based on flag in CVT */
1225 PUSHB_3,
1226 bci_strong_blue_round,
1227 bci_smooth_blue_round,
1228 cvtl_use_strong_functions,
1229 RCVT,
1231 POP,
1233 ELSE,
1234 SWAP,
1235 POP,
1237 EIF,
1238 LOOPCALL,
1239 POP,
1241 ENDF,
1247 * bci_decrement_component_counter
1249 * An auxiliary function for composite glyphs.
1251 * CVT: cvtl_is_subglyph
1254 unsigned char FPGM(bci_decrement_component_counter) [] =
1257 PUSHB_1,
1258 bci_decrement_component_counter,
1259 FDEF,
1261 /* decrement `cvtl_is_subglyph' counter */
1262 PUSHB_2,
1263 cvtl_is_subglyph,
1264 cvtl_is_subglyph,
1265 RCVT,
1266 PUSHB_1,
1267 100,
1268 SUB,
1269 WCVTP,
1271 ENDF,
1277 * bci_get_point_extrema
1279 * An auxiliary function for `bci_create_segment'.
1281 * in: point-1
1283 * out: point
1285 * sal: sal_point_min
1286 * sal_point_max
1289 unsigned char FPGM(bci_get_point_extrema) [] =
1292 PUSHB_1,
1293 bci_get_point_extrema,
1294 FDEF,
1296 PUSHB_1,
1298 ADD, /* s: point */
1299 DUP,
1300 DUP,
1302 /* check whether `point' is a new minimum */
1303 PUSHB_1,
1304 sal_point_min,
1305 RS, /* s: point point point point_min */
1306 MD_orig,
1307 /* if distance is negative, we have a new minimum */
1308 PUSHB_1,
1311 IF, /* s: point point */
1312 DUP,
1313 PUSHB_1,
1314 sal_point_min,
1315 SWAP,
1317 EIF,
1319 /* check whether `point' is a new maximum */
1320 PUSHB_1,
1321 sal_point_max,
1322 RS, /* s: point point point_max */
1323 MD_orig,
1324 /* if distance is positive, we have a new maximum */
1325 PUSHB_1,
1328 IF, /* s: point */
1329 DUP,
1330 PUSHB_1,
1331 sal_point_max,
1332 SWAP,
1334 EIF, /* s: point */
1336 ENDF,
1342 * bci_nibbles
1344 * Pop a byte with two delta arguments in its nibbles and push the
1345 * expanded arguments separately as two bytes.
1347 * in: 16 * (end - start) + (start - base)
1349 * out: start
1350 * end
1352 * sal: sal_base (set to `end' at return)
1356 unsigned char FPGM(bci_nibbles) [] =
1358 PUSHB_1,
1359 bci_nibbles,
1360 FDEF,
1362 DUP,
1363 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1365 DIV,
1366 FLOOR,
1367 PUSHB_1,
1369 MUL, /* s: in hnibble */
1370 DUP,
1371 PUSHW_1,
1372 0x04, /* 16*64 */
1373 0x00,
1374 MUL, /* s: in hnibble (hnibble * 16) */
1375 ROLL,
1376 SWAP,
1377 SUB, /* s: hnibble lnibble */
1379 PUSHB_1,
1380 sal_base,
1382 ADD, /* s: hnibble start */
1383 DUP,
1384 ROLL,
1385 ADD, /* s: start end */
1387 DUP,
1388 PUSHB_1,
1389 sal_base,
1390 SWAP,
1391 WS, /* sal_base = end */
1393 SWAP,
1395 ENDF,
1401 * bci_number_set_is_element
1403 * Pop values from stack until it is empty. If one of them is equal to
1404 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1405 * otherwise).
1407 * in: ppem_value_1
1408 * ppem_value_2
1409 * ...
1411 * CVT: cvtl_is_element
1414 unsigned char FPGM(bci_number_set_is_element) [] =
1417 PUSHB_1,
1418 bci_number_set_is_element,
1419 FDEF,
1421 /* start_loop: */
1422 MPPEM,
1425 PUSHB_2,
1426 cvtl_is_element,
1427 100,
1428 WCVTP,
1429 EIF,
1431 DEPTH,
1432 PUSHB_1,
1434 NEG,
1435 SWAP,
1436 JROT, /* goto start_loop if stack depth != 0 */
1438 ENDF,
1444 * bci_number_set_is_element2
1446 * Pop value ranges from stack until it is empty. If one of them contains
1447 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1448 * otherwise).
1450 * in: ppem_range_1_start
1451 * ppem_range_1_end
1452 * ppem_range_2_start
1453 * ppem_range_2_end
1454 * ...
1456 * CVT: cvtl_is_element
1459 unsigned char FPGM(bci_number_set_is_element2) [] =
1462 PUSHB_1,
1463 bci_number_set_is_element2,
1464 FDEF,
1466 /* start_loop: */
1467 MPPEM,
1468 LTEQ,
1470 MPPEM,
1471 GTEQ,
1473 PUSHB_2,
1474 cvtl_is_element,
1475 100,
1476 WCVTP,
1477 EIF,
1478 ELSE,
1479 POP,
1480 EIF,
1482 DEPTH,
1483 PUSHB_1,
1485 NEG,
1486 SWAP,
1487 JROT, /* goto start_loop if stack depth != 0 */
1489 ENDF,
1495 * bci_create_segment
1497 * Store start and end point of a segment in the storage area,
1498 * then construct a point in the twilight zone to represent it.
1500 * This function is used by `bci_create_segments'.
1502 * in: start
1503 * end
1504 * [last (if wrap-around segment)]
1505 * [first (if wrap-around segment)]
1507 * sal: sal_i (start of current segment)
1508 * sal_j (current twilight point)
1509 * sal_point_min
1510 * sal_point_max
1511 * sal_base
1512 * sal_num_packed_segments
1513 * sal_scale
1515 * CVT: cvtl_temp
1517 * uses: bci_get_point_extrema
1518 * bci_nibbles
1520 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1521 * delta values in nibbles (without a wrap-around segment).
1524 unsigned char FPGM(bci_create_segment) [] =
1527 PUSHB_1,
1528 bci_create_segment,
1529 FDEF,
1531 PUSHB_2,
1533 sal_num_packed_segments,
1535 NEQ,
1537 PUSHB_2,
1538 sal_num_packed_segments,
1539 sal_num_packed_segments,
1541 PUSHB_1,
1543 SUB,
1544 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1546 PUSHB_1,
1547 bci_nibbles,
1548 CALL,
1549 EIF,
1551 PUSHB_1,
1552 sal_i,
1554 PUSHB_1,
1556 CINDEX,
1557 WS, /* sal[sal_i] = start */
1559 /* initialize inner loop(s) */
1560 PUSHB_2,
1561 sal_point_min,
1563 CINDEX,
1564 WS, /* sal_point_min = start */
1565 PUSHB_2,
1566 sal_point_max,
1568 CINDEX,
1569 WS, /* sal_point_max = start */
1571 PUSHB_1,
1573 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1575 SWAP,
1576 DUP,
1577 PUSHB_1,
1579 CINDEX, /* s: start end end start */
1580 LT, /* start > end */
1582 /* we have a wrap-around segment with two more arguments */
1583 /* to give the last and first point of the contour, respectively; */
1584 /* our job is to store a segment `start'-`last', */
1585 /* and to get extrema for the two segments */
1586 /* `start'-`last' and `first'-`end' */
1588 /* s: first last start end */
1589 PUSHB_2,
1591 sal_i,
1593 ADD,
1594 PUSHB_1,
1596 CINDEX,
1597 WS, /* sal[sal_i + 1] = last */
1599 ROLL,
1600 ROLL, /* s: first end last start */
1601 DUP,
1602 ROLL,
1603 SWAP, /* s: first end start last start */
1604 SUB, /* s: first end start loop_count */
1606 PUSHB_1,
1607 bci_get_point_extrema,
1608 LOOPCALL,
1609 /* clean up stack */
1610 POP,
1612 SWAP, /* s: end first */
1613 PUSHB_1,
1615 SUB,
1616 DUP,
1617 ROLL, /* s: (first - 1) (first - 1) end */
1618 SWAP,
1619 SUB, /* s: (first - 1) loop_count */
1621 PUSHB_1,
1622 bci_get_point_extrema,
1623 LOOPCALL,
1624 /* clean up stack */
1625 POP,
1627 ELSE, /* s: start end */
1628 PUSHB_2,
1630 sal_i,
1632 ADD,
1633 PUSHB_1,
1635 CINDEX,
1636 WS, /* sal[sal_i + 1] = end */
1638 PUSHB_1,
1640 CINDEX,
1641 SUB, /* s: start loop_count */
1643 PUSHB_1,
1644 bci_get_point_extrema,
1645 LOOPCALL,
1646 /* clean up stack */
1647 POP,
1648 EIF,
1650 /* the twilight point representing a segment */
1651 /* is in the middle between the minimum and maximum */
1652 PUSHB_1,
1653 sal_point_min,
1655 GC_orig,
1656 PUSHB_1,
1657 sal_point_max,
1659 GC_orig,
1660 ADD,
1661 DIV_BY_2, /* s: middle_pos */
1663 DO_SCALE, /* middle_pos = middle_pos * scale */
1665 /* write it to temporary CVT location */
1666 PUSHB_2,
1667 cvtl_temp,
1669 SZP0, /* set zp0 to twilight zone 0 */
1670 SWAP,
1671 WCVTP,
1673 /* create twilight point with index `sal_j' */
1674 PUSHB_1,
1675 sal_j,
1677 PUSHB_1,
1678 cvtl_temp,
1679 MIAP_noround,
1681 PUSHB_3,
1682 sal_j,
1684 sal_j,
1686 ADD, /* twilight_point = twilight_point + 1 */
1689 ENDF,
1695 * bci_create_segments
1697 * This is the top-level entry function.
1699 * It pops point ranges from the stack to define segments, computes
1700 * twilight points to represent segments, and finally calls
1701 * `bci_hint_glyph' to handle the rest.
1703 * The second argument (`data_offset') addresses three CVT arrays in
1704 * parallel:
1706 * CVT(data_offset):
1707 * the current style's scaling value (stored in `sal_scale')
1709 * data_offset + num_used_styles:
1710 * offset to the current style's vwidth index array (this value gets
1711 * stored in `sal_vwidth_data_offset')
1713 * data_offset + 2*num_used_styles:
1714 * offset to the current style's vwidth size
1716 * This addressing scheme ensures that (a) we only need a single argument,
1717 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1718 * which should be sufficient for a long time.
1720 * in: num_packed_segments
1721 * data_offset
1722 * num_segments (N)
1723 * segment_start_0
1724 * segment_end_0
1725 * [contour_last 0 (if wrap-around segment)]
1726 * [contour_first 0 (if wrap-around segment)]
1727 * segment_start_1
1728 * segment_end_1
1729 * [contour_last 0 (if wrap-around segment)]
1730 * [contour_first 0 (if wrap-around segment)]
1731 * ...
1732 * segment_start_(N-1)
1733 * segment_end_(N-1)
1734 * [contour_last (N-1) (if wrap-around segment)]
1735 * [contour_first (N-1) (if wrap-around segment)]
1736 * ... stuff for bci_hint_glyph ...
1738 * sal: sal_i (start of current segment)
1739 * sal_j (current twilight point)
1740 * sal_num_packed_segments
1741 * sal_base (the base for delta values in nibbles)
1742 * sal_vwidth_data_offset
1743 * sal_scale
1745 * CVT: cvtl_is_subglyph
1747 * uses: bci_create_segment
1748 * bci_loop
1749 * bci_hint_glyph
1751 * If `num_packed_segments' is set to p, the first p start/end pairs are
1752 * stored as delta values in nibbles, with the `start' delta in the lower
1753 * nibble (and there are no wrap-around segments). For example, if the
1754 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1755 * stack are 0x21, 0x32, and 0x14.
1759 unsigned char FPGM(bci_create_segments_a) [] =
1762 PUSHB_1,
1763 bci_create_segments,
1764 FDEF,
1766 /* all our measurements are taken along the y axis */
1767 SVTCA_y,
1769 /* only do something if we are not a subglyph */
1770 PUSHB_2,
1772 cvtl_is_subglyph,
1773 RCVT,
1776 PUSHB_1,
1777 sal_num_packed_segments,
1778 SWAP,
1781 DUP,
1782 RCVT,
1783 PUSHB_1,
1784 sal_scale, /* sal_scale = CVT(data_offset) */
1785 SWAP,
1788 PUSHB_1,
1789 sal_vwidth_data_offset,
1790 SWAP,
1791 PUSHB_1,
1795 /* %c, number of used styles */
1797 unsigned char FPGM(bci_create_segments_b) [] =
1800 ADD,
1801 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1803 DUP,
1804 ADD,
1805 PUSHB_1,
1807 SUB, /* delta = (2*num_segments - 1) */
1809 PUSHB_6,
1810 sal_segment_offset,
1811 sal_segment_offset,
1813 sal_j,
1815 sal_base,
1817 WS, /* sal_base = 0 */
1818 WS, /* sal_j = 0 (point offset) */
1820 ROLL,
1821 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1823 PUSHB_2,
1824 bci_create_segment,
1825 bci_loop,
1826 CALL,
1828 PUSHB_1,
1829 bci_hint_glyph,
1830 CALL,
1832 ELSE,
1833 CLEAR,
1834 EIF,
1836 ENDF,
1842 * bci_create_segments_X
1844 * Top-level routines for calling `bci_create_segments'.
1847 unsigned char FPGM(bci_create_segments_0) [] =
1850 PUSHB_1,
1851 bci_create_segments_0,
1852 FDEF,
1854 PUSHB_2,
1856 bci_create_segments,
1857 CALL,
1859 ENDF,
1863 unsigned char FPGM(bci_create_segments_1) [] =
1866 PUSHB_1,
1867 bci_create_segments_1,
1868 FDEF,
1870 PUSHB_2,
1872 bci_create_segments,
1873 CALL,
1875 ENDF,
1879 unsigned char FPGM(bci_create_segments_2) [] =
1882 PUSHB_1,
1883 bci_create_segments_2,
1884 FDEF,
1886 PUSHB_2,
1888 bci_create_segments,
1889 CALL,
1891 ENDF,
1895 unsigned char FPGM(bci_create_segments_3) [] =
1898 PUSHB_1,
1899 bci_create_segments_3,
1900 FDEF,
1902 PUSHB_2,
1904 bci_create_segments,
1905 CALL,
1907 ENDF,
1911 unsigned char FPGM(bci_create_segments_4) [] =
1914 PUSHB_1,
1915 bci_create_segments_4,
1916 FDEF,
1918 PUSHB_2,
1920 bci_create_segments,
1921 CALL,
1923 ENDF,
1927 unsigned char FPGM(bci_create_segments_5) [] =
1930 PUSHB_1,
1931 bci_create_segments_5,
1932 FDEF,
1934 PUSHB_2,
1936 bci_create_segments,
1937 CALL,
1939 ENDF,
1943 unsigned char FPGM(bci_create_segments_6) [] =
1946 PUSHB_1,
1947 bci_create_segments_6,
1948 FDEF,
1950 PUSHB_2,
1952 bci_create_segments,
1953 CALL,
1955 ENDF,
1959 unsigned char FPGM(bci_create_segments_7) [] =
1962 PUSHB_1,
1963 bci_create_segments_7,
1964 FDEF,
1966 PUSHB_2,
1968 bci_create_segments,
1969 CALL,
1971 ENDF,
1975 unsigned char FPGM(bci_create_segments_8) [] =
1978 PUSHB_1,
1979 bci_create_segments_8,
1980 FDEF,
1982 PUSHB_2,
1984 bci_create_segments,
1985 CALL,
1987 ENDF,
1991 unsigned char FPGM(bci_create_segments_9) [] =
1994 PUSHB_1,
1995 bci_create_segments_9,
1996 FDEF,
1998 PUSHB_2,
2000 bci_create_segments,
2001 CALL,
2003 ENDF,
2009 * bci_create_segments_composite
2011 * The same as `bci_create_segments'.
2012 * It also decrements the composite component counter.
2014 * sal: sal_num_packed_segments
2015 * sal_segment_offset
2016 * sal_vwidth_data_offset
2018 * CVT: cvtl_is_subglyph
2020 * uses: bci_decrement_component_counter
2021 * bci_create_segment
2022 * bci_loop
2023 * bci_hint_glyph
2026 unsigned char FPGM(bci_create_segments_composite_a) [] =
2029 PUSHB_1,
2030 bci_create_segments_composite,
2031 FDEF,
2033 /* all our measurements are taken along the y axis */
2034 SVTCA_y,
2036 PUSHB_1,
2037 bci_decrement_component_counter,
2038 CALL,
2040 /* only do something if we are not a subglyph */
2041 PUSHB_2,
2043 cvtl_is_subglyph,
2044 RCVT,
2047 PUSHB_1,
2048 sal_num_packed_segments,
2049 SWAP,
2052 DUP,
2053 RCVT,
2054 PUSHB_1,
2055 sal_scale, /* sal_scale = CVT(data_offset) */
2056 SWAP,
2059 PUSHB_1,
2060 sal_vwidth_data_offset,
2061 SWAP,
2062 PUSHB_1,
2066 /* %c, number of used styles */
2068 unsigned char FPGM(bci_create_segments_composite_b) [] =
2071 ADD,
2072 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2074 DUP,
2075 ADD,
2076 PUSHB_1,
2078 SUB, /* delta = (2*num_segments - 1) */
2080 PUSHB_6,
2081 sal_segment_offset,
2082 sal_segment_offset,
2084 sal_j,
2086 sal_base,
2088 WS, /* sal_base = 0 */
2089 WS, /* sal_j = 0 (point offset) */
2091 ROLL,
2092 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2094 PUSHB_2,
2095 bci_create_segment,
2096 bci_loop,
2097 CALL,
2099 PUSHB_1,
2100 bci_hint_glyph,
2101 CALL,
2103 ELSE,
2104 CLEAR,
2105 EIF,
2107 ENDF,
2113 * bci_create_segments_composite_X
2115 * Top-level routines for calling `bci_create_segments_composite'.
2118 unsigned char FPGM(bci_create_segments_composite_0) [] =
2121 PUSHB_1,
2122 bci_create_segments_composite_0,
2123 FDEF,
2125 PUSHB_2,
2127 bci_create_segments_composite,
2128 CALL,
2130 ENDF,
2134 unsigned char FPGM(bci_create_segments_composite_1) [] =
2137 PUSHB_1,
2138 bci_create_segments_composite_1,
2139 FDEF,
2141 PUSHB_2,
2143 bci_create_segments_composite,
2144 CALL,
2146 ENDF,
2150 unsigned char FPGM(bci_create_segments_composite_2) [] =
2153 PUSHB_1,
2154 bci_create_segments_composite_2,
2155 FDEF,
2157 PUSHB_2,
2159 bci_create_segments_composite,
2160 CALL,
2162 ENDF,
2166 unsigned char FPGM(bci_create_segments_composite_3) [] =
2169 PUSHB_1,
2170 bci_create_segments_composite_3,
2171 FDEF,
2173 PUSHB_2,
2175 bci_create_segments_composite,
2176 CALL,
2178 ENDF,
2182 unsigned char FPGM(bci_create_segments_composite_4) [] =
2185 PUSHB_1,
2186 bci_create_segments_composite_4,
2187 FDEF,
2189 PUSHB_2,
2191 bci_create_segments_composite,
2192 CALL,
2194 ENDF,
2198 unsigned char FPGM(bci_create_segments_composite_5) [] =
2201 PUSHB_1,
2202 bci_create_segments_composite_5,
2203 FDEF,
2205 PUSHB_2,
2207 bci_create_segments_composite,
2208 CALL,
2210 ENDF,
2214 unsigned char FPGM(bci_create_segments_composite_6) [] =
2217 PUSHB_1,
2218 bci_create_segments_composite_6,
2219 FDEF,
2221 PUSHB_2,
2223 bci_create_segments_composite,
2224 CALL,
2226 ENDF,
2230 unsigned char FPGM(bci_create_segments_composite_7) [] =
2233 PUSHB_1,
2234 bci_create_segments_composite_7,
2235 FDEF,
2237 PUSHB_2,
2239 bci_create_segments_composite,
2240 CALL,
2242 ENDF,
2246 unsigned char FPGM(bci_create_segments_composite_8) [] =
2249 PUSHB_1,
2250 bci_create_segments_composite_8,
2251 FDEF,
2253 PUSHB_2,
2255 bci_create_segments_composite,
2256 CALL,
2258 ENDF,
2262 unsigned char FPGM(bci_create_segments_composite_9) [] =
2265 PUSHB_1,
2266 bci_create_segments_composite_9,
2267 FDEF,
2269 PUSHB_2,
2271 bci_create_segments_composite,
2272 CALL,
2274 ENDF,
2280 * bci_align_point
2282 * An auxiliary function for `bci_align_segment'.
2284 * in: point
2286 * out: point+1
2289 unsigned char FPGM(bci_align_point) [] =
2292 PUSHB_1,
2293 bci_align_point,
2294 FDEF,
2296 DUP,
2297 ALIGNRP, /* align point with rp0 */
2299 PUSHB_1,
2301 ADD,
2303 ENDF,
2309 * bci_align_segment
2311 * Align all points in a segment to the twilight point in rp0.
2312 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2314 * in: segment_index
2316 * sal: sal_segment_offset
2318 * uses: bci_align_point
2321 unsigned char FPGM(bci_align_segment) [] =
2324 PUSHB_1,
2325 bci_align_segment,
2326 FDEF,
2328 /* we need the values of `sal_segment_offset + 2*segment_index' */
2329 /* and `sal_segment_offset + 2*segment_index + 1' */
2330 DUP,
2331 ADD,
2332 PUSHB_1,
2333 sal_segment_offset,
2334 ADD,
2335 DUP,
2337 SWAP,
2338 PUSHB_1,
2340 ADD,
2341 RS, /* s: first last */
2343 PUSHB_1,
2345 CINDEX, /* s: first last first */
2346 SUB,
2347 PUSHB_1,
2349 ADD, /* s: first loop_count */
2351 PUSHB_1,
2352 bci_align_point,
2353 LOOPCALL,
2354 /* clean up stack */
2355 POP,
2357 ENDF,
2363 * bci_align_segments
2365 * Align segments to the twilight point in rp0.
2366 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2368 * in: first_segment
2369 * loop_counter (N)
2370 * segment_1
2371 * segment_2
2372 * ...
2373 * segment_N
2375 * uses: bci_align_segment
2378 unsigned char FPGM(bci_align_segments) [] =
2381 PUSHB_1,
2382 bci_align_segments,
2383 FDEF,
2385 PUSHB_1,
2386 bci_align_segment,
2387 CALL,
2389 PUSHB_1,
2390 bci_align_segment,
2391 LOOPCALL,
2393 ENDF,
2399 * bci_scale_contour
2401 * Scale a contour using two points giving the maximum and minimum
2402 * coordinates.
2404 * It expects that no point on the contour is touched.
2406 * in: min_point
2407 * max_point
2409 * sal: sal_scale
2412 unsigned char FPGM(bci_scale_contour) [] =
2415 PUSHB_1,
2416 bci_scale_contour,
2417 FDEF,
2419 DUP,
2420 DUP,
2421 GC_orig,
2422 DUP,
2423 DO_SCALE, /* min_pos_new = min_pos * scale */
2424 SWAP,
2425 SUB,
2426 SHPIX,
2428 /* don't scale a single-point contour twice */
2429 SWAP,
2430 DUP,
2431 ROLL,
2432 NEQ,
2434 DUP,
2435 GC_orig,
2436 DUP,
2437 DO_SCALE, /* max_pos_new = max_pos * scale */
2438 SWAP,
2439 SUB,
2440 SHPIX,
2442 ELSE,
2443 POP,
2444 EIF,
2446 ENDF,
2452 * bci_scale_glyph
2454 * Scale a glyph using a list of points (two points per contour, giving
2455 * the maximum and mininum coordinates).
2457 * It expects that no point in the glyph is touched.
2459 * Note that the point numbers are sorted in ascending order;
2460 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2461 * contour without specifying which one is the minimum and maximum.
2463 * in: num_contours (N)
2464 * min_point_1
2465 * max_point_1
2466 * min_point_2
2467 * max_point_2
2468 * ...
2469 * min_point_N
2470 * max_point_N
2472 * CVT: cvtl_is_subglyph
2474 * uses: bci_scale_contour
2477 unsigned char FPGM(bci_scale_glyph) [] =
2480 PUSHB_1,
2481 bci_scale_glyph,
2482 FDEF,
2484 /* all our measurements are taken along the y axis */
2485 SVTCA_y,
2487 /* only do something if we are not a subglyph */
2488 PUSHB_2,
2490 cvtl_is_subglyph,
2491 RCVT,
2494 PUSHB_1,
2496 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2498 PUSHB_1,
2499 bci_scale_contour,
2500 LOOPCALL,
2502 PUSHB_1,
2504 SZP2, /* set zp2 to normal zone 1 */
2505 IUP_y,
2507 ELSE,
2508 CLEAR,
2509 EIF,
2511 ENDF,
2517 * bci_scale_composite_glyph
2519 * The same as `bci_scale_glyph'.
2520 * It also decrements the composite component counter.
2522 * CVT: cvtl_is_subglyph
2524 * uses: bci_decrement_component_counter
2525 * bci_scale_contour
2528 unsigned char FPGM(bci_scale_composite_glyph) [] =
2531 PUSHB_1,
2532 bci_scale_composite_glyph,
2533 FDEF,
2535 /* all our measurements are taken along the y axis */
2536 SVTCA_y,
2538 PUSHB_1,
2539 bci_decrement_component_counter,
2540 CALL,
2542 /* only do something if we are not a subglyph */
2543 PUSHB_2,
2545 cvtl_is_subglyph,
2546 RCVT,
2549 PUSHB_1,
2551 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2553 PUSHB_1,
2554 bci_scale_contour,
2555 LOOPCALL,
2557 PUSHB_1,
2559 SZP2, /* set zp2 to normal zone 1 */
2560 IUP_y,
2562 ELSE,
2563 CLEAR,
2564 EIF,
2566 ENDF,
2572 * bci_shift_contour
2574 * Shift a contour by a given amount.
2576 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2577 * point to the normal zone 1.
2579 * in: contour
2581 * out: contour+1
2584 unsigned char FPGM(bci_shift_contour) [] =
2587 PUSHB_1,
2588 bci_shift_contour,
2589 FDEF,
2591 DUP,
2592 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2594 PUSHB_1,
2596 ADD,
2598 ENDF,
2604 * bci_shift_subglyph
2606 * Shift a subglyph. To be more specific, it corrects the already applied
2607 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2608 * also.
2610 * If this function is called, a point `x' in the subglyph has been scaled
2611 * already (during the hinting of the subglyph itself), and `offset' has
2612 * been applied also:
2614 * x -> x * scale + offset (1)
2616 * However, the offset should be applied first, then the scaling:
2618 * x -> (x + offset) * scale (2)
2620 * Our job is now to transform (1) to (2); a simple calculation shows that
2621 * we have to shift all points of the subglyph by
2623 * offset * scale - offset = offset * (scale - 1)
2625 * Note that `sal_scale' is equal to the above `scale - 1'.
2627 * in: offset (in FUnits)
2628 * num_contours
2629 * first_contour
2631 * CVT: cvtl_funits_to_pixels
2633 * sal: sal_scale
2635 * uses: bci_round
2636 * bci_shift_contour
2639 unsigned char FPGM(bci_shift_subglyph) [] =
2642 PUSHB_1,
2643 bci_shift_subglyph,
2644 FDEF,
2646 /* all our measurements are taken along the y axis */
2647 SVTCA_y,
2649 PUSHB_1,
2650 cvtl_funits_to_pixels,
2651 RCVT, /* scaling factor FUnits -> pixels */
2652 MUL,
2653 DIV_BY_1024,
2655 /* the autohinter always rounds offsets */
2656 PUSHB_1,
2657 bci_round,
2658 CALL, /* offset = round(offset) */
2660 PUSHB_1,
2661 sal_scale,
2663 MUL,
2664 DIV_BY_1024, /* delta = offset * (scale - 1) */
2666 /* and round again */
2667 PUSHB_1,
2668 bci_round,
2669 CALL, /* offset = round(offset) */
2671 PUSHB_1,
2673 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2675 /* we create twilight point 0 as a reference point, */
2676 /* setting the original position to zero (using `cvtl_temp') */
2677 PUSHB_5,
2680 cvtl_temp,
2681 cvtl_temp,
2683 WCVTP,
2684 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2686 SWAP, /* s: first_contour num_contours 0 delta */
2687 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2689 PUSHB_2,
2690 bci_shift_contour,
2692 SZP2, /* set zp2 to normal zone 1 */
2693 LOOPCALL,
2695 ENDF,
2701 * bci_ip_outer_align_point
2703 * Auxiliary function for `bci_action_ip_before' and
2704 * `bci_action_ip_after'.
2706 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2707 * zone, and both zp1 and zp2 set to normal zone.
2709 * in: point
2711 * sal: sal_i (edge_orig_pos)
2712 * sal_scale
2715 unsigned char FPGM(bci_ip_outer_align_point) [] =
2718 PUSHB_1,
2719 bci_ip_outer_align_point,
2720 FDEF,
2722 DUP,
2723 ALIGNRP, /* align `point' with `edge' */
2724 DUP,
2725 GC_orig,
2726 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2728 PUSHB_1,
2729 sal_i,
2731 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2732 SHPIX,
2734 ENDF,
2740 * bci_ip_on_align_points
2742 * Auxiliary function for `bci_action_ip_on'.
2744 * in: edge (in twilight zone)
2745 * loop_counter (N)
2746 * point_1
2747 * point_2
2748 * ...
2749 * point_N
2752 unsigned char FPGM(bci_ip_on_align_points) [] =
2755 PUSHB_1,
2756 bci_ip_on_align_points,
2757 FDEF,
2759 MDAP_noround, /* set rp0 and rp1 to `edge' */
2761 SLOOP,
2762 ALIGNRP,
2764 ENDF,
2770 * bci_ip_between_align_point
2772 * Auxiliary function for `bci_ip_between_align_points'.
2774 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2775 * zone, and both zp1 and zp2 set to normal zone.
2777 * in: point
2779 * sal: sal_i (edge_orig_pos)
2780 * sal_j (stretch_factor)
2781 * sal_scale
2784 unsigned char FPGM(bci_ip_between_align_point) [] =
2787 PUSHB_1,
2788 bci_ip_between_align_point,
2789 FDEF,
2791 DUP,
2792 ALIGNRP, /* align `point' with `edge' */
2793 DUP,
2794 GC_orig,
2795 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2797 PUSHB_1,
2798 sal_i,
2800 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2801 PUSHB_1,
2802 sal_j,
2804 MUL, /* s: point delta */
2805 SHPIX,
2807 ENDF,
2813 * bci_ip_between_align_points
2815 * Auxiliary function for `bci_action_ip_between'.
2817 * in: after_edge (in twilight zone)
2818 * before_edge (in twilight zone)
2819 * loop_counter (N)
2820 * point_1
2821 * point_2
2822 * ...
2823 * point_N
2825 * sal: sal_i (before_orig_pos)
2826 * sal_j (stretch_factor)
2828 * uses: bci_ip_between_align_point
2831 unsigned char FPGM(bci_ip_between_align_points) [] =
2834 PUSHB_1,
2835 bci_ip_between_align_points,
2836 FDEF,
2838 PUSHB_2,
2841 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2842 CINDEX,
2843 DUP, /* s: ... before after before before */
2844 MDAP_noround, /* set rp0 and rp1 to `before' */
2845 DUP,
2846 GC_orig, /* s: ... before after before before_orig_pos */
2847 PUSHB_1,
2848 sal_i,
2849 SWAP,
2850 WS, /* sal_i = before_orig_pos */
2851 PUSHB_1,
2853 CINDEX, /* s: ... before after before after */
2854 MD_cur, /* a = after_pos - before_pos */
2855 ROLL,
2856 ROLL,
2857 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2859 DUP,
2860 IF, /* b != 0 ? */
2861 DIV, /* s: a/b */
2862 ELSE,
2863 POP, /* avoid division by zero */
2864 EIF,
2866 PUSHB_1,
2867 sal_j,
2868 SWAP,
2869 WS, /* sal_j = stretch_factor */
2871 PUSHB_3,
2872 bci_ip_between_align_point,
2875 SZP2, /* set zp2 to normal zone 1 */
2876 SZP1, /* set zp1 to normal zone 1 */
2877 LOOPCALL,
2879 ENDF,
2885 * bci_action_ip_before
2887 * Handle `ip_before' data to align points located before the first edge.
2889 * in: first_edge (in twilight zone)
2890 * loop_counter (N)
2891 * point_1
2892 * point_2
2893 * ...
2894 * point_N
2896 * sal: sal_i (first_edge_orig_pos)
2898 * uses: bci_ip_outer_align_point
2901 unsigned char FPGM(bci_action_ip_before) [] =
2904 PUSHB_1,
2905 bci_action_ip_before,
2906 FDEF,
2908 PUSHB_1,
2910 SZP2, /* set zp2 to twilight zone 0 */
2912 DUP,
2913 GC_orig,
2914 PUSHB_1,
2915 sal_i,
2916 SWAP,
2917 WS, /* sal_i = first_edge_orig_pos */
2919 PUSHB_3,
2923 SZP2, /* set zp2 to normal zone 1 */
2924 SZP1, /* set zp1 to normal zone 1 */
2925 SZP0, /* set zp0 to twilight zone 0 */
2927 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2929 PUSHB_1,
2930 bci_ip_outer_align_point,
2931 LOOPCALL,
2933 ENDF,
2939 * bci_action_ip_after
2941 * Handle `ip_after' data to align points located after the last edge.
2943 * in: last_edge (in twilight zone)
2944 * loop_counter (N)
2945 * point_1
2946 * point_2
2947 * ...
2948 * point_N
2950 * sal: sal_i (last_edge_orig_pos)
2952 * uses: bci_ip_outer_align_point
2955 unsigned char FPGM(bci_action_ip_after) [] =
2958 PUSHB_1,
2959 bci_action_ip_after,
2960 FDEF,
2962 PUSHB_1,
2964 SZP2, /* set zp2 to twilight zone 0 */
2966 DUP,
2967 GC_orig,
2968 PUSHB_1,
2969 sal_i,
2970 SWAP,
2971 WS, /* sal_i = last_edge_orig_pos */
2973 PUSHB_3,
2977 SZP2, /* set zp2 to normal zone 1 */
2978 SZP1, /* set zp1 to normal zone 1 */
2979 SZP0, /* set zp0 to twilight zone 0 */
2981 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2983 PUSHB_1,
2984 bci_ip_outer_align_point,
2985 LOOPCALL,
2987 ENDF,
2993 * bci_action_ip_on
2995 * Handle `ip_on' data to align points located on an edge coordinate (but
2996 * not part of an edge).
2998 * in: loop_counter (M)
2999 * edge_1 (in twilight zone)
3000 * loop_counter (N_1)
3001 * point_1
3002 * point_2
3003 * ...
3004 * point_N_1
3005 * edge_2 (in twilight zone)
3006 * loop_counter (N_2)
3007 * point_1
3008 * point_2
3009 * ...
3010 * point_N_2
3011 * ...
3012 * edge_M (in twilight zone)
3013 * loop_counter (N_M)
3014 * point_1
3015 * point_2
3016 * ...
3017 * point_N_M
3019 * uses: bci_ip_on_align_points
3022 unsigned char FPGM(bci_action_ip_on) [] =
3025 PUSHB_1,
3026 bci_action_ip_on,
3027 FDEF,
3029 PUSHB_2,
3032 SZP1, /* set zp1 to normal zone 1 */
3033 SZP0, /* set zp0 to twilight zone 0 */
3035 PUSHB_1,
3036 bci_ip_on_align_points,
3037 LOOPCALL,
3039 ENDF,
3045 * bci_action_ip_between
3047 * Handle `ip_between' data to align points located between two edges.
3049 * in: loop_counter (M)
3050 * before_edge_1 (in twilight zone)
3051 * after_edge_1 (in twilight zone)
3052 * loop_counter (N_1)
3053 * point_1
3054 * point_2
3055 * ...
3056 * point_N_1
3057 * before_edge_2 (in twilight zone)
3058 * after_edge_2 (in twilight zone)
3059 * loop_counter (N_2)
3060 * point_1
3061 * point_2
3062 * ...
3063 * point_N_2
3064 * ...
3065 * before_edge_M (in twilight zone)
3066 * after_edge_M (in twilight zone)
3067 * loop_counter (N_M)
3068 * point_1
3069 * point_2
3070 * ...
3071 * point_N_M
3073 * uses: bci_ip_between_align_points
3076 unsigned char FPGM(bci_action_ip_between) [] =
3079 PUSHB_1,
3080 bci_action_ip_between,
3081 FDEF,
3083 PUSHB_1,
3084 bci_ip_between_align_points,
3085 LOOPCALL,
3087 ENDF,
3093 * bci_adjust_common
3095 * Common code for bci_action_adjust routines.
3097 * uses: func[sal_stem_width_function]
3100 unsigned char FPGM(bci_adjust_common) [] =
3103 PUSHB_1,
3104 bci_adjust_common,
3105 FDEF,
3107 PUSHB_1,
3109 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3111 PUSHB_1,
3113 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3114 PUSHB_1,
3116 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3117 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3119 PUSHB_1,
3120 sal_stem_width_function,
3122 CALL,
3123 NEG, /* s: [...] edge2 edge -cur_len */
3125 ROLL, /* s: [...] edge -cur_len edge2 */
3126 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3127 SWAP,
3128 DUP,
3129 DUP, /* s: [...] -cur_len edge edge edge */
3130 ALIGNRP, /* align `edge' with `edge2' */
3131 ROLL,
3132 SHPIX, /* shift `edge' by -cur_len */
3134 ENDF,
3140 * bci_adjust_bound
3142 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3143 * edge of the stem has already been moved, then moving it again if
3144 * necessary to stay bound.
3146 * in: edge2_is_serif
3147 * edge_is_round
3148 * edge_point (in twilight zone)
3149 * edge2_point (in twilight zone)
3150 * edge[-1] (in twilight zone)
3151 * ... stuff for bci_align_segments (edge) ...
3153 * uses: bci_adjust_common
3154 * bci_align_segments
3157 unsigned char FPGM(bci_adjust_bound) [] =
3160 PUSHB_1,
3161 bci_adjust_bound,
3162 FDEF,
3164 PUSHB_1,
3165 bci_adjust_common,
3166 CALL,
3168 SWAP, /* s: edge edge[-1] */
3169 DUP,
3170 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3171 GC_cur,
3172 PUSHB_1,
3174 CINDEX,
3175 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3176 GT, /* edge_pos < edge[-1]_pos */
3178 DUP,
3179 ALIGNRP, /* align `edge' to `edge[-1]' */
3180 EIF,
3182 MDAP_noround, /* set rp0 and rp1 to `edge' */
3184 PUSHB_2,
3185 bci_align_segments,
3187 SZP1, /* set zp1 to normal zone 1 */
3188 CALL,
3190 ENDF,
3196 * bci_action_adjust_bound
3197 * bci_action_adjust_bound_serif
3198 * bci_action_adjust_bound_round
3199 * bci_action_adjust_bound_round_serif
3201 * Higher-level routines for calling `bci_adjust_bound'.
3204 unsigned char FPGM(bci_action_adjust_bound) [] =
3207 PUSHB_1,
3208 bci_action_adjust_bound,
3209 FDEF,
3211 PUSHB_3,
3214 bci_adjust_bound,
3215 CALL,
3217 ENDF,
3221 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3224 PUSHB_1,
3225 bci_action_adjust_bound_serif,
3226 FDEF,
3228 PUSHB_3,
3231 bci_adjust_bound,
3232 CALL,
3234 ENDF,
3238 unsigned char FPGM(bci_action_adjust_bound_round) [] =
3241 PUSHB_1,
3242 bci_action_adjust_bound_round,
3243 FDEF,
3245 PUSHB_3,
3248 bci_adjust_bound,
3249 CALL,
3251 ENDF,
3255 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3258 PUSHB_1,
3259 bci_action_adjust_bound_round_serif,
3260 FDEF,
3262 PUSHB_3,
3265 bci_adjust_bound,
3266 CALL,
3268 ENDF,
3274 * bci_adjust
3276 * Handle the ADJUST action to align an edge of a stem if the other edge
3277 * of the stem has already been moved.
3279 * in: edge2_is_serif
3280 * edge_is_round
3281 * edge_point (in twilight zone)
3282 * edge2_point (in twilight zone)
3283 * ... stuff for bci_align_segments (edge) ...
3285 * uses: bci_adjust_common
3286 * bci_align_segments
3289 unsigned char FPGM(bci_adjust) [] =
3292 PUSHB_1,
3293 bci_adjust,
3294 FDEF,
3296 PUSHB_1,
3297 bci_adjust_common,
3298 CALL,
3300 MDAP_noround, /* set rp0 and rp1 to `edge' */
3302 PUSHB_2,
3303 bci_align_segments,
3305 SZP1, /* set zp1 to normal zone 1 */
3306 CALL,
3308 ENDF,
3314 * bci_action_adjust
3315 * bci_action_adjust_serif
3316 * bci_action_adjust_round
3317 * bci_action_adjust_round_serif
3319 * Higher-level routines for calling `bci_adjust'.
3322 unsigned char FPGM(bci_action_adjust) [] =
3325 PUSHB_1,
3326 bci_action_adjust,
3327 FDEF,
3329 PUSHB_3,
3332 bci_adjust,
3333 CALL,
3335 ENDF,
3339 unsigned char FPGM(bci_action_adjust_serif) [] =
3342 PUSHB_1,
3343 bci_action_adjust_serif,
3344 FDEF,
3346 PUSHB_3,
3349 bci_adjust,
3350 CALL,
3352 ENDF,
3356 unsigned char FPGM(bci_action_adjust_round) [] =
3359 PUSHB_1,
3360 bci_action_adjust_round,
3361 FDEF,
3363 PUSHB_3,
3366 bci_adjust,
3367 CALL,
3369 ENDF,
3373 unsigned char FPGM(bci_action_adjust_round_serif) [] =
3376 PUSHB_1,
3377 bci_action_adjust_round_serif,
3378 FDEF,
3380 PUSHB_3,
3383 bci_adjust,
3384 CALL,
3386 ENDF,
3392 * bci_stem_common
3394 * Common code for bci_action_stem routines.
3396 * sal: sal_anchor
3397 * sal_temp1
3398 * sal_temp2
3399 * sal_temp3
3401 * uses: func[sal_stem_width_function]
3402 * bci_round
3405 #undef sal_u_off
3406 #define sal_u_off sal_temp1
3407 #undef sal_d_off
3408 #define sal_d_off sal_temp2
3409 #undef sal_org_len
3410 #define sal_org_len sal_temp3
3411 #undef sal_edge2
3412 #define sal_edge2 sal_temp3
3414 unsigned char FPGM(bci_stem_common) [] =
3417 PUSHB_1,
3418 bci_stem_common,
3419 FDEF,
3421 PUSHB_1,
3423 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3425 PUSHB_1,
3427 CINDEX,
3428 PUSHB_1,
3430 CINDEX,
3431 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3432 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3434 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3435 DUP,
3436 PUSHB_1,
3437 sal_org_len,
3438 SWAP,
3441 PUSHB_1,
3442 sal_stem_width_function,
3444 CALL, /* s: [...] edge2 edge cur_len */
3446 DUP,
3447 PUSHB_1,
3449 LT, /* cur_len < 96 */
3451 DUP,
3452 PUSHB_1,
3454 LTEQ, /* cur_len <= 64 */
3456 PUSHB_4,
3457 sal_u_off,
3459 sal_d_off,
3462 ELSE,
3463 PUSHB_4,
3464 sal_u_off,
3466 sal_d_off,
3468 EIF,
3472 SWAP, /* s: [...] edge2 cur_len edge */
3473 DUP,
3474 PUSHB_1,
3475 sal_anchor,
3477 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3478 ROLL,
3479 SWAP,
3480 MD_orig_ZP2_0,
3481 SWAP,
3482 GC_cur,
3483 ADD, /* s: [...] edge2 cur_len edge org_pos */
3484 PUSHB_1,
3485 sal_org_len,
3487 DIV_BY_2,
3488 ADD, /* s: [...] edge2 cur_len edge org_center */
3490 DUP,
3491 PUSHB_1,
3492 bci_round,
3493 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3495 DUP,
3496 ROLL,
3497 ROLL,
3498 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3500 DUP,
3501 PUSHB_1,
3502 sal_u_off,
3504 ADD,
3505 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3507 SWAP,
3508 PUSHB_1,
3509 sal_d_off,
3511 SUB,
3512 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3514 LT, /* delta1 < delta2 */
3516 PUSHB_1,
3517 sal_u_off,
3519 SUB, /* cur_pos1 = cur_pos1 - u_off */
3521 ELSE,
3522 PUSHB_1,
3523 sal_d_off,
3525 ADD, /* cur_pos1 = cur_pos1 + d_off */
3526 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3528 PUSHB_1,
3530 CINDEX,
3531 DIV_BY_2,
3532 SUB, /* arg = cur_pos1 - cur_len/2 */
3534 SWAP, /* s: [...] edge2 cur_len arg edge */
3535 DUP,
3536 DUP,
3537 PUSHB_1,
3539 MINDEX,
3540 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3541 GC_cur,
3542 SUB,
3543 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3545 ELSE,
3546 SWAP, /* s: [...] edge2 cur_len edge */
3547 PUSHB_1,
3548 sal_anchor,
3550 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3551 PUSHB_1,
3553 CINDEX,
3554 PUSHB_1,
3555 sal_anchor,
3557 MD_orig_ZP2_0,
3558 ADD, /* s: [...] edge2 cur_len edge org_pos */
3560 DUP,
3561 PUSHB_1,
3562 sal_org_len,
3564 DIV_BY_2,
3565 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3567 SWAP,
3568 DUP,
3569 PUSHB_1,
3570 bci_round,
3571 CALL, /* cur_pos1 = ROUND(org_pos) */
3572 SWAP,
3573 PUSHB_1,
3574 sal_org_len,
3576 ADD,
3577 PUSHB_1,
3578 bci_round,
3579 CALL,
3580 PUSHB_1,
3582 CINDEX,
3583 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3585 PUSHB_1,
3587 CINDEX,
3588 DIV_BY_2,
3589 PUSHB_1,
3591 MINDEX,
3592 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3594 DUP,
3595 PUSHB_1,
3597 CINDEX,
3598 ADD,
3599 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3600 SWAP,
3601 PUSHB_1,
3603 CINDEX,
3604 ADD,
3605 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3606 LT, /* delta1 < delta2 */
3608 POP, /* arg = cur_pos1 */
3610 ELSE,
3611 SWAP,
3612 POP, /* arg = cur_pos2 */
3613 EIF, /* s: [...] edge2 cur_len edge arg */
3614 SWAP,
3615 DUP,
3616 DUP,
3617 PUSHB_1,
3619 MINDEX,
3620 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3621 GC_cur,
3622 SUB,
3623 SHPIX, /* edge = arg */
3624 EIF, /* s: [...] edge2 cur_len edge */
3626 ENDF,
3632 * bci_stem_bound
3634 * Handle the STEM action to align two edges of a stem, then moving one
3635 * edge again if necessary to stay bound.
3637 * The code after computing `cur_len' to shift `edge' and `edge2'
3638 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3640 * if cur_len < 96:
3641 * if cur_len < = 64:
3642 * u_off = 32
3643 * d_off = 32
3644 * else:
3645 * u_off = 38
3646 * d_off = 26
3648 * org_pos = anchor + (edge_orig - anchor_orig);
3649 * org_center = org_pos + org_len / 2;
3651 * cur_pos1 = ROUND(org_center)
3652 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3653 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3654 * if (delta1 < delta2):
3655 * cur_pos1 = cur_pos1 - u_off
3656 * else:
3657 * cur_pos1 = cur_pos1 + d_off
3659 * edge = cur_pos1 - cur_len / 2
3661 * else:
3662 * org_pos = anchor + (edge_orig - anchor_orig)
3663 * org_center = org_pos + org_len / 2;
3665 * cur_pos1 = ROUND(org_pos)
3666 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3667 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3668 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3670 * if (delta1 < delta2):
3671 * edge = cur_pos1
3672 * else:
3673 * edge = cur_pos2
3675 * edge2 = edge + cur_len
3677 * in: edge2_is_serif
3678 * edge_is_round
3679 * edge_point (in twilight zone)
3680 * edge2_point (in twilight zone)
3681 * edge[-1] (in twilight zone)
3682 * ... stuff for bci_align_segments (edge) ...
3683 * ... stuff for bci_align_segments (edge2)...
3685 * sal: sal_anchor
3686 * sal_temp1
3687 * sal_temp2
3688 * sal_temp3
3690 * uses: bci_stem_common
3691 * bci_align_segments
3694 unsigned char FPGM(bci_stem_bound) [] =
3697 PUSHB_1,
3698 bci_stem_bound,
3699 FDEF,
3701 PUSHB_1,
3702 bci_stem_common,
3703 CALL,
3705 ROLL, /* s: edge[-1] cur_len edge edge2 */
3706 DUP,
3707 DUP,
3708 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3709 PUSHB_1,
3710 sal_edge2,
3711 SWAP,
3712 WS, /* s: edge[-1] cur_len edge edge2 */
3713 ROLL,
3714 SHPIX, /* edge2 = edge + cur_len */
3716 SWAP, /* s: edge edge[-1] */
3717 DUP,
3718 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3719 GC_cur,
3720 PUSHB_1,
3722 CINDEX,
3723 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3724 GT, /* edge_pos < edge[-1]_pos */
3726 DUP,
3727 ALIGNRP, /* align `edge' to `edge[-1]' */
3728 EIF,
3730 MDAP_noround, /* set rp0 and rp1 to `edge' */
3732 PUSHB_2,
3733 bci_align_segments,
3735 SZP1, /* set zp1 to normal zone 1 */
3736 CALL,
3738 PUSHB_1,
3739 sal_edge2,
3741 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3743 PUSHB_1,
3744 bci_align_segments,
3745 CALL,
3747 ENDF,
3753 * bci_action_stem_bound
3754 * bci_action_stem_bound_serif
3755 * bci_action_stem_bound_round
3756 * bci_action_stem_bound_round_serif
3758 * Higher-level routines for calling `bci_stem_bound'.
3761 unsigned char FPGM(bci_action_stem_bound) [] =
3764 PUSHB_1,
3765 bci_action_stem_bound,
3766 FDEF,
3768 PUSHB_3,
3771 bci_stem_bound,
3772 CALL,
3774 ENDF,
3778 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3781 PUSHB_1,
3782 bci_action_stem_bound_serif,
3783 FDEF,
3785 PUSHB_3,
3788 bci_stem_bound,
3789 CALL,
3791 ENDF,
3795 unsigned char FPGM(bci_action_stem_bound_round) [] =
3798 PUSHB_1,
3799 bci_action_stem_bound_round,
3800 FDEF,
3802 PUSHB_3,
3805 bci_stem_bound,
3806 CALL,
3808 ENDF,
3812 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3815 PUSHB_1,
3816 bci_action_stem_bound_round_serif,
3817 FDEF,
3819 PUSHB_3,
3822 bci_stem_bound,
3823 CALL,
3825 ENDF,
3831 * bci_stem
3833 * Handle the STEM action to align two edges of a stem.
3835 * See `bci_stem_bound' for more details.
3837 * in: edge2_is_serif
3838 * edge_is_round
3839 * edge_point (in twilight zone)
3840 * edge2_point (in twilight zone)
3841 * ... stuff for bci_align_segments (edge) ...
3842 * ... stuff for bci_align_segments (edge2)...
3844 * sal: sal_anchor
3845 * sal_temp1
3846 * sal_temp2
3847 * sal_temp3
3849 * uses: bci_stem_common
3850 * bci_align_segments
3853 unsigned char FPGM(bci_stem) [] =
3856 PUSHB_1,
3857 bci_stem,
3858 FDEF,
3860 PUSHB_1,
3861 bci_stem_common,
3862 CALL,
3864 POP,
3865 SWAP, /* s: cur_len edge2 */
3866 DUP,
3867 DUP,
3868 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3869 PUSHB_1,
3870 sal_edge2,
3871 SWAP,
3872 WS, /* s: cur_len edge2 */
3873 SWAP,
3874 SHPIX, /* edge2 = edge + cur_len */
3876 PUSHB_2,
3877 bci_align_segments,
3879 SZP1, /* set zp1 to normal zone 1 */
3880 CALL,
3882 PUSHB_1,
3883 sal_edge2,
3885 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3887 PUSHB_1,
3888 bci_align_segments,
3889 CALL,
3890 ENDF,
3896 * bci_action_stem
3897 * bci_action_stem_serif
3898 * bci_action_stem_round
3899 * bci_action_stem_round_serif
3901 * Higher-level routines for calling `bci_stem'.
3904 unsigned char FPGM(bci_action_stem) [] =
3907 PUSHB_1,
3908 bci_action_stem,
3909 FDEF,
3911 PUSHB_3,
3914 bci_stem,
3915 CALL,
3917 ENDF,
3921 unsigned char FPGM(bci_action_stem_serif) [] =
3924 PUSHB_1,
3925 bci_action_stem_serif,
3926 FDEF,
3928 PUSHB_3,
3931 bci_stem,
3932 CALL,
3934 ENDF,
3938 unsigned char FPGM(bci_action_stem_round) [] =
3941 PUSHB_1,
3942 bci_action_stem_round,
3943 FDEF,
3945 PUSHB_3,
3948 bci_stem,
3949 CALL,
3951 ENDF,
3955 unsigned char FPGM(bci_action_stem_round_serif) [] =
3958 PUSHB_1,
3959 bci_action_stem_round_serif,
3960 FDEF,
3962 PUSHB_3,
3965 bci_stem,
3966 CALL,
3968 ENDF,
3974 * bci_link
3976 * Handle the LINK action to link an edge to another one.
3978 * in: stem_is_serif
3979 * base_is_round
3980 * base_point (in twilight zone)
3981 * stem_point (in twilight zone)
3982 * ... stuff for bci_align_segments (base) ...
3984 * uses: func[sal_stem_width_function]
3985 * bci_align_segments
3988 unsigned char FPGM(bci_link) [] =
3991 PUSHB_1,
3992 bci_link,
3993 FDEF,
3995 PUSHB_1,
3997 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3999 PUSHB_1,
4001 CINDEX,
4002 PUSHB_1,
4004 MINDEX,
4005 DUP, /* s: stem is_round is_serif stem base base */
4006 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4008 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4010 PUSHB_1,
4011 sal_stem_width_function,
4013 CALL, /* s: stem new_dist */
4015 SWAP,
4016 DUP,
4017 ALIGNRP, /* align `stem_point' with `base_point' */
4018 DUP,
4019 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4020 SWAP,
4021 SHPIX, /* stem_point = base_point + new_dist */
4023 PUSHB_2,
4024 bci_align_segments,
4026 SZP1, /* set zp1 to normal zone 1 */
4027 CALL,
4029 ENDF,
4035 * bci_action_link
4036 * bci_action_link_serif
4037 * bci_action_link_round
4038 * bci_action_link_round_serif
4040 * Higher-level routines for calling `bci_link'.
4043 unsigned char FPGM(bci_action_link) [] =
4046 PUSHB_1,
4047 bci_action_link,
4048 FDEF,
4050 PUSHB_3,
4053 bci_link,
4054 CALL,
4056 ENDF,
4060 unsigned char FPGM(bci_action_link_serif) [] =
4063 PUSHB_1,
4064 bci_action_link_serif,
4065 FDEF,
4067 PUSHB_3,
4070 bci_link,
4071 CALL,
4073 ENDF,
4077 unsigned char FPGM(bci_action_link_round) [] =
4080 PUSHB_1,
4081 bci_action_link_round,
4082 FDEF,
4084 PUSHB_3,
4087 bci_link,
4088 CALL,
4090 ENDF,
4094 unsigned char FPGM(bci_action_link_round_serif) [] =
4097 PUSHB_1,
4098 bci_action_link_round_serif,
4099 FDEF,
4101 PUSHB_3,
4104 bci_link,
4105 CALL,
4107 ENDF,
4113 * bci_anchor
4115 * Handle the ANCHOR action to align two edges
4116 * and to set the edge anchor.
4118 * The code after computing `cur_len' to shift `edge' and `edge2'
4119 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4121 * if cur_len < 96:
4122 * if cur_len < = 64:
4123 * u_off = 32
4124 * d_off = 32
4125 * else:
4126 * u_off = 38
4127 * d_off = 26
4129 * org_center = edge_orig + org_len / 2
4130 * cur_pos1 = ROUND(org_center)
4132 * error1 = ABS(org_center - (cur_pos1 - u_off))
4133 * error2 = ABS(org_center - (cur_pos1 + d_off))
4134 * if (error1 < error2):
4135 * cur_pos1 = cur_pos1 - u_off
4136 * else:
4137 * cur_pos1 = cur_pos1 + d_off
4139 * edge = cur_pos1 - cur_len / 2
4140 * edge2 = edge + cur_len
4142 * else:
4143 * edge = ROUND(edge_orig)
4145 * in: edge2_is_serif
4146 * edge_is_round
4147 * edge_point (in twilight zone)
4148 * edge2_point (in twilight zone)
4149 * ... stuff for bci_align_segments (edge) ...
4151 * sal: sal_anchor
4152 * sal_temp1
4153 * sal_temp2
4154 * sal_temp3
4156 * uses: func[sal_stem_width_function]
4157 * bci_round
4158 * bci_align_segments
4161 #undef sal_u_off
4162 #define sal_u_off sal_temp1
4163 #undef sal_d_off
4164 #define sal_d_off sal_temp2
4165 #undef sal_org_len
4166 #define sal_org_len sal_temp3
4168 unsigned char FPGM(bci_anchor) [] =
4171 PUSHB_1,
4172 bci_anchor,
4173 FDEF,
4175 /* store anchor point number in `sal_anchor' */
4176 PUSHB_2,
4177 sal_anchor,
4179 CINDEX,
4180 WS, /* sal_anchor = edge_point */
4182 PUSHB_1,
4184 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4186 PUSHB_1,
4188 CINDEX,
4189 PUSHB_1,
4191 CINDEX,
4192 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4193 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4195 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4196 DUP,
4197 PUSHB_1,
4198 sal_org_len,
4199 SWAP,
4202 PUSHB_1,
4203 sal_stem_width_function,
4205 CALL, /* s: edge2 edge cur_len */
4207 DUP,
4208 PUSHB_1,
4210 LT, /* cur_len < 96 */
4212 DUP,
4213 PUSHB_1,
4215 LTEQ, /* cur_len <= 64 */
4217 PUSHB_4,
4218 sal_u_off,
4220 sal_d_off,
4223 ELSE,
4224 PUSHB_4,
4225 sal_u_off,
4227 sal_d_off,
4229 EIF,
4233 SWAP, /* s: edge2 cur_len edge */
4234 DUP, /* s: edge2 cur_len edge edge */
4236 GC_orig,
4237 PUSHB_1,
4238 sal_org_len,
4240 DIV_BY_2,
4241 ADD, /* s: edge2 cur_len edge org_center */
4243 DUP,
4244 PUSHB_1,
4245 bci_round,
4246 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4248 DUP,
4249 ROLL,
4250 ROLL,
4251 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4253 DUP,
4254 PUSHB_1,
4255 sal_u_off,
4257 ADD,
4258 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4260 SWAP,
4261 PUSHB_1,
4262 sal_d_off,
4264 SUB,
4265 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4267 LT, /* error1 < error2 */
4269 PUSHB_1,
4270 sal_u_off,
4272 SUB, /* cur_pos1 = cur_pos1 - u_off */
4274 ELSE,
4275 PUSHB_1,
4276 sal_d_off,
4278 ADD, /* cur_pos1 = cur_pos1 + d_off */
4279 EIF, /* s: edge2 cur_len edge cur_pos1 */
4281 PUSHB_1,
4283 CINDEX,
4284 DIV_BY_2,
4285 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4287 PUSHB_1,
4289 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4290 GC_cur,
4291 SUB,
4292 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4294 SWAP, /* s: cur_len edge2 */
4295 DUP,
4296 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4297 SWAP,
4298 SHPIX, /* edge2 = edge1 + cur_len */
4300 ELSE,
4301 POP, /* s: edge2 edge */
4302 DUP,
4303 DUP,
4304 GC_cur,
4305 SWAP,
4306 GC_orig,
4307 PUSHB_1,
4308 bci_round,
4309 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4310 SWAP,
4311 SUB,
4312 SHPIX, /* edge = round(edge_orig) */
4314 /* clean up stack */
4315 POP,
4316 EIF,
4318 PUSHB_2,
4319 bci_align_segments,
4321 SZP1, /* set zp1 to normal zone 1 */
4322 CALL,
4324 ENDF,
4330 * bci_action_anchor
4331 * bci_action_anchor_serif
4332 * bci_action_anchor_round
4333 * bci_action_anchor_round_serif
4335 * Higher-level routines for calling `bci_anchor'.
4338 unsigned char FPGM(bci_action_anchor) [] =
4341 PUSHB_1,
4342 bci_action_anchor,
4343 FDEF,
4345 PUSHB_3,
4348 bci_anchor,
4349 CALL,
4351 ENDF,
4355 unsigned char FPGM(bci_action_anchor_serif) [] =
4358 PUSHB_1,
4359 bci_action_anchor_serif,
4360 FDEF,
4362 PUSHB_3,
4365 bci_anchor,
4366 CALL,
4368 ENDF,
4372 unsigned char FPGM(bci_action_anchor_round) [] =
4375 PUSHB_1,
4376 bci_action_anchor_round,
4377 FDEF,
4379 PUSHB_3,
4382 bci_anchor,
4383 CALL,
4385 ENDF,
4389 unsigned char FPGM(bci_action_anchor_round_serif) [] =
4392 PUSHB_1,
4393 bci_action_anchor_round_serif,
4394 FDEF,
4396 PUSHB_3,
4399 bci_anchor,
4400 CALL,
4402 ENDF,
4408 * bci_action_blue_anchor
4410 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4411 * and to set the edge anchor.
4413 * in: anchor_point (in twilight zone)
4414 * blue_cvt_idx
4415 * edge_point (in twilight zone)
4416 * ... stuff for bci_align_segments (edge) ...
4418 * sal: sal_anchor
4420 * uses: bci_action_blue
4423 unsigned char FPGM(bci_action_blue_anchor) [] =
4426 PUSHB_1,
4427 bci_action_blue_anchor,
4428 FDEF,
4430 /* store anchor point number in `sal_anchor' */
4431 PUSHB_1,
4432 sal_anchor,
4433 SWAP,
4436 PUSHB_1,
4437 bci_action_blue,
4438 CALL,
4440 ENDF,
4446 * bci_action_blue
4448 * Handle the BLUE action to align an edge with a blue zone.
4450 * in: blue_cvt_idx
4451 * edge_point (in twilight zone)
4452 * ... stuff for bci_align_segments (edge) ...
4454 * uses: bci_align_segments
4457 unsigned char FPGM(bci_action_blue) [] =
4460 PUSHB_1,
4461 bci_action_blue,
4462 FDEF,
4464 PUSHB_1,
4466 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4468 /* move `edge_point' to `blue_cvt_idx' position; */
4469 /* note that we can't use MIAP since this would modify */
4470 /* the twilight point's original coordinates also */
4471 RCVT,
4472 SWAP,
4473 DUP,
4474 MDAP_noround, /* set rp0 and rp1 to `edge' */
4475 DUP,
4476 GC_cur, /* s: new_pos edge edge_pos */
4477 ROLL,
4478 SWAP,
4479 SUB, /* s: edge (new_pos - edge_pos) */
4480 SHPIX,
4482 PUSHB_2,
4483 bci_align_segments,
4485 SZP1, /* set zp1 to normal zone 1 */
4486 CALL,
4488 ENDF,
4494 * bci_serif_common
4496 * Common code for bci_action_serif routines.
4499 unsigned char FPGM(bci_serif_common) [] =
4502 PUSHB_1,
4503 bci_serif_common,
4504 FDEF,
4506 PUSHB_1,
4508 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4510 DUP,
4511 DUP,
4512 DUP,
4513 PUSHB_1,
4515 MINDEX, /* s: [...] serif serif serif serif base */
4516 DUP,
4517 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4518 MD_orig_ZP2_0,
4519 SWAP,
4520 ALIGNRP, /* align `serif_point' with `base_point' */
4521 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4523 ENDF,
4529 * bci_lower_bound
4531 * Move an edge if necessary to stay within a lower bound.
4533 * in: edge
4534 * bound
4536 * uses: bci_align_segments
4539 unsigned char FPGM(bci_lower_bound) [] =
4542 PUSHB_1,
4543 bci_lower_bound,
4544 FDEF,
4546 SWAP, /* s: edge bound */
4547 DUP,
4548 MDAP_noround, /* set rp0 and rp1 to `bound' */
4549 GC_cur,
4550 PUSHB_1,
4552 CINDEX,
4553 GC_cur, /* s: edge bound_pos edge_pos */
4554 GT, /* edge_pos < bound_pos */
4556 DUP,
4557 ALIGNRP, /* align `edge' to `bound' */
4558 EIF,
4560 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4562 PUSHB_2,
4563 bci_align_segments,
4565 SZP1, /* set zp1 to normal zone 1 */
4566 CALL,
4568 ENDF,
4574 * bci_upper_bound
4576 * Move an edge if necessary to stay within an upper bound.
4578 * in: edge
4579 * bound
4581 * uses: bci_align_segments
4584 unsigned char FPGM(bci_upper_bound) [] =
4587 PUSHB_1,
4588 bci_upper_bound,
4589 FDEF,
4591 SWAP, /* s: edge bound */
4592 DUP,
4593 MDAP_noround, /* set rp0 and rp1 to `bound' */
4594 GC_cur,
4595 PUSHB_1,
4597 CINDEX,
4598 GC_cur, /* s: edge bound_pos edge_pos */
4599 LT, /* edge_pos > bound_pos */
4601 DUP,
4602 ALIGNRP, /* align `edge' to `bound' */
4603 EIF,
4605 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4607 PUSHB_2,
4608 bci_align_segments,
4610 SZP1, /* set zp1 to normal zone 1 */
4611 CALL,
4613 ENDF,
4619 * bci_upper_lower_bound
4621 * Move an edge if necessary to stay within a lower and lower bound.
4623 * in: edge
4624 * lower
4625 * upper
4627 * uses: bci_align_segments
4630 unsigned char FPGM(bci_upper_lower_bound) [] =
4633 PUSHB_1,
4634 bci_upper_lower_bound,
4635 FDEF,
4637 SWAP, /* s: upper serif lower */
4638 DUP,
4639 MDAP_noround, /* set rp0 and rp1 to `lower' */
4640 GC_cur,
4641 PUSHB_1,
4643 CINDEX,
4644 GC_cur, /* s: upper serif lower_pos serif_pos */
4645 GT, /* serif_pos < lower_pos */
4647 DUP,
4648 ALIGNRP, /* align `serif' to `lower' */
4649 EIF,
4651 SWAP, /* s: serif upper */
4652 DUP,
4653 MDAP_noround, /* set rp0 and rp1 to `upper' */
4654 GC_cur,
4655 PUSHB_1,
4657 CINDEX,
4658 GC_cur, /* s: serif upper_pos serif_pos */
4659 LT, /* serif_pos > upper_pos */
4661 DUP,
4662 ALIGNRP, /* align `serif' to `upper' */
4663 EIF,
4665 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4667 PUSHB_2,
4668 bci_align_segments,
4670 SZP1, /* set zp1 to normal zone 1 */
4671 CALL,
4673 ENDF,
4679 * bci_action_serif
4681 * Handle the SERIF action to align a serif with its base.
4683 * in: serif_point (in twilight zone)
4684 * base_point (in twilight zone)
4685 * ... stuff for bci_align_segments (serif) ...
4687 * uses: bci_serif_common
4688 * bci_align_segments
4691 unsigned char FPGM(bci_action_serif) [] =
4694 PUSHB_1,
4695 bci_action_serif,
4696 FDEF,
4698 PUSHB_1,
4699 bci_serif_common,
4700 CALL,
4702 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4704 PUSHB_2,
4705 bci_align_segments,
4707 SZP1, /* set zp1 to normal zone 1 */
4708 CALL,
4710 ENDF,
4716 * bci_action_serif_lower_bound
4718 * Handle the SERIF action to align a serif with its base, then moving it
4719 * again if necessary to stay within a lower bound.
4721 * in: serif_point (in twilight zone)
4722 * base_point (in twilight zone)
4723 * edge[-1] (in twilight zone)
4724 * ... stuff for bci_align_segments (serif) ...
4726 * uses: bci_serif_common
4727 * bci_lower_bound
4730 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4733 PUSHB_1,
4734 bci_action_serif_lower_bound,
4735 FDEF,
4737 PUSHB_1,
4738 bci_serif_common,
4739 CALL,
4741 PUSHB_1,
4742 bci_lower_bound,
4743 CALL,
4745 ENDF,
4751 * bci_action_serif_upper_bound
4753 * Handle the SERIF action to align a serif with its base, then moving it
4754 * again if necessary to stay within an upper bound.
4756 * in: serif_point (in twilight zone)
4757 * base_point (in twilight zone)
4758 * edge[1] (in twilight zone)
4759 * ... stuff for bci_align_segments (serif) ...
4761 * uses: bci_serif_common
4762 * bci_upper_bound
4765 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4768 PUSHB_1,
4769 bci_action_serif_upper_bound,
4770 FDEF,
4772 PUSHB_1,
4773 bci_serif_common,
4774 CALL,
4776 PUSHB_1,
4777 bci_upper_bound,
4778 CALL,
4780 ENDF,
4786 * bci_action_serif_upper_lower_bound
4788 * Handle the SERIF action to align a serif with its base, then moving it
4789 * again if necessary to stay within a lower and upper bound.
4791 * in: serif_point (in twilight zone)
4792 * base_point (in twilight zone)
4793 * edge[-1] (in twilight zone)
4794 * edge[1] (in twilight zone)
4795 * ... stuff for bci_align_segments (serif) ...
4797 * uses: bci_serif_common
4798 * bci_upper_lower_bound
4801 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4804 PUSHB_1,
4805 bci_action_serif_upper_lower_bound,
4806 FDEF,
4808 PUSHB_1,
4810 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4812 PUSHB_1,
4813 bci_serif_common,
4814 CALL,
4816 PUSHB_1,
4817 bci_upper_lower_bound,
4818 CALL,
4820 ENDF,
4826 * bci_serif_anchor_common
4828 * Common code for bci_action_serif_anchor routines.
4830 * sal: sal_anchor
4832 * uses: bci_round
4835 unsigned char FPGM(bci_serif_anchor_common) [] =
4838 PUSHB_1,
4839 bci_serif_anchor_common,
4840 FDEF,
4842 PUSHB_1,
4844 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4846 DUP,
4847 PUSHB_1,
4848 sal_anchor,
4849 SWAP,
4850 WS, /* sal_anchor = edge_point */
4852 DUP,
4853 DUP,
4854 DUP,
4855 GC_cur,
4856 SWAP,
4857 GC_orig,
4858 PUSHB_1,
4859 bci_round,
4860 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4861 SWAP,
4862 SUB,
4863 SHPIX, /* edge = round(edge_orig) */
4865 ENDF,
4871 * bci_action_serif_anchor
4873 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4874 * anchor.
4876 * in: edge_point (in twilight zone)
4877 * ... stuff for bci_align_segments (edge) ...
4879 * uses: bci_serif_anchor_common
4880 * bci_align_segments
4883 unsigned char FPGM(bci_action_serif_anchor) [] =
4886 PUSHB_1,
4887 bci_action_serif_anchor,
4888 FDEF,
4890 PUSHB_1,
4891 bci_serif_anchor_common,
4892 CALL,
4894 MDAP_noround, /* set rp0 and rp1 to `edge' */
4896 PUSHB_2,
4897 bci_align_segments,
4899 SZP1, /* set zp1 to normal zone 1 */
4900 CALL,
4902 ENDF,
4908 * bci_action_serif_anchor_lower_bound
4910 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4911 * anchor, then moving it again if necessary to stay within a lower
4912 * bound.
4914 * in: edge_point (in twilight zone)
4915 * edge[-1] (in twilight zone)
4916 * ... stuff for bci_align_segments (edge) ...
4918 * uses: bci_serif_anchor_common
4919 * bci_lower_bound
4922 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4925 PUSHB_1,
4926 bci_action_serif_anchor_lower_bound,
4927 FDEF,
4929 PUSHB_1,
4930 bci_serif_anchor_common,
4931 CALL,
4933 PUSHB_1,
4934 bci_lower_bound,
4935 CALL,
4937 ENDF,
4943 * bci_action_serif_anchor_upper_bound
4945 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4946 * anchor, then moving it again if necessary to stay within an upper
4947 * bound.
4949 * in: edge_point (in twilight zone)
4950 * edge[1] (in twilight zone)
4951 * ... stuff for bci_align_segments (edge) ...
4953 * uses: bci_serif_anchor_common
4954 * bci_upper_bound
4957 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4960 PUSHB_1,
4961 bci_action_serif_anchor_upper_bound,
4962 FDEF,
4964 PUSHB_1,
4965 bci_serif_anchor_common,
4966 CALL,
4968 PUSHB_1,
4969 bci_upper_bound,
4970 CALL,
4972 ENDF,
4978 * bci_action_serif_anchor_upper_lower_bound
4980 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4981 * anchor, then moving it again if necessary to stay within a lower and
4982 * upper bound.
4984 * in: edge_point (in twilight zone)
4985 * edge[-1] (in twilight zone)
4986 * edge[1] (in twilight zone)
4987 * ... stuff for bci_align_segments (edge) ...
4989 * uses: bci_serif_anchor_common
4990 * bci_upper_lower_bound
4993 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4996 PUSHB_1,
4997 bci_action_serif_anchor_upper_lower_bound,
4998 FDEF,
5000 PUSHB_1,
5001 bci_serif_anchor_common,
5002 CALL,
5004 PUSHB_1,
5005 bci_upper_lower_bound,
5006 CALL,
5008 ENDF,
5014 * bci_serif_link1_common
5016 * Common code for bci_action_serif_link1 routines.
5019 unsigned char FPGM(bci_serif_link1_common) [] =
5022 PUSHB_1,
5023 bci_serif_link1_common,
5024 FDEF,
5026 PUSHB_1,
5028 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5030 PUSHB_1,
5032 CINDEX, /* s: [...] after edge before after */
5033 PUSHB_1,
5035 CINDEX, /* s: [...] after edge before after before */
5036 MD_orig_ZP2_0,
5037 PUSHB_1,
5039 EQ, /* after_orig_pos == before_orig_pos */
5040 IF, /* s: [...] after edge before */
5041 MDAP_noround, /* set rp0 and rp1 to `before' */
5042 DUP,
5043 ALIGNRP, /* align `edge' with `before' */
5044 SWAP,
5045 POP,
5047 ELSE,
5048 /* we have to execute `a*b/c', with b/c very near to 1: */
5049 /* to avoid overflow while retaining precision, */
5050 /* we transform this to `a + a * (b-c)/c' */
5052 PUSHB_1,
5054 CINDEX, /* s: [...] after edge before edge */
5055 PUSHB_1,
5057 CINDEX, /* s: [...] after edge before edge before */
5058 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
5060 DUP,
5061 PUSHB_1,
5063 CINDEX, /* s: [...] after edge before a a after */
5064 PUSHB_1,
5066 CINDEX, /* s: [...] after edge before a a after before */
5067 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
5069 PUSHB_1,
5071 CINDEX, /* s: [...] after edge before a a c after */
5072 PUSHB_1,
5074 CINDEX, /* s: [...] after edge before a a c after before */
5075 MD_cur, /* b = after_pos - before_pos */
5077 PUSHB_1,
5079 CINDEX, /* s: [...] after edge before a a c b c */
5080 SUB, /* b-c */
5082 PUSHW_2,
5083 0x08, /* 0x800 */
5084 0x00,
5085 0x08, /* 0x800 */
5086 0x00,
5087 MUL, /* 0x10000 */
5088 MUL, /* (b-c) in 16.16 format */
5089 SWAP,
5091 DUP,
5092 IF, /* c != 0 ? */
5093 DIV, /* s: [...] after edge before a a (b-c)/c */
5094 ELSE,
5095 POP, /* avoid division by zero */
5096 EIF,
5098 MUL, /* a * (b-c)/c * 2^10 */
5099 DIV_BY_1024, /* a * (b-c)/c */
5100 ADD, /* a*b/c */
5102 SWAP,
5103 MDAP_noround, /* set rp0 and rp1 to `before' */
5104 SWAP, /* s: [...] after a*b/c edge */
5105 DUP,
5106 DUP,
5107 ALIGNRP, /* align `edge' with `before' */
5108 ROLL,
5109 SHPIX, /* shift `edge' by `a*b/c' */
5111 SWAP, /* s: [...] edge after */
5112 POP,
5113 EIF,
5115 ENDF,
5121 * bci_action_serif_link1
5123 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5124 * before and after.
5126 * in: before_point (in twilight zone)
5127 * edge_point (in twilight zone)
5128 * after_point (in twilight zone)
5129 * ... stuff for bci_align_segments (edge) ...
5131 * uses: bci_serif_link1_common
5132 * bci_align_segments
5135 unsigned char FPGM(bci_action_serif_link1) [] =
5138 PUSHB_1,
5139 bci_action_serif_link1,
5140 FDEF,
5142 PUSHB_1,
5143 bci_serif_link1_common,
5144 CALL,
5146 MDAP_noround, /* set rp0 and rp1 to `edge' */
5148 PUSHB_2,
5149 bci_align_segments,
5151 SZP1, /* set zp1 to normal zone 1 */
5152 CALL,
5154 ENDF,
5160 * bci_action_serif_link1_lower_bound
5162 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5163 * before and after. Additionally, move the serif again if necessary to
5164 * stay within a lower bound.
5166 * in: before_point (in twilight zone)
5167 * edge_point (in twilight zone)
5168 * after_point (in twilight zone)
5169 * edge[-1] (in twilight zone)
5170 * ... stuff for bci_align_segments (edge) ...
5172 * uses: bci_serif_link1_common
5173 * bci_lower_bound
5176 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
5179 PUSHB_1,
5180 bci_action_serif_link1_lower_bound,
5181 FDEF,
5183 PUSHB_1,
5184 bci_serif_link1_common,
5185 CALL,
5187 PUSHB_1,
5188 bci_lower_bound,
5189 CALL,
5191 ENDF,
5197 * bci_action_serif_link1_upper_bound
5199 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5200 * before and after. Additionally, move the serif again if necessary to
5201 * stay within an upper bound.
5203 * in: before_point (in twilight zone)
5204 * edge_point (in twilight zone)
5205 * after_point (in twilight zone)
5206 * edge[1] (in twilight zone)
5207 * ... stuff for bci_align_segments (edge) ...
5209 * uses: bci_serif_link1_common
5210 * bci_upper_bound
5213 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
5216 PUSHB_1,
5217 bci_action_serif_link1_upper_bound,
5218 FDEF,
5220 PUSHB_1,
5221 bci_serif_link1_common,
5222 CALL,
5224 PUSHB_1,
5225 bci_upper_bound,
5226 CALL,
5228 ENDF,
5234 * bci_action_serif_link1_upper_lower_bound
5236 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5237 * before and after. Additionally, move the serif again if necessary to
5238 * stay within a lower and upper bound.
5240 * in: before_point (in twilight zone)
5241 * edge_point (in twilight zone)
5242 * after_point (in twilight zone)
5243 * edge[-1] (in twilight zone)
5244 * edge[1] (in twilight zone)
5245 * ... stuff for bci_align_segments (edge) ...
5247 * uses: bci_serif_link1_common
5248 * bci_upper_lower_bound
5251 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
5254 PUSHB_1,
5255 bci_action_serif_link1_upper_lower_bound,
5256 FDEF,
5258 PUSHB_1,
5259 bci_serif_link1_common,
5260 CALL,
5262 PUSHB_1,
5263 bci_upper_lower_bound,
5264 CALL,
5266 ENDF,
5272 * bci_serif_link2_common
5274 * Common code for bci_action_serif_link2 routines.
5276 * sal: sal_anchor
5279 unsigned char FPGM(bci_serif_link2_common) [] =
5282 PUSHB_1,
5283 bci_serif_link2_common,
5284 FDEF,
5286 PUSHB_1,
5288 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5290 DUP, /* s: [...] edge edge */
5291 PUSHB_1,
5292 sal_anchor,
5294 DUP, /* s: [...] edge edge anchor anchor */
5295 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
5297 MD_orig_ZP2_0,
5298 DUP,
5299 ADD,
5300 PUSHB_1,
5302 ADD,
5303 FLOOR,
5304 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5306 SWAP,
5307 DUP,
5308 DUP,
5309 ALIGNRP, /* align `edge' with `sal_anchor' */
5310 ROLL,
5311 SHPIX, /* shift `edge' by `delta' */
5313 ENDF,
5319 * bci_action_serif_link2
5321 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5323 * in: edge_point (in twilight zone)
5324 * ... stuff for bci_align_segments (edge) ...
5326 * uses: bci_serif_link2_common
5327 * bci_align_segments
5330 unsigned char FPGM(bci_action_serif_link2) [] =
5333 PUSHB_1,
5334 bci_action_serif_link2,
5335 FDEF,
5337 PUSHB_1,
5338 bci_serif_link2_common,
5339 CALL,
5341 MDAP_noround, /* set rp0 and rp1 to `edge' */
5343 PUSHB_2,
5344 bci_align_segments,
5346 SZP1, /* set zp1 to normal zone 1 */
5347 CALL,
5349 ENDF,
5355 * bci_action_serif_link2_lower_bound
5357 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5358 * Additionally, move the serif again if necessary to stay within a lower
5359 * bound.
5361 * in: edge_point (in twilight zone)
5362 * edge[-1] (in twilight zone)
5363 * ... stuff for bci_align_segments (edge) ...
5365 * uses: bci_serif_link2_common
5366 * bci_lower_bound
5369 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
5372 PUSHB_1,
5373 bci_action_serif_link2_lower_bound,
5374 FDEF,
5376 PUSHB_1,
5377 bci_serif_link2_common,
5378 CALL,
5380 PUSHB_1,
5381 bci_lower_bound,
5382 CALL,
5384 ENDF,
5390 * bci_action_serif_link2_upper_bound
5392 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5393 * Additionally, move the serif again if necessary to stay within an upper
5394 * bound.
5396 * in: edge_point (in twilight zone)
5397 * edge[1] (in twilight zone)
5398 * ... stuff for bci_align_segments (edge) ...
5400 * uses: bci_serif_link2_common
5401 * bci_upper_bound
5404 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
5407 PUSHB_1,
5408 bci_action_serif_link2_upper_bound,
5409 FDEF,
5411 PUSHB_1,
5412 bci_serif_link2_common,
5413 CALL,
5415 PUSHB_1,
5416 bci_upper_bound,
5417 CALL,
5419 ENDF,
5425 * bci_action_serif_link2_upper_lower_bound
5427 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5428 * Additionally, move the serif again if necessary to stay within a lower
5429 * and upper bound.
5431 * in: edge_point (in twilight zone)
5432 * edge[-1] (in twilight zone)
5433 * edge[1] (in twilight zone)
5434 * ... stuff for bci_align_segments (edge) ...
5436 * uses: bci_serif_link2_common
5437 * bci_upper_lower_bound
5440 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
5443 PUSHB_1,
5444 bci_action_serif_link2_upper_lower_bound,
5445 FDEF,
5447 PUSHB_1,
5448 bci_serif_link2_common,
5449 CALL,
5451 PUSHB_1,
5452 bci_upper_lower_bound,
5453 CALL,
5455 ENDF,
5461 * bci_hint_glyph
5463 * This is the top-level glyph hinting function which parses the arguments
5464 * on the stack and calls subroutines.
5466 * in: action_0_func_idx
5467 * ... data ...
5468 * action_1_func_idx
5469 * ... data ...
5470 * ...
5472 * CVT: cvtl_is_subglyph
5473 * cvtl_use_strong_functions
5475 * sal: sal_stem_width_function
5477 * uses: bci_action_ip_before
5478 * bci_action_ip_after
5479 * bci_action_ip_on
5480 * bci_action_ip_between
5482 * bci_action_adjust_bound
5483 * bci_action_adjust_bound_serif
5484 * bci_action_adjust_bound_round
5485 * bci_action_adjust_bound_round_serif
5487 * bci_action_stem_bound
5488 * bci_action_stem_bound_serif
5489 * bci_action_stem_bound_round
5490 * bci_action_stem_bound_round_serif
5492 * bci_action_link
5493 * bci_action_link_serif
5494 * bci_action_link_round
5495 * bci_action_link_round_serif
5497 * bci_action_anchor
5498 * bci_action_anchor_serif
5499 * bci_action_anchor_round
5500 * bci_action_anchor_round_serif
5502 * bci_action_blue_anchor
5504 * bci_action_adjust
5505 * bci_action_adjust_serif
5506 * bci_action_adjust_round
5507 * bci_action_adjust_round_serif
5509 * bci_action_stem
5510 * bci_action_stem_serif
5511 * bci_action_stem_round
5512 * bci_action_stem_round_serif
5514 * bci_action_blue
5516 * bci_action_serif
5517 * bci_action_serif_lower_bound
5518 * bci_action_serif_upper_bound
5519 * bci_action_serif_upper_lower_bound
5521 * bci_action_serif_anchor
5522 * bci_action_serif_anchor_lower_bound
5523 * bci_action_serif_anchor_upper_bound
5524 * bci_action_serif_anchor_upper_lower_bound
5526 * bci_action_serif_link1
5527 * bci_action_serif_link1_lower_bound
5528 * bci_action_serif_link1_upper_bound
5529 * bci_action_serif_link1_upper_lower_bound
5531 * bci_action_serif_link2
5532 * bci_action_serif_link2_lower_bound
5533 * bci_action_serif_link2_upper_bound
5534 * bci_action_serif_link2_upper_lower_bound
5537 unsigned char FPGM(bci_hint_glyph) [] =
5540 PUSHB_1,
5541 bci_hint_glyph,
5542 FDEF,
5544 /* set up stem width function based on flag in CVT */
5545 PUSHB_4,
5546 sal_stem_width_function,
5547 bci_strong_stem_width,
5548 bci_smooth_stem_width,
5549 cvtl_use_strong_functions,
5550 RCVT,
5552 POP,
5554 ELSE,
5555 SWAP,
5556 POP,
5558 EIF,
5561 /* start_loop: */
5562 /* loop until all data on stack is used */
5563 CALL,
5564 PUSHB_1,
5566 NEG,
5567 PUSHB_1,
5569 DEPTH,
5571 JROT, /* goto start_loop */
5573 PUSHB_1,
5575 SZP2, /* set zp2 to normal zone 1 */
5576 IUP_y,
5578 ENDF,
5583 #define COPY_FPGM(func_name) \
5584 do \
5586 memcpy(bufp, fpgm_ ## func_name, \
5587 sizeof (fpgm_ ## func_name)); \
5588 bufp += sizeof (fpgm_ ## func_name); \
5589 } while (0)
5591 static FT_Error
5592 TA_table_build_fpgm(FT_Byte** fpgm,
5593 FT_ULong* fpgm_len,
5594 SFNT* sfnt,
5595 FONT* font)
5597 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5598 glyf_Data* data = (glyf_Data*)glyf_table->data;
5600 FT_UInt buf_len;
5601 FT_UInt len;
5602 FT_Byte* buf;
5603 FT_Byte* bufp;
5606 /* for compatibility with dumb bytecode interpreters or analyzers, */
5607 /* FDEFs are stored in ascending index order, without holes -- */
5608 /* note that some FDEFs are not always needed */
5609 /* (depending on options of `TTFautohint'), */
5610 /* but implementing dynamic FDEF indices would be a lot of work */
5612 buf_len = sizeof (FPGM(bci_align_top_a))
5613 + (font->increase_x_height
5614 ? (sizeof (FPGM(bci_align_top_b1a))
5616 + sizeof (FPGM(bci_align_top_b1b)))
5617 : sizeof (FPGM(bci_align_top_b2)))
5618 + sizeof (FPGM(bci_align_top_c))
5619 + sizeof (FPGM(bci_round))
5620 + sizeof (FPGM(bci_smooth_stem_width))
5621 + sizeof (FPGM(bci_get_best_width))
5622 + sizeof (FPGM(bci_strong_stem_width_a))
5624 + sizeof (FPGM(bci_strong_stem_width_b))
5625 + sizeof (FPGM(bci_loop_do))
5626 + sizeof (FPGM(bci_loop))
5627 + sizeof (FPGM(bci_cvt_rescale))
5628 + sizeof (FPGM(bci_cvt_rescale_range))
5629 + sizeof (FPGM(bci_vwidth_data_store))
5630 + sizeof (FPGM(bci_smooth_blue_round))
5631 + sizeof (FPGM(bci_strong_blue_round))
5632 + sizeof (FPGM(bci_blue_round_range))
5633 + sizeof (FPGM(bci_decrement_component_counter))
5634 + sizeof (FPGM(bci_get_point_extrema))
5635 + sizeof (FPGM(bci_nibbles))
5636 + sizeof (FPGM(bci_number_set_is_element))
5637 + sizeof (FPGM(bci_number_set_is_element2))
5639 + sizeof (FPGM(bci_create_segment))
5640 + sizeof (FPGM(bci_create_segments_a))
5642 + sizeof (FPGM(bci_create_segments_b))
5644 + sizeof (FPGM(bci_create_segments_0))
5645 + sizeof (FPGM(bci_create_segments_1))
5646 + sizeof (FPGM(bci_create_segments_2))
5647 + sizeof (FPGM(bci_create_segments_3))
5648 + sizeof (FPGM(bci_create_segments_4))
5649 + sizeof (FPGM(bci_create_segments_5))
5650 + sizeof (FPGM(bci_create_segments_6))
5651 + sizeof (FPGM(bci_create_segments_7))
5652 + sizeof (FPGM(bci_create_segments_8))
5653 + sizeof (FPGM(bci_create_segments_9))
5655 + sizeof (FPGM(bci_create_segments_composite_a))
5657 + sizeof (FPGM(bci_create_segments_composite_b))
5659 + sizeof (FPGM(bci_create_segments_composite_0))
5660 + sizeof (FPGM(bci_create_segments_composite_1))
5661 + sizeof (FPGM(bci_create_segments_composite_2))
5662 + sizeof (FPGM(bci_create_segments_composite_3))
5663 + sizeof (FPGM(bci_create_segments_composite_4))
5664 + sizeof (FPGM(bci_create_segments_composite_5))
5665 + sizeof (FPGM(bci_create_segments_composite_6))
5666 + sizeof (FPGM(bci_create_segments_composite_7))
5667 + sizeof (FPGM(bci_create_segments_composite_8))
5668 + sizeof (FPGM(bci_create_segments_composite_9))
5670 + sizeof (FPGM(bci_align_point))
5671 + sizeof (FPGM(bci_align_segment))
5672 + sizeof (FPGM(bci_align_segments))
5674 + sizeof (FPGM(bci_scale_contour))
5675 + sizeof (FPGM(bci_scale_glyph))
5676 + sizeof (FPGM(bci_scale_composite_glyph))
5677 + sizeof (FPGM(bci_shift_contour))
5678 + sizeof (FPGM(bci_shift_subglyph))
5680 + sizeof (FPGM(bci_ip_outer_align_point))
5681 + sizeof (FPGM(bci_ip_on_align_points))
5682 + sizeof (FPGM(bci_ip_between_align_point))
5683 + sizeof (FPGM(bci_ip_between_align_points))
5685 + sizeof (FPGM(bci_adjust_common))
5686 + sizeof (FPGM(bci_stem_common))
5687 + sizeof (FPGM(bci_serif_common))
5688 + sizeof (FPGM(bci_serif_anchor_common))
5689 + sizeof (FPGM(bci_serif_link1_common))
5690 + sizeof (FPGM(bci_serif_link2_common))
5692 + sizeof (FPGM(bci_lower_bound))
5693 + sizeof (FPGM(bci_upper_bound))
5694 + sizeof (FPGM(bci_upper_lower_bound))
5696 + sizeof (FPGM(bci_adjust_bound))
5697 + sizeof (FPGM(bci_stem_bound))
5698 + sizeof (FPGM(bci_link))
5699 + sizeof (FPGM(bci_anchor))
5700 + sizeof (FPGM(bci_adjust))
5701 + sizeof (FPGM(bci_stem))
5703 + sizeof (FPGM(bci_action_ip_before))
5704 + sizeof (FPGM(bci_action_ip_after))
5705 + sizeof (FPGM(bci_action_ip_on))
5706 + sizeof (FPGM(bci_action_ip_between))
5708 + sizeof (FPGM(bci_action_blue))
5709 + sizeof (FPGM(bci_action_blue_anchor))
5711 + sizeof (FPGM(bci_action_anchor))
5712 + sizeof (FPGM(bci_action_anchor_serif))
5713 + sizeof (FPGM(bci_action_anchor_round))
5714 + sizeof (FPGM(bci_action_anchor_round_serif))
5716 + sizeof (FPGM(bci_action_adjust))
5717 + sizeof (FPGM(bci_action_adjust_serif))
5718 + sizeof (FPGM(bci_action_adjust_round))
5719 + sizeof (FPGM(bci_action_adjust_round_serif))
5720 + sizeof (FPGM(bci_action_adjust_bound))
5721 + sizeof (FPGM(bci_action_adjust_bound_serif))
5722 + sizeof (FPGM(bci_action_adjust_bound_round))
5723 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5725 + sizeof (FPGM(bci_action_link))
5726 + sizeof (FPGM(bci_action_link_serif))
5727 + sizeof (FPGM(bci_action_link_round))
5728 + sizeof (FPGM(bci_action_link_round_serif))
5730 + sizeof (FPGM(bci_action_stem))
5731 + sizeof (FPGM(bci_action_stem_serif))
5732 + sizeof (FPGM(bci_action_stem_round))
5733 + sizeof (FPGM(bci_action_stem_round_serif))
5734 + sizeof (FPGM(bci_action_stem_bound))
5735 + sizeof (FPGM(bci_action_stem_bound_serif))
5736 + sizeof (FPGM(bci_action_stem_bound_round))
5737 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5739 + sizeof (FPGM(bci_action_serif))
5740 + sizeof (FPGM(bci_action_serif_lower_bound))
5741 + sizeof (FPGM(bci_action_serif_upper_bound))
5742 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5744 + sizeof (FPGM(bci_action_serif_anchor))
5745 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5746 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5747 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5749 + sizeof (FPGM(bci_action_serif_link1))
5750 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5751 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5752 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5754 + sizeof (FPGM(bci_action_serif_link2))
5755 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5756 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5757 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5759 + sizeof (FPGM(bci_hint_glyph));
5761 /* buffer length must be a multiple of four */
5762 len = (buf_len + 3) & ~3;
5763 buf = (FT_Byte*)malloc(len);
5764 if (!buf)
5765 return FT_Err_Out_Of_Memory;
5767 /* pad end of buffer with zeros */
5768 buf[len - 1] = 0x00;
5769 buf[len - 2] = 0x00;
5770 buf[len - 3] = 0x00;
5772 /* copy font program into buffer and fill in the missing variables */
5773 bufp = buf;
5775 COPY_FPGM(bci_align_top_a);
5776 if (font->increase_x_height)
5778 COPY_FPGM(bci_align_top_b1a);
5779 *(bufp++) = HIGH(font->increase_x_height);
5780 *(bufp++) = LOW(font->increase_x_height);
5781 COPY_FPGM(bci_align_top_b1b);
5783 else
5784 COPY_FPGM(bci_align_top_b2);
5785 COPY_FPGM(bci_align_top_c);
5787 COPY_FPGM(bci_round);
5788 COPY_FPGM(bci_smooth_stem_width);
5789 COPY_FPGM(bci_get_best_width);
5790 COPY_FPGM(bci_strong_stem_width_a);
5791 *(bufp++) = (unsigned char)data->num_used_styles;
5792 COPY_FPGM(bci_strong_stem_width_b);
5793 COPY_FPGM(bci_loop_do);
5794 COPY_FPGM(bci_loop);
5795 COPY_FPGM(bci_cvt_rescale);
5796 COPY_FPGM(bci_cvt_rescale_range);
5797 COPY_FPGM(bci_vwidth_data_store);
5798 COPY_FPGM(bci_smooth_blue_round);
5799 COPY_FPGM(bci_strong_blue_round);
5800 COPY_FPGM(bci_blue_round_range);
5801 COPY_FPGM(bci_decrement_component_counter);
5802 COPY_FPGM(bci_get_point_extrema);
5803 COPY_FPGM(bci_nibbles);
5804 COPY_FPGM(bci_number_set_is_element);
5805 COPY_FPGM(bci_number_set_is_element2);
5807 COPY_FPGM(bci_create_segment);
5808 COPY_FPGM(bci_create_segments_a);
5809 *(bufp++) = (unsigned char)data->num_used_styles;
5810 COPY_FPGM(bci_create_segments_b);
5812 COPY_FPGM(bci_create_segments_0);
5813 COPY_FPGM(bci_create_segments_1);
5814 COPY_FPGM(bci_create_segments_2);
5815 COPY_FPGM(bci_create_segments_3);
5816 COPY_FPGM(bci_create_segments_4);
5817 COPY_FPGM(bci_create_segments_5);
5818 COPY_FPGM(bci_create_segments_6);
5819 COPY_FPGM(bci_create_segments_7);
5820 COPY_FPGM(bci_create_segments_8);
5821 COPY_FPGM(bci_create_segments_9);
5823 COPY_FPGM(bci_create_segments_composite_a);
5824 *(bufp++) = (unsigned char)data->num_used_styles;
5825 COPY_FPGM(bci_create_segments_composite_b);
5827 COPY_FPGM(bci_create_segments_composite_0);
5828 COPY_FPGM(bci_create_segments_composite_1);
5829 COPY_FPGM(bci_create_segments_composite_2);
5830 COPY_FPGM(bci_create_segments_composite_3);
5831 COPY_FPGM(bci_create_segments_composite_4);
5832 COPY_FPGM(bci_create_segments_composite_5);
5833 COPY_FPGM(bci_create_segments_composite_6);
5834 COPY_FPGM(bci_create_segments_composite_7);
5835 COPY_FPGM(bci_create_segments_composite_8);
5836 COPY_FPGM(bci_create_segments_composite_9);
5838 COPY_FPGM(bci_align_point);
5839 COPY_FPGM(bci_align_segment);
5840 COPY_FPGM(bci_align_segments);
5842 COPY_FPGM(bci_scale_contour);
5843 COPY_FPGM(bci_scale_glyph);
5844 COPY_FPGM(bci_scale_composite_glyph);
5845 COPY_FPGM(bci_shift_contour);
5846 COPY_FPGM(bci_shift_subglyph);
5848 COPY_FPGM(bci_ip_outer_align_point);
5849 COPY_FPGM(bci_ip_on_align_points);
5850 COPY_FPGM(bci_ip_between_align_point);
5851 COPY_FPGM(bci_ip_between_align_points);
5853 COPY_FPGM(bci_adjust_common);
5854 COPY_FPGM(bci_stem_common);
5855 COPY_FPGM(bci_serif_common);
5856 COPY_FPGM(bci_serif_anchor_common);
5857 COPY_FPGM(bci_serif_link1_common);
5858 COPY_FPGM(bci_serif_link2_common);
5860 COPY_FPGM(bci_lower_bound);
5861 COPY_FPGM(bci_upper_bound);
5862 COPY_FPGM(bci_upper_lower_bound);
5864 COPY_FPGM(bci_adjust_bound);
5865 COPY_FPGM(bci_stem_bound);
5866 COPY_FPGM(bci_link);
5867 COPY_FPGM(bci_anchor);
5868 COPY_FPGM(bci_adjust);
5869 COPY_FPGM(bci_stem);
5871 COPY_FPGM(bci_action_ip_before);
5872 COPY_FPGM(bci_action_ip_after);
5873 COPY_FPGM(bci_action_ip_on);
5874 COPY_FPGM(bci_action_ip_between);
5876 COPY_FPGM(bci_action_blue);
5877 COPY_FPGM(bci_action_blue_anchor);
5879 COPY_FPGM(bci_action_anchor);
5880 COPY_FPGM(bci_action_anchor_serif);
5881 COPY_FPGM(bci_action_anchor_round);
5882 COPY_FPGM(bci_action_anchor_round_serif);
5884 COPY_FPGM(bci_action_adjust);
5885 COPY_FPGM(bci_action_adjust_serif);
5886 COPY_FPGM(bci_action_adjust_round);
5887 COPY_FPGM(bci_action_adjust_round_serif);
5888 COPY_FPGM(bci_action_adjust_bound);
5889 COPY_FPGM(bci_action_adjust_bound_serif);
5890 COPY_FPGM(bci_action_adjust_bound_round);
5891 COPY_FPGM(bci_action_adjust_bound_round_serif);
5893 COPY_FPGM(bci_action_link);
5894 COPY_FPGM(bci_action_link_serif);
5895 COPY_FPGM(bci_action_link_round);
5896 COPY_FPGM(bci_action_link_round_serif);
5898 COPY_FPGM(bci_action_stem);
5899 COPY_FPGM(bci_action_stem_serif);
5900 COPY_FPGM(bci_action_stem_round);
5901 COPY_FPGM(bci_action_stem_round_serif);
5902 COPY_FPGM(bci_action_stem_bound);
5903 COPY_FPGM(bci_action_stem_bound_serif);
5904 COPY_FPGM(bci_action_stem_bound_round);
5905 COPY_FPGM(bci_action_stem_bound_round_serif);
5907 COPY_FPGM(bci_action_serif);
5908 COPY_FPGM(bci_action_serif_lower_bound);
5909 COPY_FPGM(bci_action_serif_upper_bound);
5910 COPY_FPGM(bci_action_serif_upper_lower_bound);
5912 COPY_FPGM(bci_action_serif_anchor);
5913 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5914 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5915 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5917 COPY_FPGM(bci_action_serif_link1);
5918 COPY_FPGM(bci_action_serif_link1_lower_bound);
5919 COPY_FPGM(bci_action_serif_link1_upper_bound);
5920 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5922 COPY_FPGM(bci_action_serif_link2);
5923 COPY_FPGM(bci_action_serif_link2_lower_bound);
5924 COPY_FPGM(bci_action_serif_link2_upper_bound);
5925 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5927 COPY_FPGM(bci_hint_glyph);
5929 *fpgm = buf;
5930 *fpgm_len = buf_len;
5932 return FT_Err_Ok;
5936 FT_Error
5937 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5938 FONT* font)
5940 FT_Error error;
5942 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5943 glyf_Data* data = (glyf_Data*)glyf_table->data;
5945 FT_Byte* fpgm_buf;
5946 FT_ULong fpgm_len;
5949 error = TA_sfnt_add_table_info(sfnt);
5950 if (error)
5951 goto Exit;
5953 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5954 if (glyf_table->processed)
5956 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5957 goto Exit;
5960 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
5961 if (error)
5962 goto Exit;
5964 if (fpgm_len > sfnt->max_instructions)
5965 sfnt->max_instructions = fpgm_len;
5967 /* in case of success, `fpgm_buf' gets linked */
5968 /* and is eventually freed in `TA_font_unload' */
5969 error = TA_font_add_table(font,
5970 &sfnt->table_infos[sfnt->num_table_infos - 1],
5971 TTAG_fpgm, fpgm_len, fpgm_buf);
5972 if (error)
5973 free(fpgm_buf);
5974 else
5975 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5977 Exit:
5978 return error;
5981 /* end of tafpgm.c */