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.
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 \
38 #define MD_orig_ZP2_0 \
41 #define MD_orig_ZP2_1 \
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
57 MUL, /* delta * 2^10 */ \
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
81 unsigned char FPGM(bci_round
) [] =
99 * bci_smooth_stem_width
101 * This is the equivalent to the following code from function
102 * `ta_latin_compute_stem_width':
110 * else if base_is_round:
116 * delta = ABS(dist - std_width)
127 * delta = delta - dist
130 * dist = dist + delta
131 * else if delta < 32:
133 * else if delta < 54:
136 * dist = dist + delta
152 * CVT: cvtl_is_extra_light
158 unsigned char FPGM(bci_smooth_stem_width_a
) [] =
162 bci_smooth_stem_width
,
166 ABS
, /* s: base_is_round stem_is_serif width dist */
171 LT
, /* dist < 3*64 */
175 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
176 AND
, /* stem_is_serif && dist < 3*64 */
181 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
183 IF
, /* s: base_is_round width dist */
189 ROLL
, /* s: width dist base_is_round */
190 IF
, /* s: width dist */
195 IF
, /* s: width dist */
206 IF
, /* s: width dist */
213 DUP
, /* s: width dist dist */
218 /* %c, index of std_width */
220 unsigned char FPGM(bci_smooth_stem_width_b
) [] =
225 ABS
, /* s: width dist delta */
230 IF
, /* s: width dist */
236 /* %c, index of std_width */
238 unsigned char FPGM(bci_smooth_stem_width_c
) [] =
241 RCVT
, /* dist = std_width */
253 DUP
, /* s: width dist dist */
256 LT
, /* dist < 3*64 */
258 DUP
, /* s: width delta dist */
259 FLOOR
, /* dist = FLOOR(dist) */
260 DUP
, /* s: width delta dist dist */
262 ROLL
, /* s: width dist delta dist */
263 SUB
, /* delta = delta - dist */
265 DUP
, /* s: width dist delta delta */
269 IF
, /* s: width dist delta */
270 ADD
, /* dist = dist + delta */
281 ADD
, /* dist = dist + 10 */
292 ADD
, /* dist = dist + 54 */
295 ADD
, /* dist = dist + delta */
304 CALL
, /* dist = round(dist) */
309 SWAP
, /* s: dist width */
314 NEG
, /* dist = -dist */
326 * An auxiliary function for `bci_strong_stem_width'.
328 * in: n (initialized with CVT index for first vertical width)
340 unsigned char FPGM(bci_get_best_width
) [] =
348 RCVT
, /* s: dist n w */
352 CINDEX
, /* s: dist n w w dist */
354 ABS
, /* s: dist n w d */
358 RS
, /* s: dist n w d d best */
368 WS
, /* reference = w */
385 * bci_strong_stem_width
387 * This is the equivalent to the following code (function
388 * `ta_latin_snap_width' and some lines from
389 * `ta_latin_compute_stem_width'):
391 * best = 64 + 32 + 2;
395 * for n in 0 .. num_widths:
403 * if dist >= reference:
404 * if dist < ROUND(reference) + 48:
407 * if dist > ROUND(reference) - 48:
420 * stem_is_serif (unused)
421 * base_is_round (unused)
430 * uses: bci_get_best_width
434 unsigned char FPGM(bci_strong_stem_width_a
) [] =
438 bci_strong_stem_width
,
446 ABS
, /* s: width dist */
451 WS
, /* sal_best = 98 */
457 WS
, /* sal_ref = width */
462 /* %c, first index of vertical widths */
463 /* %c, number of vertical widths */
465 unsigned char FPGM(bci_strong_stem_width_b
) [] =
471 POP
, /* s: width dist */
475 RS
, /* s: width dist dist reference */
482 CALL
, /* s: width dist reference dist dist ROUND(reference) */
487 ROLL
, /* s: width dist reference dist ROUND(reference) 48 reference dist */
489 LTEQ
, /* dist >= reference */
490 IF
, /* s: width dist reference dist ROUND(reference) 48 */
492 LT
, /* dist < ROUND(reference) + 48 */
496 GT
, /* dist > ROUND(reference) - 48 */
500 SWAP
, /* s: width reference dist */
507 GTEQ
, /* dist >= 64 */
511 CALL
, /* dist = ROUND(dist) */
519 SWAP
, /* s: dist width */
524 NEG
, /* dist = -dist */
535 * An auxiliary function for `bci_loop'.
537 * sal: sal_i (gets incremented by 2 after execution)
540 * uses: func[sal_func]
543 unsigned char FPGM(bci_loop_do
) [] =
560 ADD
, /* sal_i = sal_i + 2 */
571 * Take a range `start'..`end' and a function number and apply the
572 * associated function to the range elements `start', `start+2',
579 * sal: sal_i (counter initialized with `start')
580 * sal_func (`func_num')
585 unsigned char FPGM(bci_loop
) [] =
595 WS
, /* sal_func = func_num */
602 WS
, /* sal_i = start */
610 ADD
, /* number of loops ((end - start) / 2 + 1) */
624 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
626 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
627 * consequently, the calculation `a * b/c' is done as `a + delta' with
628 * `delta = a * (b-c)/c'. This avoids overflow.
638 unsigned char FPGM(bci_cvt_rescale
) [] =
663 * Round a blue ref value and adjust its corresponding shoot value.
665 * This is the equivalent to the following code (function
666 * `ta_latin_metrics_scale_dim':
674 * else if (delta < 48)
689 unsigned char FPGM(bci_blue_round_a
) [] =
698 RCVT
, /* s: ref_idx ref_idx ref */
704 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
712 unsigned char FPGM(bci_blue_round_b
) [] =
717 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
719 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
721 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
723 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
725 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
750 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
755 NEG
, /* delta = -delta */
762 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
769 ADD
, /* s: (ref_idx + 1) */
777 * bci_decrement_component_counter
779 * An auxiliary function for composite glyphs.
781 * CVT: cvtl_is_subglyph
784 unsigned char FPGM(bci_decrement_component_counter
) [] =
788 bci_decrement_component_counter
,
791 /* decrement `cvtl_is_subglyph' counter */
807 * bci_get_point_extrema
809 * An auxiliary function for `bci_create_segment'.
819 unsigned char FPGM(bci_get_point_extrema
) [] =
823 bci_get_point_extrema
,
832 /* check whether `point' is a new minimum */
835 RS
, /* s: point point point point_min */
837 /* if distance is negative, we have a new minimum */
841 IF
, /* s: point point */
849 /* check whether `point' is a new maximum */
852 RS
, /* s: point point point_max */
854 /* if distance is positive, we have a new maximum */
874 * Pop a byte with two delta arguments in its nibbles and push the
875 * expanded arguments separately as two bytes.
877 * in: 16 * (end - start) + (start - base)
882 * sal: sal_base (set to `end' at return)
886 unsigned char FPGM(bci_nibbles
) [] =
896 DIV
, /* s: in hnibble */
901 MUL
, /* s: in hnibble (hnibble * 16) */
904 SUB
, /* s: hnibble lnibble */
909 ADD
, /* s: hnibble start */
912 ADD
, /* s: start end */
918 WS
, /* sal_base = end */
928 * bci_number_set_is_element
930 * Pop values from stack until it is empty. If one of them is equal to
931 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
938 * CVT: cvtl_is_element
941 unsigned char FPGM(bci_number_set_is_element
) [] =
945 bci_number_set_is_element
,
963 JROT
, /* goto start_loop if stack depth != 0 */
971 * bci_number_set_is_element2
973 * Pop value ranges from stack until it is empty. If one of them contains
974 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
977 * in: ppem_range_1_start
983 * CVT: cvtl_is_element
986 unsigned char FPGM(bci_number_set_is_element2
) [] =
990 bci_number_set_is_element2
,
1014 JROT
, /* goto start_loop if stack depth != 0 */
1022 * bci_create_segment
1024 * Store start and end point of a segment in the storage area,
1025 * then construct a point in the twilight zone to represent it.
1027 * This function is used by `bci_create_segments'.
1031 * [last (if wrap-around segment)]
1032 * [first (if wrap-around segment)]
1034 * sal: sal_i (start of current segment)
1035 * sal_j (current twilight point)
1039 * sal_num_packed_segments
1045 * uses: bci_get_point_extrema
1048 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1049 * delta values in nibbles (without a wrap-around segment).
1052 unsigned char FPGM(bci_create_segment
) [] =
1061 sal_num_packed_segments
,
1066 sal_num_packed_segments
,
1067 sal_num_packed_segments
,
1072 WS
, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1085 WS
, /* sal[sal_i] = start */
1087 /* initialize inner loop(s) */
1092 WS
, /* sal_point_min = start */
1097 WS
, /* sal_point_max = start */
1101 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1107 CINDEX
, /* s: start end end start */
1108 LT
, /* start > end */
1110 /* we have a wrap-around segment with two more arguments */
1111 /* to give the last and first point of the contour, respectively; */
1112 /* our job is to store a segment `start'-`last', */
1113 /* and to get extrema for the two segments */
1114 /* `start'-`last' and `first'-`end' */
1116 /* s: first last start end */
1125 WS
, /* sal[sal_i + 1] = last */
1128 ROLL
, /* s: first end last start */
1131 SWAP
, /* s: first end start last start */
1132 SUB
, /* s: first end start loop_count */
1135 bci_get_point_extrema
,
1137 /* clean up stack */
1140 SWAP
, /* s: end first */
1145 ROLL
, /* s: (first - 1) (first - 1) end */
1147 SUB
, /* s: (first - 1) loop_count */
1150 bci_get_point_extrema
,
1152 /* clean up stack */
1155 ELSE
, /* s: start end */
1164 WS
, /* sal[sal_i + 1] = end */
1169 SUB
, /* s: start loop_count */
1172 bci_get_point_extrema
,
1174 /* clean up stack */
1178 /* the twilight point representing a segment */
1179 /* is in the middle between the minimum and maximum */
1191 DIV
, /* s: middle_pos */
1193 DO_SCALE
, /* middle_pos = middle_pos * scale */
1195 /* write it to temporary CVT location */
1199 SZP0
, /* set zp0 to twilight zone 0 */
1203 /* create twilight point with index `sal_j' */
1216 ADD
, /* twilight_point = twilight_point + 1 */
1225 * bci_create_segments
1227 * This is the top-level entry function.
1229 * It pops point ranges from the stack to define segments, computes
1230 * twilight points to represent segments, and finally calls
1231 * `bci_hint_glyph' to handle the rest.
1233 * in: num_packed_segments
1237 * [contour_last 0 (if wrap-around segment)]
1238 * [contour_first 0 (if wrap-around segment)]
1241 * [contour_last 0 (if wrap-around segment)]
1242 * [contour_first 0 (if wrap-around segment)]
1244 * segment_start_(N-1)
1246 * [contour_last (N-1) (if wrap-around segment)]
1247 * [contour_first (N-1) (if wrap-around segment)]
1248 * ... stuff for bci_hint_glyph ...
1250 * sal: sal_i (start of current segment)
1251 * sal_j (current twilight point)
1252 * sal_num_packed_segments
1253 * sal_base (the base for delta values in nibbles)
1255 * CVT: cvtl_is_subglyph
1257 * uses: bci_create_segment
1261 * If `num_packed_segments' is set to p, the first p start/end pairs are
1262 * stored as delta values in nibbles, with the `start' delta in the lower
1263 * nibble (and there are no wrap-around segments). For example, if the
1264 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1265 * stack are 0x21, 0x32, and 0x14.
1269 unsigned char FPGM(bci_create_segments
) [] =
1273 bci_create_segments
,
1276 /* only do something if we are not a subglyph */
1283 /* all our measurements are taken along the y axis */
1287 sal_num_packed_segments
,
1295 SUB
, /* delta = (2*num_segments - 1) */
1305 WS
, /* sal_base = 0 */
1306 WS
, /* sal_j = 0 (point offset) */
1309 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1330 * bci_create_segments_X
1332 * Top-level routines for calling `bci_create_segments'.
1335 unsigned char FPGM(bci_create_segments_0
) [] =
1339 bci_create_segments_0
,
1344 bci_create_segments
,
1351 unsigned char FPGM(bci_create_segments_1
) [] =
1355 bci_create_segments_1
,
1360 bci_create_segments
,
1367 unsigned char FPGM(bci_create_segments_2
) [] =
1371 bci_create_segments_2
,
1376 bci_create_segments
,
1383 unsigned char FPGM(bci_create_segments_3
) [] =
1387 bci_create_segments_3
,
1392 bci_create_segments
,
1399 unsigned char FPGM(bci_create_segments_4
) [] =
1403 bci_create_segments_4
,
1408 bci_create_segments
,
1415 unsigned char FPGM(bci_create_segments_5
) [] =
1419 bci_create_segments_5
,
1424 bci_create_segments
,
1431 unsigned char FPGM(bci_create_segments_6
) [] =
1435 bci_create_segments_6
,
1440 bci_create_segments
,
1447 unsigned char FPGM(bci_create_segments_7
) [] =
1451 bci_create_segments_7
,
1456 bci_create_segments
,
1463 unsigned char FPGM(bci_create_segments_8
) [] =
1467 bci_create_segments_8
,
1472 bci_create_segments
,
1479 unsigned char FPGM(bci_create_segments_9
) [] =
1483 bci_create_segments_9
,
1488 bci_create_segments
,
1497 * bci_create_segments_composite
1499 * The same as `bci_create_segments'.
1500 * It also decrements the composite component counter.
1502 * sal: sal_num_packed_segments
1503 * sal_segment_offset
1505 * CVT: cvtl_is_subglyph
1507 * uses: bci_decrement_component_counter
1508 * bci_create_segment
1513 unsigned char FPGM(bci_create_segments_composite
) [] =
1517 bci_create_segments_composite
,
1521 bci_decrement_component_counter
,
1524 /* only do something if we are not a subglyph */
1531 /* all our measurements are taken along the y axis */
1535 sal_num_packed_segments
,
1543 SUB
, /* delta = (2*num_segments - 1) */
1553 WS
, /* sal_base = 0 */
1554 WS
, /* sal_j = 0 (point offset) */
1557 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1578 * bci_create_segments_composite_X
1580 * Top-level routines for calling `bci_create_segments_composite'.
1583 unsigned char FPGM(bci_create_segments_composite_0
) [] =
1587 bci_create_segments_composite_0
,
1592 bci_create_segments_composite
,
1599 unsigned char FPGM(bci_create_segments_composite_1
) [] =
1603 bci_create_segments_composite_1
,
1608 bci_create_segments_composite
,
1615 unsigned char FPGM(bci_create_segments_composite_2
) [] =
1619 bci_create_segments_composite_2
,
1624 bci_create_segments_composite
,
1631 unsigned char FPGM(bci_create_segments_composite_3
) [] =
1635 bci_create_segments_composite_3
,
1640 bci_create_segments_composite
,
1647 unsigned char FPGM(bci_create_segments_composite_4
) [] =
1651 bci_create_segments_composite_4
,
1656 bci_create_segments_composite
,
1663 unsigned char FPGM(bci_create_segments_composite_5
) [] =
1667 bci_create_segments_composite_5
,
1672 bci_create_segments_composite
,
1679 unsigned char FPGM(bci_create_segments_composite_6
) [] =
1683 bci_create_segments_composite_6
,
1688 bci_create_segments_composite
,
1695 unsigned char FPGM(bci_create_segments_composite_7
) [] =
1699 bci_create_segments_composite_7
,
1704 bci_create_segments_composite
,
1711 unsigned char FPGM(bci_create_segments_composite_8
) [] =
1715 bci_create_segments_composite_8
,
1720 bci_create_segments_composite
,
1727 unsigned char FPGM(bci_create_segments_composite_9
) [] =
1731 bci_create_segments_composite_9
,
1736 bci_create_segments_composite
,
1747 * An auxiliary function for `bci_align_segment'.
1754 unsigned char FPGM(bci_align_point
) [] =
1762 ALIGNRP
, /* align point with rp0 */
1776 * Align all points in a segment to the twilight point in rp0.
1777 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1781 * sal: sal_segment_offset
1783 * uses: bci_align_point
1786 unsigned char FPGM(bci_align_segment
) [] =
1793 /* we need the values of `sal_segment_offset + 2*segment_index' */
1794 /* and `sal_segment_offset + 2*segment_index + 1' */
1806 RS
, /* s: first last */
1810 CINDEX
, /* s: first last first */
1814 ADD
, /* s: first loop_count */
1819 /* clean up stack */
1828 * bci_align_segments
1830 * Align segments to the twilight point in rp0.
1831 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1840 * uses: bci_align_segment
1843 unsigned char FPGM(bci_align_segments
) [] =
1866 * Scale a contour using two points giving the maximum and minimum
1869 * It expects that no point on the contour is touched.
1878 unsigned char FPGM(bci_scale_contour
) [] =
1889 DO_SCALE
, /* min_pos_new = min_pos * scale */
1894 /* don't scale a single-point contour twice */
1903 DO_SCALE
, /* max_pos_new = max_pos * scale */
1920 * Scale a glyph using a list of points (two points per contour, giving
1921 * the maximum and mininum coordinates).
1923 * It expects that no point in the glyph is touched.
1925 * Note that the point numbers are sorted in ascending order;
1926 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1927 * contour without specifying which one is the minimum and maximum.
1929 * in: num_contours (N)
1938 * CVT: cvtl_is_subglyph
1940 * uses: bci_scale_contour
1943 unsigned char FPGM(bci_scale_glyph
) [] =
1950 /* only do something if we are not a subglyph */
1957 /* all our measurements are taken along the y axis */
1962 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1970 SZP2
, /* set zp2 to normal zone 1 */
1983 * bci_scale_composite_glyph
1985 * The same as `bci_scale_glyph'.
1986 * It also decrements the composite component counter.
1988 * CVT: cvtl_is_subglyph
1990 * uses: bci_decrement_component_counter
1994 unsigned char FPGM(bci_scale_composite_glyph
) [] =
1998 bci_scale_composite_glyph
,
2002 bci_decrement_component_counter
,
2005 /* only do something if we are not a subglyph */
2012 /* all our measurements are taken along the y axis */
2017 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2025 SZP2
, /* set zp2 to normal zone 1 */
2040 * Shift a contour by a given amount.
2042 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2043 * point to the normal zone 1.
2050 unsigned char FPGM(bci_shift_contour
) [] =
2058 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2070 * bci_shift_subglyph
2072 * Shift a subglyph. To be more specific, it corrects the already applied
2073 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2076 * If this function is called, a point `x' in the subglyph has been scaled
2077 * already (during the hinting of the subglyph itself), and `offset' has
2078 * been applied also:
2080 * x -> x * scale + offset (1)
2082 * However, the offset should be applied first, then the scaling:
2084 * x -> (x + offset) * scale (2)
2086 * Our job is now to transform (1) to (2); a simple calculation shows that
2087 * we have to shift all points of the subglyph by
2089 * offset * scale - offset = offset * (scale - 1)
2091 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2093 * in: offset (in FUnits)
2097 * CVT: cvtl_funits_to_pixels
2105 unsigned char FPGM(bci_shift_subglyph
) [] =
2115 cvtl_funits_to_pixels
,
2116 RCVT
, /* scaling factor FUnits -> pixels */
2123 /* the autohinter always rounds offsets */
2126 CALL
, /* offset = round(offset) */
2135 DIV
, /* delta = offset * (scale - 1) */
2137 /* and round again */
2140 CALL
, /* offset = round(offset) */
2144 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2146 /* we create twilight point 0 as a reference point, */
2147 /* setting the original position to zero (using `cvtl_temp') */
2155 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
2157 SWAP
, /* s: first_contour num_contours 0 delta */
2158 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
2163 SZP2
, /* set zp2 to normal zone 1 */
2172 * bci_ip_outer_align_point
2174 * Auxiliary function for `bci_action_ip_before' and
2175 * `bci_action_ip_after'.
2177 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2178 * zone, and both zp1 and zp2 set to normal zone.
2182 * sal: sal_i (edge_orig_pos)
2188 unsigned char FPGM(bci_ip_outer_align_point
) [] =
2192 bci_ip_outer_align_point
,
2196 ALIGNRP
, /* align `point' with `edge' */
2199 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2204 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2213 * bci_ip_on_align_points
2215 * Auxiliary function for `bci_action_ip_on'.
2217 * in: edge (in twilight zone)
2225 unsigned char FPGM(bci_ip_on_align_points
) [] =
2229 bci_ip_on_align_points
,
2232 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2243 * bci_ip_between_align_point
2245 * Auxiliary function for `bci_ip_between_align_points'.
2247 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2248 * zone, and both zp1 and zp2 set to normal zone.
2252 * sal: sal_i (edge_orig_pos)
2253 * sal_j (stretch_factor)
2259 unsigned char FPGM(bci_ip_between_align_point
) [] =
2263 bci_ip_between_align_point
,
2267 ALIGNRP
, /* align `point' with `edge' */
2270 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2275 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2279 MUL
, /* s: point delta */
2288 * bci_ip_between_align_points
2290 * Auxiliary function for `bci_action_ip_between'.
2292 * in: after_edge (in twilight zone)
2293 * before_edge (in twilight zone)
2300 * sal: sal_i (before_orig_pos)
2301 * sal_j (stretch_factor)
2303 * uses: bci_ip_between_align_point
2306 unsigned char FPGM(bci_ip_between_align_points
) [] =
2310 bci_ip_between_align_points
,
2316 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2318 DUP
, /* s: ... before after before before */
2319 MDAP_noround
, /* set rp0 and rp1 to `before' */
2321 GC_orig
, /* s: ... before after before before_orig_pos */
2325 WS
, /* sal_i = before_orig_pos */
2328 CINDEX
, /* s: ... before after before after */
2329 MD_cur
, /* a = after_pos - before_pos */
2332 MD_orig_ZP2_0
, /* b = after_orig_pos - before_orig_pos */
2338 POP
, /* avoid division by zero */
2344 WS
, /* sal_j = stretch_factor */
2347 bci_ip_between_align_point
,
2350 SZP2
, /* set zp2 to normal zone 1 */
2351 SZP1
, /* set zp1 to normal zone 1 */
2360 * bci_action_ip_before
2362 * Handle `ip_before' data to align points located before the first edge.
2364 * in: first_edge (in twilight zone)
2371 * sal: sal_i (first_edge_orig_pos)
2373 * uses: bci_ip_outer_align_point
2376 unsigned char FPGM(bci_action_ip_before
) [] =
2380 bci_action_ip_before
,
2385 SZP2
, /* set zp2 to twilight zone 0 */
2392 WS
, /* sal_i = first_edge_orig_pos */
2398 SZP2
, /* set zp2 to normal zone 1 */
2399 SZP1
, /* set zp1 to normal zone 1 */
2400 SZP0
, /* set zp0 to twilight zone 0 */
2402 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
2405 bci_ip_outer_align_point
,
2414 * bci_action_ip_after
2416 * Handle `ip_after' data to align points located after the last edge.
2418 * in: last_edge (in twilight zone)
2425 * sal: sal_i (last_edge_orig_pos)
2427 * uses: bci_ip_outer_align_point
2430 unsigned char FPGM(bci_action_ip_after
) [] =
2434 bci_action_ip_after
,
2439 SZP2
, /* set zp2 to twilight zone 0 */
2446 WS
, /* sal_i = last_edge_orig_pos */
2452 SZP2
, /* set zp2 to normal zone 1 */
2453 SZP1
, /* set zp1 to normal zone 1 */
2454 SZP0
, /* set zp0 to twilight zone 0 */
2456 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
2459 bci_ip_outer_align_point
,
2470 * Handle `ip_on' data to align points located on an edge coordinate (but
2471 * not part of an edge).
2473 * in: loop_counter (M)
2474 * edge_1 (in twilight zone)
2475 * loop_counter (N_1)
2480 * edge_2 (in twilight zone)
2481 * loop_counter (N_2)
2487 * edge_M (in twilight zone)
2488 * loop_counter (N_M)
2494 * uses: bci_ip_on_align_points
2497 unsigned char FPGM(bci_action_ip_on
) [] =
2507 SZP1
, /* set zp1 to normal zone 1 */
2508 SZP0
, /* set zp0 to twilight zone 0 */
2511 bci_ip_on_align_points
,
2520 * bci_action_ip_between
2522 * Handle `ip_between' data to align points located between two edges.
2524 * in: loop_counter (M)
2525 * before_edge_1 (in twilight zone)
2526 * after_edge_1 (in twilight zone)
2527 * loop_counter (N_1)
2532 * before_edge_2 (in twilight zone)
2533 * after_edge_2 (in twilight zone)
2534 * loop_counter (N_2)
2540 * before_edge_M (in twilight zone)
2541 * after_edge_M (in twilight zone)
2542 * loop_counter (N_M)
2548 * uses: bci_ip_between_align_points
2551 unsigned char FPGM(bci_action_ip_between
) [] =
2555 bci_action_ip_between
,
2559 bci_ip_between_align_points
,
2570 * Common code for bci_action_adjust routines.
2572 * uses: func[cvtl_stem_width_function]
2575 unsigned char FPGM(bci_adjust_common
) [] =
2584 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2588 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
2591 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2592 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
2595 cvtl_stem_width_function
,
2598 NEG
, /* s: [...] edge2 edge -cur_len */
2600 ROLL
, /* s: [...] edge -cur_len edge2 */
2601 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2604 DUP
, /* s: [...] -cur_len edge edge edge */
2605 ALIGNRP
, /* align `edge' with `edge2' */
2607 SHPIX
, /* shift `edge' by -cur_len */
2617 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2618 * edge of the stem has already been moved, then moving it again if
2619 * necessary to stay bound.
2621 * in: edge2_is_serif
2623 * edge_point (in twilight zone)
2624 * edge2_point (in twilight zone)
2625 * edge[-1] (in twilight zone)
2626 * ... stuff for bci_align_segments (edge) ...
2628 * uses: bci_adjust_common
2629 * bci_align_segments
2632 unsigned char FPGM(bci_adjust_bound
) [] =
2643 SWAP
, /* s: edge edge[-1] */
2645 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2650 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2651 GT
, /* edge_pos < edge[-1]_pos */
2654 ALIGNRP
, /* align `edge' to `edge[-1]' */
2657 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2662 SZP1
, /* set zp1 to normal zone 1 */
2671 * bci_action_adjust_bound
2672 * bci_action_adjust_bound_serif
2673 * bci_action_adjust_bound_round
2674 * bci_action_adjust_bound_round_serif
2676 * Higher-level routines for calling `bci_adjust_bound'.
2679 unsigned char FPGM(bci_action_adjust_bound
) [] =
2683 bci_action_adjust_bound
,
2696 unsigned char FPGM(bci_action_adjust_bound_serif
) [] =
2700 bci_action_adjust_bound_serif
,
2713 unsigned char FPGM(bci_action_adjust_bound_round
) [] =
2717 bci_action_adjust_bound_round
,
2730 unsigned char FPGM(bci_action_adjust_bound_round_serif
) [] =
2734 bci_action_adjust_bound_round_serif
,
2751 * Handle the ADJUST action to align an edge of a stem if the other edge
2752 * of the stem has already been moved.
2754 * in: edge2_is_serif
2756 * edge_point (in twilight zone)
2757 * edge2_point (in twilight zone)
2758 * ... stuff for bci_align_segments (edge) ...
2760 * uses: bci_adjust_common
2761 * bci_align_segments
2764 unsigned char FPGM(bci_adjust
) [] =
2775 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2780 SZP1
, /* set zp1 to normal zone 1 */
2790 * bci_action_adjust_serif
2791 * bci_action_adjust_round
2792 * bci_action_adjust_round_serif
2794 * Higher-level routines for calling `bci_adjust'.
2797 unsigned char FPGM(bci_action_adjust
) [] =
2814 unsigned char FPGM(bci_action_adjust_serif
) [] =
2818 bci_action_adjust_serif
,
2831 unsigned char FPGM(bci_action_adjust_round
) [] =
2835 bci_action_adjust_round
,
2848 unsigned char FPGM(bci_action_adjust_round_serif
) [] =
2852 bci_action_adjust_round_serif
,
2869 * Common code for bci_action_stem routines.
2876 * uses: func[cvtl_stem_width_function]
2881 #define sal_u_off sal_temp1
2883 #define sal_d_off sal_temp2
2885 #define sal_org_len sal_temp3
2887 #define sal_edge2 sal_temp3
2889 unsigned char FPGM(bci_stem_common
) [] =
2898 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2906 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2907 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2909 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
2917 cvtl_stem_width_function
,
2919 CALL
, /* s: [...] edge2 edge cur_len */
2924 LT
, /* cur_len < 96 */
2929 LTEQ
, /* cur_len <= 64 */
2947 SWAP
, /* s: [...] edge2 cur_len edge */
2952 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
2958 ADD
, /* s: [...] edge2 cur_len edge org_pos */
2965 ADD
, /* s: [...] edge2 cur_len edge org_center */
2970 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2975 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2982 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2989 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2991 LT
, /* delta1 < delta2 */
2996 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3002 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3003 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
3011 SUB
, /* arg = cur_pos1 - cur_len/2 */
3013 SWAP
, /* s: [...] edge2 cur_len arg edge */
3019 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3022 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3025 SWAP
, /* s: [...] edge2 cur_len edge */
3029 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
3037 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3046 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
3052 CALL
, /* cur_pos1 = ROUND(org_pos) */
3064 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3075 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3082 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3088 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3089 LT
, /* delta1 < delta2 */
3091 POP
, /* arg = cur_pos1 */
3095 POP
, /* arg = cur_pos2 */
3096 EIF
, /* s: [...] edge2 cur_len edge arg */
3103 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3106 SHPIX
, /* edge = arg */
3107 EIF
, /* s: [...] edge2 cur_len edge */
3117 * Handle the STEM action to align two edges of a stem, then moving one
3118 * edge again if necessary to stay bound.
3120 * The code after computing `cur_len' to shift `edge' and `edge2'
3121 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3124 * if cur_len < = 64:
3131 * org_pos = anchor + (edge_orig - anchor_orig);
3132 * org_center = org_pos + org_len / 2;
3134 * cur_pos1 = ROUND(org_center)
3135 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3136 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3137 * if (delta1 < delta2):
3138 * cur_pos1 = cur_pos1 - u_off
3140 * cur_pos1 = cur_pos1 + d_off
3142 * edge = cur_pos1 - cur_len / 2
3145 * org_pos = anchor + (edge_orig - anchor_orig)
3146 * org_center = org_pos + org_len / 2;
3148 * cur_pos1 = ROUND(org_pos)
3149 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3150 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3151 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3153 * if (delta1 < delta2):
3158 * edge2 = edge + cur_len
3160 * in: edge2_is_serif
3162 * edge_point (in twilight zone)
3163 * edge2_point (in twilight zone)
3164 * edge[-1] (in twilight zone)
3165 * ... stuff for bci_align_segments (edge) ...
3166 * ... stuff for bci_align_segments (edge2)...
3173 * uses: bci_stem_common
3174 * bci_align_segments
3177 unsigned char FPGM(bci_stem_bound
) [] =
3188 ROLL
, /* s: edge[-1] cur_len edge edge2 */
3191 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3195 WS
, /* s: edge[-1] cur_len edge edge2 */
3197 SHPIX
, /* edge2 = edge + cur_len */
3199 SWAP
, /* s: edge edge[-1] */
3201 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3206 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3207 GT
, /* edge_pos < edge[-1]_pos */
3210 ALIGNRP
, /* align `edge' to `edge[-1]' */
3213 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3218 SZP1
, /* set zp1 to normal zone 1 */
3224 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3236 * bci_action_stem_bound
3237 * bci_action_stem_bound_serif
3238 * bci_action_stem_bound_round
3239 * bci_action_stem_bound_round_serif
3241 * Higher-level routines for calling `bci_stem_bound'.
3244 unsigned char FPGM(bci_action_stem_bound
) [] =
3248 bci_action_stem_bound
,
3261 unsigned char FPGM(bci_action_stem_bound_serif
) [] =
3265 bci_action_stem_bound_serif
,
3278 unsigned char FPGM(bci_action_stem_bound_round
) [] =
3282 bci_action_stem_bound_round
,
3295 unsigned char FPGM(bci_action_stem_bound_round_serif
) [] =
3299 bci_action_stem_bound_round_serif
,
3316 * Handle the STEM action to align two edges of a stem.
3318 * See `bci_stem_bound' for more details.
3320 * in: edge2_is_serif
3322 * edge_point (in twilight zone)
3323 * edge2_point (in twilight zone)
3324 * ... stuff for bci_align_segments (edge) ...
3325 * ... stuff for bci_align_segments (edge2)...
3332 * uses: bci_stem_common
3333 * bci_align_segments
3336 unsigned char FPGM(bci_stem
) [] =
3348 SWAP
, /* s: cur_len edge2 */
3351 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3355 WS
, /* s: cur_len edge2 */
3357 SHPIX
, /* edge2 = edge + cur_len */
3362 SZP1
, /* set zp1 to normal zone 1 */
3368 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3380 * bci_action_stem_serif
3381 * bci_action_stem_round
3382 * bci_action_stem_round_serif
3384 * Higher-level routines for calling `bci_stem'.
3387 unsigned char FPGM(bci_action_stem
) [] =
3404 unsigned char FPGM(bci_action_stem_serif
) [] =
3408 bci_action_stem_serif
,
3421 unsigned char FPGM(bci_action_stem_round
) [] =
3425 bci_action_stem_round
,
3438 unsigned char FPGM(bci_action_stem_round_serif
) [] =
3442 bci_action_stem_round_serif
,
3459 * Handle the LINK action to link an edge to another one.
3463 * base_point (in twilight zone)
3464 * stem_point (in twilight zone)
3465 * ... stuff for bci_align_segments (base) ...
3467 * uses: func[cvtl_stem_width_function]
3468 * bci_align_segments
3471 unsigned char FPGM(bci_link
) [] =
3480 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3488 DUP
, /* s: stem is_round is_serif stem base base */
3489 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3491 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
3494 cvtl_stem_width_function
,
3496 CALL
, /* s: stem new_dist */
3500 ALIGNRP
, /* align `stem_point' with `base_point' */
3502 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
3504 SHPIX
, /* stem_point = base_point + new_dist */
3509 SZP1
, /* set zp1 to normal zone 1 */
3519 * bci_action_link_serif
3520 * bci_action_link_round
3521 * bci_action_link_round_serif
3523 * Higher-level routines for calling `bci_link'.
3526 unsigned char FPGM(bci_action_link
) [] =
3543 unsigned char FPGM(bci_action_link_serif
) [] =
3547 bci_action_link_serif
,
3560 unsigned char FPGM(bci_action_link_round
) [] =
3564 bci_action_link_round
,
3577 unsigned char FPGM(bci_action_link_round_serif
) [] =
3581 bci_action_link_round_serif
,
3598 * Handle the ANCHOR action to align two edges
3599 * and to set the edge anchor.
3601 * The code after computing `cur_len' to shift `edge' and `edge2'
3602 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3605 * if cur_len < = 64:
3612 * org_center = edge_orig + org_len / 2
3613 * cur_pos1 = ROUND(org_center)
3615 * error1 = ABS(org_center - (cur_pos1 - u_off))
3616 * error2 = ABS(org_center - (cur_pos1 + d_off))
3617 * if (error1 < error2):
3618 * cur_pos1 = cur_pos1 - u_off
3620 * cur_pos1 = cur_pos1 + d_off
3622 * edge = cur_pos1 - cur_len / 2
3623 * edge2 = edge + cur_len
3626 * edge = ROUND(edge_orig)
3628 * in: edge2_is_serif
3630 * edge_point (in twilight zone)
3631 * edge2_point (in twilight zone)
3632 * ... stuff for bci_align_segments (edge) ...
3639 * uses: func[cvtl_stem_width_function]
3641 * bci_align_segments
3645 #define sal_u_off sal_temp1
3647 #define sal_d_off sal_temp2
3649 #define sal_org_len sal_temp3
3651 unsigned char FPGM(bci_anchor
) [] =
3658 /* store anchor point number in `sal_anchor' */
3663 WS
, /* sal_anchor = edge_point */
3667 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3675 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
3676 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3678 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
3686 cvtl_stem_width_function
,
3688 CALL
, /* s: edge2 edge cur_len */
3693 LT
, /* cur_len < 96 */
3698 LTEQ
, /* cur_len <= 64 */
3716 SWAP
, /* s: edge2 cur_len edge */
3717 DUP
, /* s: edge2 cur_len edge edge */
3726 ADD
, /* s: edge2 cur_len edge org_center */
3731 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
3736 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3743 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3750 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3752 LT
, /* error1 < error2 */
3757 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3763 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3764 EIF
, /* s: edge2 cur_len edge cur_pos1 */
3772 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3776 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3779 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3781 SWAP
, /* s: cur_len edge2 */
3783 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3785 SHPIX
, /* edge2 = edge1 + cur_len */
3788 POP
, /* s: edge2 edge */
3796 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3799 SHPIX
, /* edge = round(edge_orig) */
3801 /* clean up stack */
3808 SZP1
, /* set zp1 to normal zone 1 */
3818 * bci_action_anchor_serif
3819 * bci_action_anchor_round
3820 * bci_action_anchor_round_serif
3822 * Higher-level routines for calling `bci_anchor'.
3825 unsigned char FPGM(bci_action_anchor
) [] =
3842 unsigned char FPGM(bci_action_anchor_serif
) [] =
3846 bci_action_anchor_serif
,
3859 unsigned char FPGM(bci_action_anchor_round
) [] =
3863 bci_action_anchor_round
,
3876 unsigned char FPGM(bci_action_anchor_round_serif
) [] =
3880 bci_action_anchor_round_serif
,
3895 * bci_action_blue_anchor
3897 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3898 * and to set the edge anchor.
3900 * in: anchor_point (in twilight zone)
3902 * edge_point (in twilight zone)
3903 * ... stuff for bci_align_segments (edge) ...
3907 * uses: bci_action_blue
3910 unsigned char FPGM(bci_action_blue_anchor
) [] =
3914 bci_action_blue_anchor
,
3917 /* store anchor point number in `sal_anchor' */
3935 * Handle the BLUE action to align an edge with a blue zone.
3938 * edge_point (in twilight zone)
3939 * ... stuff for bci_align_segments (edge) ...
3941 * uses: bci_align_segments
3944 unsigned char FPGM(bci_action_blue
) [] =
3953 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3955 /* move `edge_point' to `blue_cvt_idx' position; */
3956 /* note that we can't use MIAP since this would modify */
3957 /* the twilight point's original coordinates also */
3961 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3963 GC_cur
, /* s: new_pos edge edge_pos */
3966 SUB
, /* s: edge (new_pos - edge_pos) */
3972 SZP1
, /* set zp1 to normal zone 1 */
3983 * Common code for bci_action_serif routines.
3986 unsigned char FPGM(bci_serif_common
) [] =
3995 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4002 MINDEX
, /* s: [...] serif serif serif serif base */
4004 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
4007 ALIGNRP
, /* align `serif_point' with `base_point' */
4008 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
4018 * Move an edge if necessary to stay within a lower bound.
4023 * uses: bci_align_segments
4026 unsigned char FPGM(bci_lower_bound
) [] =
4033 SWAP
, /* s: edge bound */
4035 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4040 GC_cur
, /* s: edge bound_pos edge_pos */
4041 GT
, /* edge_pos < bound_pos */
4044 ALIGNRP
, /* align `edge' to `bound' */
4047 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4052 SZP1
, /* set zp1 to normal zone 1 */
4063 * Move an edge if necessary to stay within an upper bound.
4068 * uses: bci_align_segments
4071 unsigned char FPGM(bci_upper_bound
) [] =
4078 SWAP
, /* s: edge bound */
4080 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4085 GC_cur
, /* s: edge bound_pos edge_pos */
4086 LT
, /* edge_pos > bound_pos */
4089 ALIGNRP
, /* align `edge' to `bound' */
4092 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4097 SZP1
, /* set zp1 to normal zone 1 */
4106 * bci_upper_lower_bound
4108 * Move an edge if necessary to stay within a lower and lower bound.
4114 * uses: bci_align_segments
4117 unsigned char FPGM(bci_upper_lower_bound
) [] =
4121 bci_upper_lower_bound
,
4124 SWAP
, /* s: upper serif lower */
4126 MDAP_noround
, /* set rp0 and rp1 to `lower' */
4131 GC_cur
, /* s: upper serif lower_pos serif_pos */
4132 GT
, /* serif_pos < lower_pos */
4135 ALIGNRP
, /* align `serif' to `lower' */
4138 SWAP
, /* s: serif upper */
4140 MDAP_noround
, /* set rp0 and rp1 to `upper' */
4145 GC_cur
, /* s: serif upper_pos serif_pos */
4146 LT
, /* serif_pos > upper_pos */
4149 ALIGNRP
, /* align `serif' to `upper' */
4152 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4157 SZP1
, /* set zp1 to normal zone 1 */
4168 * Handle the SERIF action to align a serif with its base.
4170 * in: serif_point (in twilight zone)
4171 * base_point (in twilight zone)
4172 * ... stuff for bci_align_segments (serif) ...
4174 * uses: bci_serif_common
4175 * bci_align_segments
4178 unsigned char FPGM(bci_action_serif
) [] =
4189 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4194 SZP1
, /* set zp1 to normal zone 1 */
4203 * bci_action_serif_lower_bound
4205 * Handle the SERIF action to align a serif with its base, then moving it
4206 * again if necessary to stay within a lower bound.
4208 * in: serif_point (in twilight zone)
4209 * base_point (in twilight zone)
4210 * edge[-1] (in twilight zone)
4211 * ... stuff for bci_align_segments (serif) ...
4213 * uses: bci_serif_common
4217 unsigned char FPGM(bci_action_serif_lower_bound
) [] =
4221 bci_action_serif_lower_bound
,
4238 * bci_action_serif_upper_bound
4240 * Handle the SERIF action to align a serif with its base, then moving it
4241 * again if necessary to stay within an upper bound.
4243 * in: serif_point (in twilight zone)
4244 * base_point (in twilight zone)
4245 * edge[1] (in twilight zone)
4246 * ... stuff for bci_align_segments (serif) ...
4248 * uses: bci_serif_common
4252 unsigned char FPGM(bci_action_serif_upper_bound
) [] =
4256 bci_action_serif_upper_bound
,
4273 * bci_action_serif_upper_lower_bound
4275 * Handle the SERIF action to align a serif with its base, then moving it
4276 * again if necessary to stay within a lower and upper bound.
4278 * in: serif_point (in twilight zone)
4279 * base_point (in twilight zone)
4280 * edge[-1] (in twilight zone)
4281 * edge[1] (in twilight zone)
4282 * ... stuff for bci_align_segments (serif) ...
4284 * uses: bci_serif_common
4285 * bci_upper_lower_bound
4288 unsigned char FPGM(bci_action_serif_upper_lower_bound
) [] =
4292 bci_action_serif_upper_lower_bound
,
4297 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4304 bci_upper_lower_bound
,
4313 * bci_serif_anchor_common
4315 * Common code for bci_action_serif_anchor routines.
4322 unsigned char FPGM(bci_serif_anchor_common
) [] =
4326 bci_serif_anchor_common
,
4331 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4337 WS
, /* sal_anchor = edge_point */
4347 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4350 SHPIX
, /* edge = round(edge_orig) */
4358 * bci_action_serif_anchor
4360 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4363 * in: edge_point (in twilight zone)
4364 * ... stuff for bci_align_segments (edge) ...
4366 * uses: bci_serif_anchor_common
4367 * bci_align_segments
4370 unsigned char FPGM(bci_action_serif_anchor
) [] =
4374 bci_action_serif_anchor
,
4378 bci_serif_anchor_common
,
4381 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4386 SZP1
, /* set zp1 to normal zone 1 */
4395 * bci_action_serif_anchor_lower_bound
4397 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4398 * anchor, then moving it again if necessary to stay within a lower
4401 * in: edge_point (in twilight zone)
4402 * edge[-1] (in twilight zone)
4403 * ... stuff for bci_align_segments (edge) ...
4405 * uses: bci_serif_anchor_common
4409 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
4413 bci_action_serif_anchor_lower_bound
,
4417 bci_serif_anchor_common
,
4430 * bci_action_serif_anchor_upper_bound
4432 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4433 * anchor, then moving it again if necessary to stay within an upper
4436 * in: edge_point (in twilight zone)
4437 * edge[1] (in twilight zone)
4438 * ... stuff for bci_align_segments (edge) ...
4440 * uses: bci_serif_anchor_common
4444 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
4448 bci_action_serif_anchor_upper_bound
,
4452 bci_serif_anchor_common
,
4465 * bci_action_serif_anchor_upper_lower_bound
4467 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4468 * anchor, then moving it again if necessary to stay within a lower and
4471 * in: edge_point (in twilight zone)
4472 * edge[-1] (in twilight zone)
4473 * edge[1] (in twilight zone)
4474 * ... stuff for bci_align_segments (edge) ...
4476 * uses: bci_serif_anchor_common
4477 * bci_upper_lower_bound
4480 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound
) [] =
4484 bci_action_serif_anchor_upper_lower_bound
,
4488 bci_serif_anchor_common
,
4492 bci_upper_lower_bound
,
4501 * bci_serif_link1_common
4503 * Common code for bci_action_serif_link1 routines.
4508 unsigned char FPGM(bci_serif_link1_common
) [] =
4512 bci_serif_link1_common
,
4517 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4521 CINDEX
, /* s: [...] after edge before after */
4524 CINDEX
, /* s: [...] after edge before after before */
4528 EQ
, /* after_orig_pos == before_orig_pos */
4529 IF
, /* s: [...] after edge before */
4530 MDAP_noround
, /* set rp0 and rp1 to `before' */
4532 ALIGNRP
, /* align `edge' with `before' */
4537 /* we have to execute `a*b/c', with b/c very near to 1: */
4538 /* to avoid overflow while retaining precision, */
4539 /* we transform this to `a + a * (b-c)/c' */
4543 CINDEX
, /* s: [...] after edge before edge */
4546 CINDEX
, /* s: [...] after edge before edge before */
4547 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
4552 CINDEX
, /* s: [...] after edge before a a after */
4555 CINDEX
, /* s: [...] after edge before a a after before */
4556 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
4560 CINDEX
, /* s: [...] after edge before a a c after */
4563 CINDEX
, /* s: [...] after edge before a a c after before */
4564 MD_cur
, /* b = after_pos - before_pos */
4568 CINDEX
, /* s: [...] after edge before a a c b c */
4574 MUL
, /* (b-c) in 16.16 format */
4579 DIV
, /* s: [...] after edge before a a (b-c)/c */
4581 POP
, /* avoid division by zero */
4584 MUL
, /* a * (b-c)/c * 2^10 */
4588 DIV
, /* a * (b-c)/c */
4592 MDAP_noround
, /* set rp0 and rp1 to `before' */
4593 SWAP
, /* s: [...] after a*b/c edge */
4596 ALIGNRP
, /* align `edge' with `before' */
4598 SHPIX
, /* shift `edge' by `a*b/c' */
4600 SWAP
, /* s: [...] edge after */
4610 * bci_action_serif_link1
4612 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4615 * in: before_point (in twilight zone)
4616 * edge_point (in twilight zone)
4617 * after_point (in twilight zone)
4618 * ... stuff for bci_align_segments (edge) ...
4620 * uses: bci_serif_link1_common
4621 * bci_align_segments
4624 unsigned char FPGM(bci_action_serif_link1
) [] =
4628 bci_action_serif_link1
,
4632 bci_serif_link1_common
,
4635 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4640 SZP1
, /* set zp1 to normal zone 1 */
4649 * bci_action_serif_link1_lower_bound
4651 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4652 * before and after. Additionally, move the serif again if necessary to
4653 * stay within a lower bound.
4655 * in: before_point (in twilight zone)
4656 * edge_point (in twilight zone)
4657 * after_point (in twilight zone)
4658 * edge[-1] (in twilight zone)
4659 * ... stuff for bci_align_segments (edge) ...
4661 * uses: bci_serif_link1_common
4665 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
4669 bci_action_serif_link1_lower_bound
,
4673 bci_serif_link1_common
,
4686 * bci_action_serif_link1_upper_bound
4688 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4689 * before and after. Additionally, move the serif again if necessary to
4690 * stay within an upper bound.
4692 * in: before_point (in twilight zone)
4693 * edge_point (in twilight zone)
4694 * after_point (in twilight zone)
4695 * edge[1] (in twilight zone)
4696 * ... stuff for bci_align_segments (edge) ...
4698 * uses: bci_serif_link1_common
4702 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
4706 bci_action_serif_link1_upper_bound
,
4710 bci_serif_link1_common
,
4723 * bci_action_serif_link1_upper_lower_bound
4725 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4726 * before and after. Additionally, move the serif again if necessary to
4727 * stay within a lower and upper bound.
4729 * in: before_point (in twilight zone)
4730 * edge_point (in twilight zone)
4731 * after_point (in twilight zone)
4732 * edge[-1] (in twilight zone)
4733 * edge[1] (in twilight zone)
4734 * ... stuff for bci_align_segments (edge) ...
4736 * uses: bci_serif_link1_common
4737 * bci_upper_lower_bound
4740 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound
) [] =
4744 bci_action_serif_link1_upper_lower_bound
,
4748 bci_serif_link1_common
,
4752 bci_upper_lower_bound
,
4761 * bci_serif_link2_common
4763 * Common code for bci_action_serif_link2 routines.
4768 unsigned char FPGM(bci_serif_link2_common
) [] =
4772 bci_serif_link2_common
,
4777 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4779 DUP
, /* s: [...] edge edge */
4783 DUP
, /* s: [...] edge edge anchor anchor */
4784 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
4795 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4800 ALIGNRP
, /* align `edge' with `sal_anchor' */
4802 SHPIX
, /* shift `edge' by `delta' */
4810 * bci_action_serif_link2
4812 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4814 * in: edge_point (in twilight zone)
4815 * ... stuff for bci_align_segments (edge) ...
4817 * uses: bci_serif_link2_common
4818 * bci_align_segments
4821 unsigned char FPGM(bci_action_serif_link2
) [] =
4825 bci_action_serif_link2
,
4829 bci_serif_link2_common
,
4832 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4837 SZP1
, /* set zp1 to normal zone 1 */
4846 * bci_action_serif_link2_lower_bound
4848 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4849 * Additionally, move the serif again if necessary to stay within a lower
4852 * in: edge_point (in twilight zone)
4853 * edge[-1] (in twilight zone)
4854 * ... stuff for bci_align_segments (edge) ...
4856 * uses: bci_serif_link2_common
4860 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
4864 bci_action_serif_link2_lower_bound
,
4868 bci_serif_link2_common
,
4881 * bci_action_serif_link2_upper_bound
4883 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4884 * Additionally, move the serif again if necessary to stay within an upper
4887 * in: edge_point (in twilight zone)
4888 * edge[1] (in twilight zone)
4889 * ... stuff for bci_align_segments (edge) ...
4891 * uses: bci_serif_link2_common
4895 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
4899 bci_action_serif_link2_upper_bound
,
4903 bci_serif_link2_common
,
4916 * bci_action_serif_link2_upper_lower_bound
4918 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4919 * Additionally, move the serif again if necessary to stay within a lower
4922 * in: edge_point (in twilight zone)
4923 * edge[-1] (in twilight zone)
4924 * edge[1] (in twilight zone)
4925 * ... stuff for bci_align_segments (edge) ...
4927 * uses: bci_serif_link2_common
4928 * bci_upper_lower_bound
4931 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound
) [] =
4935 bci_action_serif_link2_upper_lower_bound
,
4939 bci_serif_link2_common
,
4943 bci_upper_lower_bound
,
4954 * This is the top-level glyph hinting function which parses the arguments
4955 * on the stack and calls subroutines.
4957 * in: action_0_func_idx
4963 * CVT: cvtl_is_subglyph
4965 * uses: bci_action_ip_before
4966 * bci_action_ip_after
4968 * bci_action_ip_between
4970 * bci_action_adjust_bound
4971 * bci_action_adjust_bound_serif
4972 * bci_action_adjust_bound_round
4973 * bci_action_adjust_bound_round_serif
4975 * bci_action_stem_bound
4976 * bci_action_stem_bound_serif
4977 * bci_action_stem_bound_round
4978 * bci_action_stem_bound_round_serif
4981 * bci_action_link_serif
4982 * bci_action_link_round
4983 * bci_action_link_round_serif
4986 * bci_action_anchor_serif
4987 * bci_action_anchor_round
4988 * bci_action_anchor_round_serif
4990 * bci_action_blue_anchor
4993 * bci_action_adjust_serif
4994 * bci_action_adjust_round
4995 * bci_action_adjust_round_serif
4998 * bci_action_stem_serif
4999 * bci_action_stem_round
5000 * bci_action_stem_round_serif
5005 * bci_action_serif_lower_bound
5006 * bci_action_serif_upper_bound
5007 * bci_action_serif_upper_lower_bound
5009 * bci_action_serif_anchor
5010 * bci_action_serif_anchor_lower_bound
5011 * bci_action_serif_anchor_upper_bound
5012 * bci_action_serif_anchor_upper_lower_bound
5014 * bci_action_serif_link1
5015 * bci_action_serif_link1_lower_bound
5016 * bci_action_serif_link1_upper_bound
5017 * bci_action_serif_link1_upper_lower_bound
5019 * bci_action_serif_link2
5020 * bci_action_serif_link2_lower_bound
5021 * bci_action_serif_link2_upper_bound
5022 * bci_action_serif_link2_upper_lower_bound
5025 unsigned char FPGM(bci_hint_glyph
) [] =
5033 /* loop until all data on stack is used */
5042 JROT
, /* goto start_loop */
5046 SZP2
, /* set zp2 to normal zone 1 */
5054 #define COPY_FPGM(func_name) \
5055 memcpy(buf_p, fpgm_ ## func_name, \
5056 sizeof (fpgm_ ## func_name)); \
5057 buf_p += sizeof (fpgm_ ## func_name) \
5060 TA_table_build_fpgm(FT_Byte
** fpgm
,
5070 /* for compatibility with dumb bytecode interpreters or analyzers, */
5071 /* FDEFs are stored in ascending index order, without holes -- */
5072 /* note that some FDEFs are not always needed */
5073 /* (depending on options of `TTFautohint'), */
5074 /* but implementing dynamic FDEF indices would be a lot of work */
5076 buf_len
= sizeof (FPGM(bci_round
))
5077 + sizeof (FPGM(bci_smooth_stem_width_a
))
5079 + sizeof (FPGM(bci_smooth_stem_width_b
))
5081 + sizeof (FPGM(bci_smooth_stem_width_c
))
5082 + sizeof (FPGM(bci_get_best_width
))
5083 + sizeof (FPGM(bci_strong_stem_width_a
))
5085 + sizeof (FPGM(bci_strong_stem_width_b
))
5086 + sizeof (FPGM(bci_loop_do
))
5087 + sizeof (FPGM(bci_loop
))
5088 + sizeof (FPGM(bci_cvt_rescale
))
5089 + sizeof (FPGM(bci_blue_round_a
))
5091 + sizeof (FPGM(bci_blue_round_b
))
5092 + sizeof (FPGM(bci_decrement_component_counter
))
5093 + sizeof (FPGM(bci_get_point_extrema
))
5094 + sizeof (FPGM(bci_nibbles
))
5095 + sizeof (FPGM(bci_number_set_is_element
))
5096 + sizeof (FPGM(bci_number_set_is_element2
))
5098 + sizeof (FPGM(bci_create_segment
))
5099 + sizeof (FPGM(bci_create_segments
))
5101 + sizeof (FPGM(bci_create_segments_0
))
5102 + sizeof (FPGM(bci_create_segments_1
))
5103 + sizeof (FPGM(bci_create_segments_2
))
5104 + sizeof (FPGM(bci_create_segments_3
))
5105 + sizeof (FPGM(bci_create_segments_4
))
5106 + sizeof (FPGM(bci_create_segments_5
))
5107 + sizeof (FPGM(bci_create_segments_6
))
5108 + sizeof (FPGM(bci_create_segments_7
))
5109 + sizeof (FPGM(bci_create_segments_8
))
5110 + sizeof (FPGM(bci_create_segments_9
))
5112 + sizeof (FPGM(bci_create_segments_composite
))
5114 + sizeof (FPGM(bci_create_segments_composite_0
))
5115 + sizeof (FPGM(bci_create_segments_composite_1
))
5116 + sizeof (FPGM(bci_create_segments_composite_2
))
5117 + sizeof (FPGM(bci_create_segments_composite_3
))
5118 + sizeof (FPGM(bci_create_segments_composite_4
))
5119 + sizeof (FPGM(bci_create_segments_composite_5
))
5120 + sizeof (FPGM(bci_create_segments_composite_6
))
5121 + sizeof (FPGM(bci_create_segments_composite_7
))
5122 + sizeof (FPGM(bci_create_segments_composite_8
))
5123 + sizeof (FPGM(bci_create_segments_composite_9
))
5125 + sizeof (FPGM(bci_align_point
))
5126 + sizeof (FPGM(bci_align_segment
))
5127 + sizeof (FPGM(bci_align_segments
))
5129 + sizeof (FPGM(bci_scale_contour
))
5130 + sizeof (FPGM(bci_scale_glyph
))
5131 + sizeof (FPGM(bci_scale_composite_glyph
))
5132 + sizeof (FPGM(bci_shift_contour
))
5133 + sizeof (FPGM(bci_shift_subglyph
))
5135 + sizeof (FPGM(bci_ip_outer_align_point
))
5136 + sizeof (FPGM(bci_ip_on_align_points
))
5137 + sizeof (FPGM(bci_ip_between_align_point
))
5138 + sizeof (FPGM(bci_ip_between_align_points
))
5140 + sizeof (FPGM(bci_adjust_common
))
5141 + sizeof (FPGM(bci_stem_common
))
5142 + sizeof (FPGM(bci_serif_common
))
5143 + sizeof (FPGM(bci_serif_anchor_common
))
5144 + sizeof (FPGM(bci_serif_link1_common
))
5145 + sizeof (FPGM(bci_serif_link2_common
))
5147 + sizeof (FPGM(bci_lower_bound
))
5148 + sizeof (FPGM(bci_upper_bound
))
5149 + sizeof (FPGM(bci_upper_lower_bound
))
5151 + sizeof (FPGM(bci_adjust_bound
))
5152 + sizeof (FPGM(bci_stem_bound
))
5153 + sizeof (FPGM(bci_link
))
5154 + sizeof (FPGM(bci_anchor
))
5155 + sizeof (FPGM(bci_adjust
))
5156 + sizeof (FPGM(bci_stem
))
5158 + sizeof (FPGM(bci_action_ip_before
))
5159 + sizeof (FPGM(bci_action_ip_after
))
5160 + sizeof (FPGM(bci_action_ip_on
))
5161 + sizeof (FPGM(bci_action_ip_between
))
5163 + sizeof (FPGM(bci_action_blue
))
5164 + sizeof (FPGM(bci_action_blue_anchor
))
5166 + sizeof (FPGM(bci_action_anchor
))
5167 + sizeof (FPGM(bci_action_anchor_serif
))
5168 + sizeof (FPGM(bci_action_anchor_round
))
5169 + sizeof (FPGM(bci_action_anchor_round_serif
))
5171 + sizeof (FPGM(bci_action_adjust
))
5172 + sizeof (FPGM(bci_action_adjust_serif
))
5173 + sizeof (FPGM(bci_action_adjust_round
))
5174 + sizeof (FPGM(bci_action_adjust_round_serif
))
5175 + sizeof (FPGM(bci_action_adjust_bound
))
5176 + sizeof (FPGM(bci_action_adjust_bound_serif
))
5177 + sizeof (FPGM(bci_action_adjust_bound_round
))
5178 + sizeof (FPGM(bci_action_adjust_bound_round_serif
))
5180 + sizeof (FPGM(bci_action_link
))
5181 + sizeof (FPGM(bci_action_link_serif
))
5182 + sizeof (FPGM(bci_action_link_round
))
5183 + sizeof (FPGM(bci_action_link_round_serif
))
5185 + sizeof (FPGM(bci_action_stem
))
5186 + sizeof (FPGM(bci_action_stem_serif
))
5187 + sizeof (FPGM(bci_action_stem_round
))
5188 + sizeof (FPGM(bci_action_stem_round_serif
))
5189 + sizeof (FPGM(bci_action_stem_bound
))
5190 + sizeof (FPGM(bci_action_stem_bound_serif
))
5191 + sizeof (FPGM(bci_action_stem_bound_round
))
5192 + sizeof (FPGM(bci_action_stem_bound_round_serif
))
5194 + sizeof (FPGM(bci_action_serif
))
5195 + sizeof (FPGM(bci_action_serif_lower_bound
))
5196 + sizeof (FPGM(bci_action_serif_upper_bound
))
5197 + sizeof (FPGM(bci_action_serif_upper_lower_bound
))
5199 + sizeof (FPGM(bci_action_serif_anchor
))
5200 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
5201 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
5202 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound
))
5204 + sizeof (FPGM(bci_action_serif_link1
))
5205 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
5206 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
5207 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound
))
5209 + sizeof (FPGM(bci_action_serif_link2
))
5210 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
5211 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
5212 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound
))
5214 + sizeof (FPGM(bci_hint_glyph
));
5216 /* buffer length must be a multiple of four */
5217 len
= (buf_len
+ 3) & ~3;
5218 buf
= (FT_Byte
*)malloc(len
);
5220 return FT_Err_Out_Of_Memory
;
5222 /* pad end of buffer with zeros */
5223 buf
[len
- 1] = 0x00;
5224 buf
[len
- 2] = 0x00;
5225 buf
[len
- 3] = 0x00;
5227 /* copy font program into buffer and fill in the missing variables */
5230 COPY_FPGM(bci_round
);
5231 COPY_FPGM(bci_smooth_stem_width_a
);
5232 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5233 COPY_FPGM(bci_smooth_stem_width_b
);
5234 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5235 COPY_FPGM(bci_smooth_stem_width_c
);
5236 COPY_FPGM(bci_get_best_width
);
5237 COPY_FPGM(bci_strong_stem_width_a
);
5238 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5239 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font
);
5240 COPY_FPGM(bci_strong_stem_width_b
);
5241 COPY_FPGM(bci_loop_do
);
5242 COPY_FPGM(bci_loop
);
5243 COPY_FPGM(bci_cvt_rescale
);
5244 COPY_FPGM(bci_blue_round_a
);
5245 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
5246 COPY_FPGM(bci_blue_round_b
);
5247 COPY_FPGM(bci_decrement_component_counter
);
5248 COPY_FPGM(bci_get_point_extrema
);
5249 COPY_FPGM(bci_nibbles
);
5250 COPY_FPGM(bci_number_set_is_element
);
5251 COPY_FPGM(bci_number_set_is_element2
);
5253 COPY_FPGM(bci_create_segment
);
5254 COPY_FPGM(bci_create_segments
);
5256 COPY_FPGM(bci_create_segments_0
);
5257 COPY_FPGM(bci_create_segments_1
);
5258 COPY_FPGM(bci_create_segments_2
);
5259 COPY_FPGM(bci_create_segments_3
);
5260 COPY_FPGM(bci_create_segments_4
);
5261 COPY_FPGM(bci_create_segments_5
);
5262 COPY_FPGM(bci_create_segments_6
);
5263 COPY_FPGM(bci_create_segments_7
);
5264 COPY_FPGM(bci_create_segments_8
);
5265 COPY_FPGM(bci_create_segments_9
);
5267 COPY_FPGM(bci_create_segments_composite
);
5269 COPY_FPGM(bci_create_segments_composite_0
);
5270 COPY_FPGM(bci_create_segments_composite_1
);
5271 COPY_FPGM(bci_create_segments_composite_2
);
5272 COPY_FPGM(bci_create_segments_composite_3
);
5273 COPY_FPGM(bci_create_segments_composite_4
);
5274 COPY_FPGM(bci_create_segments_composite_5
);
5275 COPY_FPGM(bci_create_segments_composite_6
);
5276 COPY_FPGM(bci_create_segments_composite_7
);
5277 COPY_FPGM(bci_create_segments_composite_8
);
5278 COPY_FPGM(bci_create_segments_composite_9
);
5280 COPY_FPGM(bci_align_point
);
5281 COPY_FPGM(bci_align_segment
);
5282 COPY_FPGM(bci_align_segments
);
5284 COPY_FPGM(bci_scale_contour
);
5285 COPY_FPGM(bci_scale_glyph
);
5286 COPY_FPGM(bci_scale_composite_glyph
);
5287 COPY_FPGM(bci_shift_contour
);
5288 COPY_FPGM(bci_shift_subglyph
);
5290 COPY_FPGM(bci_ip_outer_align_point
);
5291 COPY_FPGM(bci_ip_on_align_points
);
5292 COPY_FPGM(bci_ip_between_align_point
);
5293 COPY_FPGM(bci_ip_between_align_points
);
5295 COPY_FPGM(bci_adjust_common
);
5296 COPY_FPGM(bci_stem_common
);
5297 COPY_FPGM(bci_serif_common
);
5298 COPY_FPGM(bci_serif_anchor_common
);
5299 COPY_FPGM(bci_serif_link1_common
);
5300 COPY_FPGM(bci_serif_link2_common
);
5302 COPY_FPGM(bci_lower_bound
);
5303 COPY_FPGM(bci_upper_bound
);
5304 COPY_FPGM(bci_upper_lower_bound
);
5306 COPY_FPGM(bci_adjust_bound
);
5307 COPY_FPGM(bci_stem_bound
);
5308 COPY_FPGM(bci_link
);
5309 COPY_FPGM(bci_anchor
);
5310 COPY_FPGM(bci_adjust
);
5311 COPY_FPGM(bci_stem
);
5313 COPY_FPGM(bci_action_ip_before
);
5314 COPY_FPGM(bci_action_ip_after
);
5315 COPY_FPGM(bci_action_ip_on
);
5316 COPY_FPGM(bci_action_ip_between
);
5318 COPY_FPGM(bci_action_blue
);
5319 COPY_FPGM(bci_action_blue_anchor
);
5321 COPY_FPGM(bci_action_anchor
);
5322 COPY_FPGM(bci_action_anchor_serif
);
5323 COPY_FPGM(bci_action_anchor_round
);
5324 COPY_FPGM(bci_action_anchor_round_serif
);
5326 COPY_FPGM(bci_action_adjust
);
5327 COPY_FPGM(bci_action_adjust_serif
);
5328 COPY_FPGM(bci_action_adjust_round
);
5329 COPY_FPGM(bci_action_adjust_round_serif
);
5330 COPY_FPGM(bci_action_adjust_bound
);
5331 COPY_FPGM(bci_action_adjust_bound_serif
);
5332 COPY_FPGM(bci_action_adjust_bound_round
);
5333 COPY_FPGM(bci_action_adjust_bound_round_serif
);
5335 COPY_FPGM(bci_action_link
);
5336 COPY_FPGM(bci_action_link_serif
);
5337 COPY_FPGM(bci_action_link_round
);
5338 COPY_FPGM(bci_action_link_round_serif
);
5340 COPY_FPGM(bci_action_stem
);
5341 COPY_FPGM(bci_action_stem_serif
);
5342 COPY_FPGM(bci_action_stem_round
);
5343 COPY_FPGM(bci_action_stem_round_serif
);
5344 COPY_FPGM(bci_action_stem_bound
);
5345 COPY_FPGM(bci_action_stem_bound_serif
);
5346 COPY_FPGM(bci_action_stem_bound_round
);
5347 COPY_FPGM(bci_action_stem_bound_round_serif
);
5349 COPY_FPGM(bci_action_serif
);
5350 COPY_FPGM(bci_action_serif_lower_bound
);
5351 COPY_FPGM(bci_action_serif_upper_bound
);
5352 COPY_FPGM(bci_action_serif_upper_lower_bound
);
5354 COPY_FPGM(bci_action_serif_anchor
);
5355 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
5356 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
5357 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound
);
5359 COPY_FPGM(bci_action_serif_link1
);
5360 COPY_FPGM(bci_action_serif_link1_lower_bound
);
5361 COPY_FPGM(bci_action_serif_link1_upper_bound
);
5362 COPY_FPGM(bci_action_serif_link1_upper_lower_bound
);
5364 COPY_FPGM(bci_action_serif_link2
);
5365 COPY_FPGM(bci_action_serif_link2_lower_bound
);
5366 COPY_FPGM(bci_action_serif_link2_upper_bound
);
5367 COPY_FPGM(bci_action_serif_link2_upper_lower_bound
);
5369 COPY_FPGM(bci_hint_glyph
);
5372 *fpgm_len
= buf_len
;
5379 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
5382 FT_Error error
= FT_Err_Ok
;
5384 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5385 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5391 error
= TA_sfnt_add_table_info(sfnt
);
5395 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5396 if (glyf_table
->processed
)
5398 sfnt
->table_infos
[sfnt
->num_table_infos
- 1] = data
->fpgm_idx
;
5402 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
5406 if (fpgm_len
> sfnt
->max_instructions
)
5407 sfnt
->max_instructions
= fpgm_len
;
5409 /* in case of success, `fpgm_buf' gets linked */
5410 /* and is eventually freed in `TA_font_unload' */
5411 error
= TA_font_add_table(font
,
5412 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
5413 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
5417 data
->fpgm_idx
= sfnt
->table_infos
[sfnt
->num_table_infos
- 1];
5423 /* end of tafpgm.c */