[doc] Improve formatting of tables in HTML format.
[ttfautohint.git] / lib / tafpgm.c
blob876e3103743cf5feafa35dd8c7d789da856bb2aa
1 /* tafpgm.c */
3 /*
4 * Copyright (C) 2011-2013 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
32 GC_orig, \
33 SWAP, \
34 GC_orig, \
35 SWAP, \
36 SUB
38 #define MD_orig_ZP2_0 \
39 MD_orig_fixed
41 #define MD_orig_ZP2_1 \
42 PUSHB_1, \
43 0, \
44 SZP2, \
45 MD_orig_fixed, \
46 PUSHB_1, \
47 1, \
48 SZP2
52 * Older versions of Monotype's `iType' bytecode interpreter have a serious
53 * bug: The DIV instruction rounds the result, while the correct operation
54 * is truncation. (Note, however, that MUL always rounds the result.)
55 * Since many printers contain this rasterizer without any possibility to
56 * update to a non-buggy version, we have to work around the problem.
58 * DIV and MUL work on 26.6 numbers which means that the numerator gets
59 * multiplied by 64 before the division, and the product gets divided by 64
60 * after the multiplication, respectively. For example, to divide 2 by 3,
61 * you have to write
63 * PUSHB_1,
64 * 2,
65 * 3*64,
66 * DIV
68 * The correct formula to divide two values in 26.6 format with truncation
69 * is
71 * a*64 / b ,
73 * while older `iType' versions incorrectly apply rounding by using
75 * (a*64 + b/2) / b .
77 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
79 * (2*64 + (3*64)/2) / (3*64) = 1
81 * instead of the correct result 0.
83 * The solution to the rounding issue is to use a 26.6 value as an
84 * intermediate result so that we can truncate to the nearest integer (in
85 * 26.6 format) with the FLOOR operator before converting back to a plain
86 * integer (in 32.0 format).
88 * For the common divisions by 2 and 2^10 we define macros.
90 #define DIV_POS_BY_2 \
91 PUSHB_1, \
92 2, \
93 DIV, /* multiply by 64, then divide by 2 */ \
94 FLOOR, \
95 PUSHB_1, \
96 1, \
97 MUL /* multiply by 1, then divide by 64 */
99 #define DIV_BY_2 \
100 PUSHB_1, \
101 2, \
102 DIV, \
103 DUP, \
104 PUSHB_1, \
105 0, \
106 LT, \
107 IF, \
108 PUSHB_1, \
109 64, \
110 ADD, /* add 1 if value is negative */ \
111 EIF, \
112 FLOOR, \
113 PUSHB_1, \
114 1, \
117 #define DIV_BY_1024 \
118 PUSHW_1, \
119 0x04, /* 2^10 */ \
120 0x00, \
121 DIV, \
122 DUP, \
123 PUSHB_1, \
124 0, \
125 LT, \
126 IF, \
127 PUSHB_1, \
128 64, \
129 ADD, \
130 EIF, \
131 FLOOR, \
132 PUSHB_1, \
133 1, \
137 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
138 #define DO_SCALE \
139 DUP, /* s: a a */ \
140 PUSHB_1, \
141 sal_scale, \
142 RS, \
143 MUL, /* delta * 2^10 */ \
144 DIV_BY_1024, /* delta */ \
145 ADD /* a + delta */
148 /* in the comments below, the top of the stack (`s:') */
149 /* is the rightmost element; the stack is shown */
150 /* after the instruction on the same line has been executed */
154 * bci_align_top
156 * Optimize the alignment of the top of small letters to the pixel grid.
158 * This function gets used in the `prep' table.
160 * in: blue_idx (CVT index for the script's top of small letters blue zone)
162 * sal: sal_i (CVT index of the script's scaling value;
163 * gets incremented by 1 after execution)
166 unsigned char FPGM(bci_align_top_a) [] =
169 PUSHB_1,
170 bci_align_top,
171 FDEF,
173 /* only get CVT value for non-zero index */
174 DUP,
175 PUSHB_1,
177 NEQ,
179 RCVT,
180 EIF,
181 DUP,
182 DUP, /* s: blue blue blue */
186 /* if (font->increase_x_height) */
187 /* { */
189 unsigned char FPGM(bci_align_top_b1a) [] =
192 /* apply much `stronger' rounding up of x height for */
193 /* 6 <= PPEM <= increase_x_height */
194 MPPEM,
195 PUSHW_1,
199 /* %d, x height increase limit */
201 unsigned char FPGM(bci_align_top_b1b) [] =
204 LTEQ,
205 MPPEM,
206 PUSHB_1,
208 GTEQ,
209 AND,
211 PUSHB_1,
212 52, /* threshold = 52 */
214 ELSE,
215 PUSHB_1,
216 40, /* threshold = 40 */
218 EIF,
219 ADD,
220 FLOOR, /* fitted = FLOOR(blue + threshold) */
224 /* } */
226 /* if (!font->increase_x_height) */
227 /* { */
229 unsigned char FPGM(bci_align_top_b2) [] =
232 PUSHB_1,
234 ADD,
235 FLOOR, /* fitted = FLOOR(blue + 40) */
239 /* } */
241 unsigned char FPGM(bci_align_top_c) [] =
244 DUP, /* s: blue blue fitted fitted */
245 ROLL,
246 NEQ,
247 IF, /* s: blue fitted */
248 PUSHB_1,
250 CINDEX,
251 SUB, /* s: blue (fitted-blue) */
252 PUSHB_1,
253 cvtl_0x10000,
254 RCVT,
255 MUL, /* (fitted-blue) in 16.16 format */
256 SWAP,
257 DIV, /* factor = ((fitted-blue) / blue) in 16.16 format */
259 ELSE,
260 POP,
261 POP,
262 PUSHB_1,
263 0, /* factor = 0 */
265 EIF,
267 PUSHB_1,
268 sal_i,
269 RS, /* s: factor idx */
270 SWAP,
271 WCVTP,
273 PUSHB_3,
274 sal_i,
276 sal_i,
278 ADD, /* sal_i = sal_i + 1 */
281 ENDF,
287 * bci_round
289 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
290 * engine specific corrections are applied.
292 * in: val
294 * out: ROUND(val)
297 unsigned char FPGM(bci_round) [] =
300 PUSHB_1,
301 bci_round,
302 FDEF,
304 PUSHB_1,
306 ADD,
307 FLOOR,
309 ENDF,
315 * bci_smooth_stem_width
317 * This is the equivalent to the following code from function
318 * `ta_latin_compute_stem_width':
320 * dist = ABS(width)
322 * if (stem_is_serif
323 * && dist < 3*64)
324 * || std_width < 40:
325 * return width
326 * else if base_is_round:
327 * if dist < 80
328 * dist = 64
329 * else if dist < 56:
330 * dist = 56
332 * delta = ABS(dist - std_width)
334 * if delta < 40:
335 * dist = std_width
336 * if dist < 48
337 * dist = 48
338 * goto End
340 * if dist < 3*64:
341 * delta = dist
342 * dist = FLOOR(dist)
343 * delta = delta - dist
345 * if delta < 10:
346 * dist = dist + delta
347 * else if delta < 32:
348 * dist = dist + 10
349 * else if delta < 54:
350 * dist = dist + 54
351 * else
352 * dist = dist + delta
353 * else
354 * dist = ROUND(dist)
356 * End:
357 * if width < 0:
358 * dist = -dist
359 * return dist
361 * in: width
362 * stem_is_serif
363 * base_is_round
365 * out: new_width
367 * sal: sal_vwidth_data_offset
369 * CVT: std_width
371 * uses: bci_round
374 unsigned char FPGM(bci_smooth_stem_width) [] =
377 PUSHB_1,
378 bci_smooth_stem_width,
379 FDEF,
381 DUP,
382 ABS, /* s: base_is_round stem_is_serif width dist */
384 DUP,
385 PUSHB_1,
386 3*64,
387 LT, /* dist < 3*64 */
389 PUSHB_1,
391 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
392 AND, /* stem_is_serif && dist < 3*64 */
394 PUSHB_2,
396 sal_vwidth_data_offset,
398 RCVT, /* double indirection */
399 RCVT,
400 GT, /* standard_width < 40 */
401 OR, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
403 IF, /* s: base_is_round width dist */
404 POP,
405 SWAP,
406 POP, /* s: width */
408 ELSE,
409 ROLL, /* s: width dist base_is_round */
410 IF, /* s: width dist */
411 DUP,
412 PUSHB_1,
414 LT, /* dist < 80 */
415 IF, /* s: width dist */
416 POP,
417 PUSHB_1,
418 64, /* dist = 64 */
419 EIF,
421 ELSE,
422 DUP,
423 PUSHB_1,
425 LT, /* dist < 56 */
426 IF, /* s: width dist */
427 POP,
428 PUSHB_1,
429 56, /* dist = 56 */
430 EIF,
431 EIF,
433 DUP, /* s: width dist dist */
434 PUSHB_1,
435 sal_vwidth_data_offset,
437 RCVT, /* double indirection */
438 RCVT,
439 SUB,
440 ABS, /* s: width dist delta */
442 PUSHB_1,
444 LT, /* delta < 40 */
445 IF, /* s: width dist */
446 POP,
447 PUSHB_1,
448 sal_vwidth_data_offset,
450 RCVT, /* double indirection */
451 RCVT, /* dist = std_width */
452 DUP,
453 PUSHB_1,
455 LT, /* dist < 48 */
457 POP,
458 PUSHB_1,
459 48, /* dist = 48 */
460 EIF,
462 ELSE,
463 DUP, /* s: width dist dist */
464 PUSHB_1,
465 3*64,
466 LT, /* dist < 3*64 */
468 DUP, /* s: width delta dist */
469 FLOOR, /* dist = FLOOR(dist) */
470 DUP, /* s: width delta dist dist */
471 ROLL,
472 ROLL, /* s: width dist delta dist */
473 SUB, /* delta = delta - dist */
475 DUP, /* s: width dist delta delta */
476 PUSHB_1,
478 LT, /* delta < 10 */
479 IF, /* s: width dist delta */
480 ADD, /* dist = dist + delta */
482 ELSE,
483 DUP,
484 PUSHB_1,
486 LT, /* delta < 32 */
488 POP,
489 PUSHB_1,
491 ADD, /* dist = dist + 10 */
493 ELSE,
494 DUP,
495 PUSHB_1,
497 LT, /* delta < 54 */
499 POP,
500 PUSHB_1,
502 ADD, /* dist = dist + 54 */
504 ELSE,
505 ADD, /* dist = dist + delta */
507 EIF,
508 EIF,
509 EIF,
511 ELSE,
512 PUSHB_1,
513 bci_round,
514 CALL, /* dist = round(dist) */
516 EIF,
517 EIF,
519 SWAP, /* s: dist width */
520 PUSHB_1,
522 LT, /* width < 0 */
524 NEG, /* dist = -dist */
525 EIF,
526 EIF,
528 ENDF,
534 * bci_get_best_width
536 * An auxiliary function for `bci_strong_stem_width'.
538 * in: n (initialized with CVT index for first vertical width)
539 * dist
541 * out: n+1
542 * dist
544 * sal: sal_best
545 * sal_ref
547 * CVT: widths[]
550 unsigned char FPGM(bci_get_best_width) [] =
553 PUSHB_1,
554 bci_get_best_width,
555 FDEF,
557 DUP,
558 RCVT, /* s: dist n w */
559 DUP,
560 PUSHB_1,
562 CINDEX, /* s: dist n w w dist */
563 SUB,
564 ABS, /* s: dist n w d */
565 DUP,
566 PUSHB_1,
567 sal_best,
568 RS, /* s: dist n w d d best */
569 LT, /* d < best */
571 PUSHB_1,
572 sal_best,
573 SWAP,
574 WS, /* best = d */
575 PUSHB_1,
576 sal_ref,
577 SWAP,
578 WS, /* reference = w */
580 ELSE,
581 POP,
582 POP,
583 EIF,
585 PUSHB_1,
587 ADD, /* n = n + 1 */
589 ENDF,
595 * bci_strong_stem_width
597 * This is the equivalent to the following code (function
598 * `ta_latin_snap_width' and some lines from
599 * `ta_latin_compute_stem_width'):
601 * best = 64 + 32 + 2;
602 * reference = width
603 * dist = ABS(width)
605 * for n in 0 .. num_widths:
606 * w = widths[n]
607 * d = ABS(dist - w)
609 * if d < best:
610 * best = d
611 * reference = w;
613 * if dist >= reference:
614 * if dist < ROUND(reference) + 48:
615 * dist = reference
616 * else
617 * if dist > ROUND(reference) - 48:
618 * dist = reference
620 * if dist >= 64:
621 * dist = ROUND(dist)
622 * else
623 * dist = 64
625 * if width < 0:
626 * dist = -dist
627 * return dist
629 * in: width
630 * stem_is_serif (unused)
631 * base_is_round (unused)
633 * out: new_width
635 * sal: sal_best
636 * sal_ref
637 * sal_vwidth_data_offset
639 * CVT: widths[]
641 * uses: bci_get_best_width
642 * bci_round
645 unsigned char FPGM(bci_strong_stem_width) [] =
648 PUSHB_1,
649 bci_strong_stem_width,
650 FDEF,
652 SWAP,
653 POP,
654 SWAP,
655 POP,
656 DUP,
657 ABS, /* s: width dist */
659 PUSHB_2,
660 sal_best,
661 64 + 32 + 2,
662 WS, /* sal_best = 98 */
664 DUP,
665 PUSHB_1,
666 sal_ref,
667 SWAP,
668 WS, /* sal_ref = width */
670 PUSHB_1,
671 sal_vwidth_data_offset,
673 RCVT, /* first index of vertical widths */
675 PUSHB_1,
676 sal_vwidth_data_offset,
678 PUSHB_1,
679 cvtl_num_used_scripts,
680 RCVT,
681 ADD,
682 RCVT, /* number of vertical widths */
684 PUSHB_1,
685 bci_get_best_width,
686 LOOPCALL,
688 POP, /* s: width dist */
689 DUP,
690 PUSHB_1,
691 sal_ref,
692 RS, /* s: width dist dist reference */
693 DUP,
694 ROLL,
695 DUP,
696 ROLL,
697 PUSHB_1,
698 bci_round,
699 CALL, /* s: width dist reference dist dist ROUND(reference) */
700 PUSHB_2,
703 CINDEX,
704 ROLL, /* s: width dist reference dist ROUND(reference) 48 reference dist */
706 LTEQ, /* dist >= reference */
707 IF, /* s: width dist reference dist ROUND(reference) 48 */
708 ADD,
709 LT, /* dist < ROUND(reference) + 48 */
711 ELSE,
712 SUB,
713 GT, /* dist > ROUND(reference) - 48 */
714 EIF,
717 SWAP, /* s: width reference dist */
718 EIF,
719 POP,
721 DUP,
722 PUSHB_1,
724 GTEQ, /* dist >= 64 */
726 PUSHB_1,
727 bci_round,
728 CALL, /* dist = ROUND(dist) */
730 ELSE,
731 POP,
732 PUSHB_1,
733 64, /* dist = 64 */
734 EIF,
736 SWAP, /* s: dist width */
737 PUSHB_1,
739 LT, /* width < 0 */
741 NEG, /* dist = -dist */
742 EIF,
744 ENDF,
750 * bci_do_loop
752 * An auxiliary function for `bci_loop'.
754 * sal: sal_i (gets incremented by 2 after execution)
755 * sal_func
757 * uses: func[sal_func]
760 unsigned char FPGM(bci_loop_do) [] =
763 PUSHB_1,
764 bci_loop_do,
765 FDEF,
767 PUSHB_1,
768 sal_func,
770 CALL,
772 PUSHB_3,
773 sal_i,
775 sal_i,
777 ADD, /* sal_i = sal_i + 2 */
780 ENDF,
786 * bci_loop
788 * Take a range `start'..`end' and a function number and apply the
789 * associated function to the range elements `start', `start+2',
790 * `start+4', ...
792 * in: func_num
793 * end
794 * start
796 * sal: sal_i (counter initialized with `start')
797 * sal_func (`func_num')
799 * uses: bci_loop_do
802 unsigned char FPGM(bci_loop) [] =
805 PUSHB_1,
806 bci_loop,
807 FDEF,
809 PUSHB_1,
810 sal_func,
811 SWAP,
812 WS, /* sal_func = func_num */
814 SWAP,
815 DUP,
816 PUSHB_1,
817 sal_i,
818 SWAP,
819 WS, /* sal_i = start */
821 SUB,
822 DIV_POS_BY_2,
823 PUSHB_1,
825 ADD, /* number of loops ((end - start) / 2 + 1) */
827 PUSHB_1,
828 bci_loop_do,
829 LOOPCALL,
831 ENDF,
837 * bci_cvt_rescale
839 * Rescale CVT value by `sal_scale' (in 16.16 format).
841 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
842 * consequently, the calculation `a * b/c' is done as `a + delta' with
843 * `delta = a * (b-c)/c'. This avoids overflow.
845 * in: cvt_idx
847 * out: cvt_idx+1
849 * sal: sal_scale
852 unsigned char FPGM(bci_cvt_rescale) [] =
855 PUSHB_1,
856 bci_cvt_rescale,
857 FDEF,
859 DUP,
860 DUP,
861 RCVT,
862 DO_SCALE,
863 WCVTP,
865 PUSHB_1,
867 ADD,
869 ENDF,
875 * bci_cvt_rescale_range
877 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
878 * scaling value.
880 * This function gets used in the `prep' table.
882 * in: num_cvt
883 * cvt_start_idx
885 * sal: sal_i (CVT index of the script's scaling value;
886 * gets incremented by 1 after execution)
887 * sal_scale
889 * uses: bci_cvt_rescale
892 unsigned char FPGM(bci_cvt_rescale_range) [] =
895 PUSHB_1,
896 bci_cvt_rescale_range,
897 FDEF,
899 /* store scaling value in `sal_scale' */
900 PUSHB_3,
901 bci_cvt_rescale,
902 sal_scale,
903 sal_i,
905 RCVT,
906 WS, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
908 LOOPCALL,
909 POP,
911 PUSHB_3,
912 sal_i,
914 sal_i,
916 ADD, /* sal_i = sal_i + 1 */
919 ENDF,
925 * bci_vwidth_data_store
927 * Store a vertical width array value.
929 * This function gets used in the `prep' table.
931 * in: value
933 * sal: sal_i (CVT index of the script's vwidth data;
934 * gets incremented by 1 after execution)
937 unsigned char FPGM(bci_vwidth_data_store) [] =
940 PUSHB_1,
941 bci_vwidth_data_store,
942 FDEF,
944 PUSHB_1,
945 sal_i,
947 SWAP,
948 WCVTP,
950 PUSHB_3,
951 sal_i,
953 sal_i,
955 ADD, /* sal_i = sal_i + 1 */
958 ENDF,
964 * bci_blue_round
966 * Round a blue ref value and adjust its corresponding shoot value.
968 * This is the equivalent to the following code (function
969 * `ta_latin_metrics_scale_dim':
971 * delta = dist;
972 * if (dist < 0)
973 * delta = -delta;
975 * if (delta < 32)
976 * delta = 0;
977 * else if (delta < 48)
978 * delta = 32;
979 * else
980 * delta = 64;
982 * if (dist < 0)
983 * delta = -delta;
985 * in: ref_idx
987 * sal: sal_i (number of blue zones)
989 * out: ref_idx+1
991 * uses: bci_round
994 unsigned char FPGM(bci_blue_round) [] =
997 PUSHB_1,
998 bci_blue_round,
999 FDEF,
1001 DUP,
1002 DUP,
1003 RCVT, /* s: ref_idx ref_idx ref */
1005 DUP,
1006 PUSHB_1,
1007 bci_round,
1008 CALL,
1009 SWAP, /* s: ref_idx ref_idx round(ref) ref */
1011 PUSHB_1,
1012 sal_i,
1014 PUSHB_1,
1016 CINDEX,
1017 ADD, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1018 DUP,
1019 RCVT, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1021 ROLL, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1022 SWAP,
1023 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1024 DUP,
1025 ABS, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1027 DUP,
1028 PUSHB_1,
1030 LT, /* delta < 32 */
1032 POP,
1033 PUSHB_1,
1034 0, /* delta = 0 */
1036 ELSE,
1037 PUSHB_1,
1039 LT, /* delta < 48 */
1041 PUSHB_1,
1042 32, /* delta = 32 */
1044 ELSE,
1045 PUSHB_1,
1046 64, /* delta = 64 */
1047 EIF,
1048 EIF,
1050 SWAP, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1051 PUSHB_1,
1053 LT, /* dist < 0 */
1055 NEG, /* delta = -delta */
1056 EIF,
1058 PUSHB_1,
1060 CINDEX,
1061 SWAP,
1062 SUB, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1064 WCVTP,
1065 WCVTP,
1067 PUSHB_1,
1069 ADD, /* s: (ref_idx + 1) */
1071 ENDF,
1077 * bci_blue_round_range
1079 * Round a range of blue zones (both reference and shoot values).
1081 * This function gets used in the `prep' table.
1083 * in: num_blue_zones
1084 * blue_ref_idx
1086 * sal: sal_i (holds a copy of `num_blue_zones' for `bci_blue_round')
1088 * uses: bci_blue_round
1091 unsigned char FPGM(bci_blue_round_range) [] =
1094 PUSHB_1,
1095 bci_blue_round_range,
1096 FDEF,
1098 DUP,
1099 PUSHB_1,
1100 sal_i,
1101 SWAP,
1104 PUSHB_1,
1105 bci_blue_round,
1106 LOOPCALL,
1107 POP,
1109 ENDF,
1115 * bci_decrement_component_counter
1117 * An auxiliary function for composite glyphs.
1119 * CVT: cvtl_is_subglyph
1122 unsigned char FPGM(bci_decrement_component_counter) [] =
1125 PUSHB_1,
1126 bci_decrement_component_counter,
1127 FDEF,
1129 /* decrement `cvtl_is_subglyph' counter */
1130 PUSHB_2,
1131 cvtl_is_subglyph,
1132 cvtl_is_subglyph,
1133 RCVT,
1134 PUSHB_1,
1136 SUB,
1137 WCVTP,
1139 ENDF,
1145 * bci_get_point_extrema
1147 * An auxiliary function for `bci_create_segment'.
1149 * in: point-1
1151 * out: point
1153 * sal: sal_point_min
1154 * sal_point_max
1157 unsigned char FPGM(bci_get_point_extrema) [] =
1160 PUSHB_1,
1161 bci_get_point_extrema,
1162 FDEF,
1164 PUSHB_1,
1166 ADD, /* s: point */
1167 DUP,
1168 DUP,
1170 /* check whether `point' is a new minimum */
1171 PUSHB_1,
1172 sal_point_min,
1173 RS, /* s: point point point point_min */
1174 MD_orig,
1175 /* if distance is negative, we have a new minimum */
1176 PUSHB_1,
1179 IF, /* s: point point */
1180 DUP,
1181 PUSHB_1,
1182 sal_point_min,
1183 SWAP,
1185 EIF,
1187 /* check whether `point' is a new maximum */
1188 PUSHB_1,
1189 sal_point_max,
1190 RS, /* s: point point point_max */
1191 MD_orig,
1192 /* if distance is positive, we have a new maximum */
1193 PUSHB_1,
1196 IF, /* s: point */
1197 DUP,
1198 PUSHB_1,
1199 sal_point_max,
1200 SWAP,
1202 EIF, /* s: point */
1204 ENDF,
1210 * bci_nibbles
1212 * Pop a byte with two delta arguments in its nibbles and push the
1213 * expanded arguments separately as two bytes.
1215 * in: 16 * (end - start) + (start - base)
1217 * out: start
1218 * end
1220 * sal: sal_base (set to `end' at return)
1224 unsigned char FPGM(bci_nibbles) [] =
1226 PUSHB_1,
1227 bci_nibbles,
1228 FDEF,
1230 DUP,
1231 PUSHB_1, /* cf. DIV_POS_BY_2 macro */
1233 DIV,
1234 FLOOR,
1235 PUSHB_1,
1237 MUL, /* s: in hnibble */
1238 DUP,
1239 PUSHW_1,
1240 0x04, /* 16*64 */
1241 0x00,
1242 MUL, /* s: in hnibble (hnibble * 16) */
1243 ROLL,
1244 SWAP,
1245 SUB, /* s: hnibble lnibble */
1247 PUSHB_1,
1248 sal_base,
1250 ADD, /* s: hnibble start */
1251 DUP,
1252 ROLL,
1253 ADD, /* s: start end */
1255 DUP,
1256 PUSHB_1,
1257 sal_base,
1258 SWAP,
1259 WS, /* sal_base = end */
1261 SWAP,
1263 ENDF,
1269 * bci_number_set_is_element
1271 * Pop values from stack until it is empty. If one of them is equal to
1272 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
1273 * otherwise).
1275 * in: ppem_value_1
1276 * ppem_value_2
1277 * ...
1279 * CVT: cvtl_is_element
1282 unsigned char FPGM(bci_number_set_is_element) [] =
1285 PUSHB_1,
1286 bci_number_set_is_element,
1287 FDEF,
1289 /* start_loop: */
1290 MPPEM,
1293 PUSHB_2,
1294 cvtl_is_element,
1296 WCVTP,
1297 EIF,
1299 DEPTH,
1300 PUSHB_1,
1302 NEG,
1303 SWAP,
1304 JROT, /* goto start_loop if stack depth != 0 */
1306 ENDF,
1312 * bci_number_set_is_element2
1314 * Pop value ranges from stack until it is empty. If one of them contains
1315 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
1316 * otherwise).
1318 * in: ppem_range_1_start
1319 * ppem_range_1_end
1320 * ppem_range_2_start
1321 * ppem_range_2_end
1322 * ...
1324 * CVT: cvtl_is_element
1327 unsigned char FPGM(bci_number_set_is_element2) [] =
1330 PUSHB_1,
1331 bci_number_set_is_element2,
1332 FDEF,
1334 /* start_loop: */
1335 MPPEM,
1336 LTEQ,
1338 MPPEM,
1339 GTEQ,
1341 PUSHB_2,
1342 cvtl_is_element,
1344 WCVTP,
1345 EIF,
1346 ELSE,
1347 POP,
1348 EIF,
1350 DEPTH,
1351 PUSHB_1,
1353 NEG,
1354 SWAP,
1355 JROT, /* goto start_loop if stack depth != 0 */
1357 ENDF,
1363 * bci_create_segment
1365 * Store start and end point of a segment in the storage area,
1366 * then construct a point in the twilight zone to represent it.
1368 * This function is used by `bci_create_segments'.
1370 * in: start
1371 * end
1372 * [last (if wrap-around segment)]
1373 * [first (if wrap-around segment)]
1375 * sal: sal_i (start of current segment)
1376 * sal_j (current twilight point)
1377 * sal_point_min
1378 * sal_point_max
1379 * sal_base
1380 * sal_num_packed_segments
1381 * sal_scale
1383 * CVT: cvtl_temp
1385 * uses: bci_get_point_extrema
1386 * bci_nibbles
1388 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1389 * delta values in nibbles (without a wrap-around segment).
1392 unsigned char FPGM(bci_create_segment) [] =
1395 PUSHB_1,
1396 bci_create_segment,
1397 FDEF,
1399 PUSHB_2,
1401 sal_num_packed_segments,
1403 NEQ,
1405 PUSHB_2,
1406 sal_num_packed_segments,
1407 sal_num_packed_segments,
1409 PUSHB_1,
1411 SUB,
1412 WS, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1414 PUSHB_1,
1415 bci_nibbles,
1416 CALL,
1417 EIF,
1419 PUSHB_1,
1420 sal_i,
1422 PUSHB_1,
1424 CINDEX,
1425 WS, /* sal[sal_i] = start */
1427 /* initialize inner loop(s) */
1428 PUSHB_2,
1429 sal_point_min,
1431 CINDEX,
1432 WS, /* sal_point_min = start */
1433 PUSHB_2,
1434 sal_point_max,
1436 CINDEX,
1437 WS, /* sal_point_max = start */
1439 PUSHB_1,
1441 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
1443 SWAP,
1444 DUP,
1445 PUSHB_1,
1447 CINDEX, /* s: start end end start */
1448 LT, /* start > end */
1450 /* we have a wrap-around segment with two more arguments */
1451 /* to give the last and first point of the contour, respectively; */
1452 /* our job is to store a segment `start'-`last', */
1453 /* and to get extrema for the two segments */
1454 /* `start'-`last' and `first'-`end' */
1456 /* s: first last start end */
1457 PUSHB_2,
1459 sal_i,
1461 ADD,
1462 PUSHB_1,
1464 CINDEX,
1465 WS, /* sal[sal_i + 1] = last */
1467 ROLL,
1468 ROLL, /* s: first end last start */
1469 DUP,
1470 ROLL,
1471 SWAP, /* s: first end start last start */
1472 SUB, /* s: first end start loop_count */
1474 PUSHB_1,
1475 bci_get_point_extrema,
1476 LOOPCALL,
1477 /* clean up stack */
1478 POP,
1480 SWAP, /* s: end first */
1481 PUSHB_1,
1483 SUB,
1484 DUP,
1485 ROLL, /* s: (first - 1) (first - 1) end */
1486 SWAP,
1487 SUB, /* s: (first - 1) loop_count */
1489 PUSHB_1,
1490 bci_get_point_extrema,
1491 LOOPCALL,
1492 /* clean up stack */
1493 POP,
1495 ELSE, /* s: start end */
1496 PUSHB_2,
1498 sal_i,
1500 ADD,
1501 PUSHB_1,
1503 CINDEX,
1504 WS, /* sal[sal_i + 1] = end */
1506 PUSHB_1,
1508 CINDEX,
1509 SUB, /* s: start loop_count */
1511 PUSHB_1,
1512 bci_get_point_extrema,
1513 LOOPCALL,
1514 /* clean up stack */
1515 POP,
1516 EIF,
1518 /* the twilight point representing a segment */
1519 /* is in the middle between the minimum and maximum */
1520 PUSHB_1,
1521 sal_point_min,
1523 GC_orig,
1524 PUSHB_1,
1525 sal_point_max,
1527 GC_orig,
1528 ADD,
1529 DIV_BY_2, /* s: middle_pos */
1531 DO_SCALE, /* middle_pos = middle_pos * scale */
1533 /* write it to temporary CVT location */
1534 PUSHB_2,
1535 cvtl_temp,
1537 SZP0, /* set zp0 to twilight zone 0 */
1538 SWAP,
1539 WCVTP,
1541 /* create twilight point with index `sal_j' */
1542 PUSHB_1,
1543 sal_j,
1545 PUSHB_1,
1546 cvtl_temp,
1547 MIAP_noround,
1549 PUSHB_3,
1550 sal_j,
1552 sal_j,
1554 ADD, /* twilight_point = twilight_point + 1 */
1557 ENDF,
1563 * bci_create_segments
1565 * This is the top-level entry function.
1567 * It pops point ranges from the stack to define segments, computes
1568 * twilight points to represent segments, and finally calls
1569 * `bci_hint_glyph' to handle the rest.
1571 * The second argument (`data_offset') addresses three CVT arrays in
1572 * parallel:
1574 * CVT(data_offset):
1575 * the current script's scaling value (stored in `sal_scale')
1577 * data_offset + CVT(cvtl_num_used_scripts):
1578 * offset to the current script's vwidth index array (this value gets
1579 * stored in `sal_vwidth_data_offset')
1581 * data_offset + 2*CVT(cvtl_num_used_scripts):
1582 * offset to the current script's vwidth size
1584 * This addressing scheme ensures that (a) we only need a single argument,
1585 * and (b) this argument supports up to (256-cvtl_max_runtime) scripts,
1586 * which should be sufficient for a long time.
1588 * in: num_packed_segments
1589 * data_offset
1590 * num_segments (N)
1591 * segment_start_0
1592 * segment_end_0
1593 * [contour_last 0 (if wrap-around segment)]
1594 * [contour_first 0 (if wrap-around segment)]
1595 * segment_start_1
1596 * segment_end_1
1597 * [contour_last 0 (if wrap-around segment)]
1598 * [contour_first 0 (if wrap-around segment)]
1599 * ...
1600 * segment_start_(N-1)
1601 * segment_end_(N-1)
1602 * [contour_last (N-1) (if wrap-around segment)]
1603 * [contour_first (N-1) (if wrap-around segment)]
1604 * ... stuff for bci_hint_glyph ...
1606 * sal: sal_i (start of current segment)
1607 * sal_j (current twilight point)
1608 * sal_num_packed_segments
1609 * sal_base (the base for delta values in nibbles)
1610 * sal_vwidth_data_offset
1611 * sal_scale
1613 * CVT: cvtl_is_subglyph
1615 * uses: bci_create_segment
1616 * bci_loop
1617 * bci_hint_glyph
1619 * If `num_packed_segments' is set to p, the first p start/end pairs are
1620 * stored as delta values in nibbles, with the `start' delta in the lower
1621 * nibble (and there are no wrap-around segments). For example, if the
1622 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1623 * stack are 0x21, 0x32, and 0x14.
1627 unsigned char FPGM(bci_create_segments) [] =
1630 PUSHB_1,
1631 bci_create_segments,
1632 FDEF,
1634 /* only do something if we are not a subglyph */
1635 PUSHB_2,
1637 cvtl_is_subglyph,
1638 RCVT,
1641 /* all our measurements are taken along the y axis */
1642 SVTCA_y,
1644 PUSHB_1,
1645 sal_num_packed_segments,
1646 SWAP,
1649 DUP,
1650 RCVT,
1651 PUSHB_1,
1652 sal_scale, /* sal_scale = CVT(data_offset) */
1653 SWAP,
1656 PUSHB_1,
1657 sal_vwidth_data_offset,
1658 SWAP,
1659 PUSHB_1,
1660 cvtl_num_used_scripts,
1661 RCVT,
1662 ADD,
1663 WS, /* sal_vwidth_data_offset = data_offset + num_used_scripts */
1665 DUP,
1666 ADD,
1667 PUSHB_1,
1669 SUB, /* delta = (2*num_segments - 1) */
1671 PUSHB_6,
1672 sal_segment_offset,
1673 sal_segment_offset,
1675 sal_j,
1677 sal_base,
1679 WS, /* sal_base = 0 */
1680 WS, /* sal_j = 0 (point offset) */
1682 ROLL,
1683 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1685 PUSHB_2,
1686 bci_create_segment,
1687 bci_loop,
1688 CALL,
1690 PUSHB_1,
1691 bci_hint_glyph,
1692 CALL,
1694 ELSE,
1695 CLEAR,
1696 EIF,
1698 ENDF,
1704 * bci_create_segments_X
1706 * Top-level routines for calling `bci_create_segments'.
1709 unsigned char FPGM(bci_create_segments_0) [] =
1712 PUSHB_1,
1713 bci_create_segments_0,
1714 FDEF,
1716 PUSHB_2,
1718 bci_create_segments,
1719 CALL,
1721 ENDF,
1725 unsigned char FPGM(bci_create_segments_1) [] =
1728 PUSHB_1,
1729 bci_create_segments_1,
1730 FDEF,
1732 PUSHB_2,
1734 bci_create_segments,
1735 CALL,
1737 ENDF,
1741 unsigned char FPGM(bci_create_segments_2) [] =
1744 PUSHB_1,
1745 bci_create_segments_2,
1746 FDEF,
1748 PUSHB_2,
1750 bci_create_segments,
1751 CALL,
1753 ENDF,
1757 unsigned char FPGM(bci_create_segments_3) [] =
1760 PUSHB_1,
1761 bci_create_segments_3,
1762 FDEF,
1764 PUSHB_2,
1766 bci_create_segments,
1767 CALL,
1769 ENDF,
1773 unsigned char FPGM(bci_create_segments_4) [] =
1776 PUSHB_1,
1777 bci_create_segments_4,
1778 FDEF,
1780 PUSHB_2,
1782 bci_create_segments,
1783 CALL,
1785 ENDF,
1789 unsigned char FPGM(bci_create_segments_5) [] =
1792 PUSHB_1,
1793 bci_create_segments_5,
1794 FDEF,
1796 PUSHB_2,
1798 bci_create_segments,
1799 CALL,
1801 ENDF,
1805 unsigned char FPGM(bci_create_segments_6) [] =
1808 PUSHB_1,
1809 bci_create_segments_6,
1810 FDEF,
1812 PUSHB_2,
1814 bci_create_segments,
1815 CALL,
1817 ENDF,
1821 unsigned char FPGM(bci_create_segments_7) [] =
1824 PUSHB_1,
1825 bci_create_segments_7,
1826 FDEF,
1828 PUSHB_2,
1830 bci_create_segments,
1831 CALL,
1833 ENDF,
1837 unsigned char FPGM(bci_create_segments_8) [] =
1840 PUSHB_1,
1841 bci_create_segments_8,
1842 FDEF,
1844 PUSHB_2,
1846 bci_create_segments,
1847 CALL,
1849 ENDF,
1853 unsigned char FPGM(bci_create_segments_9) [] =
1856 PUSHB_1,
1857 bci_create_segments_9,
1858 FDEF,
1860 PUSHB_2,
1862 bci_create_segments,
1863 CALL,
1865 ENDF,
1871 * bci_create_segments_composite
1873 * The same as `bci_create_segments'.
1874 * It also decrements the composite component counter.
1876 * sal: sal_num_packed_segments
1877 * sal_segment_offset
1878 * sal_vwidth_data_offset
1880 * CVT: cvtl_is_subglyph
1882 * uses: bci_decrement_component_counter
1883 * bci_create_segment
1884 * bci_loop
1885 * bci_hint_glyph
1888 unsigned char FPGM(bci_create_segments_composite) [] =
1891 PUSHB_1,
1892 bci_create_segments_composite,
1893 FDEF,
1895 PUSHB_1,
1896 bci_decrement_component_counter,
1897 CALL,
1899 /* only do something if we are not a subglyph */
1900 PUSHB_2,
1902 cvtl_is_subglyph,
1903 RCVT,
1906 /* all our measurements are taken along the y axis */
1907 SVTCA_y,
1909 PUSHB_1,
1910 sal_num_packed_segments,
1911 SWAP,
1914 DUP,
1915 RCVT,
1916 PUSHB_1,
1917 sal_scale, /* sal_scale = CVT(data_offset) */
1918 SWAP,
1921 PUSHB_1,
1922 sal_vwidth_data_offset,
1923 SWAP,
1924 PUSHB_1,
1925 cvtl_num_used_scripts,
1926 RCVT,
1927 ADD,
1928 WS, /* sal_vwidth_data_offset = data_offset + num_used_scripts */
1930 DUP,
1931 ADD,
1932 PUSHB_1,
1934 SUB, /* delta = (2*num_segments - 1) */
1936 PUSHB_6,
1937 sal_segment_offset,
1938 sal_segment_offset,
1940 sal_j,
1942 sal_base,
1944 WS, /* sal_base = 0 */
1945 WS, /* sal_j = 0 (point offset) */
1947 ROLL,
1948 ADD, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1950 PUSHB_2,
1951 bci_create_segment,
1952 bci_loop,
1953 CALL,
1955 PUSHB_1,
1956 bci_hint_glyph,
1957 CALL,
1959 ELSE,
1960 CLEAR,
1961 EIF,
1963 ENDF,
1969 * bci_create_segments_composite_X
1971 * Top-level routines for calling `bci_create_segments_composite'.
1974 unsigned char FPGM(bci_create_segments_composite_0) [] =
1977 PUSHB_1,
1978 bci_create_segments_composite_0,
1979 FDEF,
1981 PUSHB_2,
1983 bci_create_segments_composite,
1984 CALL,
1986 ENDF,
1990 unsigned char FPGM(bci_create_segments_composite_1) [] =
1993 PUSHB_1,
1994 bci_create_segments_composite_1,
1995 FDEF,
1997 PUSHB_2,
1999 bci_create_segments_composite,
2000 CALL,
2002 ENDF,
2006 unsigned char FPGM(bci_create_segments_composite_2) [] =
2009 PUSHB_1,
2010 bci_create_segments_composite_2,
2011 FDEF,
2013 PUSHB_2,
2015 bci_create_segments_composite,
2016 CALL,
2018 ENDF,
2022 unsigned char FPGM(bci_create_segments_composite_3) [] =
2025 PUSHB_1,
2026 bci_create_segments_composite_3,
2027 FDEF,
2029 PUSHB_2,
2031 bci_create_segments_composite,
2032 CALL,
2034 ENDF,
2038 unsigned char FPGM(bci_create_segments_composite_4) [] =
2041 PUSHB_1,
2042 bci_create_segments_composite_4,
2043 FDEF,
2045 PUSHB_2,
2047 bci_create_segments_composite,
2048 CALL,
2050 ENDF,
2054 unsigned char FPGM(bci_create_segments_composite_5) [] =
2057 PUSHB_1,
2058 bci_create_segments_composite_5,
2059 FDEF,
2061 PUSHB_2,
2063 bci_create_segments_composite,
2064 CALL,
2066 ENDF,
2070 unsigned char FPGM(bci_create_segments_composite_6) [] =
2073 PUSHB_1,
2074 bci_create_segments_composite_6,
2075 FDEF,
2077 PUSHB_2,
2079 bci_create_segments_composite,
2080 CALL,
2082 ENDF,
2086 unsigned char FPGM(bci_create_segments_composite_7) [] =
2089 PUSHB_1,
2090 bci_create_segments_composite_7,
2091 FDEF,
2093 PUSHB_2,
2095 bci_create_segments_composite,
2096 CALL,
2098 ENDF,
2102 unsigned char FPGM(bci_create_segments_composite_8) [] =
2105 PUSHB_1,
2106 bci_create_segments_composite_8,
2107 FDEF,
2109 PUSHB_2,
2111 bci_create_segments_composite,
2112 CALL,
2114 ENDF,
2118 unsigned char FPGM(bci_create_segments_composite_9) [] =
2121 PUSHB_1,
2122 bci_create_segments_composite_9,
2123 FDEF,
2125 PUSHB_2,
2127 bci_create_segments_composite,
2128 CALL,
2130 ENDF,
2136 * bci_align_point
2138 * An auxiliary function for `bci_align_segment'.
2140 * in: point
2142 * out: point+1
2145 unsigned char FPGM(bci_align_point) [] =
2148 PUSHB_1,
2149 bci_align_point,
2150 FDEF,
2152 DUP,
2153 ALIGNRP, /* align point with rp0 */
2155 PUSHB_1,
2157 ADD,
2159 ENDF,
2165 * bci_align_segment
2167 * Align all points in a segment to the twilight point in rp0.
2168 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2170 * in: segment_index
2172 * sal: sal_segment_offset
2174 * uses: bci_align_point
2177 unsigned char FPGM(bci_align_segment) [] =
2180 PUSHB_1,
2181 bci_align_segment,
2182 FDEF,
2184 /* we need the values of `sal_segment_offset + 2*segment_index' */
2185 /* and `sal_segment_offset + 2*segment_index + 1' */
2186 DUP,
2187 ADD,
2188 PUSHB_1,
2189 sal_segment_offset,
2190 ADD,
2191 DUP,
2193 SWAP,
2194 PUSHB_1,
2196 ADD,
2197 RS, /* s: first last */
2199 PUSHB_1,
2201 CINDEX, /* s: first last first */
2202 SUB,
2203 PUSHB_1,
2205 ADD, /* s: first loop_count */
2207 PUSHB_1,
2208 bci_align_point,
2209 LOOPCALL,
2210 /* clean up stack */
2211 POP,
2213 ENDF,
2219 * bci_align_segments
2221 * Align segments to the twilight point in rp0.
2222 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2224 * in: first_segment
2225 * loop_counter (N)
2226 * segment_1
2227 * segment_2
2228 * ...
2229 * segment_N
2231 * uses: bci_align_segment
2234 unsigned char FPGM(bci_align_segments) [] =
2237 PUSHB_1,
2238 bci_align_segments,
2239 FDEF,
2241 PUSHB_1,
2242 bci_align_segment,
2243 CALL,
2245 PUSHB_1,
2246 bci_align_segment,
2247 LOOPCALL,
2249 ENDF,
2255 * bci_scale_contour
2257 * Scale a contour using two points giving the maximum and minimum
2258 * coordinates.
2260 * It expects that no point on the contour is touched.
2262 * in: min_point
2263 * max_point
2265 * sal: sal_scale
2268 unsigned char FPGM(bci_scale_contour) [] =
2271 PUSHB_1,
2272 bci_scale_contour,
2273 FDEF,
2275 DUP,
2276 DUP,
2277 GC_orig,
2278 DUP,
2279 DO_SCALE, /* min_pos_new = min_pos * scale */
2280 SWAP,
2281 SUB,
2282 SHPIX,
2284 /* don't scale a single-point contour twice */
2285 SWAP,
2286 DUP,
2287 ROLL,
2288 NEQ,
2290 DUP,
2291 GC_orig,
2292 DUP,
2293 DO_SCALE, /* max_pos_new = max_pos * scale */
2294 SWAP,
2295 SUB,
2296 SHPIX,
2298 ELSE,
2299 POP,
2300 EIF,
2302 ENDF,
2308 * bci_scale_glyph
2310 * Scale a glyph using a list of points (two points per contour, giving
2311 * the maximum and mininum coordinates).
2313 * It expects that no point in the glyph is touched.
2315 * Note that the point numbers are sorted in ascending order;
2316 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2317 * contour without specifying which one is the minimum and maximum.
2319 * in: num_contours (N)
2320 * min_point_1
2321 * max_point_1
2322 * min_point_2
2323 * max_point_2
2324 * ...
2325 * min_point_N
2326 * max_point_N
2328 * CVT: cvtl_is_subglyph
2330 * uses: bci_scale_contour
2333 unsigned char FPGM(bci_scale_glyph) [] =
2336 PUSHB_1,
2337 bci_scale_glyph,
2338 FDEF,
2340 /* only do something if we are not a subglyph */
2341 PUSHB_2,
2343 cvtl_is_subglyph,
2344 RCVT,
2347 /* all our measurements are taken along the y axis */
2348 SVTCA_y,
2350 PUSHB_1,
2352 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2354 PUSHB_1,
2355 bci_scale_contour,
2356 LOOPCALL,
2358 PUSHB_1,
2360 SZP2, /* set zp2 to normal zone 1 */
2361 IUP_y,
2363 ELSE,
2364 CLEAR,
2365 EIF,
2367 ENDF,
2373 * bci_scale_composite_glyph
2375 * The same as `bci_scale_glyph'.
2376 * It also decrements the composite component counter.
2378 * CVT: cvtl_is_subglyph
2380 * uses: bci_decrement_component_counter
2381 * bci_scale_contour
2384 unsigned char FPGM(bci_scale_composite_glyph) [] =
2387 PUSHB_1,
2388 bci_scale_composite_glyph,
2389 FDEF,
2391 PUSHB_1,
2392 bci_decrement_component_counter,
2393 CALL,
2395 /* only do something if we are not a subglyph */
2396 PUSHB_2,
2398 cvtl_is_subglyph,
2399 RCVT,
2402 /* all our measurements are taken along the y axis */
2403 SVTCA_y,
2405 PUSHB_1,
2407 SZPS, /* set zp0, zp1, and zp2 to normal zone 1 */
2409 PUSHB_1,
2410 bci_scale_contour,
2411 LOOPCALL,
2413 PUSHB_1,
2415 SZP2, /* set zp2 to normal zone 1 */
2416 IUP_y,
2418 ELSE,
2419 CLEAR,
2420 EIF,
2422 ENDF,
2428 * bci_shift_contour
2430 * Shift a contour by a given amount.
2432 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2433 * point to the normal zone 1.
2435 * in: contour
2437 * out: contour+1
2440 unsigned char FPGM(bci_shift_contour) [] =
2443 PUSHB_1,
2444 bci_shift_contour,
2445 FDEF,
2447 DUP,
2448 SHC_rp1, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2450 PUSHB_1,
2452 ADD,
2454 ENDF,
2460 * bci_shift_subglyph
2462 * Shift a subglyph. To be more specific, it corrects the already applied
2463 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2464 * also.
2466 * If this function is called, a point `x' in the subglyph has been scaled
2467 * already (during the hinting of the subglyph itself), and `offset' has
2468 * been applied also:
2470 * x -> x * scale + offset (1)
2472 * However, the offset should be applied first, then the scaling:
2474 * x -> (x + offset) * scale (2)
2476 * Our job is now to transform (1) to (2); a simple calculation shows that
2477 * we have to shift all points of the subglyph by
2479 * offset * scale - offset = offset * (scale - 1)
2481 * Note that `sal_scale' is equal to the above `scale - 1'.
2483 * in: offset (in FUnits)
2484 * num_contours
2485 * first_contour
2487 * CVT: cvtl_funits_to_pixels
2489 * sal: sal_scale
2491 * uses: bci_round
2492 * bci_shift_contour
2495 unsigned char FPGM(bci_shift_subglyph) [] =
2498 PUSHB_1,
2499 bci_shift_subglyph,
2500 FDEF,
2502 SVTCA_y,
2504 PUSHB_1,
2505 cvtl_funits_to_pixels,
2506 RCVT, /* scaling factor FUnits -> pixels */
2507 MUL,
2508 DIV_BY_1024,
2510 /* the autohinter always rounds offsets */
2511 PUSHB_1,
2512 bci_round,
2513 CALL, /* offset = round(offset) */
2515 PUSHB_1,
2516 sal_scale,
2518 MUL,
2519 DIV_BY_1024, /* delta = offset * (scale - 1) */
2521 /* and round again */
2522 PUSHB_1,
2523 bci_round,
2524 CALL, /* offset = round(offset) */
2526 PUSHB_1,
2528 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2530 /* we create twilight point 0 as a reference point, */
2531 /* setting the original position to zero (using `cvtl_temp') */
2532 PUSHB_5,
2535 cvtl_temp,
2536 cvtl_temp,
2538 WCVTP,
2539 MIAP_noround, /* rp0 and rp1 now point to twilight point 0 */
2541 SWAP, /* s: first_contour num_contours 0 delta */
2542 SHPIX, /* rp1_pos - rp1_orig_pos = delta */
2544 PUSHB_2,
2545 bci_shift_contour,
2547 SZP2, /* set zp2 to normal zone 1 */
2548 LOOPCALL,
2550 ENDF,
2556 * bci_ip_outer_align_point
2558 * Auxiliary function for `bci_action_ip_before' and
2559 * `bci_action_ip_after'.
2561 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2562 * zone, and both zp1 and zp2 set to normal zone.
2564 * in: point
2566 * sal: sal_i (edge_orig_pos)
2567 * sal_scale
2570 unsigned char FPGM(bci_ip_outer_align_point) [] =
2573 PUSHB_1,
2574 bci_ip_outer_align_point,
2575 FDEF,
2577 DUP,
2578 ALIGNRP, /* align `point' with `edge' */
2579 DUP,
2580 GC_orig,
2581 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2583 PUSHB_1,
2584 sal_i,
2586 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2587 SHPIX,
2589 ENDF,
2595 * bci_ip_on_align_points
2597 * Auxiliary function for `bci_action_ip_on'.
2599 * in: edge (in twilight zone)
2600 * loop_counter (N)
2601 * point_1
2602 * point_2
2603 * ...
2604 * point_N
2607 unsigned char FPGM(bci_ip_on_align_points) [] =
2610 PUSHB_1,
2611 bci_ip_on_align_points,
2612 FDEF,
2614 MDAP_noround, /* set rp0 and rp1 to `edge' */
2616 SLOOP,
2617 ALIGNRP,
2619 ENDF,
2625 * bci_ip_between_align_point
2627 * Auxiliary function for `bci_ip_between_align_points'.
2629 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2630 * zone, and both zp1 and zp2 set to normal zone.
2632 * in: point
2634 * sal: sal_i (edge_orig_pos)
2635 * sal_j (stretch_factor)
2636 * sal_scale
2639 unsigned char FPGM(bci_ip_between_align_point) [] =
2642 PUSHB_1,
2643 bci_ip_between_align_point,
2644 FDEF,
2646 DUP,
2647 ALIGNRP, /* align `point' with `edge' */
2648 DUP,
2649 GC_orig,
2650 DO_SCALE, /* point_orig_pos = point_orig_pos * scale */
2652 PUSHB_1,
2653 sal_i,
2655 SUB, /* s: point (point_orig_pos - edge_orig_pos) */
2656 PUSHB_1,
2657 sal_j,
2659 MUL, /* s: point delta */
2660 SHPIX,
2662 ENDF,
2668 * bci_ip_between_align_points
2670 * Auxiliary function for `bci_action_ip_between'.
2672 * in: after_edge (in twilight zone)
2673 * before_edge (in twilight zone)
2674 * loop_counter (N)
2675 * point_1
2676 * point_2
2677 * ...
2678 * point_N
2680 * sal: sal_i (before_orig_pos)
2681 * sal_j (stretch_factor)
2683 * uses: bci_ip_between_align_point
2686 unsigned char FPGM(bci_ip_between_align_points) [] =
2689 PUSHB_1,
2690 bci_ip_between_align_points,
2691 FDEF,
2693 PUSHB_2,
2696 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2697 CINDEX,
2698 DUP, /* s: ... before after before before */
2699 MDAP_noround, /* set rp0 and rp1 to `before' */
2700 DUP,
2701 GC_orig, /* s: ... before after before before_orig_pos */
2702 PUSHB_1,
2703 sal_i,
2704 SWAP,
2705 WS, /* sal_i = before_orig_pos */
2706 PUSHB_1,
2708 CINDEX, /* s: ... before after before after */
2709 MD_cur, /* a = after_pos - before_pos */
2710 ROLL,
2711 ROLL,
2712 MD_orig_ZP2_0, /* b = after_orig_pos - before_orig_pos */
2714 DUP,
2715 IF, /* b != 0 ? */
2716 DIV, /* s: a/b */
2717 ELSE,
2718 POP, /* avoid division by zero */
2719 EIF,
2721 PUSHB_1,
2722 sal_j,
2723 SWAP,
2724 WS, /* sal_j = stretch_factor */
2726 PUSHB_3,
2727 bci_ip_between_align_point,
2730 SZP2, /* set zp2 to normal zone 1 */
2731 SZP1, /* set zp1 to normal zone 1 */
2732 LOOPCALL,
2734 ENDF,
2740 * bci_action_ip_before
2742 * Handle `ip_before' data to align points located before the first edge.
2744 * in: first_edge (in twilight zone)
2745 * loop_counter (N)
2746 * point_1
2747 * point_2
2748 * ...
2749 * point_N
2751 * sal: sal_i (first_edge_orig_pos)
2753 * uses: bci_ip_outer_align_point
2756 unsigned char FPGM(bci_action_ip_before) [] =
2759 PUSHB_1,
2760 bci_action_ip_before,
2761 FDEF,
2763 PUSHB_1,
2765 SZP2, /* set zp2 to twilight zone 0 */
2767 DUP,
2768 GC_orig,
2769 PUSHB_1,
2770 sal_i,
2771 SWAP,
2772 WS, /* sal_i = first_edge_orig_pos */
2774 PUSHB_3,
2778 SZP2, /* set zp2 to normal zone 1 */
2779 SZP1, /* set zp1 to normal zone 1 */
2780 SZP0, /* set zp0 to twilight zone 0 */
2782 MDAP_noround, /* set rp0 and rp1 to `first_edge' */
2784 PUSHB_1,
2785 bci_ip_outer_align_point,
2786 LOOPCALL,
2788 ENDF,
2794 * bci_action_ip_after
2796 * Handle `ip_after' data to align points located after the last edge.
2798 * in: last_edge (in twilight zone)
2799 * loop_counter (N)
2800 * point_1
2801 * point_2
2802 * ...
2803 * point_N
2805 * sal: sal_i (last_edge_orig_pos)
2807 * uses: bci_ip_outer_align_point
2810 unsigned char FPGM(bci_action_ip_after) [] =
2813 PUSHB_1,
2814 bci_action_ip_after,
2815 FDEF,
2817 PUSHB_1,
2819 SZP2, /* set zp2 to twilight zone 0 */
2821 DUP,
2822 GC_orig,
2823 PUSHB_1,
2824 sal_i,
2825 SWAP,
2826 WS, /* sal_i = last_edge_orig_pos */
2828 PUSHB_3,
2832 SZP2, /* set zp2 to normal zone 1 */
2833 SZP1, /* set zp1 to normal zone 1 */
2834 SZP0, /* set zp0 to twilight zone 0 */
2836 MDAP_noround, /* set rp0 and rp1 to `last_edge' */
2838 PUSHB_1,
2839 bci_ip_outer_align_point,
2840 LOOPCALL,
2842 ENDF,
2848 * bci_action_ip_on
2850 * Handle `ip_on' data to align points located on an edge coordinate (but
2851 * not part of an edge).
2853 * in: loop_counter (M)
2854 * edge_1 (in twilight zone)
2855 * loop_counter (N_1)
2856 * point_1
2857 * point_2
2858 * ...
2859 * point_N_1
2860 * edge_2 (in twilight zone)
2861 * loop_counter (N_2)
2862 * point_1
2863 * point_2
2864 * ...
2865 * point_N_2
2866 * ...
2867 * edge_M (in twilight zone)
2868 * loop_counter (N_M)
2869 * point_1
2870 * point_2
2871 * ...
2872 * point_N_M
2874 * uses: bci_ip_on_align_points
2877 unsigned char FPGM(bci_action_ip_on) [] =
2880 PUSHB_1,
2881 bci_action_ip_on,
2882 FDEF,
2884 PUSHB_2,
2887 SZP1, /* set zp1 to normal zone 1 */
2888 SZP0, /* set zp0 to twilight zone 0 */
2890 PUSHB_1,
2891 bci_ip_on_align_points,
2892 LOOPCALL,
2894 ENDF,
2900 * bci_action_ip_between
2902 * Handle `ip_between' data to align points located between two edges.
2904 * in: loop_counter (M)
2905 * before_edge_1 (in twilight zone)
2906 * after_edge_1 (in twilight zone)
2907 * loop_counter (N_1)
2908 * point_1
2909 * point_2
2910 * ...
2911 * point_N_1
2912 * before_edge_2 (in twilight zone)
2913 * after_edge_2 (in twilight zone)
2914 * loop_counter (N_2)
2915 * point_1
2916 * point_2
2917 * ...
2918 * point_N_2
2919 * ...
2920 * before_edge_M (in twilight zone)
2921 * after_edge_M (in twilight zone)
2922 * loop_counter (N_M)
2923 * point_1
2924 * point_2
2925 * ...
2926 * point_N_M
2928 * uses: bci_ip_between_align_points
2931 unsigned char FPGM(bci_action_ip_between) [] =
2934 PUSHB_1,
2935 bci_action_ip_between,
2936 FDEF,
2938 PUSHB_1,
2939 bci_ip_between_align_points,
2940 LOOPCALL,
2942 ENDF,
2948 * bci_adjust_common
2950 * Common code for bci_action_adjust routines.
2952 * uses: func[cvtl_stem_width_function]
2955 unsigned char FPGM(bci_adjust_common) [] =
2958 PUSHB_1,
2959 bci_adjust_common,
2960 FDEF,
2962 PUSHB_1,
2964 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
2966 PUSHB_1,
2968 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 */
2969 PUSHB_1,
2971 CINDEX, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2972 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
2974 PUSHB_1,
2975 cvtl_stem_width_function,
2976 RCVT,
2977 CALL,
2978 NEG, /* s: [...] edge2 edge -cur_len */
2980 ROLL, /* s: [...] edge -cur_len edge2 */
2981 MDAP_noround, /* set rp0 and rp1 to `edge2' */
2982 SWAP,
2983 DUP,
2984 DUP, /* s: [...] -cur_len edge edge edge */
2985 ALIGNRP, /* align `edge' with `edge2' */
2986 ROLL,
2987 SHPIX, /* shift `edge' by -cur_len */
2989 ENDF,
2995 * bci_adjust_bound
2997 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2998 * edge of the stem has already been moved, then moving it again if
2999 * necessary to stay bound.
3001 * in: edge2_is_serif
3002 * edge_is_round
3003 * edge_point (in twilight zone)
3004 * edge2_point (in twilight zone)
3005 * edge[-1] (in twilight zone)
3006 * ... stuff for bci_align_segments (edge) ...
3008 * uses: bci_adjust_common
3009 * bci_align_segments
3012 unsigned char FPGM(bci_adjust_bound) [] =
3015 PUSHB_1,
3016 bci_adjust_bound,
3017 FDEF,
3019 PUSHB_1,
3020 bci_adjust_common,
3021 CALL,
3023 SWAP, /* s: edge edge[-1] */
3024 DUP,
3025 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3026 GC_cur,
3027 PUSHB_1,
3029 CINDEX,
3030 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3031 GT, /* edge_pos < edge[-1]_pos */
3033 DUP,
3034 ALIGNRP, /* align `edge' to `edge[-1]' */
3035 EIF,
3037 MDAP_noround, /* set rp0 and rp1 to `edge' */
3039 PUSHB_2,
3040 bci_align_segments,
3042 SZP1, /* set zp1 to normal zone 1 */
3043 CALL,
3045 ENDF,
3051 * bci_action_adjust_bound
3052 * bci_action_adjust_bound_serif
3053 * bci_action_adjust_bound_round
3054 * bci_action_adjust_bound_round_serif
3056 * Higher-level routines for calling `bci_adjust_bound'.
3059 unsigned char FPGM(bci_action_adjust_bound) [] =
3062 PUSHB_1,
3063 bci_action_adjust_bound,
3064 FDEF,
3066 PUSHB_3,
3069 bci_adjust_bound,
3070 CALL,
3072 ENDF,
3076 unsigned char FPGM(bci_action_adjust_bound_serif) [] =
3079 PUSHB_1,
3080 bci_action_adjust_bound_serif,
3081 FDEF,
3083 PUSHB_3,
3086 bci_adjust_bound,
3087 CALL,
3089 ENDF,
3093 unsigned char FPGM(bci_action_adjust_bound_round) [] =
3096 PUSHB_1,
3097 bci_action_adjust_bound_round,
3098 FDEF,
3100 PUSHB_3,
3103 bci_adjust_bound,
3104 CALL,
3106 ENDF,
3110 unsigned char FPGM(bci_action_adjust_bound_round_serif) [] =
3113 PUSHB_1,
3114 bci_action_adjust_bound_round_serif,
3115 FDEF,
3117 PUSHB_3,
3120 bci_adjust_bound,
3121 CALL,
3123 ENDF,
3129 * bci_adjust
3131 * Handle the ADJUST action to align an edge of a stem if the other edge
3132 * of the stem has already been moved.
3134 * in: edge2_is_serif
3135 * edge_is_round
3136 * edge_point (in twilight zone)
3137 * edge2_point (in twilight zone)
3138 * ... stuff for bci_align_segments (edge) ...
3140 * uses: bci_adjust_common
3141 * bci_align_segments
3144 unsigned char FPGM(bci_adjust) [] =
3147 PUSHB_1,
3148 bci_adjust,
3149 FDEF,
3151 PUSHB_1,
3152 bci_adjust_common,
3153 CALL,
3155 MDAP_noround, /* set rp0 and rp1 to `edge' */
3157 PUSHB_2,
3158 bci_align_segments,
3160 SZP1, /* set zp1 to normal zone 1 */
3161 CALL,
3163 ENDF,
3169 * bci_action_adjust
3170 * bci_action_adjust_serif
3171 * bci_action_adjust_round
3172 * bci_action_adjust_round_serif
3174 * Higher-level routines for calling `bci_adjust'.
3177 unsigned char FPGM(bci_action_adjust) [] =
3180 PUSHB_1,
3181 bci_action_adjust,
3182 FDEF,
3184 PUSHB_3,
3187 bci_adjust,
3188 CALL,
3190 ENDF,
3194 unsigned char FPGM(bci_action_adjust_serif) [] =
3197 PUSHB_1,
3198 bci_action_adjust_serif,
3199 FDEF,
3201 PUSHB_3,
3204 bci_adjust,
3205 CALL,
3207 ENDF,
3211 unsigned char FPGM(bci_action_adjust_round) [] =
3214 PUSHB_1,
3215 bci_action_adjust_round,
3216 FDEF,
3218 PUSHB_3,
3221 bci_adjust,
3222 CALL,
3224 ENDF,
3228 unsigned char FPGM(bci_action_adjust_round_serif) [] =
3231 PUSHB_1,
3232 bci_action_adjust_round_serif,
3233 FDEF,
3235 PUSHB_3,
3238 bci_adjust,
3239 CALL,
3241 ENDF,
3247 * bci_stem_common
3249 * Common code for bci_action_stem routines.
3251 * sal: sal_anchor
3252 * sal_temp1
3253 * sal_temp2
3254 * sal_temp3
3256 * uses: func[cvtl_stem_width_function]
3257 * bci_round
3260 #undef sal_u_off
3261 #define sal_u_off sal_temp1
3262 #undef sal_d_off
3263 #define sal_d_off sal_temp2
3264 #undef sal_org_len
3265 #define sal_org_len sal_temp3
3266 #undef sal_edge2
3267 #define sal_edge2 sal_temp3
3269 unsigned char FPGM(bci_stem_common) [] =
3272 PUSHB_1,
3273 bci_stem_common,
3274 FDEF,
3276 PUSHB_1,
3278 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3280 PUSHB_1,
3282 CINDEX,
3283 PUSHB_1,
3285 CINDEX,
3286 DUP, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3287 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3289 MD_orig_ZP2_0, /* s: [...] edge2 edge is_round is_serif org_len */
3290 DUP,
3291 PUSHB_1,
3292 sal_org_len,
3293 SWAP,
3296 PUSHB_1,
3297 cvtl_stem_width_function,
3298 RCVT,
3299 CALL, /* s: [...] edge2 edge cur_len */
3301 DUP,
3302 PUSHB_1,
3304 LT, /* cur_len < 96 */
3306 DUP,
3307 PUSHB_1,
3309 LTEQ, /* cur_len <= 64 */
3311 PUSHB_4,
3312 sal_u_off,
3314 sal_d_off,
3317 ELSE,
3318 PUSHB_4,
3319 sal_u_off,
3321 sal_d_off,
3323 EIF,
3327 SWAP, /* s: [...] edge2 cur_len edge */
3328 DUP,
3329 PUSHB_1,
3330 sal_anchor,
3332 DUP, /* s: [...] edge2 cur_len edge edge anchor anchor */
3333 ROLL,
3334 SWAP,
3335 MD_orig_ZP2_0,
3336 SWAP,
3337 GC_cur,
3338 ADD, /* s: [...] edge2 cur_len edge org_pos */
3339 PUSHB_1,
3340 sal_org_len,
3342 DIV_BY_2,
3343 ADD, /* s: [...] edge2 cur_len edge org_center */
3345 DUP,
3346 PUSHB_1,
3347 bci_round,
3348 CALL, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3350 DUP,
3351 ROLL,
3352 ROLL,
3353 SUB, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3355 DUP,
3356 PUSHB_1,
3357 sal_u_off,
3359 ADD,
3360 ABS, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3362 SWAP,
3363 PUSHB_1,
3364 sal_d_off,
3366 SUB,
3367 ABS, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3369 LT, /* delta1 < delta2 */
3371 PUSHB_1,
3372 sal_u_off,
3374 SUB, /* cur_pos1 = cur_pos1 - u_off */
3376 ELSE,
3377 PUSHB_1,
3378 sal_d_off,
3380 ADD, /* cur_pos1 = cur_pos1 + d_off */
3381 EIF, /* s: [...] edge2 cur_len edge cur_pos1 */
3383 PUSHB_1,
3385 CINDEX,
3386 DIV_BY_2,
3387 SUB, /* arg = cur_pos1 - cur_len/2 */
3389 SWAP, /* s: [...] edge2 cur_len arg edge */
3390 DUP,
3391 DUP,
3392 PUSHB_1,
3394 MINDEX,
3395 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3396 GC_cur,
3397 SUB,
3398 SHPIX, /* edge = cur_pos1 - cur_len/2 */
3400 ELSE,
3401 SWAP, /* s: [...] edge2 cur_len edge */
3402 PUSHB_1,
3403 sal_anchor,
3405 GC_cur, /* s: [...] edge2 cur_len edge anchor_pos */
3406 PUSHB_1,
3408 CINDEX,
3409 PUSHB_1,
3410 sal_anchor,
3412 MD_orig_ZP2_0,
3413 ADD, /* s: [...] edge2 cur_len edge org_pos */
3415 DUP,
3416 PUSHB_1,
3417 sal_org_len,
3419 DIV_BY_2,
3420 ADD, /* s: [...] edge2 cur_len edge org_pos org_center */
3422 SWAP,
3423 DUP,
3424 PUSHB_1,
3425 bci_round,
3426 CALL, /* cur_pos1 = ROUND(org_pos) */
3427 SWAP,
3428 PUSHB_1,
3429 sal_org_len,
3431 ADD,
3432 PUSHB_1,
3433 bci_round,
3434 CALL,
3435 PUSHB_1,
3437 CINDEX,
3438 SUB, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3440 PUSHB_1,
3442 CINDEX,
3443 DIV_BY_2,
3444 PUSHB_1,
3446 MINDEX,
3447 SUB, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3449 DUP,
3450 PUSHB_1,
3452 CINDEX,
3453 ADD,
3454 ABS, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3455 SWAP,
3456 PUSHB_1,
3458 CINDEX,
3459 ADD,
3460 ABS, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3461 LT, /* delta1 < delta2 */
3463 POP, /* arg = cur_pos1 */
3465 ELSE,
3466 SWAP,
3467 POP, /* arg = cur_pos2 */
3468 EIF, /* s: [...] edge2 cur_len edge arg */
3469 SWAP,
3470 DUP,
3471 DUP,
3472 PUSHB_1,
3474 MINDEX,
3475 SWAP, /* s: [...] edge2 cur_len edge edge arg edge */
3476 GC_cur,
3477 SUB,
3478 SHPIX, /* edge = arg */
3479 EIF, /* s: [...] edge2 cur_len edge */
3481 ENDF,
3487 * bci_stem_bound
3489 * Handle the STEM action to align two edges of a stem, then moving one
3490 * edge again if necessary to stay bound.
3492 * The code after computing `cur_len' to shift `edge' and `edge2'
3493 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3495 * if cur_len < 96:
3496 * if cur_len < = 64:
3497 * u_off = 32
3498 * d_off = 32
3499 * else:
3500 * u_off = 38
3501 * d_off = 26
3503 * org_pos = anchor + (edge_orig - anchor_orig);
3504 * org_center = org_pos + org_len / 2;
3506 * cur_pos1 = ROUND(org_center)
3507 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3508 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3509 * if (delta1 < delta2):
3510 * cur_pos1 = cur_pos1 - u_off
3511 * else:
3512 * cur_pos1 = cur_pos1 + d_off
3514 * edge = cur_pos1 - cur_len / 2
3516 * else:
3517 * org_pos = anchor + (edge_orig - anchor_orig)
3518 * org_center = org_pos + org_len / 2;
3520 * cur_pos1 = ROUND(org_pos)
3521 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3522 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3523 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3525 * if (delta1 < delta2):
3526 * edge = cur_pos1
3527 * else:
3528 * edge = cur_pos2
3530 * edge2 = edge + cur_len
3532 * in: edge2_is_serif
3533 * edge_is_round
3534 * edge_point (in twilight zone)
3535 * edge2_point (in twilight zone)
3536 * edge[-1] (in twilight zone)
3537 * ... stuff for bci_align_segments (edge) ...
3538 * ... stuff for bci_align_segments (edge2)...
3540 * sal: sal_anchor
3541 * sal_temp1
3542 * sal_temp2
3543 * sal_temp3
3545 * uses: bci_stem_common
3546 * bci_align_segments
3549 unsigned char FPGM(bci_stem_bound) [] =
3552 PUSHB_1,
3553 bci_stem_bound,
3554 FDEF,
3556 PUSHB_1,
3557 bci_stem_common,
3558 CALL,
3560 ROLL, /* s: edge[-1] cur_len edge edge2 */
3561 DUP,
3562 DUP,
3563 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3564 PUSHB_1,
3565 sal_edge2,
3566 SWAP,
3567 WS, /* s: edge[-1] cur_len edge edge2 */
3568 ROLL,
3569 SHPIX, /* edge2 = edge + cur_len */
3571 SWAP, /* s: edge edge[-1] */
3572 DUP,
3573 MDAP_noround, /* set rp0 and rp1 to `edge[-1]' */
3574 GC_cur,
3575 PUSHB_1,
3577 CINDEX,
3578 GC_cur, /* s: edge edge[-1]_pos edge_pos */
3579 GT, /* edge_pos < edge[-1]_pos */
3581 DUP,
3582 ALIGNRP, /* align `edge' to `edge[-1]' */
3583 EIF,
3585 MDAP_noround, /* set rp0 and rp1 to `edge' */
3587 PUSHB_2,
3588 bci_align_segments,
3590 SZP1, /* set zp1 to normal zone 1 */
3591 CALL,
3593 PUSHB_1,
3594 sal_edge2,
3596 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3598 PUSHB_1,
3599 bci_align_segments,
3600 CALL,
3602 ENDF,
3608 * bci_action_stem_bound
3609 * bci_action_stem_bound_serif
3610 * bci_action_stem_bound_round
3611 * bci_action_stem_bound_round_serif
3613 * Higher-level routines for calling `bci_stem_bound'.
3616 unsigned char FPGM(bci_action_stem_bound) [] =
3619 PUSHB_1,
3620 bci_action_stem_bound,
3621 FDEF,
3623 PUSHB_3,
3626 bci_stem_bound,
3627 CALL,
3629 ENDF,
3633 unsigned char FPGM(bci_action_stem_bound_serif) [] =
3636 PUSHB_1,
3637 bci_action_stem_bound_serif,
3638 FDEF,
3640 PUSHB_3,
3643 bci_stem_bound,
3644 CALL,
3646 ENDF,
3650 unsigned char FPGM(bci_action_stem_bound_round) [] =
3653 PUSHB_1,
3654 bci_action_stem_bound_round,
3655 FDEF,
3657 PUSHB_3,
3660 bci_stem_bound,
3661 CALL,
3663 ENDF,
3667 unsigned char FPGM(bci_action_stem_bound_round_serif) [] =
3670 PUSHB_1,
3671 bci_action_stem_bound_round_serif,
3672 FDEF,
3674 PUSHB_3,
3677 bci_stem_bound,
3678 CALL,
3680 ENDF,
3686 * bci_stem
3688 * Handle the STEM action to align two edges of a stem.
3690 * See `bci_stem_bound' for more details.
3692 * in: edge2_is_serif
3693 * edge_is_round
3694 * edge_point (in twilight zone)
3695 * edge2_point (in twilight zone)
3696 * ... stuff for bci_align_segments (edge) ...
3697 * ... stuff for bci_align_segments (edge2)...
3699 * sal: sal_anchor
3700 * sal_temp1
3701 * sal_temp2
3702 * sal_temp3
3704 * uses: bci_stem_common
3705 * bci_align_segments
3708 unsigned char FPGM(bci_stem) [] =
3711 PUSHB_1,
3712 bci_stem,
3713 FDEF,
3715 PUSHB_1,
3716 bci_stem_common,
3717 CALL,
3719 POP,
3720 SWAP, /* s: cur_len edge2 */
3721 DUP,
3722 DUP,
3723 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
3724 PUSHB_1,
3725 sal_edge2,
3726 SWAP,
3727 WS, /* s: cur_len edge2 */
3728 SWAP,
3729 SHPIX, /* edge2 = edge + cur_len */
3731 PUSHB_2,
3732 bci_align_segments,
3734 SZP1, /* set zp1 to normal zone 1 */
3735 CALL,
3737 PUSHB_1,
3738 sal_edge2,
3740 MDAP_noround, /* set rp0 and rp1 to `edge2' */
3742 PUSHB_1,
3743 bci_align_segments,
3744 CALL,
3745 ENDF,
3751 * bci_action_stem
3752 * bci_action_stem_serif
3753 * bci_action_stem_round
3754 * bci_action_stem_round_serif
3756 * Higher-level routines for calling `bci_stem'.
3759 unsigned char FPGM(bci_action_stem) [] =
3762 PUSHB_1,
3763 bci_action_stem,
3764 FDEF,
3766 PUSHB_3,
3769 bci_stem,
3770 CALL,
3772 ENDF,
3776 unsigned char FPGM(bci_action_stem_serif) [] =
3779 PUSHB_1,
3780 bci_action_stem_serif,
3781 FDEF,
3783 PUSHB_3,
3786 bci_stem,
3787 CALL,
3789 ENDF,
3793 unsigned char FPGM(bci_action_stem_round) [] =
3796 PUSHB_1,
3797 bci_action_stem_round,
3798 FDEF,
3800 PUSHB_3,
3803 bci_stem,
3804 CALL,
3806 ENDF,
3810 unsigned char FPGM(bci_action_stem_round_serif) [] =
3813 PUSHB_1,
3814 bci_action_stem_round_serif,
3815 FDEF,
3817 PUSHB_3,
3820 bci_stem,
3821 CALL,
3823 ENDF,
3829 * bci_link
3831 * Handle the LINK action to link an edge to another one.
3833 * in: stem_is_serif
3834 * base_is_round
3835 * base_point (in twilight zone)
3836 * stem_point (in twilight zone)
3837 * ... stuff for bci_align_segments (base) ...
3839 * uses: func[cvtl_stem_width_function]
3840 * bci_align_segments
3843 unsigned char FPGM(bci_link) [] =
3846 PUSHB_1,
3847 bci_link,
3848 FDEF,
3850 PUSHB_1,
3852 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
3854 PUSHB_1,
3856 CINDEX,
3857 PUSHB_1,
3859 MINDEX,
3860 DUP, /* s: stem is_round is_serif stem base base */
3861 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3863 MD_orig_ZP2_0, /* s: stem is_round is_serif dist_orig */
3865 PUSHB_1,
3866 cvtl_stem_width_function,
3867 RCVT,
3868 CALL, /* s: stem new_dist */
3870 SWAP,
3871 DUP,
3872 ALIGNRP, /* align `stem_point' with `base_point' */
3873 DUP,
3874 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
3875 SWAP,
3876 SHPIX, /* stem_point = base_point + new_dist */
3878 PUSHB_2,
3879 bci_align_segments,
3881 SZP1, /* set zp1 to normal zone 1 */
3882 CALL,
3884 ENDF,
3890 * bci_action_link
3891 * bci_action_link_serif
3892 * bci_action_link_round
3893 * bci_action_link_round_serif
3895 * Higher-level routines for calling `bci_link'.
3898 unsigned char FPGM(bci_action_link) [] =
3901 PUSHB_1,
3902 bci_action_link,
3903 FDEF,
3905 PUSHB_3,
3908 bci_link,
3909 CALL,
3911 ENDF,
3915 unsigned char FPGM(bci_action_link_serif) [] =
3918 PUSHB_1,
3919 bci_action_link_serif,
3920 FDEF,
3922 PUSHB_3,
3925 bci_link,
3926 CALL,
3928 ENDF,
3932 unsigned char FPGM(bci_action_link_round) [] =
3935 PUSHB_1,
3936 bci_action_link_round,
3937 FDEF,
3939 PUSHB_3,
3942 bci_link,
3943 CALL,
3945 ENDF,
3949 unsigned char FPGM(bci_action_link_round_serif) [] =
3952 PUSHB_1,
3953 bci_action_link_round_serif,
3954 FDEF,
3956 PUSHB_3,
3959 bci_link,
3960 CALL,
3962 ENDF,
3968 * bci_anchor
3970 * Handle the ANCHOR action to align two edges
3971 * and to set the edge anchor.
3973 * The code after computing `cur_len' to shift `edge' and `edge2'
3974 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3976 * if cur_len < 96:
3977 * if cur_len < = 64:
3978 * u_off = 32
3979 * d_off = 32
3980 * else:
3981 * u_off = 38
3982 * d_off = 26
3984 * org_center = edge_orig + org_len / 2
3985 * cur_pos1 = ROUND(org_center)
3987 * error1 = ABS(org_center - (cur_pos1 - u_off))
3988 * error2 = ABS(org_center - (cur_pos1 + d_off))
3989 * if (error1 < error2):
3990 * cur_pos1 = cur_pos1 - u_off
3991 * else:
3992 * cur_pos1 = cur_pos1 + d_off
3994 * edge = cur_pos1 - cur_len / 2
3995 * edge2 = edge + cur_len
3997 * else:
3998 * edge = ROUND(edge_orig)
4000 * in: edge2_is_serif
4001 * edge_is_round
4002 * edge_point (in twilight zone)
4003 * edge2_point (in twilight zone)
4004 * ... stuff for bci_align_segments (edge) ...
4006 * sal: sal_anchor
4007 * sal_temp1
4008 * sal_temp2
4009 * sal_temp3
4011 * uses: func[cvtl_stem_width_function]
4012 * bci_round
4013 * bci_align_segments
4016 #undef sal_u_off
4017 #define sal_u_off sal_temp1
4018 #undef sal_d_off
4019 #define sal_d_off sal_temp2
4020 #undef sal_org_len
4021 #define sal_org_len sal_temp3
4023 unsigned char FPGM(bci_anchor) [] =
4026 PUSHB_1,
4027 bci_anchor,
4028 FDEF,
4030 /* store anchor point number in `sal_anchor' */
4031 PUSHB_2,
4032 sal_anchor,
4034 CINDEX,
4035 WS, /* sal_anchor = edge_point */
4037 PUSHB_1,
4039 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4041 PUSHB_1,
4043 CINDEX,
4044 PUSHB_1,
4046 CINDEX,
4047 DUP, /* s: edge2 edge is_round is_serif edge2 edge edge */
4048 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4050 MD_orig_ZP2_0, /* s: edge2 edge is_round is_serif org_len */
4051 DUP,
4052 PUSHB_1,
4053 sal_org_len,
4054 SWAP,
4057 PUSHB_1,
4058 cvtl_stem_width_function,
4059 RCVT,
4060 CALL, /* s: edge2 edge cur_len */
4062 DUP,
4063 PUSHB_1,
4065 LT, /* cur_len < 96 */
4067 DUP,
4068 PUSHB_1,
4070 LTEQ, /* cur_len <= 64 */
4072 PUSHB_4,
4073 sal_u_off,
4075 sal_d_off,
4078 ELSE,
4079 PUSHB_4,
4080 sal_u_off,
4082 sal_d_off,
4084 EIF,
4088 SWAP, /* s: edge2 cur_len edge */
4089 DUP, /* s: edge2 cur_len edge edge */
4091 GC_orig,
4092 PUSHB_1,
4093 sal_org_len,
4095 DIV_BY_2,
4096 ADD, /* s: edge2 cur_len edge org_center */
4098 DUP,
4099 PUSHB_1,
4100 bci_round,
4101 CALL, /* s: edge2 cur_len edge org_center cur_pos1 */
4103 DUP,
4104 ROLL,
4105 ROLL,
4106 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4108 DUP,
4109 PUSHB_1,
4110 sal_u_off,
4112 ADD,
4113 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4115 SWAP,
4116 PUSHB_1,
4117 sal_d_off,
4119 SUB,
4120 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4122 LT, /* error1 < error2 */
4124 PUSHB_1,
4125 sal_u_off,
4127 SUB, /* cur_pos1 = cur_pos1 - u_off */
4129 ELSE,
4130 PUSHB_1,
4131 sal_d_off,
4133 ADD, /* cur_pos1 = cur_pos1 + d_off */
4134 EIF, /* s: edge2 cur_len edge cur_pos1 */
4136 PUSHB_1,
4138 CINDEX,
4139 DIV_BY_2,
4140 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4142 PUSHB_1,
4144 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4145 GC_cur,
4146 SUB,
4147 SHPIX, /* edge = cur_pos1 - cur_len/2 */
4149 SWAP, /* s: cur_len edge2 */
4150 DUP,
4151 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
4152 SWAP,
4153 SHPIX, /* edge2 = edge1 + cur_len */
4155 ELSE,
4156 POP, /* s: edge2 edge */
4157 DUP,
4158 DUP,
4159 GC_cur,
4160 SWAP,
4161 GC_orig,
4162 PUSHB_1,
4163 bci_round,
4164 CALL, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4165 SWAP,
4166 SUB,
4167 SHPIX, /* edge = round(edge_orig) */
4169 /* clean up stack */
4170 POP,
4171 EIF,
4173 PUSHB_2,
4174 bci_align_segments,
4176 SZP1, /* set zp1 to normal zone 1 */
4177 CALL,
4179 ENDF,
4185 * bci_action_anchor
4186 * bci_action_anchor_serif
4187 * bci_action_anchor_round
4188 * bci_action_anchor_round_serif
4190 * Higher-level routines for calling `bci_anchor'.
4193 unsigned char FPGM(bci_action_anchor) [] =
4196 PUSHB_1,
4197 bci_action_anchor,
4198 FDEF,
4200 PUSHB_3,
4203 bci_anchor,
4204 CALL,
4206 ENDF,
4210 unsigned char FPGM(bci_action_anchor_serif) [] =
4213 PUSHB_1,
4214 bci_action_anchor_serif,
4215 FDEF,
4217 PUSHB_3,
4220 bci_anchor,
4221 CALL,
4223 ENDF,
4227 unsigned char FPGM(bci_action_anchor_round) [] =
4230 PUSHB_1,
4231 bci_action_anchor_round,
4232 FDEF,
4234 PUSHB_3,
4237 bci_anchor,
4238 CALL,
4240 ENDF,
4244 unsigned char FPGM(bci_action_anchor_round_serif) [] =
4247 PUSHB_1,
4248 bci_action_anchor_round_serif,
4249 FDEF,
4251 PUSHB_3,
4254 bci_anchor,
4255 CALL,
4257 ENDF,
4263 * bci_action_blue_anchor
4265 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4266 * and to set the edge anchor.
4268 * in: anchor_point (in twilight zone)
4269 * blue_cvt_idx
4270 * edge_point (in twilight zone)
4271 * ... stuff for bci_align_segments (edge) ...
4273 * sal: sal_anchor
4275 * uses: bci_action_blue
4278 unsigned char FPGM(bci_action_blue_anchor) [] =
4281 PUSHB_1,
4282 bci_action_blue_anchor,
4283 FDEF,
4285 /* store anchor point number in `sal_anchor' */
4286 PUSHB_1,
4287 sal_anchor,
4288 SWAP,
4291 PUSHB_1,
4292 bci_action_blue,
4293 CALL,
4295 ENDF,
4301 * bci_action_blue
4303 * Handle the BLUE action to align an edge with a blue zone.
4305 * in: blue_cvt_idx
4306 * edge_point (in twilight zone)
4307 * ... stuff for bci_align_segments (edge) ...
4309 * uses: bci_align_segments
4312 unsigned char FPGM(bci_action_blue) [] =
4315 PUSHB_1,
4316 bci_action_blue,
4317 FDEF,
4319 PUSHB_1,
4321 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4323 /* move `edge_point' to `blue_cvt_idx' position; */
4324 /* note that we can't use MIAP since this would modify */
4325 /* the twilight point's original coordinates also */
4326 RCVT,
4327 SWAP,
4328 DUP,
4329 MDAP_noround, /* set rp0 and rp1 to `edge' */
4330 DUP,
4331 GC_cur, /* s: new_pos edge edge_pos */
4332 ROLL,
4333 SWAP,
4334 SUB, /* s: edge (new_pos - edge_pos) */
4335 SHPIX,
4337 PUSHB_2,
4338 bci_align_segments,
4340 SZP1, /* set zp1 to normal zone 1 */
4341 CALL,
4343 ENDF,
4349 * bci_serif_common
4351 * Common code for bci_action_serif routines.
4354 unsigned char FPGM(bci_serif_common) [] =
4357 PUSHB_1,
4358 bci_serif_common,
4359 FDEF,
4361 PUSHB_1,
4363 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4365 DUP,
4366 DUP,
4367 DUP,
4368 PUSHB_1,
4370 MINDEX, /* s: [...] serif serif serif serif base */
4371 DUP,
4372 MDAP_noround, /* set rp0 and rp1 to `base_point' */
4373 MD_orig_ZP2_0,
4374 SWAP,
4375 ALIGNRP, /* align `serif_point' with `base_point' */
4376 SHPIX, /* serif = base + (serif_orig_pos - base_orig_pos) */
4378 ENDF,
4384 * bci_lower_bound
4386 * Move an edge if necessary to stay within a lower bound.
4388 * in: edge
4389 * bound
4391 * uses: bci_align_segments
4394 unsigned char FPGM(bci_lower_bound) [] =
4397 PUSHB_1,
4398 bci_lower_bound,
4399 FDEF,
4401 SWAP, /* s: edge bound */
4402 DUP,
4403 MDAP_noround, /* set rp0 and rp1 to `bound' */
4404 GC_cur,
4405 PUSHB_1,
4407 CINDEX,
4408 GC_cur, /* s: edge bound_pos edge_pos */
4409 GT, /* edge_pos < bound_pos */
4411 DUP,
4412 ALIGNRP, /* align `edge' to `bound' */
4413 EIF,
4415 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4417 PUSHB_2,
4418 bci_align_segments,
4420 SZP1, /* set zp1 to normal zone 1 */
4421 CALL,
4423 ENDF,
4429 * bci_upper_bound
4431 * Move an edge if necessary to stay within an upper bound.
4433 * in: edge
4434 * bound
4436 * uses: bci_align_segments
4439 unsigned char FPGM(bci_upper_bound) [] =
4442 PUSHB_1,
4443 bci_upper_bound,
4444 FDEF,
4446 SWAP, /* s: edge bound */
4447 DUP,
4448 MDAP_noround, /* set rp0 and rp1 to `bound' */
4449 GC_cur,
4450 PUSHB_1,
4452 CINDEX,
4453 GC_cur, /* s: edge bound_pos edge_pos */
4454 LT, /* edge_pos > bound_pos */
4456 DUP,
4457 ALIGNRP, /* align `edge' to `bound' */
4458 EIF,
4460 MDAP_noround, /* set rp0 and rp1 to `edge_point' */
4462 PUSHB_2,
4463 bci_align_segments,
4465 SZP1, /* set zp1 to normal zone 1 */
4466 CALL,
4468 ENDF,
4474 * bci_upper_lower_bound
4476 * Move an edge if necessary to stay within a lower and lower bound.
4478 * in: edge
4479 * lower
4480 * upper
4482 * uses: bci_align_segments
4485 unsigned char FPGM(bci_upper_lower_bound) [] =
4488 PUSHB_1,
4489 bci_upper_lower_bound,
4490 FDEF,
4492 SWAP, /* s: upper serif lower */
4493 DUP,
4494 MDAP_noround, /* set rp0 and rp1 to `lower' */
4495 GC_cur,
4496 PUSHB_1,
4498 CINDEX,
4499 GC_cur, /* s: upper serif lower_pos serif_pos */
4500 GT, /* serif_pos < lower_pos */
4502 DUP,
4503 ALIGNRP, /* align `serif' to `lower' */
4504 EIF,
4506 SWAP, /* s: serif upper */
4507 DUP,
4508 MDAP_noround, /* set rp0 and rp1 to `upper' */
4509 GC_cur,
4510 PUSHB_1,
4512 CINDEX,
4513 GC_cur, /* s: serif upper_pos serif_pos */
4514 LT, /* serif_pos > upper_pos */
4516 DUP,
4517 ALIGNRP, /* align `serif' to `upper' */
4518 EIF,
4520 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4522 PUSHB_2,
4523 bci_align_segments,
4525 SZP1, /* set zp1 to normal zone 1 */
4526 CALL,
4528 ENDF,
4534 * bci_action_serif
4536 * Handle the SERIF action to align a serif with its base.
4538 * in: serif_point (in twilight zone)
4539 * base_point (in twilight zone)
4540 * ... stuff for bci_align_segments (serif) ...
4542 * uses: bci_serif_common
4543 * bci_align_segments
4546 unsigned char FPGM(bci_action_serif) [] =
4549 PUSHB_1,
4550 bci_action_serif,
4551 FDEF,
4553 PUSHB_1,
4554 bci_serif_common,
4555 CALL,
4557 MDAP_noround, /* set rp0 and rp1 to `serif_point' */
4559 PUSHB_2,
4560 bci_align_segments,
4562 SZP1, /* set zp1 to normal zone 1 */
4563 CALL,
4565 ENDF,
4571 * bci_action_serif_lower_bound
4573 * Handle the SERIF action to align a serif with its base, then moving it
4574 * again if necessary to stay within a lower bound.
4576 * in: serif_point (in twilight zone)
4577 * base_point (in twilight zone)
4578 * edge[-1] (in twilight zone)
4579 * ... stuff for bci_align_segments (serif) ...
4581 * uses: bci_serif_common
4582 * bci_lower_bound
4585 unsigned char FPGM(bci_action_serif_lower_bound) [] =
4588 PUSHB_1,
4589 bci_action_serif_lower_bound,
4590 FDEF,
4592 PUSHB_1,
4593 bci_serif_common,
4594 CALL,
4596 PUSHB_1,
4597 bci_lower_bound,
4598 CALL,
4600 ENDF,
4606 * bci_action_serif_upper_bound
4608 * Handle the SERIF action to align a serif with its base, then moving it
4609 * again if necessary to stay within an upper bound.
4611 * in: serif_point (in twilight zone)
4612 * base_point (in twilight zone)
4613 * edge[1] (in twilight zone)
4614 * ... stuff for bci_align_segments (serif) ...
4616 * uses: bci_serif_common
4617 * bci_upper_bound
4620 unsigned char FPGM(bci_action_serif_upper_bound) [] =
4623 PUSHB_1,
4624 bci_action_serif_upper_bound,
4625 FDEF,
4627 PUSHB_1,
4628 bci_serif_common,
4629 CALL,
4631 PUSHB_1,
4632 bci_upper_bound,
4633 CALL,
4635 ENDF,
4641 * bci_action_serif_upper_lower_bound
4643 * Handle the SERIF action to align a serif with its base, then moving it
4644 * again if necessary to stay within a lower and upper bound.
4646 * in: serif_point (in twilight zone)
4647 * base_point (in twilight zone)
4648 * edge[-1] (in twilight zone)
4649 * edge[1] (in twilight zone)
4650 * ... stuff for bci_align_segments (serif) ...
4652 * uses: bci_serif_common
4653 * bci_upper_lower_bound
4656 unsigned char FPGM(bci_action_serif_upper_lower_bound) [] =
4659 PUSHB_1,
4660 bci_action_serif_upper_lower_bound,
4661 FDEF,
4663 PUSHB_1,
4665 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4667 PUSHB_1,
4668 bci_serif_common,
4669 CALL,
4671 PUSHB_1,
4672 bci_upper_lower_bound,
4673 CALL,
4675 ENDF,
4681 * bci_serif_anchor_common
4683 * Common code for bci_action_serif_anchor routines.
4685 * sal: sal_anchor
4687 * uses: bci_round
4690 unsigned char FPGM(bci_serif_anchor_common) [] =
4693 PUSHB_1,
4694 bci_serif_anchor_common,
4695 FDEF,
4697 PUSHB_1,
4699 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4701 DUP,
4702 PUSHB_1,
4703 sal_anchor,
4704 SWAP,
4705 WS, /* sal_anchor = edge_point */
4707 DUP,
4708 DUP,
4709 DUP,
4710 GC_cur,
4711 SWAP,
4712 GC_orig,
4713 PUSHB_1,
4714 bci_round,
4715 CALL, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4716 SWAP,
4717 SUB,
4718 SHPIX, /* edge = round(edge_orig) */
4720 ENDF,
4726 * bci_action_serif_anchor
4728 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4729 * anchor.
4731 * in: edge_point (in twilight zone)
4732 * ... stuff for bci_align_segments (edge) ...
4734 * uses: bci_serif_anchor_common
4735 * bci_align_segments
4738 unsigned char FPGM(bci_action_serif_anchor) [] =
4741 PUSHB_1,
4742 bci_action_serif_anchor,
4743 FDEF,
4745 PUSHB_1,
4746 bci_serif_anchor_common,
4747 CALL,
4749 MDAP_noround, /* set rp0 and rp1 to `edge' */
4751 PUSHB_2,
4752 bci_align_segments,
4754 SZP1, /* set zp1 to normal zone 1 */
4755 CALL,
4757 ENDF,
4763 * bci_action_serif_anchor_lower_bound
4765 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4766 * anchor, then moving it again if necessary to stay within a lower
4767 * bound.
4769 * in: edge_point (in twilight zone)
4770 * edge[-1] (in twilight zone)
4771 * ... stuff for bci_align_segments (edge) ...
4773 * uses: bci_serif_anchor_common
4774 * bci_lower_bound
4777 unsigned char FPGM(bci_action_serif_anchor_lower_bound) [] =
4780 PUSHB_1,
4781 bci_action_serif_anchor_lower_bound,
4782 FDEF,
4784 PUSHB_1,
4785 bci_serif_anchor_common,
4786 CALL,
4788 PUSHB_1,
4789 bci_lower_bound,
4790 CALL,
4792 ENDF,
4798 * bci_action_serif_anchor_upper_bound
4800 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4801 * anchor, then moving it again if necessary to stay within an upper
4802 * bound.
4804 * in: edge_point (in twilight zone)
4805 * edge[1] (in twilight zone)
4806 * ... stuff for bci_align_segments (edge) ...
4808 * uses: bci_serif_anchor_common
4809 * bci_upper_bound
4812 unsigned char FPGM(bci_action_serif_anchor_upper_bound) [] =
4815 PUSHB_1,
4816 bci_action_serif_anchor_upper_bound,
4817 FDEF,
4819 PUSHB_1,
4820 bci_serif_anchor_common,
4821 CALL,
4823 PUSHB_1,
4824 bci_upper_bound,
4825 CALL,
4827 ENDF,
4833 * bci_action_serif_anchor_upper_lower_bound
4835 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4836 * anchor, then moving it again if necessary to stay within a lower and
4837 * upper bound.
4839 * in: edge_point (in twilight zone)
4840 * edge[-1] (in twilight zone)
4841 * edge[1] (in twilight zone)
4842 * ... stuff for bci_align_segments (edge) ...
4844 * uses: bci_serif_anchor_common
4845 * bci_upper_lower_bound
4848 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound) [] =
4851 PUSHB_1,
4852 bci_action_serif_anchor_upper_lower_bound,
4853 FDEF,
4855 PUSHB_1,
4856 bci_serif_anchor_common,
4857 CALL,
4859 PUSHB_1,
4860 bci_upper_lower_bound,
4861 CALL,
4863 ENDF,
4869 * bci_serif_link1_common
4871 * Common code for bci_action_serif_link1 routines.
4873 * CVT: cvtl_0x10000
4876 unsigned char FPGM(bci_serif_link1_common) [] =
4879 PUSHB_1,
4880 bci_serif_link1_common,
4881 FDEF,
4883 PUSHB_1,
4885 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
4887 PUSHB_1,
4889 CINDEX, /* s: [...] after edge before after */
4890 PUSHB_1,
4892 CINDEX, /* s: [...] after edge before after before */
4893 MD_orig_ZP2_0,
4894 PUSHB_1,
4896 EQ, /* after_orig_pos == before_orig_pos */
4897 IF, /* s: [...] after edge before */
4898 MDAP_noround, /* set rp0 and rp1 to `before' */
4899 DUP,
4900 ALIGNRP, /* align `edge' with `before' */
4901 SWAP,
4902 POP,
4904 ELSE,
4905 /* we have to execute `a*b/c', with b/c very near to 1: */
4906 /* to avoid overflow while retaining precision, */
4907 /* we transform this to `a + a * (b-c)/c' */
4909 PUSHB_1,
4911 CINDEX, /* s: [...] after edge before edge */
4912 PUSHB_1,
4914 CINDEX, /* s: [...] after edge before edge before */
4915 MD_orig_ZP2_0, /* a = edge_orig_pos - before_orig_pos */
4917 DUP,
4918 PUSHB_1,
4920 CINDEX, /* s: [...] after edge before a a after */
4921 PUSHB_1,
4923 CINDEX, /* s: [...] after edge before a a after before */
4924 MD_orig_ZP2_0, /* c = after_orig_pos - before_orig_pos */
4926 PUSHB_1,
4928 CINDEX, /* s: [...] after edge before a a c after */
4929 PUSHB_1,
4931 CINDEX, /* s: [...] after edge before a a c after before */
4932 MD_cur, /* b = after_pos - before_pos */
4934 PUSHB_1,
4936 CINDEX, /* s: [...] after edge before a a c b c */
4937 SUB, /* b-c */
4939 PUSHB_1,
4940 cvtl_0x10000,
4941 RCVT,
4942 MUL, /* (b-c) in 16.16 format */
4943 SWAP,
4945 DUP,
4946 IF, /* c != 0 ? */
4947 DIV, /* s: [...] after edge before a a (b-c)/c */
4948 ELSE,
4949 POP, /* avoid division by zero */
4950 EIF,
4952 MUL, /* a * (b-c)/c * 2^10 */
4953 DIV_BY_1024, /* a * (b-c)/c */
4954 ADD, /* a*b/c */
4956 SWAP,
4957 MDAP_noround, /* set rp0 and rp1 to `before' */
4958 SWAP, /* s: [...] after a*b/c edge */
4959 DUP,
4960 DUP,
4961 ALIGNRP, /* align `edge' with `before' */
4962 ROLL,
4963 SHPIX, /* shift `edge' by `a*b/c' */
4965 SWAP, /* s: [...] edge after */
4966 POP,
4967 EIF,
4969 ENDF,
4975 * bci_action_serif_link1
4977 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4978 * before and after.
4980 * in: before_point (in twilight zone)
4981 * edge_point (in twilight zone)
4982 * after_point (in twilight zone)
4983 * ... stuff for bci_align_segments (edge) ...
4985 * uses: bci_serif_link1_common
4986 * bci_align_segments
4989 unsigned char FPGM(bci_action_serif_link1) [] =
4992 PUSHB_1,
4993 bci_action_serif_link1,
4994 FDEF,
4996 PUSHB_1,
4997 bci_serif_link1_common,
4998 CALL,
5000 MDAP_noround, /* set rp0 and rp1 to `edge' */
5002 PUSHB_2,
5003 bci_align_segments,
5005 SZP1, /* set zp1 to normal zone 1 */
5006 CALL,
5008 ENDF,
5014 * bci_action_serif_link1_lower_bound
5016 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5017 * before and after. Additionally, move the serif again if necessary to
5018 * stay within a lower bound.
5020 * in: before_point (in twilight zone)
5021 * edge_point (in twilight zone)
5022 * after_point (in twilight zone)
5023 * edge[-1] (in twilight zone)
5024 * ... stuff for bci_align_segments (edge) ...
5026 * uses: bci_serif_link1_common
5027 * bci_lower_bound
5030 unsigned char FPGM(bci_action_serif_link1_lower_bound) [] =
5033 PUSHB_1,
5034 bci_action_serif_link1_lower_bound,
5035 FDEF,
5037 PUSHB_1,
5038 bci_serif_link1_common,
5039 CALL,
5041 PUSHB_1,
5042 bci_lower_bound,
5043 CALL,
5045 ENDF,
5051 * bci_action_serif_link1_upper_bound
5053 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5054 * before and after. Additionally, move the serif again if necessary to
5055 * stay within an upper bound.
5057 * in: before_point (in twilight zone)
5058 * edge_point (in twilight zone)
5059 * after_point (in twilight zone)
5060 * edge[1] (in twilight zone)
5061 * ... stuff for bci_align_segments (edge) ...
5063 * uses: bci_serif_link1_common
5064 * bci_upper_bound
5067 unsigned char FPGM(bci_action_serif_link1_upper_bound) [] =
5070 PUSHB_1,
5071 bci_action_serif_link1_upper_bound,
5072 FDEF,
5074 PUSHB_1,
5075 bci_serif_link1_common,
5076 CALL,
5078 PUSHB_1,
5079 bci_upper_bound,
5080 CALL,
5082 ENDF,
5088 * bci_action_serif_link1_upper_lower_bound
5090 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5091 * before and after. Additionally, move the serif again if necessary to
5092 * stay within a lower and upper bound.
5094 * in: before_point (in twilight zone)
5095 * edge_point (in twilight zone)
5096 * after_point (in twilight zone)
5097 * edge[-1] (in twilight zone)
5098 * edge[1] (in twilight zone)
5099 * ... stuff for bci_align_segments (edge) ...
5101 * uses: bci_serif_link1_common
5102 * bci_upper_lower_bound
5105 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound) [] =
5108 PUSHB_1,
5109 bci_action_serif_link1_upper_lower_bound,
5110 FDEF,
5112 PUSHB_1,
5113 bci_serif_link1_common,
5114 CALL,
5116 PUSHB_1,
5117 bci_upper_lower_bound,
5118 CALL,
5120 ENDF,
5126 * bci_serif_link2_common
5128 * Common code for bci_action_serif_link2 routines.
5130 * sal: sal_anchor
5133 unsigned char FPGM(bci_serif_link2_common) [] =
5136 PUSHB_1,
5137 bci_serif_link2_common,
5138 FDEF,
5140 PUSHB_1,
5142 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
5144 DUP, /* s: [...] edge edge */
5145 PUSHB_1,
5146 sal_anchor,
5148 DUP, /* s: [...] edge edge anchor anchor */
5149 MDAP_noround, /* set rp0 and rp1 to `sal_anchor' */
5151 MD_orig_ZP2_0,
5152 DUP,
5153 ADD,
5154 PUSHB_1,
5156 ADD,
5157 FLOOR,
5158 DIV_BY_2, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5160 SWAP,
5161 DUP,
5162 DUP,
5163 ALIGNRP, /* align `edge' with `sal_anchor' */
5164 ROLL,
5165 SHPIX, /* shift `edge' by `delta' */
5167 ENDF,
5173 * bci_action_serif_link2
5175 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5177 * in: edge_point (in twilight zone)
5178 * ... stuff for bci_align_segments (edge) ...
5180 * uses: bci_serif_link2_common
5181 * bci_align_segments
5184 unsigned char FPGM(bci_action_serif_link2) [] =
5187 PUSHB_1,
5188 bci_action_serif_link2,
5189 FDEF,
5191 PUSHB_1,
5192 bci_serif_link2_common,
5193 CALL,
5195 MDAP_noround, /* set rp0 and rp1 to `edge' */
5197 PUSHB_2,
5198 bci_align_segments,
5200 SZP1, /* set zp1 to normal zone 1 */
5201 CALL,
5203 ENDF,
5209 * bci_action_serif_link2_lower_bound
5211 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5212 * Additionally, move the serif again if necessary to stay within a lower
5213 * bound.
5215 * in: edge_point (in twilight zone)
5216 * edge[-1] (in twilight zone)
5217 * ... stuff for bci_align_segments (edge) ...
5219 * uses: bci_serif_link2_common
5220 * bci_lower_bound
5223 unsigned char FPGM(bci_action_serif_link2_lower_bound) [] =
5226 PUSHB_1,
5227 bci_action_serif_link2_lower_bound,
5228 FDEF,
5230 PUSHB_1,
5231 bci_serif_link2_common,
5232 CALL,
5234 PUSHB_1,
5235 bci_lower_bound,
5236 CALL,
5238 ENDF,
5244 * bci_action_serif_link2_upper_bound
5246 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5247 * Additionally, move the serif again if necessary to stay within an upper
5248 * bound.
5250 * in: edge_point (in twilight zone)
5251 * edge[1] (in twilight zone)
5252 * ... stuff for bci_align_segments (edge) ...
5254 * uses: bci_serif_link2_common
5255 * bci_upper_bound
5258 unsigned char FPGM(bci_action_serif_link2_upper_bound) [] =
5261 PUSHB_1,
5262 bci_action_serif_link2_upper_bound,
5263 FDEF,
5265 PUSHB_1,
5266 bci_serif_link2_common,
5267 CALL,
5269 PUSHB_1,
5270 bci_upper_bound,
5271 CALL,
5273 ENDF,
5279 * bci_action_serif_link2_upper_lower_bound
5281 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5282 * Additionally, move the serif again if necessary to stay within a lower
5283 * and upper bound.
5285 * in: edge_point (in twilight zone)
5286 * edge[-1] (in twilight zone)
5287 * edge[1] (in twilight zone)
5288 * ... stuff for bci_align_segments (edge) ...
5290 * uses: bci_serif_link2_common
5291 * bci_upper_lower_bound
5294 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound) [] =
5297 PUSHB_1,
5298 bci_action_serif_link2_upper_lower_bound,
5299 FDEF,
5301 PUSHB_1,
5302 bci_serif_link2_common,
5303 CALL,
5305 PUSHB_1,
5306 bci_upper_lower_bound,
5307 CALL,
5309 ENDF,
5315 * bci_hint_glyph
5317 * This is the top-level glyph hinting function which parses the arguments
5318 * on the stack and calls subroutines.
5320 * in: action_0_func_idx
5321 * ... data ...
5322 * action_1_func_idx
5323 * ... data ...
5324 * ...
5326 * CVT: cvtl_is_subglyph
5328 * uses: bci_action_ip_before
5329 * bci_action_ip_after
5330 * bci_action_ip_on
5331 * bci_action_ip_between
5333 * bci_action_adjust_bound
5334 * bci_action_adjust_bound_serif
5335 * bci_action_adjust_bound_round
5336 * bci_action_adjust_bound_round_serif
5338 * bci_action_stem_bound
5339 * bci_action_stem_bound_serif
5340 * bci_action_stem_bound_round
5341 * bci_action_stem_bound_round_serif
5343 * bci_action_link
5344 * bci_action_link_serif
5345 * bci_action_link_round
5346 * bci_action_link_round_serif
5348 * bci_action_anchor
5349 * bci_action_anchor_serif
5350 * bci_action_anchor_round
5351 * bci_action_anchor_round_serif
5353 * bci_action_blue_anchor
5355 * bci_action_adjust
5356 * bci_action_adjust_serif
5357 * bci_action_adjust_round
5358 * bci_action_adjust_round_serif
5360 * bci_action_stem
5361 * bci_action_stem_serif
5362 * bci_action_stem_round
5363 * bci_action_stem_round_serif
5365 * bci_action_blue
5367 * bci_action_serif
5368 * bci_action_serif_lower_bound
5369 * bci_action_serif_upper_bound
5370 * bci_action_serif_upper_lower_bound
5372 * bci_action_serif_anchor
5373 * bci_action_serif_anchor_lower_bound
5374 * bci_action_serif_anchor_upper_bound
5375 * bci_action_serif_anchor_upper_lower_bound
5377 * bci_action_serif_link1
5378 * bci_action_serif_link1_lower_bound
5379 * bci_action_serif_link1_upper_bound
5380 * bci_action_serif_link1_upper_lower_bound
5382 * bci_action_serif_link2
5383 * bci_action_serif_link2_lower_bound
5384 * bci_action_serif_link2_upper_bound
5385 * bci_action_serif_link2_upper_lower_bound
5388 unsigned char FPGM(bci_hint_glyph) [] =
5391 PUSHB_1,
5392 bci_hint_glyph,
5393 FDEF,
5395 /* start_loop: */
5396 /* loop until all data on stack is used */
5397 CALL,
5398 PUSHB_1,
5400 NEG,
5401 PUSHB_1,
5403 DEPTH,
5405 JROT, /* goto start_loop */
5407 PUSHB_1,
5409 SZP2, /* set zp2 to normal zone 1 */
5410 IUP_y,
5412 ENDF,
5417 #define COPY_FPGM(func_name) \
5418 do \
5420 memcpy(bufp, fpgm_ ## func_name, \
5421 sizeof (fpgm_ ## func_name)); \
5422 bufp += sizeof (fpgm_ ## func_name); \
5423 } while (0)
5425 static FT_Error
5426 TA_table_build_fpgm(FT_Byte** fpgm,
5427 FT_ULong* fpgm_len,
5428 SFNT* sfnt,
5429 FONT* font)
5431 FT_UInt buf_len;
5432 FT_UInt len;
5433 FT_Byte* buf;
5434 FT_Byte* bufp;
5437 /* for compatibility with dumb bytecode interpreters or analyzers, */
5438 /* FDEFs are stored in ascending index order, without holes -- */
5439 /* note that some FDEFs are not always needed */
5440 /* (depending on options of `TTFautohint'), */
5441 /* but implementing dynamic FDEF indices would be a lot of work */
5443 buf_len = sizeof (FPGM(bci_align_top_a))
5444 + (font->increase_x_height
5445 ? (sizeof (FPGM(bci_align_top_b1a))
5447 + sizeof (FPGM(bci_align_top_b1b)))
5448 : sizeof (FPGM(bci_align_top_b2)))
5449 + sizeof (FPGM(bci_align_top_c))
5450 + sizeof (FPGM(bci_round))
5451 + sizeof (FPGM(bci_smooth_stem_width))
5452 + sizeof (FPGM(bci_get_best_width))
5453 + sizeof (FPGM(bci_strong_stem_width))
5454 + sizeof (FPGM(bci_loop_do))
5455 + sizeof (FPGM(bci_loop))
5456 + sizeof (FPGM(bci_cvt_rescale))
5457 + sizeof (FPGM(bci_cvt_rescale_range))
5458 + sizeof (FPGM(bci_vwidth_data_store))
5459 + sizeof (FPGM(bci_blue_round))
5460 + sizeof (FPGM(bci_blue_round_range))
5461 + sizeof (FPGM(bci_decrement_component_counter))
5462 + sizeof (FPGM(bci_get_point_extrema))
5463 + sizeof (FPGM(bci_nibbles))
5464 + sizeof (FPGM(bci_number_set_is_element))
5465 + sizeof (FPGM(bci_number_set_is_element2))
5467 + sizeof (FPGM(bci_create_segment))
5468 + sizeof (FPGM(bci_create_segments))
5470 + sizeof (FPGM(bci_create_segments_0))
5471 + sizeof (FPGM(bci_create_segments_1))
5472 + sizeof (FPGM(bci_create_segments_2))
5473 + sizeof (FPGM(bci_create_segments_3))
5474 + sizeof (FPGM(bci_create_segments_4))
5475 + sizeof (FPGM(bci_create_segments_5))
5476 + sizeof (FPGM(bci_create_segments_6))
5477 + sizeof (FPGM(bci_create_segments_7))
5478 + sizeof (FPGM(bci_create_segments_8))
5479 + sizeof (FPGM(bci_create_segments_9))
5481 + sizeof (FPGM(bci_create_segments_composite))
5483 + sizeof (FPGM(bci_create_segments_composite_0))
5484 + sizeof (FPGM(bci_create_segments_composite_1))
5485 + sizeof (FPGM(bci_create_segments_composite_2))
5486 + sizeof (FPGM(bci_create_segments_composite_3))
5487 + sizeof (FPGM(bci_create_segments_composite_4))
5488 + sizeof (FPGM(bci_create_segments_composite_5))
5489 + sizeof (FPGM(bci_create_segments_composite_6))
5490 + sizeof (FPGM(bci_create_segments_composite_7))
5491 + sizeof (FPGM(bci_create_segments_composite_8))
5492 + sizeof (FPGM(bci_create_segments_composite_9))
5494 + sizeof (FPGM(bci_align_point))
5495 + sizeof (FPGM(bci_align_segment))
5496 + sizeof (FPGM(bci_align_segments))
5498 + sizeof (FPGM(bci_scale_contour))
5499 + sizeof (FPGM(bci_scale_glyph))
5500 + sizeof (FPGM(bci_scale_composite_glyph))
5501 + sizeof (FPGM(bci_shift_contour))
5502 + sizeof (FPGM(bci_shift_subglyph))
5504 + sizeof (FPGM(bci_ip_outer_align_point))
5505 + sizeof (FPGM(bci_ip_on_align_points))
5506 + sizeof (FPGM(bci_ip_between_align_point))
5507 + sizeof (FPGM(bci_ip_between_align_points))
5509 + sizeof (FPGM(bci_adjust_common))
5510 + sizeof (FPGM(bci_stem_common))
5511 + sizeof (FPGM(bci_serif_common))
5512 + sizeof (FPGM(bci_serif_anchor_common))
5513 + sizeof (FPGM(bci_serif_link1_common))
5514 + sizeof (FPGM(bci_serif_link2_common))
5516 + sizeof (FPGM(bci_lower_bound))
5517 + sizeof (FPGM(bci_upper_bound))
5518 + sizeof (FPGM(bci_upper_lower_bound))
5520 + sizeof (FPGM(bci_adjust_bound))
5521 + sizeof (FPGM(bci_stem_bound))
5522 + sizeof (FPGM(bci_link))
5523 + sizeof (FPGM(bci_anchor))
5524 + sizeof (FPGM(bci_adjust))
5525 + sizeof (FPGM(bci_stem))
5527 + sizeof (FPGM(bci_action_ip_before))
5528 + sizeof (FPGM(bci_action_ip_after))
5529 + sizeof (FPGM(bci_action_ip_on))
5530 + sizeof (FPGM(bci_action_ip_between))
5532 + sizeof (FPGM(bci_action_blue))
5533 + sizeof (FPGM(bci_action_blue_anchor))
5535 + sizeof (FPGM(bci_action_anchor))
5536 + sizeof (FPGM(bci_action_anchor_serif))
5537 + sizeof (FPGM(bci_action_anchor_round))
5538 + sizeof (FPGM(bci_action_anchor_round_serif))
5540 + sizeof (FPGM(bci_action_adjust))
5541 + sizeof (FPGM(bci_action_adjust_serif))
5542 + sizeof (FPGM(bci_action_adjust_round))
5543 + sizeof (FPGM(bci_action_adjust_round_serif))
5544 + sizeof (FPGM(bci_action_adjust_bound))
5545 + sizeof (FPGM(bci_action_adjust_bound_serif))
5546 + sizeof (FPGM(bci_action_adjust_bound_round))
5547 + sizeof (FPGM(bci_action_adjust_bound_round_serif))
5549 + sizeof (FPGM(bci_action_link))
5550 + sizeof (FPGM(bci_action_link_serif))
5551 + sizeof (FPGM(bci_action_link_round))
5552 + sizeof (FPGM(bci_action_link_round_serif))
5554 + sizeof (FPGM(bci_action_stem))
5555 + sizeof (FPGM(bci_action_stem_serif))
5556 + sizeof (FPGM(bci_action_stem_round))
5557 + sizeof (FPGM(bci_action_stem_round_serif))
5558 + sizeof (FPGM(bci_action_stem_bound))
5559 + sizeof (FPGM(bci_action_stem_bound_serif))
5560 + sizeof (FPGM(bci_action_stem_bound_round))
5561 + sizeof (FPGM(bci_action_stem_bound_round_serif))
5563 + sizeof (FPGM(bci_action_serif))
5564 + sizeof (FPGM(bci_action_serif_lower_bound))
5565 + sizeof (FPGM(bci_action_serif_upper_bound))
5566 + sizeof (FPGM(bci_action_serif_upper_lower_bound))
5568 + sizeof (FPGM(bci_action_serif_anchor))
5569 + sizeof (FPGM(bci_action_serif_anchor_lower_bound))
5570 + sizeof (FPGM(bci_action_serif_anchor_upper_bound))
5571 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound))
5573 + sizeof (FPGM(bci_action_serif_link1))
5574 + sizeof (FPGM(bci_action_serif_link1_lower_bound))
5575 + sizeof (FPGM(bci_action_serif_link1_upper_bound))
5576 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound))
5578 + sizeof (FPGM(bci_action_serif_link2))
5579 + sizeof (FPGM(bci_action_serif_link2_lower_bound))
5580 + sizeof (FPGM(bci_action_serif_link2_upper_bound))
5581 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound))
5583 + sizeof (FPGM(bci_hint_glyph));
5585 /* buffer length must be a multiple of four */
5586 len = (buf_len + 3) & ~3;
5587 buf = (FT_Byte*)malloc(len);
5588 if (!buf)
5589 return FT_Err_Out_Of_Memory;
5591 /* pad end of buffer with zeros */
5592 buf[len - 1] = 0x00;
5593 buf[len - 2] = 0x00;
5594 buf[len - 3] = 0x00;
5596 /* copy font program into buffer and fill in the missing variables */
5597 bufp = buf;
5599 COPY_FPGM(bci_align_top_a);
5600 if (font->increase_x_height)
5602 COPY_FPGM(bci_align_top_b1a);
5603 *(bufp++) = HIGH(font->increase_x_height);
5604 *(bufp++) = LOW(font->increase_x_height);
5605 COPY_FPGM(bci_align_top_b1b);
5607 else
5608 COPY_FPGM(bci_align_top_b2);
5609 COPY_FPGM(bci_align_top_c);
5611 COPY_FPGM(bci_round);
5612 COPY_FPGM(bci_smooth_stem_width);
5613 COPY_FPGM(bci_get_best_width);
5614 COPY_FPGM(bci_strong_stem_width);
5615 COPY_FPGM(bci_loop_do);
5616 COPY_FPGM(bci_loop);
5617 COPY_FPGM(bci_cvt_rescale);
5618 COPY_FPGM(bci_cvt_rescale_range);
5619 COPY_FPGM(bci_vwidth_data_store);
5620 COPY_FPGM(bci_blue_round);
5621 COPY_FPGM(bci_blue_round_range);
5622 COPY_FPGM(bci_decrement_component_counter);
5623 COPY_FPGM(bci_get_point_extrema);
5624 COPY_FPGM(bci_nibbles);
5625 COPY_FPGM(bci_number_set_is_element);
5626 COPY_FPGM(bci_number_set_is_element2);
5628 COPY_FPGM(bci_create_segment);
5629 COPY_FPGM(bci_create_segments);
5631 COPY_FPGM(bci_create_segments_0);
5632 COPY_FPGM(bci_create_segments_1);
5633 COPY_FPGM(bci_create_segments_2);
5634 COPY_FPGM(bci_create_segments_3);
5635 COPY_FPGM(bci_create_segments_4);
5636 COPY_FPGM(bci_create_segments_5);
5637 COPY_FPGM(bci_create_segments_6);
5638 COPY_FPGM(bci_create_segments_7);
5639 COPY_FPGM(bci_create_segments_8);
5640 COPY_FPGM(bci_create_segments_9);
5642 COPY_FPGM(bci_create_segments_composite);
5644 COPY_FPGM(bci_create_segments_composite_0);
5645 COPY_FPGM(bci_create_segments_composite_1);
5646 COPY_FPGM(bci_create_segments_composite_2);
5647 COPY_FPGM(bci_create_segments_composite_3);
5648 COPY_FPGM(bci_create_segments_composite_4);
5649 COPY_FPGM(bci_create_segments_composite_5);
5650 COPY_FPGM(bci_create_segments_composite_6);
5651 COPY_FPGM(bci_create_segments_composite_7);
5652 COPY_FPGM(bci_create_segments_composite_8);
5653 COPY_FPGM(bci_create_segments_composite_9);
5655 COPY_FPGM(bci_align_point);
5656 COPY_FPGM(bci_align_segment);
5657 COPY_FPGM(bci_align_segments);
5659 COPY_FPGM(bci_scale_contour);
5660 COPY_FPGM(bci_scale_glyph);
5661 COPY_FPGM(bci_scale_composite_glyph);
5662 COPY_FPGM(bci_shift_contour);
5663 COPY_FPGM(bci_shift_subglyph);
5665 COPY_FPGM(bci_ip_outer_align_point);
5666 COPY_FPGM(bci_ip_on_align_points);
5667 COPY_FPGM(bci_ip_between_align_point);
5668 COPY_FPGM(bci_ip_between_align_points);
5670 COPY_FPGM(bci_adjust_common);
5671 COPY_FPGM(bci_stem_common);
5672 COPY_FPGM(bci_serif_common);
5673 COPY_FPGM(bci_serif_anchor_common);
5674 COPY_FPGM(bci_serif_link1_common);
5675 COPY_FPGM(bci_serif_link2_common);
5677 COPY_FPGM(bci_lower_bound);
5678 COPY_FPGM(bci_upper_bound);
5679 COPY_FPGM(bci_upper_lower_bound);
5681 COPY_FPGM(bci_adjust_bound);
5682 COPY_FPGM(bci_stem_bound);
5683 COPY_FPGM(bci_link);
5684 COPY_FPGM(bci_anchor);
5685 COPY_FPGM(bci_adjust);
5686 COPY_FPGM(bci_stem);
5688 COPY_FPGM(bci_action_ip_before);
5689 COPY_FPGM(bci_action_ip_after);
5690 COPY_FPGM(bci_action_ip_on);
5691 COPY_FPGM(bci_action_ip_between);
5693 COPY_FPGM(bci_action_blue);
5694 COPY_FPGM(bci_action_blue_anchor);
5696 COPY_FPGM(bci_action_anchor);
5697 COPY_FPGM(bci_action_anchor_serif);
5698 COPY_FPGM(bci_action_anchor_round);
5699 COPY_FPGM(bci_action_anchor_round_serif);
5701 COPY_FPGM(bci_action_adjust);
5702 COPY_FPGM(bci_action_adjust_serif);
5703 COPY_FPGM(bci_action_adjust_round);
5704 COPY_FPGM(bci_action_adjust_round_serif);
5705 COPY_FPGM(bci_action_adjust_bound);
5706 COPY_FPGM(bci_action_adjust_bound_serif);
5707 COPY_FPGM(bci_action_adjust_bound_round);
5708 COPY_FPGM(bci_action_adjust_bound_round_serif);
5710 COPY_FPGM(bci_action_link);
5711 COPY_FPGM(bci_action_link_serif);
5712 COPY_FPGM(bci_action_link_round);
5713 COPY_FPGM(bci_action_link_round_serif);
5715 COPY_FPGM(bci_action_stem);
5716 COPY_FPGM(bci_action_stem_serif);
5717 COPY_FPGM(bci_action_stem_round);
5718 COPY_FPGM(bci_action_stem_round_serif);
5719 COPY_FPGM(bci_action_stem_bound);
5720 COPY_FPGM(bci_action_stem_bound_serif);
5721 COPY_FPGM(bci_action_stem_bound_round);
5722 COPY_FPGM(bci_action_stem_bound_round_serif);
5724 COPY_FPGM(bci_action_serif);
5725 COPY_FPGM(bci_action_serif_lower_bound);
5726 COPY_FPGM(bci_action_serif_upper_bound);
5727 COPY_FPGM(bci_action_serif_upper_lower_bound);
5729 COPY_FPGM(bci_action_serif_anchor);
5730 COPY_FPGM(bci_action_serif_anchor_lower_bound);
5731 COPY_FPGM(bci_action_serif_anchor_upper_bound);
5732 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound);
5734 COPY_FPGM(bci_action_serif_link1);
5735 COPY_FPGM(bci_action_serif_link1_lower_bound);
5736 COPY_FPGM(bci_action_serif_link1_upper_bound);
5737 COPY_FPGM(bci_action_serif_link1_upper_lower_bound);
5739 COPY_FPGM(bci_action_serif_link2);
5740 COPY_FPGM(bci_action_serif_link2_lower_bound);
5741 COPY_FPGM(bci_action_serif_link2_upper_bound);
5742 COPY_FPGM(bci_action_serif_link2_upper_lower_bound);
5744 COPY_FPGM(bci_hint_glyph);
5746 *fpgm = buf;
5747 *fpgm_len = buf_len;
5749 return FT_Err_Ok;
5753 FT_Error
5754 TA_sfnt_build_fpgm_table(SFNT* sfnt,
5755 FONT* font)
5757 FT_Error error;
5759 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
5760 glyf_Data* data = (glyf_Data*)glyf_table->data;
5762 FT_Byte* fpgm_buf;
5763 FT_ULong fpgm_len;
5766 error = TA_sfnt_add_table_info(sfnt);
5767 if (error)
5768 goto Exit;
5770 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5771 if (glyf_table->processed)
5773 sfnt->table_infos[sfnt->num_table_infos - 1] = data->fpgm_idx;
5774 goto Exit;
5777 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, sfnt, font);
5778 if (error)
5779 goto Exit;
5781 if (fpgm_len > sfnt->max_instructions)
5782 sfnt->max_instructions = fpgm_len;
5784 /* in case of success, `fpgm_buf' gets linked */
5785 /* and is eventually freed in `TA_font_unload' */
5786 error = TA_font_add_table(font,
5787 &sfnt->table_infos[sfnt->num_table_infos - 1],
5788 TTAG_fpgm, fpgm_len, fpgm_buf);
5789 if (error)
5790 free(fpgm_buf);
5791 else
5792 data->fpgm_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
5794 Exit:
5795 return error;
5798 /* end of tafpgm.c */