Fix OTS warning about `maxp.maxSizeOfInstructions`.
[ttfautohint.git] / lib / tafpgm.c
blob672e6a864a00c2301f0b1d5b52c33e7769d9170e
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2022 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 #if 0
42 #define MD_orig_ZP2_1 \
43 PUSHB_1, \
44 0, \
45 SZP2, \
46 MD_orig_fixed, \
47 PUSHB_1, \
48 1, \
49 SZP2
50 #endif
54 * Older versions of Monotype's `iType' bytecode interpreter have a serious
55 * bug: The DIV instruction rounds the result, while the correct operation
56 * is truncation. (Note, however, that MUL always rounds the result.)
57 * Since many printers contain this rasterizer without any possibility to
58 * update to a non-buggy version, we have to work around the problem.
60 * DIV and MUL work on 26.6 numbers which means that the numerator gets
61 * multiplied by 64 before the division, and the product gets divided by 64
62 * after the multiplication, respectively. For example, to divide 2 by 3,
63 * you have to write
65 * PUSHB_1,
66 * 2,
67 * 3*64,
68 * DIV
70 * The correct formula to divide two values in 26.6 format with truncation
71 * is
73 * a*64 / b ,
75 * while older `iType' versions incorrectly apply rounding by using
77 * (a*64 + b/2) / b .
79 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
81 * (2*64 + (3*64)/2) / (3*64) = 1
83 * instead of the correct result 0.
85 * The solution to the rounding issue is to use a 26.6 value as an
86 * intermediate result so that we can truncate to the nearest integer (in
87 * 26.6 format) with the FLOOR operator before converting back to a plain
88 * integer (in 32.0 format).
90 * For the common divisions by 2 and 2^10 we define macros.
92 #define DIV_POS_BY_2 \
93 PUSHB_1, \
94 2, \
95 DIV, /* multiply by 64, then divide by 2 */ \
96 FLOOR, \
97 PUSHB_1, \
98 1, \
99 MUL /* multiply by 1, then divide by 64 */
101 #define DIV_BY_2 \
102 PUSHB_1, \
103 2, \
104 DIV, \
105 DUP, \
106 PUSHB_1, \
107 0, \
108 LT, \
109 IF, \
110 PUSHB_1, \
111 64, \
112 ADD, /* add 1 if value is negative */ \
113 EIF, \
114 FLOOR, \
115 PUSHB_1, \
116 1, \
119 #define DIV_BY_1024 \
120 PUSHW_1, \
121 0x04, /* 2^10 */ \
122 0x00, \
123 DIV, \
124 DUP, \
125 PUSHB_1, \
126 0, \
127 LT, \
128 IF, \
129 PUSHB_1, \
130 64, \
131 ADD, \
132 EIF, \
133 FLOOR, \
134 PUSHB_1, \
135 1, \
139 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
140 #define DO_SCALE \
141 DUP, /* s: a a */ \
142 PUSHB_1, \
143 sal_scale, \
144 RS, \
145 MUL, /* delta * 2^10 */ \
146 DIV_BY_1024, /* delta */ \
147 ADD /* a + delta */
150 /* in the comments below, the top of the stack (`s:') */
151 /* is the rightmost element; the stack is shown */
152 /* after the instruction on the same line has been executed */
156 * bci_align_x_height
158 * Optimize the alignment of the top of small letters to the pixel grid.
160 * This function gets used in the `prep' table.
162 * in: blue_idx (CVT index for the style's top of small letters blue zone)
164 * sal: sal_i (CVT index of the style's scaling value;
165 * gets incremented by 1 after execution)
168 static const unsigned char FPGM(bci_align_x_height_a) [] =
171 PUSHB_1,
172 bci_align_x_height,
173 FDEF,
175 /* only get CVT value for non-zero index */
176 DUP,
177 PUSHB_1,
179 NEQ,
181 RCVT,
182 EIF,
183 DUP,
184 DUP, /* s: blue blue blue */
188 /* if (font->increase_x_height) */
189 /* { */
191 static const unsigned char FPGM(bci_align_x_height_b1a) [] =
194 /* apply much `stronger' rounding up of x height for */
195 /* 6 <= PPEM <= increase_x_height */
196 MPPEM,
197 PUSHW_1,
201 /* %d, x height increase limit */
203 static const unsigned char FPGM(bci_align_x_height_b1b) [] =
206 LTEQ,
207 MPPEM,
208 PUSHB_1,
210 GTEQ,
211 AND,
213 PUSHB_1,
214 52, /* threshold = 52 */
216 ELSE,
217 PUSHB_1,
218 40, /* threshold = 40 */
220 EIF,
221 ADD,
222 FLOOR, /* fitted = FLOOR(blue + threshold) */
226 /* } */
228 /* if (!font->increase_x_height) */
229 /* { */
231 static const unsigned char FPGM(bci_align_x_height_b2) [] =
234 PUSHB_1,
236 ADD,
237 FLOOR, /* fitted = FLOOR(blue + 40) */
241 /* } */
243 static const unsigned char FPGM(bci_align_x_height_c) [] =
246 DUP, /* s: blue blue fitted fitted */
247 ROLL,
248 NEQ,
249 IF, /* s: blue fitted */
250 PUSHB_1,
252 CINDEX,
253 SUB, /* s: blue (fitted-blue) */
254 PUSHW_2,
255 0x08, /* 0x800 */
256 0x00,
257 0x08, /* 0x800 */
258 0x00,
259 MUL, /* 0x10000 */
260 MUL, /* (fitted-blue) in 16.16 format */
261 SWAP,
262 DIV, /* factor = ((fitted-blue) / blue) in 16.16 format */
264 ELSE,
265 POP,
266 POP,
267 PUSHB_1,
268 0, /* factor = 0 */
270 EIF,
272 PUSHB_1,
273 sal_i,
274 RS, /* s: factor idx */
275 SWAP,
276 WCVTP,
278 PUSHB_3,
279 sal_i,
281 sal_i,
283 ADD, /* sal_i = sal_i + 1 */
286 ENDF,
292 * bci_round
294 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
295 * engine specific corrections are applied.
297 * in: val
299 * out: ROUND(val)
302 static const unsigned char FPGM(bci_round) [] =
305 PUSHB_1,
306 bci_round,
307 FDEF,
309 PUSHB_1,
311 ADD,
312 FLOOR,
314 ENDF,
320 * bci_quantize_stem_width
322 * Take a stem width and compare it against a set of already stored stem
323 * widths. If the difference to one of the values is less than 4, replace
324 * the argument with the stored one. Otherwise add the argument to the
325 * array of stem widths, without changing the argument.
327 * We do this to catch rounding errors.
329 * in: val
331 * out: quantized(val)
333 * sal: sal_num_stem_widths
334 * sal_stem_width_offset
335 * sal_k
336 * sal_limit
337 * sal_have_cached_width
338 * sal_cached_width_offset
341 static const unsigned char FPGM(bci_quantize_stem_width) [] =
344 PUSHB_1,
345 bci_quantize_stem_width,
346 FDEF,
348 DUP,
349 ABS, /* s: val |val| */
351 PUSHB_4,
352 sal_limit,
353 sal_stem_width_offset,
354 sal_have_cached_width,
356 WS, /* sal_have_cached_width = 0 */
358 PUSHB_1,
359 sal_num_stem_widths,
361 DUP,
362 ADD,
363 ADD, /* sal_limit = sal_stem_width_offset + 2 * sal_num_stem_widths */
366 PUSHB_2,
367 sal_k,
368 sal_stem_width_offset,
370 WS, /* sal_k = sal_stem_width_offset */
372 /* start_loop: */
373 PUSHB_2,
374 37, /* not_in_array jump offset */
375 sal_limit,
377 PUSHB_1,
378 sal_k,
380 EQ, /* sal_limit == sal_k ? */
381 JROT, /* goto not_in_array */
383 DUP,
384 PUSHB_1,
385 12, /* found_stem jump offset */
386 SWAP,
387 PUSHB_1,
388 sal_k,
390 RS, /* cur_stem_width = sal[sal_k] */
391 SUB,
392 ABS,
393 PUSHB_1,
395 LT, /* |val - cur_stem_width| < 4 ? */
396 JROT, /* goto found_stem */
398 PUSHB_3,
399 sal_k,
401 sal_k,
403 ADD, /* sal_k = sal_k + 2, skipping associated cache value */
406 PUSHB_1,
407 33, /* start_loop jump offset */
408 NEG,
409 JMPR, /* goto start_loop */
411 /* found_stem: */
412 POP, /* discard val */
413 PUSHB_1,
414 sal_k,
416 RS, /* val = sal[sal_k] */
417 PUSHB_3,
418 14, /* exit jump offset */
419 sal_have_cached_width,
421 WS, /* sal_have_cached_width = 1 */
422 JMPR, /* goto exit */
424 /* not_in_array: */
425 DUP,
426 PUSHB_1,
427 sal_k,
429 SWAP,
430 WS, /* sal[sal_k] = val */
432 PUSHB_3,
433 sal_num_stem_widths,
435 sal_num_stem_widths,
437 ADD,
438 WS, /* sal_num_stem_widths = sal_num_stem_widths + 1 */
440 /* exit: */
441 SWAP, /* s: |new_val| val */
442 PUSHB_1,
444 LT, /* val < 0 */
446 NEG, /* new_val = -new_val */
447 EIF,
449 /* for input width array index `n' we have (or soon will have) */
450 /* a cached output width at array index `n + 1' */
451 PUSHB_3,
452 sal_cached_width_offset,
454 sal_k,
456 ADD,
457 WS, /* sal_cached_width_offset = sal_k + 1 */
459 ENDF,
465 * bci_natural_stem_width
467 * This dummy function only pops arguments as necessary.
469 * in: width
470 * stem_is_serif
471 * base_is_round
473 * out: width
476 static const unsigned char FPGM(bci_natural_stem_width) [] =
479 PUSHB_1,
480 bci_natural_stem_width,
481 FDEF,
483 SWAP,
484 POP,
485 SWAP,
486 POP,
488 ENDF,
494 * bci_smooth_stem_width
496 * This is the equivalent to the following code from function
497 * `ta_latin_compute_stem_width':
499 * dist = |width|
501 * if (stem_is_serif
502 * && dist < 3*64)
503 * || std_width < 40:
504 * return width
505 * else if base_is_round:
506 * if dist < 80:
507 * dist = 64
508 * else if dist < 56:
509 * dist = 56
511 * delta = |dist - std_width|
513 * if delta < 40:
514 * dist = std_width
515 * if dist < 48:
516 * dist = 48
517 * goto End
519 * if dist < 3*64:
520 * delta = dist
521 * dist = FLOOR(dist)
522 * delta = delta - dist
524 * if delta < 10:
525 * dist = dist + delta
526 * else if delta < 32:
527 * dist = dist + 10
528 * else if delta < 54:
529 * dist = dist + 54
530 * else:
531 * dist = dist + delta
532 * else:
533 * bdelta = 0
535 * if width * base_delta > 0:
536 * if ppem < 10:
537 * bdelta = base_delta
538 * else if ppem < 30:
539 * bdelta = (base_delta * (30 - ppem)) / 20
541 * bdelta = |bdelta|
543 * dist = ROUND(dist - bdelta)
545 * End:
546 * if width < 0:
547 * dist = -dist
548 * return dist
550 * If `cvtl_ignore_std_width' is set, we simply set `std_width'
551 * equal to `dist'.
553 * If `sal_have_cached_width' is set (by `bci_quantize_stem_width'), the
554 * cached value given by `sal_cached_width_offset' is directly taken, not
555 * computing the width again. Otherwise, the computed width gets stored
556 * at the given offset.
558 * in: width
559 * stem_is_serif
560 * base_is_round
562 * out: new_width
564 * sal: sal_vwidth_data_offset
565 * sal_base_delta
566 * sal_have_cached_width
567 * sal_cached_width_offset
569 * CVT: std_width
570 * cvtl_ignore_std_width
572 * uses: bci_round
573 * bci_quantize_stem_width
576 static const unsigned char FPGM(bci_smooth_stem_width) [] =
579 PUSHB_1,
580 bci_smooth_stem_width,
581 FDEF,
583 PUSHB_1,
584 bci_quantize_stem_width,
585 CALL,
587 PUSHB_1,
588 sal_have_cached_width,
591 SWAP,
592 POP,
593 SWAP,
594 POP,
596 PUSHB_1,
597 sal_cached_width_offset,
599 RS, /* cached_width = sal[sal_cached_width_offset] */
600 SWAP,
601 PUSHB_1,
603 LT, /* width < 0 */
605 NEG, /* cached_width = -cached_width */
606 EIF,
608 ELSE,
609 DUP,
610 ABS, /* s: base_is_round stem_is_serif width dist */
612 DUP,
613 PUSHB_1,
614 3*64,
615 LT, /* dist < 3*64 */
617 PUSHB_1,
619 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
620 AND, /* stem_is_serif && dist < 3*64 */
622 PUSHB_3,
625 sal_vwidth_data_offset,
627 RCVT, /* first indirection */
628 MUL, /* divide by 64 */
629 RCVT, /* second indirection */
631 PUSHB_1,
632 cvtl_ignore_std_width,
633 RCVT,
635 POP, /* s: ... dist (stem_is_serif && dist < 3*64) 40 */
636 PUSHB_1,
638 CINDEX, /* standard_width = dist */
639 EIF,
641 GT, /* standard_width < 40 */
642 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
644 IF, /* s: base_is_round width dist */
645 POP,
646 SWAP,
647 POP, /* s: width */
649 ELSE,
650 ROLL, /* s: width dist base_is_round */
651 IF, /* s: width dist */
652 DUP,
653 PUSHB_1,
655 LT, /* dist < 80 */
656 IF, /* s: width dist */
657 POP,
658 PUSHB_1,
659 64, /* dist = 64 */
660 EIF,
662 ELSE,
663 DUP,
664 PUSHB_1,
666 LT, /* dist < 56 */
667 IF, /* s: width dist */
668 POP,
669 PUSHB_1,
670 56, /* dist = 56 */
671 EIF,
672 EIF,
674 DUP, /* s: width dist dist */
675 PUSHB_2,
677 sal_vwidth_data_offset,
679 RCVT, /* first indirection */
680 MUL, /* divide by 64 */
681 RCVT, /* second indirection */
682 SUB,
683 ABS, /* s: width dist delta */
685 PUSHB_1,
687 LT, /* delta < 40 */
688 IF, /* s: width dist */
689 POP,
690 PUSHB_2,
692 sal_vwidth_data_offset,
694 RCVT, /* first indirection */
695 MUL, /* divide by 64 */
696 RCVT, /* second indirection; dist = std_width */
697 DUP,
698 PUSHB_1,
700 LT, /* dist < 48 */
702 POP,
703 PUSHB_1,
704 48, /* dist = 48 */
705 EIF,
707 ELSE,
708 DUP, /* s: width dist dist */
709 PUSHB_1,
710 3*64,
711 LT, /* dist < 3*64 */
713 DUP, /* s: width delta dist */
714 FLOOR, /* dist = FLOOR(dist) */
715 DUP, /* s: width delta dist dist */
716 ROLL,
717 ROLL, /* s: width dist delta dist */
718 SUB, /* delta = delta - dist */
720 DUP, /* s: width dist delta delta */
721 PUSHB_1,
723 LT, /* delta < 10 */
724 IF, /* s: width dist delta */
725 ADD, /* dist = dist + delta */
727 ELSE,
728 DUP,
729 PUSHB_1,
731 LT, /* delta < 32 */
733 POP,
734 PUSHB_1,
736 ADD, /* dist = dist + 10 */
738 ELSE,
739 DUP,
740 PUSHB_1,
742 LT, /* delta < 54 */
744 POP,
745 PUSHB_1,
747 ADD, /* dist = dist + 54 */
749 ELSE,
750 ADD, /* dist = dist + delta */
752 EIF,
753 EIF,
754 EIF,
756 ELSE,
757 PUSHB_1,
759 CINDEX, /* s: width dist width */
760 PUSHB_1,
761 sal_base_delta,
763 MUL, /* s: width dist width*base_delta */
764 PUSHB_1,
766 GT, /* width * base_delta > 0 */
768 PUSHB_1,
769 0, /* s: width dist bdelta */
771 MPPEM,
772 PUSHB_1,
774 LT, /* ppem < 10 */
776 POP,
777 PUSHB_1,
778 sal_base_delta,
779 RS, /* bdelta = base_delta */
781 ELSE,
782 MPPEM,
783 PUSHB_1,
785 LT, /* ppem < 30 */
787 POP,
788 PUSHB_1,
790 MPPEM,
791 SUB, /* 30 - ppem */
792 PUSHW_1,
793 0x10, /* 64 * 64 */
794 0x00,
795 MUL, /* (30 - ppem) in 26.6 format */
796 PUSHB_1,
797 sal_base_delta,
799 MUL, /* base_delta * (30 - ppem) */
800 PUSHW_1,
801 0x05, /* 20 * 64 */
802 0x00,
803 DIV, /* bdelta = (base_delta * (30 - ppem)) / 20 */
804 EIF,
805 EIF,
807 ABS, /* bdelta = |bdelta| */
808 SUB, /* dist = dist - bdelta */
809 EIF,
811 PUSHB_1,
812 bci_round,
813 CALL, /* dist = round(dist) */
815 EIF,
816 EIF,
818 SWAP, /* s: dist width */
819 PUSHB_1,
821 LT, /* width < 0 */
823 NEG, /* dist = -dist */
824 EIF,
825 EIF,
827 DUP,
828 ABS,
829 PUSHB_1,
830 sal_cached_width_offset,
832 SWAP,
833 WS, /* sal[sal_cached_width_offset] = |dist| */
834 EIF,
836 ENDF,
842 * bci_get_best_width
844 * An auxiliary function for `bci_strong_stem_width'.
846 * in: n (initialized with CVT index for first vertical width)
847 * dist
849 * out: n+1
850 * dist
852 * sal: sal_best
853 * sal_ref
855 * CVT: widths[]
858 static const unsigned char FPGM(bci_get_best_width) [] =
861 PUSHB_1,
862 bci_get_best_width,
863 FDEF,
865 DUP,
866 RCVT, /* s: dist n w */
867 DUP,
868 PUSHB_1,
870 CINDEX, /* s: dist n w w dist */
871 SUB,
872 ABS, /* s: dist n w d */
873 DUP,
874 PUSHB_1,
875 sal_best,
876 RS, /* s: dist n w d d best */
877 LT, /* d < best */
879 PUSHB_1,
880 sal_best,
881 SWAP,
882 WS, /* best = d */
883 PUSHB_1,
884 sal_ref,
885 SWAP,
886 WS, /* reference = w */
888 ELSE,
889 POP,
890 POP,
891 EIF,
893 PUSHB_1,
895 ADD, /* n = n + 1 */
897 ENDF,
903 * bci_strong_stem_width
905 * This is the equivalent to the following code (function
906 * `ta_latin_snap_width' and some lines from
907 * `ta_latin_compute_stem_width'):
909 * best = 64 + 32 + 2
910 * dist = |width|
911 * reference = dist
913 * for n in 0 .. num_widths:
914 * w = widths[n]
915 * d = |dist - w|
917 * if d < best:
918 * best = d
919 * reference = w
921 * if dist >= reference:
922 * if dist < ROUND(reference) + 48:
923 * dist = reference
924 * else:
925 * if dist > ROUND(reference) - 48:
926 * dist = reference
928 * if dist >= 64:
929 * dist = ROUND(dist)
930 * else:
931 * dist = 64
933 * if width < 0:
934 * dist = -dist
935 * return dist
937 * If `cvtl_ignore_std_width' is set, we leave `reference = width'.
939 * in: width
940 * stem_is_serif (unused)
941 * base_is_round (unused)
943 * out: new_width
945 * sal: sal_best
946 * sal_ref
947 * sal_vwidth_data_offset
949 * CVT: widths[]
950 * cvtl_ignore_std_width
952 * uses: bci_get_best_width
953 * bci_round
954 * bci_quantize_stem_width
957 static const unsigned char FPGM(bci_strong_stem_width_a) [] =
960 PUSHB_1,
961 bci_strong_stem_width,
962 FDEF,
964 SWAP,
965 POP,
966 SWAP,
967 POP,
969 PUSHB_1,
970 bci_quantize_stem_width,
971 CALL,
973 DUP,
974 ABS, /* s: width dist */
976 PUSHB_2,
977 sal_best,
978 64 + 32 + 2,
979 WS, /* sal_best = 98 */
981 DUP,
982 PUSHB_1,
983 sal_ref,
984 SWAP,
985 WS, /* sal_ref = width */
987 PUSHB_1,
988 cvtl_ignore_std_width,
989 RCVT,
991 ELSE,
993 /* s: width dist */
994 PUSHB_2,
996 sal_vwidth_data_offset,
998 RCVT,
999 MUL, /* divide by 64; first index of vertical widths */
1001 /* s: width dist vw_idx */
1002 PUSHB_2,
1004 sal_vwidth_data_offset,
1006 PUSHB_1,
1010 /* %c, number of used styles */
1012 static const unsigned char FPGM(bci_strong_stem_width_b) [] =
1015 ADD,
1016 RCVT, /* number of vertical widths */
1017 MUL, /* divide by 64 */
1019 /* s: width dist vw_idx loop_count */
1020 PUSHB_1,
1021 bci_get_best_width,
1022 LOOPCALL,
1023 /* clean up stack */
1024 POP, /* s: width dist */
1026 DUP,
1027 PUSHB_1,
1028 sal_ref,
1029 RS, /* s: width dist dist reference */
1030 DUP,
1031 ROLL,
1032 DUP,
1033 ROLL,
1034 PUSHB_1,
1035 bci_round,
1036 CALL, /* s: width dist reference dist dist ROUND(reference) */
1037 PUSHB_2,
1040 CINDEX, /* s: width dist reference dist dist ROUND(reference) 48 reference */
1041 PUSHB_1,
1043 MINDEX, /* s: width dist reference dist ROUND(reference) 48 reference dist */
1045 LTEQ, /* reference <= dist */
1046 IF, /* s: width dist reference dist ROUND(reference) 48 */
1047 ADD,
1048 LT, /* dist < ROUND(reference) + 48 */
1050 ELSE,
1051 SUB,
1052 GT, /* dist > ROUND(reference) - 48 */
1053 EIF,
1056 SWAP, /* s: width reference=new_dist dist */
1057 EIF,
1058 POP,
1059 EIF, /* !cvtl_ignore_std_width */
1061 DUP, /* s: width dist dist */
1062 PUSHB_1,
1064 GTEQ, /* dist >= 64 */
1066 PUSHB_1,
1067 bci_round,
1068 CALL, /* dist = ROUND(dist) */
1070 ELSE,
1071 POP,
1072 PUSHB_1,
1073 64, /* dist = 64 */
1074 EIF,
1076 SWAP, /* s: dist width */
1077 PUSHB_1,
1079 LT, /* width < 0 */
1081 NEG, /* dist = -dist */
1082 EIF,
1084 ENDF,
1090 * bci_do_loop
1092 * An auxiliary function for `bci_loop'.
1094 * sal: sal_i (gets incremented by 2 after execution)
1095 * sal_func
1097 * uses: func[sal_func]
1100 static const unsigned char FPGM(bci_loop_do) [] =
1103 PUSHB_1,
1104 bci_loop_do,
1105 FDEF,
1107 PUSHB_1,
1108 sal_func,
1110 CALL,
1112 PUSHB_3,
1113 sal_i,
1115 sal_i,
1117 ADD, /* sal_i = sal_i + 2 */
1120 ENDF,
1126 * bci_loop
1128 * Take a range `start'..`end' and a function number and apply the
1129 * associated function to the range elements `start', `start+2',
1130 * `start+4', ...
1132 * in: func_num
1133 * end
1134 * start
1136 * sal: sal_i (counter initialized with `start')
1137 * sal_func (`func_num')
1139 * uses: bci_loop_do
1142 static const unsigned char FPGM(bci_loop) [] =
1145 PUSHB_1,
1146 bci_loop,
1147 FDEF,
1149 PUSHB_1,
1150 sal_func,
1151 SWAP,
1152 WS, /* sal_func = func_num */
1154 SWAP,
1155 DUP,
1156 PUSHB_1,
1157 sal_i,
1158 SWAP,
1159 WS, /* sal_i = start */
1161 SUB,
1162 DIV_POS_BY_2,
1163 PUSHB_1,
1165 ADD, /* number of loops ((end - start) / 2 + 1) */
1167 PUSHB_1,
1168 bci_loop_do,
1169 LOOPCALL,
1171 ENDF,
1177 * bci_cvt_rescale
1179 * Rescale CVT value by `sal_scale' (in 16.16 format).
1181 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
1182 * consequently, the calculation `a * b/c' is done as `a + delta' with
1183 * `delta = a * (b-c)/c'. This avoids overflow.
1185 * in: cvt_idx
1187 * out: cvt_idx+1
1189 * sal: sal_scale
1192 static const unsigned char FPGM(bci_cvt_rescale) [] =
1195 PUSHB_1,
1196 bci_cvt_rescale,
1197 FDEF,
1199 DUP,
1200 DUP,
1201 RCVT,
1202 DO_SCALE,
1203 WCVTP,
1205 PUSHB_1,
1207 ADD,
1209 ENDF,
1215 * bci_cvt_rescale_range
1217 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
1218 * scaling value.
1220 * This function gets used in the `prep' table.
1222 * in: num_cvt
1223 * cvt_start_idx
1225 * sal: sal_i (CVT index of the style's scaling value;
1226 * gets incremented by 1 after execution)
1227 * sal_scale
1229 * uses: bci_cvt_rescale
1232 static const unsigned char FPGM(bci_cvt_rescale_range) [] =
1235 PUSHB_1,
1236 bci_cvt_rescale_range,
1237 FDEF,
1239 /* store scaling value in `sal_scale' */
1240 PUSHB_3,
1241 bci_cvt_rescale,
1242 sal_scale,
1243 sal_i,
1245 RCVT,
1246 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
1248 LOOPCALL,
1249 /* clean up stack */
1250 POP,
1252 PUSHB_3,
1253 sal_i,
1255 sal_i,
1257 ADD, /* sal_i = sal_i + 1 */
1260 ENDF,
1266 * bci_vwidth_data_store
1268 * Store a vertical width array value.
1270 * This function gets used in the `prep' table.
1272 * in: value
1274 * sal: sal_i (CVT index of the style's vwidth data;
1275 * gets incremented by 1 after execution)
1278 static const unsigned char FPGM(bci_vwidth_data_store) [] =
1281 PUSHB_1,
1282 bci_vwidth_data_store,
1283 FDEF,
1285 PUSHB_1,
1286 sal_i,
1288 SWAP,
1289 WCVTP,
1291 PUSHB_3,
1292 sal_i,
1294 sal_i,
1296 ADD, /* sal_i = sal_i + 1 */
1299 ENDF,
1305 * bci_smooth_blue_round
1307 * Round a blue ref value and adjust its corresponding shoot value.
1309 * This is the equivalent to the following code (function
1310 * `ta_latin_metrics_scale_dim'):
1312 * delta = dist
1313 * if dist < 0:
1314 * delta = -delta
1316 * if delta < 32:
1317 * delta = 0
1318 * else if delta < 48:
1319 * delta = 32
1320 * else:
1321 * delta = 64
1323 * if dist < 0:
1324 * delta = -delta
1326 * in: ref_idx
1328 * sal: sal_i (number of blue zones)
1330 * out: ref_idx+1
1332 * uses: bci_round
1335 static const unsigned char FPGM(bci_smooth_blue_round) [] =
1338 PUSHB_1,
1339 bci_smooth_blue_round,
1340 FDEF,
1342 DUP,
1343 DUP,
1344 RCVT, /* s: ref_idx ref_idx ref */
1346 DUP,
1347 PUSHB_1,
1348 bci_round,
1349 CALL,
1350 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1352 PUSHB_1,
1353 sal_i,
1355 PUSHB_1,
1357 CINDEX,
1358 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1359 DUP,
1360 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1362 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1363 SWAP,
1364 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1365 DUP,
1366 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1368 DUP,
1369 PUSHB_1,
1371 LT, /* delta < 32 */
1373 POP,
1374 PUSHB_1,
1375 0, /* delta = 0 */
1377 ELSE,
1378 PUSHB_1,
1380 LT, /* delta < 48 */
1382 PUSHB_1,
1383 32, /* delta = 32 */
1385 ELSE,
1386 PUSHB_1,
1387 64, /* delta = 64 */
1388 EIF,
1389 EIF,
1391 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1392 PUSHB_1,
1394 LT, /* dist < 0 */
1396 NEG, /* delta = -delta */
1397 EIF,
1399 PUSHB_1,
1401 CINDEX,
1402 SWAP,
1403 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1405 WCVTP,
1406 WCVTP,
1408 PUSHB_1,
1410 ADD, /* s: (ref_idx + 1) */
1412 ENDF,
1418 * bci_strong_blue_round
1420 * Round a blue ref value and adjust its corresponding shoot value.
1422 * This is the equivalent to the following code:
1424 * delta = dist
1425 * if dist < 0:
1426 * delta = -delta
1428 * if delta < 36:
1429 * delta = 0
1430 * else:
1431 * delta = 64
1433 * if dist < 0:
1434 * delta = -delta
1436 * It doesn't have corresponding code in talatin.c; however, some tests
1437 * have shown that the `smooth' code works just fine for this case also.
1439 * in: ref_idx
1441 * sal: sal_i (number of blue zones)
1443 * out: ref_idx+1
1445 * uses: bci_round
1448 static const unsigned char FPGM(bci_strong_blue_round) [] =
1451 PUSHB_1,
1452 bci_strong_blue_round,
1453 FDEF,
1455 DUP,
1456 DUP,
1457 RCVT, /* s: ref_idx ref_idx ref */
1459 DUP,
1460 PUSHB_1,
1461 bci_round,
1462 CALL,
1463 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1465 PUSHB_1,
1466 sal_i,
1468 PUSHB_1,
1470 CINDEX,
1471 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1472 DUP,
1473 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1475 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1476 SWAP,
1477 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1478 DUP,
1479 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1481 PUSHB_1,
1483 LT, /* delta < 36 */
1485 PUSHB_1,
1486 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1488 ELSE,
1489 PUSHB_1,
1490 64, /* delta = 64 (one pixel unit) */
1491 EIF,
1493 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1494 PUSHB_1,
1496 LT, /* dist < 0 */
1498 NEG, /* delta = -delta */
1499 EIF,
1501 PUSHB_1,
1503 CINDEX,
1504 SWAP,
1505 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1507 WCVTP,
1508 WCVTP,
1510 PUSHB_1,
1512 ADD, /* s: (ref_idx + 1) */
1514 ENDF,
1520 * bci_blue_round_range
1522 * Round a range of blue zones (both reference and shoot values).
1524 * This function gets used in the `prep' table.
1526 * in: num_blue_zones
1527 * blue_ref_idx
1529 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1531 * uses: bci_smooth_blue_round
1532 * bci_strong_blue_round
1535 static const unsigned char FPGM(bci_blue_round_range) [] =
1538 PUSHB_1,
1539 bci_blue_round_range,
1540 FDEF,
1542 DUP,
1543 PUSHB_1,
1544 sal_i,
1545 SWAP,
1548 /* select blue rounding function based on flag in CVT; */
1549 /* for value >0 we use strong mode, else smooth mode */
1550 PUSHB_4,
1551 bci_strong_blue_round,
1552 bci_smooth_blue_round,
1554 cvtl_stem_width_mode,
1555 RCVT,
1558 POP,
1560 ELSE,
1561 SWAP,
1562 POP,
1564 EIF,
1565 LOOPCALL,
1566 /* clean up stack */
1567 POP,
1569 ENDF,
1575 * bci_decrement_component_counter
1577 * An auxiliary function for composite glyphs.
1579 * CVT: cvtl_is_subglyph
1582 static const unsigned char FPGM(bci_decrement_component_counter) [] =
1585 PUSHB_1,
1586 bci_decrement_component_counter,
1587 FDEF,
1589 /* decrement `cvtl_is_subglyph' counter */
1590 PUSHB_2,
1591 cvtl_is_subglyph,
1592 cvtl_is_subglyph,
1593 RCVT,
1594 PUSHB_1,
1595 100,
1596 SUB,
1597 WCVTP,
1599 ENDF,
1605 * bci_get_point_extrema
1607 * An auxiliary function for `bci_create_segment'.
1609 * in: point-1
1611 * out: point
1613 * sal: sal_point_min
1614 * sal_point_max
1617 static const unsigned char FPGM(bci_get_point_extrema) [] =
1620 PUSHB_1,
1621 bci_get_point_extrema,
1622 FDEF,
1624 PUSHB_1,
1626 ADD, /* s: point */
1627 DUP,
1628 DUP,
1630 /* check whether `point' is a new minimum */
1631 PUSHB_1,
1632 sal_point_min,
1633 RS, /* s: point point point point_min */
1634 MD_orig,
1635 /* if distance is negative, we have a new minimum */
1636 PUSHB_1,
1639 IF, /* s: point point */
1640 DUP,
1641 PUSHB_1,
1642 sal_point_min,
1643 SWAP,
1645 EIF,
1647 /* check whether `point' is a new maximum */
1648 PUSHB_1,
1649 sal_point_max,
1650 RS, /* s: point point point_max */
1651 MD_orig,
1652 /* if distance is positive, we have a new maximum */
1653 PUSHB_1,
1656 IF, /* s: point */
1657 DUP,
1658 PUSHB_1,
1659 sal_point_max,
1660 SWAP,
1662 EIF, /* s: point */
1664 ENDF,
1670 * bci_nibbles
1672 * Pop a byte with two delta arguments in its nibbles and push the
1673 * expanded arguments separately as two bytes.
1675 * in: 16 * (end - start) + (start - base)
1677 * out: start
1678 * end
1680 * sal: sal_base (set to `end' at return)
1684 static const unsigned char FPGM(bci_nibbles) [] =
1686 PUSHB_1,
1687 bci_nibbles,
1688 FDEF,
1690 DUP,
1691 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1693 DIV,
1694 FLOOR,
1695 PUSHB_1,
1697 MUL, /* s: in hnibble */
1698 DUP,
1699 PUSHW_1,
1700 0x04, /* 16*64 */
1701 0x00,
1702 MUL, /* s: in hnibble (hnibble * 16) */
1703 ROLL,
1704 SWAP,
1705 SUB, /* s: hnibble lnibble */
1707 PUSHB_1,
1708 sal_base,
1710 ADD, /* s: hnibble start */
1711 DUP,
1712 ROLL,
1713 ADD, /* s: start end */
1715 DUP,
1716 PUSHB_1,
1717 sal_base,
1718 SWAP,
1719 WS, /* sal_base = end */
1721 SWAP,
1723 ENDF,
1729 * bci_number_set_is_element
1731 * Pop values from stack until it is empty. If one of them is equal to
1732 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1733 * otherwise).
1735 * in: ppem_value_1
1736 * ppem_value_2
1737 * ...
1739 * CVT: cvtl_is_element
1742 static const unsigned char FPGM(bci_number_set_is_element) [] =
1745 PUSHB_1,
1746 bci_number_set_is_element,
1747 FDEF,
1749 /* start_loop: */
1750 MPPEM,
1753 PUSHB_2,
1754 cvtl_is_element,
1755 100,
1756 WCVTP,
1757 EIF,
1759 DEPTH,
1760 PUSHB_1,
1762 NEG,
1763 SWAP,
1764 JROT, /* goto start_loop if stack depth != 0 */
1766 ENDF,
1772 * bci_number_set_is_element2
1774 * Pop value ranges from stack until it is empty. If one of them contains
1775 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1776 * otherwise).
1778 * in: ppem_range_1_start
1779 * ppem_range_1_end
1780 * ppem_range_2_start
1781 * ppem_range_2_end
1782 * ...
1784 * CVT: cvtl_is_element
1787 static const unsigned char FPGM(bci_number_set_is_element2) [] =
1790 PUSHB_1,
1791 bci_number_set_is_element2,
1792 FDEF,
1794 /* start_loop: */
1795 MPPEM,
1796 LTEQ,
1798 MPPEM,
1799 GTEQ,
1801 PUSHB_2,
1802 cvtl_is_element,
1803 100,
1804 WCVTP,
1805 EIF,
1806 ELSE,
1807 POP,
1808 EIF,
1810 DEPTH,
1811 PUSHB_1,
1813 NEG,
1814 SWAP,
1815 JROT, /* goto start_loop if stack depth != 0 */
1817 ENDF,
1823 * bci_create_segment
1825 * Store start and end point of a segment in the storage area,
1826 * then construct a point in the twilight zone to represent it.
1828 * This function is used by `bci_create_segments'.
1830 * in: start
1831 * end
1832 * [last (if wrap-around segment)]
1833 * [first (if wrap-around segment)]
1835 * sal: sal_i (start of current segment)
1836 * sal_j (current twilight point)
1837 * sal_point_min
1838 * sal_point_max
1839 * sal_base
1840 * sal_num_packed_segments
1841 * sal_scale
1843 * CVT: cvtl_temp
1845 * uses: bci_get_point_extrema
1846 * bci_nibbles
1848 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1849 * delta values in nibbles (without a wrap-around segment).
1852 static const unsigned char FPGM(bci_create_segment) [] =
1855 PUSHB_1,
1856 bci_create_segment,
1857 FDEF,
1859 PUSHB_2,
1861 sal_num_packed_segments,
1863 NEQ,
1865 PUSHB_2,
1866 sal_num_packed_segments,
1867 sal_num_packed_segments,
1869 PUSHB_1,
1871 SUB,
1872 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1874 PUSHB_1,
1875 bci_nibbles,
1876 CALL,
1877 EIF,
1879 PUSHB_1,
1880 sal_i,
1882 PUSHB_1,
1884 CINDEX,
1885 WS, /* sal[sal_i] = start */
1887 /* initialize inner loop(s) */
1888 PUSHB_2,
1889 sal_point_min,
1891 CINDEX,
1892 WS, /* sal_point_min = start */
1893 PUSHB_2,
1894 sal_point_max,
1896 CINDEX,
1897 WS, /* sal_point_max = start */
1899 PUSHB_1,
1901 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1903 SWAP,
1904 DUP,
1905 PUSHB_1,
1907 CINDEX, /* s: start end end start */
1908 LT, /* start > end */
1910 /* we have a wrap-around segment with two more arguments */
1911 /* to give the last and first point of the contour, respectively; */
1912 /* our job is to store a segment `start'-`last', */
1913 /* and to get extrema for the two segments */
1914 /* `start'-`last' and `first'-`end' */
1916 /* s: first last start end */
1917 PUSHB_2,
1919 sal_i,
1921 ADD,
1922 PUSHB_1,
1924 CINDEX,
1925 WS, /* sal[sal_i + 1] = last */
1927 ROLL,
1928 ROLL, /* s: first end last start */
1929 DUP,
1930 ROLL,
1931 SWAP, /* s: first end start last start */
1932 SUB, /* s: first end start loop_count */
1934 PUSHB_1,
1935 bci_get_point_extrema,
1936 LOOPCALL,
1937 /* clean up stack */
1938 POP,
1940 SWAP, /* s: end first */
1941 PUSHB_1,
1943 SUB,
1944 DUP,
1945 ROLL, /* s: (first - 1) (first - 1) end */
1946 SWAP,
1947 SUB, /* s: (first - 1) loop_count */
1949 PUSHB_1,
1950 bci_get_point_extrema,
1951 LOOPCALL,
1952 /* clean up stack */
1953 POP,
1955 ELSE, /* s: start end */
1956 PUSHB_2,
1958 sal_i,
1960 ADD,
1961 PUSHB_1,
1963 CINDEX,
1964 WS, /* sal[sal_i + 1] = end */
1966 PUSHB_1,
1968 CINDEX,
1969 SUB, /* s: start loop_count */
1971 PUSHB_1,
1972 bci_get_point_extrema,
1973 LOOPCALL,
1974 /* clean up stack */
1975 POP,
1976 EIF,
1978 /* the twilight point representing a segment */
1979 /* is in the middle between the minimum and maximum */
1980 PUSHB_1,
1981 sal_point_min,
1983 GC_orig,
1984 PUSHB_1,
1985 sal_point_max,
1987 GC_orig,
1988 ADD,
1989 DIV_BY_2, /* s: middle_pos */
1991 DO_SCALE, /* middle_pos = middle_pos * scale */
1993 /* write it to temporary CVT location */
1994 PUSHB_2,
1995 cvtl_temp,
1997 SZP0, /* set zp0 to twilight zone 0 */
1998 SWAP,
1999 WCVTP,
2001 /* create twilight point with index `sal_j' */
2002 PUSHB_1,
2003 sal_j,
2005 PUSHB_1,
2006 cvtl_temp,
2007 MIAP_noround,
2009 PUSHB_3,
2010 sal_j,
2012 sal_j,
2014 ADD, /* twilight_point = twilight_point + 1 */
2017 ENDF,
2023 * bci_create_segments
2025 * This is the top-level entry function.
2027 * It pops point ranges from the stack to define segments, computes
2028 * twilight points to represent segments, and finally calls
2029 * `bci_hint_glyph' to handle the rest.
2031 * The second argument (`data_offset') addresses three CVT arrays in
2032 * parallel:
2034 * CVT(data_offset):
2035 * the current style's scaling value (stored in `sal_scale')
2037 * data_offset + num_used_styles:
2038 * offset to the current style's vwidth index array (this value gets
2039 * stored in `sal_vwidth_data_offset')
2041 * data_offset + 2*num_used_styles:
2042 * offset to the current style's vwidth size
2044 * This addressing scheme ensures that (a) we only need a single argument,
2045 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
2046 * which should be sufficient for a long time.
2048 * in: num_packed_segments
2049 * data_offset
2050 * num_segments (N)
2051 * segment_start_0
2052 * segment_end_0
2053 * [contour_last 0 (if wrap-around segment)]
2054 * [contour_first 0 (if wrap-around segment)]
2055 * segment_start_1
2056 * segment_end_1
2057 * [contour_last 0 (if wrap-around segment)]
2058 * [contour_first 0 (if wrap-around segment)]
2059 * ...
2060 * segment_start_(N-1)
2061 * segment_end_(N-1)
2062 * [contour_last (N-1) (if wrap-around segment)]
2063 * [contour_first (N-1) (if wrap-around segment)]
2064 * ... stuff for bci_hint_glyph ...
2066 * sal: sal_i (start of current segment)
2067 * sal_j (current twilight point)
2068 * sal_num_packed_segments
2069 * sal_base (the base for delta values in nibbles)
2070 * sal_vwidth_data_offset
2071 * sal_stem_width_offset
2072 * sal_scale
2074 * CVT: cvtl_is_subglyph
2076 * uses: bci_create_segment
2077 * bci_loop
2078 * bci_hint_glyph
2080 * If `num_packed_segments' is set to p, the first p start/end pairs are
2081 * stored as delta values in nibbles, with the `start' delta in the lower
2082 * nibble (and there are no wrap-around segments). For example, if the
2083 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
2084 * stack are 0x21, 0x32, and 0x14.
2088 static const unsigned char FPGM(bci_create_segments_a) [] =
2091 PUSHB_1,
2092 bci_create_segments,
2093 FDEF,
2095 /* all our measurements are taken along the y axis */
2096 SVTCA_y,
2098 /* only do something if we are not a subglyph */
2099 PUSHB_2,
2101 cvtl_is_subglyph,
2102 RCVT,
2105 PUSHB_1,
2106 sal_num_packed_segments,
2107 SWAP,
2110 DUP,
2111 RCVT,
2112 PUSHB_1,
2113 sal_scale, /* sal_scale = CVT(data_offset) */
2114 SWAP,
2117 PUSHB_1,
2118 sal_vwidth_data_offset,
2119 SWAP,
2120 PUSHB_1,
2124 /* %c, number of used styles */
2126 static const unsigned char FPGM(bci_create_segments_b) [] =
2129 ADD,
2130 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2132 DUP,
2133 ADD, /* delta = 2*num_segments */
2135 PUSHB_8,
2136 sal_segment_offset,
2137 sal_segment_offset,
2139 sal_j,
2141 sal_base,
2143 sal_num_stem_widths,
2145 WS, /* sal_num_stem_widths = 0 */
2146 WS, /* sal_base = 0 */
2147 WS, /* sal_j = 0 (point offset) */
2149 ROLL,
2150 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2152 DUP,
2153 PUSHB_1,
2154 sal_stem_width_offset,
2155 SWAP,
2156 WS, /* sal_stem_width_offset = sal_segment_offset + delta */
2158 PUSHB_1,
2160 SUB, /* s: ... sal_segment_offset (sal_segment_offset + delta - 1) */
2162 PUSHB_2,
2163 bci_create_segment,
2164 bci_loop,
2165 CALL,
2167 PUSHB_1,
2168 bci_hint_glyph,
2169 CALL,
2173 /* used if we have delta exceptions */
2175 static const unsigned char FPGM(bci_create_segments_c) [] =
2178 PUSHB_1,
2180 SZPS,
2184 static const unsigned char FPGM(bci_create_segments_d) [] =
2187 ELSE,
2188 CLEAR,
2189 EIF,
2191 ENDF,
2197 * bci_create_segments_X
2199 * Top-level routines for calling `bci_create_segments'.
2202 static const unsigned char FPGM(bci_create_segments_0) [] =
2205 PUSHB_1,
2206 bci_create_segments_0,
2207 FDEF,
2209 PUSHB_2,
2211 bci_create_segments,
2212 CALL,
2214 ENDF,
2218 static const unsigned char FPGM(bci_create_segments_1) [] =
2221 PUSHB_1,
2222 bci_create_segments_1,
2223 FDEF,
2225 PUSHB_2,
2227 bci_create_segments,
2228 CALL,
2230 ENDF,
2234 static const unsigned char FPGM(bci_create_segments_2) [] =
2237 PUSHB_1,
2238 bci_create_segments_2,
2239 FDEF,
2241 PUSHB_2,
2243 bci_create_segments,
2244 CALL,
2246 ENDF,
2250 static const unsigned char FPGM(bci_create_segments_3) [] =
2253 PUSHB_1,
2254 bci_create_segments_3,
2255 FDEF,
2257 PUSHB_2,
2259 bci_create_segments,
2260 CALL,
2262 ENDF,
2266 static const unsigned char FPGM(bci_create_segments_4) [] =
2269 PUSHB_1,
2270 bci_create_segments_4,
2271 FDEF,
2273 PUSHB_2,
2275 bci_create_segments,
2276 CALL,
2278 ENDF,
2282 static const unsigned char FPGM(bci_create_segments_5) [] =
2285 PUSHB_1,
2286 bci_create_segments_5,
2287 FDEF,
2289 PUSHB_2,
2291 bci_create_segments,
2292 CALL,
2294 ENDF,
2298 static const unsigned char FPGM(bci_create_segments_6) [] =
2301 PUSHB_1,
2302 bci_create_segments_6,
2303 FDEF,
2305 PUSHB_2,
2307 bci_create_segments,
2308 CALL,
2310 ENDF,
2314 static const unsigned char FPGM(bci_create_segments_7) [] =
2317 PUSHB_1,
2318 bci_create_segments_7,
2319 FDEF,
2321 PUSHB_2,
2323 bci_create_segments,
2324 CALL,
2326 ENDF,
2330 static const unsigned char FPGM(bci_create_segments_8) [] =
2333 PUSHB_1,
2334 bci_create_segments_8,
2335 FDEF,
2337 PUSHB_2,
2339 bci_create_segments,
2340 CALL,
2342 ENDF,
2346 static const unsigned char FPGM(bci_create_segments_9) [] =
2349 PUSHB_1,
2350 bci_create_segments_9,
2351 FDEF,
2353 PUSHB_2,
2355 bci_create_segments,
2356 CALL,
2358 ENDF,
2364 * bci_deltapX
2366 * Wrapper functions around DELTAP[123] that touch the affected points
2367 * before applying the delta. This is necessary for ClearType.
2369 * While DELTAP[123] implicitly do a loop, we have to process the
2370 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2372 * in: point
2373 * arg
2376 static const unsigned char FPGM(bci_deltap1) [] =
2379 PUSHB_1,
2380 bci_deltap1,
2381 FDEF,
2383 SWAP,
2384 DUP, /* s: point arg arg */
2385 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2387 DIV,
2388 FLOOR,
2389 PUSHB_1,
2391 MUL, /* s: point arg hnibble(arg) */
2392 PUSHB_1,
2393 CONTROL_DELTA_PPEM_MIN,
2394 ADD, /* s: point arg ppem(arg) */
2395 MPPEM,
2398 SWAP,
2399 DUP,
2400 MDAP_noround, /* touch `point' */
2402 PUSHB_1,
2404 DELTAP1, /* process one `(point,arg)' pair */
2405 ELSE,
2406 POP,
2407 POP,
2408 EIF,
2410 ENDF,
2414 static const unsigned char FPGM(bci_deltap2) [] =
2417 PUSHB_1,
2418 bci_deltap2,
2419 FDEF,
2421 SWAP,
2422 DUP, /* s: point arg arg */
2423 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2425 DIV,
2426 FLOOR,
2427 PUSHB_1,
2429 MUL, /* s: point arg hnibble(arg) */
2430 PUSHB_1,
2431 CONTROL_DELTA_PPEM_MIN + 16,
2432 ADD, /* s: point arg ppem(arg) */
2433 MPPEM,
2436 SWAP,
2437 DUP,
2438 MDAP_noround, /* touch `point' */
2440 PUSHB_1,
2442 DELTAP2, /* process one `(point,arg)' pair */
2443 ELSE,
2444 POP,
2445 POP,
2446 EIF,
2448 ENDF,
2452 static const unsigned char FPGM(bci_deltap3) [] =
2455 PUSHB_1,
2456 bci_deltap3,
2457 FDEF,
2459 SWAP,
2460 DUP, /* s: point arg arg */
2461 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2463 DIV,
2464 FLOOR,
2465 PUSHB_1,
2467 MUL, /* s: point arg hnibble(arg) */
2468 PUSHB_1,
2469 CONTROL_DELTA_PPEM_MIN + 32,
2470 ADD, /* s: point arg ppem(arg) */
2471 MPPEM,
2474 SWAP,
2475 DUP,
2476 MDAP_noround, /* touch `point' */
2478 PUSHB_1,
2480 DELTAP3, /* process one `(point,arg)' pair */
2481 ELSE,
2482 POP,
2483 POP,
2484 EIF,
2486 ENDF,
2492 * bci_create_segments_composite
2494 * The same as `bci_create_segments'.
2495 * It also decrements the composite component counter.
2497 * sal: sal_num_packed_segments
2498 * sal_segment_offset
2499 * sal_vwidth_data_offset
2501 * CVT: cvtl_is_subglyph
2503 * uses: bci_decrement_component_counter
2504 * bci_create_segment
2505 * bci_loop
2506 * bci_hint_glyph
2509 static const unsigned char FPGM(bci_create_segments_composite_a) [] =
2512 PUSHB_1,
2513 bci_create_segments_composite,
2514 FDEF,
2516 /* all our measurements are taken along the y axis */
2517 SVTCA_y,
2519 PUSHB_1,
2520 bci_decrement_component_counter,
2521 CALL,
2523 /* only do something if we are not a subglyph */
2524 PUSHB_2,
2526 cvtl_is_subglyph,
2527 RCVT,
2530 PUSHB_1,
2531 sal_num_packed_segments,
2532 SWAP,
2535 DUP,
2536 RCVT,
2537 PUSHB_1,
2538 sal_scale, /* sal_scale = CVT(data_offset) */
2539 SWAP,
2542 PUSHB_1,
2543 sal_vwidth_data_offset,
2544 SWAP,
2545 PUSHB_1,
2549 /* %c, number of used styles */
2551 static const unsigned char FPGM(bci_create_segments_composite_b) [] =
2554 ADD,
2555 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2557 DUP,
2558 ADD,
2559 PUSHB_1,
2561 SUB, /* delta = (2*num_segments - 1) */
2563 PUSHB_6,
2564 sal_segment_offset,
2565 sal_segment_offset,
2567 sal_j,
2569 sal_base,
2571 WS, /* sal_base = 0 */
2572 WS, /* sal_j = 0 (point offset) */
2574 ROLL,
2575 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2577 PUSHB_2,
2578 bci_create_segment,
2579 bci_loop,
2580 CALL,
2582 PUSHB_1,
2583 bci_hint_glyph,
2584 CALL,
2588 /* used if we have delta exceptions */
2590 static const unsigned char FPGM(bci_create_segments_composite_c) [] =
2593 PUSHB_1,
2595 SZPS,
2599 static const unsigned char FPGM(bci_create_segments_composite_d) [] =
2602 ELSE,
2603 CLEAR,
2604 EIF,
2606 ENDF,
2612 * bci_create_segments_composite_X
2614 * Top-level routines for calling `bci_create_segments_composite'.
2617 static const unsigned char FPGM(bci_create_segments_composite_0) [] =
2620 PUSHB_1,
2621 bci_create_segments_composite_0,
2622 FDEF,
2624 PUSHB_2,
2626 bci_create_segments_composite,
2627 CALL,
2629 ENDF,
2633 static const unsigned char FPGM(bci_create_segments_composite_1) [] =
2636 PUSHB_1,
2637 bci_create_segments_composite_1,
2638 FDEF,
2640 PUSHB_2,
2642 bci_create_segments_composite,
2643 CALL,
2645 ENDF,
2649 static const unsigned char FPGM(bci_create_segments_composite_2) [] =
2652 PUSHB_1,
2653 bci_create_segments_composite_2,
2654 FDEF,
2656 PUSHB_2,
2658 bci_create_segments_composite,
2659 CALL,
2661 ENDF,
2665 static const unsigned char FPGM(bci_create_segments_composite_3) [] =
2668 PUSHB_1,
2669 bci_create_segments_composite_3,
2670 FDEF,
2672 PUSHB_2,
2674 bci_create_segments_composite,
2675 CALL,
2677 ENDF,
2681 static const unsigned char FPGM(bci_create_segments_composite_4) [] =
2684 PUSHB_1,
2685 bci_create_segments_composite_4,
2686 FDEF,
2688 PUSHB_2,
2690 bci_create_segments_composite,
2691 CALL,
2693 ENDF,
2697 static const unsigned char FPGM(bci_create_segments_composite_5) [] =
2700 PUSHB_1,
2701 bci_create_segments_composite_5,
2702 FDEF,
2704 PUSHB_2,
2706 bci_create_segments_composite,
2707 CALL,
2709 ENDF,
2713 static const unsigned char FPGM(bci_create_segments_composite_6) [] =
2716 PUSHB_1,
2717 bci_create_segments_composite_6,
2718 FDEF,
2720 PUSHB_2,
2722 bci_create_segments_composite,
2723 CALL,
2725 ENDF,
2729 static const unsigned char FPGM(bci_create_segments_composite_7) [] =
2732 PUSHB_1,
2733 bci_create_segments_composite_7,
2734 FDEF,
2736 PUSHB_2,
2738 bci_create_segments_composite,
2739 CALL,
2741 ENDF,
2745 static const unsigned char FPGM(bci_create_segments_composite_8) [] =
2748 PUSHB_1,
2749 bci_create_segments_composite_8,
2750 FDEF,
2752 PUSHB_2,
2754 bci_create_segments_composite,
2755 CALL,
2757 ENDF,
2761 static const unsigned char FPGM(bci_create_segments_composite_9) [] =
2764 PUSHB_1,
2765 bci_create_segments_composite_9,
2766 FDEF,
2768 PUSHB_2,
2770 bci_create_segments_composite,
2771 CALL,
2773 ENDF,
2779 * bci_align_point
2781 * An auxiliary function for `bci_align_segment'.
2783 * in: point
2785 * out: point+1
2788 static const unsigned char FPGM(bci_align_point) [] =
2791 PUSHB_1,
2792 bci_align_point,
2793 FDEF,
2795 DUP,
2796 ALIGNRP, /* align point with rp0 */
2798 PUSHB_1,
2800 ADD,
2802 ENDF,
2808 * bci_align_segment
2810 * Align all points in a segment to the twilight point in rp0.
2811 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2813 * in: segment_index
2815 * sal: sal_segment_offset
2817 * uses: bci_align_point
2820 static const unsigned char FPGM(bci_align_segment) [] =
2823 PUSHB_1,
2824 bci_align_segment,
2825 FDEF,
2827 /* we need the values of `sal_segment_offset + 2*segment_index' */
2828 /* and `sal_segment_offset + 2*segment_index + 1' */
2829 DUP,
2830 ADD,
2831 PUSHB_1,
2832 sal_segment_offset,
2833 ADD,
2834 DUP,
2836 SWAP,
2837 PUSHB_1,
2839 ADD,
2840 RS, /* s: first last */
2842 PUSHB_1,
2844 CINDEX, /* s: first last first */
2845 SUB,
2846 PUSHB_1,
2848 ADD, /* s: first loop_count */
2850 PUSHB_1,
2851 bci_align_point,
2852 LOOPCALL,
2853 /* clean up stack */
2854 POP,
2856 ENDF,
2862 * bci_align_segments
2864 * Align segments to the twilight point in rp0.
2865 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2867 * in: first_segment
2868 * loop_counter (N)
2869 * segment_1
2870 * segment_2
2871 * ...
2872 * segment_N
2874 * uses: bci_align_segment
2877 static const unsigned char FPGM(bci_align_segments) [] =
2880 PUSHB_1,
2881 bci_align_segments,
2882 FDEF,
2884 PUSHB_1,
2885 bci_align_segment,
2886 CALL,
2888 PUSHB_1,
2889 bci_align_segment,
2890 LOOPCALL,
2892 ENDF,
2898 * bci_scale_contour
2900 * Scale a contour using two points giving the maximum and minimum
2901 * coordinates.
2903 * It expects that no point on the contour is touched.
2905 * in: min_point
2906 * max_point
2908 * sal: sal_scale
2911 static const unsigned char FPGM(bci_scale_contour) [] =
2914 PUSHB_1,
2915 bci_scale_contour,
2916 FDEF,
2918 DUP,
2919 DUP,
2920 GC_orig,
2921 DUP,
2922 DO_SCALE, /* min_pos_new = min_pos * scale */
2923 SWAP,
2924 SUB,
2925 SHPIX,
2927 /* don't scale a single-point contour twice */
2928 SWAP,
2929 DUP,
2930 ROLL,
2931 NEQ,
2933 DUP,
2934 GC_orig,
2935 DUP,
2936 DO_SCALE, /* max_pos_new = max_pos * scale */
2937 SWAP,
2938 SUB,
2939 SHPIX,
2941 ELSE,
2942 POP,
2943 EIF,
2945 ENDF,
2951 * bci_scale_glyph
2953 * Scale a glyph using a list of points (two points per contour, giving
2954 * the maximum and mininum coordinates).
2956 * It expects that no point in the glyph is touched.
2958 * Note that the point numbers are sorted in ascending order;
2959 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2960 * contour without specifying which one is the minimum and maximum.
2962 * in: num_contours (N)
2963 * min_point_1
2964 * max_point_1
2965 * min_point_2
2966 * max_point_2
2967 * ...
2968 * min_point_N
2969 * max_point_N
2971 * CVT: cvtl_is_subglyph
2972 * cvtl_do_iup_y
2974 * sal: sal_scale
2976 * uses: bci_scale_contour
2979 static const unsigned char FPGM(bci_scale_glyph_a) [] =
2982 PUSHB_1,
2983 bci_scale_glyph,
2984 FDEF,
2986 /* all our measurements are taken along the y axis */
2987 SVTCA_y,
2989 /* only do something if we are not a subglyph */
2990 PUSHB_2,
2992 cvtl_is_subglyph,
2993 RCVT,
2996 /* use fallback scaling value */
2997 PUSHB_2,
2998 sal_scale,
3002 /* %c, fallback scaling index */
3004 static const unsigned char FPGM(bci_scale_glyph_b) [] =
3007 RCVT,
3010 PUSHB_1,
3012 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
3014 PUSHB_1,
3015 bci_scale_contour,
3016 LOOPCALL,
3018 PUSHB_2,
3019 cvtl_do_iup_y,
3021 SZP2, /* set zp2 to normal zone 1 */
3022 RCVT,
3024 IUP_y,
3025 EIF,
3027 ELSE,
3028 CLEAR,
3029 EIF,
3031 ENDF,
3037 * bci_scale_composite_glyph
3039 * The same as `bci_scale_glyph'.
3040 * It also decrements the composite component counter.
3042 * CVT: cvtl_is_subglyph
3043 * cvtl_do_iup_y
3045 * sal: sal_scale
3047 * uses: bci_decrement_component_counter
3048 * bci_scale_contour
3051 static const unsigned char FPGM(bci_scale_composite_glyph_a) [] =
3054 PUSHB_1,
3055 bci_scale_composite_glyph,
3056 FDEF,
3058 /* all our measurements are taken along the y axis */
3059 SVTCA_y,
3061 PUSHB_1,
3062 bci_decrement_component_counter,
3063 CALL,
3065 /* only do something if we are not a subglyph */
3066 PUSHB_2,
3068 cvtl_is_subglyph,
3069 RCVT,
3072 /* use fallback scaling value */
3073 PUSHB_2,
3074 sal_scale,
3078 /* %c, fallback scaling index */
3080 static const unsigned char FPGM(bci_scale_composite_glyph_b) [] =
3083 RCVT,
3086 PUSHB_1,
3088 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
3090 PUSHB_1,
3091 bci_scale_contour,
3092 LOOPCALL,
3094 PUSHB_2,
3095 cvtl_do_iup_y,
3097 SZP2, /* set zp2 to normal zone 1 */
3098 RCVT,
3100 IUP_y,
3101 EIF,
3103 ELSE,
3104 CLEAR,
3105 EIF,
3107 ENDF,
3113 * bci_shift_contour
3115 * Shift a contour by a given amount.
3117 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
3118 * point to the normal zone 1.
3120 * in: contour
3122 * out: contour+1
3125 static const unsigned char FPGM(bci_shift_contour) [] =
3128 PUSHB_1,
3129 bci_shift_contour,
3130 FDEF,
3132 DUP,
3133 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
3135 PUSHB_1,
3137 ADD,
3139 ENDF,
3145 * bci_shift_subglyph
3147 * Shift a subglyph. To be more specific, it corrects the already applied
3148 * subglyph offset (if any) from the `glyf' table which needs to be scaled
3149 * also.
3151 * If this function is called, a point `x' in the subglyph has been scaled
3152 * already (during the hinting of the subglyph itself), and `offset' has
3153 * been applied also:
3155 * x -> x * scale + offset (1)
3157 * However, the offset should be applied first, then the scaling:
3159 * x -> (x + offset) * scale (2)
3161 * Our job is now to transform (1) to (2); a simple calculation shows that
3162 * we have to shift all points of the subglyph by
3164 * offset * scale - offset = offset * (scale - 1)
3166 * Note that `sal_scale' is equal to the above `scale - 1'.
3168 * in: offset (in FUnits)
3169 * num_contours
3170 * first_contour
3172 * CVT: cvtl_funits_to_pixels
3174 * sal: sal_scale
3176 * uses: bci_round
3177 * bci_shift_contour
3180 static const unsigned char FPGM(bci_shift_subglyph_a) [] =
3183 PUSHB_1,
3184 bci_shift_subglyph,
3185 FDEF,
3187 /* all our measurements are taken along the y axis */
3188 SVTCA_y,
3190 /* use fallback scaling value */
3191 PUSHB_2,
3192 sal_scale,
3196 /* %c, fallback scaling index */
3198 static const unsigned char FPGM(bci_shift_subglyph_b) [] =
3201 RCVT,
3204 PUSHB_1,
3205 cvtl_funits_to_pixels,
3206 RCVT, /* scaling factor FUnits -> pixels */
3207 MUL,
3208 DIV_BY_1024,
3210 /* the autohinter always rounds offsets */
3211 PUSHB_1,
3212 bci_round,
3213 CALL, /* offset = round(offset) */
3215 PUSHB_1,
3216 sal_scale,
3218 MUL,
3219 DIV_BY_1024, /* delta = offset * (scale - 1) */
3221 /* and round again */
3222 PUSHB_1,
3223 bci_round,
3224 CALL, /* offset = round(offset) */
3226 PUSHB_1,
3228 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3230 /* we create twilight point 0 as a reference point, */
3231 /* setting the original position to zero (using `cvtl_temp') */
3232 PUSHB_5,
3235 cvtl_temp,
3236 cvtl_temp,
3238 WCVTP,
3239 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
3241 SWAP, /* s: first_contour num_contours 0 delta */
3242 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
3244 PUSHB_2,
3245 bci_shift_contour,
3247 SZP2, /* set zp2 to normal zone 1 */
3248 LOOPCALL,
3249 /* clean up stack */
3250 POP,
3254 /* used if we have delta exceptions */
3256 static const unsigned char FPGM(bci_shift_subglyph_c) [] =
3259 PUSHB_1,
3261 SZPS,
3265 static const unsigned char FPGM(bci_shift_subglyph_d) [] =
3268 ENDF,
3274 * bci_ip_outer_align_point
3276 * Auxiliary function for `bci_action_ip_before' and
3277 * `bci_action_ip_after'.
3279 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3280 * zone, and both zp1 and zp2 set to normal zone.
3282 * in: point
3284 * sal: sal_i (edge_orig_pos)
3285 * sal_scale
3288 static const unsigned char FPGM(bci_ip_outer_align_point) [] =
3291 PUSHB_1,
3292 bci_ip_outer_align_point,
3293 FDEF,
3295 DUP,
3296 ALIGNRP, /* align `point' with `edge' */
3297 DUP,
3298 GC_orig,
3299 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3301 PUSHB_1,
3302 sal_i,
3304 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3305 SHPIX,
3307 ENDF,
3313 * bci_ip_on_align_points
3315 * Auxiliary function for `bci_action_ip_on'.
3317 * in: edge (in twilight zone)
3318 * loop_counter (N)
3319 * point_1
3320 * point_2
3321 * ...
3322 * point_N
3325 static const unsigned char FPGM(bci_ip_on_align_points) [] =
3328 PUSHB_1,
3329 bci_ip_on_align_points,
3330 FDEF,
3332 MDAP_noround, /* set rp0 and rp1 to `edge' */
3334 SLOOP,
3335 ALIGNRP,
3337 ENDF,
3343 * bci_ip_between_align_point
3345 * Auxiliary function for `bci_ip_between_align_points'.
3347 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3348 * zone, and both zp1 and zp2 set to normal zone.
3350 * in: point
3352 * sal: sal_i (edge_orig_pos)
3353 * sal_j (stretch_factor)
3354 * sal_scale
3357 static const unsigned char FPGM(bci_ip_between_align_point) [] =
3360 PUSHB_1,
3361 bci_ip_between_align_point,
3362 FDEF,
3364 DUP,
3365 ALIGNRP, /* align `point' with `edge' */
3366 DUP,
3367 GC_orig,
3368 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3370 PUSHB_1,
3371 sal_i,
3373 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3374 PUSHB_1,
3375 sal_j,
3377 MUL, /* s: point delta */
3378 SHPIX,
3380 ENDF,
3386 * bci_ip_between_align_points
3388 * Auxiliary function for `bci_action_ip_between'.
3390 * in: after_edge (in twilight zone)
3391 * before_edge (in twilight zone)
3392 * loop_counter (N)
3393 * point_1
3394 * point_2
3395 * ...
3396 * point_N
3398 * sal: sal_i (before_orig_pos)
3399 * sal_j (stretch_factor)
3401 * uses: bci_ip_between_align_point
3404 static const unsigned char FPGM(bci_ip_between_align_points) [] =
3407 PUSHB_1,
3408 bci_ip_between_align_points,
3409 FDEF,
3411 PUSHB_2,
3414 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3415 CINDEX,
3416 DUP, /* s: ... before after before before */
3417 MDAP_noround, /* set rp0 and rp1 to `before' */
3418 DUP,
3419 GC_orig, /* s: ... before after before before_orig_pos */
3420 PUSHB_1,
3421 sal_i,
3422 SWAP,
3423 WS, /* sal_i = before_orig_pos */
3424 PUSHB_1,
3426 CINDEX, /* s: ... before after before after */
3427 MD_cur, /* a = after_pos - before_pos */
3428 ROLL,
3429 ROLL,
3430 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
3432 DUP,
3433 IF, /* b != 0 ? */
3434 DIV, /* s: a/b */
3435 ELSE,
3436 POP, /* avoid division by zero */
3437 EIF,
3439 PUSHB_1,
3440 sal_j,
3441 SWAP,
3442 WS, /* sal_j = stretch_factor */
3444 PUSHB_3,
3445 bci_ip_between_align_point,
3448 SZP2, /* set zp2 to normal zone 1 */
3449 SZP1, /* set zp1 to normal zone 1 */
3450 LOOPCALL,
3452 ENDF,
3458 * bci_action_ip_before
3460 * Handle `ip_before' data to align points located before the first edge.
3462 * in: first_edge (in twilight zone)
3463 * loop_counter (N)
3464 * point_1
3465 * point_2
3466 * ...
3467 * point_N
3469 * sal: sal_i (first_edge_orig_pos)
3471 * uses: bci_ip_outer_align_point
3474 static const unsigned char FPGM(bci_action_ip_before) [] =
3477 PUSHB_1,
3478 bci_action_ip_before,
3479 FDEF,
3481 PUSHB_1,
3483 SZP2, /* set zp2 to twilight zone 0 */
3485 DUP,
3486 GC_orig,
3487 PUSHB_1,
3488 sal_i,
3489 SWAP,
3490 WS, /* sal_i = first_edge_orig_pos */
3492 PUSHB_3,
3496 SZP2, /* set zp2 to normal zone 1 */
3497 SZP1, /* set zp1 to normal zone 1 */
3498 SZP0, /* set zp0 to twilight zone 0 */
3500 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
3502 PUSHB_1,
3503 bci_ip_outer_align_point,
3504 LOOPCALL,
3506 ENDF,
3512 * bci_action_ip_after
3514 * Handle `ip_after' data to align points located after the last edge.
3516 * in: last_edge (in twilight zone)
3517 * loop_counter (N)
3518 * point_1
3519 * point_2
3520 * ...
3521 * point_N
3523 * sal: sal_i (last_edge_orig_pos)
3525 * uses: bci_ip_outer_align_point
3528 static const unsigned char FPGM(bci_action_ip_after) [] =
3531 PUSHB_1,
3532 bci_action_ip_after,
3533 FDEF,
3535 PUSHB_1,
3537 SZP2, /* set zp2 to twilight zone 0 */
3539 DUP,
3540 GC_orig,
3541 PUSHB_1,
3542 sal_i,
3543 SWAP,
3544 WS, /* sal_i = last_edge_orig_pos */
3546 PUSHB_3,
3550 SZP2, /* set zp2 to normal zone 1 */
3551 SZP1, /* set zp1 to normal zone 1 */
3552 SZP0, /* set zp0 to twilight zone 0 */
3554 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3556 PUSHB_1,
3557 bci_ip_outer_align_point,
3558 LOOPCALL,
3560 ENDF,
3566 * bci_action_ip_on
3568 * Handle `ip_on' data to align points located on an edge coordinate (but
3569 * not part of an edge).
3571 * in: loop_counter (M)
3572 * edge_1 (in twilight zone)
3573 * loop_counter (N_1)
3574 * point_1
3575 * point_2
3576 * ...
3577 * point_N_1
3578 * edge_2 (in twilight zone)
3579 * loop_counter (N_2)
3580 * point_1
3581 * point_2
3582 * ...
3583 * point_N_2
3584 * ...
3585 * edge_M (in twilight zone)
3586 * loop_counter (N_M)
3587 * point_1
3588 * point_2
3589 * ...
3590 * point_N_M
3592 * uses: bci_ip_on_align_points
3595 static const unsigned char FPGM(bci_action_ip_on) [] =
3598 PUSHB_1,
3599 bci_action_ip_on,
3600 FDEF,
3602 PUSHB_2,
3605 SZP1, /* set zp1 to normal zone 1 */
3606 SZP0, /* set zp0 to twilight zone 0 */
3608 PUSHB_1,
3609 bci_ip_on_align_points,
3610 LOOPCALL,
3612 ENDF,
3618 * bci_action_ip_between
3620 * Handle `ip_between' data to align points located between two edges.
3622 * in: loop_counter (M)
3623 * before_edge_1 (in twilight zone)
3624 * after_edge_1 (in twilight zone)
3625 * loop_counter (N_1)
3626 * point_1
3627 * point_2
3628 * ...
3629 * point_N_1
3630 * before_edge_2 (in twilight zone)
3631 * after_edge_2 (in twilight zone)
3632 * loop_counter (N_2)
3633 * point_1
3634 * point_2
3635 * ...
3636 * point_N_2
3637 * ...
3638 * before_edge_M (in twilight zone)
3639 * after_edge_M (in twilight zone)
3640 * loop_counter (N_M)
3641 * point_1
3642 * point_2
3643 * ...
3644 * point_N_M
3646 * uses: bci_ip_between_align_points
3649 static const unsigned char FPGM(bci_action_ip_between) [] =
3652 PUSHB_1,
3653 bci_action_ip_between,
3654 FDEF,
3656 PUSHB_1,
3657 bci_ip_between_align_points,
3658 LOOPCALL,
3660 ENDF,
3666 * bci_adjust_common
3668 * Common code for bci_action_adjust routines.
3670 * in: top_to_bottom_hinting
3671 * edge2_is_serif
3672 * edge_is_round
3673 * edge
3674 * edge2
3676 * out: edge (adjusted)
3678 * sal: sal_top_to_bottom_hinting
3679 * sal_base_delta
3681 * uses: func[sal_stem_width_function]
3684 static const unsigned char FPGM(bci_adjust_common) [] =
3687 PUSHB_1,
3688 bci_adjust_common,
3689 FDEF,
3691 PUSHB_1,
3693 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3694 PUSHB_1,
3695 sal_top_to_bottom_hinting,
3696 SWAP,
3699 PUSHB_1,
3701 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3702 PUSHB_1,
3704 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3705 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3707 PUSHB_2,
3708 sal_base_delta, /* no base_delta needed here */
3712 PUSHB_1,
3713 sal_stem_width_function,
3715 CALL,
3716 NEG, /* s: [...] edge2 edge -cur_len */
3718 ROLL, /* s: [...] edge -cur_len edge2 */
3719 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3720 SWAP,
3721 DUP,
3722 DUP, /* s: [...] -cur_len edge edge edge */
3723 ALIGNRP, /* align `edge' with `edge2' */
3724 ROLL,
3725 SHPIX, /* shift `edge' by -cur_len */
3727 ENDF,
3733 * bci_adjust_bound
3735 * Handle the ADJUST + BOUND actions to align an edge of a stem if the
3736 * other edge of the stem has already been moved, then moving it again if
3737 * necessary to stay bound.
3739 * in: top_to_bottom_hinting
3740 * edge2_is_serif
3741 * edge_is_round
3742 * edge_point (in twilight zone)
3743 * edge2_point (in twilight zone)
3744 * edge[-1] (in twilight zone)
3745 * ... stuff for bci_align_segments (edge) ...
3747 * sal: sal_top_to_bottom_hinting
3749 * uses: bci_adjust_common
3750 * bci_align_segments
3753 static const unsigned char FPGM(bci_adjust_bound) [] =
3756 PUSHB_1,
3757 bci_adjust_bound,
3758 FDEF,
3760 PUSHB_1,
3761 bci_adjust_common,
3762 CALL,
3764 SWAP, /* s: edge edge[-1] */
3765 DUP,
3766 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3767 GC_cur,
3768 PUSHB_1,
3770 CINDEX,
3771 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3772 PUSHB_1,
3773 sal_top_to_bottom_hinting,
3776 LT, /* edge_pos > edge[-1]_pos */
3777 ELSE,
3778 GT, /* edge_pos < edge[-1]_pos */
3779 EIF,
3781 DUP,
3782 ALIGNRP, /* align `edge' to `edge[-1]' */
3783 EIF,
3785 MDAP_noround, /* set rp0 and rp1 to `edge' */
3787 PUSHB_2,
3788 bci_align_segments,
3790 SZP1, /* set zp1 to normal zone 1 */
3791 CALL,
3793 ENDF,
3799 * bci_action_adjust_bound
3800 * bci_action_adjust_bound_serif
3801 * bci_action_adjust_bound_round
3802 * bci_action_adjust_bound_round_serif
3803 * bci_action_adjust_down_bound
3804 * bci_action_adjust_down_bound_serif
3805 * bci_action_adjust_down_bound_round
3806 * bci_action_adjust_down_bound_round_serif
3808 * Higher-level routines for calling `bci_adjust_bound'.
3811 static const unsigned char FPGM(bci_action_adjust_bound) [] =
3814 PUSHB_1,
3815 bci_action_adjust_bound,
3816 FDEF,
3818 PUSHB_4,
3822 bci_adjust_bound,
3823 CALL,
3825 ENDF,
3829 static const unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3832 PUSHB_1,
3833 bci_action_adjust_bound_serif,
3834 FDEF,
3836 PUSHB_4,
3840 bci_adjust_bound,
3841 CALL,
3843 ENDF,
3847 static const unsigned char FPGM(bci_action_adjust_bound_round) [] =
3850 PUSHB_1,
3851 bci_action_adjust_bound_round,
3852 FDEF,
3854 PUSHB_4,
3858 bci_adjust_bound,
3859 CALL,
3861 ENDF,
3865 static const unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3868 PUSHB_1,
3869 bci_action_adjust_bound_round_serif,
3870 FDEF,
3872 PUSHB_4,
3876 bci_adjust_bound,
3877 CALL,
3879 ENDF,
3883 static const unsigned char FPGM(bci_action_adjust_down_bound) [] =
3886 PUSHB_1,
3887 bci_action_adjust_down_bound,
3888 FDEF,
3890 PUSHB_4,
3894 bci_adjust_bound,
3895 CALL,
3897 ENDF,
3901 static const unsigned char FPGM(bci_action_adjust_down_bound_serif) [] =
3904 PUSHB_1,
3905 bci_action_adjust_down_bound_serif,
3906 FDEF,
3908 PUSHB_4,
3912 bci_adjust_bound,
3913 CALL,
3915 ENDF,
3919 static const unsigned char FPGM(bci_action_adjust_down_bound_round) [] =
3922 PUSHB_1,
3923 bci_action_adjust_down_bound_round,
3924 FDEF,
3926 PUSHB_4,
3930 bci_adjust_bound,
3931 CALL,
3933 ENDF,
3937 static const unsigned char FPGM(bci_action_adjust_down_bound_round_serif) [] =
3940 PUSHB_1,
3941 bci_action_adjust_down_bound_round_serif,
3942 FDEF,
3944 PUSHB_4,
3948 bci_adjust_bound,
3949 CALL,
3951 ENDF,
3957 * bci_adjust
3959 * Handle the ADJUST action to align an edge of a stem if the other edge
3960 * of the stem has already been moved.
3962 * in: edge2_is_serif
3963 * edge_is_round
3964 * edge_point (in twilight zone)
3965 * edge2_point (in twilight zone)
3966 * ... stuff for bci_align_segments (edge) ...
3968 * uses: bci_adjust_common
3969 * bci_align_segments
3972 static const unsigned char FPGM(bci_adjust) [] =
3975 PUSHB_1,
3976 bci_adjust,
3977 FDEF,
3979 PUSHB_2,
3981 bci_adjust_common,
3982 CALL,
3984 MDAP_noround, /* set rp0 and rp1 to `edge' */
3986 PUSHB_2,
3987 bci_align_segments,
3989 SZP1, /* set zp1 to normal zone 1 */
3990 CALL,
3992 ENDF,
3998 * bci_action_adjust
3999 * bci_action_adjust_serif
4000 * bci_action_adjust_round
4001 * bci_action_adjust_round_serif
4003 * Higher-level routines for calling `bci_adjust'.
4006 static const unsigned char FPGM(bci_action_adjust) [] =
4009 PUSHB_1,
4010 bci_action_adjust,
4011 FDEF,
4013 PUSHB_3,
4016 bci_adjust,
4017 CALL,
4019 ENDF,
4023 static const unsigned char FPGM(bci_action_adjust_serif) [] =
4026 PUSHB_1,
4027 bci_action_adjust_serif,
4028 FDEF,
4030 PUSHB_3,
4033 bci_adjust,
4034 CALL,
4036 ENDF,
4040 static const unsigned char FPGM(bci_action_adjust_round) [] =
4043 PUSHB_1,
4044 bci_action_adjust_round,
4045 FDEF,
4047 PUSHB_3,
4050 bci_adjust,
4051 CALL,
4053 ENDF,
4057 static const unsigned char FPGM(bci_action_adjust_round_serif) [] =
4060 PUSHB_1,
4061 bci_action_adjust_round_serif,
4062 FDEF,
4064 PUSHB_3,
4067 bci_adjust,
4068 CALL,
4070 ENDF,
4076 * bci_stem_common
4078 * Common code for bci_action_stem routines.
4080 * in: top_to_bottom_hinting
4081 * edge2_is_serif
4082 * edge_is_round
4083 * edge
4084 * edge2
4086 * out: edge
4087 * cur_len
4088 * edge2
4090 * sal: sal_anchor
4091 * sal_temp1
4092 * sal_temp2
4093 * sal_temp3
4094 * sal_top_to_bottom_hinting
4095 * sal_base_delta
4097 * uses: func[sal_stem_width_function]
4098 * bci_round
4101 #undef sal_u_off
4102 #define sal_u_off sal_temp1
4103 #undef sal_d_off
4104 #define sal_d_off sal_temp2
4105 #undef sal_org_len
4106 #define sal_org_len sal_temp3
4107 #undef sal_edge2
4108 #define sal_edge2 sal_temp3
4110 static const unsigned char FPGM(bci_stem_common) [] =
4113 PUSHB_1,
4114 bci_stem_common,
4115 FDEF,
4117 PUSHB_1,
4119 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4121 PUSHB_1,
4122 sal_top_to_bottom_hinting,
4123 SWAP,
4126 PUSHB_1,
4128 CINDEX,
4129 PUSHB_1,
4131 CINDEX,
4132 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
4133 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4135 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
4136 DUP,
4137 PUSHB_1,
4138 sal_org_len,
4139 SWAP,
4142 PUSHB_2,
4143 sal_base_delta, /* no base_delta needed here */
4147 PUSHB_1,
4148 sal_stem_width_function,
4150 CALL, /* s: [...] edge2 edge cur_len */
4152 DUP,
4153 PUSHB_1,
4155 LT, /* cur_len < 96 */
4157 DUP,
4158 PUSHB_1,
4160 LTEQ, /* cur_len <= 64 */
4162 PUSHB_4,
4163 sal_u_off,
4165 sal_d_off,
4168 ELSE,
4169 PUSHB_4,
4170 sal_u_off,
4172 sal_d_off,
4174 EIF,
4178 SWAP, /* s: [...] edge2 cur_len edge */
4179 DUP,
4180 PUSHB_1,
4181 sal_anchor,
4183 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
4184 ROLL,
4185 SWAP,
4186 MD_orig_ZP2_0,
4187 SWAP,
4188 GC_cur,
4189 ADD, /* s: [...] edge2 cur_len edge org_pos */
4190 PUSHB_1,
4191 sal_org_len,
4193 DIV_BY_2,
4194 ADD, /* s: [...] edge2 cur_len edge org_center */
4196 DUP,
4197 PUSHB_1,
4198 bci_round,
4199 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
4201 DUP,
4202 ROLL,
4203 ROLL,
4204 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
4206 DUP,
4207 PUSHB_1,
4208 sal_u_off,
4210 ADD,
4211 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
4213 SWAP,
4214 PUSHB_1,
4215 sal_d_off,
4217 SUB,
4218 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
4220 LT, /* delta1 < delta2 */
4222 PUSHB_1,
4223 sal_u_off,
4225 SUB, /* cur_pos1 = cur_pos1 - u_off */
4227 ELSE,
4228 PUSHB_1,
4229 sal_d_off,
4231 ADD, /* cur_pos1 = cur_pos1 + d_off */
4232 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
4234 PUSHB_1,
4236 CINDEX,
4237 DIV_BY_2,
4238 SUB, /* arg = cur_pos1 - cur_len/2 */
4240 SWAP, /* s: [...] edge2 cur_len arg edge */
4241 DUP,
4242 DUP,
4243 PUSHB_1,
4245 MINDEX,
4246 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4247 GC_cur,
4248 SUB,
4249 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4251 ELSE,
4252 SWAP, /* s: [...] edge2 cur_len edge */
4253 PUSHB_1,
4254 sal_anchor,
4256 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
4257 PUSHB_1,
4259 CINDEX,
4260 PUSHB_1,
4261 sal_anchor,
4263 MD_orig_ZP2_0,
4264 ADD, /* s: [...] edge2 cur_len edge org_pos */
4266 DUP,
4267 PUSHB_1,
4268 sal_org_len,
4270 DIV_BY_2,
4271 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
4273 SWAP,
4274 DUP,
4275 PUSHB_1,
4276 bci_round,
4277 CALL, /* cur_pos1 = ROUND(org_pos) */
4278 SWAP,
4279 PUSHB_1,
4280 sal_org_len,
4282 ADD,
4283 PUSHB_1,
4284 bci_round,
4285 CALL,
4286 PUSHB_1,
4288 CINDEX,
4289 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
4291 PUSHB_1,
4293 CINDEX,
4294 DIV_BY_2,
4295 PUSHB_1,
4297 MINDEX,
4298 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
4300 DUP,
4301 PUSHB_1,
4303 CINDEX,
4304 ADD,
4305 ABS, /* delta1 = |cur_pos1 + cur_len / 2 - org_center| */
4306 SWAP,
4307 PUSHB_1,
4309 CINDEX,
4310 ADD,
4311 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
4312 LT, /* delta1 < delta2 */
4314 POP, /* arg = cur_pos1 */
4316 ELSE,
4317 SWAP,
4318 POP, /* arg = cur_pos2 */
4319 EIF, /* s: [...] edge2 cur_len edge arg */
4320 SWAP,
4321 DUP,
4322 DUP,
4323 PUSHB_1,
4325 MINDEX,
4326 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4327 GC_cur,
4328 SUB,
4329 SHPIX, /* edge = arg */
4330 EIF, /* s: [...] edge2 cur_len edge */
4332 ENDF,
4338 * bci_stem_bound
4340 * Handle the STEM action to align two edges of a stem, then moving one
4341 * edge again if necessary to stay bound.
4343 * The code after computing `cur_len' to shift `edge' and `edge2'
4344 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4346 * if cur_len < 96:
4347 * if cur_len < = 64:
4348 * u_off = 32
4349 * d_off = 32
4350 * else:
4351 * u_off = 38
4352 * d_off = 26
4354 * org_pos = anchor + (edge_orig - anchor_orig)
4355 * org_center = org_pos + org_len / 2
4357 * cur_pos1 = ROUND(org_center)
4358 * delta1 = |org_center - (cur_pos1 - u_off)|
4359 * delta2 = |org_center - (cur_pos1 + d_off)|
4360 * if (delta1 < delta2):
4361 * cur_pos1 = cur_pos1 - u_off
4362 * else:
4363 * cur_pos1 = cur_pos1 + d_off
4365 * edge = cur_pos1 - cur_len / 2
4367 * else:
4368 * org_pos = anchor + (edge_orig - anchor_orig)
4369 * org_center = org_pos + org_len / 2
4371 * cur_pos1 = ROUND(org_pos)
4372 * delta1 = |cur_pos1 + cur_len / 2 - org_center|
4373 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
4374 * delta2 = |cur_pos2 + cur_len / 2 - org_center|
4376 * if (delta1 < delta2):
4377 * edge = cur_pos1
4378 * else:
4379 * edge = cur_pos2
4381 * edge2 = edge + cur_len
4383 * in: top_to_bottom_hinting
4384 * edge2_is_serif
4385 * edge_is_round
4386 * edge_point (in twilight zone)
4387 * edge2_point (in twilight zone)
4388 * edge[-1] (in twilight zone)
4389 * ... stuff for bci_align_segments (edge) ...
4390 * ... stuff for bci_align_segments (edge2)...
4392 * sal: sal_anchor
4393 * sal_temp1
4394 * sal_temp2
4395 * sal_temp3
4396 * sal_top_to_bottom_hinting
4398 * uses: bci_stem_common
4399 * bci_align_segments
4402 static const unsigned char FPGM(bci_stem_bound) [] =
4405 PUSHB_1,
4406 bci_stem_bound,
4407 FDEF,
4409 PUSHB_1,
4410 bci_stem_common,
4411 CALL,
4413 ROLL, /* s: edge[-1] cur_len edge edge2 */
4414 DUP,
4415 DUP,
4416 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4417 PUSHB_1,
4418 sal_edge2,
4419 SWAP,
4420 WS, /* s: edge[-1] cur_len edge edge2 */
4421 ROLL,
4422 SHPIX, /* edge2 = edge + cur_len */
4424 SWAP, /* s: edge edge[-1] */
4425 DUP,
4426 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
4427 GC_cur,
4428 PUSHB_1,
4430 CINDEX,
4431 GC_cur, /* s: edge edge[-1]_pos edge_pos */
4432 PUSHB_1,
4433 sal_top_to_bottom_hinting,
4436 LT, /* edge_pos > edge[-1]_pos */
4437 ELSE,
4438 GT, /* edge_pos < edge[-1]_pos */
4439 EIF,
4441 DUP,
4442 ALIGNRP, /* align `edge' to `edge[-1]' */
4443 EIF,
4445 MDAP_noround, /* set rp0 and rp1 to `edge' */
4447 PUSHB_2,
4448 bci_align_segments,
4450 SZP1, /* set zp1 to normal zone 1 */
4451 CALL,
4453 PUSHB_1,
4454 sal_edge2,
4456 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4458 PUSHB_1,
4459 bci_align_segments,
4460 CALL,
4462 ENDF,
4468 * bci_action_stem_bound
4469 * bci_action_stem_bound_serif
4470 * bci_action_stem_bound_round
4471 * bci_action_stem_bound_round_serif
4472 * bci_action_stem_down_bound
4473 * bci_action_stem_down_bound_serif
4474 * bci_action_stem_down_bound_round
4475 * bci_action_stem_down_bound_round_serif
4477 * Higher-level routines for calling `bci_stem_bound'.
4480 static const unsigned char FPGM(bci_action_stem_bound) [] =
4483 PUSHB_1,
4484 bci_action_stem_bound,
4485 FDEF,
4487 PUSHB_4,
4491 bci_stem_bound,
4492 CALL,
4494 ENDF,
4498 static const unsigned char FPGM(bci_action_stem_bound_serif) [] =
4501 PUSHB_1,
4502 bci_action_stem_bound_serif,
4503 FDEF,
4505 PUSHB_4,
4509 bci_stem_bound,
4510 CALL,
4512 ENDF,
4516 static const unsigned char FPGM(bci_action_stem_bound_round) [] =
4519 PUSHB_1,
4520 bci_action_stem_bound_round,
4521 FDEF,
4523 PUSHB_4,
4527 bci_stem_bound,
4528 CALL,
4530 ENDF,
4534 static const unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
4537 PUSHB_1,
4538 bci_action_stem_bound_round_serif,
4539 FDEF,
4541 PUSHB_4,
4545 bci_stem_bound,
4546 CALL,
4548 ENDF,
4552 static const unsigned char FPGM(bci_action_stem_down_bound) [] =
4555 PUSHB_1,
4556 bci_action_stem_down_bound,
4557 FDEF,
4559 PUSHB_4,
4563 bci_stem_bound,
4564 CALL,
4566 ENDF,
4570 static const unsigned char FPGM(bci_action_stem_down_bound_serif) [] =
4573 PUSHB_1,
4574 bci_action_stem_down_bound_serif,
4575 FDEF,
4577 PUSHB_4,
4581 bci_stem_bound,
4582 CALL,
4584 ENDF,
4588 static const unsigned char FPGM(bci_action_stem_down_bound_round) [] =
4591 PUSHB_1,
4592 bci_action_stem_down_bound_round,
4593 FDEF,
4595 PUSHB_4,
4599 bci_stem_bound,
4600 CALL,
4602 ENDF,
4606 static const unsigned char FPGM(bci_action_stem_down_bound_round_serif) [] =
4609 PUSHB_1,
4610 bci_action_stem_down_bound_round_serif,
4611 FDEF,
4613 PUSHB_4,
4617 bci_stem_bound,
4618 CALL,
4620 ENDF,
4626 * bci_stem
4628 * Handle the STEM action to align two edges of a stem.
4630 * See `bci_stem_bound' for more details.
4632 * in: edge2_is_serif
4633 * edge_is_round
4634 * edge_point (in twilight zone)
4635 * edge2_point (in twilight zone)
4636 * ... stuff for bci_align_segments (edge) ...
4637 * ... stuff for bci_align_segments (edge2)...
4639 * sal: sal_anchor
4640 * sal_temp1
4641 * sal_temp2
4642 * sal_temp3
4644 * uses: bci_stem_common
4645 * bci_align_segments
4648 static const unsigned char FPGM(bci_stem) [] =
4651 PUSHB_1,
4652 bci_stem,
4653 FDEF,
4655 PUSHB_2,
4657 bci_stem_common,
4658 CALL,
4660 POP,
4661 SWAP, /* s: cur_len edge2 */
4662 DUP,
4663 DUP,
4664 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4665 PUSHB_1,
4666 sal_edge2,
4667 SWAP,
4668 WS, /* s: cur_len edge2 */
4669 SWAP,
4670 SHPIX, /* edge2 = edge + cur_len */
4672 PUSHB_2,
4673 bci_align_segments,
4675 SZP1, /* set zp1 to normal zone 1 */
4676 CALL,
4678 PUSHB_1,
4679 sal_edge2,
4681 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4683 PUSHB_1,
4684 bci_align_segments,
4685 CALL,
4686 ENDF,
4692 * bci_action_stem
4693 * bci_action_stem_serif
4694 * bci_action_stem_round
4695 * bci_action_stem_round_serif
4697 * Higher-level routines for calling `bci_stem'.
4700 static const unsigned char FPGM(bci_action_stem) [] =
4703 PUSHB_1,
4704 bci_action_stem,
4705 FDEF,
4707 PUSHB_3,
4710 bci_stem,
4711 CALL,
4713 ENDF,
4717 static const unsigned char FPGM(bci_action_stem_serif) [] =
4720 PUSHB_1,
4721 bci_action_stem_serif,
4722 FDEF,
4724 PUSHB_3,
4727 bci_stem,
4728 CALL,
4730 ENDF,
4734 static const unsigned char FPGM(bci_action_stem_round) [] =
4737 PUSHB_1,
4738 bci_action_stem_round,
4739 FDEF,
4741 PUSHB_3,
4744 bci_stem,
4745 CALL,
4747 ENDF,
4751 static const unsigned char FPGM(bci_action_stem_round_serif) [] =
4754 PUSHB_1,
4755 bci_action_stem_round_serif,
4756 FDEF,
4758 PUSHB_3,
4761 bci_stem,
4762 CALL,
4764 ENDF,
4770 * bci_link
4772 * Handle the LINK action to link an edge to another one.
4774 * in: stem_is_serif
4775 * base_is_round
4776 * base_point (in twilight zone)
4777 * stem_point (in twilight zone)
4778 * ... stuff for bci_align_segments (base) ...
4780 * sal: sal_base_delta
4782 * uses: func[sal_stem_width_function]
4783 * bci_align_segments
4786 static const unsigned char FPGM(bci_link) [] =
4789 PUSHB_1,
4790 bci_link,
4791 FDEF,
4793 PUSHB_1,
4795 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4797 PUSHB_1,
4799 CINDEX,
4800 PUSHB_1,
4802 MINDEX,
4803 DUP, /* s: stem is_round is_serif stem base base */
4805 DUP,
4806 DUP,
4807 GC_cur,
4808 SWAP,
4809 GC_orig,
4810 SUB, /* base_delta = base_point_pos - base_point_orig_pos */
4811 PUSHB_1,
4812 sal_base_delta,
4813 SWAP,
4814 WS, /* sal_base_delta = base_delta */
4816 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4818 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4820 PUSHB_1,
4821 sal_stem_width_function,
4823 CALL, /* s: stem new_dist */
4825 SWAP,
4826 DUP,
4827 ALIGNRP, /* align `stem_point' with `base_point' */
4828 DUP,
4829 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4830 SWAP,
4831 SHPIX, /* stem_point = base_point + new_dist */
4833 PUSHB_2,
4834 bci_align_segments,
4836 SZP1, /* set zp1 to normal zone 1 */
4837 CALL,
4839 ENDF,
4845 * bci_action_link
4846 * bci_action_link_serif
4847 * bci_action_link_round
4848 * bci_action_link_round_serif
4850 * Higher-level routines for calling `bci_link'.
4853 static const unsigned char FPGM(bci_action_link) [] =
4856 PUSHB_1,
4857 bci_action_link,
4858 FDEF,
4860 PUSHB_3,
4863 bci_link,
4864 CALL,
4866 ENDF,
4870 static const unsigned char FPGM(bci_action_link_serif) [] =
4873 PUSHB_1,
4874 bci_action_link_serif,
4875 FDEF,
4877 PUSHB_3,
4880 bci_link,
4881 CALL,
4883 ENDF,
4887 static const unsigned char FPGM(bci_action_link_round) [] =
4890 PUSHB_1,
4891 bci_action_link_round,
4892 FDEF,
4894 PUSHB_3,
4897 bci_link,
4898 CALL,
4900 ENDF,
4904 static const unsigned char FPGM(bci_action_link_round_serif) [] =
4907 PUSHB_1,
4908 bci_action_link_round_serif,
4909 FDEF,
4911 PUSHB_3,
4914 bci_link,
4915 CALL,
4917 ENDF,
4923 * bci_anchor
4925 * Handle the ANCHOR action to align two edges
4926 * and to set the edge anchor.
4928 * The code after computing `cur_len' to shift `edge' and `edge2'
4929 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4931 * if cur_len < 96:
4932 * if cur_len < = 64:
4933 * u_off = 32
4934 * d_off = 32
4935 * else:
4936 * u_off = 38
4937 * d_off = 26
4939 * org_center = edge_orig + org_len / 2
4940 * cur_pos1 = ROUND(org_center)
4942 * error1 = |org_center - (cur_pos1 - u_off)|
4943 * error2 = |org_center - (cur_pos1 + d_off)|
4944 * if (error1 < error2):
4945 * cur_pos1 = cur_pos1 - u_off
4946 * else:
4947 * cur_pos1 = cur_pos1 + d_off
4949 * edge = cur_pos1 - cur_len / 2
4950 * edge2 = edge + cur_len
4952 * else:
4953 * edge = ROUND(edge_orig)
4955 * in: edge2_is_serif
4956 * edge_is_round
4957 * edge_point (in twilight zone)
4958 * edge2_point (in twilight zone)
4959 * ... stuff for bci_align_segments (edge) ...
4961 * sal: sal_anchor
4962 * sal_temp1
4963 * sal_temp2
4964 * sal_temp3
4965 * sal_base_delta
4967 * uses: func[sal_stem_width_function]
4968 * bci_round
4969 * bci_align_segments
4972 #undef sal_u_off
4973 #define sal_u_off sal_temp1
4974 #undef sal_d_off
4975 #define sal_d_off sal_temp2
4976 #undef sal_org_len
4977 #define sal_org_len sal_temp3
4979 static const unsigned char FPGM(bci_anchor) [] =
4982 PUSHB_1,
4983 bci_anchor,
4984 FDEF,
4986 /* store anchor point number in `sal_anchor' */
4987 PUSHB_2,
4988 sal_anchor,
4990 CINDEX,
4991 WS, /* sal_anchor = edge_point */
4993 PUSHB_1,
4995 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4997 PUSHB_1,
4999 CINDEX,
5000 PUSHB_1,
5002 CINDEX,
5003 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
5004 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
5006 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
5007 DUP,
5008 PUSHB_1,
5009 sal_org_len,
5010 SWAP,
5013 PUSHB_2,
5014 sal_base_delta, /* no base_delta needed here */
5018 PUSHB_1,
5019 sal_stem_width_function,
5021 CALL, /* s: edge2 edge cur_len */
5023 DUP,
5024 PUSHB_1,
5026 LT, /* cur_len < 96 */
5028 DUP,
5029 PUSHB_1,
5031 LTEQ, /* cur_len <= 64 */
5033 PUSHB_4,
5034 sal_u_off,
5036 sal_d_off,
5039 ELSE,
5040 PUSHB_4,
5041 sal_u_off,
5043 sal_d_off,
5045 EIF,
5049 SWAP, /* s: edge2 cur_len edge */
5050 DUP, /* s: edge2 cur_len edge edge */
5052 GC_orig,
5053 PUSHB_1,
5054 sal_org_len,
5056 DIV_BY_2,
5057 ADD, /* s: edge2 cur_len edge org_center */
5059 DUP,
5060 PUSHB_1,
5061 bci_round,
5062 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
5064 DUP,
5065 ROLL,
5066 ROLL,
5067 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
5069 DUP,
5070 PUSHB_1,
5071 sal_u_off,
5073 ADD,
5074 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
5076 SWAP,
5077 PUSHB_1,
5078 sal_d_off,
5080 SUB,
5081 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
5083 LT, /* error1 < error2 */
5085 PUSHB_1,
5086 sal_u_off,
5088 SUB, /* cur_pos1 = cur_pos1 - u_off */
5090 ELSE,
5091 PUSHB_1,
5092 sal_d_off,
5094 ADD, /* cur_pos1 = cur_pos1 + d_off */
5095 EIF, /* s: edge2 cur_len edge cur_pos1 */
5097 PUSHB_1,
5099 CINDEX,
5100 DIV_BY_2,
5101 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
5103 PUSHB_1,
5105 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
5106 GC_cur,
5107 SUB,
5108 SHPIX, /* edge = cur_pos1 - cur_len/2 */
5110 SWAP, /* s: cur_len edge2 */
5111 DUP,
5112 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
5113 SWAP,
5114 SHPIX, /* edge2 = edge1 + cur_len */
5116 ELSE,
5117 POP, /* s: edge2 edge */
5118 DUP,
5119 DUP,
5120 GC_cur,
5121 SWAP,
5122 GC_orig,
5123 PUSHB_1,
5124 bci_round,
5125 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
5126 SWAP,
5127 SUB,
5128 SHPIX, /* edge = round(edge_orig) */
5130 /* clean up stack */
5131 POP,
5132 EIF,
5134 PUSHB_2,
5135 bci_align_segments,
5137 SZP1, /* set zp1 to normal zone 1 */
5138 CALL,
5140 ENDF,
5146 * bci_action_anchor
5147 * bci_action_anchor_serif
5148 * bci_action_anchor_round
5149 * bci_action_anchor_round_serif
5151 * Higher-level routines for calling `bci_anchor'.
5154 static const unsigned char FPGM(bci_action_anchor) [] =
5157 PUSHB_1,
5158 bci_action_anchor,
5159 FDEF,
5161 PUSHB_3,
5164 bci_anchor,
5165 CALL,
5167 ENDF,
5171 static const unsigned char FPGM(bci_action_anchor_serif) [] =
5174 PUSHB_1,
5175 bci_action_anchor_serif,
5176 FDEF,
5178 PUSHB_3,
5181 bci_anchor,
5182 CALL,
5184 ENDF,
5188 static const unsigned char FPGM(bci_action_anchor_round) [] =
5191 PUSHB_1,
5192 bci_action_anchor_round,
5193 FDEF,
5195 PUSHB_3,
5198 bci_anchor,
5199 CALL,
5201 ENDF,
5205 static const unsigned char FPGM(bci_action_anchor_round_serif) [] =
5208 PUSHB_1,
5209 bci_action_anchor_round_serif,
5210 FDEF,
5212 PUSHB_3,
5215 bci_anchor,
5216 CALL,
5218 ENDF,
5224 * bci_action_blue_anchor
5226 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
5227 * and to set the edge anchor.
5229 * in: anchor_point (in twilight zone)
5230 * blue_cvt_idx
5231 * edge_point (in twilight zone)
5232 * ... stuff for bci_align_segments (edge) ...
5234 * sal: sal_anchor
5236 * uses: bci_action_blue
5239 static const unsigned char FPGM(bci_action_blue_anchor) [] =
5242 PUSHB_1,
5243 bci_action_blue_anchor,
5244 FDEF,
5246 /* store anchor point number in `sal_anchor' */
5247 PUSHB_1,
5248 sal_anchor,
5249 SWAP,
5252 PUSHB_1,
5253 bci_action_blue,
5254 CALL,
5256 ENDF,
5262 * bci_action_blue
5264 * Handle the BLUE action to align an edge with a blue zone.
5266 * in: blue_cvt_idx
5267 * edge_point (in twilight zone)
5268 * ... stuff for bci_align_segments (edge) ...
5270 * uses: bci_align_segments
5273 static const unsigned char FPGM(bci_action_blue) [] =
5276 PUSHB_1,
5277 bci_action_blue,
5278 FDEF,
5280 PUSHB_1,
5282 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5284 /* move `edge_point' to `blue_cvt_idx' position; */
5285 /* note that we can't use MIAP since this would modify */
5286 /* the twilight point's original coordinates also */
5287 RCVT,
5288 SWAP,
5289 DUP,
5290 MDAP_noround, /* set rp0 and rp1 to `edge' */
5291 DUP,
5292 GC_cur, /* s: new_pos edge edge_pos */
5293 ROLL,
5294 SWAP,
5295 SUB, /* s: edge (new_pos - edge_pos) */
5296 SHPIX,
5298 PUSHB_2,
5299 bci_align_segments,
5301 SZP1, /* set zp1 to normal zone 1 */
5302 CALL,
5304 ENDF,
5310 * bci_serif_common
5312 * Common code for bci_action_serif routines.
5314 * in: top_to_bottom_hinting
5315 * serif
5316 * base
5318 * sal: sal_top_to_bottom_hinting
5322 static const unsigned char FPGM(bci_serif_common) [] =
5325 PUSHB_1,
5326 bci_serif_common,
5327 FDEF,
5329 PUSHB_1,
5331 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5333 PUSHB_1,
5334 sal_top_to_bottom_hinting,
5335 SWAP,
5338 DUP,
5339 DUP,
5340 DUP,
5341 PUSHB_1,
5343 MINDEX, /* s: [...] serif serif serif serif base */
5344 DUP,
5345 MDAP_noround, /* set rp0 and rp1 to `base_point' */
5346 MD_orig_ZP2_0,
5347 SWAP,
5348 ALIGNRP, /* align `serif_point' with `base_point' */
5349 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
5351 ENDF,
5357 * bci_lower_bound
5359 * Move an edge if necessary to stay within a lower bound.
5361 * in: edge
5362 * bound
5364 * sal: sal_top_to_bottom_hinting
5366 * uses: bci_align_segments
5369 static const unsigned char FPGM(bci_lower_bound) [] =
5372 PUSHB_1,
5373 bci_lower_bound,
5374 FDEF,
5376 SWAP, /* s: edge bound */
5377 DUP,
5378 MDAP_noround, /* set rp0 and rp1 to `bound' */
5379 GC_cur,
5380 PUSHB_1,
5382 CINDEX,
5383 GC_cur, /* s: edge bound_pos edge_pos */
5384 PUSHB_1,
5385 sal_top_to_bottom_hinting,
5388 LT, /* edge_pos > bound_pos */
5389 ELSE,
5390 GT, /* edge_pos < bound_pos */
5391 EIF,
5393 DUP,
5394 ALIGNRP, /* align `edge' to `bound' */
5395 EIF,
5397 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5399 PUSHB_2,
5400 bci_align_segments,
5402 SZP1, /* set zp1 to normal zone 1 */
5403 CALL,
5405 ENDF,
5411 * bci_upper_bound
5413 * Move an edge if necessary to stay within an upper bound.
5415 * in: edge
5416 * bound
5418 * sal: sal_top_to_bottom_hinting
5420 * uses: bci_align_segments
5423 static const unsigned char FPGM(bci_upper_bound) [] =
5426 PUSHB_1,
5427 bci_upper_bound,
5428 FDEF,
5430 SWAP, /* s: edge bound */
5431 DUP,
5432 MDAP_noround, /* set rp0 and rp1 to `bound' */
5433 GC_cur,
5434 PUSHB_1,
5436 CINDEX,
5437 GC_cur, /* s: edge bound_pos edge_pos */
5438 PUSHB_1,
5439 sal_top_to_bottom_hinting,
5442 GT, /* edge_pos < bound_pos */
5443 ELSE,
5444 LT, /* edge_pos > bound_pos */
5445 EIF,
5447 DUP,
5448 ALIGNRP, /* align `edge' to `bound' */
5449 EIF,
5451 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5453 PUSHB_2,
5454 bci_align_segments,
5456 SZP1, /* set zp1 to normal zone 1 */
5457 CALL,
5459 ENDF,
5465 * bci_upper_lower_bound
5467 * Move an edge if necessary to stay within a lower and lower bound.
5469 * in: edge
5470 * lower
5471 * upper
5473 * sal: sal_top_to_bottom_hinting
5475 * uses: bci_align_segments
5478 static const unsigned char FPGM(bci_upper_lower_bound) [] =
5481 PUSHB_1,
5482 bci_upper_lower_bound,
5483 FDEF,
5485 SWAP, /* s: upper serif lower */
5486 DUP,
5487 MDAP_noround, /* set rp0 and rp1 to `lower' */
5488 GC_cur,
5489 PUSHB_1,
5491 CINDEX,
5492 GC_cur, /* s: upper serif lower_pos serif_pos */
5493 PUSHB_1,
5494 sal_top_to_bottom_hinting,
5497 LT, /* serif_pos > lower_pos */
5498 ELSE,
5499 GT, /* serif_pos < lower_pos */
5500 EIF,
5502 DUP,
5503 ALIGNRP, /* align `serif' to `lower' */
5504 EIF,
5506 SWAP, /* s: serif upper */
5507 DUP,
5508 MDAP_noround, /* set rp0 and rp1 to `upper' */
5509 GC_cur,
5510 PUSHB_1,
5512 CINDEX,
5513 GC_cur, /* s: serif upper_pos serif_pos */
5514 PUSHB_1,
5515 sal_top_to_bottom_hinting,
5518 GT, /* serif_pos < upper_pos */
5519 ELSE,
5520 LT, /* serif_pos > upper_pos */
5521 EIF,
5523 DUP,
5524 ALIGNRP, /* align `serif' to `upper' */
5525 EIF,
5527 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5529 PUSHB_2,
5530 bci_align_segments,
5532 SZP1, /* set zp1 to normal zone 1 */
5533 CALL,
5535 ENDF,
5541 * bci_action_serif
5543 * Handle the SERIF action to align a serif with its base.
5545 * in: serif_point (in twilight zone)
5546 * base_point (in twilight zone)
5547 * ... stuff for bci_align_segments (serif) ...
5549 * uses: bci_serif_common
5550 * bci_align_segments
5553 static const unsigned char FPGM(bci_action_serif) [] =
5556 PUSHB_1,
5557 bci_action_serif,
5558 FDEF,
5560 PUSHB_2,
5562 bci_serif_common,
5563 CALL,
5565 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5567 PUSHB_2,
5568 bci_align_segments,
5570 SZP1, /* set zp1 to normal zone 1 */
5571 CALL,
5573 ENDF,
5579 * bci_action_serif_lower_bound
5581 * Handle the SERIF action to align a serif with its base, then moving it
5582 * again if necessary to stay within a lower bound.
5584 * in: serif_point (in twilight zone)
5585 * base_point (in twilight zone)
5586 * edge[-1] (in twilight zone)
5587 * ... stuff for bci_align_segments (serif) ...
5589 * uses: bci_serif_common
5590 * bci_lower_bound
5593 static const unsigned char FPGM(bci_action_serif_lower_bound) [] =
5596 PUSHB_1,
5597 bci_action_serif_lower_bound,
5598 FDEF,
5600 PUSHB_2,
5602 bci_serif_common,
5603 CALL,
5605 PUSHB_1,
5606 bci_lower_bound,
5607 CALL,
5609 ENDF,
5615 * bci_action_serif_upper_bound
5617 * Handle the SERIF action to align a serif with its base, then moving it
5618 * again if necessary to stay within an upper bound.
5620 * in: serif_point (in twilight zone)
5621 * base_point (in twilight zone)
5622 * edge[1] (in twilight zone)
5623 * ... stuff for bci_align_segments (serif) ...
5625 * uses: bci_serif_common
5626 * bci_upper_bound
5629 static const unsigned char FPGM(bci_action_serif_upper_bound) [] =
5632 PUSHB_1,
5633 bci_action_serif_upper_bound,
5634 FDEF,
5636 PUSHB_2,
5638 bci_serif_common,
5639 CALL,
5641 PUSHB_1,
5642 bci_upper_bound,
5643 CALL,
5645 ENDF,
5651 * bci_action_serif_upper_lower_bound
5653 * Handle the SERIF action to align a serif with its base, then moving it
5654 * again if necessary to stay within a lower and upper bound.
5656 * in: serif_point (in twilight zone)
5657 * base_point (in twilight zone)
5658 * edge[-1] (in twilight zone)
5659 * edge[1] (in twilight zone)
5660 * ... stuff for bci_align_segments (serif) ...
5662 * uses: bci_serif_common
5663 * bci_upper_lower_bound
5666 static const unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
5669 PUSHB_1,
5670 bci_action_serif_upper_lower_bound,
5671 FDEF,
5673 PUSHB_1,
5675 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5677 PUSHB_2,
5679 bci_serif_common,
5680 CALL,
5682 PUSHB_1,
5683 bci_upper_lower_bound,
5684 CALL,
5686 ENDF,
5692 * bci_action_serif_down_lower_bound
5694 * Handle the SERIF action to align a serif with its base, then moving it
5695 * again if necessary to stay within a lower bound. We hint top to
5696 * bottom.
5698 * in: serif_point (in twilight zone)
5699 * base_point (in twilight zone)
5700 * edge[-1] (in twilight zone)
5701 * ... stuff for bci_align_segments (serif) ...
5703 * uses: bci_serif_common
5704 * bci_lower_bound
5707 static const unsigned char FPGM(bci_action_serif_down_lower_bound) [] =
5710 PUSHB_1,
5711 bci_action_serif_down_lower_bound,
5712 FDEF,
5714 PUSHB_2,
5716 bci_serif_common,
5717 CALL,
5719 PUSHB_1,
5720 bci_lower_bound,
5721 CALL,
5723 ENDF,
5729 * bci_action_serif_down_upper_bound
5731 * Handle the SERIF action to align a serif with its base, then moving it
5732 * again if necessary to stay within an upper bound. We hint top to
5733 * bottom.
5735 * in: serif_point (in twilight zone)
5736 * base_point (in twilight zone)
5737 * edge[1] (in twilight zone)
5738 * ... stuff for bci_align_segments (serif) ...
5740 * uses: bci_serif_common
5741 * bci_upper_bound
5744 static const unsigned char FPGM(bci_action_serif_down_upper_bound) [] =
5747 PUSHB_1,
5748 bci_action_serif_down_upper_bound,
5749 FDEF,
5751 PUSHB_2,
5753 bci_serif_common,
5754 CALL,
5756 PUSHB_1,
5757 bci_upper_bound,
5758 CALL,
5760 ENDF,
5766 * bci_action_serif_down_upper_lower_bound
5768 * Handle the SERIF action to align a serif with its base, then moving it
5769 * again if necessary to stay within a lower and upper bound. We hint top
5770 * to bottom.
5772 * in: serif_point (in twilight zone)
5773 * base_point (in twilight zone)
5774 * edge[-1] (in twilight zone)
5775 * edge[1] (in twilight zone)
5776 * ... stuff for bci_align_segments (serif) ...
5778 * uses: bci_serif_common
5779 * bci_upper_lower_bound
5782 static const unsigned char FPGM(bci_action_serif_down_upper_lower_bound) [] =
5785 PUSHB_1,
5786 bci_action_serif_down_upper_lower_bound,
5787 FDEF,
5789 PUSHB_1,
5791 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5793 PUSHB_2,
5795 bci_serif_common,
5796 CALL,
5798 PUSHB_1,
5799 bci_upper_lower_bound,
5800 CALL,
5802 ENDF,
5808 * bci_serif_anchor_common
5810 * Common code for bci_action_serif_anchor routines.
5812 * in: top_to_bottom_hinting
5813 * edge
5815 * out: edge (adjusted)
5817 * sal: sal_anchor
5818 * sal_top_to_bottom_hinting
5820 * uses: bci_round
5823 static const unsigned char FPGM(bci_serif_anchor_common) [] =
5826 PUSHB_1,
5827 bci_serif_anchor_common,
5828 FDEF,
5830 PUSHB_1,
5832 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5834 PUSHB_1,
5835 sal_top_to_bottom_hinting,
5836 SWAP,
5839 DUP,
5840 PUSHB_1,
5841 sal_anchor,
5842 SWAP,
5843 WS, /* sal_anchor = edge_point */
5845 DUP,
5846 DUP,
5847 DUP,
5848 GC_cur,
5849 SWAP,
5850 GC_orig,
5851 PUSHB_1,
5852 bci_round,
5853 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
5854 SWAP,
5855 SUB,
5856 SHPIX, /* edge = round(edge_orig) */
5858 ENDF,
5864 * bci_action_serif_anchor
5866 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5867 * anchor.
5869 * in: edge_point (in twilight zone)
5870 * ... stuff for bci_align_segments (edge) ...
5872 * uses: bci_serif_anchor_common
5873 * bci_align_segments
5876 static const unsigned char FPGM(bci_action_serif_anchor) [] =
5879 PUSHB_1,
5880 bci_action_serif_anchor,
5881 FDEF,
5883 PUSHB_2,
5885 bci_serif_anchor_common,
5886 CALL,
5888 MDAP_noround, /* set rp0 and rp1 to `edge' */
5890 PUSHB_2,
5891 bci_align_segments,
5893 SZP1, /* set zp1 to normal zone 1 */
5894 CALL,
5896 ENDF,
5902 * bci_action_serif_anchor_lower_bound
5904 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5905 * anchor, then moving it again if necessary to stay within a lower
5906 * bound.
5908 * in: edge_point (in twilight zone)
5909 * edge[-1] (in twilight zone)
5910 * ... stuff for bci_align_segments (edge) ...
5912 * uses: bci_serif_anchor_common
5913 * bci_lower_bound
5916 static const unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
5919 PUSHB_1,
5920 bci_action_serif_anchor_lower_bound,
5921 FDEF,
5923 PUSHB_2,
5925 bci_serif_anchor_common,
5926 CALL,
5928 PUSHB_1,
5929 bci_lower_bound,
5930 CALL,
5932 ENDF,
5938 * bci_action_serif_anchor_upper_bound
5940 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5941 * anchor, then moving it again if necessary to stay within an upper
5942 * bound.
5944 * in: edge_point (in twilight zone)
5945 * edge[1] (in twilight zone)
5946 * ... stuff for bci_align_segments (edge) ...
5948 * uses: bci_serif_anchor_common
5949 * bci_upper_bound
5952 static const unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5955 PUSHB_1,
5956 bci_action_serif_anchor_upper_bound,
5957 FDEF,
5959 PUSHB_2,
5961 bci_serif_anchor_common,
5962 CALL,
5964 PUSHB_1,
5965 bci_upper_bound,
5966 CALL,
5968 ENDF,
5974 * bci_action_serif_anchor_upper_lower_bound
5976 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5977 * anchor, then moving it again if necessary to stay within a lower and
5978 * upper bound.
5980 * in: edge_point (in twilight zone)
5981 * edge[-1] (in twilight zone)
5982 * edge[1] (in twilight zone)
5983 * ... stuff for bci_align_segments (edge) ...
5985 * uses: bci_serif_anchor_common
5986 * bci_upper_lower_bound
5989 static const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5992 PUSHB_1,
5993 bci_action_serif_anchor_upper_lower_bound,
5994 FDEF,
5996 PUSHB_2,
5998 bci_serif_anchor_common,
5999 CALL,
6001 PUSHB_1,
6002 bci_upper_lower_bound,
6003 CALL,
6005 ENDF,
6011 * bci_action_serif_anchor_down_lower_bound
6013 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6014 * anchor, then moving it again if necessary to stay within a lower
6015 * bound. We hint top to bottom.
6017 * in: edge_point (in twilight zone)
6018 * edge[-1] (in twilight zone)
6019 * ... stuff for bci_align_segments (edge) ...
6021 * uses: bci_serif_anchor_common
6022 * bci_lower_bound
6025 static const unsigned char FPGM(bci_action_serif_anchor_down_lower_bound) [] =
6028 PUSHB_1,
6029 bci_action_serif_anchor_down_lower_bound,
6030 FDEF,
6032 PUSHB_2,
6034 bci_serif_anchor_common,
6035 CALL,
6037 PUSHB_1,
6038 bci_lower_bound,
6039 CALL,
6041 ENDF,
6047 * bci_action_serif_anchor_down_upper_bound
6049 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6050 * anchor, then moving it again if necessary to stay within an upper
6051 * bound. We hint top to bottom.
6053 * in: edge_point (in twilight zone)
6054 * edge[1] (in twilight zone)
6055 * ... stuff for bci_align_segments (edge) ...
6057 * uses: bci_serif_anchor_common
6058 * bci_upper_bound
6061 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_bound) [] =
6064 PUSHB_1,
6065 bci_action_serif_anchor_down_upper_bound,
6066 FDEF,
6068 PUSHB_2,
6070 bci_serif_anchor_common,
6071 CALL,
6073 PUSHB_1,
6074 bci_upper_bound,
6075 CALL,
6077 ENDF,
6083 * bci_action_serif_anchor_down_upper_lower_bound
6085 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6086 * anchor, then moving it again if necessary to stay within a lower and
6087 * upper bound. We hint top to bottom.
6089 * in: edge_point (in twilight zone)
6090 * edge[-1] (in twilight zone)
6091 * edge[1] (in twilight zone)
6092 * ... stuff for bci_align_segments (edge) ...
6094 * uses: bci_serif_anchor_common
6095 * bci_upper_lower_bound
6098 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_lower_bound) [] =
6101 PUSHB_1,
6102 bci_action_serif_anchor_down_upper_lower_bound,
6103 FDEF,
6105 PUSHB_2,
6107 bci_serif_anchor_common,
6108 CALL,
6110 PUSHB_1,
6111 bci_upper_lower_bound,
6112 CALL,
6114 ENDF,
6120 * bci_serif_link1_common
6122 * Common code for bci_action_serif_link1 routines.
6124 * in: top_to_bottom_hinting
6125 * before
6126 * edge
6127 * after
6129 * out: edge (adjusted)
6131 * sal: sal_top_to_bottom_hinting
6135 static const unsigned char FPGM(bci_serif_link1_common) [] =
6138 PUSHB_1,
6139 bci_serif_link1_common,
6140 FDEF,
6142 PUSHB_1,
6144 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6146 PUSHB_1,
6147 sal_top_to_bottom_hinting,
6148 SWAP,
6151 PUSHB_1,
6153 CINDEX, /* s: [...] after edge before after */
6154 PUSHB_1,
6156 CINDEX, /* s: [...] after edge before after before */
6157 MD_orig_ZP2_0,
6158 PUSHB_1,
6160 EQ, /* after_orig_pos == before_orig_pos */
6161 IF, /* s: [...] after edge before */
6162 MDAP_noround, /* set rp0 and rp1 to `before' */
6163 DUP,
6164 ALIGNRP, /* align `edge' with `before' */
6165 SWAP,
6166 POP,
6168 ELSE,
6169 /* we have to execute `a*b/c', with b/c very near to 1: */
6170 /* to avoid overflow while retaining precision, */
6171 /* we transform this to `a + a * (b-c)/c' */
6173 PUSHB_1,
6175 CINDEX, /* s: [...] after edge before edge */
6176 PUSHB_1,
6178 CINDEX, /* s: [...] after edge before edge before */
6179 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
6181 DUP,
6182 PUSHB_1,
6184 CINDEX, /* s: [...] after edge before a a after */
6185 PUSHB_1,
6187 CINDEX, /* s: [...] after edge before a a after before */
6188 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
6190 PUSHB_1,
6192 CINDEX, /* s: [...] after edge before a a c after */
6193 PUSHB_1,
6195 CINDEX, /* s: [...] after edge before a a c after before */
6196 MD_cur, /* b = after_pos - before_pos */
6198 PUSHB_1,
6200 CINDEX, /* s: [...] after edge before a a c b c */
6201 SUB, /* b-c */
6203 PUSHW_2,
6204 0x08, /* 0x800 */
6205 0x00,
6206 0x08, /* 0x800 */
6207 0x00,
6208 MUL, /* 0x10000 */
6209 MUL, /* (b-c) in 16.16 format */
6210 SWAP,
6212 DUP,
6213 IF, /* c != 0 ? */
6214 DIV, /* s: [...] after edge before a a (b-c)/c */
6215 ELSE,
6216 POP, /* avoid division by zero */
6217 EIF,
6219 MUL, /* a * (b-c)/c * 2^10 */
6220 DIV_BY_1024, /* a * (b-c)/c */
6221 ADD, /* a*b/c */
6223 SWAP,
6224 MDAP_noround, /* set rp0 and rp1 to `before' */
6225 SWAP, /* s: [...] after a*b/c edge */
6226 DUP,
6227 DUP,
6228 ALIGNRP, /* align `edge' with `before' */
6229 ROLL,
6230 SHPIX, /* shift `edge' by `a*b/c' */
6232 SWAP, /* s: [...] edge after */
6233 POP,
6234 EIF,
6236 ENDF,
6242 * bci_action_serif_link1
6244 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6245 * before and after.
6247 * in: before_point (in twilight zone)
6248 * edge_point (in twilight zone)
6249 * after_point (in twilight zone)
6250 * ... stuff for bci_align_segments (edge) ...
6252 * uses: bci_serif_link1_common
6253 * bci_align_segments
6256 static const unsigned char FPGM(bci_action_serif_link1) [] =
6259 PUSHB_1,
6260 bci_action_serif_link1,
6261 FDEF,
6263 PUSHB_2,
6265 bci_serif_link1_common,
6266 CALL,
6268 MDAP_noround, /* set rp0 and rp1 to `edge' */
6270 PUSHB_2,
6271 bci_align_segments,
6273 SZP1, /* set zp1 to normal zone 1 */
6274 CALL,
6276 ENDF,
6282 * bci_action_serif_link1_lower_bound
6284 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6285 * before and after. Additionally, move the serif again if necessary to
6286 * stay within a lower bound.
6288 * in: before_point (in twilight zone)
6289 * edge_point (in twilight zone)
6290 * after_point (in twilight zone)
6291 * edge[-1] (in twilight zone)
6292 * ... stuff for bci_align_segments (edge) ...
6294 * uses: bci_serif_link1_common
6295 * bci_lower_bound
6298 static const unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
6301 PUSHB_1,
6302 bci_action_serif_link1_lower_bound,
6303 FDEF,
6305 PUSHB_2,
6307 bci_serif_link1_common,
6308 CALL,
6310 PUSHB_1,
6311 bci_lower_bound,
6312 CALL,
6314 ENDF,
6320 * bci_action_serif_link1_upper_bound
6322 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6323 * before and after. Additionally, move the serif again if necessary to
6324 * stay within an upper bound.
6326 * in: before_point (in twilight zone)
6327 * edge_point (in twilight zone)
6328 * after_point (in twilight zone)
6329 * edge[1] (in twilight zone)
6330 * ... stuff for bci_align_segments (edge) ...
6332 * uses: bci_serif_link1_common
6333 * bci_upper_bound
6336 static const unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
6339 PUSHB_1,
6340 bci_action_serif_link1_upper_bound,
6341 FDEF,
6343 PUSHB_2,
6345 bci_serif_link1_common,
6346 CALL,
6348 PUSHB_1,
6349 bci_upper_bound,
6350 CALL,
6352 ENDF,
6358 * bci_action_serif_link1_upper_lower_bound
6360 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6361 * before and after. Additionally, move the serif again if necessary to
6362 * stay within a lower and upper bound.
6364 * in: before_point (in twilight zone)
6365 * edge_point (in twilight zone)
6366 * after_point (in twilight zone)
6367 * edge[-1] (in twilight zone)
6368 * edge[1] (in twilight zone)
6369 * ... stuff for bci_align_segments (edge) ...
6371 * uses: bci_serif_link1_common
6372 * bci_upper_lower_bound
6375 static const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
6378 PUSHB_1,
6379 bci_action_serif_link1_upper_lower_bound,
6380 FDEF,
6382 PUSHB_2,
6384 bci_serif_link1_common,
6385 CALL,
6387 PUSHB_1,
6388 bci_upper_lower_bound,
6389 CALL,
6391 ENDF,
6397 * bci_action_serif_link1_down_lower_bound
6399 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6400 * before and after. Additionally, move the serif again if necessary to
6401 * stay within a lower bound. We hint top to bottom.
6403 * in: before_point (in twilight zone)
6404 * edge_point (in twilight zone)
6405 * after_point (in twilight zone)
6406 * edge[-1] (in twilight zone)
6407 * ... stuff for bci_align_segments (edge) ...
6409 * uses: bci_serif_link1_common
6410 * bci_lower_bound
6413 static const unsigned char FPGM(bci_action_serif_link1_down_lower_bound) [] =
6416 PUSHB_1,
6417 bci_action_serif_link1_down_lower_bound,
6418 FDEF,
6420 PUSHB_2,
6422 bci_serif_link1_common,
6423 CALL,
6425 PUSHB_1,
6426 bci_lower_bound,
6427 CALL,
6429 ENDF,
6435 * bci_action_serif_link1_down_upper_bound
6437 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6438 * before and after. Additionally, move the serif again if necessary to
6439 * stay within an upper bound. We hint top to bottom.
6441 * in: before_point (in twilight zone)
6442 * edge_point (in twilight zone)
6443 * after_point (in twilight zone)
6444 * edge[1] (in twilight zone)
6445 * ... stuff for bci_align_segments (edge) ...
6447 * uses: bci_serif_link1_common
6448 * bci_upper_bound
6451 static const unsigned char FPGM(bci_action_serif_link1_down_upper_bound) [] =
6454 PUSHB_1,
6455 bci_action_serif_link1_down_upper_bound,
6456 FDEF,
6458 PUSHB_2,
6460 bci_serif_link1_common,
6461 CALL,
6463 PUSHB_1,
6464 bci_upper_bound,
6465 CALL,
6467 ENDF,
6473 * bci_action_serif_link1_down_upper_lower_bound
6475 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6476 * before and after. Additionally, move the serif again if necessary to
6477 * stay within a lower and upper bound. We hint top to bottom.
6479 * in: before_point (in twilight zone)
6480 * edge_point (in twilight zone)
6481 * after_point (in twilight zone)
6482 * edge[-1] (in twilight zone)
6483 * edge[1] (in twilight zone)
6484 * ... stuff for bci_align_segments (edge) ...
6486 * uses: bci_serif_link1_common
6487 * bci_upper_lower_bound
6490 static const unsigned char FPGM(bci_action_serif_link1_down_upper_lower_bound) [] =
6493 PUSHB_1,
6494 bci_action_serif_link1_down_upper_lower_bound,
6495 FDEF,
6497 PUSHB_2,
6499 bci_serif_link1_common,
6500 CALL,
6502 PUSHB_1,
6503 bci_upper_lower_bound,
6504 CALL,
6506 ENDF,
6512 * bci_serif_link2_common
6514 * Common code for bci_action_serif_link2 routines.
6516 * in: top_to_bottom_hinting
6517 * edge
6519 * out: edge (adjusted)
6521 * sal: sal_anchor
6522 * sal_top_to_bottom_hinting
6526 static const unsigned char FPGM(bci_serif_link2_common) [] =
6529 PUSHB_1,
6530 bci_serif_link2_common,
6531 FDEF,
6533 PUSHB_1,
6535 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6537 PUSHB_1,
6538 sal_top_to_bottom_hinting,
6539 SWAP,
6542 DUP, /* s: [...] edge edge */
6543 PUSHB_1,
6544 sal_anchor,
6546 DUP, /* s: [...] edge edge anchor anchor */
6547 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
6549 MD_orig_ZP2_0,
6550 DUP,
6551 ADD,
6552 PUSHB_1,
6554 ADD,
6555 FLOOR,
6556 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
6558 SWAP,
6559 DUP,
6560 DUP,
6561 ALIGNRP, /* align `edge' with `sal_anchor' */
6562 ROLL,
6563 SHPIX, /* shift `edge' by `delta' */
6565 ENDF,
6571 * bci_action_serif_link2
6573 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6575 * in: edge_point (in twilight zone)
6576 * ... stuff for bci_align_segments (edge) ...
6578 * uses: bci_serif_link2_common
6579 * bci_align_segments
6582 static const unsigned char FPGM(bci_action_serif_link2) [] =
6585 PUSHB_1,
6586 bci_action_serif_link2,
6587 FDEF,
6589 PUSHB_2,
6591 bci_serif_link2_common,
6592 CALL,
6594 MDAP_noround, /* set rp0 and rp1 to `edge' */
6596 PUSHB_2,
6597 bci_align_segments,
6599 SZP1, /* set zp1 to normal zone 1 */
6600 CALL,
6602 ENDF,
6608 * bci_action_serif_link2_lower_bound
6610 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6611 * Additionally, move the serif again if necessary to stay within a lower
6612 * bound.
6614 * in: edge_point (in twilight zone)
6615 * edge[-1] (in twilight zone)
6616 * ... stuff for bci_align_segments (edge) ...
6618 * uses: bci_serif_link2_common
6619 * bci_lower_bound
6622 static const unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
6625 PUSHB_1,
6626 bci_action_serif_link2_lower_bound,
6627 FDEF,
6629 PUSHB_2,
6631 bci_serif_link2_common,
6632 CALL,
6634 PUSHB_1,
6635 bci_lower_bound,
6636 CALL,
6638 ENDF,
6644 * bci_action_serif_link2_upper_bound
6646 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6647 * Additionally, move the serif again if necessary to stay within an upper
6648 * bound.
6650 * in: edge_point (in twilight zone)
6651 * edge[1] (in twilight zone)
6652 * ... stuff for bci_align_segments (edge) ...
6654 * uses: bci_serif_link2_common
6655 * bci_upper_bound
6658 static const unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
6661 PUSHB_1,
6662 bci_action_serif_link2_upper_bound,
6663 FDEF,
6665 PUSHB_2,
6667 bci_serif_link2_common,
6668 CALL,
6670 PUSHB_1,
6671 bci_upper_bound,
6672 CALL,
6674 ENDF,
6680 * bci_action_serif_link2_upper_lower_bound
6682 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6683 * Additionally, move the serif again if necessary to stay within a lower
6684 * and upper bound.
6686 * in: edge_point (in twilight zone)
6687 * edge[-1] (in twilight zone)
6688 * edge[1] (in twilight zone)
6689 * ... stuff for bci_align_segments (edge) ...
6691 * uses: bci_serif_link2_common
6692 * bci_upper_lower_bound
6695 static const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
6698 PUSHB_1,
6699 bci_action_serif_link2_upper_lower_bound,
6700 FDEF,
6702 PUSHB_2,
6704 bci_serif_link2_common,
6705 CALL,
6707 PUSHB_1,
6708 bci_upper_lower_bound,
6709 CALL,
6711 ENDF,
6717 * bci_action_serif_link2_down_lower_bound
6719 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6720 * Additionally, move the serif again if necessary to stay within a lower
6721 * bound. We hint top to bottom.
6723 * in: edge_point (in twilight zone)
6724 * edge[-1] (in twilight zone)
6725 * ... stuff for bci_align_segments (edge) ...
6727 * uses: bci_serif_link2_common
6728 * bci_lower_bound
6731 static const unsigned char FPGM(bci_action_serif_link2_down_lower_bound) [] =
6734 PUSHB_1,
6735 bci_action_serif_link2_down_lower_bound,
6736 FDEF,
6738 PUSHB_2,
6740 bci_serif_link2_common,
6741 CALL,
6743 PUSHB_1,
6744 bci_lower_bound,
6745 CALL,
6747 ENDF,
6753 * bci_action_serif_link2_down_upper_bound
6755 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6756 * Additionally, move the serif again if necessary to stay within an upper
6757 * bound. We hint top to bottom.
6759 * in: edge_point (in twilight zone)
6760 * edge[1] (in twilight zone)
6761 * ... stuff for bci_align_segments (edge) ...
6763 * uses: bci_serif_link2_common
6764 * bci_upper_bound
6767 static const unsigned char FPGM(bci_action_serif_link2_down_upper_bound) [] =
6770 PUSHB_1,
6771 bci_action_serif_link2_down_upper_bound,
6772 FDEF,
6774 PUSHB_2,
6776 bci_serif_link2_common,
6777 CALL,
6779 PUSHB_1,
6780 bci_upper_bound,
6781 CALL,
6783 ENDF,
6789 * bci_action_serif_link2_down_upper_lower_bound
6791 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6792 * Additionally, move the serif again if necessary to stay within a lower
6793 * and upper bound. We hint top to bottom.
6795 * in: edge_point (in twilight zone)
6796 * edge[-1] (in twilight zone)
6797 * edge[1] (in twilight zone)
6798 * ... stuff for bci_align_segments (edge) ...
6800 * uses: bci_serif_link2_common
6801 * bci_upper_lower_bound
6804 static const unsigned char FPGM(bci_action_serif_link2_down_upper_lower_bound) [] =
6807 PUSHB_1,
6808 bci_action_serif_link2_down_upper_lower_bound,
6809 FDEF,
6811 PUSHB_2,
6813 bci_serif_link2_common,
6814 CALL,
6816 PUSHB_1,
6817 bci_upper_lower_bound,
6818 CALL,
6820 ENDF,
6826 * bci_hint_glyph
6828 * This is the top-level glyph hinting function which parses the arguments
6829 * on the stack and calls subroutines.
6831 * in: action_0_func_idx
6832 * ... data ...
6833 * action_1_func_idx
6834 * ... data ...
6835 * ...
6837 * CVT: cvtl_is_subglyph
6838 * cvtl_stem_width_mode
6839 * cvtl_do_iup_y
6841 * sal: sal_stem_width_function
6843 * uses: bci_action_ip_before
6844 * bci_action_ip_after
6845 * bci_action_ip_on
6846 * bci_action_ip_between
6848 * bci_action_adjust_bound
6849 * bci_action_adjust_bound_serif
6850 * bci_action_adjust_bound_round
6851 * bci_action_adjust_bound_round_serif
6853 * bci_action_stem_bound
6854 * bci_action_stem_bound_serif
6855 * bci_action_stem_bound_round
6856 * bci_action_stem_bound_round_serif
6858 * bci_action_link
6859 * bci_action_link_serif
6860 * bci_action_link_round
6861 * bci_action_link_round_serif
6863 * bci_action_anchor
6864 * bci_action_anchor_serif
6865 * bci_action_anchor_round
6866 * bci_action_anchor_round_serif
6868 * bci_action_blue_anchor
6870 * bci_action_adjust
6871 * bci_action_adjust_serif
6872 * bci_action_adjust_round
6873 * bci_action_adjust_round_serif
6875 * bci_action_stem
6876 * bci_action_stem_serif
6877 * bci_action_stem_round
6878 * bci_action_stem_round_serif
6880 * bci_action_blue
6882 * bci_action_serif
6883 * bci_action_serif_lower_bound
6884 * bci_action_serif_upper_bound
6885 * bci_action_serif_upper_lower_bound
6887 * bci_action_serif_anchor
6888 * bci_action_serif_anchor_lower_bound
6889 * bci_action_serif_anchor_upper_bound
6890 * bci_action_serif_anchor_upper_lower_bound
6892 * bci_action_serif_link1
6893 * bci_action_serif_link1_lower_bound
6894 * bci_action_serif_link1_upper_bound
6895 * bci_action_serif_link1_upper_lower_bound
6897 * bci_action_serif_link2
6898 * bci_action_serif_link2_lower_bound
6899 * bci_action_serif_link2_upper_bound
6900 * bci_action_serif_link2_upper_lower_bound
6903 static const unsigned char FPGM(bci_hint_glyph) [] =
6906 PUSHB_1,
6907 bci_hint_glyph,
6908 FDEF,
6911 * set up stem width function based on flag in CVT:
6913 * < 0: bci_natural_stem_width
6914 * == 0: bci_smooth_stem_width
6915 * > 0: bci_strong_stem_width
6917 PUSHB_3,
6918 sal_stem_width_function,
6920 cvtl_stem_width_mode,
6921 RCVT,
6924 PUSHB_1,
6925 bci_strong_stem_width,
6927 ELSE,
6928 PUSHB_3,
6929 bci_smooth_stem_width,
6930 bci_natural_stem_width,
6931 cvtl_stem_width_mode,
6932 RCVT,
6934 SWAP,
6935 POP,
6937 ELSE,
6938 POP,
6939 EIF,
6940 EIF,
6943 /* start_loop: */
6944 /* loop until all data on stack is used */
6945 CALL,
6946 PUSHB_1,
6948 NEG,
6949 PUSHB_1,
6951 DEPTH,
6953 JROT, /* goto start_loop */
6955 PUSHB_2,
6956 cvtl_do_iup_y,
6958 SZP2, /* set zp2 to normal zone 1 */
6959 RCVT,
6961 IUP_y,
6962 EIF,
6964 ENDF,
6969 #define COPY_FPGM(func_name) \
6970 do \
6972 memcpy(bufp, fpgm_ ## func_name, \
6973 sizeof (fpgm_ ## func_name)); \
6974 bufp += sizeof (fpgm_ ## func_name); \
6975 } while (0)
6977 static FT_Error
6978 TA_table_build_fpgm(FT_Byte** fpgm,
6979 FT_ULong* fpgm_len,
6980 SFNT* sfnt,
6981 FONT* font)
6983 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6984 glyf_Data* data = (glyf_Data*)glyf_table->data;
6986 unsigned char num_used_styles = (unsigned char)data->num_used_styles;
6987 unsigned char fallback_style =
6988 CVT_SCALING_VALUE_OFFSET(0)
6989 + (unsigned char)data->style_ids[font->fallback_style];
6991 FT_UInt buf_len;
6992 FT_UInt len;
6993 FT_Byte* buf;
6994 FT_Byte* bufp;
6997 /* for compatibility with dumb bytecode interpreters or analyzers, */
6998 /* FDEFs are stored in ascending index order, without holes -- */
6999 /* note that some FDEFs are not always needed */
7000 /* (depending on options of `TTFautohint'), */
7001 /* but implementing dynamic FDEF indices would be a lot of work */
7003 buf_len = sizeof (FPGM(bci_align_x_height_a))
7004 + (font->increase_x_height
7005 ? (sizeof (FPGM(bci_align_x_height_b1a))
7007 + sizeof (FPGM(bci_align_x_height_b1b)))
7008 : sizeof (FPGM(bci_align_x_height_b2)))
7009 + sizeof (FPGM(bci_align_x_height_c))
7010 + sizeof (FPGM(bci_round))
7011 + sizeof (FPGM(bci_natural_stem_width))
7012 + sizeof (FPGM(bci_quantize_stem_width))
7013 + sizeof (FPGM(bci_smooth_stem_width))
7014 + sizeof (FPGM(bci_get_best_width))
7015 + sizeof (FPGM(bci_strong_stem_width_a))
7017 + sizeof (FPGM(bci_strong_stem_width_b))
7018 + sizeof (FPGM(bci_loop_do))
7019 + sizeof (FPGM(bci_loop))
7020 + sizeof (FPGM(bci_cvt_rescale))
7021 + sizeof (FPGM(bci_cvt_rescale_range))
7022 + sizeof (FPGM(bci_vwidth_data_store))
7023 + sizeof (FPGM(bci_smooth_blue_round))
7024 + sizeof (FPGM(bci_strong_blue_round))
7025 + sizeof (FPGM(bci_blue_round_range))
7026 + sizeof (FPGM(bci_decrement_component_counter))
7027 + sizeof (FPGM(bci_get_point_extrema))
7028 + sizeof (FPGM(bci_nibbles))
7029 + sizeof (FPGM(bci_number_set_is_element))
7030 + sizeof (FPGM(bci_number_set_is_element2))
7032 + sizeof (FPGM(bci_create_segment))
7033 + sizeof (FPGM(bci_create_segments_a))
7035 + sizeof (FPGM(bci_create_segments_b))
7036 + (font->control_data_head != 0
7037 ? sizeof (FPGM(bci_create_segments_c))
7038 : 0)
7039 + sizeof (FPGM(bci_create_segments_d))
7041 + sizeof (FPGM(bci_create_segments_0))
7042 + sizeof (FPGM(bci_create_segments_1))
7043 + sizeof (FPGM(bci_create_segments_2))
7044 + sizeof (FPGM(bci_create_segments_3))
7045 + sizeof (FPGM(bci_create_segments_4))
7046 + sizeof (FPGM(bci_create_segments_5))
7047 + sizeof (FPGM(bci_create_segments_6))
7048 + sizeof (FPGM(bci_create_segments_7))
7049 + sizeof (FPGM(bci_create_segments_8))
7050 + sizeof (FPGM(bci_create_segments_9))
7052 + sizeof (FPGM(bci_deltap1))
7053 + sizeof (FPGM(bci_deltap2))
7054 + sizeof (FPGM(bci_deltap3))
7056 + sizeof (FPGM(bci_create_segments_composite_a))
7058 + sizeof (FPGM(bci_create_segments_composite_b))
7059 + (font->control_data_head != 0
7060 ? sizeof (FPGM(bci_create_segments_composite_c))
7061 : 0)
7062 + sizeof (FPGM(bci_create_segments_composite_d))
7064 + sizeof (FPGM(bci_create_segments_composite_0))
7065 + sizeof (FPGM(bci_create_segments_composite_1))
7066 + sizeof (FPGM(bci_create_segments_composite_2))
7067 + sizeof (FPGM(bci_create_segments_composite_3))
7068 + sizeof (FPGM(bci_create_segments_composite_4))
7069 + sizeof (FPGM(bci_create_segments_composite_5))
7070 + sizeof (FPGM(bci_create_segments_composite_6))
7071 + sizeof (FPGM(bci_create_segments_composite_7))
7072 + sizeof (FPGM(bci_create_segments_composite_8))
7073 + sizeof (FPGM(bci_create_segments_composite_9))
7075 + sizeof (FPGM(bci_align_point))
7076 + sizeof (FPGM(bci_align_segment))
7077 + sizeof (FPGM(bci_align_segments))
7079 + sizeof (FPGM(bci_scale_contour))
7080 + sizeof (FPGM(bci_scale_glyph_a))
7082 + sizeof (FPGM(bci_scale_glyph_b))
7083 + sizeof (FPGM(bci_scale_composite_glyph_a))
7085 + sizeof (FPGM(bci_scale_composite_glyph_b))
7086 + sizeof (FPGM(bci_shift_contour))
7087 + sizeof (FPGM(bci_shift_subglyph_a))
7089 + sizeof (FPGM(bci_shift_subglyph_b))
7090 + (font->control_data_head != 0
7091 ? sizeof (FPGM(bci_shift_subglyph_c))
7092 : 0)
7093 + sizeof (FPGM(bci_shift_subglyph_d))
7095 + sizeof (FPGM(bci_ip_outer_align_point))
7096 + sizeof (FPGM(bci_ip_on_align_points))
7097 + sizeof (FPGM(bci_ip_between_align_point))
7098 + sizeof (FPGM(bci_ip_between_align_points))
7100 + sizeof (FPGM(bci_adjust_common))
7101 + sizeof (FPGM(bci_stem_common))
7102 + sizeof (FPGM(bci_serif_common))
7103 + sizeof (FPGM(bci_serif_anchor_common))
7104 + sizeof (FPGM(bci_serif_link1_common))
7105 + sizeof (FPGM(bci_serif_link2_common))
7107 + sizeof (FPGM(bci_lower_bound))
7108 + sizeof (FPGM(bci_upper_bound))
7109 + sizeof (FPGM(bci_upper_lower_bound))
7111 + sizeof (FPGM(bci_adjust_bound))
7112 + sizeof (FPGM(bci_stem_bound))
7113 + sizeof (FPGM(bci_link))
7114 + sizeof (FPGM(bci_anchor))
7115 + sizeof (FPGM(bci_adjust))
7116 + sizeof (FPGM(bci_stem))
7118 + sizeof (FPGM(bci_action_ip_before))
7119 + sizeof (FPGM(bci_action_ip_after))
7120 + sizeof (FPGM(bci_action_ip_on))
7121 + sizeof (FPGM(bci_action_ip_between))
7123 + sizeof (FPGM(bci_action_blue))
7124 + sizeof (FPGM(bci_action_blue_anchor))
7126 + sizeof (FPGM(bci_action_anchor))
7127 + sizeof (FPGM(bci_action_anchor_serif))
7128 + sizeof (FPGM(bci_action_anchor_round))
7129 + sizeof (FPGM(bci_action_anchor_round_serif))
7131 + sizeof (FPGM(bci_action_adjust))
7132 + sizeof (FPGM(bci_action_adjust_serif))
7133 + sizeof (FPGM(bci_action_adjust_round))
7134 + sizeof (FPGM(bci_action_adjust_round_serif))
7135 + sizeof (FPGM(bci_action_adjust_bound))
7136 + sizeof (FPGM(bci_action_adjust_bound_serif))
7137 + sizeof (FPGM(bci_action_adjust_bound_round))
7138 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
7139 + sizeof (FPGM(bci_action_adjust_down_bound))
7140 + sizeof (FPGM(bci_action_adjust_down_bound_serif))
7141 + sizeof (FPGM(bci_action_adjust_down_bound_round))
7142 + sizeof (FPGM(bci_action_adjust_down_bound_round_serif))
7144 + sizeof (FPGM(bci_action_link))
7145 + sizeof (FPGM(bci_action_link_serif))
7146 + sizeof (FPGM(bci_action_link_round))
7147 + sizeof (FPGM(bci_action_link_round_serif))
7149 + sizeof (FPGM(bci_action_stem))
7150 + sizeof (FPGM(bci_action_stem_serif))
7151 + sizeof (FPGM(bci_action_stem_round))
7152 + sizeof (FPGM(bci_action_stem_round_serif))
7153 + sizeof (FPGM(bci_action_stem_bound))
7154 + sizeof (FPGM(bci_action_stem_bound_serif))
7155 + sizeof (FPGM(bci_action_stem_bound_round))
7156 + sizeof (FPGM(bci_action_stem_bound_round_serif))
7157 + sizeof (FPGM(bci_action_stem_down_bound))
7158 + sizeof (FPGM(bci_action_stem_down_bound_serif))
7159 + sizeof (FPGM(bci_action_stem_down_bound_round))
7160 + sizeof (FPGM(bci_action_stem_down_bound_round_serif))
7162 + sizeof (FPGM(bci_action_serif))
7163 + sizeof (FPGM(bci_action_serif_lower_bound))
7164 + sizeof (FPGM(bci_action_serif_upper_bound))
7165 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
7166 + sizeof (FPGM(bci_action_serif_down_lower_bound))
7167 + sizeof (FPGM(bci_action_serif_down_upper_bound))
7168 + sizeof (FPGM(bci_action_serif_down_upper_lower_bound))
7170 + sizeof (FPGM(bci_action_serif_anchor))
7171 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
7172 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
7173 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
7174 + sizeof (FPGM(bci_action_serif_anchor_down_lower_bound))
7175 + sizeof (FPGM(bci_action_serif_anchor_down_upper_bound))
7176 + sizeof (FPGM(bci_action_serif_anchor_down_upper_lower_bound))
7178 + sizeof (FPGM(bci_action_serif_link1))
7179 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
7180 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
7181 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
7182 + sizeof (FPGM(bci_action_serif_link1_down_lower_bound))
7183 + sizeof (FPGM(bci_action_serif_link1_down_upper_bound))
7184 + sizeof (FPGM(bci_action_serif_link1_down_upper_lower_bound))
7186 + sizeof (FPGM(bci_action_serif_link2))
7187 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
7188 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
7189 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
7190 + sizeof (FPGM(bci_action_serif_link2_down_lower_bound))
7191 + sizeof (FPGM(bci_action_serif_link2_down_upper_bound))
7192 + sizeof (FPGM(bci_action_serif_link2_down_upper_lower_bound))
7194 + sizeof (FPGM(bci_hint_glyph));
7196 /* buffer length must be a multiple of four */
7197 len = (buf_len + 3) & ~3U;
7198 buf = (FT_Byte*)malloc(len);
7199 if (!buf)
7200 return FT_Err_Out_Of_Memory;
7202 /* pad end of buffer with zeros */
7203 buf[len - 1] = 0x00;
7204 buf[len - 2] = 0x00;
7205 buf[len - 3] = 0x00;
7207 /* copy font program into buffer and fill in the missing variables */
7208 bufp = buf;
7210 COPY_FPGM(bci_align_x_height_a);
7211 if (font->increase_x_height)
7213 COPY_FPGM(bci_align_x_height_b1a);
7214 *(bufp++) = HIGH(font->increase_x_height);
7215 *(bufp++) = LOW(font->increase_x_height);
7216 COPY_FPGM(bci_align_x_height_b1b);
7218 else
7219 COPY_FPGM(bci_align_x_height_b2);
7220 COPY_FPGM(bci_align_x_height_c);
7222 COPY_FPGM(bci_round);
7223 COPY_FPGM(bci_natural_stem_width);
7224 COPY_FPGM(bci_quantize_stem_width);
7225 COPY_FPGM(bci_smooth_stem_width);
7226 COPY_FPGM(bci_get_best_width);
7227 COPY_FPGM(bci_strong_stem_width_a);
7228 *(bufp++) = num_used_styles;
7229 COPY_FPGM(bci_strong_stem_width_b);
7230 COPY_FPGM(bci_loop_do);
7231 COPY_FPGM(bci_loop);
7232 COPY_FPGM(bci_cvt_rescale);
7233 COPY_FPGM(bci_cvt_rescale_range);
7234 COPY_FPGM(bci_vwidth_data_store);
7235 COPY_FPGM(bci_smooth_blue_round);
7236 COPY_FPGM(bci_strong_blue_round);
7237 COPY_FPGM(bci_blue_round_range);
7238 COPY_FPGM(bci_decrement_component_counter);
7239 COPY_FPGM(bci_get_point_extrema);
7240 COPY_FPGM(bci_nibbles);
7241 COPY_FPGM(bci_number_set_is_element);
7242 COPY_FPGM(bci_number_set_is_element2);
7244 COPY_FPGM(bci_create_segment);
7245 COPY_FPGM(bci_create_segments_a);
7246 *(bufp++) = num_used_styles;
7247 COPY_FPGM(bci_create_segments_b);
7248 if (font->control_data_head)
7249 COPY_FPGM(bci_create_segments_c);
7250 COPY_FPGM(bci_create_segments_d);
7252 COPY_FPGM(bci_create_segments_0);
7253 COPY_FPGM(bci_create_segments_1);
7254 COPY_FPGM(bci_create_segments_2);
7255 COPY_FPGM(bci_create_segments_3);
7256 COPY_FPGM(bci_create_segments_4);
7257 COPY_FPGM(bci_create_segments_5);
7258 COPY_FPGM(bci_create_segments_6);
7259 COPY_FPGM(bci_create_segments_7);
7260 COPY_FPGM(bci_create_segments_8);
7261 COPY_FPGM(bci_create_segments_9);
7263 COPY_FPGM(bci_deltap1);
7264 COPY_FPGM(bci_deltap2);
7265 COPY_FPGM(bci_deltap3);
7267 COPY_FPGM(bci_create_segments_composite_a);
7268 *(bufp++) = num_used_styles;
7269 COPY_FPGM(bci_create_segments_composite_b);
7270 if (font->control_data_head)
7271 COPY_FPGM(bci_create_segments_composite_c);
7272 COPY_FPGM(bci_create_segments_composite_d);
7274 COPY_FPGM(bci_create_segments_composite_0);
7275 COPY_FPGM(bci_create_segments_composite_1);
7276 COPY_FPGM(bci_create_segments_composite_2);
7277 COPY_FPGM(bci_create_segments_composite_3);
7278 COPY_FPGM(bci_create_segments_composite_4);
7279 COPY_FPGM(bci_create_segments_composite_5);
7280 COPY_FPGM(bci_create_segments_composite_6);
7281 COPY_FPGM(bci_create_segments_composite_7);
7282 COPY_FPGM(bci_create_segments_composite_8);
7283 COPY_FPGM(bci_create_segments_composite_9);
7285 COPY_FPGM(bci_align_point);
7286 COPY_FPGM(bci_align_segment);
7287 COPY_FPGM(bci_align_segments);
7289 COPY_FPGM(bci_scale_contour);
7290 COPY_FPGM(bci_scale_glyph_a);
7291 *(bufp++) = fallback_style;
7292 COPY_FPGM(bci_scale_glyph_b);
7293 COPY_FPGM(bci_scale_composite_glyph_a);
7294 *(bufp++) = fallback_style;
7295 COPY_FPGM(bci_scale_composite_glyph_b);
7296 COPY_FPGM(bci_shift_contour);
7297 COPY_FPGM(bci_shift_subglyph_a);
7298 *(bufp++) = fallback_style;
7299 COPY_FPGM(bci_shift_subglyph_b);
7300 if (font->control_data_head)
7301 COPY_FPGM(bci_shift_subglyph_c);
7302 COPY_FPGM(bci_shift_subglyph_d);
7304 COPY_FPGM(bci_ip_outer_align_point);
7305 COPY_FPGM(bci_ip_on_align_points);
7306 COPY_FPGM(bci_ip_between_align_point);
7307 COPY_FPGM(bci_ip_between_align_points);
7309 COPY_FPGM(bci_adjust_common);
7310 COPY_FPGM(bci_stem_common);
7311 COPY_FPGM(bci_serif_common);
7312 COPY_FPGM(bci_serif_anchor_common);
7313 COPY_FPGM(bci_serif_link1_common);
7314 COPY_FPGM(bci_serif_link2_common);
7316 COPY_FPGM(bci_lower_bound);
7317 COPY_FPGM(bci_upper_bound);
7318 COPY_FPGM(bci_upper_lower_bound);
7320 COPY_FPGM(bci_adjust_bound);
7321 COPY_FPGM(bci_stem_bound);
7322 COPY_FPGM(bci_link);
7323 COPY_FPGM(bci_anchor);
7324 COPY_FPGM(bci_adjust);
7325 COPY_FPGM(bci_stem);
7327 COPY_FPGM(bci_action_ip_before);
7328 COPY_FPGM(bci_action_ip_after);
7329 COPY_FPGM(bci_action_ip_on);
7330 COPY_FPGM(bci_action_ip_between);
7332 COPY_FPGM(bci_action_blue);
7333 COPY_FPGM(bci_action_blue_anchor);
7335 COPY_FPGM(bci_action_anchor);
7336 COPY_FPGM(bci_action_anchor_serif);
7337 COPY_FPGM(bci_action_anchor_round);
7338 COPY_FPGM(bci_action_anchor_round_serif);
7340 COPY_FPGM(bci_action_adjust);
7341 COPY_FPGM(bci_action_adjust_serif);
7342 COPY_FPGM(bci_action_adjust_round);
7343 COPY_FPGM(bci_action_adjust_round_serif);
7344 COPY_FPGM(bci_action_adjust_bound);
7345 COPY_FPGM(bci_action_adjust_bound_serif);
7346 COPY_FPGM(bci_action_adjust_bound_round);
7347 COPY_FPGM(bci_action_adjust_bound_round_serif);
7348 COPY_FPGM(bci_action_adjust_down_bound);
7349 COPY_FPGM(bci_action_adjust_down_bound_serif);
7350 COPY_FPGM(bci_action_adjust_down_bound_round);
7351 COPY_FPGM(bci_action_adjust_down_bound_round_serif);
7353 COPY_FPGM(bci_action_link);
7354 COPY_FPGM(bci_action_link_serif);
7355 COPY_FPGM(bci_action_link_round);
7356 COPY_FPGM(bci_action_link_round_serif);
7358 COPY_FPGM(bci_action_stem);
7359 COPY_FPGM(bci_action_stem_serif);
7360 COPY_FPGM(bci_action_stem_round);
7361 COPY_FPGM(bci_action_stem_round_serif);
7362 COPY_FPGM(bci_action_stem_bound);
7363 COPY_FPGM(bci_action_stem_bound_serif);
7364 COPY_FPGM(bci_action_stem_bound_round);
7365 COPY_FPGM(bci_action_stem_bound_round_serif);
7366 COPY_FPGM(bci_action_stem_down_bound);
7367 COPY_FPGM(bci_action_stem_down_bound_serif);
7368 COPY_FPGM(bci_action_stem_down_bound_round);
7369 COPY_FPGM(bci_action_stem_down_bound_round_serif);
7371 COPY_FPGM(bci_action_serif);
7372 COPY_FPGM(bci_action_serif_lower_bound);
7373 COPY_FPGM(bci_action_serif_upper_bound);
7374 COPY_FPGM(bci_action_serif_upper_lower_bound);
7375 COPY_FPGM(bci_action_serif_down_lower_bound);
7376 COPY_FPGM(bci_action_serif_down_upper_bound);
7377 COPY_FPGM(bci_action_serif_down_upper_lower_bound);
7379 COPY_FPGM(bci_action_serif_anchor);
7380 COPY_FPGM(bci_action_serif_anchor_lower_bound);
7381 COPY_FPGM(bci_action_serif_anchor_upper_bound);
7382 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
7383 COPY_FPGM(bci_action_serif_anchor_down_lower_bound);
7384 COPY_FPGM(bci_action_serif_anchor_down_upper_bound);
7385 COPY_FPGM(bci_action_serif_anchor_down_upper_lower_bound);
7387 COPY_FPGM(bci_action_serif_link1);
7388 COPY_FPGM(bci_action_serif_link1_lower_bound);
7389 COPY_FPGM(bci_action_serif_link1_upper_bound);
7390 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
7391 COPY_FPGM(bci_action_serif_link1_down_lower_bound);
7392 COPY_FPGM(bci_action_serif_link1_down_upper_bound);
7393 COPY_FPGM(bci_action_serif_link1_down_upper_lower_bound);
7395 COPY_FPGM(bci_action_serif_link2);
7396 COPY_FPGM(bci_action_serif_link2_lower_bound);
7397 COPY_FPGM(bci_action_serif_link2_upper_bound);
7398 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
7399 COPY_FPGM(bci_action_serif_link2_down_lower_bound);
7400 COPY_FPGM(bci_action_serif_link2_down_upper_bound);
7401 COPY_FPGM(bci_action_serif_link2_down_upper_lower_bound);
7403 COPY_FPGM(bci_hint_glyph);
7405 *fpgm = buf;
7406 *fpgm_len = buf_len;
7408 return FT_Err_Ok;
7412 FT_Error
7413 TA_sfnt_build_fpgm_table(SFNT* sfnt,
7414 FONT* font)
7416 FT_Error error;
7418 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
7419 glyf_Data* data = (glyf_Data*)glyf_table->data;
7421 FT_Byte* fpgm_buf;
7422 FT_ULong fpgm_len;
7425 error = TA_sfnt_add_table_info(sfnt);
7426 if (error)
7427 goto Exit;
7429 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
7430 if (glyf_table->processed)
7432 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
7433 goto Exit;
7436 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
7437 if (error)
7438 goto Exit;
7440 if (fpgm_len > sfnt->max_instructions)
7441 sfnt->max_instructions = (FT_UShort)fpgm_len;
7443 /* in case of success, `fpgm_buf' gets linked */
7444 /* and is eventually freed in `TA_font_unload' */
7445 error = TA_font_add_table(font,
7446 &sfnt->table_infos[sfnt->num_table_infos - 1],
7447 TTAG_fpgm, fpgm_len, fpgm_buf);
7448 if (error)
7449 free(fpgm_buf);
7450 else
7451 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
7453 Exit:
7454 return error;
7457 /* end of tafpgm.c */