Run `update-copyright' script.
[ttfautohint.git] / lib / tafpgm.c
blob7057cf48b983d5e77a9d1b33a784a43ffe53f09f
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2018 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_scale
2073 * CVT: cvtl_is_subglyph
2075 * uses: bci_create_segment
2076 * bci_loop
2077 * bci_hint_glyph
2079 * If `num_packed_segments' is set to p, the first p start/end pairs are
2080 * stored as delta values in nibbles, with the `start' delta in the lower
2081 * nibble (and there are no wrap-around segments). For example, if the
2082 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
2083 * stack are 0x21, 0x32, and 0x14.
2087 static const unsigned char FPGM(bci_create_segments_a) [] =
2090 PUSHB_1,
2091 bci_create_segments,
2092 FDEF,
2094 /* all our measurements are taken along the y axis */
2095 SVTCA_y,
2097 /* only do something if we are not a subglyph */
2098 PUSHB_2,
2100 cvtl_is_subglyph,
2101 RCVT,
2104 PUSHB_1,
2105 sal_num_packed_segments,
2106 SWAP,
2109 DUP,
2110 RCVT,
2111 PUSHB_1,
2112 sal_scale, /* sal_scale = CVT(data_offset) */
2113 SWAP,
2116 PUSHB_1,
2117 sal_vwidth_data_offset,
2118 SWAP,
2119 PUSHB_1,
2123 /* %c, number of used styles */
2125 static const unsigned char FPGM(bci_create_segments_b) [] =
2128 ADD,
2129 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2131 DUP,
2132 PUSHB_1,
2133 sal_stem_width_offset,
2134 SWAP,
2135 WS, /* sal_stem_width_offset = num_segments (more to come) */
2137 DUP,
2138 ADD,
2139 PUSHB_1,
2141 SUB, /* delta = (2*num_segments - 1) */
2143 PUSHB_8,
2144 sal_segment_offset,
2145 sal_segment_offset,
2147 sal_j,
2149 sal_base,
2151 sal_num_stem_widths,
2153 WS, /* sal_num_stem_widths = 0 */
2154 WS, /* sal_base = 0 */
2155 WS, /* sal_j = 0 (point offset) */
2157 ROLL,
2158 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2160 DUP,
2161 PUSHB_1,
2162 sal_stem_width_offset,
2164 ADD,
2165 PUSHB_1,
2166 sal_stem_width_offset,
2167 SWAP,
2168 WS, /* sal_stem_width_offset += sal_segment_offset + delta */
2170 PUSHB_2,
2171 bci_create_segment,
2172 bci_loop,
2173 CALL,
2175 PUSHB_1,
2176 bci_hint_glyph,
2177 CALL,
2181 /* used if we have delta exceptions */
2183 static const unsigned char FPGM(bci_create_segments_c) [] =
2186 PUSHB_1,
2188 SZPS,
2192 static const unsigned char FPGM(bci_create_segments_d) [] =
2195 ELSE,
2196 CLEAR,
2197 EIF,
2199 ENDF,
2205 * bci_create_segments_X
2207 * Top-level routines for calling `bci_create_segments'.
2210 static const unsigned char FPGM(bci_create_segments_0) [] =
2213 PUSHB_1,
2214 bci_create_segments_0,
2215 FDEF,
2217 PUSHB_2,
2219 bci_create_segments,
2220 CALL,
2222 ENDF,
2226 static const unsigned char FPGM(bci_create_segments_1) [] =
2229 PUSHB_1,
2230 bci_create_segments_1,
2231 FDEF,
2233 PUSHB_2,
2235 bci_create_segments,
2236 CALL,
2238 ENDF,
2242 static const unsigned char FPGM(bci_create_segments_2) [] =
2245 PUSHB_1,
2246 bci_create_segments_2,
2247 FDEF,
2249 PUSHB_2,
2251 bci_create_segments,
2252 CALL,
2254 ENDF,
2258 static const unsigned char FPGM(bci_create_segments_3) [] =
2261 PUSHB_1,
2262 bci_create_segments_3,
2263 FDEF,
2265 PUSHB_2,
2267 bci_create_segments,
2268 CALL,
2270 ENDF,
2274 static const unsigned char FPGM(bci_create_segments_4) [] =
2277 PUSHB_1,
2278 bci_create_segments_4,
2279 FDEF,
2281 PUSHB_2,
2283 bci_create_segments,
2284 CALL,
2286 ENDF,
2290 static const unsigned char FPGM(bci_create_segments_5) [] =
2293 PUSHB_1,
2294 bci_create_segments_5,
2295 FDEF,
2297 PUSHB_2,
2299 bci_create_segments,
2300 CALL,
2302 ENDF,
2306 static const unsigned char FPGM(bci_create_segments_6) [] =
2309 PUSHB_1,
2310 bci_create_segments_6,
2311 FDEF,
2313 PUSHB_2,
2315 bci_create_segments,
2316 CALL,
2318 ENDF,
2322 static const unsigned char FPGM(bci_create_segments_7) [] =
2325 PUSHB_1,
2326 bci_create_segments_7,
2327 FDEF,
2329 PUSHB_2,
2331 bci_create_segments,
2332 CALL,
2334 ENDF,
2338 static const unsigned char FPGM(bci_create_segments_8) [] =
2341 PUSHB_1,
2342 bci_create_segments_8,
2343 FDEF,
2345 PUSHB_2,
2347 bci_create_segments,
2348 CALL,
2350 ENDF,
2354 static const unsigned char FPGM(bci_create_segments_9) [] =
2357 PUSHB_1,
2358 bci_create_segments_9,
2359 FDEF,
2361 PUSHB_2,
2363 bci_create_segments,
2364 CALL,
2366 ENDF,
2372 * bci_deltapX
2374 * Wrapper functions around DELTAP[123] that touch the affected points
2375 * before applying the delta. This is necessary for ClearType.
2377 * While DELTAP[123] implicitly do a loop, we have to process the
2378 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2380 * in: point
2381 * arg
2384 static const unsigned char FPGM(bci_deltap1) [] =
2387 PUSHB_1,
2388 bci_deltap1,
2389 FDEF,
2391 SWAP,
2392 DUP, /* s: point arg arg */
2393 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2395 DIV,
2396 FLOOR,
2397 PUSHB_1,
2399 MUL, /* s: point arg hnibble(arg) */
2400 PUSHB_1,
2401 CONTROL_DELTA_PPEM_MIN,
2402 ADD, /* s: point arg ppem(arg) */
2403 MPPEM,
2406 SWAP,
2407 DUP,
2408 MDAP_noround, /* touch `point' */
2410 PUSHB_1,
2412 DELTAP1, /* process one `(point,arg)' pair */
2413 ELSE,
2414 POP,
2415 POP,
2416 EIF,
2418 ENDF,
2422 static const unsigned char FPGM(bci_deltap2) [] =
2425 PUSHB_1,
2426 bci_deltap2,
2427 FDEF,
2429 SWAP,
2430 DUP, /* s: point arg arg */
2431 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2433 DIV,
2434 FLOOR,
2435 PUSHB_1,
2437 MUL, /* s: point arg hnibble(arg) */
2438 PUSHB_1,
2439 CONTROL_DELTA_PPEM_MIN + 16,
2440 ADD, /* s: point arg ppem(arg) */
2441 MPPEM,
2444 SWAP,
2445 DUP,
2446 MDAP_noround, /* touch `point' */
2448 PUSHB_1,
2450 DELTAP2, /* process one `(point,arg)' pair */
2451 ELSE,
2452 POP,
2453 POP,
2454 EIF,
2456 ENDF,
2460 static const unsigned char FPGM(bci_deltap3) [] =
2463 PUSHB_1,
2464 bci_deltap3,
2465 FDEF,
2467 SWAP,
2468 DUP, /* s: point arg arg */
2469 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2471 DIV,
2472 FLOOR,
2473 PUSHB_1,
2475 MUL, /* s: point arg hnibble(arg) */
2476 PUSHB_1,
2477 CONTROL_DELTA_PPEM_MIN + 32,
2478 ADD, /* s: point arg ppem(arg) */
2479 MPPEM,
2482 SWAP,
2483 DUP,
2484 MDAP_noround, /* touch `point' */
2486 PUSHB_1,
2488 DELTAP3, /* process one `(point,arg)' pair */
2489 ELSE,
2490 POP,
2491 POP,
2492 EIF,
2494 ENDF,
2500 * bci_create_segments_composite
2502 * The same as `bci_create_segments'.
2503 * It also decrements the composite component counter.
2505 * sal: sal_num_packed_segments
2506 * sal_segment_offset
2507 * sal_vwidth_data_offset
2509 * CVT: cvtl_is_subglyph
2511 * uses: bci_decrement_component_counter
2512 * bci_create_segment
2513 * bci_loop
2514 * bci_hint_glyph
2517 static const unsigned char FPGM(bci_create_segments_composite_a) [] =
2520 PUSHB_1,
2521 bci_create_segments_composite,
2522 FDEF,
2524 /* all our measurements are taken along the y axis */
2525 SVTCA_y,
2527 PUSHB_1,
2528 bci_decrement_component_counter,
2529 CALL,
2531 /* only do something if we are not a subglyph */
2532 PUSHB_2,
2534 cvtl_is_subglyph,
2535 RCVT,
2538 PUSHB_1,
2539 sal_num_packed_segments,
2540 SWAP,
2543 DUP,
2544 RCVT,
2545 PUSHB_1,
2546 sal_scale, /* sal_scale = CVT(data_offset) */
2547 SWAP,
2550 PUSHB_1,
2551 sal_vwidth_data_offset,
2552 SWAP,
2553 PUSHB_1,
2557 /* %c, number of used styles */
2559 static const unsigned char FPGM(bci_create_segments_composite_b) [] =
2562 ADD,
2563 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2565 DUP,
2566 ADD,
2567 PUSHB_1,
2569 SUB, /* delta = (2*num_segments - 1) */
2571 PUSHB_6,
2572 sal_segment_offset,
2573 sal_segment_offset,
2575 sal_j,
2577 sal_base,
2579 WS, /* sal_base = 0 */
2580 WS, /* sal_j = 0 (point offset) */
2582 ROLL,
2583 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2585 PUSHB_2,
2586 bci_create_segment,
2587 bci_loop,
2588 CALL,
2590 PUSHB_1,
2591 bci_hint_glyph,
2592 CALL,
2596 /* used if we have delta exceptions */
2598 static const unsigned char FPGM(bci_create_segments_composite_c) [] =
2601 PUSHB_1,
2603 SZPS,
2607 static const unsigned char FPGM(bci_create_segments_composite_d) [] =
2610 ELSE,
2611 CLEAR,
2612 EIF,
2614 ENDF,
2620 * bci_create_segments_composite_X
2622 * Top-level routines for calling `bci_create_segments_composite'.
2625 static const unsigned char FPGM(bci_create_segments_composite_0) [] =
2628 PUSHB_1,
2629 bci_create_segments_composite_0,
2630 FDEF,
2632 PUSHB_2,
2634 bci_create_segments_composite,
2635 CALL,
2637 ENDF,
2641 static const unsigned char FPGM(bci_create_segments_composite_1) [] =
2644 PUSHB_1,
2645 bci_create_segments_composite_1,
2646 FDEF,
2648 PUSHB_2,
2650 bci_create_segments_composite,
2651 CALL,
2653 ENDF,
2657 static const unsigned char FPGM(bci_create_segments_composite_2) [] =
2660 PUSHB_1,
2661 bci_create_segments_composite_2,
2662 FDEF,
2664 PUSHB_2,
2666 bci_create_segments_composite,
2667 CALL,
2669 ENDF,
2673 static const unsigned char FPGM(bci_create_segments_composite_3) [] =
2676 PUSHB_1,
2677 bci_create_segments_composite_3,
2678 FDEF,
2680 PUSHB_2,
2682 bci_create_segments_composite,
2683 CALL,
2685 ENDF,
2689 static const unsigned char FPGM(bci_create_segments_composite_4) [] =
2692 PUSHB_1,
2693 bci_create_segments_composite_4,
2694 FDEF,
2696 PUSHB_2,
2698 bci_create_segments_composite,
2699 CALL,
2701 ENDF,
2705 static const unsigned char FPGM(bci_create_segments_composite_5) [] =
2708 PUSHB_1,
2709 bci_create_segments_composite_5,
2710 FDEF,
2712 PUSHB_2,
2714 bci_create_segments_composite,
2715 CALL,
2717 ENDF,
2721 static const unsigned char FPGM(bci_create_segments_composite_6) [] =
2724 PUSHB_1,
2725 bci_create_segments_composite_6,
2726 FDEF,
2728 PUSHB_2,
2730 bci_create_segments_composite,
2731 CALL,
2733 ENDF,
2737 static const unsigned char FPGM(bci_create_segments_composite_7) [] =
2740 PUSHB_1,
2741 bci_create_segments_composite_7,
2742 FDEF,
2744 PUSHB_2,
2746 bci_create_segments_composite,
2747 CALL,
2749 ENDF,
2753 static const unsigned char FPGM(bci_create_segments_composite_8) [] =
2756 PUSHB_1,
2757 bci_create_segments_composite_8,
2758 FDEF,
2760 PUSHB_2,
2762 bci_create_segments_composite,
2763 CALL,
2765 ENDF,
2769 static const unsigned char FPGM(bci_create_segments_composite_9) [] =
2772 PUSHB_1,
2773 bci_create_segments_composite_9,
2774 FDEF,
2776 PUSHB_2,
2778 bci_create_segments_composite,
2779 CALL,
2781 ENDF,
2787 * bci_align_point
2789 * An auxiliary function for `bci_align_segment'.
2791 * in: point
2793 * out: point+1
2796 static const unsigned char FPGM(bci_align_point) [] =
2799 PUSHB_1,
2800 bci_align_point,
2801 FDEF,
2803 DUP,
2804 ALIGNRP, /* align point with rp0 */
2806 PUSHB_1,
2808 ADD,
2810 ENDF,
2816 * bci_align_segment
2818 * Align all points in a segment to the twilight point in rp0.
2819 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2821 * in: segment_index
2823 * sal: sal_segment_offset
2825 * uses: bci_align_point
2828 static const unsigned char FPGM(bci_align_segment) [] =
2831 PUSHB_1,
2832 bci_align_segment,
2833 FDEF,
2835 /* we need the values of `sal_segment_offset + 2*segment_index' */
2836 /* and `sal_segment_offset + 2*segment_index + 1' */
2837 DUP,
2838 ADD,
2839 PUSHB_1,
2840 sal_segment_offset,
2841 ADD,
2842 DUP,
2844 SWAP,
2845 PUSHB_1,
2847 ADD,
2848 RS, /* s: first last */
2850 PUSHB_1,
2852 CINDEX, /* s: first last first */
2853 SUB,
2854 PUSHB_1,
2856 ADD, /* s: first loop_count */
2858 PUSHB_1,
2859 bci_align_point,
2860 LOOPCALL,
2861 /* clean up stack */
2862 POP,
2864 ENDF,
2870 * bci_align_segments
2872 * Align segments to the twilight point in rp0.
2873 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2875 * in: first_segment
2876 * loop_counter (N)
2877 * segment_1
2878 * segment_2
2879 * ...
2880 * segment_N
2882 * uses: bci_align_segment
2885 static const unsigned char FPGM(bci_align_segments) [] =
2888 PUSHB_1,
2889 bci_align_segments,
2890 FDEF,
2892 PUSHB_1,
2893 bci_align_segment,
2894 CALL,
2896 PUSHB_1,
2897 bci_align_segment,
2898 LOOPCALL,
2900 ENDF,
2906 * bci_scale_contour
2908 * Scale a contour using two points giving the maximum and minimum
2909 * coordinates.
2911 * It expects that no point on the contour is touched.
2913 * in: min_point
2914 * max_point
2916 * sal: sal_scale
2919 static const unsigned char FPGM(bci_scale_contour) [] =
2922 PUSHB_1,
2923 bci_scale_contour,
2924 FDEF,
2926 DUP,
2927 DUP,
2928 GC_orig,
2929 DUP,
2930 DO_SCALE, /* min_pos_new = min_pos * scale */
2931 SWAP,
2932 SUB,
2933 SHPIX,
2935 /* don't scale a single-point contour twice */
2936 SWAP,
2937 DUP,
2938 ROLL,
2939 NEQ,
2941 DUP,
2942 GC_orig,
2943 DUP,
2944 DO_SCALE, /* max_pos_new = max_pos * scale */
2945 SWAP,
2946 SUB,
2947 SHPIX,
2949 ELSE,
2950 POP,
2951 EIF,
2953 ENDF,
2959 * bci_scale_glyph
2961 * Scale a glyph using a list of points (two points per contour, giving
2962 * the maximum and mininum coordinates).
2964 * It expects that no point in the glyph is touched.
2966 * Note that the point numbers are sorted in ascending order;
2967 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2968 * contour without specifying which one is the minimum and maximum.
2970 * in: num_contours (N)
2971 * min_point_1
2972 * max_point_1
2973 * min_point_2
2974 * max_point_2
2975 * ...
2976 * min_point_N
2977 * max_point_N
2979 * CVT: cvtl_is_subglyph
2980 * cvtl_do_iup_y
2982 * sal: sal_scale
2984 * uses: bci_scale_contour
2987 static const unsigned char FPGM(bci_scale_glyph_a) [] =
2990 PUSHB_1,
2991 bci_scale_glyph,
2992 FDEF,
2994 /* all our measurements are taken along the y axis */
2995 SVTCA_y,
2997 /* only do something if we are not a subglyph */
2998 PUSHB_2,
3000 cvtl_is_subglyph,
3001 RCVT,
3004 /* use fallback scaling value */
3005 PUSHB_2,
3006 sal_scale,
3010 /* %c, fallback scaling index */
3012 static const unsigned char FPGM(bci_scale_glyph_b) [] =
3015 RCVT,
3018 PUSHB_1,
3020 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
3022 PUSHB_1,
3023 bci_scale_contour,
3024 LOOPCALL,
3026 PUSHB_2,
3027 cvtl_do_iup_y,
3029 SZP2, /* set zp2 to normal zone 1 */
3030 RCVT,
3032 IUP_y,
3033 EIF,
3035 ELSE,
3036 CLEAR,
3037 EIF,
3039 ENDF,
3045 * bci_scale_composite_glyph
3047 * The same as `bci_scale_glyph'.
3048 * It also decrements the composite component counter.
3050 * CVT: cvtl_is_subglyph
3051 * cvtl_do_iup_y
3053 * sal: sal_scale
3055 * uses: bci_decrement_component_counter
3056 * bci_scale_contour
3059 static const unsigned char FPGM(bci_scale_composite_glyph_a) [] =
3062 PUSHB_1,
3063 bci_scale_composite_glyph,
3064 FDEF,
3066 /* all our measurements are taken along the y axis */
3067 SVTCA_y,
3069 PUSHB_1,
3070 bci_decrement_component_counter,
3071 CALL,
3073 /* only do something if we are not a subglyph */
3074 PUSHB_2,
3076 cvtl_is_subglyph,
3077 RCVT,
3080 /* use fallback scaling value */
3081 PUSHB_2,
3082 sal_scale,
3086 /* %c, fallback scaling index */
3088 static const unsigned char FPGM(bci_scale_composite_glyph_b) [] =
3091 RCVT,
3094 PUSHB_1,
3096 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
3098 PUSHB_1,
3099 bci_scale_contour,
3100 LOOPCALL,
3102 PUSHB_2,
3103 cvtl_do_iup_y,
3105 SZP2, /* set zp2 to normal zone 1 */
3106 RCVT,
3108 IUP_y,
3109 EIF,
3111 ELSE,
3112 CLEAR,
3113 EIF,
3115 ENDF,
3121 * bci_shift_contour
3123 * Shift a contour by a given amount.
3125 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
3126 * point to the normal zone 1.
3128 * in: contour
3130 * out: contour+1
3133 static const unsigned char FPGM(bci_shift_contour) [] =
3136 PUSHB_1,
3137 bci_shift_contour,
3138 FDEF,
3140 DUP,
3141 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
3143 PUSHB_1,
3145 ADD,
3147 ENDF,
3153 * bci_shift_subglyph
3155 * Shift a subglyph. To be more specific, it corrects the already applied
3156 * subglyph offset (if any) from the `glyf' table which needs to be scaled
3157 * also.
3159 * If this function is called, a point `x' in the subglyph has been scaled
3160 * already (during the hinting of the subglyph itself), and `offset' has
3161 * been applied also:
3163 * x -> x * scale + offset (1)
3165 * However, the offset should be applied first, then the scaling:
3167 * x -> (x + offset) * scale (2)
3169 * Our job is now to transform (1) to (2); a simple calculation shows that
3170 * we have to shift all points of the subglyph by
3172 * offset * scale - offset = offset * (scale - 1)
3174 * Note that `sal_scale' is equal to the above `scale - 1'.
3176 * in: offset (in FUnits)
3177 * num_contours
3178 * first_contour
3180 * CVT: cvtl_funits_to_pixels
3182 * sal: sal_scale
3184 * uses: bci_round
3185 * bci_shift_contour
3188 static const unsigned char FPGM(bci_shift_subglyph_a) [] =
3191 PUSHB_1,
3192 bci_shift_subglyph,
3193 FDEF,
3195 /* all our measurements are taken along the y axis */
3196 SVTCA_y,
3198 /* use fallback scaling value */
3199 PUSHB_2,
3200 sal_scale,
3204 /* %c, fallback scaling index */
3206 static const unsigned char FPGM(bci_shift_subglyph_b) [] =
3209 RCVT,
3212 PUSHB_1,
3213 cvtl_funits_to_pixels,
3214 RCVT, /* scaling factor FUnits -> pixels */
3215 MUL,
3216 DIV_BY_1024,
3218 /* the autohinter always rounds offsets */
3219 PUSHB_1,
3220 bci_round,
3221 CALL, /* offset = round(offset) */
3223 PUSHB_1,
3224 sal_scale,
3226 MUL,
3227 DIV_BY_1024, /* delta = offset * (scale - 1) */
3229 /* and round again */
3230 PUSHB_1,
3231 bci_round,
3232 CALL, /* offset = round(offset) */
3234 PUSHB_1,
3236 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3238 /* we create twilight point 0 as a reference point, */
3239 /* setting the original position to zero (using `cvtl_temp') */
3240 PUSHB_5,
3243 cvtl_temp,
3244 cvtl_temp,
3246 WCVTP,
3247 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
3249 SWAP, /* s: first_contour num_contours 0 delta */
3250 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
3252 PUSHB_2,
3253 bci_shift_contour,
3255 SZP2, /* set zp2 to normal zone 1 */
3256 LOOPCALL,
3257 /* clean up stack */
3258 POP,
3262 /* used if we have delta exceptions */
3264 static const unsigned char FPGM(bci_shift_subglyph_c) [] =
3267 PUSHB_1,
3269 SZPS,
3273 static const unsigned char FPGM(bci_shift_subglyph_d) [] =
3276 ENDF,
3282 * bci_ip_outer_align_point
3284 * Auxiliary function for `bci_action_ip_before' and
3285 * `bci_action_ip_after'.
3287 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3288 * zone, and both zp1 and zp2 set to normal zone.
3290 * in: point
3292 * sal: sal_i (edge_orig_pos)
3293 * sal_scale
3296 static const unsigned char FPGM(bci_ip_outer_align_point) [] =
3299 PUSHB_1,
3300 bci_ip_outer_align_point,
3301 FDEF,
3303 DUP,
3304 ALIGNRP, /* align `point' with `edge' */
3305 DUP,
3306 GC_orig,
3307 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3309 PUSHB_1,
3310 sal_i,
3312 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3313 SHPIX,
3315 ENDF,
3321 * bci_ip_on_align_points
3323 * Auxiliary function for `bci_action_ip_on'.
3325 * in: edge (in twilight zone)
3326 * loop_counter (N)
3327 * point_1
3328 * point_2
3329 * ...
3330 * point_N
3333 static const unsigned char FPGM(bci_ip_on_align_points) [] =
3336 PUSHB_1,
3337 bci_ip_on_align_points,
3338 FDEF,
3340 MDAP_noround, /* set rp0 and rp1 to `edge' */
3342 SLOOP,
3343 ALIGNRP,
3345 ENDF,
3351 * bci_ip_between_align_point
3353 * Auxiliary function for `bci_ip_between_align_points'.
3355 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3356 * zone, and both zp1 and zp2 set to normal zone.
3358 * in: point
3360 * sal: sal_i (edge_orig_pos)
3361 * sal_j (stretch_factor)
3362 * sal_scale
3365 static const unsigned char FPGM(bci_ip_between_align_point) [] =
3368 PUSHB_1,
3369 bci_ip_between_align_point,
3370 FDEF,
3372 DUP,
3373 ALIGNRP, /* align `point' with `edge' */
3374 DUP,
3375 GC_orig,
3376 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3378 PUSHB_1,
3379 sal_i,
3381 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3382 PUSHB_1,
3383 sal_j,
3385 MUL, /* s: point delta */
3386 SHPIX,
3388 ENDF,
3394 * bci_ip_between_align_points
3396 * Auxiliary function for `bci_action_ip_between'.
3398 * in: after_edge (in twilight zone)
3399 * before_edge (in twilight zone)
3400 * loop_counter (N)
3401 * point_1
3402 * point_2
3403 * ...
3404 * point_N
3406 * sal: sal_i (before_orig_pos)
3407 * sal_j (stretch_factor)
3409 * uses: bci_ip_between_align_point
3412 static const unsigned char FPGM(bci_ip_between_align_points) [] =
3415 PUSHB_1,
3416 bci_ip_between_align_points,
3417 FDEF,
3419 PUSHB_2,
3422 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3423 CINDEX,
3424 DUP, /* s: ... before after before before */
3425 MDAP_noround, /* set rp0 and rp1 to `before' */
3426 DUP,
3427 GC_orig, /* s: ... before after before before_orig_pos */
3428 PUSHB_1,
3429 sal_i,
3430 SWAP,
3431 WS, /* sal_i = before_orig_pos */
3432 PUSHB_1,
3434 CINDEX, /* s: ... before after before after */
3435 MD_cur, /* a = after_pos - before_pos */
3436 ROLL,
3437 ROLL,
3438 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
3440 DUP,
3441 IF, /* b != 0 ? */
3442 DIV, /* s: a/b */
3443 ELSE,
3444 POP, /* avoid division by zero */
3445 EIF,
3447 PUSHB_1,
3448 sal_j,
3449 SWAP,
3450 WS, /* sal_j = stretch_factor */
3452 PUSHB_3,
3453 bci_ip_between_align_point,
3456 SZP2, /* set zp2 to normal zone 1 */
3457 SZP1, /* set zp1 to normal zone 1 */
3458 LOOPCALL,
3460 ENDF,
3466 * bci_action_ip_before
3468 * Handle `ip_before' data to align points located before the first edge.
3470 * in: first_edge (in twilight zone)
3471 * loop_counter (N)
3472 * point_1
3473 * point_2
3474 * ...
3475 * point_N
3477 * sal: sal_i (first_edge_orig_pos)
3479 * uses: bci_ip_outer_align_point
3482 static const unsigned char FPGM(bci_action_ip_before) [] =
3485 PUSHB_1,
3486 bci_action_ip_before,
3487 FDEF,
3489 PUSHB_1,
3491 SZP2, /* set zp2 to twilight zone 0 */
3493 DUP,
3494 GC_orig,
3495 PUSHB_1,
3496 sal_i,
3497 SWAP,
3498 WS, /* sal_i = first_edge_orig_pos */
3500 PUSHB_3,
3504 SZP2, /* set zp2 to normal zone 1 */
3505 SZP1, /* set zp1 to normal zone 1 */
3506 SZP0, /* set zp0 to twilight zone 0 */
3508 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
3510 PUSHB_1,
3511 bci_ip_outer_align_point,
3512 LOOPCALL,
3514 ENDF,
3520 * bci_action_ip_after
3522 * Handle `ip_after' data to align points located after the last edge.
3524 * in: last_edge (in twilight zone)
3525 * loop_counter (N)
3526 * point_1
3527 * point_2
3528 * ...
3529 * point_N
3531 * sal: sal_i (last_edge_orig_pos)
3533 * uses: bci_ip_outer_align_point
3536 static const unsigned char FPGM(bci_action_ip_after) [] =
3539 PUSHB_1,
3540 bci_action_ip_after,
3541 FDEF,
3543 PUSHB_1,
3545 SZP2, /* set zp2 to twilight zone 0 */
3547 DUP,
3548 GC_orig,
3549 PUSHB_1,
3550 sal_i,
3551 SWAP,
3552 WS, /* sal_i = last_edge_orig_pos */
3554 PUSHB_3,
3558 SZP2, /* set zp2 to normal zone 1 */
3559 SZP1, /* set zp1 to normal zone 1 */
3560 SZP0, /* set zp0 to twilight zone 0 */
3562 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3564 PUSHB_1,
3565 bci_ip_outer_align_point,
3566 LOOPCALL,
3568 ENDF,
3574 * bci_action_ip_on
3576 * Handle `ip_on' data to align points located on an edge coordinate (but
3577 * not part of an edge).
3579 * in: loop_counter (M)
3580 * edge_1 (in twilight zone)
3581 * loop_counter (N_1)
3582 * point_1
3583 * point_2
3584 * ...
3585 * point_N_1
3586 * edge_2 (in twilight zone)
3587 * loop_counter (N_2)
3588 * point_1
3589 * point_2
3590 * ...
3591 * point_N_2
3592 * ...
3593 * edge_M (in twilight zone)
3594 * loop_counter (N_M)
3595 * point_1
3596 * point_2
3597 * ...
3598 * point_N_M
3600 * uses: bci_ip_on_align_points
3603 static const unsigned char FPGM(bci_action_ip_on) [] =
3606 PUSHB_1,
3607 bci_action_ip_on,
3608 FDEF,
3610 PUSHB_2,
3613 SZP1, /* set zp1 to normal zone 1 */
3614 SZP0, /* set zp0 to twilight zone 0 */
3616 PUSHB_1,
3617 bci_ip_on_align_points,
3618 LOOPCALL,
3620 ENDF,
3626 * bci_action_ip_between
3628 * Handle `ip_between' data to align points located between two edges.
3630 * in: loop_counter (M)
3631 * before_edge_1 (in twilight zone)
3632 * after_edge_1 (in twilight zone)
3633 * loop_counter (N_1)
3634 * point_1
3635 * point_2
3636 * ...
3637 * point_N_1
3638 * before_edge_2 (in twilight zone)
3639 * after_edge_2 (in twilight zone)
3640 * loop_counter (N_2)
3641 * point_1
3642 * point_2
3643 * ...
3644 * point_N_2
3645 * ...
3646 * before_edge_M (in twilight zone)
3647 * after_edge_M (in twilight zone)
3648 * loop_counter (N_M)
3649 * point_1
3650 * point_2
3651 * ...
3652 * point_N_M
3654 * uses: bci_ip_between_align_points
3657 static const unsigned char FPGM(bci_action_ip_between) [] =
3660 PUSHB_1,
3661 bci_action_ip_between,
3662 FDEF,
3664 PUSHB_1,
3665 bci_ip_between_align_points,
3666 LOOPCALL,
3668 ENDF,
3674 * bci_adjust_common
3676 * Common code for bci_action_adjust routines.
3678 * in: top_to_bottom_hinting
3679 * edge2_is_serif
3680 * edge_is_round
3681 * edge
3682 * edge2
3684 * out: edge (adjusted)
3686 * sal: sal_top_to_bottom_hinting
3687 * sal_base_delta
3689 * uses: func[sal_stem_width_function]
3692 static const unsigned char FPGM(bci_adjust_common) [] =
3695 PUSHB_1,
3696 bci_adjust_common,
3697 FDEF,
3699 PUSHB_1,
3701 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3702 PUSHB_1,
3703 sal_top_to_bottom_hinting,
3704 SWAP,
3707 PUSHB_1,
3709 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3710 PUSHB_1,
3712 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3713 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3715 PUSHB_2,
3716 sal_base_delta, /* no base_delta needed here */
3720 PUSHB_1,
3721 sal_stem_width_function,
3723 CALL,
3724 NEG, /* s: [...] edge2 edge -cur_len */
3726 ROLL, /* s: [...] edge -cur_len edge2 */
3727 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3728 SWAP,
3729 DUP,
3730 DUP, /* s: [...] -cur_len edge edge edge */
3731 ALIGNRP, /* align `edge' with `edge2' */
3732 ROLL,
3733 SHPIX, /* shift `edge' by -cur_len */
3735 ENDF,
3741 * bci_adjust_bound
3743 * Handle the ADJUST + BOUND actions to align an edge of a stem if the
3744 * other edge of the stem has already been moved, then moving it again if
3745 * necessary to stay bound.
3747 * in: top_to_bottom_hinting
3748 * edge2_is_serif
3749 * edge_is_round
3750 * edge_point (in twilight zone)
3751 * edge2_point (in twilight zone)
3752 * edge[-1] (in twilight zone)
3753 * ... stuff for bci_align_segments (edge) ...
3755 * sal: sal_top_to_bottom_hinting
3757 * uses: bci_adjust_common
3758 * bci_align_segments
3761 static const unsigned char FPGM(bci_adjust_bound) [] =
3764 PUSHB_1,
3765 bci_adjust_bound,
3766 FDEF,
3768 PUSHB_1,
3769 bci_adjust_common,
3770 CALL,
3772 SWAP, /* s: edge edge[-1] */
3773 DUP,
3774 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3775 GC_cur,
3776 PUSHB_1,
3778 CINDEX,
3779 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3780 PUSHB_1,
3781 sal_top_to_bottom_hinting,
3784 LT, /* edge_pos > edge[-1]_pos */
3785 ELSE,
3786 GT, /* edge_pos < edge[-1]_pos */
3787 EIF,
3789 DUP,
3790 ALIGNRP, /* align `edge' to `edge[-1]' */
3791 EIF,
3793 MDAP_noround, /* set rp0 and rp1 to `edge' */
3795 PUSHB_2,
3796 bci_align_segments,
3798 SZP1, /* set zp1 to normal zone 1 */
3799 CALL,
3801 ENDF,
3807 * bci_action_adjust_bound
3808 * bci_action_adjust_bound_serif
3809 * bci_action_adjust_bound_round
3810 * bci_action_adjust_bound_round_serif
3811 * bci_action_adjust_down_bound
3812 * bci_action_adjust_down_bound_serif
3813 * bci_action_adjust_down_bound_round
3814 * bci_action_adjust_down_bound_round_serif
3816 * Higher-level routines for calling `bci_adjust_bound'.
3819 static const unsigned char FPGM(bci_action_adjust_bound) [] =
3822 PUSHB_1,
3823 bci_action_adjust_bound,
3824 FDEF,
3826 PUSHB_4,
3830 bci_adjust_bound,
3831 CALL,
3833 ENDF,
3837 static const unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3840 PUSHB_1,
3841 bci_action_adjust_bound_serif,
3842 FDEF,
3844 PUSHB_4,
3848 bci_adjust_bound,
3849 CALL,
3851 ENDF,
3855 static const unsigned char FPGM(bci_action_adjust_bound_round) [] =
3858 PUSHB_1,
3859 bci_action_adjust_bound_round,
3860 FDEF,
3862 PUSHB_4,
3866 bci_adjust_bound,
3867 CALL,
3869 ENDF,
3873 static const unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3876 PUSHB_1,
3877 bci_action_adjust_bound_round_serif,
3878 FDEF,
3880 PUSHB_4,
3884 bci_adjust_bound,
3885 CALL,
3887 ENDF,
3891 static const unsigned char FPGM(bci_action_adjust_down_bound) [] =
3894 PUSHB_1,
3895 bci_action_adjust_down_bound,
3896 FDEF,
3898 PUSHB_4,
3902 bci_adjust_bound,
3903 CALL,
3905 ENDF,
3909 static const unsigned char FPGM(bci_action_adjust_down_bound_serif) [] =
3912 PUSHB_1,
3913 bci_action_adjust_down_bound_serif,
3914 FDEF,
3916 PUSHB_4,
3920 bci_adjust_bound,
3921 CALL,
3923 ENDF,
3927 static const unsigned char FPGM(bci_action_adjust_down_bound_round) [] =
3930 PUSHB_1,
3931 bci_action_adjust_down_bound_round,
3932 FDEF,
3934 PUSHB_4,
3938 bci_adjust_bound,
3939 CALL,
3941 ENDF,
3945 static const unsigned char FPGM(bci_action_adjust_down_bound_round_serif) [] =
3948 PUSHB_1,
3949 bci_action_adjust_down_bound_round_serif,
3950 FDEF,
3952 PUSHB_4,
3956 bci_adjust_bound,
3957 CALL,
3959 ENDF,
3965 * bci_adjust
3967 * Handle the ADJUST action to align an edge of a stem if the other edge
3968 * of the stem has already been moved.
3970 * in: edge2_is_serif
3971 * edge_is_round
3972 * edge_point (in twilight zone)
3973 * edge2_point (in twilight zone)
3974 * ... stuff for bci_align_segments (edge) ...
3976 * uses: bci_adjust_common
3977 * bci_align_segments
3980 static const unsigned char FPGM(bci_adjust) [] =
3983 PUSHB_1,
3984 bci_adjust,
3985 FDEF,
3987 PUSHB_2,
3989 bci_adjust_common,
3990 CALL,
3992 MDAP_noround, /* set rp0 and rp1 to `edge' */
3994 PUSHB_2,
3995 bci_align_segments,
3997 SZP1, /* set zp1 to normal zone 1 */
3998 CALL,
4000 ENDF,
4006 * bci_action_adjust
4007 * bci_action_adjust_serif
4008 * bci_action_adjust_round
4009 * bci_action_adjust_round_serif
4011 * Higher-level routines for calling `bci_adjust'.
4014 static const unsigned char FPGM(bci_action_adjust) [] =
4017 PUSHB_1,
4018 bci_action_adjust,
4019 FDEF,
4021 PUSHB_3,
4024 bci_adjust,
4025 CALL,
4027 ENDF,
4031 static const unsigned char FPGM(bci_action_adjust_serif) [] =
4034 PUSHB_1,
4035 bci_action_adjust_serif,
4036 FDEF,
4038 PUSHB_3,
4041 bci_adjust,
4042 CALL,
4044 ENDF,
4048 static const unsigned char FPGM(bci_action_adjust_round) [] =
4051 PUSHB_1,
4052 bci_action_adjust_round,
4053 FDEF,
4055 PUSHB_3,
4058 bci_adjust,
4059 CALL,
4061 ENDF,
4065 static const unsigned char FPGM(bci_action_adjust_round_serif) [] =
4068 PUSHB_1,
4069 bci_action_adjust_round_serif,
4070 FDEF,
4072 PUSHB_3,
4075 bci_adjust,
4076 CALL,
4078 ENDF,
4084 * bci_stem_common
4086 * Common code for bci_action_stem routines.
4088 * in: top_to_bottom_hinting
4089 * edge2_is_serif
4090 * edge_is_round
4091 * edge
4092 * edge2
4094 * out: edge
4095 * cur_len
4096 * edge2
4098 * sal: sal_anchor
4099 * sal_temp1
4100 * sal_temp2
4101 * sal_temp3
4102 * sal_top_to_bottom_hinting
4103 * sal_base_delta
4105 * uses: func[sal_stem_width_function]
4106 * bci_round
4109 #undef sal_u_off
4110 #define sal_u_off sal_temp1
4111 #undef sal_d_off
4112 #define sal_d_off sal_temp2
4113 #undef sal_org_len
4114 #define sal_org_len sal_temp3
4115 #undef sal_edge2
4116 #define sal_edge2 sal_temp3
4118 static const unsigned char FPGM(bci_stem_common) [] =
4121 PUSHB_1,
4122 bci_stem_common,
4123 FDEF,
4125 PUSHB_1,
4127 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4129 PUSHB_1,
4130 sal_top_to_bottom_hinting,
4131 SWAP,
4134 PUSHB_1,
4136 CINDEX,
4137 PUSHB_1,
4139 CINDEX,
4140 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
4141 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4143 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
4144 DUP,
4145 PUSHB_1,
4146 sal_org_len,
4147 SWAP,
4150 PUSHB_2,
4151 sal_base_delta, /* no base_delta needed here */
4155 PUSHB_1,
4156 sal_stem_width_function,
4158 CALL, /* s: [...] edge2 edge cur_len */
4160 DUP,
4161 PUSHB_1,
4163 LT, /* cur_len < 96 */
4165 DUP,
4166 PUSHB_1,
4168 LTEQ, /* cur_len <= 64 */
4170 PUSHB_4,
4171 sal_u_off,
4173 sal_d_off,
4176 ELSE,
4177 PUSHB_4,
4178 sal_u_off,
4180 sal_d_off,
4182 EIF,
4186 SWAP, /* s: [...] edge2 cur_len edge */
4187 DUP,
4188 PUSHB_1,
4189 sal_anchor,
4191 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
4192 ROLL,
4193 SWAP,
4194 MD_orig_ZP2_0,
4195 SWAP,
4196 GC_cur,
4197 ADD, /* s: [...] edge2 cur_len edge org_pos */
4198 PUSHB_1,
4199 sal_org_len,
4201 DIV_BY_2,
4202 ADD, /* s: [...] edge2 cur_len edge org_center */
4204 DUP,
4205 PUSHB_1,
4206 bci_round,
4207 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
4209 DUP,
4210 ROLL,
4211 ROLL,
4212 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
4214 DUP,
4215 PUSHB_1,
4216 sal_u_off,
4218 ADD,
4219 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
4221 SWAP,
4222 PUSHB_1,
4223 sal_d_off,
4225 SUB,
4226 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
4228 LT, /* delta1 < delta2 */
4230 PUSHB_1,
4231 sal_u_off,
4233 SUB, /* cur_pos1 = cur_pos1 - u_off */
4235 ELSE,
4236 PUSHB_1,
4237 sal_d_off,
4239 ADD, /* cur_pos1 = cur_pos1 + d_off */
4240 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
4242 PUSHB_1,
4244 CINDEX,
4245 DIV_BY_2,
4246 SUB, /* arg = cur_pos1 - cur_len/2 */
4248 SWAP, /* s: [...] edge2 cur_len arg edge */
4249 DUP,
4250 DUP,
4251 PUSHB_1,
4253 MINDEX,
4254 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4255 GC_cur,
4256 SUB,
4257 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4259 ELSE,
4260 SWAP, /* s: [...] edge2 cur_len edge */
4261 PUSHB_1,
4262 sal_anchor,
4264 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
4265 PUSHB_1,
4267 CINDEX,
4268 PUSHB_1,
4269 sal_anchor,
4271 MD_orig_ZP2_0,
4272 ADD, /* s: [...] edge2 cur_len edge org_pos */
4274 DUP,
4275 PUSHB_1,
4276 sal_org_len,
4278 DIV_BY_2,
4279 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
4281 SWAP,
4282 DUP,
4283 PUSHB_1,
4284 bci_round,
4285 CALL, /* cur_pos1 = ROUND(org_pos) */
4286 SWAP,
4287 PUSHB_1,
4288 sal_org_len,
4290 ADD,
4291 PUSHB_1,
4292 bci_round,
4293 CALL,
4294 PUSHB_1,
4296 CINDEX,
4297 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
4299 PUSHB_1,
4301 CINDEX,
4302 DIV_BY_2,
4303 PUSHB_1,
4305 MINDEX,
4306 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
4308 DUP,
4309 PUSHB_1,
4311 CINDEX,
4312 ADD,
4313 ABS, /* delta1 = |cur_pos1 + cur_len / 2 - org_center| */
4314 SWAP,
4315 PUSHB_1,
4317 CINDEX,
4318 ADD,
4319 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
4320 LT, /* delta1 < delta2 */
4322 POP, /* arg = cur_pos1 */
4324 ELSE,
4325 SWAP,
4326 POP, /* arg = cur_pos2 */
4327 EIF, /* s: [...] edge2 cur_len edge arg */
4328 SWAP,
4329 DUP,
4330 DUP,
4331 PUSHB_1,
4333 MINDEX,
4334 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4335 GC_cur,
4336 SUB,
4337 SHPIX, /* edge = arg */
4338 EIF, /* s: [...] edge2 cur_len edge */
4340 ENDF,
4346 * bci_stem_bound
4348 * Handle the STEM action to align two edges of a stem, then moving one
4349 * edge again if necessary to stay bound.
4351 * The code after computing `cur_len' to shift `edge' and `edge2'
4352 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4354 * if cur_len < 96:
4355 * if cur_len < = 64:
4356 * u_off = 32
4357 * d_off = 32
4358 * else:
4359 * u_off = 38
4360 * d_off = 26
4362 * org_pos = anchor + (edge_orig - anchor_orig)
4363 * org_center = org_pos + org_len / 2
4365 * cur_pos1 = ROUND(org_center)
4366 * delta1 = |org_center - (cur_pos1 - u_off)|
4367 * delta2 = |org_center - (cur_pos1 + d_off)|
4368 * if (delta1 < delta2):
4369 * cur_pos1 = cur_pos1 - u_off
4370 * else:
4371 * cur_pos1 = cur_pos1 + d_off
4373 * edge = cur_pos1 - cur_len / 2
4375 * else:
4376 * org_pos = anchor + (edge_orig - anchor_orig)
4377 * org_center = org_pos + org_len / 2
4379 * cur_pos1 = ROUND(org_pos)
4380 * delta1 = |cur_pos1 + cur_len / 2 - org_center|
4381 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
4382 * delta2 = |cur_pos2 + cur_len / 2 - org_center|
4384 * if (delta1 < delta2):
4385 * edge = cur_pos1
4386 * else:
4387 * edge = cur_pos2
4389 * edge2 = edge + cur_len
4391 * in: top_to_bottom_hinting
4392 * edge2_is_serif
4393 * edge_is_round
4394 * edge_point (in twilight zone)
4395 * edge2_point (in twilight zone)
4396 * edge[-1] (in twilight zone)
4397 * ... stuff for bci_align_segments (edge) ...
4398 * ... stuff for bci_align_segments (edge2)...
4400 * sal: sal_anchor
4401 * sal_temp1
4402 * sal_temp2
4403 * sal_temp3
4404 * sal_top_to_bottom_hinting
4406 * uses: bci_stem_common
4407 * bci_align_segments
4410 static const unsigned char FPGM(bci_stem_bound) [] =
4413 PUSHB_1,
4414 bci_stem_bound,
4415 FDEF,
4417 PUSHB_1,
4418 bci_stem_common,
4419 CALL,
4421 ROLL, /* s: edge[-1] cur_len edge edge2 */
4422 DUP,
4423 DUP,
4424 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4425 PUSHB_1,
4426 sal_edge2,
4427 SWAP,
4428 WS, /* s: edge[-1] cur_len edge edge2 */
4429 ROLL,
4430 SHPIX, /* edge2 = edge + cur_len */
4432 SWAP, /* s: edge edge[-1] */
4433 DUP,
4434 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
4435 GC_cur,
4436 PUSHB_1,
4438 CINDEX,
4439 GC_cur, /* s: edge edge[-1]_pos edge_pos */
4440 PUSHB_1,
4441 sal_top_to_bottom_hinting,
4444 LT, /* edge_pos > edge[-1]_pos */
4445 ELSE,
4446 GT, /* edge_pos < edge[-1]_pos */
4447 EIF,
4449 DUP,
4450 ALIGNRP, /* align `edge' to `edge[-1]' */
4451 EIF,
4453 MDAP_noround, /* set rp0 and rp1 to `edge' */
4455 PUSHB_2,
4456 bci_align_segments,
4458 SZP1, /* set zp1 to normal zone 1 */
4459 CALL,
4461 PUSHB_1,
4462 sal_edge2,
4464 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4466 PUSHB_1,
4467 bci_align_segments,
4468 CALL,
4470 ENDF,
4476 * bci_action_stem_bound
4477 * bci_action_stem_bound_serif
4478 * bci_action_stem_bound_round
4479 * bci_action_stem_bound_round_serif
4480 * bci_action_stem_down_bound
4481 * bci_action_stem_down_bound_serif
4482 * bci_action_stem_down_bound_round
4483 * bci_action_stem_down_bound_round_serif
4485 * Higher-level routines for calling `bci_stem_bound'.
4488 static const unsigned char FPGM(bci_action_stem_bound) [] =
4491 PUSHB_1,
4492 bci_action_stem_bound,
4493 FDEF,
4495 PUSHB_4,
4499 bci_stem_bound,
4500 CALL,
4502 ENDF,
4506 static const unsigned char FPGM(bci_action_stem_bound_serif) [] =
4509 PUSHB_1,
4510 bci_action_stem_bound_serif,
4511 FDEF,
4513 PUSHB_4,
4517 bci_stem_bound,
4518 CALL,
4520 ENDF,
4524 static const unsigned char FPGM(bci_action_stem_bound_round) [] =
4527 PUSHB_1,
4528 bci_action_stem_bound_round,
4529 FDEF,
4531 PUSHB_4,
4535 bci_stem_bound,
4536 CALL,
4538 ENDF,
4542 static const unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
4545 PUSHB_1,
4546 bci_action_stem_bound_round_serif,
4547 FDEF,
4549 PUSHB_4,
4553 bci_stem_bound,
4554 CALL,
4556 ENDF,
4560 static const unsigned char FPGM(bci_action_stem_down_bound) [] =
4563 PUSHB_1,
4564 bci_action_stem_down_bound,
4565 FDEF,
4567 PUSHB_4,
4571 bci_stem_bound,
4572 CALL,
4574 ENDF,
4578 static const unsigned char FPGM(bci_action_stem_down_bound_serif) [] =
4581 PUSHB_1,
4582 bci_action_stem_down_bound_serif,
4583 FDEF,
4585 PUSHB_4,
4589 bci_stem_bound,
4590 CALL,
4592 ENDF,
4596 static const unsigned char FPGM(bci_action_stem_down_bound_round) [] =
4599 PUSHB_1,
4600 bci_action_stem_down_bound_round,
4601 FDEF,
4603 PUSHB_4,
4607 bci_stem_bound,
4608 CALL,
4610 ENDF,
4614 static const unsigned char FPGM(bci_action_stem_down_bound_round_serif) [] =
4617 PUSHB_1,
4618 bci_action_stem_down_bound_round_serif,
4619 FDEF,
4621 PUSHB_4,
4625 bci_stem_bound,
4626 CALL,
4628 ENDF,
4634 * bci_stem
4636 * Handle the STEM action to align two edges of a stem.
4638 * See `bci_stem_bound' for more details.
4640 * in: edge2_is_serif
4641 * edge_is_round
4642 * edge_point (in twilight zone)
4643 * edge2_point (in twilight zone)
4644 * ... stuff for bci_align_segments (edge) ...
4645 * ... stuff for bci_align_segments (edge2)...
4647 * sal: sal_anchor
4648 * sal_temp1
4649 * sal_temp2
4650 * sal_temp3
4652 * uses: bci_stem_common
4653 * bci_align_segments
4656 static const unsigned char FPGM(bci_stem) [] =
4659 PUSHB_1,
4660 bci_stem,
4661 FDEF,
4663 PUSHB_2,
4665 bci_stem_common,
4666 CALL,
4668 POP,
4669 SWAP, /* s: cur_len edge2 */
4670 DUP,
4671 DUP,
4672 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4673 PUSHB_1,
4674 sal_edge2,
4675 SWAP,
4676 WS, /* s: cur_len edge2 */
4677 SWAP,
4678 SHPIX, /* edge2 = edge + cur_len */
4680 PUSHB_2,
4681 bci_align_segments,
4683 SZP1, /* set zp1 to normal zone 1 */
4684 CALL,
4686 PUSHB_1,
4687 sal_edge2,
4689 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4691 PUSHB_1,
4692 bci_align_segments,
4693 CALL,
4694 ENDF,
4700 * bci_action_stem
4701 * bci_action_stem_serif
4702 * bci_action_stem_round
4703 * bci_action_stem_round_serif
4705 * Higher-level routines for calling `bci_stem'.
4708 static const unsigned char FPGM(bci_action_stem) [] =
4711 PUSHB_1,
4712 bci_action_stem,
4713 FDEF,
4715 PUSHB_3,
4718 bci_stem,
4719 CALL,
4721 ENDF,
4725 static const unsigned char FPGM(bci_action_stem_serif) [] =
4728 PUSHB_1,
4729 bci_action_stem_serif,
4730 FDEF,
4732 PUSHB_3,
4735 bci_stem,
4736 CALL,
4738 ENDF,
4742 static const unsigned char FPGM(bci_action_stem_round) [] =
4745 PUSHB_1,
4746 bci_action_stem_round,
4747 FDEF,
4749 PUSHB_3,
4752 bci_stem,
4753 CALL,
4755 ENDF,
4759 static const unsigned char FPGM(bci_action_stem_round_serif) [] =
4762 PUSHB_1,
4763 bci_action_stem_round_serif,
4764 FDEF,
4766 PUSHB_3,
4769 bci_stem,
4770 CALL,
4772 ENDF,
4778 * bci_link
4780 * Handle the LINK action to link an edge to another one.
4782 * in: stem_is_serif
4783 * base_is_round
4784 * base_point (in twilight zone)
4785 * stem_point (in twilight zone)
4786 * ... stuff for bci_align_segments (base) ...
4788 * sal: sal_base_delta
4790 * uses: func[sal_stem_width_function]
4791 * bci_align_segments
4794 static const unsigned char FPGM(bci_link) [] =
4797 PUSHB_1,
4798 bci_link,
4799 FDEF,
4801 PUSHB_1,
4803 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4805 PUSHB_1,
4807 CINDEX,
4808 PUSHB_1,
4810 MINDEX,
4811 DUP, /* s: stem is_round is_serif stem base base */
4813 DUP,
4814 DUP,
4815 GC_cur,
4816 SWAP,
4817 GC_orig,
4818 SUB, /* base_delta = base_point_pos - base_point_orig_pos */
4819 PUSHB_1,
4820 sal_base_delta,
4821 SWAP,
4822 WS, /* sal_base_delta = base_delta */
4824 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4826 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4828 PUSHB_1,
4829 sal_stem_width_function,
4831 CALL, /* s: stem new_dist */
4833 SWAP,
4834 DUP,
4835 ALIGNRP, /* align `stem_point' with `base_point' */
4836 DUP,
4837 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4838 SWAP,
4839 SHPIX, /* stem_point = base_point + new_dist */
4841 PUSHB_2,
4842 bci_align_segments,
4844 SZP1, /* set zp1 to normal zone 1 */
4845 CALL,
4847 ENDF,
4853 * bci_action_link
4854 * bci_action_link_serif
4855 * bci_action_link_round
4856 * bci_action_link_round_serif
4858 * Higher-level routines for calling `bci_link'.
4861 static const unsigned char FPGM(bci_action_link) [] =
4864 PUSHB_1,
4865 bci_action_link,
4866 FDEF,
4868 PUSHB_3,
4871 bci_link,
4872 CALL,
4874 ENDF,
4878 static const unsigned char FPGM(bci_action_link_serif) [] =
4881 PUSHB_1,
4882 bci_action_link_serif,
4883 FDEF,
4885 PUSHB_3,
4888 bci_link,
4889 CALL,
4891 ENDF,
4895 static const unsigned char FPGM(bci_action_link_round) [] =
4898 PUSHB_1,
4899 bci_action_link_round,
4900 FDEF,
4902 PUSHB_3,
4905 bci_link,
4906 CALL,
4908 ENDF,
4912 static const unsigned char FPGM(bci_action_link_round_serif) [] =
4915 PUSHB_1,
4916 bci_action_link_round_serif,
4917 FDEF,
4919 PUSHB_3,
4922 bci_link,
4923 CALL,
4925 ENDF,
4931 * bci_anchor
4933 * Handle the ANCHOR action to align two edges
4934 * and to set the edge anchor.
4936 * The code after computing `cur_len' to shift `edge' and `edge2'
4937 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4939 * if cur_len < 96:
4940 * if cur_len < = 64:
4941 * u_off = 32
4942 * d_off = 32
4943 * else:
4944 * u_off = 38
4945 * d_off = 26
4947 * org_center = edge_orig + org_len / 2
4948 * cur_pos1 = ROUND(org_center)
4950 * error1 = |org_center - (cur_pos1 - u_off)|
4951 * error2 = |org_center - (cur_pos1 + d_off)|
4952 * if (error1 < error2):
4953 * cur_pos1 = cur_pos1 - u_off
4954 * else:
4955 * cur_pos1 = cur_pos1 + d_off
4957 * edge = cur_pos1 - cur_len / 2
4958 * edge2 = edge + cur_len
4960 * else:
4961 * edge = ROUND(edge_orig)
4963 * in: edge2_is_serif
4964 * edge_is_round
4965 * edge_point (in twilight zone)
4966 * edge2_point (in twilight zone)
4967 * ... stuff for bci_align_segments (edge) ...
4969 * sal: sal_anchor
4970 * sal_temp1
4971 * sal_temp2
4972 * sal_temp3
4973 * sal_base_delta
4975 * uses: func[sal_stem_width_function]
4976 * bci_round
4977 * bci_align_segments
4980 #undef sal_u_off
4981 #define sal_u_off sal_temp1
4982 #undef sal_d_off
4983 #define sal_d_off sal_temp2
4984 #undef sal_org_len
4985 #define sal_org_len sal_temp3
4987 static const unsigned char FPGM(bci_anchor) [] =
4990 PUSHB_1,
4991 bci_anchor,
4992 FDEF,
4994 /* store anchor point number in `sal_anchor' */
4995 PUSHB_2,
4996 sal_anchor,
4998 CINDEX,
4999 WS, /* sal_anchor = edge_point */
5001 PUSHB_1,
5003 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5005 PUSHB_1,
5007 CINDEX,
5008 PUSHB_1,
5010 CINDEX,
5011 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
5012 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
5014 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
5015 DUP,
5016 PUSHB_1,
5017 sal_org_len,
5018 SWAP,
5021 PUSHB_2,
5022 sal_base_delta, /* no base_delta needed here */
5026 PUSHB_1,
5027 sal_stem_width_function,
5029 CALL, /* s: edge2 edge cur_len */
5031 DUP,
5032 PUSHB_1,
5034 LT, /* cur_len < 96 */
5036 DUP,
5037 PUSHB_1,
5039 LTEQ, /* cur_len <= 64 */
5041 PUSHB_4,
5042 sal_u_off,
5044 sal_d_off,
5047 ELSE,
5048 PUSHB_4,
5049 sal_u_off,
5051 sal_d_off,
5053 EIF,
5057 SWAP, /* s: edge2 cur_len edge */
5058 DUP, /* s: edge2 cur_len edge edge */
5060 GC_orig,
5061 PUSHB_1,
5062 sal_org_len,
5064 DIV_BY_2,
5065 ADD, /* s: edge2 cur_len edge org_center */
5067 DUP,
5068 PUSHB_1,
5069 bci_round,
5070 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
5072 DUP,
5073 ROLL,
5074 ROLL,
5075 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
5077 DUP,
5078 PUSHB_1,
5079 sal_u_off,
5081 ADD,
5082 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
5084 SWAP,
5085 PUSHB_1,
5086 sal_d_off,
5088 SUB,
5089 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
5091 LT, /* error1 < error2 */
5093 PUSHB_1,
5094 sal_u_off,
5096 SUB, /* cur_pos1 = cur_pos1 - u_off */
5098 ELSE,
5099 PUSHB_1,
5100 sal_d_off,
5102 ADD, /* cur_pos1 = cur_pos1 + d_off */
5103 EIF, /* s: edge2 cur_len edge cur_pos1 */
5105 PUSHB_1,
5107 CINDEX,
5108 DIV_BY_2,
5109 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
5111 PUSHB_1,
5113 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
5114 GC_cur,
5115 SUB,
5116 SHPIX, /* edge = cur_pos1 - cur_len/2 */
5118 SWAP, /* s: cur_len edge2 */
5119 DUP,
5120 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
5121 SWAP,
5122 SHPIX, /* edge2 = edge1 + cur_len */
5124 ELSE,
5125 POP, /* s: edge2 edge */
5126 DUP,
5127 DUP,
5128 GC_cur,
5129 SWAP,
5130 GC_orig,
5131 PUSHB_1,
5132 bci_round,
5133 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
5134 SWAP,
5135 SUB,
5136 SHPIX, /* edge = round(edge_orig) */
5138 /* clean up stack */
5139 POP,
5140 EIF,
5142 PUSHB_2,
5143 bci_align_segments,
5145 SZP1, /* set zp1 to normal zone 1 */
5146 CALL,
5148 ENDF,
5154 * bci_action_anchor
5155 * bci_action_anchor_serif
5156 * bci_action_anchor_round
5157 * bci_action_anchor_round_serif
5159 * Higher-level routines for calling `bci_anchor'.
5162 static const unsigned char FPGM(bci_action_anchor) [] =
5165 PUSHB_1,
5166 bci_action_anchor,
5167 FDEF,
5169 PUSHB_3,
5172 bci_anchor,
5173 CALL,
5175 ENDF,
5179 static const unsigned char FPGM(bci_action_anchor_serif) [] =
5182 PUSHB_1,
5183 bci_action_anchor_serif,
5184 FDEF,
5186 PUSHB_3,
5189 bci_anchor,
5190 CALL,
5192 ENDF,
5196 static const unsigned char FPGM(bci_action_anchor_round) [] =
5199 PUSHB_1,
5200 bci_action_anchor_round,
5201 FDEF,
5203 PUSHB_3,
5206 bci_anchor,
5207 CALL,
5209 ENDF,
5213 static const unsigned char FPGM(bci_action_anchor_round_serif) [] =
5216 PUSHB_1,
5217 bci_action_anchor_round_serif,
5218 FDEF,
5220 PUSHB_3,
5223 bci_anchor,
5224 CALL,
5226 ENDF,
5232 * bci_action_blue_anchor
5234 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
5235 * and to set the edge anchor.
5237 * in: anchor_point (in twilight zone)
5238 * blue_cvt_idx
5239 * edge_point (in twilight zone)
5240 * ... stuff for bci_align_segments (edge) ...
5242 * sal: sal_anchor
5244 * uses: bci_action_blue
5247 static const unsigned char FPGM(bci_action_blue_anchor) [] =
5250 PUSHB_1,
5251 bci_action_blue_anchor,
5252 FDEF,
5254 /* store anchor point number in `sal_anchor' */
5255 PUSHB_1,
5256 sal_anchor,
5257 SWAP,
5260 PUSHB_1,
5261 bci_action_blue,
5262 CALL,
5264 ENDF,
5270 * bci_action_blue
5272 * Handle the BLUE action to align an edge with a blue zone.
5274 * in: blue_cvt_idx
5275 * edge_point (in twilight zone)
5276 * ... stuff for bci_align_segments (edge) ...
5278 * uses: bci_align_segments
5281 static const unsigned char FPGM(bci_action_blue) [] =
5284 PUSHB_1,
5285 bci_action_blue,
5286 FDEF,
5288 PUSHB_1,
5290 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5292 /* move `edge_point' to `blue_cvt_idx' position; */
5293 /* note that we can't use MIAP since this would modify */
5294 /* the twilight point's original coordinates also */
5295 RCVT,
5296 SWAP,
5297 DUP,
5298 MDAP_noround, /* set rp0 and rp1 to `edge' */
5299 DUP,
5300 GC_cur, /* s: new_pos edge edge_pos */
5301 ROLL,
5302 SWAP,
5303 SUB, /* s: edge (new_pos - edge_pos) */
5304 SHPIX,
5306 PUSHB_2,
5307 bci_align_segments,
5309 SZP1, /* set zp1 to normal zone 1 */
5310 CALL,
5312 ENDF,
5318 * bci_serif_common
5320 * Common code for bci_action_serif routines.
5322 * in: top_to_bottom_hinting
5323 * serif
5324 * base
5326 * sal: sal_top_to_bottom_hinting
5330 static const unsigned char FPGM(bci_serif_common) [] =
5333 PUSHB_1,
5334 bci_serif_common,
5335 FDEF,
5337 PUSHB_1,
5339 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5341 PUSHB_1,
5342 sal_top_to_bottom_hinting,
5343 SWAP,
5346 DUP,
5347 DUP,
5348 DUP,
5349 PUSHB_1,
5351 MINDEX, /* s: [...] serif serif serif serif base */
5352 DUP,
5353 MDAP_noround, /* set rp0 and rp1 to `base_point' */
5354 MD_orig_ZP2_0,
5355 SWAP,
5356 ALIGNRP, /* align `serif_point' with `base_point' */
5357 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
5359 ENDF,
5365 * bci_lower_bound
5367 * Move an edge if necessary to stay within a lower bound.
5369 * in: edge
5370 * bound
5372 * sal: sal_top_to_bottom_hinting
5374 * uses: bci_align_segments
5377 static const unsigned char FPGM(bci_lower_bound) [] =
5380 PUSHB_1,
5381 bci_lower_bound,
5382 FDEF,
5384 SWAP, /* s: edge bound */
5385 DUP,
5386 MDAP_noround, /* set rp0 and rp1 to `bound' */
5387 GC_cur,
5388 PUSHB_1,
5390 CINDEX,
5391 GC_cur, /* s: edge bound_pos edge_pos */
5392 PUSHB_1,
5393 sal_top_to_bottom_hinting,
5396 LT, /* edge_pos > bound_pos */
5397 ELSE,
5398 GT, /* edge_pos < bound_pos */
5399 EIF,
5401 DUP,
5402 ALIGNRP, /* align `edge' to `bound' */
5403 EIF,
5405 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5407 PUSHB_2,
5408 bci_align_segments,
5410 SZP1, /* set zp1 to normal zone 1 */
5411 CALL,
5413 ENDF,
5419 * bci_upper_bound
5421 * Move an edge if necessary to stay within an upper bound.
5423 * in: edge
5424 * bound
5426 * sal: sal_top_to_bottom_hinting
5428 * uses: bci_align_segments
5431 static const unsigned char FPGM(bci_upper_bound) [] =
5434 PUSHB_1,
5435 bci_upper_bound,
5436 FDEF,
5438 SWAP, /* s: edge bound */
5439 DUP,
5440 MDAP_noround, /* set rp0 and rp1 to `bound' */
5441 GC_cur,
5442 PUSHB_1,
5444 CINDEX,
5445 GC_cur, /* s: edge bound_pos edge_pos */
5446 PUSHB_1,
5447 sal_top_to_bottom_hinting,
5450 GT, /* edge_pos < bound_pos */
5451 ELSE,
5452 LT, /* edge_pos > bound_pos */
5453 EIF,
5455 DUP,
5456 ALIGNRP, /* align `edge' to `bound' */
5457 EIF,
5459 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5461 PUSHB_2,
5462 bci_align_segments,
5464 SZP1, /* set zp1 to normal zone 1 */
5465 CALL,
5467 ENDF,
5473 * bci_upper_lower_bound
5475 * Move an edge if necessary to stay within a lower and lower bound.
5477 * in: edge
5478 * lower
5479 * upper
5481 * sal: sal_top_to_bottom_hinting
5483 * uses: bci_align_segments
5486 static const unsigned char FPGM(bci_upper_lower_bound) [] =
5489 PUSHB_1,
5490 bci_upper_lower_bound,
5491 FDEF,
5493 SWAP, /* s: upper serif lower */
5494 DUP,
5495 MDAP_noround, /* set rp0 and rp1 to `lower' */
5496 GC_cur,
5497 PUSHB_1,
5499 CINDEX,
5500 GC_cur, /* s: upper serif lower_pos serif_pos */
5501 PUSHB_1,
5502 sal_top_to_bottom_hinting,
5505 LT, /* serif_pos > lower_pos */
5506 ELSE,
5507 GT, /* serif_pos < lower_pos */
5508 EIF,
5510 DUP,
5511 ALIGNRP, /* align `serif' to `lower' */
5512 EIF,
5514 SWAP, /* s: serif upper */
5515 DUP,
5516 MDAP_noround, /* set rp0 and rp1 to `upper' */
5517 GC_cur,
5518 PUSHB_1,
5520 CINDEX,
5521 GC_cur, /* s: serif upper_pos serif_pos */
5522 PUSHB_1,
5523 sal_top_to_bottom_hinting,
5526 GT, /* serif_pos < upper_pos */
5527 ELSE,
5528 LT, /* serif_pos > upper_pos */
5529 EIF,
5531 DUP,
5532 ALIGNRP, /* align `serif' to `upper' */
5533 EIF,
5535 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5537 PUSHB_2,
5538 bci_align_segments,
5540 SZP1, /* set zp1 to normal zone 1 */
5541 CALL,
5543 ENDF,
5549 * bci_action_serif
5551 * Handle the SERIF action to align a serif with its base.
5553 * in: serif_point (in twilight zone)
5554 * base_point (in twilight zone)
5555 * ... stuff for bci_align_segments (serif) ...
5557 * uses: bci_serif_common
5558 * bci_align_segments
5561 static const unsigned char FPGM(bci_action_serif) [] =
5564 PUSHB_1,
5565 bci_action_serif,
5566 FDEF,
5568 PUSHB_2,
5570 bci_serif_common,
5571 CALL,
5573 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5575 PUSHB_2,
5576 bci_align_segments,
5578 SZP1, /* set zp1 to normal zone 1 */
5579 CALL,
5581 ENDF,
5587 * bci_action_serif_lower_bound
5589 * Handle the SERIF action to align a serif with its base, then moving it
5590 * again if necessary to stay within a lower bound.
5592 * in: serif_point (in twilight zone)
5593 * base_point (in twilight zone)
5594 * edge[-1] (in twilight zone)
5595 * ... stuff for bci_align_segments (serif) ...
5597 * uses: bci_serif_common
5598 * bci_lower_bound
5601 static const unsigned char FPGM(bci_action_serif_lower_bound) [] =
5604 PUSHB_1,
5605 bci_action_serif_lower_bound,
5606 FDEF,
5608 PUSHB_2,
5610 bci_serif_common,
5611 CALL,
5613 PUSHB_1,
5614 bci_lower_bound,
5615 CALL,
5617 ENDF,
5623 * bci_action_serif_upper_bound
5625 * Handle the SERIF action to align a serif with its base, then moving it
5626 * again if necessary to stay within an upper bound.
5628 * in: serif_point (in twilight zone)
5629 * base_point (in twilight zone)
5630 * edge[1] (in twilight zone)
5631 * ... stuff for bci_align_segments (serif) ...
5633 * uses: bci_serif_common
5634 * bci_upper_bound
5637 static const unsigned char FPGM(bci_action_serif_upper_bound) [] =
5640 PUSHB_1,
5641 bci_action_serif_upper_bound,
5642 FDEF,
5644 PUSHB_2,
5646 bci_serif_common,
5647 CALL,
5649 PUSHB_1,
5650 bci_upper_bound,
5651 CALL,
5653 ENDF,
5659 * bci_action_serif_upper_lower_bound
5661 * Handle the SERIF action to align a serif with its base, then moving it
5662 * again if necessary to stay within a lower and upper bound.
5664 * in: serif_point (in twilight zone)
5665 * base_point (in twilight zone)
5666 * edge[-1] (in twilight zone)
5667 * edge[1] (in twilight zone)
5668 * ... stuff for bci_align_segments (serif) ...
5670 * uses: bci_serif_common
5671 * bci_upper_lower_bound
5674 static const unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
5677 PUSHB_1,
5678 bci_action_serif_upper_lower_bound,
5679 FDEF,
5681 PUSHB_1,
5683 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5685 PUSHB_2,
5687 bci_serif_common,
5688 CALL,
5690 PUSHB_1,
5691 bci_upper_lower_bound,
5692 CALL,
5694 ENDF,
5700 * bci_action_serif_down_lower_bound
5702 * Handle the SERIF action to align a serif with its base, then moving it
5703 * again if necessary to stay within a lower bound. We hint top to
5704 * bottom.
5706 * in: serif_point (in twilight zone)
5707 * base_point (in twilight zone)
5708 * edge[-1] (in twilight zone)
5709 * ... stuff for bci_align_segments (serif) ...
5711 * uses: bci_serif_common
5712 * bci_lower_bound
5715 static const unsigned char FPGM(bci_action_serif_down_lower_bound) [] =
5718 PUSHB_1,
5719 bci_action_serif_down_lower_bound,
5720 FDEF,
5722 PUSHB_2,
5724 bci_serif_common,
5725 CALL,
5727 PUSHB_1,
5728 bci_lower_bound,
5729 CALL,
5731 ENDF,
5737 * bci_action_serif_down_upper_bound
5739 * Handle the SERIF action to align a serif with its base, then moving it
5740 * again if necessary to stay within an upper bound. We hint top to
5741 * bottom.
5743 * in: serif_point (in twilight zone)
5744 * base_point (in twilight zone)
5745 * edge[1] (in twilight zone)
5746 * ... stuff for bci_align_segments (serif) ...
5748 * uses: bci_serif_common
5749 * bci_upper_bound
5752 static const unsigned char FPGM(bci_action_serif_down_upper_bound) [] =
5755 PUSHB_1,
5756 bci_action_serif_down_upper_bound,
5757 FDEF,
5759 PUSHB_2,
5761 bci_serif_common,
5762 CALL,
5764 PUSHB_1,
5765 bci_upper_bound,
5766 CALL,
5768 ENDF,
5774 * bci_action_serif_down_upper_lower_bound
5776 * Handle the SERIF action to align a serif with its base, then moving it
5777 * again if necessary to stay within a lower and upper bound. We hint top
5778 * to bottom.
5780 * in: serif_point (in twilight zone)
5781 * base_point (in twilight zone)
5782 * edge[-1] (in twilight zone)
5783 * edge[1] (in twilight zone)
5784 * ... stuff for bci_align_segments (serif) ...
5786 * uses: bci_serif_common
5787 * bci_upper_lower_bound
5790 static const unsigned char FPGM(bci_action_serif_down_upper_lower_bound) [] =
5793 PUSHB_1,
5794 bci_action_serif_down_upper_lower_bound,
5795 FDEF,
5797 PUSHB_1,
5799 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5801 PUSHB_2,
5803 bci_serif_common,
5804 CALL,
5806 PUSHB_1,
5807 bci_upper_lower_bound,
5808 CALL,
5810 ENDF,
5816 * bci_serif_anchor_common
5818 * Common code for bci_action_serif_anchor routines.
5820 * in: top_to_bottom_hinting
5821 * edge
5823 * out: edge (adjusted)
5825 * sal: sal_anchor
5826 * sal_top_to_bottom_hinting
5828 * uses: bci_round
5831 static const unsigned char FPGM(bci_serif_anchor_common) [] =
5834 PUSHB_1,
5835 bci_serif_anchor_common,
5836 FDEF,
5838 PUSHB_1,
5840 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5842 PUSHB_1,
5843 sal_top_to_bottom_hinting,
5844 SWAP,
5847 DUP,
5848 PUSHB_1,
5849 sal_anchor,
5850 SWAP,
5851 WS, /* sal_anchor = edge_point */
5853 DUP,
5854 DUP,
5855 DUP,
5856 GC_cur,
5857 SWAP,
5858 GC_orig,
5859 PUSHB_1,
5860 bci_round,
5861 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
5862 SWAP,
5863 SUB,
5864 SHPIX, /* edge = round(edge_orig) */
5866 ENDF,
5872 * bci_action_serif_anchor
5874 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5875 * anchor.
5877 * in: edge_point (in twilight zone)
5878 * ... stuff for bci_align_segments (edge) ...
5880 * uses: bci_serif_anchor_common
5881 * bci_align_segments
5884 static const unsigned char FPGM(bci_action_serif_anchor) [] =
5887 PUSHB_1,
5888 bci_action_serif_anchor,
5889 FDEF,
5891 PUSHB_2,
5893 bci_serif_anchor_common,
5894 CALL,
5896 MDAP_noround, /* set rp0 and rp1 to `edge' */
5898 PUSHB_2,
5899 bci_align_segments,
5901 SZP1, /* set zp1 to normal zone 1 */
5902 CALL,
5904 ENDF,
5910 * bci_action_serif_anchor_lower_bound
5912 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5913 * anchor, then moving it again if necessary to stay within a lower
5914 * bound.
5916 * in: edge_point (in twilight zone)
5917 * edge[-1] (in twilight zone)
5918 * ... stuff for bci_align_segments (edge) ...
5920 * uses: bci_serif_anchor_common
5921 * bci_lower_bound
5924 static const unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
5927 PUSHB_1,
5928 bci_action_serif_anchor_lower_bound,
5929 FDEF,
5931 PUSHB_2,
5933 bci_serif_anchor_common,
5934 CALL,
5936 PUSHB_1,
5937 bci_lower_bound,
5938 CALL,
5940 ENDF,
5946 * bci_action_serif_anchor_upper_bound
5948 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5949 * anchor, then moving it again if necessary to stay within an upper
5950 * bound.
5952 * in: edge_point (in twilight zone)
5953 * edge[1] (in twilight zone)
5954 * ... stuff for bci_align_segments (edge) ...
5956 * uses: bci_serif_anchor_common
5957 * bci_upper_bound
5960 static const unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5963 PUSHB_1,
5964 bci_action_serif_anchor_upper_bound,
5965 FDEF,
5967 PUSHB_2,
5969 bci_serif_anchor_common,
5970 CALL,
5972 PUSHB_1,
5973 bci_upper_bound,
5974 CALL,
5976 ENDF,
5982 * bci_action_serif_anchor_upper_lower_bound
5984 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5985 * anchor, then moving it again if necessary to stay within a lower and
5986 * upper bound.
5988 * in: edge_point (in twilight zone)
5989 * edge[-1] (in twilight zone)
5990 * edge[1] (in twilight zone)
5991 * ... stuff for bci_align_segments (edge) ...
5993 * uses: bci_serif_anchor_common
5994 * bci_upper_lower_bound
5997 static const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
6000 PUSHB_1,
6001 bci_action_serif_anchor_upper_lower_bound,
6002 FDEF,
6004 PUSHB_2,
6006 bci_serif_anchor_common,
6007 CALL,
6009 PUSHB_1,
6010 bci_upper_lower_bound,
6011 CALL,
6013 ENDF,
6019 * bci_action_serif_anchor_down_lower_bound
6021 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6022 * anchor, then moving it again if necessary to stay within a lower
6023 * bound. We hint top to bottom.
6025 * in: edge_point (in twilight zone)
6026 * edge[-1] (in twilight zone)
6027 * ... stuff for bci_align_segments (edge) ...
6029 * uses: bci_serif_anchor_common
6030 * bci_lower_bound
6033 static const unsigned char FPGM(bci_action_serif_anchor_down_lower_bound) [] =
6036 PUSHB_1,
6037 bci_action_serif_anchor_down_lower_bound,
6038 FDEF,
6040 PUSHB_2,
6042 bci_serif_anchor_common,
6043 CALL,
6045 PUSHB_1,
6046 bci_lower_bound,
6047 CALL,
6049 ENDF,
6055 * bci_action_serif_anchor_down_upper_bound
6057 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6058 * anchor, then moving it again if necessary to stay within an upper
6059 * bound. We hint top to bottom.
6061 * in: edge_point (in twilight zone)
6062 * edge[1] (in twilight zone)
6063 * ... stuff for bci_align_segments (edge) ...
6065 * uses: bci_serif_anchor_common
6066 * bci_upper_bound
6069 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_bound) [] =
6072 PUSHB_1,
6073 bci_action_serif_anchor_down_upper_bound,
6074 FDEF,
6076 PUSHB_2,
6078 bci_serif_anchor_common,
6079 CALL,
6081 PUSHB_1,
6082 bci_upper_bound,
6083 CALL,
6085 ENDF,
6091 * bci_action_serif_anchor_down_upper_lower_bound
6093 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6094 * anchor, then moving it again if necessary to stay within a lower and
6095 * upper bound. We hint top to bottom.
6097 * in: edge_point (in twilight zone)
6098 * edge[-1] (in twilight zone)
6099 * edge[1] (in twilight zone)
6100 * ... stuff for bci_align_segments (edge) ...
6102 * uses: bci_serif_anchor_common
6103 * bci_upper_lower_bound
6106 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_lower_bound) [] =
6109 PUSHB_1,
6110 bci_action_serif_anchor_down_upper_lower_bound,
6111 FDEF,
6113 PUSHB_2,
6115 bci_serif_anchor_common,
6116 CALL,
6118 PUSHB_1,
6119 bci_upper_lower_bound,
6120 CALL,
6122 ENDF,
6128 * bci_serif_link1_common
6130 * Common code for bci_action_serif_link1 routines.
6132 * in: top_to_bottom_hinting
6133 * before
6134 * edge
6135 * after
6137 * out: edge (adjusted)
6139 * sal: sal_top_to_bottom_hinting
6143 static const unsigned char FPGM(bci_serif_link1_common) [] =
6146 PUSHB_1,
6147 bci_serif_link1_common,
6148 FDEF,
6150 PUSHB_1,
6152 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6154 PUSHB_1,
6155 sal_top_to_bottom_hinting,
6156 SWAP,
6159 PUSHB_1,
6161 CINDEX, /* s: [...] after edge before after */
6162 PUSHB_1,
6164 CINDEX, /* s: [...] after edge before after before */
6165 MD_orig_ZP2_0,
6166 PUSHB_1,
6168 EQ, /* after_orig_pos == before_orig_pos */
6169 IF, /* s: [...] after edge before */
6170 MDAP_noround, /* set rp0 and rp1 to `before' */
6171 DUP,
6172 ALIGNRP, /* align `edge' with `before' */
6173 SWAP,
6174 POP,
6176 ELSE,
6177 /* we have to execute `a*b/c', with b/c very near to 1: */
6178 /* to avoid overflow while retaining precision, */
6179 /* we transform this to `a + a * (b-c)/c' */
6181 PUSHB_1,
6183 CINDEX, /* s: [...] after edge before edge */
6184 PUSHB_1,
6186 CINDEX, /* s: [...] after edge before edge before */
6187 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
6189 DUP,
6190 PUSHB_1,
6192 CINDEX, /* s: [...] after edge before a a after */
6193 PUSHB_1,
6195 CINDEX, /* s: [...] after edge before a a after before */
6196 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
6198 PUSHB_1,
6200 CINDEX, /* s: [...] after edge before a a c after */
6201 PUSHB_1,
6203 CINDEX, /* s: [...] after edge before a a c after before */
6204 MD_cur, /* b = after_pos - before_pos */
6206 PUSHB_1,
6208 CINDEX, /* s: [...] after edge before a a c b c */
6209 SUB, /* b-c */
6211 PUSHW_2,
6212 0x08, /* 0x800 */
6213 0x00,
6214 0x08, /* 0x800 */
6215 0x00,
6216 MUL, /* 0x10000 */
6217 MUL, /* (b-c) in 16.16 format */
6218 SWAP,
6220 DUP,
6221 IF, /* c != 0 ? */
6222 DIV, /* s: [...] after edge before a a (b-c)/c */
6223 ELSE,
6224 POP, /* avoid division by zero */
6225 EIF,
6227 MUL, /* a * (b-c)/c * 2^10 */
6228 DIV_BY_1024, /* a * (b-c)/c */
6229 ADD, /* a*b/c */
6231 SWAP,
6232 MDAP_noround, /* set rp0 and rp1 to `before' */
6233 SWAP, /* s: [...] after a*b/c edge */
6234 DUP,
6235 DUP,
6236 ALIGNRP, /* align `edge' with `before' */
6237 ROLL,
6238 SHPIX, /* shift `edge' by `a*b/c' */
6240 SWAP, /* s: [...] edge after */
6241 POP,
6242 EIF,
6244 ENDF,
6250 * bci_action_serif_link1
6252 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6253 * before and after.
6255 * in: before_point (in twilight zone)
6256 * edge_point (in twilight zone)
6257 * after_point (in twilight zone)
6258 * ... stuff for bci_align_segments (edge) ...
6260 * uses: bci_serif_link1_common
6261 * bci_align_segments
6264 static const unsigned char FPGM(bci_action_serif_link1) [] =
6267 PUSHB_1,
6268 bci_action_serif_link1,
6269 FDEF,
6271 PUSHB_2,
6273 bci_serif_link1_common,
6274 CALL,
6276 MDAP_noround, /* set rp0 and rp1 to `edge' */
6278 PUSHB_2,
6279 bci_align_segments,
6281 SZP1, /* set zp1 to normal zone 1 */
6282 CALL,
6284 ENDF,
6290 * bci_action_serif_link1_lower_bound
6292 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6293 * before and after. Additionally, move the serif again if necessary to
6294 * stay within a lower bound.
6296 * in: before_point (in twilight zone)
6297 * edge_point (in twilight zone)
6298 * after_point (in twilight zone)
6299 * edge[-1] (in twilight zone)
6300 * ... stuff for bci_align_segments (edge) ...
6302 * uses: bci_serif_link1_common
6303 * bci_lower_bound
6306 static const unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
6309 PUSHB_1,
6310 bci_action_serif_link1_lower_bound,
6311 FDEF,
6313 PUSHB_2,
6315 bci_serif_link1_common,
6316 CALL,
6318 PUSHB_1,
6319 bci_lower_bound,
6320 CALL,
6322 ENDF,
6328 * bci_action_serif_link1_upper_bound
6330 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6331 * before and after. Additionally, move the serif again if necessary to
6332 * stay within an upper bound.
6334 * in: before_point (in twilight zone)
6335 * edge_point (in twilight zone)
6336 * after_point (in twilight zone)
6337 * edge[1] (in twilight zone)
6338 * ... stuff for bci_align_segments (edge) ...
6340 * uses: bci_serif_link1_common
6341 * bci_upper_bound
6344 static const unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
6347 PUSHB_1,
6348 bci_action_serif_link1_upper_bound,
6349 FDEF,
6351 PUSHB_2,
6353 bci_serif_link1_common,
6354 CALL,
6356 PUSHB_1,
6357 bci_upper_bound,
6358 CALL,
6360 ENDF,
6366 * bci_action_serif_link1_upper_lower_bound
6368 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6369 * before and after. Additionally, move the serif again if necessary to
6370 * stay within a lower and upper bound.
6372 * in: before_point (in twilight zone)
6373 * edge_point (in twilight zone)
6374 * after_point (in twilight zone)
6375 * edge[-1] (in twilight zone)
6376 * edge[1] (in twilight zone)
6377 * ... stuff for bci_align_segments (edge) ...
6379 * uses: bci_serif_link1_common
6380 * bci_upper_lower_bound
6383 static const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
6386 PUSHB_1,
6387 bci_action_serif_link1_upper_lower_bound,
6388 FDEF,
6390 PUSHB_2,
6392 bci_serif_link1_common,
6393 CALL,
6395 PUSHB_1,
6396 bci_upper_lower_bound,
6397 CALL,
6399 ENDF,
6405 * bci_action_serif_link1_down_lower_bound
6407 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6408 * before and after. Additionally, move the serif again if necessary to
6409 * stay within a lower bound. We hint top to bottom.
6411 * in: before_point (in twilight zone)
6412 * edge_point (in twilight zone)
6413 * after_point (in twilight zone)
6414 * edge[-1] (in twilight zone)
6415 * ... stuff for bci_align_segments (edge) ...
6417 * uses: bci_serif_link1_common
6418 * bci_lower_bound
6421 static const unsigned char FPGM(bci_action_serif_link1_down_lower_bound) [] =
6424 PUSHB_1,
6425 bci_action_serif_link1_down_lower_bound,
6426 FDEF,
6428 PUSHB_2,
6430 bci_serif_link1_common,
6431 CALL,
6433 PUSHB_1,
6434 bci_lower_bound,
6435 CALL,
6437 ENDF,
6443 * bci_action_serif_link1_down_upper_bound
6445 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6446 * before and after. Additionally, move the serif again if necessary to
6447 * stay within an upper bound. We hint top to bottom.
6449 * in: before_point (in twilight zone)
6450 * edge_point (in twilight zone)
6451 * after_point (in twilight zone)
6452 * edge[1] (in twilight zone)
6453 * ... stuff for bci_align_segments (edge) ...
6455 * uses: bci_serif_link1_common
6456 * bci_upper_bound
6459 static const unsigned char FPGM(bci_action_serif_link1_down_upper_bound) [] =
6462 PUSHB_1,
6463 bci_action_serif_link1_down_upper_bound,
6464 FDEF,
6466 PUSHB_2,
6468 bci_serif_link1_common,
6469 CALL,
6471 PUSHB_1,
6472 bci_upper_bound,
6473 CALL,
6475 ENDF,
6481 * bci_action_serif_link1_down_upper_lower_bound
6483 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6484 * before and after. Additionally, move the serif again if necessary to
6485 * stay within a lower and upper bound. We hint top to bottom.
6487 * in: before_point (in twilight zone)
6488 * edge_point (in twilight zone)
6489 * after_point (in twilight zone)
6490 * edge[-1] (in twilight zone)
6491 * edge[1] (in twilight zone)
6492 * ... stuff for bci_align_segments (edge) ...
6494 * uses: bci_serif_link1_common
6495 * bci_upper_lower_bound
6498 static const unsigned char FPGM(bci_action_serif_link1_down_upper_lower_bound) [] =
6501 PUSHB_1,
6502 bci_action_serif_link1_down_upper_lower_bound,
6503 FDEF,
6505 PUSHB_2,
6507 bci_serif_link1_common,
6508 CALL,
6510 PUSHB_1,
6511 bci_upper_lower_bound,
6512 CALL,
6514 ENDF,
6520 * bci_serif_link2_common
6522 * Common code for bci_action_serif_link2 routines.
6524 * in: top_to_bottom_hinting
6525 * edge
6527 * out: edge (adjusted)
6529 * sal: sal_anchor
6530 * sal_top_to_bottom_hinting
6534 static const unsigned char FPGM(bci_serif_link2_common) [] =
6537 PUSHB_1,
6538 bci_serif_link2_common,
6539 FDEF,
6541 PUSHB_1,
6543 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6545 PUSHB_1,
6546 sal_top_to_bottom_hinting,
6547 SWAP,
6550 DUP, /* s: [...] edge edge */
6551 PUSHB_1,
6552 sal_anchor,
6554 DUP, /* s: [...] edge edge anchor anchor */
6555 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
6557 MD_orig_ZP2_0,
6558 DUP,
6559 ADD,
6560 PUSHB_1,
6562 ADD,
6563 FLOOR,
6564 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
6566 SWAP,
6567 DUP,
6568 DUP,
6569 ALIGNRP, /* align `edge' with `sal_anchor' */
6570 ROLL,
6571 SHPIX, /* shift `edge' by `delta' */
6573 ENDF,
6579 * bci_action_serif_link2
6581 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6583 * in: edge_point (in twilight zone)
6584 * ... stuff for bci_align_segments (edge) ...
6586 * uses: bci_serif_link2_common
6587 * bci_align_segments
6590 static const unsigned char FPGM(bci_action_serif_link2) [] =
6593 PUSHB_1,
6594 bci_action_serif_link2,
6595 FDEF,
6597 PUSHB_2,
6599 bci_serif_link2_common,
6600 CALL,
6602 MDAP_noround, /* set rp0 and rp1 to `edge' */
6604 PUSHB_2,
6605 bci_align_segments,
6607 SZP1, /* set zp1 to normal zone 1 */
6608 CALL,
6610 ENDF,
6616 * bci_action_serif_link2_lower_bound
6618 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6619 * Additionally, move the serif again if necessary to stay within a lower
6620 * bound.
6622 * in: edge_point (in twilight zone)
6623 * edge[-1] (in twilight zone)
6624 * ... stuff for bci_align_segments (edge) ...
6626 * uses: bci_serif_link2_common
6627 * bci_lower_bound
6630 static const unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
6633 PUSHB_1,
6634 bci_action_serif_link2_lower_bound,
6635 FDEF,
6637 PUSHB_2,
6639 bci_serif_link2_common,
6640 CALL,
6642 PUSHB_1,
6643 bci_lower_bound,
6644 CALL,
6646 ENDF,
6652 * bci_action_serif_link2_upper_bound
6654 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6655 * Additionally, move the serif again if necessary to stay within an upper
6656 * bound.
6658 * in: edge_point (in twilight zone)
6659 * edge[1] (in twilight zone)
6660 * ... stuff for bci_align_segments (edge) ...
6662 * uses: bci_serif_link2_common
6663 * bci_upper_bound
6666 static const unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
6669 PUSHB_1,
6670 bci_action_serif_link2_upper_bound,
6671 FDEF,
6673 PUSHB_2,
6675 bci_serif_link2_common,
6676 CALL,
6678 PUSHB_1,
6679 bci_upper_bound,
6680 CALL,
6682 ENDF,
6688 * bci_action_serif_link2_upper_lower_bound
6690 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6691 * Additionally, move the serif again if necessary to stay within a lower
6692 * and upper bound.
6694 * in: edge_point (in twilight zone)
6695 * edge[-1] (in twilight zone)
6696 * edge[1] (in twilight zone)
6697 * ... stuff for bci_align_segments (edge) ...
6699 * uses: bci_serif_link2_common
6700 * bci_upper_lower_bound
6703 static const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
6706 PUSHB_1,
6707 bci_action_serif_link2_upper_lower_bound,
6708 FDEF,
6710 PUSHB_2,
6712 bci_serif_link2_common,
6713 CALL,
6715 PUSHB_1,
6716 bci_upper_lower_bound,
6717 CALL,
6719 ENDF,
6725 * bci_action_serif_link2_down_lower_bound
6727 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6728 * Additionally, move the serif again if necessary to stay within a lower
6729 * bound. We hint top to bottom.
6731 * in: edge_point (in twilight zone)
6732 * edge[-1] (in twilight zone)
6733 * ... stuff for bci_align_segments (edge) ...
6735 * uses: bci_serif_link2_common
6736 * bci_lower_bound
6739 static const unsigned char FPGM(bci_action_serif_link2_down_lower_bound) [] =
6742 PUSHB_1,
6743 bci_action_serif_link2_down_lower_bound,
6744 FDEF,
6746 PUSHB_2,
6748 bci_serif_link2_common,
6749 CALL,
6751 PUSHB_1,
6752 bci_lower_bound,
6753 CALL,
6755 ENDF,
6761 * bci_action_serif_link2_down_upper_bound
6763 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6764 * Additionally, move the serif again if necessary to stay within an upper
6765 * bound. We hint top to bottom.
6767 * in: edge_point (in twilight zone)
6768 * edge[1] (in twilight zone)
6769 * ... stuff for bci_align_segments (edge) ...
6771 * uses: bci_serif_link2_common
6772 * bci_upper_bound
6775 static const unsigned char FPGM(bci_action_serif_link2_down_upper_bound) [] =
6778 PUSHB_1,
6779 bci_action_serif_link2_down_upper_bound,
6780 FDEF,
6782 PUSHB_2,
6784 bci_serif_link2_common,
6785 CALL,
6787 PUSHB_1,
6788 bci_upper_bound,
6789 CALL,
6791 ENDF,
6797 * bci_action_serif_link2_down_upper_lower_bound
6799 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6800 * Additionally, move the serif again if necessary to stay within a lower
6801 * and upper bound. We hint top to bottom.
6803 * in: edge_point (in twilight zone)
6804 * edge[-1] (in twilight zone)
6805 * edge[1] (in twilight zone)
6806 * ... stuff for bci_align_segments (edge) ...
6808 * uses: bci_serif_link2_common
6809 * bci_upper_lower_bound
6812 static const unsigned char FPGM(bci_action_serif_link2_down_upper_lower_bound) [] =
6815 PUSHB_1,
6816 bci_action_serif_link2_down_upper_lower_bound,
6817 FDEF,
6819 PUSHB_2,
6821 bci_serif_link2_common,
6822 CALL,
6824 PUSHB_1,
6825 bci_upper_lower_bound,
6826 CALL,
6828 ENDF,
6834 * bci_hint_glyph
6836 * This is the top-level glyph hinting function which parses the arguments
6837 * on the stack and calls subroutines.
6839 * in: action_0_func_idx
6840 * ... data ...
6841 * action_1_func_idx
6842 * ... data ...
6843 * ...
6845 * CVT: cvtl_is_subglyph
6846 * cvtl_stem_width_mode
6847 * cvtl_do_iup_y
6849 * sal: sal_stem_width_function
6851 * uses: bci_action_ip_before
6852 * bci_action_ip_after
6853 * bci_action_ip_on
6854 * bci_action_ip_between
6856 * bci_action_adjust_bound
6857 * bci_action_adjust_bound_serif
6858 * bci_action_adjust_bound_round
6859 * bci_action_adjust_bound_round_serif
6861 * bci_action_stem_bound
6862 * bci_action_stem_bound_serif
6863 * bci_action_stem_bound_round
6864 * bci_action_stem_bound_round_serif
6866 * bci_action_link
6867 * bci_action_link_serif
6868 * bci_action_link_round
6869 * bci_action_link_round_serif
6871 * bci_action_anchor
6872 * bci_action_anchor_serif
6873 * bci_action_anchor_round
6874 * bci_action_anchor_round_serif
6876 * bci_action_blue_anchor
6878 * bci_action_adjust
6879 * bci_action_adjust_serif
6880 * bci_action_adjust_round
6881 * bci_action_adjust_round_serif
6883 * bci_action_stem
6884 * bci_action_stem_serif
6885 * bci_action_stem_round
6886 * bci_action_stem_round_serif
6888 * bci_action_blue
6890 * bci_action_serif
6891 * bci_action_serif_lower_bound
6892 * bci_action_serif_upper_bound
6893 * bci_action_serif_upper_lower_bound
6895 * bci_action_serif_anchor
6896 * bci_action_serif_anchor_lower_bound
6897 * bci_action_serif_anchor_upper_bound
6898 * bci_action_serif_anchor_upper_lower_bound
6900 * bci_action_serif_link1
6901 * bci_action_serif_link1_lower_bound
6902 * bci_action_serif_link1_upper_bound
6903 * bci_action_serif_link1_upper_lower_bound
6905 * bci_action_serif_link2
6906 * bci_action_serif_link2_lower_bound
6907 * bci_action_serif_link2_upper_bound
6908 * bci_action_serif_link2_upper_lower_bound
6911 static const unsigned char FPGM(bci_hint_glyph) [] =
6914 PUSHB_1,
6915 bci_hint_glyph,
6916 FDEF,
6919 * set up stem width function based on flag in CVT:
6921 * < 0: bci_natural_stem_width
6922 * == 0: bci_smooth_stem_width
6923 * > 0: bci_strong_stem_width
6925 PUSHB_3,
6926 sal_stem_width_function,
6928 cvtl_stem_width_mode,
6929 RCVT,
6932 PUSHB_1,
6933 bci_strong_stem_width,
6935 ELSE,
6936 PUSHB_3,
6937 bci_smooth_stem_width,
6938 bci_natural_stem_width,
6939 cvtl_stem_width_mode,
6940 RCVT,
6942 SWAP,
6943 POP,
6945 ELSE,
6946 POP,
6947 EIF,
6948 EIF,
6951 /* start_loop: */
6952 /* loop until all data on stack is used */
6953 CALL,
6954 PUSHB_1,
6956 NEG,
6957 PUSHB_1,
6959 DEPTH,
6961 JROT, /* goto start_loop */
6963 PUSHB_2,
6964 cvtl_do_iup_y,
6966 SZP2, /* set zp2 to normal zone 1 */
6967 RCVT,
6969 IUP_y,
6970 EIF,
6972 ENDF,
6977 #define COPY_FPGM(func_name) \
6978 do \
6980 memcpy(bufp, fpgm_ ## func_name, \
6981 sizeof (fpgm_ ## func_name)); \
6982 bufp += sizeof (fpgm_ ## func_name); \
6983 } while (0)
6985 static FT_Error
6986 TA_table_build_fpgm(FT_Byte** fpgm,
6987 FT_ULong* fpgm_len,
6988 SFNT* sfnt,
6989 FONT* font)
6991 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6992 glyf_Data* data = (glyf_Data*)glyf_table->data;
6994 unsigned char num_used_styles = (unsigned char)data->num_used_styles;
6995 unsigned char fallback_style =
6996 CVT_SCALING_VALUE_OFFSET(0)
6997 + (unsigned char)data->style_ids[font->fallback_style];
6999 FT_UInt buf_len;
7000 FT_UInt len;
7001 FT_Byte* buf;
7002 FT_Byte* bufp;
7005 /* for compatibility with dumb bytecode interpreters or analyzers, */
7006 /* FDEFs are stored in ascending index order, without holes -- */
7007 /* note that some FDEFs are not always needed */
7008 /* (depending on options of `TTFautohint'), */
7009 /* but implementing dynamic FDEF indices would be a lot of work */
7011 buf_len = sizeof (FPGM(bci_align_x_height_a))
7012 + (font->increase_x_height
7013 ? (sizeof (FPGM(bci_align_x_height_b1a))
7015 + sizeof (FPGM(bci_align_x_height_b1b)))
7016 : sizeof (FPGM(bci_align_x_height_b2)))
7017 + sizeof (FPGM(bci_align_x_height_c))
7018 + sizeof (FPGM(bci_round))
7019 + sizeof (FPGM(bci_natural_stem_width))
7020 + sizeof (FPGM(bci_quantize_stem_width))
7021 + sizeof (FPGM(bci_smooth_stem_width))
7022 + sizeof (FPGM(bci_get_best_width))
7023 + sizeof (FPGM(bci_strong_stem_width_a))
7025 + sizeof (FPGM(bci_strong_stem_width_b))
7026 + sizeof (FPGM(bci_loop_do))
7027 + sizeof (FPGM(bci_loop))
7028 + sizeof (FPGM(bci_cvt_rescale))
7029 + sizeof (FPGM(bci_cvt_rescale_range))
7030 + sizeof (FPGM(bci_vwidth_data_store))
7031 + sizeof (FPGM(bci_smooth_blue_round))
7032 + sizeof (FPGM(bci_strong_blue_round))
7033 + sizeof (FPGM(bci_blue_round_range))
7034 + sizeof (FPGM(bci_decrement_component_counter))
7035 + sizeof (FPGM(bci_get_point_extrema))
7036 + sizeof (FPGM(bci_nibbles))
7037 + sizeof (FPGM(bci_number_set_is_element))
7038 + sizeof (FPGM(bci_number_set_is_element2))
7040 + sizeof (FPGM(bci_create_segment))
7041 + sizeof (FPGM(bci_create_segments_a))
7043 + sizeof (FPGM(bci_create_segments_b))
7044 + (font->control_data_head != 0
7045 ? sizeof (FPGM(bci_create_segments_c))
7046 : 0)
7047 + sizeof (FPGM(bci_create_segments_d))
7049 + sizeof (FPGM(bci_create_segments_0))
7050 + sizeof (FPGM(bci_create_segments_1))
7051 + sizeof (FPGM(bci_create_segments_2))
7052 + sizeof (FPGM(bci_create_segments_3))
7053 + sizeof (FPGM(bci_create_segments_4))
7054 + sizeof (FPGM(bci_create_segments_5))
7055 + sizeof (FPGM(bci_create_segments_6))
7056 + sizeof (FPGM(bci_create_segments_7))
7057 + sizeof (FPGM(bci_create_segments_8))
7058 + sizeof (FPGM(bci_create_segments_9))
7060 + sizeof (FPGM(bci_deltap1))
7061 + sizeof (FPGM(bci_deltap2))
7062 + sizeof (FPGM(bci_deltap3))
7064 + sizeof (FPGM(bci_create_segments_composite_a))
7066 + sizeof (FPGM(bci_create_segments_composite_b))
7067 + (font->control_data_head != 0
7068 ? sizeof (FPGM(bci_create_segments_composite_c))
7069 : 0)
7070 + sizeof (FPGM(bci_create_segments_composite_d))
7072 + sizeof (FPGM(bci_create_segments_composite_0))
7073 + sizeof (FPGM(bci_create_segments_composite_1))
7074 + sizeof (FPGM(bci_create_segments_composite_2))
7075 + sizeof (FPGM(bci_create_segments_composite_3))
7076 + sizeof (FPGM(bci_create_segments_composite_4))
7077 + sizeof (FPGM(bci_create_segments_composite_5))
7078 + sizeof (FPGM(bci_create_segments_composite_6))
7079 + sizeof (FPGM(bci_create_segments_composite_7))
7080 + sizeof (FPGM(bci_create_segments_composite_8))
7081 + sizeof (FPGM(bci_create_segments_composite_9))
7083 + sizeof (FPGM(bci_align_point))
7084 + sizeof (FPGM(bci_align_segment))
7085 + sizeof (FPGM(bci_align_segments))
7087 + sizeof (FPGM(bci_scale_contour))
7088 + sizeof (FPGM(bci_scale_glyph_a))
7090 + sizeof (FPGM(bci_scale_glyph_b))
7091 + sizeof (FPGM(bci_scale_composite_glyph_a))
7093 + sizeof (FPGM(bci_scale_composite_glyph_b))
7094 + sizeof (FPGM(bci_shift_contour))
7095 + sizeof (FPGM(bci_shift_subglyph_a))
7097 + sizeof (FPGM(bci_shift_subglyph_b))
7098 + (font->control_data_head != 0
7099 ? sizeof (FPGM(bci_shift_subglyph_c))
7100 : 0)
7101 + sizeof (FPGM(bci_shift_subglyph_d))
7103 + sizeof (FPGM(bci_ip_outer_align_point))
7104 + sizeof (FPGM(bci_ip_on_align_points))
7105 + sizeof (FPGM(bci_ip_between_align_point))
7106 + sizeof (FPGM(bci_ip_between_align_points))
7108 + sizeof (FPGM(bci_adjust_common))
7109 + sizeof (FPGM(bci_stem_common))
7110 + sizeof (FPGM(bci_serif_common))
7111 + sizeof (FPGM(bci_serif_anchor_common))
7112 + sizeof (FPGM(bci_serif_link1_common))
7113 + sizeof (FPGM(bci_serif_link2_common))
7115 + sizeof (FPGM(bci_lower_bound))
7116 + sizeof (FPGM(bci_upper_bound))
7117 + sizeof (FPGM(bci_upper_lower_bound))
7119 + sizeof (FPGM(bci_adjust_bound))
7120 + sizeof (FPGM(bci_stem_bound))
7121 + sizeof (FPGM(bci_link))
7122 + sizeof (FPGM(bci_anchor))
7123 + sizeof (FPGM(bci_adjust))
7124 + sizeof (FPGM(bci_stem))
7126 + sizeof (FPGM(bci_action_ip_before))
7127 + sizeof (FPGM(bci_action_ip_after))
7128 + sizeof (FPGM(bci_action_ip_on))
7129 + sizeof (FPGM(bci_action_ip_between))
7131 + sizeof (FPGM(bci_action_blue))
7132 + sizeof (FPGM(bci_action_blue_anchor))
7134 + sizeof (FPGM(bci_action_anchor))
7135 + sizeof (FPGM(bci_action_anchor_serif))
7136 + sizeof (FPGM(bci_action_anchor_round))
7137 + sizeof (FPGM(bci_action_anchor_round_serif))
7139 + sizeof (FPGM(bci_action_adjust))
7140 + sizeof (FPGM(bci_action_adjust_serif))
7141 + sizeof (FPGM(bci_action_adjust_round))
7142 + sizeof (FPGM(bci_action_adjust_round_serif))
7143 + sizeof (FPGM(bci_action_adjust_bound))
7144 + sizeof (FPGM(bci_action_adjust_bound_serif))
7145 + sizeof (FPGM(bci_action_adjust_bound_round))
7146 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
7147 + sizeof (FPGM(bci_action_adjust_down_bound))
7148 + sizeof (FPGM(bci_action_adjust_down_bound_serif))
7149 + sizeof (FPGM(bci_action_adjust_down_bound_round))
7150 + sizeof (FPGM(bci_action_adjust_down_bound_round_serif))
7152 + sizeof (FPGM(bci_action_link))
7153 + sizeof (FPGM(bci_action_link_serif))
7154 + sizeof (FPGM(bci_action_link_round))
7155 + sizeof (FPGM(bci_action_link_round_serif))
7157 + sizeof (FPGM(bci_action_stem))
7158 + sizeof (FPGM(bci_action_stem_serif))
7159 + sizeof (FPGM(bci_action_stem_round))
7160 + sizeof (FPGM(bci_action_stem_round_serif))
7161 + sizeof (FPGM(bci_action_stem_bound))
7162 + sizeof (FPGM(bci_action_stem_bound_serif))
7163 + sizeof (FPGM(bci_action_stem_bound_round))
7164 + sizeof (FPGM(bci_action_stem_bound_round_serif))
7165 + sizeof (FPGM(bci_action_stem_down_bound))
7166 + sizeof (FPGM(bci_action_stem_down_bound_serif))
7167 + sizeof (FPGM(bci_action_stem_down_bound_round))
7168 + sizeof (FPGM(bci_action_stem_down_bound_round_serif))
7170 + sizeof (FPGM(bci_action_serif))
7171 + sizeof (FPGM(bci_action_serif_lower_bound))
7172 + sizeof (FPGM(bci_action_serif_upper_bound))
7173 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
7174 + sizeof (FPGM(bci_action_serif_down_lower_bound))
7175 + sizeof (FPGM(bci_action_serif_down_upper_bound))
7176 + sizeof (FPGM(bci_action_serif_down_upper_lower_bound))
7178 + sizeof (FPGM(bci_action_serif_anchor))
7179 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
7180 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
7181 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
7182 + sizeof (FPGM(bci_action_serif_anchor_down_lower_bound))
7183 + sizeof (FPGM(bci_action_serif_anchor_down_upper_bound))
7184 + sizeof (FPGM(bci_action_serif_anchor_down_upper_lower_bound))
7186 + sizeof (FPGM(bci_action_serif_link1))
7187 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
7188 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
7189 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
7190 + sizeof (FPGM(bci_action_serif_link1_down_lower_bound))
7191 + sizeof (FPGM(bci_action_serif_link1_down_upper_bound))
7192 + sizeof (FPGM(bci_action_serif_link1_down_upper_lower_bound))
7194 + sizeof (FPGM(bci_action_serif_link2))
7195 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
7196 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
7197 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
7198 + sizeof (FPGM(bci_action_serif_link2_down_lower_bound))
7199 + sizeof (FPGM(bci_action_serif_link2_down_upper_bound))
7200 + sizeof (FPGM(bci_action_serif_link2_down_upper_lower_bound))
7202 + sizeof (FPGM(bci_hint_glyph));
7204 /* buffer length must be a multiple of four */
7205 len = (buf_len + 3) & ~3U;
7206 buf = (FT_Byte*)malloc(len);
7207 if (!buf)
7208 return FT_Err_Out_Of_Memory;
7210 /* pad end of buffer with zeros */
7211 buf[len - 1] = 0x00;
7212 buf[len - 2] = 0x00;
7213 buf[len - 3] = 0x00;
7215 /* copy font program into buffer and fill in the missing variables */
7216 bufp = buf;
7218 COPY_FPGM(bci_align_x_height_a);
7219 if (font->increase_x_height)
7221 COPY_FPGM(bci_align_x_height_b1a);
7222 *(bufp++) = HIGH(font->increase_x_height);
7223 *(bufp++) = LOW(font->increase_x_height);
7224 COPY_FPGM(bci_align_x_height_b1b);
7226 else
7227 COPY_FPGM(bci_align_x_height_b2);
7228 COPY_FPGM(bci_align_x_height_c);
7230 COPY_FPGM(bci_round);
7231 COPY_FPGM(bci_natural_stem_width);
7232 COPY_FPGM(bci_quantize_stem_width);
7233 COPY_FPGM(bci_smooth_stem_width);
7234 COPY_FPGM(bci_get_best_width);
7235 COPY_FPGM(bci_strong_stem_width_a);
7236 *(bufp++) = num_used_styles;
7237 COPY_FPGM(bci_strong_stem_width_b);
7238 COPY_FPGM(bci_loop_do);
7239 COPY_FPGM(bci_loop);
7240 COPY_FPGM(bci_cvt_rescale);
7241 COPY_FPGM(bci_cvt_rescale_range);
7242 COPY_FPGM(bci_vwidth_data_store);
7243 COPY_FPGM(bci_smooth_blue_round);
7244 COPY_FPGM(bci_strong_blue_round);
7245 COPY_FPGM(bci_blue_round_range);
7246 COPY_FPGM(bci_decrement_component_counter);
7247 COPY_FPGM(bci_get_point_extrema);
7248 COPY_FPGM(bci_nibbles);
7249 COPY_FPGM(bci_number_set_is_element);
7250 COPY_FPGM(bci_number_set_is_element2);
7252 COPY_FPGM(bci_create_segment);
7253 COPY_FPGM(bci_create_segments_a);
7254 *(bufp++) = num_used_styles;
7255 COPY_FPGM(bci_create_segments_b);
7256 if (font->control_data_head)
7257 COPY_FPGM(bci_create_segments_c);
7258 COPY_FPGM(bci_create_segments_d);
7260 COPY_FPGM(bci_create_segments_0);
7261 COPY_FPGM(bci_create_segments_1);
7262 COPY_FPGM(bci_create_segments_2);
7263 COPY_FPGM(bci_create_segments_3);
7264 COPY_FPGM(bci_create_segments_4);
7265 COPY_FPGM(bci_create_segments_5);
7266 COPY_FPGM(bci_create_segments_6);
7267 COPY_FPGM(bci_create_segments_7);
7268 COPY_FPGM(bci_create_segments_8);
7269 COPY_FPGM(bci_create_segments_9);
7271 COPY_FPGM(bci_deltap1);
7272 COPY_FPGM(bci_deltap2);
7273 COPY_FPGM(bci_deltap3);
7275 COPY_FPGM(bci_create_segments_composite_a);
7276 *(bufp++) = num_used_styles;
7277 COPY_FPGM(bci_create_segments_composite_b);
7278 if (font->control_data_head)
7279 COPY_FPGM(bci_create_segments_composite_c);
7280 COPY_FPGM(bci_create_segments_composite_d);
7282 COPY_FPGM(bci_create_segments_composite_0);
7283 COPY_FPGM(bci_create_segments_composite_1);
7284 COPY_FPGM(bci_create_segments_composite_2);
7285 COPY_FPGM(bci_create_segments_composite_3);
7286 COPY_FPGM(bci_create_segments_composite_4);
7287 COPY_FPGM(bci_create_segments_composite_5);
7288 COPY_FPGM(bci_create_segments_composite_6);
7289 COPY_FPGM(bci_create_segments_composite_7);
7290 COPY_FPGM(bci_create_segments_composite_8);
7291 COPY_FPGM(bci_create_segments_composite_9);
7293 COPY_FPGM(bci_align_point);
7294 COPY_FPGM(bci_align_segment);
7295 COPY_FPGM(bci_align_segments);
7297 COPY_FPGM(bci_scale_contour);
7298 COPY_FPGM(bci_scale_glyph_a);
7299 *(bufp++) = fallback_style;
7300 COPY_FPGM(bci_scale_glyph_b);
7301 COPY_FPGM(bci_scale_composite_glyph_a);
7302 *(bufp++) = fallback_style;
7303 COPY_FPGM(bci_scale_composite_glyph_b);
7304 COPY_FPGM(bci_shift_contour);
7305 COPY_FPGM(bci_shift_subglyph_a);
7306 *(bufp++) = fallback_style;
7307 COPY_FPGM(bci_shift_subglyph_b);
7308 if (font->control_data_head)
7309 COPY_FPGM(bci_shift_subglyph_c);
7310 COPY_FPGM(bci_shift_subglyph_d);
7312 COPY_FPGM(bci_ip_outer_align_point);
7313 COPY_FPGM(bci_ip_on_align_points);
7314 COPY_FPGM(bci_ip_between_align_point);
7315 COPY_FPGM(bci_ip_between_align_points);
7317 COPY_FPGM(bci_adjust_common);
7318 COPY_FPGM(bci_stem_common);
7319 COPY_FPGM(bci_serif_common);
7320 COPY_FPGM(bci_serif_anchor_common);
7321 COPY_FPGM(bci_serif_link1_common);
7322 COPY_FPGM(bci_serif_link2_common);
7324 COPY_FPGM(bci_lower_bound);
7325 COPY_FPGM(bci_upper_bound);
7326 COPY_FPGM(bci_upper_lower_bound);
7328 COPY_FPGM(bci_adjust_bound);
7329 COPY_FPGM(bci_stem_bound);
7330 COPY_FPGM(bci_link);
7331 COPY_FPGM(bci_anchor);
7332 COPY_FPGM(bci_adjust);
7333 COPY_FPGM(bci_stem);
7335 COPY_FPGM(bci_action_ip_before);
7336 COPY_FPGM(bci_action_ip_after);
7337 COPY_FPGM(bci_action_ip_on);
7338 COPY_FPGM(bci_action_ip_between);
7340 COPY_FPGM(bci_action_blue);
7341 COPY_FPGM(bci_action_blue_anchor);
7343 COPY_FPGM(bci_action_anchor);
7344 COPY_FPGM(bci_action_anchor_serif);
7345 COPY_FPGM(bci_action_anchor_round);
7346 COPY_FPGM(bci_action_anchor_round_serif);
7348 COPY_FPGM(bci_action_adjust);
7349 COPY_FPGM(bci_action_adjust_serif);
7350 COPY_FPGM(bci_action_adjust_round);
7351 COPY_FPGM(bci_action_adjust_round_serif);
7352 COPY_FPGM(bci_action_adjust_bound);
7353 COPY_FPGM(bci_action_adjust_bound_serif);
7354 COPY_FPGM(bci_action_adjust_bound_round);
7355 COPY_FPGM(bci_action_adjust_bound_round_serif);
7356 COPY_FPGM(bci_action_adjust_down_bound);
7357 COPY_FPGM(bci_action_adjust_down_bound_serif);
7358 COPY_FPGM(bci_action_adjust_down_bound_round);
7359 COPY_FPGM(bci_action_adjust_down_bound_round_serif);
7361 COPY_FPGM(bci_action_link);
7362 COPY_FPGM(bci_action_link_serif);
7363 COPY_FPGM(bci_action_link_round);
7364 COPY_FPGM(bci_action_link_round_serif);
7366 COPY_FPGM(bci_action_stem);
7367 COPY_FPGM(bci_action_stem_serif);
7368 COPY_FPGM(bci_action_stem_round);
7369 COPY_FPGM(bci_action_stem_round_serif);
7370 COPY_FPGM(bci_action_stem_bound);
7371 COPY_FPGM(bci_action_stem_bound_serif);
7372 COPY_FPGM(bci_action_stem_bound_round);
7373 COPY_FPGM(bci_action_stem_bound_round_serif);
7374 COPY_FPGM(bci_action_stem_down_bound);
7375 COPY_FPGM(bci_action_stem_down_bound_serif);
7376 COPY_FPGM(bci_action_stem_down_bound_round);
7377 COPY_FPGM(bci_action_stem_down_bound_round_serif);
7379 COPY_FPGM(bci_action_serif);
7380 COPY_FPGM(bci_action_serif_lower_bound);
7381 COPY_FPGM(bci_action_serif_upper_bound);
7382 COPY_FPGM(bci_action_serif_upper_lower_bound);
7383 COPY_FPGM(bci_action_serif_down_lower_bound);
7384 COPY_FPGM(bci_action_serif_down_upper_bound);
7385 COPY_FPGM(bci_action_serif_down_upper_lower_bound);
7387 COPY_FPGM(bci_action_serif_anchor);
7388 COPY_FPGM(bci_action_serif_anchor_lower_bound);
7389 COPY_FPGM(bci_action_serif_anchor_upper_bound);
7390 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
7391 COPY_FPGM(bci_action_serif_anchor_down_lower_bound);
7392 COPY_FPGM(bci_action_serif_anchor_down_upper_bound);
7393 COPY_FPGM(bci_action_serif_anchor_down_upper_lower_bound);
7395 COPY_FPGM(bci_action_serif_link1);
7396 COPY_FPGM(bci_action_serif_link1_lower_bound);
7397 COPY_FPGM(bci_action_serif_link1_upper_bound);
7398 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
7399 COPY_FPGM(bci_action_serif_link1_down_lower_bound);
7400 COPY_FPGM(bci_action_serif_link1_down_upper_bound);
7401 COPY_FPGM(bci_action_serif_link1_down_upper_lower_bound);
7403 COPY_FPGM(bci_action_serif_link2);
7404 COPY_FPGM(bci_action_serif_link2_lower_bound);
7405 COPY_FPGM(bci_action_serif_link2_upper_bound);
7406 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
7407 COPY_FPGM(bci_action_serif_link2_down_lower_bound);
7408 COPY_FPGM(bci_action_serif_link2_down_upper_bound);
7409 COPY_FPGM(bci_action_serif_link2_down_upper_lower_bound);
7411 COPY_FPGM(bci_hint_glyph);
7413 *fpgm = buf;
7414 *fpgm_len = buf_len;
7416 return FT_Err_Ok;
7420 FT_Error
7421 TA_sfnt_build_fpgm_table(SFNT* sfnt,
7422 FONT* font)
7424 FT_Error error;
7426 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
7427 glyf_Data* data = (glyf_Data*)glyf_table->data;
7429 FT_Byte* fpgm_buf;
7430 FT_ULong fpgm_len;
7433 error = TA_sfnt_add_table_info(sfnt);
7434 if (error)
7435 goto Exit;
7437 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
7438 if (glyf_table->processed)
7440 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
7441 goto Exit;
7444 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
7445 if (error)
7446 goto Exit;
7448 if (fpgm_len > sfnt->max_instructions)
7449 sfnt->max_instructions = (FT_UShort)fpgm_len;
7451 /* in case of success, `fpgm_buf' gets linked */
7452 /* and is eventually freed in `TA_font_unload' */
7453 error = TA_font_add_table(font,
7454 &sfnt->table_infos[sfnt->num_table_infos - 1],
7455 TTAG_fpgm, fpgm_len, fpgm_buf);
7456 if (error)
7457 free(fpgm_buf);
7458 else
7459 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
7461 Exit:
7462 return error;
7465 /* end of tafpgm.c */