Add file missing in previous commit.
[ttfautohint.git] / lib / tafpgm.c
bloba30777ccbe0ca1b07476a7e9c83260c3a36d212f
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2017 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_smooth_stem_width
467 * This is the equivalent to the following code from function
468 * `ta_latin_compute_stem_width':
470 * dist = |width|
472 * if (stem_is_serif
473 * && dist < 3*64)
474 * || std_width < 40:
475 * return width
476 * else if base_is_round:
477 * if dist < 80:
478 * dist = 64
479 * else if dist < 56:
480 * dist = 56
482 * delta = |dist - std_width|
484 * if delta < 40:
485 * dist = std_width
486 * if dist < 48:
487 * dist = 48
488 * goto End
490 * if dist < 3*64:
491 * delta = dist
492 * dist = FLOOR(dist)
493 * delta = delta - dist
495 * if delta < 10:
496 * dist = dist + delta
497 * else if delta < 32:
498 * dist = dist + 10
499 * else if delta < 54:
500 * dist = dist + 54
501 * else:
502 * dist = dist + delta
503 * else:
504 * bdelta = 0
506 * if width * base_delta > 0:
507 * if ppem < 10:
508 * bdelta = base_delta
509 * else if ppem < 30:
510 * bdelta = (base_delta * (30 - ppem)) / 20
512 * bdelta = |bdelta|
514 * dist = ROUND(dist - bdelta)
516 * End:
517 * if width < 0:
518 * dist = -dist
519 * return dist
521 * If `cvtl_ignore_std_width' is set, we simply set `std_width'
522 * equal to `dist'.
524 * If `sal_have_cached_width' is set (by `bci_quantize_stem_width'), the
525 * cached value given by `sal_cached_width_offset' is directly taken, not
526 * computing the width again. Otherwise, the computed width gets stored
527 * at the given offset.
529 * in: width
530 * stem_is_serif
531 * base_is_round
533 * out: new_width
535 * sal: sal_vwidth_data_offset
536 * sal_base_delta
537 * sal_have_cached_width
538 * sal_cached_width_offset
540 * CVT: std_width
541 * cvtl_ignore_std_width
543 * uses: bci_round
544 * bci_quantize_stem_width
547 static const unsigned char FPGM(bci_smooth_stem_width) [] =
550 PUSHB_1,
551 bci_smooth_stem_width,
552 FDEF,
554 PUSHB_1,
555 bci_quantize_stem_width,
556 CALL,
558 PUSHB_1,
559 sal_have_cached_width,
562 SWAP,
563 POP,
564 SWAP,
565 POP,
567 PUSHB_1,
568 sal_cached_width_offset,
570 RS, /* cached_width = sal[sal_cached_width_offset] */
571 SWAP,
572 PUSHB_1,
574 LT, /* width < 0 */
576 NEG, /* cached_width = -cached_width */
577 EIF,
579 ELSE,
580 DUP,
581 ABS, /* s: base_is_round stem_is_serif width dist */
583 DUP,
584 PUSHB_1,
585 3*64,
586 LT, /* dist < 3*64 */
588 PUSHB_1,
590 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
591 AND, /* stem_is_serif && dist < 3*64 */
593 PUSHB_3,
596 sal_vwidth_data_offset,
598 RCVT, /* first indirection */
599 MUL, /* divide by 64 */
600 RCVT, /* second indirection */
602 PUSHB_1,
603 cvtl_ignore_std_width,
604 RCVT,
606 POP, /* s: ... dist (stem_is_serif && dist < 3*64) 40 */
607 PUSHB_1,
609 CINDEX, /* standard_width = dist */
610 EIF,
612 GT, /* standard_width < 40 */
613 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
615 IF, /* s: base_is_round width dist */
616 POP,
617 SWAP,
618 POP, /* s: width */
620 ELSE,
621 ROLL, /* s: width dist base_is_round */
622 IF, /* s: width dist */
623 DUP,
624 PUSHB_1,
626 LT, /* dist < 80 */
627 IF, /* s: width dist */
628 POP,
629 PUSHB_1,
630 64, /* dist = 64 */
631 EIF,
633 ELSE,
634 DUP,
635 PUSHB_1,
637 LT, /* dist < 56 */
638 IF, /* s: width dist */
639 POP,
640 PUSHB_1,
641 56, /* dist = 56 */
642 EIF,
643 EIF,
645 DUP, /* s: width dist dist */
646 PUSHB_2,
648 sal_vwidth_data_offset,
650 RCVT, /* first indirection */
651 MUL, /* divide by 64 */
652 RCVT, /* second indirection */
653 SUB,
654 ABS, /* s: width dist delta */
656 PUSHB_1,
658 LT, /* delta < 40 */
659 IF, /* s: width dist */
660 POP,
661 PUSHB_2,
663 sal_vwidth_data_offset,
665 RCVT, /* first indirection */
666 MUL, /* divide by 64 */
667 RCVT, /* second indirection; dist = std_width */
668 DUP,
669 PUSHB_1,
671 LT, /* dist < 48 */
673 POP,
674 PUSHB_1,
675 48, /* dist = 48 */
676 EIF,
678 ELSE,
679 DUP, /* s: width dist dist */
680 PUSHB_1,
681 3*64,
682 LT, /* dist < 3*64 */
684 DUP, /* s: width delta dist */
685 FLOOR, /* dist = FLOOR(dist) */
686 DUP, /* s: width delta dist dist */
687 ROLL,
688 ROLL, /* s: width dist delta dist */
689 SUB, /* delta = delta - dist */
691 DUP, /* s: width dist delta delta */
692 PUSHB_1,
694 LT, /* delta < 10 */
695 IF, /* s: width dist delta */
696 ADD, /* dist = dist + delta */
698 ELSE,
699 DUP,
700 PUSHB_1,
702 LT, /* delta < 32 */
704 POP,
705 PUSHB_1,
707 ADD, /* dist = dist + 10 */
709 ELSE,
710 DUP,
711 PUSHB_1,
713 LT, /* delta < 54 */
715 POP,
716 PUSHB_1,
718 ADD, /* dist = dist + 54 */
720 ELSE,
721 ADD, /* dist = dist + delta */
723 EIF,
724 EIF,
725 EIF,
727 ELSE,
728 PUSHB_1,
730 CINDEX, /* s: width dist width */
731 PUSHB_1,
732 sal_base_delta,
734 MUL, /* s: width dist width*base_delta */
735 PUSHB_1,
737 GT, /* width * base_delta > 0 */
739 PUSHB_1,
740 0, /* s: width dist bdelta */
742 MPPEM,
743 PUSHB_1,
745 LT, /* ppem < 10 */
747 POP,
748 PUSHB_1,
749 sal_base_delta,
750 RS, /* bdelta = base_delta */
752 ELSE,
753 MPPEM,
754 PUSHB_1,
756 LT, /* ppem < 30 */
758 POP,
759 PUSHB_1,
761 MPPEM,
762 SUB, /* 30 - ppem */
763 PUSHW_1,
764 0x10, /* 64 * 64 */
765 0x00,
766 MUL, /* (30 - ppem) in 26.6 format */
767 PUSHB_1,
768 sal_base_delta,
770 MUL, /* base_delta * (30 - ppem) */
771 PUSHW_1,
772 0x05, /* 20 * 64 */
773 0x00,
774 DIV, /* bdelta = (base_delta * (30 - ppem)) / 20 */
775 EIF,
776 EIF,
778 ABS, /* bdelta = |bdelta| */
779 SUB, /* dist = dist - bdelta */
780 EIF,
782 PUSHB_1,
783 bci_round,
784 CALL, /* dist = round(dist) */
786 EIF,
787 EIF,
789 SWAP, /* s: dist width */
790 PUSHB_1,
792 LT, /* width < 0 */
794 NEG, /* dist = -dist */
795 EIF,
796 EIF,
798 DUP,
799 ABS,
800 PUSHB_1,
801 sal_cached_width_offset,
803 SWAP,
804 WS, /* sal[sal_cached_width_offset] = |dist| */
805 EIF,
807 ENDF,
813 * bci_get_best_width
815 * An auxiliary function for `bci_strong_stem_width'.
817 * in: n (initialized with CVT index for first vertical width)
818 * dist
820 * out: n+1
821 * dist
823 * sal: sal_best
824 * sal_ref
826 * CVT: widths[]
829 static const unsigned char FPGM(bci_get_best_width) [] =
832 PUSHB_1,
833 bci_get_best_width,
834 FDEF,
836 DUP,
837 RCVT, /* s: dist n w */
838 DUP,
839 PUSHB_1,
841 CINDEX, /* s: dist n w w dist */
842 SUB,
843 ABS, /* s: dist n w d */
844 DUP,
845 PUSHB_1,
846 sal_best,
847 RS, /* s: dist n w d d best */
848 LT, /* d < best */
850 PUSHB_1,
851 sal_best,
852 SWAP,
853 WS, /* best = d */
854 PUSHB_1,
855 sal_ref,
856 SWAP,
857 WS, /* reference = w */
859 ELSE,
860 POP,
861 POP,
862 EIF,
864 PUSHB_1,
866 ADD, /* n = n + 1 */
868 ENDF,
874 * bci_strong_stem_width
876 * This is the equivalent to the following code (function
877 * `ta_latin_snap_width' and some lines from
878 * `ta_latin_compute_stem_width'):
880 * best = 64 + 32 + 2
881 * dist = |width|
882 * reference = dist
884 * for n in 0 .. num_widths:
885 * w = widths[n]
886 * d = |dist - w|
888 * if d < best:
889 * best = d
890 * reference = w
892 * if dist >= reference:
893 * if dist < ROUND(reference) + 48:
894 * dist = reference
895 * else:
896 * if dist > ROUND(reference) - 48:
897 * dist = reference
899 * if dist >= 64:
900 * dist = ROUND(dist)
901 * else:
902 * dist = 64
904 * if width < 0:
905 * dist = -dist
906 * return dist
908 * If `cvtl_ignore_std_width' is set, we leave `reference = width'.
910 * in: width
911 * stem_is_serif (unused)
912 * base_is_round (unused)
914 * out: new_width
916 * sal: sal_best
917 * sal_ref
918 * sal_vwidth_data_offset
920 * CVT: widths[]
921 * cvtl_ignore_std_width
923 * uses: bci_get_best_width
924 * bci_round
925 * bci_quantize_stem_width
928 static const unsigned char FPGM(bci_strong_stem_width_a) [] =
931 PUSHB_1,
932 bci_strong_stem_width,
933 FDEF,
935 SWAP,
936 POP,
937 SWAP,
938 POP,
940 PUSHB_1,
941 bci_quantize_stem_width,
942 CALL,
944 DUP,
945 ABS, /* s: width dist */
947 PUSHB_2,
948 sal_best,
949 64 + 32 + 2,
950 WS, /* sal_best = 98 */
952 DUP,
953 PUSHB_1,
954 sal_ref,
955 SWAP,
956 WS, /* sal_ref = width */
958 PUSHB_1,
959 cvtl_ignore_std_width,
960 RCVT,
962 ELSE,
964 /* s: width dist */
965 PUSHB_2,
967 sal_vwidth_data_offset,
969 RCVT,
970 MUL, /* divide by 64; first index of vertical widths */
972 /* s: width dist vw_idx */
973 PUSHB_2,
975 sal_vwidth_data_offset,
977 PUSHB_1,
981 /* %c, number of used styles */
983 static const unsigned char FPGM(bci_strong_stem_width_b) [] =
986 ADD,
987 RCVT, /* number of vertical widths */
988 MUL, /* divide by 64 */
990 /* s: width dist vw_idx loop_count */
991 PUSHB_1,
992 bci_get_best_width,
993 LOOPCALL,
994 /* clean up stack */
995 POP, /* s: width dist */
997 DUP,
998 PUSHB_1,
999 sal_ref,
1000 RS, /* s: width dist dist reference */
1001 DUP,
1002 ROLL,
1003 DUP,
1004 ROLL,
1005 PUSHB_1,
1006 bci_round,
1007 CALL, /* s: width dist reference dist dist ROUND(reference) */
1008 PUSHB_2,
1011 CINDEX, /* s: width dist reference dist dist ROUND(reference) 48 reference */
1012 PUSHB_1,
1014 MINDEX, /* s: width dist reference dist ROUND(reference) 48 reference dist */
1016 LTEQ, /* reference <= dist */
1017 IF, /* s: width dist reference dist ROUND(reference) 48 */
1018 ADD,
1019 LT, /* dist < ROUND(reference) + 48 */
1021 ELSE,
1022 SUB,
1023 GT, /* dist > ROUND(reference) - 48 */
1024 EIF,
1027 SWAP, /* s: width reference=new_dist dist */
1028 EIF,
1029 POP,
1030 EIF, /* !cvtl_ignore_std_width */
1032 DUP, /* s: width dist dist */
1033 PUSHB_1,
1035 GTEQ, /* dist >= 64 */
1037 PUSHB_1,
1038 bci_round,
1039 CALL, /* dist = ROUND(dist) */
1041 ELSE,
1042 POP,
1043 PUSHB_1,
1044 64, /* dist = 64 */
1045 EIF,
1047 SWAP, /* s: dist width */
1048 PUSHB_1,
1050 LT, /* width < 0 */
1052 NEG, /* dist = -dist */
1053 EIF,
1055 ENDF,
1061 * bci_do_loop
1063 * An auxiliary function for `bci_loop'.
1065 * sal: sal_i (gets incremented by 2 after execution)
1066 * sal_func
1068 * uses: func[sal_func]
1071 static const unsigned char FPGM(bci_loop_do) [] =
1074 PUSHB_1,
1075 bci_loop_do,
1076 FDEF,
1078 PUSHB_1,
1079 sal_func,
1081 CALL,
1083 PUSHB_3,
1084 sal_i,
1086 sal_i,
1088 ADD, /* sal_i = sal_i + 2 */
1091 ENDF,
1097 * bci_loop
1099 * Take a range `start'..`end' and a function number and apply the
1100 * associated function to the range elements `start', `start+2',
1101 * `start+4', ...
1103 * in: func_num
1104 * end
1105 * start
1107 * sal: sal_i (counter initialized with `start')
1108 * sal_func (`func_num')
1110 * uses: bci_loop_do
1113 static const unsigned char FPGM(bci_loop) [] =
1116 PUSHB_1,
1117 bci_loop,
1118 FDEF,
1120 PUSHB_1,
1121 sal_func,
1122 SWAP,
1123 WS, /* sal_func = func_num */
1125 SWAP,
1126 DUP,
1127 PUSHB_1,
1128 sal_i,
1129 SWAP,
1130 WS, /* sal_i = start */
1132 SUB,
1133 DIV_POS_BY_2,
1134 PUSHB_1,
1136 ADD, /* number of loops ((end - start) / 2 + 1) */
1138 PUSHB_1,
1139 bci_loop_do,
1140 LOOPCALL,
1142 ENDF,
1148 * bci_cvt_rescale
1150 * Rescale CVT value by `sal_scale' (in 16.16 format).
1152 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
1153 * consequently, the calculation `a * b/c' is done as `a + delta' with
1154 * `delta = a * (b-c)/c'. This avoids overflow.
1156 * in: cvt_idx
1158 * out: cvt_idx+1
1160 * sal: sal_scale
1163 static const unsigned char FPGM(bci_cvt_rescale) [] =
1166 PUSHB_1,
1167 bci_cvt_rescale,
1168 FDEF,
1170 DUP,
1171 DUP,
1172 RCVT,
1173 DO_SCALE,
1174 WCVTP,
1176 PUSHB_1,
1178 ADD,
1180 ENDF,
1186 * bci_cvt_rescale_range
1188 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
1189 * scaling value.
1191 * This function gets used in the `prep' table.
1193 * in: num_cvt
1194 * cvt_start_idx
1196 * sal: sal_i (CVT index of the style's scaling value;
1197 * gets incremented by 1 after execution)
1198 * sal_scale
1200 * uses: bci_cvt_rescale
1203 static const unsigned char FPGM(bci_cvt_rescale_range) [] =
1206 PUSHB_1,
1207 bci_cvt_rescale_range,
1208 FDEF,
1210 /* store scaling value in `sal_scale' */
1211 PUSHB_3,
1212 bci_cvt_rescale,
1213 sal_scale,
1214 sal_i,
1216 RCVT,
1217 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
1219 LOOPCALL,
1220 /* clean up stack */
1221 POP,
1223 PUSHB_3,
1224 sal_i,
1226 sal_i,
1228 ADD, /* sal_i = sal_i + 1 */
1231 ENDF,
1237 * bci_vwidth_data_store
1239 * Store a vertical width array value.
1241 * This function gets used in the `prep' table.
1243 * in: value
1245 * sal: sal_i (CVT index of the style's vwidth data;
1246 * gets incremented by 1 after execution)
1249 static const unsigned char FPGM(bci_vwidth_data_store) [] =
1252 PUSHB_1,
1253 bci_vwidth_data_store,
1254 FDEF,
1256 PUSHB_1,
1257 sal_i,
1259 SWAP,
1260 WCVTP,
1262 PUSHB_3,
1263 sal_i,
1265 sal_i,
1267 ADD, /* sal_i = sal_i + 1 */
1270 ENDF,
1276 * bci_smooth_blue_round
1278 * Round a blue ref value and adjust its corresponding shoot value.
1280 * This is the equivalent to the following code (function
1281 * `ta_latin_metrics_scale_dim'):
1283 * delta = dist
1284 * if dist < 0:
1285 * delta = -delta
1287 * if delta < 32:
1288 * delta = 0
1289 * else if delta < 48:
1290 * delta = 32
1291 * else:
1292 * delta = 64
1294 * if dist < 0:
1295 * delta = -delta
1297 * in: ref_idx
1299 * sal: sal_i (number of blue zones)
1301 * out: ref_idx+1
1303 * uses: bci_round
1306 static const unsigned char FPGM(bci_smooth_blue_round) [] =
1309 PUSHB_1,
1310 bci_smooth_blue_round,
1311 FDEF,
1313 DUP,
1314 DUP,
1315 RCVT, /* s: ref_idx ref_idx ref */
1317 DUP,
1318 PUSHB_1,
1319 bci_round,
1320 CALL,
1321 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1323 PUSHB_1,
1324 sal_i,
1326 PUSHB_1,
1328 CINDEX,
1329 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1330 DUP,
1331 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1333 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1334 SWAP,
1335 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1336 DUP,
1337 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1339 DUP,
1340 PUSHB_1,
1342 LT, /* delta < 32 */
1344 POP,
1345 PUSHB_1,
1346 0, /* delta = 0 */
1348 ELSE,
1349 PUSHB_1,
1351 LT, /* delta < 48 */
1353 PUSHB_1,
1354 32, /* delta = 32 */
1356 ELSE,
1357 PUSHB_1,
1358 64, /* delta = 64 */
1359 EIF,
1360 EIF,
1362 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1363 PUSHB_1,
1365 LT, /* dist < 0 */
1367 NEG, /* delta = -delta */
1368 EIF,
1370 PUSHB_1,
1372 CINDEX,
1373 SWAP,
1374 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1376 WCVTP,
1377 WCVTP,
1379 PUSHB_1,
1381 ADD, /* s: (ref_idx + 1) */
1383 ENDF,
1389 * bci_strong_blue_round
1391 * Round a blue ref value and adjust its corresponding shoot value.
1393 * This is the equivalent to the following code:
1395 * delta = dist
1396 * if dist < 0:
1397 * delta = -delta
1399 * if delta < 36:
1400 * delta = 0
1401 * else:
1402 * delta = 64
1404 * if dist < 0:
1405 * delta = -delta
1407 * It doesn't have corresponding code in talatin.c; however, some tests
1408 * have shown that the `smooth' code works just fine for this case also.
1410 * in: ref_idx
1412 * sal: sal_i (number of blue zones)
1414 * out: ref_idx+1
1416 * uses: bci_round
1419 static const unsigned char FPGM(bci_strong_blue_round) [] =
1422 PUSHB_1,
1423 bci_strong_blue_round,
1424 FDEF,
1426 DUP,
1427 DUP,
1428 RCVT, /* s: ref_idx ref_idx ref */
1430 DUP,
1431 PUSHB_1,
1432 bci_round,
1433 CALL,
1434 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1436 PUSHB_1,
1437 sal_i,
1439 PUSHB_1,
1441 CINDEX,
1442 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1443 DUP,
1444 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1446 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1447 SWAP,
1448 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1449 DUP,
1450 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1452 PUSHB_1,
1454 LT, /* delta < 36 */
1456 PUSHB_1,
1457 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1459 ELSE,
1460 PUSHB_1,
1461 64, /* delta = 64 (one pixel unit) */
1462 EIF,
1464 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1465 PUSHB_1,
1467 LT, /* dist < 0 */
1469 NEG, /* delta = -delta */
1470 EIF,
1472 PUSHB_1,
1474 CINDEX,
1475 SWAP,
1476 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1478 WCVTP,
1479 WCVTP,
1481 PUSHB_1,
1483 ADD, /* s: (ref_idx + 1) */
1485 ENDF,
1491 * bci_blue_round_range
1493 * Round a range of blue zones (both reference and shoot values).
1495 * This function gets used in the `prep' table.
1497 * in: num_blue_zones
1498 * blue_ref_idx
1500 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1502 * uses: bci_smooth_blue_round
1503 * bci_strong_blue_round
1506 static const unsigned char FPGM(bci_blue_round_range) [] =
1509 PUSHB_1,
1510 bci_blue_round_range,
1511 FDEF,
1513 DUP,
1514 PUSHB_1,
1515 sal_i,
1516 SWAP,
1519 /* select blue rounding function based on flag in CVT */
1520 PUSHB_3,
1521 bci_strong_blue_round,
1522 bci_smooth_blue_round,
1523 cvtl_use_strong_functions,
1524 RCVT,
1526 POP,
1528 ELSE,
1529 SWAP,
1530 POP,
1532 EIF,
1533 LOOPCALL,
1534 /* clean up stack */
1535 POP,
1537 ENDF,
1543 * bci_decrement_component_counter
1545 * An auxiliary function for composite glyphs.
1547 * CVT: cvtl_is_subglyph
1550 static const unsigned char FPGM(bci_decrement_component_counter) [] =
1553 PUSHB_1,
1554 bci_decrement_component_counter,
1555 FDEF,
1557 /* decrement `cvtl_is_subglyph' counter */
1558 PUSHB_2,
1559 cvtl_is_subglyph,
1560 cvtl_is_subglyph,
1561 RCVT,
1562 PUSHB_1,
1563 100,
1564 SUB,
1565 WCVTP,
1567 ENDF,
1573 * bci_get_point_extrema
1575 * An auxiliary function for `bci_create_segment'.
1577 * in: point-1
1579 * out: point
1581 * sal: sal_point_min
1582 * sal_point_max
1585 static const unsigned char FPGM(bci_get_point_extrema) [] =
1588 PUSHB_1,
1589 bci_get_point_extrema,
1590 FDEF,
1592 PUSHB_1,
1594 ADD, /* s: point */
1595 DUP,
1596 DUP,
1598 /* check whether `point' is a new minimum */
1599 PUSHB_1,
1600 sal_point_min,
1601 RS, /* s: point point point point_min */
1602 MD_orig,
1603 /* if distance is negative, we have a new minimum */
1604 PUSHB_1,
1607 IF, /* s: point point */
1608 DUP,
1609 PUSHB_1,
1610 sal_point_min,
1611 SWAP,
1613 EIF,
1615 /* check whether `point' is a new maximum */
1616 PUSHB_1,
1617 sal_point_max,
1618 RS, /* s: point point point_max */
1619 MD_orig,
1620 /* if distance is positive, we have a new maximum */
1621 PUSHB_1,
1624 IF, /* s: point */
1625 DUP,
1626 PUSHB_1,
1627 sal_point_max,
1628 SWAP,
1630 EIF, /* s: point */
1632 ENDF,
1638 * bci_nibbles
1640 * Pop a byte with two delta arguments in its nibbles and push the
1641 * expanded arguments separately as two bytes.
1643 * in: 16 * (end - start) + (start - base)
1645 * out: start
1646 * end
1648 * sal: sal_base (set to `end' at return)
1652 static const unsigned char FPGM(bci_nibbles) [] =
1654 PUSHB_1,
1655 bci_nibbles,
1656 FDEF,
1658 DUP,
1659 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1661 DIV,
1662 FLOOR,
1663 PUSHB_1,
1665 MUL, /* s: in hnibble */
1666 DUP,
1667 PUSHW_1,
1668 0x04, /* 16*64 */
1669 0x00,
1670 MUL, /* s: in hnibble (hnibble * 16) */
1671 ROLL,
1672 SWAP,
1673 SUB, /* s: hnibble lnibble */
1675 PUSHB_1,
1676 sal_base,
1678 ADD, /* s: hnibble start */
1679 DUP,
1680 ROLL,
1681 ADD, /* s: start end */
1683 DUP,
1684 PUSHB_1,
1685 sal_base,
1686 SWAP,
1687 WS, /* sal_base = end */
1689 SWAP,
1691 ENDF,
1697 * bci_number_set_is_element
1699 * Pop values from stack until it is empty. If one of them is equal to
1700 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1701 * otherwise).
1703 * in: ppem_value_1
1704 * ppem_value_2
1705 * ...
1707 * CVT: cvtl_is_element
1710 static const unsigned char FPGM(bci_number_set_is_element) [] =
1713 PUSHB_1,
1714 bci_number_set_is_element,
1715 FDEF,
1717 /* start_loop: */
1718 MPPEM,
1721 PUSHB_2,
1722 cvtl_is_element,
1723 100,
1724 WCVTP,
1725 EIF,
1727 DEPTH,
1728 PUSHB_1,
1730 NEG,
1731 SWAP,
1732 JROT, /* goto start_loop if stack depth != 0 */
1734 ENDF,
1740 * bci_number_set_is_element2
1742 * Pop value ranges from stack until it is empty. If one of them contains
1743 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1744 * otherwise).
1746 * in: ppem_range_1_start
1747 * ppem_range_1_end
1748 * ppem_range_2_start
1749 * ppem_range_2_end
1750 * ...
1752 * CVT: cvtl_is_element
1755 static const unsigned char FPGM(bci_number_set_is_element2) [] =
1758 PUSHB_1,
1759 bci_number_set_is_element2,
1760 FDEF,
1762 /* start_loop: */
1763 MPPEM,
1764 LTEQ,
1766 MPPEM,
1767 GTEQ,
1769 PUSHB_2,
1770 cvtl_is_element,
1771 100,
1772 WCVTP,
1773 EIF,
1774 ELSE,
1775 POP,
1776 EIF,
1778 DEPTH,
1779 PUSHB_1,
1781 NEG,
1782 SWAP,
1783 JROT, /* goto start_loop if stack depth != 0 */
1785 ENDF,
1791 * bci_create_segment
1793 * Store start and end point of a segment in the storage area,
1794 * then construct a point in the twilight zone to represent it.
1796 * This function is used by `bci_create_segments'.
1798 * in: start
1799 * end
1800 * [last (if wrap-around segment)]
1801 * [first (if wrap-around segment)]
1803 * sal: sal_i (start of current segment)
1804 * sal_j (current twilight point)
1805 * sal_point_min
1806 * sal_point_max
1807 * sal_base
1808 * sal_num_packed_segments
1809 * sal_scale
1811 * CVT: cvtl_temp
1813 * uses: bci_get_point_extrema
1814 * bci_nibbles
1816 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1817 * delta values in nibbles (without a wrap-around segment).
1820 static const unsigned char FPGM(bci_create_segment) [] =
1823 PUSHB_1,
1824 bci_create_segment,
1825 FDEF,
1827 PUSHB_2,
1829 sal_num_packed_segments,
1831 NEQ,
1833 PUSHB_2,
1834 sal_num_packed_segments,
1835 sal_num_packed_segments,
1837 PUSHB_1,
1839 SUB,
1840 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1842 PUSHB_1,
1843 bci_nibbles,
1844 CALL,
1845 EIF,
1847 PUSHB_1,
1848 sal_i,
1850 PUSHB_1,
1852 CINDEX,
1853 WS, /* sal[sal_i] = start */
1855 /* initialize inner loop(s) */
1856 PUSHB_2,
1857 sal_point_min,
1859 CINDEX,
1860 WS, /* sal_point_min = start */
1861 PUSHB_2,
1862 sal_point_max,
1864 CINDEX,
1865 WS, /* sal_point_max = start */
1867 PUSHB_1,
1869 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1871 SWAP,
1872 DUP,
1873 PUSHB_1,
1875 CINDEX, /* s: start end end start */
1876 LT, /* start > end */
1878 /* we have a wrap-around segment with two more arguments */
1879 /* to give the last and first point of the contour, respectively; */
1880 /* our job is to store a segment `start'-`last', */
1881 /* and to get extrema for the two segments */
1882 /* `start'-`last' and `first'-`end' */
1884 /* s: first last start end */
1885 PUSHB_2,
1887 sal_i,
1889 ADD,
1890 PUSHB_1,
1892 CINDEX,
1893 WS, /* sal[sal_i + 1] = last */
1895 ROLL,
1896 ROLL, /* s: first end last start */
1897 DUP,
1898 ROLL,
1899 SWAP, /* s: first end start last start */
1900 SUB, /* s: first end start loop_count */
1902 PUSHB_1,
1903 bci_get_point_extrema,
1904 LOOPCALL,
1905 /* clean up stack */
1906 POP,
1908 SWAP, /* s: end first */
1909 PUSHB_1,
1911 SUB,
1912 DUP,
1913 ROLL, /* s: (first - 1) (first - 1) end */
1914 SWAP,
1915 SUB, /* s: (first - 1) loop_count */
1917 PUSHB_1,
1918 bci_get_point_extrema,
1919 LOOPCALL,
1920 /* clean up stack */
1921 POP,
1923 ELSE, /* s: start end */
1924 PUSHB_2,
1926 sal_i,
1928 ADD,
1929 PUSHB_1,
1931 CINDEX,
1932 WS, /* sal[sal_i + 1] = end */
1934 PUSHB_1,
1936 CINDEX,
1937 SUB, /* s: start loop_count */
1939 PUSHB_1,
1940 bci_get_point_extrema,
1941 LOOPCALL,
1942 /* clean up stack */
1943 POP,
1944 EIF,
1946 /* the twilight point representing a segment */
1947 /* is in the middle between the minimum and maximum */
1948 PUSHB_1,
1949 sal_point_min,
1951 GC_orig,
1952 PUSHB_1,
1953 sal_point_max,
1955 GC_orig,
1956 ADD,
1957 DIV_BY_2, /* s: middle_pos */
1959 DO_SCALE, /* middle_pos = middle_pos * scale */
1961 /* write it to temporary CVT location */
1962 PUSHB_2,
1963 cvtl_temp,
1965 SZP0, /* set zp0 to twilight zone 0 */
1966 SWAP,
1967 WCVTP,
1969 /* create twilight point with index `sal_j' */
1970 PUSHB_1,
1971 sal_j,
1973 PUSHB_1,
1974 cvtl_temp,
1975 MIAP_noround,
1977 PUSHB_3,
1978 sal_j,
1980 sal_j,
1982 ADD, /* twilight_point = twilight_point + 1 */
1985 ENDF,
1991 * bci_create_segments
1993 * This is the top-level entry function.
1995 * It pops point ranges from the stack to define segments, computes
1996 * twilight points to represent segments, and finally calls
1997 * `bci_hint_glyph' to handle the rest.
1999 * The second argument (`data_offset') addresses three CVT arrays in
2000 * parallel:
2002 * CVT(data_offset):
2003 * the current style's scaling value (stored in `sal_scale')
2005 * data_offset + num_used_styles:
2006 * offset to the current style's vwidth index array (this value gets
2007 * stored in `sal_vwidth_data_offset')
2009 * data_offset + 2*num_used_styles:
2010 * offset to the current style's vwidth size
2012 * This addressing scheme ensures that (a) we only need a single argument,
2013 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
2014 * which should be sufficient for a long time.
2016 * in: num_packed_segments
2017 * data_offset
2018 * num_segments (N)
2019 * segment_start_0
2020 * segment_end_0
2021 * [contour_last 0 (if wrap-around segment)]
2022 * [contour_first 0 (if wrap-around segment)]
2023 * segment_start_1
2024 * segment_end_1
2025 * [contour_last 0 (if wrap-around segment)]
2026 * [contour_first 0 (if wrap-around segment)]
2027 * ...
2028 * segment_start_(N-1)
2029 * segment_end_(N-1)
2030 * [contour_last (N-1) (if wrap-around segment)]
2031 * [contour_first (N-1) (if wrap-around segment)]
2032 * ... stuff for bci_hint_glyph ...
2034 * sal: sal_i (start of current segment)
2035 * sal_j (current twilight point)
2036 * sal_num_packed_segments
2037 * sal_base (the base for delta values in nibbles)
2038 * sal_vwidth_data_offset
2039 * sal_scale
2041 * CVT: cvtl_is_subglyph
2043 * uses: bci_create_segment
2044 * bci_loop
2045 * bci_hint_glyph
2047 * If `num_packed_segments' is set to p, the first p start/end pairs are
2048 * stored as delta values in nibbles, with the `start' delta in the lower
2049 * nibble (and there are no wrap-around segments). For example, if the
2050 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
2051 * stack are 0x21, 0x32, and 0x14.
2055 static const unsigned char FPGM(bci_create_segments_a) [] =
2058 PUSHB_1,
2059 bci_create_segments,
2060 FDEF,
2062 /* all our measurements are taken along the y axis */
2063 SVTCA_y,
2065 /* only do something if we are not a subglyph */
2066 PUSHB_2,
2068 cvtl_is_subglyph,
2069 RCVT,
2072 PUSHB_1,
2073 sal_num_packed_segments,
2074 SWAP,
2077 DUP,
2078 RCVT,
2079 PUSHB_1,
2080 sal_scale, /* sal_scale = CVT(data_offset) */
2081 SWAP,
2084 PUSHB_1,
2085 sal_vwidth_data_offset,
2086 SWAP,
2087 PUSHB_1,
2091 /* %c, number of used styles */
2093 static const unsigned char FPGM(bci_create_segments_b) [] =
2096 ADD,
2097 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2099 DUP,
2100 PUSHB_1,
2101 sal_stem_width_offset,
2102 SWAP,
2103 WS, /* sal_stem_width_offset = num_segments (more to come) */
2105 DUP,
2106 ADD,
2107 PUSHB_1,
2109 SUB, /* delta = (2*num_segments - 1) */
2111 PUSHB_8,
2112 sal_segment_offset,
2113 sal_segment_offset,
2115 sal_j,
2117 sal_base,
2119 sal_num_stem_widths,
2121 WS, /* sal_num_stem_widths = 0 */
2122 WS, /* sal_base = 0 */
2123 WS, /* sal_j = 0 (point offset) */
2125 ROLL,
2126 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2128 DUP,
2129 PUSHB_1,
2130 sal_stem_width_offset,
2132 ADD,
2133 PUSHB_1,
2134 sal_stem_width_offset,
2135 SWAP,
2136 WS, /* sal_stem_width_offset += sal_segment_offset + delta */
2138 PUSHB_2,
2139 bci_create_segment,
2140 bci_loop,
2141 CALL,
2143 PUSHB_1,
2144 bci_hint_glyph,
2145 CALL,
2149 /* used if we have delta exceptions */
2151 static const unsigned char FPGM(bci_create_segments_c) [] =
2154 PUSHB_1,
2156 SZPS,
2160 static const unsigned char FPGM(bci_create_segments_d) [] =
2163 ELSE,
2164 CLEAR,
2165 EIF,
2167 ENDF,
2173 * bci_create_segments_X
2175 * Top-level routines for calling `bci_create_segments'.
2178 static const unsigned char FPGM(bci_create_segments_0) [] =
2181 PUSHB_1,
2182 bci_create_segments_0,
2183 FDEF,
2185 PUSHB_2,
2187 bci_create_segments,
2188 CALL,
2190 ENDF,
2194 static const unsigned char FPGM(bci_create_segments_1) [] =
2197 PUSHB_1,
2198 bci_create_segments_1,
2199 FDEF,
2201 PUSHB_2,
2203 bci_create_segments,
2204 CALL,
2206 ENDF,
2210 static const unsigned char FPGM(bci_create_segments_2) [] =
2213 PUSHB_1,
2214 bci_create_segments_2,
2215 FDEF,
2217 PUSHB_2,
2219 bci_create_segments,
2220 CALL,
2222 ENDF,
2226 static const unsigned char FPGM(bci_create_segments_3) [] =
2229 PUSHB_1,
2230 bci_create_segments_3,
2231 FDEF,
2233 PUSHB_2,
2235 bci_create_segments,
2236 CALL,
2238 ENDF,
2242 static const unsigned char FPGM(bci_create_segments_4) [] =
2245 PUSHB_1,
2246 bci_create_segments_4,
2247 FDEF,
2249 PUSHB_2,
2251 bci_create_segments,
2252 CALL,
2254 ENDF,
2258 static const unsigned char FPGM(bci_create_segments_5) [] =
2261 PUSHB_1,
2262 bci_create_segments_5,
2263 FDEF,
2265 PUSHB_2,
2267 bci_create_segments,
2268 CALL,
2270 ENDF,
2274 static const unsigned char FPGM(bci_create_segments_6) [] =
2277 PUSHB_1,
2278 bci_create_segments_6,
2279 FDEF,
2281 PUSHB_2,
2283 bci_create_segments,
2284 CALL,
2286 ENDF,
2290 static const unsigned char FPGM(bci_create_segments_7) [] =
2293 PUSHB_1,
2294 bci_create_segments_7,
2295 FDEF,
2297 PUSHB_2,
2299 bci_create_segments,
2300 CALL,
2302 ENDF,
2306 static const unsigned char FPGM(bci_create_segments_8) [] =
2309 PUSHB_1,
2310 bci_create_segments_8,
2311 FDEF,
2313 PUSHB_2,
2315 bci_create_segments,
2316 CALL,
2318 ENDF,
2322 static const unsigned char FPGM(bci_create_segments_9) [] =
2325 PUSHB_1,
2326 bci_create_segments_9,
2327 FDEF,
2329 PUSHB_2,
2331 bci_create_segments,
2332 CALL,
2334 ENDF,
2340 * bci_deltapX
2342 * Wrapper functions around DELTAP[123] that touch the affected points
2343 * before applying the delta. This is necessary for ClearType.
2345 * While DELTAP[123] implicitly do a loop, we have to process the
2346 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2348 * in: point
2349 * arg
2352 static const unsigned char FPGM(bci_deltap1) [] =
2355 PUSHB_1,
2356 bci_deltap1,
2357 FDEF,
2359 SWAP,
2360 DUP, /* s: point arg arg */
2361 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2363 DIV,
2364 FLOOR,
2365 PUSHB_1,
2367 MUL, /* s: point arg hnibble(arg) */
2368 PUSHB_1,
2369 CONTROL_DELTA_PPEM_MIN,
2370 ADD, /* s: point arg ppem(arg) */
2371 MPPEM,
2374 SWAP,
2375 DUP,
2376 MDAP_noround, /* touch `point' */
2378 PUSHB_1,
2380 DELTAP1, /* process one `(point,arg)' pair */
2381 ELSE,
2382 POP,
2383 POP,
2384 EIF,
2386 ENDF,
2390 static const unsigned char FPGM(bci_deltap2) [] =
2393 PUSHB_1,
2394 bci_deltap2,
2395 FDEF,
2397 SWAP,
2398 DUP, /* s: point arg arg */
2399 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2401 DIV,
2402 FLOOR,
2403 PUSHB_1,
2405 MUL, /* s: point arg hnibble(arg) */
2406 PUSHB_1,
2407 CONTROL_DELTA_PPEM_MIN + 16,
2408 ADD, /* s: point arg ppem(arg) */
2409 MPPEM,
2412 SWAP,
2413 DUP,
2414 MDAP_noround, /* touch `point' */
2416 PUSHB_1,
2418 DELTAP2, /* process one `(point,arg)' pair */
2419 ELSE,
2420 POP,
2421 POP,
2422 EIF,
2424 ENDF,
2428 static const unsigned char FPGM(bci_deltap3) [] =
2431 PUSHB_1,
2432 bci_deltap3,
2433 FDEF,
2435 SWAP,
2436 DUP, /* s: point arg arg */
2437 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
2439 DIV,
2440 FLOOR,
2441 PUSHB_1,
2443 MUL, /* s: point arg hnibble(arg) */
2444 PUSHB_1,
2445 CONTROL_DELTA_PPEM_MIN + 32,
2446 ADD, /* s: point arg ppem(arg) */
2447 MPPEM,
2450 SWAP,
2451 DUP,
2452 MDAP_noround, /* touch `point' */
2454 PUSHB_1,
2456 DELTAP3, /* process one `(point,arg)' pair */
2457 ELSE,
2458 POP,
2459 POP,
2460 EIF,
2462 ENDF,
2468 * bci_create_segments_composite
2470 * The same as `bci_create_segments'.
2471 * It also decrements the composite component counter.
2473 * sal: sal_num_packed_segments
2474 * sal_segment_offset
2475 * sal_vwidth_data_offset
2477 * CVT: cvtl_is_subglyph
2479 * uses: bci_decrement_component_counter
2480 * bci_create_segment
2481 * bci_loop
2482 * bci_hint_glyph
2485 static const unsigned char FPGM(bci_create_segments_composite_a) [] =
2488 PUSHB_1,
2489 bci_create_segments_composite,
2490 FDEF,
2492 /* all our measurements are taken along the y axis */
2493 SVTCA_y,
2495 PUSHB_1,
2496 bci_decrement_component_counter,
2497 CALL,
2499 /* only do something if we are not a subglyph */
2500 PUSHB_2,
2502 cvtl_is_subglyph,
2503 RCVT,
2506 PUSHB_1,
2507 sal_num_packed_segments,
2508 SWAP,
2511 DUP,
2512 RCVT,
2513 PUSHB_1,
2514 sal_scale, /* sal_scale = CVT(data_offset) */
2515 SWAP,
2518 PUSHB_1,
2519 sal_vwidth_data_offset,
2520 SWAP,
2521 PUSHB_1,
2525 /* %c, number of used styles */
2527 static const unsigned char FPGM(bci_create_segments_composite_b) [] =
2530 ADD,
2531 WS, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2533 DUP,
2534 ADD,
2535 PUSHB_1,
2537 SUB, /* delta = (2*num_segments - 1) */
2539 PUSHB_6,
2540 sal_segment_offset,
2541 sal_segment_offset,
2543 sal_j,
2545 sal_base,
2547 WS, /* sal_base = 0 */
2548 WS, /* sal_j = 0 (point offset) */
2550 ROLL,
2551 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2553 PUSHB_2,
2554 bci_create_segment,
2555 bci_loop,
2556 CALL,
2558 PUSHB_1,
2559 bci_hint_glyph,
2560 CALL,
2564 /* used if we have delta exceptions */
2566 static const unsigned char FPGM(bci_create_segments_composite_c) [] =
2569 PUSHB_1,
2571 SZPS,
2575 static const unsigned char FPGM(bci_create_segments_composite_d) [] =
2578 ELSE,
2579 CLEAR,
2580 EIF,
2582 ENDF,
2588 * bci_create_segments_composite_X
2590 * Top-level routines for calling `bci_create_segments_composite'.
2593 static const unsigned char FPGM(bci_create_segments_composite_0) [] =
2596 PUSHB_1,
2597 bci_create_segments_composite_0,
2598 FDEF,
2600 PUSHB_2,
2602 bci_create_segments_composite,
2603 CALL,
2605 ENDF,
2609 static const unsigned char FPGM(bci_create_segments_composite_1) [] =
2612 PUSHB_1,
2613 bci_create_segments_composite_1,
2614 FDEF,
2616 PUSHB_2,
2618 bci_create_segments_composite,
2619 CALL,
2621 ENDF,
2625 static const unsigned char FPGM(bci_create_segments_composite_2) [] =
2628 PUSHB_1,
2629 bci_create_segments_composite_2,
2630 FDEF,
2632 PUSHB_2,
2634 bci_create_segments_composite,
2635 CALL,
2637 ENDF,
2641 static const unsigned char FPGM(bci_create_segments_composite_3) [] =
2644 PUSHB_1,
2645 bci_create_segments_composite_3,
2646 FDEF,
2648 PUSHB_2,
2650 bci_create_segments_composite,
2651 CALL,
2653 ENDF,
2657 static const unsigned char FPGM(bci_create_segments_composite_4) [] =
2660 PUSHB_1,
2661 bci_create_segments_composite_4,
2662 FDEF,
2664 PUSHB_2,
2666 bci_create_segments_composite,
2667 CALL,
2669 ENDF,
2673 static const unsigned char FPGM(bci_create_segments_composite_5) [] =
2676 PUSHB_1,
2677 bci_create_segments_composite_5,
2678 FDEF,
2680 PUSHB_2,
2682 bci_create_segments_composite,
2683 CALL,
2685 ENDF,
2689 static const unsigned char FPGM(bci_create_segments_composite_6) [] =
2692 PUSHB_1,
2693 bci_create_segments_composite_6,
2694 FDEF,
2696 PUSHB_2,
2698 bci_create_segments_composite,
2699 CALL,
2701 ENDF,
2705 static const unsigned char FPGM(bci_create_segments_composite_7) [] =
2708 PUSHB_1,
2709 bci_create_segments_composite_7,
2710 FDEF,
2712 PUSHB_2,
2714 bci_create_segments_composite,
2715 CALL,
2717 ENDF,
2721 static const unsigned char FPGM(bci_create_segments_composite_8) [] =
2724 PUSHB_1,
2725 bci_create_segments_composite_8,
2726 FDEF,
2728 PUSHB_2,
2730 bci_create_segments_composite,
2731 CALL,
2733 ENDF,
2737 static const unsigned char FPGM(bci_create_segments_composite_9) [] =
2740 PUSHB_1,
2741 bci_create_segments_composite_9,
2742 FDEF,
2744 PUSHB_2,
2746 bci_create_segments_composite,
2747 CALL,
2749 ENDF,
2755 * bci_align_point
2757 * An auxiliary function for `bci_align_segment'.
2759 * in: point
2761 * out: point+1
2764 static const unsigned char FPGM(bci_align_point) [] =
2767 PUSHB_1,
2768 bci_align_point,
2769 FDEF,
2771 DUP,
2772 ALIGNRP, /* align point with rp0 */
2774 PUSHB_1,
2776 ADD,
2778 ENDF,
2784 * bci_align_segment
2786 * Align all points in a segment to the twilight point in rp0.
2787 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2789 * in: segment_index
2791 * sal: sal_segment_offset
2793 * uses: bci_align_point
2796 static const unsigned char FPGM(bci_align_segment) [] =
2799 PUSHB_1,
2800 bci_align_segment,
2801 FDEF,
2803 /* we need the values of `sal_segment_offset + 2*segment_index' */
2804 /* and `sal_segment_offset + 2*segment_index + 1' */
2805 DUP,
2806 ADD,
2807 PUSHB_1,
2808 sal_segment_offset,
2809 ADD,
2810 DUP,
2812 SWAP,
2813 PUSHB_1,
2815 ADD,
2816 RS, /* s: first last */
2818 PUSHB_1,
2820 CINDEX, /* s: first last first */
2821 SUB,
2822 PUSHB_1,
2824 ADD, /* s: first loop_count */
2826 PUSHB_1,
2827 bci_align_point,
2828 LOOPCALL,
2829 /* clean up stack */
2830 POP,
2832 ENDF,
2838 * bci_align_segments
2840 * Align segments to the twilight point in rp0.
2841 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2843 * in: first_segment
2844 * loop_counter (N)
2845 * segment_1
2846 * segment_2
2847 * ...
2848 * segment_N
2850 * uses: bci_align_segment
2853 static const unsigned char FPGM(bci_align_segments) [] =
2856 PUSHB_1,
2857 bci_align_segments,
2858 FDEF,
2860 PUSHB_1,
2861 bci_align_segment,
2862 CALL,
2864 PUSHB_1,
2865 bci_align_segment,
2866 LOOPCALL,
2868 ENDF,
2874 * bci_scale_contour
2876 * Scale a contour using two points giving the maximum and minimum
2877 * coordinates.
2879 * It expects that no point on the contour is touched.
2881 * in: min_point
2882 * max_point
2884 * sal: sal_scale
2887 static const unsigned char FPGM(bci_scale_contour) [] =
2890 PUSHB_1,
2891 bci_scale_contour,
2892 FDEF,
2894 DUP,
2895 DUP,
2896 GC_orig,
2897 DUP,
2898 DO_SCALE, /* min_pos_new = min_pos * scale */
2899 SWAP,
2900 SUB,
2901 SHPIX,
2903 /* don't scale a single-point contour twice */
2904 SWAP,
2905 DUP,
2906 ROLL,
2907 NEQ,
2909 DUP,
2910 GC_orig,
2911 DUP,
2912 DO_SCALE, /* max_pos_new = max_pos * scale */
2913 SWAP,
2914 SUB,
2915 SHPIX,
2917 ELSE,
2918 POP,
2919 EIF,
2921 ENDF,
2927 * bci_scale_glyph
2929 * Scale a glyph using a list of points (two points per contour, giving
2930 * the maximum and mininum coordinates).
2932 * It expects that no point in the glyph is touched.
2934 * Note that the point numbers are sorted in ascending order;
2935 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2936 * contour without specifying which one is the minimum and maximum.
2938 * in: num_contours (N)
2939 * min_point_1
2940 * max_point_1
2941 * min_point_2
2942 * max_point_2
2943 * ...
2944 * min_point_N
2945 * max_point_N
2947 * CVT: cvtl_is_subglyph
2948 * cvtl_do_iup_y
2950 * sal: sal_scale
2952 * uses: bci_scale_contour
2955 static const unsigned char FPGM(bci_scale_glyph_a) [] =
2958 PUSHB_1,
2959 bci_scale_glyph,
2960 FDEF,
2962 /* all our measurements are taken along the y axis */
2963 SVTCA_y,
2965 /* only do something if we are not a subglyph */
2966 PUSHB_2,
2968 cvtl_is_subglyph,
2969 RCVT,
2972 /* use fallback scaling value */
2973 PUSHB_2,
2974 sal_scale,
2978 /* %c, fallback scaling index */
2980 static const unsigned char FPGM(bci_scale_glyph_b) [] =
2983 RCVT,
2986 PUSHB_1,
2988 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2990 PUSHB_1,
2991 bci_scale_contour,
2992 LOOPCALL,
2994 PUSHB_2,
2995 cvtl_do_iup_y,
2997 SZP2, /* set zp2 to normal zone 1 */
2998 RCVT,
3000 IUP_y,
3001 EIF,
3003 ELSE,
3004 CLEAR,
3005 EIF,
3007 ENDF,
3013 * bci_scale_composite_glyph
3015 * The same as `bci_scale_glyph'.
3016 * It also decrements the composite component counter.
3018 * CVT: cvtl_is_subglyph
3019 * cvtl_do_iup_y
3021 * sal: sal_scale
3023 * uses: bci_decrement_component_counter
3024 * bci_scale_contour
3027 static const unsigned char FPGM(bci_scale_composite_glyph_a) [] =
3030 PUSHB_1,
3031 bci_scale_composite_glyph,
3032 FDEF,
3034 /* all our measurements are taken along the y axis */
3035 SVTCA_y,
3037 PUSHB_1,
3038 bci_decrement_component_counter,
3039 CALL,
3041 /* only do something if we are not a subglyph */
3042 PUSHB_2,
3044 cvtl_is_subglyph,
3045 RCVT,
3048 /* use fallback scaling value */
3049 PUSHB_2,
3050 sal_scale,
3054 /* %c, fallback scaling index */
3056 static const unsigned char FPGM(bci_scale_composite_glyph_b) [] =
3059 RCVT,
3062 PUSHB_1,
3064 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
3066 PUSHB_1,
3067 bci_scale_contour,
3068 LOOPCALL,
3070 PUSHB_2,
3071 cvtl_do_iup_y,
3073 SZP2, /* set zp2 to normal zone 1 */
3074 RCVT,
3076 IUP_y,
3077 EIF,
3079 ELSE,
3080 CLEAR,
3081 EIF,
3083 ENDF,
3089 * bci_shift_contour
3091 * Shift a contour by a given amount.
3093 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
3094 * point to the normal zone 1.
3096 * in: contour
3098 * out: contour+1
3101 static const unsigned char FPGM(bci_shift_contour) [] =
3104 PUSHB_1,
3105 bci_shift_contour,
3106 FDEF,
3108 DUP,
3109 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
3111 PUSHB_1,
3113 ADD,
3115 ENDF,
3121 * bci_shift_subglyph
3123 * Shift a subglyph. To be more specific, it corrects the already applied
3124 * subglyph offset (if any) from the `glyf' table which needs to be scaled
3125 * also.
3127 * If this function is called, a point `x' in the subglyph has been scaled
3128 * already (during the hinting of the subglyph itself), and `offset' has
3129 * been applied also:
3131 * x -> x * scale + offset (1)
3133 * However, the offset should be applied first, then the scaling:
3135 * x -> (x + offset) * scale (2)
3137 * Our job is now to transform (1) to (2); a simple calculation shows that
3138 * we have to shift all points of the subglyph by
3140 * offset * scale - offset = offset * (scale - 1)
3142 * Note that `sal_scale' is equal to the above `scale - 1'.
3144 * in: offset (in FUnits)
3145 * num_contours
3146 * first_contour
3148 * CVT: cvtl_funits_to_pixels
3150 * sal: sal_scale
3152 * uses: bci_round
3153 * bci_shift_contour
3156 static const unsigned char FPGM(bci_shift_subglyph_a) [] =
3159 PUSHB_1,
3160 bci_shift_subglyph,
3161 FDEF,
3163 /* all our measurements are taken along the y axis */
3164 SVTCA_y,
3166 /* use fallback scaling value */
3167 PUSHB_2,
3168 sal_scale,
3172 /* %c, fallback scaling index */
3174 static const unsigned char FPGM(bci_shift_subglyph_b) [] =
3177 RCVT,
3180 PUSHB_1,
3181 cvtl_funits_to_pixels,
3182 RCVT, /* scaling factor FUnits -> pixels */
3183 MUL,
3184 DIV_BY_1024,
3186 /* the autohinter always rounds offsets */
3187 PUSHB_1,
3188 bci_round,
3189 CALL, /* offset = round(offset) */
3191 PUSHB_1,
3192 sal_scale,
3194 MUL,
3195 DIV_BY_1024, /* delta = offset * (scale - 1) */
3197 /* and round again */
3198 PUSHB_1,
3199 bci_round,
3200 CALL, /* offset = round(offset) */
3202 PUSHB_1,
3204 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3206 /* we create twilight point 0 as a reference point, */
3207 /* setting the original position to zero (using `cvtl_temp') */
3208 PUSHB_5,
3211 cvtl_temp,
3212 cvtl_temp,
3214 WCVTP,
3215 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
3217 SWAP, /* s: first_contour num_contours 0 delta */
3218 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
3220 PUSHB_2,
3221 bci_shift_contour,
3223 SZP2, /* set zp2 to normal zone 1 */
3224 LOOPCALL,
3225 /* clean up stack */
3226 POP,
3230 /* used if we have delta exceptions */
3232 static const unsigned char FPGM(bci_shift_subglyph_c) [] =
3235 PUSHB_1,
3237 SZPS,
3241 static const unsigned char FPGM(bci_shift_subglyph_d) [] =
3244 ENDF,
3250 * bci_ip_outer_align_point
3252 * Auxiliary function for `bci_action_ip_before' and
3253 * `bci_action_ip_after'.
3255 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3256 * zone, and both zp1 and zp2 set to normal zone.
3258 * in: point
3260 * sal: sal_i (edge_orig_pos)
3261 * sal_scale
3264 static const unsigned char FPGM(bci_ip_outer_align_point) [] =
3267 PUSHB_1,
3268 bci_ip_outer_align_point,
3269 FDEF,
3271 DUP,
3272 ALIGNRP, /* align `point' with `edge' */
3273 DUP,
3274 GC_orig,
3275 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3277 PUSHB_1,
3278 sal_i,
3280 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3281 SHPIX,
3283 ENDF,
3289 * bci_ip_on_align_points
3291 * Auxiliary function for `bci_action_ip_on'.
3293 * in: edge (in twilight zone)
3294 * loop_counter (N)
3295 * point_1
3296 * point_2
3297 * ...
3298 * point_N
3301 static const unsigned char FPGM(bci_ip_on_align_points) [] =
3304 PUSHB_1,
3305 bci_ip_on_align_points,
3306 FDEF,
3308 MDAP_noround, /* set rp0 and rp1 to `edge' */
3310 SLOOP,
3311 ALIGNRP,
3313 ENDF,
3319 * bci_ip_between_align_point
3321 * Auxiliary function for `bci_ip_between_align_points'.
3323 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
3324 * zone, and both zp1 and zp2 set to normal zone.
3326 * in: point
3328 * sal: sal_i (edge_orig_pos)
3329 * sal_j (stretch_factor)
3330 * sal_scale
3333 static const unsigned char FPGM(bci_ip_between_align_point) [] =
3336 PUSHB_1,
3337 bci_ip_between_align_point,
3338 FDEF,
3340 DUP,
3341 ALIGNRP, /* align `point' with `edge' */
3342 DUP,
3343 GC_orig,
3344 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
3346 PUSHB_1,
3347 sal_i,
3349 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
3350 PUSHB_1,
3351 sal_j,
3353 MUL, /* s: point delta */
3354 SHPIX,
3356 ENDF,
3362 * bci_ip_between_align_points
3364 * Auxiliary function for `bci_action_ip_between'.
3366 * in: after_edge (in twilight zone)
3367 * before_edge (in twilight zone)
3368 * loop_counter (N)
3369 * point_1
3370 * point_2
3371 * ...
3372 * point_N
3374 * sal: sal_i (before_orig_pos)
3375 * sal_j (stretch_factor)
3377 * uses: bci_ip_between_align_point
3380 static const unsigned char FPGM(bci_ip_between_align_points) [] =
3383 PUSHB_1,
3384 bci_ip_between_align_points,
3385 FDEF,
3387 PUSHB_2,
3390 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3391 CINDEX,
3392 DUP, /* s: ... before after before before */
3393 MDAP_noround, /* set rp0 and rp1 to `before' */
3394 DUP,
3395 GC_orig, /* s: ... before after before before_orig_pos */
3396 PUSHB_1,
3397 sal_i,
3398 SWAP,
3399 WS, /* sal_i = before_orig_pos */
3400 PUSHB_1,
3402 CINDEX, /* s: ... before after before after */
3403 MD_cur, /* a = after_pos - before_pos */
3404 ROLL,
3405 ROLL,
3406 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
3408 DUP,
3409 IF, /* b != 0 ? */
3410 DIV, /* s: a/b */
3411 ELSE,
3412 POP, /* avoid division by zero */
3413 EIF,
3415 PUSHB_1,
3416 sal_j,
3417 SWAP,
3418 WS, /* sal_j = stretch_factor */
3420 PUSHB_3,
3421 bci_ip_between_align_point,
3424 SZP2, /* set zp2 to normal zone 1 */
3425 SZP1, /* set zp1 to normal zone 1 */
3426 LOOPCALL,
3428 ENDF,
3434 * bci_action_ip_before
3436 * Handle `ip_before' data to align points located before the first edge.
3438 * in: first_edge (in twilight zone)
3439 * loop_counter (N)
3440 * point_1
3441 * point_2
3442 * ...
3443 * point_N
3445 * sal: sal_i (first_edge_orig_pos)
3447 * uses: bci_ip_outer_align_point
3450 static const unsigned char FPGM(bci_action_ip_before) [] =
3453 PUSHB_1,
3454 bci_action_ip_before,
3455 FDEF,
3457 PUSHB_1,
3459 SZP2, /* set zp2 to twilight zone 0 */
3461 DUP,
3462 GC_orig,
3463 PUSHB_1,
3464 sal_i,
3465 SWAP,
3466 WS, /* sal_i = first_edge_orig_pos */
3468 PUSHB_3,
3472 SZP2, /* set zp2 to normal zone 1 */
3473 SZP1, /* set zp1 to normal zone 1 */
3474 SZP0, /* set zp0 to twilight zone 0 */
3476 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
3478 PUSHB_1,
3479 bci_ip_outer_align_point,
3480 LOOPCALL,
3482 ENDF,
3488 * bci_action_ip_after
3490 * Handle `ip_after' data to align points located after the last edge.
3492 * in: last_edge (in twilight zone)
3493 * loop_counter (N)
3494 * point_1
3495 * point_2
3496 * ...
3497 * point_N
3499 * sal: sal_i (last_edge_orig_pos)
3501 * uses: bci_ip_outer_align_point
3504 static const unsigned char FPGM(bci_action_ip_after) [] =
3507 PUSHB_1,
3508 bci_action_ip_after,
3509 FDEF,
3511 PUSHB_1,
3513 SZP2, /* set zp2 to twilight zone 0 */
3515 DUP,
3516 GC_orig,
3517 PUSHB_1,
3518 sal_i,
3519 SWAP,
3520 WS, /* sal_i = last_edge_orig_pos */
3522 PUSHB_3,
3526 SZP2, /* set zp2 to normal zone 1 */
3527 SZP1, /* set zp1 to normal zone 1 */
3528 SZP0, /* set zp0 to twilight zone 0 */
3530 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
3532 PUSHB_1,
3533 bci_ip_outer_align_point,
3534 LOOPCALL,
3536 ENDF,
3542 * bci_action_ip_on
3544 * Handle `ip_on' data to align points located on an edge coordinate (but
3545 * not part of an edge).
3547 * in: loop_counter (M)
3548 * edge_1 (in twilight zone)
3549 * loop_counter (N_1)
3550 * point_1
3551 * point_2
3552 * ...
3553 * point_N_1
3554 * edge_2 (in twilight zone)
3555 * loop_counter (N_2)
3556 * point_1
3557 * point_2
3558 * ...
3559 * point_N_2
3560 * ...
3561 * edge_M (in twilight zone)
3562 * loop_counter (N_M)
3563 * point_1
3564 * point_2
3565 * ...
3566 * point_N_M
3568 * uses: bci_ip_on_align_points
3571 static const unsigned char FPGM(bci_action_ip_on) [] =
3574 PUSHB_1,
3575 bci_action_ip_on,
3576 FDEF,
3578 PUSHB_2,
3581 SZP1, /* set zp1 to normal zone 1 */
3582 SZP0, /* set zp0 to twilight zone 0 */
3584 PUSHB_1,
3585 bci_ip_on_align_points,
3586 LOOPCALL,
3588 ENDF,
3594 * bci_action_ip_between
3596 * Handle `ip_between' data to align points located between two edges.
3598 * in: loop_counter (M)
3599 * before_edge_1 (in twilight zone)
3600 * after_edge_1 (in twilight zone)
3601 * loop_counter (N_1)
3602 * point_1
3603 * point_2
3604 * ...
3605 * point_N_1
3606 * before_edge_2 (in twilight zone)
3607 * after_edge_2 (in twilight zone)
3608 * loop_counter (N_2)
3609 * point_1
3610 * point_2
3611 * ...
3612 * point_N_2
3613 * ...
3614 * before_edge_M (in twilight zone)
3615 * after_edge_M (in twilight zone)
3616 * loop_counter (N_M)
3617 * point_1
3618 * point_2
3619 * ...
3620 * point_N_M
3622 * uses: bci_ip_between_align_points
3625 static const unsigned char FPGM(bci_action_ip_between) [] =
3628 PUSHB_1,
3629 bci_action_ip_between,
3630 FDEF,
3632 PUSHB_1,
3633 bci_ip_between_align_points,
3634 LOOPCALL,
3636 ENDF,
3642 * bci_adjust_common
3644 * Common code for bci_action_adjust routines.
3646 * in: top_to_bottom_hinting
3647 * edge2_is_serif
3648 * edge_is_round
3649 * edge
3650 * edge2
3652 * out: edge (adjusted)
3654 * sal: sal_top_to_bottom_hinting
3655 * sal_base_delta
3657 * uses: func[sal_stem_width_function]
3660 static const unsigned char FPGM(bci_adjust_common) [] =
3663 PUSHB_1,
3664 bci_adjust_common,
3665 FDEF,
3667 PUSHB_1,
3669 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3670 PUSHB_1,
3671 sal_top_to_bottom_hinting,
3672 SWAP,
3675 PUSHB_1,
3677 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
3678 PUSHB_1,
3680 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3681 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3683 PUSHB_2,
3684 sal_base_delta, /* no base_delta needed here */
3688 PUSHB_1,
3689 sal_stem_width_function,
3691 CALL,
3692 NEG, /* s: [...] edge2 edge -cur_len */
3694 ROLL, /* s: [...] edge -cur_len edge2 */
3695 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3696 SWAP,
3697 DUP,
3698 DUP, /* s: [...] -cur_len edge edge edge */
3699 ALIGNRP, /* align `edge' with `edge2' */
3700 ROLL,
3701 SHPIX, /* shift `edge' by -cur_len */
3703 ENDF,
3709 * bci_adjust_bound
3711 * Handle the ADJUST + BOUND actions to align an edge of a stem if the
3712 * other edge of the stem has already been moved, then moving it again if
3713 * necessary to stay bound.
3715 * in: top_to_bottom_hinting
3716 * edge2_is_serif
3717 * edge_is_round
3718 * edge_point (in twilight zone)
3719 * edge2_point (in twilight zone)
3720 * edge[-1] (in twilight zone)
3721 * ... stuff for bci_align_segments (edge) ...
3723 * sal: sal_top_to_bottom_hinting
3725 * uses: bci_adjust_common
3726 * bci_align_segments
3729 static const unsigned char FPGM(bci_adjust_bound) [] =
3732 PUSHB_1,
3733 bci_adjust_bound,
3734 FDEF,
3736 PUSHB_1,
3737 bci_adjust_common,
3738 CALL,
3740 SWAP, /* s: edge edge[-1] */
3741 DUP,
3742 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3743 GC_cur,
3744 PUSHB_1,
3746 CINDEX,
3747 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3748 PUSHB_1,
3749 sal_top_to_bottom_hinting,
3752 LT, /* edge_pos > edge[-1]_pos */
3753 ELSE,
3754 GT, /* edge_pos < edge[-1]_pos */
3755 EIF,
3757 DUP,
3758 ALIGNRP, /* align `edge' to `edge[-1]' */
3759 EIF,
3761 MDAP_noround, /* set rp0 and rp1 to `edge' */
3763 PUSHB_2,
3764 bci_align_segments,
3766 SZP1, /* set zp1 to normal zone 1 */
3767 CALL,
3769 ENDF,
3775 * bci_action_adjust_bound
3776 * bci_action_adjust_bound_serif
3777 * bci_action_adjust_bound_round
3778 * bci_action_adjust_bound_round_serif
3779 * bci_action_adjust_down_bound
3780 * bci_action_adjust_down_bound_serif
3781 * bci_action_adjust_down_bound_round
3782 * bci_action_adjust_down_bound_round_serif
3784 * Higher-level routines for calling `bci_adjust_bound'.
3787 static const unsigned char FPGM(bci_action_adjust_bound) [] =
3790 PUSHB_1,
3791 bci_action_adjust_bound,
3792 FDEF,
3794 PUSHB_4,
3798 bci_adjust_bound,
3799 CALL,
3801 ENDF,
3805 static const unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3808 PUSHB_1,
3809 bci_action_adjust_bound_serif,
3810 FDEF,
3812 PUSHB_4,
3816 bci_adjust_bound,
3817 CALL,
3819 ENDF,
3823 static const unsigned char FPGM(bci_action_adjust_bound_round) [] =
3826 PUSHB_1,
3827 bci_action_adjust_bound_round,
3828 FDEF,
3830 PUSHB_4,
3834 bci_adjust_bound,
3835 CALL,
3837 ENDF,
3841 static const unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3844 PUSHB_1,
3845 bci_action_adjust_bound_round_serif,
3846 FDEF,
3848 PUSHB_4,
3852 bci_adjust_bound,
3853 CALL,
3855 ENDF,
3859 static const unsigned char FPGM(bci_action_adjust_down_bound) [] =
3862 PUSHB_1,
3863 bci_action_adjust_down_bound,
3864 FDEF,
3866 PUSHB_4,
3870 bci_adjust_bound,
3871 CALL,
3873 ENDF,
3877 static const unsigned char FPGM(bci_action_adjust_down_bound_serif) [] =
3880 PUSHB_1,
3881 bci_action_adjust_down_bound_serif,
3882 FDEF,
3884 PUSHB_4,
3888 bci_adjust_bound,
3889 CALL,
3891 ENDF,
3895 static const unsigned char FPGM(bci_action_adjust_down_bound_round) [] =
3898 PUSHB_1,
3899 bci_action_adjust_down_bound_round,
3900 FDEF,
3902 PUSHB_4,
3906 bci_adjust_bound,
3907 CALL,
3909 ENDF,
3913 static const unsigned char FPGM(bci_action_adjust_down_bound_round_serif) [] =
3916 PUSHB_1,
3917 bci_action_adjust_down_bound_round_serif,
3918 FDEF,
3920 PUSHB_4,
3924 bci_adjust_bound,
3925 CALL,
3927 ENDF,
3933 * bci_adjust
3935 * Handle the ADJUST action to align an edge of a stem if the other edge
3936 * of the stem has already been moved.
3938 * in: edge2_is_serif
3939 * edge_is_round
3940 * edge_point (in twilight zone)
3941 * edge2_point (in twilight zone)
3942 * ... stuff for bci_align_segments (edge) ...
3944 * uses: bci_adjust_common
3945 * bci_align_segments
3948 static const unsigned char FPGM(bci_adjust) [] =
3951 PUSHB_1,
3952 bci_adjust,
3953 FDEF,
3955 PUSHB_2,
3957 bci_adjust_common,
3958 CALL,
3960 MDAP_noround, /* set rp0 and rp1 to `edge' */
3962 PUSHB_2,
3963 bci_align_segments,
3965 SZP1, /* set zp1 to normal zone 1 */
3966 CALL,
3968 ENDF,
3974 * bci_action_adjust
3975 * bci_action_adjust_serif
3976 * bci_action_adjust_round
3977 * bci_action_adjust_round_serif
3979 * Higher-level routines for calling `bci_adjust'.
3982 static const unsigned char FPGM(bci_action_adjust) [] =
3985 PUSHB_1,
3986 bci_action_adjust,
3987 FDEF,
3989 PUSHB_3,
3992 bci_adjust,
3993 CALL,
3995 ENDF,
3999 static const unsigned char FPGM(bci_action_adjust_serif) [] =
4002 PUSHB_1,
4003 bci_action_adjust_serif,
4004 FDEF,
4006 PUSHB_3,
4009 bci_adjust,
4010 CALL,
4012 ENDF,
4016 static const unsigned char FPGM(bci_action_adjust_round) [] =
4019 PUSHB_1,
4020 bci_action_adjust_round,
4021 FDEF,
4023 PUSHB_3,
4026 bci_adjust,
4027 CALL,
4029 ENDF,
4033 static const unsigned char FPGM(bci_action_adjust_round_serif) [] =
4036 PUSHB_1,
4037 bci_action_adjust_round_serif,
4038 FDEF,
4040 PUSHB_3,
4043 bci_adjust,
4044 CALL,
4046 ENDF,
4052 * bci_stem_common
4054 * Common code for bci_action_stem routines.
4056 * in: top_to_bottom_hinting
4057 * edge2_is_serif
4058 * edge_is_round
4059 * edge
4060 * edge2
4062 * out: edge
4063 * cur_len
4064 * edge2
4066 * sal: sal_anchor
4067 * sal_temp1
4068 * sal_temp2
4069 * sal_temp3
4070 * sal_top_to_bottom_hinting
4071 * sal_base_delta
4073 * uses: func[sal_stem_width_function]
4074 * bci_round
4077 #undef sal_u_off
4078 #define sal_u_off sal_temp1
4079 #undef sal_d_off
4080 #define sal_d_off sal_temp2
4081 #undef sal_org_len
4082 #define sal_org_len sal_temp3
4083 #undef sal_edge2
4084 #define sal_edge2 sal_temp3
4086 static const unsigned char FPGM(bci_stem_common) [] =
4089 PUSHB_1,
4090 bci_stem_common,
4091 FDEF,
4093 PUSHB_1,
4095 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4097 PUSHB_1,
4098 sal_top_to_bottom_hinting,
4099 SWAP,
4102 PUSHB_1,
4104 CINDEX,
4105 PUSHB_1,
4107 CINDEX,
4108 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
4109 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4111 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
4112 DUP,
4113 PUSHB_1,
4114 sal_org_len,
4115 SWAP,
4118 PUSHB_2,
4119 sal_base_delta, /* no base_delta needed here */
4123 PUSHB_1,
4124 sal_stem_width_function,
4126 CALL, /* s: [...] edge2 edge cur_len */
4128 DUP,
4129 PUSHB_1,
4131 LT, /* cur_len < 96 */
4133 DUP,
4134 PUSHB_1,
4136 LTEQ, /* cur_len <= 64 */
4138 PUSHB_4,
4139 sal_u_off,
4141 sal_d_off,
4144 ELSE,
4145 PUSHB_4,
4146 sal_u_off,
4148 sal_d_off,
4150 EIF,
4154 SWAP, /* s: [...] edge2 cur_len edge */
4155 DUP,
4156 PUSHB_1,
4157 sal_anchor,
4159 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
4160 ROLL,
4161 SWAP,
4162 MD_orig_ZP2_0,
4163 SWAP,
4164 GC_cur,
4165 ADD, /* s: [...] edge2 cur_len edge org_pos */
4166 PUSHB_1,
4167 sal_org_len,
4169 DIV_BY_2,
4170 ADD, /* s: [...] edge2 cur_len edge org_center */
4172 DUP,
4173 PUSHB_1,
4174 bci_round,
4175 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
4177 DUP,
4178 ROLL,
4179 ROLL,
4180 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
4182 DUP,
4183 PUSHB_1,
4184 sal_u_off,
4186 ADD,
4187 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
4189 SWAP,
4190 PUSHB_1,
4191 sal_d_off,
4193 SUB,
4194 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
4196 LT, /* delta1 < delta2 */
4198 PUSHB_1,
4199 sal_u_off,
4201 SUB, /* cur_pos1 = cur_pos1 - u_off */
4203 ELSE,
4204 PUSHB_1,
4205 sal_d_off,
4207 ADD, /* cur_pos1 = cur_pos1 + d_off */
4208 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
4210 PUSHB_1,
4212 CINDEX,
4213 DIV_BY_2,
4214 SUB, /* arg = cur_pos1 - cur_len/2 */
4216 SWAP, /* s: [...] edge2 cur_len arg edge */
4217 DUP,
4218 DUP,
4219 PUSHB_1,
4221 MINDEX,
4222 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4223 GC_cur,
4224 SUB,
4225 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4227 ELSE,
4228 SWAP, /* s: [...] edge2 cur_len edge */
4229 PUSHB_1,
4230 sal_anchor,
4232 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
4233 PUSHB_1,
4235 CINDEX,
4236 PUSHB_1,
4237 sal_anchor,
4239 MD_orig_ZP2_0,
4240 ADD, /* s: [...] edge2 cur_len edge org_pos */
4242 DUP,
4243 PUSHB_1,
4244 sal_org_len,
4246 DIV_BY_2,
4247 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
4249 SWAP,
4250 DUP,
4251 PUSHB_1,
4252 bci_round,
4253 CALL, /* cur_pos1 = ROUND(org_pos) */
4254 SWAP,
4255 PUSHB_1,
4256 sal_org_len,
4258 ADD,
4259 PUSHB_1,
4260 bci_round,
4261 CALL,
4262 PUSHB_1,
4264 CINDEX,
4265 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
4267 PUSHB_1,
4269 CINDEX,
4270 DIV_BY_2,
4271 PUSHB_1,
4273 MINDEX,
4274 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
4276 DUP,
4277 PUSHB_1,
4279 CINDEX,
4280 ADD,
4281 ABS, /* delta1 = |cur_pos1 + cur_len / 2 - org_center| */
4282 SWAP,
4283 PUSHB_1,
4285 CINDEX,
4286 ADD,
4287 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
4288 LT, /* delta1 < delta2 */
4290 POP, /* arg = cur_pos1 */
4292 ELSE,
4293 SWAP,
4294 POP, /* arg = cur_pos2 */
4295 EIF, /* s: [...] edge2 cur_len edge arg */
4296 SWAP,
4297 DUP,
4298 DUP,
4299 PUSHB_1,
4301 MINDEX,
4302 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
4303 GC_cur,
4304 SUB,
4305 SHPIX, /* edge = arg */
4306 EIF, /* s: [...] edge2 cur_len edge */
4308 ENDF,
4314 * bci_stem_bound
4316 * Handle the STEM action to align two edges of a stem, then moving one
4317 * edge again if necessary to stay bound.
4319 * The code after computing `cur_len' to shift `edge' and `edge2'
4320 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4322 * if cur_len < 96:
4323 * if cur_len < = 64:
4324 * u_off = 32
4325 * d_off = 32
4326 * else:
4327 * u_off = 38
4328 * d_off = 26
4330 * org_pos = anchor + (edge_orig - anchor_orig)
4331 * org_center = org_pos + org_len / 2
4333 * cur_pos1 = ROUND(org_center)
4334 * delta1 = |org_center - (cur_pos1 - u_off)|
4335 * delta2 = |org_center - (cur_pos1 + d_off)|
4336 * if (delta1 < delta2):
4337 * cur_pos1 = cur_pos1 - u_off
4338 * else:
4339 * cur_pos1 = cur_pos1 + d_off
4341 * edge = cur_pos1 - cur_len / 2
4343 * else:
4344 * org_pos = anchor + (edge_orig - anchor_orig)
4345 * org_center = org_pos + org_len / 2
4347 * cur_pos1 = ROUND(org_pos)
4348 * delta1 = |cur_pos1 + cur_len / 2 - org_center|
4349 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
4350 * delta2 = |cur_pos2 + cur_len / 2 - org_center|
4352 * if (delta1 < delta2):
4353 * edge = cur_pos1
4354 * else:
4355 * edge = cur_pos2
4357 * edge2 = edge + cur_len
4359 * in: top_to_bottom_hinting
4360 * edge2_is_serif
4361 * edge_is_round
4362 * edge_point (in twilight zone)
4363 * edge2_point (in twilight zone)
4364 * edge[-1] (in twilight zone)
4365 * ... stuff for bci_align_segments (edge) ...
4366 * ... stuff for bci_align_segments (edge2)...
4368 * sal: sal_anchor
4369 * sal_temp1
4370 * sal_temp2
4371 * sal_temp3
4372 * sal_top_to_bottom_hinting
4374 * uses: bci_stem_common
4375 * bci_align_segments
4378 static const unsigned char FPGM(bci_stem_bound) [] =
4381 PUSHB_1,
4382 bci_stem_bound,
4383 FDEF,
4385 PUSHB_1,
4386 bci_stem_common,
4387 CALL,
4389 ROLL, /* s: edge[-1] cur_len edge edge2 */
4390 DUP,
4391 DUP,
4392 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4393 PUSHB_1,
4394 sal_edge2,
4395 SWAP,
4396 WS, /* s: edge[-1] cur_len edge edge2 */
4397 ROLL,
4398 SHPIX, /* edge2 = edge + cur_len */
4400 SWAP, /* s: edge edge[-1] */
4401 DUP,
4402 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
4403 GC_cur,
4404 PUSHB_1,
4406 CINDEX,
4407 GC_cur, /* s: edge edge[-1]_pos edge_pos */
4408 PUSHB_1,
4409 sal_top_to_bottom_hinting,
4412 LT, /* edge_pos > edge[-1]_pos */
4413 ELSE,
4414 GT, /* edge_pos < edge[-1]_pos */
4415 EIF,
4417 DUP,
4418 ALIGNRP, /* align `edge' to `edge[-1]' */
4419 EIF,
4421 MDAP_noround, /* set rp0 and rp1 to `edge' */
4423 PUSHB_2,
4424 bci_align_segments,
4426 SZP1, /* set zp1 to normal zone 1 */
4427 CALL,
4429 PUSHB_1,
4430 sal_edge2,
4432 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4434 PUSHB_1,
4435 bci_align_segments,
4436 CALL,
4438 ENDF,
4444 * bci_action_stem_bound
4445 * bci_action_stem_bound_serif
4446 * bci_action_stem_bound_round
4447 * bci_action_stem_bound_round_serif
4448 * bci_action_stem_down_bound
4449 * bci_action_stem_down_bound_serif
4450 * bci_action_stem_down_bound_round
4451 * bci_action_stem_down_bound_round_serif
4453 * Higher-level routines for calling `bci_stem_bound'.
4456 static const unsigned char FPGM(bci_action_stem_bound) [] =
4459 PUSHB_1,
4460 bci_action_stem_bound,
4461 FDEF,
4463 PUSHB_4,
4467 bci_stem_bound,
4468 CALL,
4470 ENDF,
4474 static const unsigned char FPGM(bci_action_stem_bound_serif) [] =
4477 PUSHB_1,
4478 bci_action_stem_bound_serif,
4479 FDEF,
4481 PUSHB_4,
4485 bci_stem_bound,
4486 CALL,
4488 ENDF,
4492 static const unsigned char FPGM(bci_action_stem_bound_round) [] =
4495 PUSHB_1,
4496 bci_action_stem_bound_round,
4497 FDEF,
4499 PUSHB_4,
4503 bci_stem_bound,
4504 CALL,
4506 ENDF,
4510 static const unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
4513 PUSHB_1,
4514 bci_action_stem_bound_round_serif,
4515 FDEF,
4517 PUSHB_4,
4521 bci_stem_bound,
4522 CALL,
4524 ENDF,
4528 static const unsigned char FPGM(bci_action_stem_down_bound) [] =
4531 PUSHB_1,
4532 bci_action_stem_down_bound,
4533 FDEF,
4535 PUSHB_4,
4539 bci_stem_bound,
4540 CALL,
4542 ENDF,
4546 static const unsigned char FPGM(bci_action_stem_down_bound_serif) [] =
4549 PUSHB_1,
4550 bci_action_stem_down_bound_serif,
4551 FDEF,
4553 PUSHB_4,
4557 bci_stem_bound,
4558 CALL,
4560 ENDF,
4564 static const unsigned char FPGM(bci_action_stem_down_bound_round) [] =
4567 PUSHB_1,
4568 bci_action_stem_down_bound_round,
4569 FDEF,
4571 PUSHB_4,
4575 bci_stem_bound,
4576 CALL,
4578 ENDF,
4582 static const unsigned char FPGM(bci_action_stem_down_bound_round_serif) [] =
4585 PUSHB_1,
4586 bci_action_stem_down_bound_round_serif,
4587 FDEF,
4589 PUSHB_4,
4593 bci_stem_bound,
4594 CALL,
4596 ENDF,
4602 * bci_stem
4604 * Handle the STEM action to align two edges of a stem.
4606 * See `bci_stem_bound' for more details.
4608 * in: edge2_is_serif
4609 * edge_is_round
4610 * edge_point (in twilight zone)
4611 * edge2_point (in twilight zone)
4612 * ... stuff for bci_align_segments (edge) ...
4613 * ... stuff for bci_align_segments (edge2)...
4615 * sal: sal_anchor
4616 * sal_temp1
4617 * sal_temp2
4618 * sal_temp3
4620 * uses: bci_stem_common
4621 * bci_align_segments
4624 static const unsigned char FPGM(bci_stem) [] =
4627 PUSHB_1,
4628 bci_stem,
4629 FDEF,
4631 PUSHB_2,
4633 bci_stem_common,
4634 CALL,
4636 POP,
4637 SWAP, /* s: cur_len edge2 */
4638 DUP,
4639 DUP,
4640 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4641 PUSHB_1,
4642 sal_edge2,
4643 SWAP,
4644 WS, /* s: cur_len edge2 */
4645 SWAP,
4646 SHPIX, /* edge2 = edge + cur_len */
4648 PUSHB_2,
4649 bci_align_segments,
4651 SZP1, /* set zp1 to normal zone 1 */
4652 CALL,
4654 PUSHB_1,
4655 sal_edge2,
4657 MDAP_noround, /* set rp0 and rp1 to `edge2' */
4659 PUSHB_1,
4660 bci_align_segments,
4661 CALL,
4662 ENDF,
4668 * bci_action_stem
4669 * bci_action_stem_serif
4670 * bci_action_stem_round
4671 * bci_action_stem_round_serif
4673 * Higher-level routines for calling `bci_stem'.
4676 static const unsigned char FPGM(bci_action_stem) [] =
4679 PUSHB_1,
4680 bci_action_stem,
4681 FDEF,
4683 PUSHB_3,
4686 bci_stem,
4687 CALL,
4689 ENDF,
4693 static const unsigned char FPGM(bci_action_stem_serif) [] =
4696 PUSHB_1,
4697 bci_action_stem_serif,
4698 FDEF,
4700 PUSHB_3,
4703 bci_stem,
4704 CALL,
4706 ENDF,
4710 static const unsigned char FPGM(bci_action_stem_round) [] =
4713 PUSHB_1,
4714 bci_action_stem_round,
4715 FDEF,
4717 PUSHB_3,
4720 bci_stem,
4721 CALL,
4723 ENDF,
4727 static const unsigned char FPGM(bci_action_stem_round_serif) [] =
4730 PUSHB_1,
4731 bci_action_stem_round_serif,
4732 FDEF,
4734 PUSHB_3,
4737 bci_stem,
4738 CALL,
4740 ENDF,
4746 * bci_link
4748 * Handle the LINK action to link an edge to another one.
4750 * in: stem_is_serif
4751 * base_is_round
4752 * base_point (in twilight zone)
4753 * stem_point (in twilight zone)
4754 * ... stuff for bci_align_segments (base) ...
4756 * sal: sal_base_delta
4758 * uses: func[sal_stem_width_function]
4759 * bci_align_segments
4762 static const unsigned char FPGM(bci_link) [] =
4765 PUSHB_1,
4766 bci_link,
4767 FDEF,
4769 PUSHB_1,
4771 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4773 PUSHB_1,
4775 CINDEX,
4776 PUSHB_1,
4778 MINDEX,
4779 DUP, /* s: stem is_round is_serif stem base base */
4781 DUP,
4782 DUP,
4783 GC_cur,
4784 SWAP,
4785 GC_orig,
4786 SUB, /* base_delta = base_point_pos - base_point_orig_pos */
4787 PUSHB_1,
4788 sal_base_delta,
4789 SWAP,
4790 WS, /* sal_base_delta = base_delta */
4792 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4794 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
4796 PUSHB_1,
4797 sal_stem_width_function,
4799 CALL, /* s: stem new_dist */
4801 SWAP,
4802 DUP,
4803 ALIGNRP, /* align `stem_point' with `base_point' */
4804 DUP,
4805 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
4806 SWAP,
4807 SHPIX, /* stem_point = base_point + new_dist */
4809 PUSHB_2,
4810 bci_align_segments,
4812 SZP1, /* set zp1 to normal zone 1 */
4813 CALL,
4815 ENDF,
4821 * bci_action_link
4822 * bci_action_link_serif
4823 * bci_action_link_round
4824 * bci_action_link_round_serif
4826 * Higher-level routines for calling `bci_link'.
4829 static const unsigned char FPGM(bci_action_link) [] =
4832 PUSHB_1,
4833 bci_action_link,
4834 FDEF,
4836 PUSHB_3,
4839 bci_link,
4840 CALL,
4842 ENDF,
4846 static const unsigned char FPGM(bci_action_link_serif) [] =
4849 PUSHB_1,
4850 bci_action_link_serif,
4851 FDEF,
4853 PUSHB_3,
4856 bci_link,
4857 CALL,
4859 ENDF,
4863 static const unsigned char FPGM(bci_action_link_round) [] =
4866 PUSHB_1,
4867 bci_action_link_round,
4868 FDEF,
4870 PUSHB_3,
4873 bci_link,
4874 CALL,
4876 ENDF,
4880 static const unsigned char FPGM(bci_action_link_round_serif) [] =
4883 PUSHB_1,
4884 bci_action_link_round_serif,
4885 FDEF,
4887 PUSHB_3,
4890 bci_link,
4891 CALL,
4893 ENDF,
4899 * bci_anchor
4901 * Handle the ANCHOR action to align two edges
4902 * and to set the edge anchor.
4904 * The code after computing `cur_len' to shift `edge' and `edge2'
4905 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4907 * if cur_len < 96:
4908 * if cur_len < = 64:
4909 * u_off = 32
4910 * d_off = 32
4911 * else:
4912 * u_off = 38
4913 * d_off = 26
4915 * org_center = edge_orig + org_len / 2
4916 * cur_pos1 = ROUND(org_center)
4918 * error1 = |org_center - (cur_pos1 - u_off)|
4919 * error2 = |org_center - (cur_pos1 + d_off)|
4920 * if (error1 < error2):
4921 * cur_pos1 = cur_pos1 - u_off
4922 * else:
4923 * cur_pos1 = cur_pos1 + d_off
4925 * edge = cur_pos1 - cur_len / 2
4926 * edge2 = edge + cur_len
4928 * else:
4929 * edge = ROUND(edge_orig)
4931 * in: edge2_is_serif
4932 * edge_is_round
4933 * edge_point (in twilight zone)
4934 * edge2_point (in twilight zone)
4935 * ... stuff for bci_align_segments (edge) ...
4937 * sal: sal_anchor
4938 * sal_temp1
4939 * sal_temp2
4940 * sal_temp3
4941 * sal_base_delta
4943 * uses: func[sal_stem_width_function]
4944 * bci_round
4945 * bci_align_segments
4948 #undef sal_u_off
4949 #define sal_u_off sal_temp1
4950 #undef sal_d_off
4951 #define sal_d_off sal_temp2
4952 #undef sal_org_len
4953 #define sal_org_len sal_temp3
4955 static const unsigned char FPGM(bci_anchor) [] =
4958 PUSHB_1,
4959 bci_anchor,
4960 FDEF,
4962 /* store anchor point number in `sal_anchor' */
4963 PUSHB_2,
4964 sal_anchor,
4966 CINDEX,
4967 WS, /* sal_anchor = edge_point */
4969 PUSHB_1,
4971 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4973 PUSHB_1,
4975 CINDEX,
4976 PUSHB_1,
4978 CINDEX,
4979 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4980 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4982 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4983 DUP,
4984 PUSHB_1,
4985 sal_org_len,
4986 SWAP,
4989 PUSHB_2,
4990 sal_base_delta, /* no base_delta needed here */
4994 PUSHB_1,
4995 sal_stem_width_function,
4997 CALL, /* s: edge2 edge cur_len */
4999 DUP,
5000 PUSHB_1,
5002 LT, /* cur_len < 96 */
5004 DUP,
5005 PUSHB_1,
5007 LTEQ, /* cur_len <= 64 */
5009 PUSHB_4,
5010 sal_u_off,
5012 sal_d_off,
5015 ELSE,
5016 PUSHB_4,
5017 sal_u_off,
5019 sal_d_off,
5021 EIF,
5025 SWAP, /* s: edge2 cur_len edge */
5026 DUP, /* s: edge2 cur_len edge edge */
5028 GC_orig,
5029 PUSHB_1,
5030 sal_org_len,
5032 DIV_BY_2,
5033 ADD, /* s: edge2 cur_len edge org_center */
5035 DUP,
5036 PUSHB_1,
5037 bci_round,
5038 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
5040 DUP,
5041 ROLL,
5042 ROLL,
5043 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
5045 DUP,
5046 PUSHB_1,
5047 sal_u_off,
5049 ADD,
5050 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
5052 SWAP,
5053 PUSHB_1,
5054 sal_d_off,
5056 SUB,
5057 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
5059 LT, /* error1 < error2 */
5061 PUSHB_1,
5062 sal_u_off,
5064 SUB, /* cur_pos1 = cur_pos1 - u_off */
5066 ELSE,
5067 PUSHB_1,
5068 sal_d_off,
5070 ADD, /* cur_pos1 = cur_pos1 + d_off */
5071 EIF, /* s: edge2 cur_len edge cur_pos1 */
5073 PUSHB_1,
5075 CINDEX,
5076 DIV_BY_2,
5077 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
5079 PUSHB_1,
5081 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
5082 GC_cur,
5083 SUB,
5084 SHPIX, /* edge = cur_pos1 - cur_len/2 */
5086 SWAP, /* s: cur_len edge2 */
5087 DUP,
5088 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
5089 SWAP,
5090 SHPIX, /* edge2 = edge1 + cur_len */
5092 ELSE,
5093 POP, /* s: edge2 edge */
5094 DUP,
5095 DUP,
5096 GC_cur,
5097 SWAP,
5098 GC_orig,
5099 PUSHB_1,
5100 bci_round,
5101 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
5102 SWAP,
5103 SUB,
5104 SHPIX, /* edge = round(edge_orig) */
5106 /* clean up stack */
5107 POP,
5108 EIF,
5110 PUSHB_2,
5111 bci_align_segments,
5113 SZP1, /* set zp1 to normal zone 1 */
5114 CALL,
5116 ENDF,
5122 * bci_action_anchor
5123 * bci_action_anchor_serif
5124 * bci_action_anchor_round
5125 * bci_action_anchor_round_serif
5127 * Higher-level routines for calling `bci_anchor'.
5130 static const unsigned char FPGM(bci_action_anchor) [] =
5133 PUSHB_1,
5134 bci_action_anchor,
5135 FDEF,
5137 PUSHB_3,
5140 bci_anchor,
5141 CALL,
5143 ENDF,
5147 static const unsigned char FPGM(bci_action_anchor_serif) [] =
5150 PUSHB_1,
5151 bci_action_anchor_serif,
5152 FDEF,
5154 PUSHB_3,
5157 bci_anchor,
5158 CALL,
5160 ENDF,
5164 static const unsigned char FPGM(bci_action_anchor_round) [] =
5167 PUSHB_1,
5168 bci_action_anchor_round,
5169 FDEF,
5171 PUSHB_3,
5174 bci_anchor,
5175 CALL,
5177 ENDF,
5181 static const unsigned char FPGM(bci_action_anchor_round_serif) [] =
5184 PUSHB_1,
5185 bci_action_anchor_round_serif,
5186 FDEF,
5188 PUSHB_3,
5191 bci_anchor,
5192 CALL,
5194 ENDF,
5200 * bci_action_blue_anchor
5202 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
5203 * and to set the edge anchor.
5205 * in: anchor_point (in twilight zone)
5206 * blue_cvt_idx
5207 * edge_point (in twilight zone)
5208 * ... stuff for bci_align_segments (edge) ...
5210 * sal: sal_anchor
5212 * uses: bci_action_blue
5215 static const unsigned char FPGM(bci_action_blue_anchor) [] =
5218 PUSHB_1,
5219 bci_action_blue_anchor,
5220 FDEF,
5222 /* store anchor point number in `sal_anchor' */
5223 PUSHB_1,
5224 sal_anchor,
5225 SWAP,
5228 PUSHB_1,
5229 bci_action_blue,
5230 CALL,
5232 ENDF,
5238 * bci_action_blue
5240 * Handle the BLUE action to align an edge with a blue zone.
5242 * in: blue_cvt_idx
5243 * edge_point (in twilight zone)
5244 * ... stuff for bci_align_segments (edge) ...
5246 * uses: bci_align_segments
5249 static const unsigned char FPGM(bci_action_blue) [] =
5252 PUSHB_1,
5253 bci_action_blue,
5254 FDEF,
5256 PUSHB_1,
5258 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5260 /* move `edge_point' to `blue_cvt_idx' position; */
5261 /* note that we can't use MIAP since this would modify */
5262 /* the twilight point's original coordinates also */
5263 RCVT,
5264 SWAP,
5265 DUP,
5266 MDAP_noround, /* set rp0 and rp1 to `edge' */
5267 DUP,
5268 GC_cur, /* s: new_pos edge edge_pos */
5269 ROLL,
5270 SWAP,
5271 SUB, /* s: edge (new_pos - edge_pos) */
5272 SHPIX,
5274 PUSHB_2,
5275 bci_align_segments,
5277 SZP1, /* set zp1 to normal zone 1 */
5278 CALL,
5280 ENDF,
5286 * bci_serif_common
5288 * Common code for bci_action_serif routines.
5290 * in: top_to_bottom_hinting
5291 * serif
5292 * base
5294 * sal: sal_top_to_bottom_hinting
5298 static const unsigned char FPGM(bci_serif_common) [] =
5301 PUSHB_1,
5302 bci_serif_common,
5303 FDEF,
5305 PUSHB_1,
5307 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5309 PUSHB_1,
5310 sal_top_to_bottom_hinting,
5311 SWAP,
5314 DUP,
5315 DUP,
5316 DUP,
5317 PUSHB_1,
5319 MINDEX, /* s: [...] serif serif serif serif base */
5320 DUP,
5321 MDAP_noround, /* set rp0 and rp1 to `base_point' */
5322 MD_orig_ZP2_0,
5323 SWAP,
5324 ALIGNRP, /* align `serif_point' with `base_point' */
5325 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
5327 ENDF,
5333 * bci_lower_bound
5335 * Move an edge if necessary to stay within a lower bound.
5337 * in: edge
5338 * bound
5340 * sal: sal_top_to_bottom_hinting
5342 * uses: bci_align_segments
5345 static const unsigned char FPGM(bci_lower_bound) [] =
5348 PUSHB_1,
5349 bci_lower_bound,
5350 FDEF,
5352 SWAP, /* s: edge bound */
5353 DUP,
5354 MDAP_noround, /* set rp0 and rp1 to `bound' */
5355 GC_cur,
5356 PUSHB_1,
5358 CINDEX,
5359 GC_cur, /* s: edge bound_pos edge_pos */
5360 PUSHB_1,
5361 sal_top_to_bottom_hinting,
5364 LT, /* edge_pos > bound_pos */
5365 ELSE,
5366 GT, /* edge_pos < bound_pos */
5367 EIF,
5369 DUP,
5370 ALIGNRP, /* align `edge' to `bound' */
5371 EIF,
5373 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5375 PUSHB_2,
5376 bci_align_segments,
5378 SZP1, /* set zp1 to normal zone 1 */
5379 CALL,
5381 ENDF,
5387 * bci_upper_bound
5389 * Move an edge if necessary to stay within an upper bound.
5391 * in: edge
5392 * bound
5394 * sal: sal_top_to_bottom_hinting
5396 * uses: bci_align_segments
5399 static const unsigned char FPGM(bci_upper_bound) [] =
5402 PUSHB_1,
5403 bci_upper_bound,
5404 FDEF,
5406 SWAP, /* s: edge bound */
5407 DUP,
5408 MDAP_noround, /* set rp0 and rp1 to `bound' */
5409 GC_cur,
5410 PUSHB_1,
5412 CINDEX,
5413 GC_cur, /* s: edge bound_pos edge_pos */
5414 PUSHB_1,
5415 sal_top_to_bottom_hinting,
5418 GT, /* edge_pos < bound_pos */
5419 ELSE,
5420 LT, /* edge_pos > bound_pos */
5421 EIF,
5423 DUP,
5424 ALIGNRP, /* align `edge' to `bound' */
5425 EIF,
5427 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
5429 PUSHB_2,
5430 bci_align_segments,
5432 SZP1, /* set zp1 to normal zone 1 */
5433 CALL,
5435 ENDF,
5441 * bci_upper_lower_bound
5443 * Move an edge if necessary to stay within a lower and lower bound.
5445 * in: edge
5446 * lower
5447 * upper
5449 * sal: sal_top_to_bottom_hinting
5451 * uses: bci_align_segments
5454 static const unsigned char FPGM(bci_upper_lower_bound) [] =
5457 PUSHB_1,
5458 bci_upper_lower_bound,
5459 FDEF,
5461 SWAP, /* s: upper serif lower */
5462 DUP,
5463 MDAP_noround, /* set rp0 and rp1 to `lower' */
5464 GC_cur,
5465 PUSHB_1,
5467 CINDEX,
5468 GC_cur, /* s: upper serif lower_pos serif_pos */
5469 PUSHB_1,
5470 sal_top_to_bottom_hinting,
5473 LT, /* serif_pos > lower_pos */
5474 ELSE,
5475 GT, /* serif_pos < lower_pos */
5476 EIF,
5478 DUP,
5479 ALIGNRP, /* align `serif' to `lower' */
5480 EIF,
5482 SWAP, /* s: serif upper */
5483 DUP,
5484 MDAP_noround, /* set rp0 and rp1 to `upper' */
5485 GC_cur,
5486 PUSHB_1,
5488 CINDEX,
5489 GC_cur, /* s: serif upper_pos serif_pos */
5490 PUSHB_1,
5491 sal_top_to_bottom_hinting,
5494 GT, /* serif_pos < upper_pos */
5495 ELSE,
5496 LT, /* serif_pos > upper_pos */
5497 EIF,
5499 DUP,
5500 ALIGNRP, /* align `serif' to `upper' */
5501 EIF,
5503 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5505 PUSHB_2,
5506 bci_align_segments,
5508 SZP1, /* set zp1 to normal zone 1 */
5509 CALL,
5511 ENDF,
5517 * bci_action_serif
5519 * Handle the SERIF action to align a serif with its base.
5521 * in: serif_point (in twilight zone)
5522 * base_point (in twilight zone)
5523 * ... stuff for bci_align_segments (serif) ...
5525 * uses: bci_serif_common
5526 * bci_align_segments
5529 static const unsigned char FPGM(bci_action_serif) [] =
5532 PUSHB_1,
5533 bci_action_serif,
5534 FDEF,
5536 PUSHB_2,
5538 bci_serif_common,
5539 CALL,
5541 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
5543 PUSHB_2,
5544 bci_align_segments,
5546 SZP1, /* set zp1 to normal zone 1 */
5547 CALL,
5549 ENDF,
5555 * bci_action_serif_lower_bound
5557 * Handle the SERIF action to align a serif with its base, then moving it
5558 * again if necessary to stay within a lower bound.
5560 * in: serif_point (in twilight zone)
5561 * base_point (in twilight zone)
5562 * edge[-1] (in twilight zone)
5563 * ... stuff for bci_align_segments (serif) ...
5565 * uses: bci_serif_common
5566 * bci_lower_bound
5569 static const unsigned char FPGM(bci_action_serif_lower_bound) [] =
5572 PUSHB_1,
5573 bci_action_serif_lower_bound,
5574 FDEF,
5576 PUSHB_2,
5578 bci_serif_common,
5579 CALL,
5581 PUSHB_1,
5582 bci_lower_bound,
5583 CALL,
5585 ENDF,
5591 * bci_action_serif_upper_bound
5593 * Handle the SERIF action to align a serif with its base, then moving it
5594 * again if necessary to stay within an upper bound.
5596 * in: serif_point (in twilight zone)
5597 * base_point (in twilight zone)
5598 * edge[1] (in twilight zone)
5599 * ... stuff for bci_align_segments (serif) ...
5601 * uses: bci_serif_common
5602 * bci_upper_bound
5605 static const unsigned char FPGM(bci_action_serif_upper_bound) [] =
5608 PUSHB_1,
5609 bci_action_serif_upper_bound,
5610 FDEF,
5612 PUSHB_2,
5614 bci_serif_common,
5615 CALL,
5617 PUSHB_1,
5618 bci_upper_bound,
5619 CALL,
5621 ENDF,
5627 * bci_action_serif_upper_lower_bound
5629 * Handle the SERIF action to align a serif with its base, then moving it
5630 * again if necessary to stay within a lower and upper bound.
5632 * in: serif_point (in twilight zone)
5633 * base_point (in twilight zone)
5634 * edge[-1] (in twilight zone)
5635 * edge[1] (in twilight zone)
5636 * ... stuff for bci_align_segments (serif) ...
5638 * uses: bci_serif_common
5639 * bci_upper_lower_bound
5642 static const unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
5645 PUSHB_1,
5646 bci_action_serif_upper_lower_bound,
5647 FDEF,
5649 PUSHB_1,
5651 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5653 PUSHB_2,
5655 bci_serif_common,
5656 CALL,
5658 PUSHB_1,
5659 bci_upper_lower_bound,
5660 CALL,
5662 ENDF,
5668 * bci_action_serif_down_lower_bound
5670 * Handle the SERIF action to align a serif with its base, then moving it
5671 * again if necessary to stay within a lower bound. We hint top to
5672 * bottom.
5674 * in: serif_point (in twilight zone)
5675 * base_point (in twilight zone)
5676 * edge[-1] (in twilight zone)
5677 * ... stuff for bci_align_segments (serif) ...
5679 * uses: bci_serif_common
5680 * bci_lower_bound
5683 static const unsigned char FPGM(bci_action_serif_down_lower_bound) [] =
5686 PUSHB_1,
5687 bci_action_serif_down_lower_bound,
5688 FDEF,
5690 PUSHB_2,
5692 bci_serif_common,
5693 CALL,
5695 PUSHB_1,
5696 bci_lower_bound,
5697 CALL,
5699 ENDF,
5705 * bci_action_serif_down_upper_bound
5707 * Handle the SERIF action to align a serif with its base, then moving it
5708 * again if necessary to stay within an upper bound. We hint top to
5709 * bottom.
5711 * in: serif_point (in twilight zone)
5712 * base_point (in twilight zone)
5713 * edge[1] (in twilight zone)
5714 * ... stuff for bci_align_segments (serif) ...
5716 * uses: bci_serif_common
5717 * bci_upper_bound
5720 static const unsigned char FPGM(bci_action_serif_down_upper_bound) [] =
5723 PUSHB_1,
5724 bci_action_serif_down_upper_bound,
5725 FDEF,
5727 PUSHB_2,
5729 bci_serif_common,
5730 CALL,
5732 PUSHB_1,
5733 bci_upper_bound,
5734 CALL,
5736 ENDF,
5742 * bci_action_serif_down_upper_lower_bound
5744 * Handle the SERIF action to align a serif with its base, then moving it
5745 * again if necessary to stay within a lower and upper bound. We hint top
5746 * to bottom.
5748 * in: serif_point (in twilight zone)
5749 * base_point (in twilight zone)
5750 * edge[-1] (in twilight zone)
5751 * edge[1] (in twilight zone)
5752 * ... stuff for bci_align_segments (serif) ...
5754 * uses: bci_serif_common
5755 * bci_upper_lower_bound
5758 static const unsigned char FPGM(bci_action_serif_down_upper_lower_bound) [] =
5761 PUSHB_1,
5762 bci_action_serif_down_upper_lower_bound,
5763 FDEF,
5765 PUSHB_1,
5767 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5769 PUSHB_2,
5771 bci_serif_common,
5772 CALL,
5774 PUSHB_1,
5775 bci_upper_lower_bound,
5776 CALL,
5778 ENDF,
5784 * bci_serif_anchor_common
5786 * Common code for bci_action_serif_anchor routines.
5788 * in: top_to_bottom_hinting
5789 * edge
5791 * out: edge (adjusted)
5793 * sal: sal_anchor
5794 * sal_top_to_bottom_hinting
5796 * uses: bci_round
5799 static const unsigned char FPGM(bci_serif_anchor_common) [] =
5802 PUSHB_1,
5803 bci_serif_anchor_common,
5804 FDEF,
5806 PUSHB_1,
5808 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5810 PUSHB_1,
5811 sal_top_to_bottom_hinting,
5812 SWAP,
5815 DUP,
5816 PUSHB_1,
5817 sal_anchor,
5818 SWAP,
5819 WS, /* sal_anchor = edge_point */
5821 DUP,
5822 DUP,
5823 DUP,
5824 GC_cur,
5825 SWAP,
5826 GC_orig,
5827 PUSHB_1,
5828 bci_round,
5829 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
5830 SWAP,
5831 SUB,
5832 SHPIX, /* edge = round(edge_orig) */
5834 ENDF,
5840 * bci_action_serif_anchor
5842 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5843 * anchor.
5845 * in: edge_point (in twilight zone)
5846 * ... stuff for bci_align_segments (edge) ...
5848 * uses: bci_serif_anchor_common
5849 * bci_align_segments
5852 static const unsigned char FPGM(bci_action_serif_anchor) [] =
5855 PUSHB_1,
5856 bci_action_serif_anchor,
5857 FDEF,
5859 PUSHB_2,
5861 bci_serif_anchor_common,
5862 CALL,
5864 MDAP_noround, /* set rp0 and rp1 to `edge' */
5866 PUSHB_2,
5867 bci_align_segments,
5869 SZP1, /* set zp1 to normal zone 1 */
5870 CALL,
5872 ENDF,
5878 * bci_action_serif_anchor_lower_bound
5880 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5881 * anchor, then moving it again if necessary to stay within a lower
5882 * bound.
5884 * in: edge_point (in twilight zone)
5885 * edge[-1] (in twilight zone)
5886 * ... stuff for bci_align_segments (edge) ...
5888 * uses: bci_serif_anchor_common
5889 * bci_lower_bound
5892 static const unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
5895 PUSHB_1,
5896 bci_action_serif_anchor_lower_bound,
5897 FDEF,
5899 PUSHB_2,
5901 bci_serif_anchor_common,
5902 CALL,
5904 PUSHB_1,
5905 bci_lower_bound,
5906 CALL,
5908 ENDF,
5914 * bci_action_serif_anchor_upper_bound
5916 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5917 * anchor, then moving it again if necessary to stay within an upper
5918 * bound.
5920 * in: edge_point (in twilight zone)
5921 * edge[1] (in twilight zone)
5922 * ... stuff for bci_align_segments (edge) ...
5924 * uses: bci_serif_anchor_common
5925 * bci_upper_bound
5928 static const unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
5931 PUSHB_1,
5932 bci_action_serif_anchor_upper_bound,
5933 FDEF,
5935 PUSHB_2,
5937 bci_serif_anchor_common,
5938 CALL,
5940 PUSHB_1,
5941 bci_upper_bound,
5942 CALL,
5944 ENDF,
5950 * bci_action_serif_anchor_upper_lower_bound
5952 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5953 * anchor, then moving it again if necessary to stay within a lower and
5954 * upper bound.
5956 * in: edge_point (in twilight zone)
5957 * edge[-1] (in twilight zone)
5958 * edge[1] (in twilight zone)
5959 * ... stuff for bci_align_segments (edge) ...
5961 * uses: bci_serif_anchor_common
5962 * bci_upper_lower_bound
5965 static const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
5968 PUSHB_1,
5969 bci_action_serif_anchor_upper_lower_bound,
5970 FDEF,
5972 PUSHB_2,
5974 bci_serif_anchor_common,
5975 CALL,
5977 PUSHB_1,
5978 bci_upper_lower_bound,
5979 CALL,
5981 ENDF,
5987 * bci_action_serif_anchor_down_lower_bound
5989 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5990 * anchor, then moving it again if necessary to stay within a lower
5991 * bound. We hint top to bottom.
5993 * in: edge_point (in twilight zone)
5994 * edge[-1] (in twilight zone)
5995 * ... stuff for bci_align_segments (edge) ...
5997 * uses: bci_serif_anchor_common
5998 * bci_lower_bound
6001 static const unsigned char FPGM(bci_action_serif_anchor_down_lower_bound) [] =
6004 PUSHB_1,
6005 bci_action_serif_anchor_down_lower_bound,
6006 FDEF,
6008 PUSHB_2,
6010 bci_serif_anchor_common,
6011 CALL,
6013 PUSHB_1,
6014 bci_lower_bound,
6015 CALL,
6017 ENDF,
6023 * bci_action_serif_anchor_down_upper_bound
6025 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6026 * anchor, then moving it again if necessary to stay within an upper
6027 * bound. We hint top to bottom.
6029 * in: edge_point (in twilight zone)
6030 * edge[1] (in twilight zone)
6031 * ... stuff for bci_align_segments (edge) ...
6033 * uses: bci_serif_anchor_common
6034 * bci_upper_bound
6037 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_bound) [] =
6040 PUSHB_1,
6041 bci_action_serif_anchor_down_upper_bound,
6042 FDEF,
6044 PUSHB_2,
6046 bci_serif_anchor_common,
6047 CALL,
6049 PUSHB_1,
6050 bci_upper_bound,
6051 CALL,
6053 ENDF,
6059 * bci_action_serif_anchor_down_upper_lower_bound
6061 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
6062 * anchor, then moving it again if necessary to stay within a lower and
6063 * upper bound. We hint top to bottom.
6065 * in: edge_point (in twilight zone)
6066 * edge[-1] (in twilight zone)
6067 * edge[1] (in twilight zone)
6068 * ... stuff for bci_align_segments (edge) ...
6070 * uses: bci_serif_anchor_common
6071 * bci_upper_lower_bound
6074 static const unsigned char FPGM(bci_action_serif_anchor_down_upper_lower_bound) [] =
6077 PUSHB_1,
6078 bci_action_serif_anchor_down_upper_lower_bound,
6079 FDEF,
6081 PUSHB_2,
6083 bci_serif_anchor_common,
6084 CALL,
6086 PUSHB_1,
6087 bci_upper_lower_bound,
6088 CALL,
6090 ENDF,
6096 * bci_serif_link1_common
6098 * Common code for bci_action_serif_link1 routines.
6100 * in: top_to_bottom_hinting
6101 * before
6102 * edge
6103 * after
6105 * out: edge (adjusted)
6107 * sal: sal_top_to_bottom_hinting
6111 static const unsigned char FPGM(bci_serif_link1_common) [] =
6114 PUSHB_1,
6115 bci_serif_link1_common,
6116 FDEF,
6118 PUSHB_1,
6120 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6122 PUSHB_1,
6123 sal_top_to_bottom_hinting,
6124 SWAP,
6127 PUSHB_1,
6129 CINDEX, /* s: [...] after edge before after */
6130 PUSHB_1,
6132 CINDEX, /* s: [...] after edge before after before */
6133 MD_orig_ZP2_0,
6134 PUSHB_1,
6136 EQ, /* after_orig_pos == before_orig_pos */
6137 IF, /* s: [...] after edge before */
6138 MDAP_noround, /* set rp0 and rp1 to `before' */
6139 DUP,
6140 ALIGNRP, /* align `edge' with `before' */
6141 SWAP,
6142 POP,
6144 ELSE,
6145 /* we have to execute `a*b/c', with b/c very near to 1: */
6146 /* to avoid overflow while retaining precision, */
6147 /* we transform this to `a + a * (b-c)/c' */
6149 PUSHB_1,
6151 CINDEX, /* s: [...] after edge before edge */
6152 PUSHB_1,
6154 CINDEX, /* s: [...] after edge before edge before */
6155 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
6157 DUP,
6158 PUSHB_1,
6160 CINDEX, /* s: [...] after edge before a a after */
6161 PUSHB_1,
6163 CINDEX, /* s: [...] after edge before a a after before */
6164 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
6166 PUSHB_1,
6168 CINDEX, /* s: [...] after edge before a a c after */
6169 PUSHB_1,
6171 CINDEX, /* s: [...] after edge before a a c after before */
6172 MD_cur, /* b = after_pos - before_pos */
6174 PUSHB_1,
6176 CINDEX, /* s: [...] after edge before a a c b c */
6177 SUB, /* b-c */
6179 PUSHW_2,
6180 0x08, /* 0x800 */
6181 0x00,
6182 0x08, /* 0x800 */
6183 0x00,
6184 MUL, /* 0x10000 */
6185 MUL, /* (b-c) in 16.16 format */
6186 SWAP,
6188 DUP,
6189 IF, /* c != 0 ? */
6190 DIV, /* s: [...] after edge before a a (b-c)/c */
6191 ELSE,
6192 POP, /* avoid division by zero */
6193 EIF,
6195 MUL, /* a * (b-c)/c * 2^10 */
6196 DIV_BY_1024, /* a * (b-c)/c */
6197 ADD, /* a*b/c */
6199 SWAP,
6200 MDAP_noround, /* set rp0 and rp1 to `before' */
6201 SWAP, /* s: [...] after a*b/c edge */
6202 DUP,
6203 DUP,
6204 ALIGNRP, /* align `edge' with `before' */
6205 ROLL,
6206 SHPIX, /* shift `edge' by `a*b/c' */
6208 SWAP, /* s: [...] edge after */
6209 POP,
6210 EIF,
6212 ENDF,
6218 * bci_action_serif_link1
6220 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6221 * before and after.
6223 * in: before_point (in twilight zone)
6224 * edge_point (in twilight zone)
6225 * after_point (in twilight zone)
6226 * ... stuff for bci_align_segments (edge) ...
6228 * uses: bci_serif_link1_common
6229 * bci_align_segments
6232 static const unsigned char FPGM(bci_action_serif_link1) [] =
6235 PUSHB_1,
6236 bci_action_serif_link1,
6237 FDEF,
6239 PUSHB_2,
6241 bci_serif_link1_common,
6242 CALL,
6244 MDAP_noround, /* set rp0 and rp1 to `edge' */
6246 PUSHB_2,
6247 bci_align_segments,
6249 SZP1, /* set zp1 to normal zone 1 */
6250 CALL,
6252 ENDF,
6258 * bci_action_serif_link1_lower_bound
6260 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6261 * before and after. Additionally, move the serif again if necessary to
6262 * stay within a lower bound.
6264 * in: before_point (in twilight zone)
6265 * edge_point (in twilight zone)
6266 * after_point (in twilight zone)
6267 * edge[-1] (in twilight zone)
6268 * ... stuff for bci_align_segments (edge) ...
6270 * uses: bci_serif_link1_common
6271 * bci_lower_bound
6274 static const unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
6277 PUSHB_1,
6278 bci_action_serif_link1_lower_bound,
6279 FDEF,
6281 PUSHB_2,
6283 bci_serif_link1_common,
6284 CALL,
6286 PUSHB_1,
6287 bci_lower_bound,
6288 CALL,
6290 ENDF,
6296 * bci_action_serif_link1_upper_bound
6298 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6299 * before and after. Additionally, move the serif again if necessary to
6300 * stay within an upper bound.
6302 * in: before_point (in twilight zone)
6303 * edge_point (in twilight zone)
6304 * after_point (in twilight zone)
6305 * edge[1] (in twilight zone)
6306 * ... stuff for bci_align_segments (edge) ...
6308 * uses: bci_serif_link1_common
6309 * bci_upper_bound
6312 static const unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
6315 PUSHB_1,
6316 bci_action_serif_link1_upper_bound,
6317 FDEF,
6319 PUSHB_2,
6321 bci_serif_link1_common,
6322 CALL,
6324 PUSHB_1,
6325 bci_upper_bound,
6326 CALL,
6328 ENDF,
6334 * bci_action_serif_link1_upper_lower_bound
6336 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6337 * before and after. Additionally, move the serif again if necessary to
6338 * stay within a lower and upper bound.
6340 * in: before_point (in twilight zone)
6341 * edge_point (in twilight zone)
6342 * after_point (in twilight zone)
6343 * edge[-1] (in twilight zone)
6344 * edge[1] (in twilight zone)
6345 * ... stuff for bci_align_segments (edge) ...
6347 * uses: bci_serif_link1_common
6348 * bci_upper_lower_bound
6351 static const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
6354 PUSHB_1,
6355 bci_action_serif_link1_upper_lower_bound,
6356 FDEF,
6358 PUSHB_2,
6360 bci_serif_link1_common,
6361 CALL,
6363 PUSHB_1,
6364 bci_upper_lower_bound,
6365 CALL,
6367 ENDF,
6373 * bci_action_serif_link1_down_lower_bound
6375 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6376 * before and after. Additionally, move the serif again if necessary to
6377 * stay within a lower bound. We hint top to bottom.
6379 * in: before_point (in twilight zone)
6380 * edge_point (in twilight zone)
6381 * after_point (in twilight zone)
6382 * edge[-1] (in twilight zone)
6383 * ... stuff for bci_align_segments (edge) ...
6385 * uses: bci_serif_link1_common
6386 * bci_lower_bound
6389 static const unsigned char FPGM(bci_action_serif_link1_down_lower_bound) [] =
6392 PUSHB_1,
6393 bci_action_serif_link1_down_lower_bound,
6394 FDEF,
6396 PUSHB_2,
6398 bci_serif_link1_common,
6399 CALL,
6401 PUSHB_1,
6402 bci_lower_bound,
6403 CALL,
6405 ENDF,
6411 * bci_action_serif_link1_down_upper_bound
6413 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6414 * before and after. Additionally, move the serif again if necessary to
6415 * stay within an upper bound. We hint top to bottom.
6417 * in: before_point (in twilight zone)
6418 * edge_point (in twilight zone)
6419 * after_point (in twilight zone)
6420 * edge[1] (in twilight zone)
6421 * ... stuff for bci_align_segments (edge) ...
6423 * uses: bci_serif_link1_common
6424 * bci_upper_bound
6427 static const unsigned char FPGM(bci_action_serif_link1_down_upper_bound) [] =
6430 PUSHB_1,
6431 bci_action_serif_link1_down_upper_bound,
6432 FDEF,
6434 PUSHB_2,
6436 bci_serif_link1_common,
6437 CALL,
6439 PUSHB_1,
6440 bci_upper_bound,
6441 CALL,
6443 ENDF,
6449 * bci_action_serif_link1_down_upper_lower_bound
6451 * Handle the SERIF_LINK1 action to align a serif, depending on edges
6452 * before and after. Additionally, move the serif again if necessary to
6453 * stay within a lower and upper bound. We hint top to bottom.
6455 * in: before_point (in twilight zone)
6456 * edge_point (in twilight zone)
6457 * after_point (in twilight zone)
6458 * edge[-1] (in twilight zone)
6459 * edge[1] (in twilight zone)
6460 * ... stuff for bci_align_segments (edge) ...
6462 * uses: bci_serif_link1_common
6463 * bci_upper_lower_bound
6466 static const unsigned char FPGM(bci_action_serif_link1_down_upper_lower_bound) [] =
6469 PUSHB_1,
6470 bci_action_serif_link1_down_upper_lower_bound,
6471 FDEF,
6473 PUSHB_2,
6475 bci_serif_link1_common,
6476 CALL,
6478 PUSHB_1,
6479 bci_upper_lower_bound,
6480 CALL,
6482 ENDF,
6488 * bci_serif_link2_common
6490 * Common code for bci_action_serif_link2 routines.
6492 * in: top_to_bottom_hinting
6493 * edge
6495 * out: edge (adjusted)
6497 * sal: sal_anchor
6498 * sal_top_to_bottom_hinting
6502 static const unsigned char FPGM(bci_serif_link2_common) [] =
6505 PUSHB_1,
6506 bci_serif_link2_common,
6507 FDEF,
6509 PUSHB_1,
6511 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
6513 PUSHB_1,
6514 sal_top_to_bottom_hinting,
6515 SWAP,
6518 DUP, /* s: [...] edge edge */
6519 PUSHB_1,
6520 sal_anchor,
6522 DUP, /* s: [...] edge edge anchor anchor */
6523 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
6525 MD_orig_ZP2_0,
6526 DUP,
6527 ADD,
6528 PUSHB_1,
6530 ADD,
6531 FLOOR,
6532 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
6534 SWAP,
6535 DUP,
6536 DUP,
6537 ALIGNRP, /* align `edge' with `sal_anchor' */
6538 ROLL,
6539 SHPIX, /* shift `edge' by `delta' */
6541 ENDF,
6547 * bci_action_serif_link2
6549 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6551 * in: edge_point (in twilight zone)
6552 * ... stuff for bci_align_segments (edge) ...
6554 * uses: bci_serif_link2_common
6555 * bci_align_segments
6558 static const unsigned char FPGM(bci_action_serif_link2) [] =
6561 PUSHB_1,
6562 bci_action_serif_link2,
6563 FDEF,
6565 PUSHB_2,
6567 bci_serif_link2_common,
6568 CALL,
6570 MDAP_noround, /* set rp0 and rp1 to `edge' */
6572 PUSHB_2,
6573 bci_align_segments,
6575 SZP1, /* set zp1 to normal zone 1 */
6576 CALL,
6578 ENDF,
6584 * bci_action_serif_link2_lower_bound
6586 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6587 * Additionally, move the serif again if necessary to stay within a lower
6588 * bound.
6590 * in: edge_point (in twilight zone)
6591 * edge[-1] (in twilight zone)
6592 * ... stuff for bci_align_segments (edge) ...
6594 * uses: bci_serif_link2_common
6595 * bci_lower_bound
6598 static const unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
6601 PUSHB_1,
6602 bci_action_serif_link2_lower_bound,
6603 FDEF,
6605 PUSHB_2,
6607 bci_serif_link2_common,
6608 CALL,
6610 PUSHB_1,
6611 bci_lower_bound,
6612 CALL,
6614 ENDF,
6620 * bci_action_serif_link2_upper_bound
6622 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6623 * Additionally, move the serif again if necessary to stay within an upper
6624 * bound.
6626 * in: edge_point (in twilight zone)
6627 * edge[1] (in twilight zone)
6628 * ... stuff for bci_align_segments (edge) ...
6630 * uses: bci_serif_link2_common
6631 * bci_upper_bound
6634 static const unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
6637 PUSHB_1,
6638 bci_action_serif_link2_upper_bound,
6639 FDEF,
6641 PUSHB_2,
6643 bci_serif_link2_common,
6644 CALL,
6646 PUSHB_1,
6647 bci_upper_bound,
6648 CALL,
6650 ENDF,
6656 * bci_action_serif_link2_upper_lower_bound
6658 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6659 * Additionally, move the serif again if necessary to stay within a lower
6660 * and upper bound.
6662 * in: edge_point (in twilight zone)
6663 * edge[-1] (in twilight zone)
6664 * edge[1] (in twilight zone)
6665 * ... stuff for bci_align_segments (edge) ...
6667 * uses: bci_serif_link2_common
6668 * bci_upper_lower_bound
6671 static const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
6674 PUSHB_1,
6675 bci_action_serif_link2_upper_lower_bound,
6676 FDEF,
6678 PUSHB_2,
6680 bci_serif_link2_common,
6681 CALL,
6683 PUSHB_1,
6684 bci_upper_lower_bound,
6685 CALL,
6687 ENDF,
6693 * bci_action_serif_link2_down_lower_bound
6695 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6696 * Additionally, move the serif again if necessary to stay within a lower
6697 * bound. We hint top to bottom.
6699 * in: edge_point (in twilight zone)
6700 * edge[-1] (in twilight zone)
6701 * ... stuff for bci_align_segments (edge) ...
6703 * uses: bci_serif_link2_common
6704 * bci_lower_bound
6707 static const unsigned char FPGM(bci_action_serif_link2_down_lower_bound) [] =
6710 PUSHB_1,
6711 bci_action_serif_link2_down_lower_bound,
6712 FDEF,
6714 PUSHB_2,
6716 bci_serif_link2_common,
6717 CALL,
6719 PUSHB_1,
6720 bci_lower_bound,
6721 CALL,
6723 ENDF,
6729 * bci_action_serif_link2_down_upper_bound
6731 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6732 * Additionally, move the serif again if necessary to stay within an upper
6733 * bound. We hint top to bottom.
6735 * in: edge_point (in twilight zone)
6736 * edge[1] (in twilight zone)
6737 * ... stuff for bci_align_segments (edge) ...
6739 * uses: bci_serif_link2_common
6740 * bci_upper_bound
6743 static const unsigned char FPGM(bci_action_serif_link2_down_upper_bound) [] =
6746 PUSHB_1,
6747 bci_action_serif_link2_down_upper_bound,
6748 FDEF,
6750 PUSHB_2,
6752 bci_serif_link2_common,
6753 CALL,
6755 PUSHB_1,
6756 bci_upper_bound,
6757 CALL,
6759 ENDF,
6765 * bci_action_serif_link2_down_upper_lower_bound
6767 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
6768 * Additionally, move the serif again if necessary to stay within a lower
6769 * and upper bound. We hint top to bottom.
6771 * in: edge_point (in twilight zone)
6772 * edge[-1] (in twilight zone)
6773 * edge[1] (in twilight zone)
6774 * ... stuff for bci_align_segments (edge) ...
6776 * uses: bci_serif_link2_common
6777 * bci_upper_lower_bound
6780 static const unsigned char FPGM(bci_action_serif_link2_down_upper_lower_bound) [] =
6783 PUSHB_1,
6784 bci_action_serif_link2_down_upper_lower_bound,
6785 FDEF,
6787 PUSHB_2,
6789 bci_serif_link2_common,
6790 CALL,
6792 PUSHB_1,
6793 bci_upper_lower_bound,
6794 CALL,
6796 ENDF,
6802 * bci_hint_glyph
6804 * This is the top-level glyph hinting function which parses the arguments
6805 * on the stack and calls subroutines.
6807 * in: action_0_func_idx
6808 * ... data ...
6809 * action_1_func_idx
6810 * ... data ...
6811 * ...
6813 * CVT: cvtl_is_subglyph
6814 * cvtl_use_strong_functions
6815 * cvtl_do_iup_y
6817 * sal: sal_stem_width_function
6819 * uses: bci_action_ip_before
6820 * bci_action_ip_after
6821 * bci_action_ip_on
6822 * bci_action_ip_between
6824 * bci_action_adjust_bound
6825 * bci_action_adjust_bound_serif
6826 * bci_action_adjust_bound_round
6827 * bci_action_adjust_bound_round_serif
6829 * bci_action_stem_bound
6830 * bci_action_stem_bound_serif
6831 * bci_action_stem_bound_round
6832 * bci_action_stem_bound_round_serif
6834 * bci_action_link
6835 * bci_action_link_serif
6836 * bci_action_link_round
6837 * bci_action_link_round_serif
6839 * bci_action_anchor
6840 * bci_action_anchor_serif
6841 * bci_action_anchor_round
6842 * bci_action_anchor_round_serif
6844 * bci_action_blue_anchor
6846 * bci_action_adjust
6847 * bci_action_adjust_serif
6848 * bci_action_adjust_round
6849 * bci_action_adjust_round_serif
6851 * bci_action_stem
6852 * bci_action_stem_serif
6853 * bci_action_stem_round
6854 * bci_action_stem_round_serif
6856 * bci_action_blue
6858 * bci_action_serif
6859 * bci_action_serif_lower_bound
6860 * bci_action_serif_upper_bound
6861 * bci_action_serif_upper_lower_bound
6863 * bci_action_serif_anchor
6864 * bci_action_serif_anchor_lower_bound
6865 * bci_action_serif_anchor_upper_bound
6866 * bci_action_serif_anchor_upper_lower_bound
6868 * bci_action_serif_link1
6869 * bci_action_serif_link1_lower_bound
6870 * bci_action_serif_link1_upper_bound
6871 * bci_action_serif_link1_upper_lower_bound
6873 * bci_action_serif_link2
6874 * bci_action_serif_link2_lower_bound
6875 * bci_action_serif_link2_upper_bound
6876 * bci_action_serif_link2_upper_lower_bound
6879 static const unsigned char FPGM(bci_hint_glyph) [] =
6882 PUSHB_1,
6883 bci_hint_glyph,
6884 FDEF,
6886 /* set up stem width function based on flag in CVT */
6887 PUSHB_4,
6888 sal_stem_width_function,
6889 bci_strong_stem_width,
6890 bci_smooth_stem_width,
6891 cvtl_use_strong_functions,
6892 RCVT,
6894 POP,
6896 ELSE,
6897 SWAP,
6898 POP,
6900 EIF,
6903 /* start_loop: */
6904 /* loop until all data on stack is used */
6905 CALL,
6906 PUSHB_1,
6908 NEG,
6909 PUSHB_1,
6911 DEPTH,
6913 JROT, /* goto start_loop */
6915 PUSHB_2,
6916 cvtl_do_iup_y,
6918 SZP2, /* set zp2 to normal zone 1 */
6919 RCVT,
6921 IUP_y,
6922 EIF,
6924 ENDF,
6929 #define COPY_FPGM(func_name) \
6930 do \
6932 memcpy(bufp, fpgm_ ## func_name, \
6933 sizeof (fpgm_ ## func_name)); \
6934 bufp += sizeof (fpgm_ ## func_name); \
6935 } while (0)
6937 static FT_Error
6938 TA_table_build_fpgm(FT_Byte** fpgm,
6939 FT_ULong* fpgm_len,
6940 SFNT* sfnt,
6941 FONT* font)
6943 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
6944 glyf_Data* data = (glyf_Data*)glyf_table->data;
6946 unsigned char num_used_styles = (unsigned char)data->num_used_styles;
6947 unsigned char fallback_style =
6948 CVT_SCALING_VALUE_OFFSET(0)
6949 + (unsigned char)data->style_ids[font->fallback_style];
6951 FT_UInt buf_len;
6952 FT_UInt len;
6953 FT_Byte* buf;
6954 FT_Byte* bufp;
6957 /* for compatibility with dumb bytecode interpreters or analyzers, */
6958 /* FDEFs are stored in ascending index order, without holes -- */
6959 /* note that some FDEFs are not always needed */
6960 /* (depending on options of `TTFautohint'), */
6961 /* but implementing dynamic FDEF indices would be a lot of work */
6963 buf_len = sizeof (FPGM(bci_align_x_height_a))
6964 + (font->increase_x_height
6965 ? (sizeof (FPGM(bci_align_x_height_b1a))
6967 + sizeof (FPGM(bci_align_x_height_b1b)))
6968 : sizeof (FPGM(bci_align_x_height_b2)))
6969 + sizeof (FPGM(bci_align_x_height_c))
6970 + sizeof (FPGM(bci_round))
6971 + sizeof (FPGM(bci_quantize_stem_width))
6972 + sizeof (FPGM(bci_smooth_stem_width))
6973 + sizeof (FPGM(bci_get_best_width))
6974 + sizeof (FPGM(bci_strong_stem_width_a))
6976 + sizeof (FPGM(bci_strong_stem_width_b))
6977 + sizeof (FPGM(bci_loop_do))
6978 + sizeof (FPGM(bci_loop))
6979 + sizeof (FPGM(bci_cvt_rescale))
6980 + sizeof (FPGM(bci_cvt_rescale_range))
6981 + sizeof (FPGM(bci_vwidth_data_store))
6982 + sizeof (FPGM(bci_smooth_blue_round))
6983 + sizeof (FPGM(bci_strong_blue_round))
6984 + sizeof (FPGM(bci_blue_round_range))
6985 + sizeof (FPGM(bci_decrement_component_counter))
6986 + sizeof (FPGM(bci_get_point_extrema))
6987 + sizeof (FPGM(bci_nibbles))
6988 + sizeof (FPGM(bci_number_set_is_element))
6989 + sizeof (FPGM(bci_number_set_is_element2))
6991 + sizeof (FPGM(bci_create_segment))
6992 + sizeof (FPGM(bci_create_segments_a))
6994 + sizeof (FPGM(bci_create_segments_b))
6995 + (font->control_data_head != 0
6996 ? sizeof (FPGM(bci_create_segments_c))
6997 : 0)
6998 + sizeof (FPGM(bci_create_segments_d))
7000 + sizeof (FPGM(bci_create_segments_0))
7001 + sizeof (FPGM(bci_create_segments_1))
7002 + sizeof (FPGM(bci_create_segments_2))
7003 + sizeof (FPGM(bci_create_segments_3))
7004 + sizeof (FPGM(bci_create_segments_4))
7005 + sizeof (FPGM(bci_create_segments_5))
7006 + sizeof (FPGM(bci_create_segments_6))
7007 + sizeof (FPGM(bci_create_segments_7))
7008 + sizeof (FPGM(bci_create_segments_8))
7009 + sizeof (FPGM(bci_create_segments_9))
7011 + sizeof (FPGM(bci_deltap1))
7012 + sizeof (FPGM(bci_deltap2))
7013 + sizeof (FPGM(bci_deltap3))
7015 + sizeof (FPGM(bci_create_segments_composite_a))
7017 + sizeof (FPGM(bci_create_segments_composite_b))
7018 + (font->control_data_head != 0
7019 ? sizeof (FPGM(bci_create_segments_composite_c))
7020 : 0)
7021 + sizeof (FPGM(bci_create_segments_composite_d))
7023 + sizeof (FPGM(bci_create_segments_composite_0))
7024 + sizeof (FPGM(bci_create_segments_composite_1))
7025 + sizeof (FPGM(bci_create_segments_composite_2))
7026 + sizeof (FPGM(bci_create_segments_composite_3))
7027 + sizeof (FPGM(bci_create_segments_composite_4))
7028 + sizeof (FPGM(bci_create_segments_composite_5))
7029 + sizeof (FPGM(bci_create_segments_composite_6))
7030 + sizeof (FPGM(bci_create_segments_composite_7))
7031 + sizeof (FPGM(bci_create_segments_composite_8))
7032 + sizeof (FPGM(bci_create_segments_composite_9))
7034 + sizeof (FPGM(bci_align_point))
7035 + sizeof (FPGM(bci_align_segment))
7036 + sizeof (FPGM(bci_align_segments))
7038 + sizeof (FPGM(bci_scale_contour))
7039 + sizeof (FPGM(bci_scale_glyph_a))
7041 + sizeof (FPGM(bci_scale_glyph_b))
7042 + sizeof (FPGM(bci_scale_composite_glyph_a))
7044 + sizeof (FPGM(bci_scale_composite_glyph_b))
7045 + sizeof (FPGM(bci_shift_contour))
7046 + sizeof (FPGM(bci_shift_subglyph_a))
7048 + sizeof (FPGM(bci_shift_subglyph_b))
7049 + (font->control_data_head != 0
7050 ? sizeof (FPGM(bci_shift_subglyph_c))
7051 : 0)
7052 + sizeof (FPGM(bci_shift_subglyph_d))
7054 + sizeof (FPGM(bci_ip_outer_align_point))
7055 + sizeof (FPGM(bci_ip_on_align_points))
7056 + sizeof (FPGM(bci_ip_between_align_point))
7057 + sizeof (FPGM(bci_ip_between_align_points))
7059 + sizeof (FPGM(bci_adjust_common))
7060 + sizeof (FPGM(bci_stem_common))
7061 + sizeof (FPGM(bci_serif_common))
7062 + sizeof (FPGM(bci_serif_anchor_common))
7063 + sizeof (FPGM(bci_serif_link1_common))
7064 + sizeof (FPGM(bci_serif_link2_common))
7066 + sizeof (FPGM(bci_lower_bound))
7067 + sizeof (FPGM(bci_upper_bound))
7068 + sizeof (FPGM(bci_upper_lower_bound))
7070 + sizeof (FPGM(bci_adjust_bound))
7071 + sizeof (FPGM(bci_stem_bound))
7072 + sizeof (FPGM(bci_link))
7073 + sizeof (FPGM(bci_anchor))
7074 + sizeof (FPGM(bci_adjust))
7075 + sizeof (FPGM(bci_stem))
7077 + sizeof (FPGM(bci_action_ip_before))
7078 + sizeof (FPGM(bci_action_ip_after))
7079 + sizeof (FPGM(bci_action_ip_on))
7080 + sizeof (FPGM(bci_action_ip_between))
7082 + sizeof (FPGM(bci_action_blue))
7083 + sizeof (FPGM(bci_action_blue_anchor))
7085 + sizeof (FPGM(bci_action_anchor))
7086 + sizeof (FPGM(bci_action_anchor_serif))
7087 + sizeof (FPGM(bci_action_anchor_round))
7088 + sizeof (FPGM(bci_action_anchor_round_serif))
7090 + sizeof (FPGM(bci_action_adjust))
7091 + sizeof (FPGM(bci_action_adjust_serif))
7092 + sizeof (FPGM(bci_action_adjust_round))
7093 + sizeof (FPGM(bci_action_adjust_round_serif))
7094 + sizeof (FPGM(bci_action_adjust_bound))
7095 + sizeof (FPGM(bci_action_adjust_bound_serif))
7096 + sizeof (FPGM(bci_action_adjust_bound_round))
7097 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
7098 + sizeof (FPGM(bci_action_adjust_down_bound))
7099 + sizeof (FPGM(bci_action_adjust_down_bound_serif))
7100 + sizeof (FPGM(bci_action_adjust_down_bound_round))
7101 + sizeof (FPGM(bci_action_adjust_down_bound_round_serif))
7103 + sizeof (FPGM(bci_action_link))
7104 + sizeof (FPGM(bci_action_link_serif))
7105 + sizeof (FPGM(bci_action_link_round))
7106 + sizeof (FPGM(bci_action_link_round_serif))
7108 + sizeof (FPGM(bci_action_stem))
7109 + sizeof (FPGM(bci_action_stem_serif))
7110 + sizeof (FPGM(bci_action_stem_round))
7111 + sizeof (FPGM(bci_action_stem_round_serif))
7112 + sizeof (FPGM(bci_action_stem_bound))
7113 + sizeof (FPGM(bci_action_stem_bound_serif))
7114 + sizeof (FPGM(bci_action_stem_bound_round))
7115 + sizeof (FPGM(bci_action_stem_bound_round_serif))
7116 + sizeof (FPGM(bci_action_stem_down_bound))
7117 + sizeof (FPGM(bci_action_stem_down_bound_serif))
7118 + sizeof (FPGM(bci_action_stem_down_bound_round))
7119 + sizeof (FPGM(bci_action_stem_down_bound_round_serif))
7121 + sizeof (FPGM(bci_action_serif))
7122 + sizeof (FPGM(bci_action_serif_lower_bound))
7123 + sizeof (FPGM(bci_action_serif_upper_bound))
7124 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
7125 + sizeof (FPGM(bci_action_serif_down_lower_bound))
7126 + sizeof (FPGM(bci_action_serif_down_upper_bound))
7127 + sizeof (FPGM(bci_action_serif_down_upper_lower_bound))
7129 + sizeof (FPGM(bci_action_serif_anchor))
7130 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
7131 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
7132 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
7133 + sizeof (FPGM(bci_action_serif_anchor_down_lower_bound))
7134 + sizeof (FPGM(bci_action_serif_anchor_down_upper_bound))
7135 + sizeof (FPGM(bci_action_serif_anchor_down_upper_lower_bound))
7137 + sizeof (FPGM(bci_action_serif_link1))
7138 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
7139 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
7140 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
7141 + sizeof (FPGM(bci_action_serif_link1_down_lower_bound))
7142 + sizeof (FPGM(bci_action_serif_link1_down_upper_bound))
7143 + sizeof (FPGM(bci_action_serif_link1_down_upper_lower_bound))
7145 + sizeof (FPGM(bci_action_serif_link2))
7146 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
7147 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
7148 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
7149 + sizeof (FPGM(bci_action_serif_link2_down_lower_bound))
7150 + sizeof (FPGM(bci_action_serif_link2_down_upper_bound))
7151 + sizeof (FPGM(bci_action_serif_link2_down_upper_lower_bound))
7153 + sizeof (FPGM(bci_hint_glyph));
7155 /* buffer length must be a multiple of four */
7156 len = (buf_len + 3) & ~3U;
7157 buf = (FT_Byte*)malloc(len);
7158 if (!buf)
7159 return FT_Err_Out_Of_Memory;
7161 /* pad end of buffer with zeros */
7162 buf[len - 1] = 0x00;
7163 buf[len - 2] = 0x00;
7164 buf[len - 3] = 0x00;
7166 /* copy font program into buffer and fill in the missing variables */
7167 bufp = buf;
7169 COPY_FPGM(bci_align_x_height_a);
7170 if (font->increase_x_height)
7172 COPY_FPGM(bci_align_x_height_b1a);
7173 *(bufp++) = HIGH(font->increase_x_height);
7174 *(bufp++) = LOW(font->increase_x_height);
7175 COPY_FPGM(bci_align_x_height_b1b);
7177 else
7178 COPY_FPGM(bci_align_x_height_b2);
7179 COPY_FPGM(bci_align_x_height_c);
7181 COPY_FPGM(bci_round);
7182 COPY_FPGM(bci_quantize_stem_width);
7183 COPY_FPGM(bci_smooth_stem_width);
7184 COPY_FPGM(bci_get_best_width);
7185 COPY_FPGM(bci_strong_stem_width_a);
7186 *(bufp++) = num_used_styles;
7187 COPY_FPGM(bci_strong_stem_width_b);
7188 COPY_FPGM(bci_loop_do);
7189 COPY_FPGM(bci_loop);
7190 COPY_FPGM(bci_cvt_rescale);
7191 COPY_FPGM(bci_cvt_rescale_range);
7192 COPY_FPGM(bci_vwidth_data_store);
7193 COPY_FPGM(bci_smooth_blue_round);
7194 COPY_FPGM(bci_strong_blue_round);
7195 COPY_FPGM(bci_blue_round_range);
7196 COPY_FPGM(bci_decrement_component_counter);
7197 COPY_FPGM(bci_get_point_extrema);
7198 COPY_FPGM(bci_nibbles);
7199 COPY_FPGM(bci_number_set_is_element);
7200 COPY_FPGM(bci_number_set_is_element2);
7202 COPY_FPGM(bci_create_segment);
7203 COPY_FPGM(bci_create_segments_a);
7204 *(bufp++) = num_used_styles;
7205 COPY_FPGM(bci_create_segments_b);
7206 if (font->control_data_head)
7207 COPY_FPGM(bci_create_segments_c);
7208 COPY_FPGM(bci_create_segments_d);
7210 COPY_FPGM(bci_create_segments_0);
7211 COPY_FPGM(bci_create_segments_1);
7212 COPY_FPGM(bci_create_segments_2);
7213 COPY_FPGM(bci_create_segments_3);
7214 COPY_FPGM(bci_create_segments_4);
7215 COPY_FPGM(bci_create_segments_5);
7216 COPY_FPGM(bci_create_segments_6);
7217 COPY_FPGM(bci_create_segments_7);
7218 COPY_FPGM(bci_create_segments_8);
7219 COPY_FPGM(bci_create_segments_9);
7221 COPY_FPGM(bci_deltap1);
7222 COPY_FPGM(bci_deltap2);
7223 COPY_FPGM(bci_deltap3);
7225 COPY_FPGM(bci_create_segments_composite_a);
7226 *(bufp++) = num_used_styles;
7227 COPY_FPGM(bci_create_segments_composite_b);
7228 if (font->control_data_head)
7229 COPY_FPGM(bci_create_segments_composite_c);
7230 COPY_FPGM(bci_create_segments_composite_d);
7232 COPY_FPGM(bci_create_segments_composite_0);
7233 COPY_FPGM(bci_create_segments_composite_1);
7234 COPY_FPGM(bci_create_segments_composite_2);
7235 COPY_FPGM(bci_create_segments_composite_3);
7236 COPY_FPGM(bci_create_segments_composite_4);
7237 COPY_FPGM(bci_create_segments_composite_5);
7238 COPY_FPGM(bci_create_segments_composite_6);
7239 COPY_FPGM(bci_create_segments_composite_7);
7240 COPY_FPGM(bci_create_segments_composite_8);
7241 COPY_FPGM(bci_create_segments_composite_9);
7243 COPY_FPGM(bci_align_point);
7244 COPY_FPGM(bci_align_segment);
7245 COPY_FPGM(bci_align_segments);
7247 COPY_FPGM(bci_scale_contour);
7248 COPY_FPGM(bci_scale_glyph_a);
7249 *(bufp++) = fallback_style;
7250 COPY_FPGM(bci_scale_glyph_b);
7251 COPY_FPGM(bci_scale_composite_glyph_a);
7252 *(bufp++) = fallback_style;
7253 COPY_FPGM(bci_scale_composite_glyph_b);
7254 COPY_FPGM(bci_shift_contour);
7255 COPY_FPGM(bci_shift_subglyph_a);
7256 *(bufp++) = fallback_style;
7257 COPY_FPGM(bci_shift_subglyph_b);
7258 if (font->control_data_head)
7259 COPY_FPGM(bci_shift_subglyph_c);
7260 COPY_FPGM(bci_shift_subglyph_d);
7262 COPY_FPGM(bci_ip_outer_align_point);
7263 COPY_FPGM(bci_ip_on_align_points);
7264 COPY_FPGM(bci_ip_between_align_point);
7265 COPY_FPGM(bci_ip_between_align_points);
7267 COPY_FPGM(bci_adjust_common);
7268 COPY_FPGM(bci_stem_common);
7269 COPY_FPGM(bci_serif_common);
7270 COPY_FPGM(bci_serif_anchor_common);
7271 COPY_FPGM(bci_serif_link1_common);
7272 COPY_FPGM(bci_serif_link2_common);
7274 COPY_FPGM(bci_lower_bound);
7275 COPY_FPGM(bci_upper_bound);
7276 COPY_FPGM(bci_upper_lower_bound);
7278 COPY_FPGM(bci_adjust_bound);
7279 COPY_FPGM(bci_stem_bound);
7280 COPY_FPGM(bci_link);
7281 COPY_FPGM(bci_anchor);
7282 COPY_FPGM(bci_adjust);
7283 COPY_FPGM(bci_stem);
7285 COPY_FPGM(bci_action_ip_before);
7286 COPY_FPGM(bci_action_ip_after);
7287 COPY_FPGM(bci_action_ip_on);
7288 COPY_FPGM(bci_action_ip_between);
7290 COPY_FPGM(bci_action_blue);
7291 COPY_FPGM(bci_action_blue_anchor);
7293 COPY_FPGM(bci_action_anchor);
7294 COPY_FPGM(bci_action_anchor_serif);
7295 COPY_FPGM(bci_action_anchor_round);
7296 COPY_FPGM(bci_action_anchor_round_serif);
7298 COPY_FPGM(bci_action_adjust);
7299 COPY_FPGM(bci_action_adjust_serif);
7300 COPY_FPGM(bci_action_adjust_round);
7301 COPY_FPGM(bci_action_adjust_round_serif);
7302 COPY_FPGM(bci_action_adjust_bound);
7303 COPY_FPGM(bci_action_adjust_bound_serif);
7304 COPY_FPGM(bci_action_adjust_bound_round);
7305 COPY_FPGM(bci_action_adjust_bound_round_serif);
7306 COPY_FPGM(bci_action_adjust_down_bound);
7307 COPY_FPGM(bci_action_adjust_down_bound_serif);
7308 COPY_FPGM(bci_action_adjust_down_bound_round);
7309 COPY_FPGM(bci_action_adjust_down_bound_round_serif);
7311 COPY_FPGM(bci_action_link);
7312 COPY_FPGM(bci_action_link_serif);
7313 COPY_FPGM(bci_action_link_round);
7314 COPY_FPGM(bci_action_link_round_serif);
7316 COPY_FPGM(bci_action_stem);
7317 COPY_FPGM(bci_action_stem_serif);
7318 COPY_FPGM(bci_action_stem_round);
7319 COPY_FPGM(bci_action_stem_round_serif);
7320 COPY_FPGM(bci_action_stem_bound);
7321 COPY_FPGM(bci_action_stem_bound_serif);
7322 COPY_FPGM(bci_action_stem_bound_round);
7323 COPY_FPGM(bci_action_stem_bound_round_serif);
7324 COPY_FPGM(bci_action_stem_down_bound);
7325 COPY_FPGM(bci_action_stem_down_bound_serif);
7326 COPY_FPGM(bci_action_stem_down_bound_round);
7327 COPY_FPGM(bci_action_stem_down_bound_round_serif);
7329 COPY_FPGM(bci_action_serif);
7330 COPY_FPGM(bci_action_serif_lower_bound);
7331 COPY_FPGM(bci_action_serif_upper_bound);
7332 COPY_FPGM(bci_action_serif_upper_lower_bound);
7333 COPY_FPGM(bci_action_serif_down_lower_bound);
7334 COPY_FPGM(bci_action_serif_down_upper_bound);
7335 COPY_FPGM(bci_action_serif_down_upper_lower_bound);
7337 COPY_FPGM(bci_action_serif_anchor);
7338 COPY_FPGM(bci_action_serif_anchor_lower_bound);
7339 COPY_FPGM(bci_action_serif_anchor_upper_bound);
7340 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
7341 COPY_FPGM(bci_action_serif_anchor_down_lower_bound);
7342 COPY_FPGM(bci_action_serif_anchor_down_upper_bound);
7343 COPY_FPGM(bci_action_serif_anchor_down_upper_lower_bound);
7345 COPY_FPGM(bci_action_serif_link1);
7346 COPY_FPGM(bci_action_serif_link1_lower_bound);
7347 COPY_FPGM(bci_action_serif_link1_upper_bound);
7348 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
7349 COPY_FPGM(bci_action_serif_link1_down_lower_bound);
7350 COPY_FPGM(bci_action_serif_link1_down_upper_bound);
7351 COPY_FPGM(bci_action_serif_link1_down_upper_lower_bound);
7353 COPY_FPGM(bci_action_serif_link2);
7354 COPY_FPGM(bci_action_serif_link2_lower_bound);
7355 COPY_FPGM(bci_action_serif_link2_upper_bound);
7356 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
7357 COPY_FPGM(bci_action_serif_link2_down_lower_bound);
7358 COPY_FPGM(bci_action_serif_link2_down_upper_bound);
7359 COPY_FPGM(bci_action_serif_link2_down_upper_lower_bound);
7361 COPY_FPGM(bci_hint_glyph);
7363 *fpgm = buf;
7364 *fpgm_len = buf_len;
7366 return FT_Err_Ok;
7370 FT_Error
7371 TA_sfnt_build_fpgm_table(SFNT* sfnt,
7372 FONT* font)
7374 FT_Error error;
7376 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
7377 glyf_Data* data = (glyf_Data*)glyf_table->data;
7379 FT_Byte* fpgm_buf;
7380 FT_ULong fpgm_len;
7383 error = TA_sfnt_add_table_info(sfnt);
7384 if (error)
7385 goto Exit;
7387 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
7388 if (glyf_table->processed)
7390 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
7391 goto Exit;
7394 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
7395 if (error)
7396 goto Exit;
7398 if (fpgm_len > sfnt->max_instructions)
7399 sfnt->max_instructions = (FT_UShort)fpgm_len;
7401 /* in case of success, `fpgm_buf' gets linked */
7402 /* and is eventually freed in `TA_font_unload' */
7403 error = TA_font_add_table(font,
7404 &sfnt->table_infos[sfnt->num_table_infos - 1],
7405 TTAG_fpgm, fpgm_len, fpgm_buf);
7406 if (error)
7407 free(fpgm_buf);
7408 else
7409 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
7411 Exit:
7412 return error;
7415 /* end of tafpgm.c */