4 * Copyright (C) 2011-2012 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.
80 unsigned char FPGM(bci_round
) [] =
98 * bci_smooth_stem_width
100 * This is the equivalent to the following code from function
101 * `ta_latin_compute_stem_width':
109 * else if base_is_round:
115 * delta = ABS(dist - std_width)
126 * delta = delta - dist
129 * dist = dist + delta
130 * else if delta < 32:
132 * else if delta < 54:
135 * dist = dist + delta
151 * CVT: cvtl_is_extra_light
157 unsigned char FPGM(bci_smooth_stem_width_a
) [] =
161 bci_smooth_stem_width
,
165 ABS
, /* s: base_is_round stem_is_serif width dist */
170 LT
, /* dist < 3*64 */
174 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
175 AND
, /* stem_is_serif && dist < 3*64 */
180 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
182 IF
, /* s: base_is_round width dist */
188 ROLL
, /* s: width dist base_is_round */
189 IF
, /* s: width dist */
194 IF
, /* s: width dist */
205 IF
, /* s: width dist */
212 DUP
, /* s: width dist dist */
217 /* %c, index of std_width */
219 unsigned char FPGM(bci_smooth_stem_width_b
) [] =
224 ABS
, /* s: width dist delta */
229 IF
, /* s: width dist */
235 /* %c, index of std_width */
237 unsigned char FPGM(bci_smooth_stem_width_c
) [] =
240 RCVT
, /* dist = std_width */
252 DUP
, /* s: width dist dist */
255 LT
, /* dist < 3*64 */
257 DUP
, /* s: width delta dist */
258 FLOOR
, /* dist = FLOOR(dist) */
259 DUP
, /* s: width delta dist dist */
261 ROLL
, /* s: width dist delta dist */
262 SUB
, /* delta = delta - dist */
264 DUP
, /* s: width dist delta delta */
268 IF
, /* s: width dist delta */
269 ADD
, /* dist = dist + delta */
280 ADD
, /* dist = dist + 10 */
291 ADD
, /* dist = dist + 54 */
294 ADD
, /* dist = dist + delta */
303 CALL
, /* dist = round(dist) */
308 SWAP
, /* s: dist width */
313 NEG
, /* dist = -dist */
325 * An auxiliary function for `bci_strong_stem_width'.
327 * in: n (initialized with CVT index for first vertical width)
339 unsigned char FPGM(bci_get_best_width
) [] =
347 RCVT
, /* s: dist n w */
351 CINDEX
, /* s: dist n w w dist */
353 ABS
, /* s: dist n w d */
357 RS
, /* s: dist n w d d best */
367 WS
, /* reference = w */
384 * bci_strong_stem_width
386 * This is the equivalent to the following code (function
387 * `ta_latin_snap_width' and some lines from
388 * `ta_latin_compute_stem_width'):
390 * best = 64 + 32 + 2;
394 * for n in 0 .. num_widths:
402 * if dist >= reference:
403 * if dist < ROUND(reference) + 48:
406 * if dist > ROUND(reference) - 48:
419 * stem_is_serif (unused)
420 * base_is_round (unused)
429 * uses: bci_get_best_width
433 unsigned char FPGM(bci_strong_stem_width_a
) [] =
437 bci_strong_stem_width
,
445 ABS
, /* s: width dist */
450 WS
, /* sal_best = 98 */
456 WS
, /* sal_ref = width */
461 /* %c, first index of vertical widths */
462 /* %c, number of vertical widths */
464 unsigned char FPGM(bci_strong_stem_width_b
) [] =
470 POP
, /* s: width dist */
474 RS
, /* s: width dist dist reference */
481 CALL
, /* s: width dist reference dist dist ROUND(reference) */
486 ROLL
, /* s: width dist reference dist ROUND(reference) 48 reference dist */
488 LTEQ
, /* dist >= reference */
489 IF
, /* s: width dist reference dist ROUND(reference) 48 */
491 LT
, /* dist < ROUND(reference) + 48 */
495 GT
, /* dist > ROUND(reference) - 48 */
499 SWAP
, /* s: width reference dist */
506 GTEQ
, /* dist >= 64 */
510 CALL
, /* dist = ROUND(dist) */
518 SWAP
, /* s: dist width */
523 NEG
, /* dist = -dist */
534 * Take a range and a function number and apply the function to all
535 * elements of the range.
541 * sal: sal_i (counter initialized with `start')
543 * sal_func (`func_num')
546 unsigned char FPGM(bci_loop
) [] =
556 WS
, /* sal_func = func_num */
560 WS
, /* sal_limit = end */
564 WS
, /* sal_i = start */
573 LTEQ
, /* start <= end */
584 ADD
, /* start = start + 1 */
590 JMPR
, /* goto start_loop */
601 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
603 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
604 * consequently, the calculation `a * b/c' is done as `a + delta' with
605 * `delta = a * (b-c)/c'. This avoids overflow.
615 unsigned char FPGM(bci_cvt_rescale
) [] =
640 * Round a blue ref value and adjust its corresponding shoot value.
649 unsigned char FPGM(bci_blue_round_a
) [] =
658 RCVT
, /* s: ref_idx ref_idx ref */
664 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
672 unsigned char FPGM(bci_blue_round_b
) [] =
677 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
679 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
681 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
683 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
685 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
710 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
715 NEG
, /* delta = -delta */
722 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
729 ADD
, /* s: (ref_idx + 1) */
737 * bci_decrement_component_counter
739 * An auxiliary function for composite glyphs.
741 * CVT: cvtl_is_subglyph
744 unsigned char FPGM(bci_decrement_component_counter
) [] =
748 bci_decrement_component_counter
,
751 /* decrement `cvtl_is_subglyph' counter */
767 * bci_get_point_extrema
769 * An auxiliary function for `bci_create_segment'.
778 unsigned char FPGM(bci_get_point_extrema
) [] =
782 bci_get_point_extrema
,
791 /* check whether `point' is a new minimum */
794 RS
, /* s: point point point point_min */
796 /* if distance is negative, we have a new minimum */
800 IF
, /* s: point point */
808 /* check whether `point' is a new maximum */
811 RS
, /* s: point point point_max */
813 /* if distance is positive, we have a new maximum */
833 * Pop a byte with two delta arguments in its nibbles and push the
834 * expanded arguments separately as two bytes.
836 * in: 16 * (end - start) + (start - base)
841 * sal: sal_base (set to `end' at return)
845 unsigned char FPGM(bci_nibbles
) [] =
855 DIV
, /* s: in hnibble */
860 MUL
, /* s: in hnibble (hnibble * 16) */
863 SUB
, /* s: hnibble lnibble */
868 ADD
, /* s: hnibble start */
871 ADD
, /* s: start end */
877 WS
, /* sal_base = end */
887 * bci_number_set_is_element
889 * Pop values from stack until it is empty. If one of them is equal to
890 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
897 * CVT: cvtl_is_element
900 unsigned char FPGM(bci_number_set_is_element
) [] =
904 bci_number_set_is_element
,
922 JROT
, /* goto start_loop if stack depth != 0 */
930 * bci_number_set_is_element2
932 * Pop value ranges from stack until it is empty. If one of them contains
933 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
936 * in: ppem_range_1_start
942 * CVT: cvtl_is_element
945 unsigned char FPGM(bci_number_set_is_element2
) [] =
949 bci_number_set_is_element2
,
973 JROT
, /* goto start_loop if stack depth != 0 */
983 * Store start and end point of a segment in the storage area,
984 * then construct a point in the twilight zone to represent it.
986 * This function is used by `bci_create_segment_points'.
990 * [last (if wrap-around segment)]
991 * [first (if wrap-around segment)]
993 * sal: sal_i (start of current segment)
994 * sal_j (current twilight point)
998 * sal_num_packed_segments
1004 * uses: bci_get_point_extrema
1007 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1008 * delta values in nibbles (without a wrap-around segment).
1011 unsigned char FPGM(bci_create_segment
) [] =
1020 sal_num_packed_segments
,
1025 sal_num_packed_segments
,
1026 sal_num_packed_segments
,
1031 WS
, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1044 WS
, /* sal[sal_i] = start */
1046 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
1052 ADD
, /* sal_i = sal_i + 1 */
1055 /* initialize inner loop(s) */
1060 WS
, /* sal_point_min = start */
1065 WS
, /* sal_point_max = start */
1069 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1075 CINDEX
, /* s: start end end start */
1076 LT
, /* start > end */
1078 /* we have a wrap-around segment with two more arguments */
1079 /* to give the last and first point of the contour, respectively; */
1080 /* our job is to store a segment `start'-`last', */
1081 /* and to get extrema for the two segments */
1082 /* `start'-`last' and `first'-`end' */
1084 /* s: first last start end */
1091 WS
, /* sal[sal_i] = last */
1094 ROLL
, /* s: first end last start */
1097 SWAP
, /* s: first end start last start */
1098 SUB
, /* s: first end start loop_count */
1101 bci_get_point_extrema
,
1103 /* clean up stack */
1106 SWAP
, /* s: end first */
1111 ROLL
, /* s: (first - 1) (first - 1) end */
1113 SUB
, /* s: (first - 1) loop_count */
1116 bci_get_point_extrema
,
1118 /* clean up stack */
1121 ELSE
, /* s: start end */
1128 WS
, /* sal[sal_i] = end */
1133 SUB
, /* s: start loop_count */
1136 bci_get_point_extrema
,
1138 /* clean up stack */
1142 /* the twilight point representing a segment */
1143 /* is in the middle between the minimum and maximum */
1155 DIV
, /* s: middle_pos */
1157 DO_SCALE
, /* middle_pos = middle_pos * scale */
1159 /* write it to temporary CVT location */
1163 SZP0
, /* set zp0 to twilight zone 0 */
1167 /* create twilight point with index `sal_j' */
1180 ADD
, /* twilight_point = twilight_point + 1 */
1189 * bci_create_segments
1191 * This is the top-level entry function.
1193 * It pops point ranges from the stack to define segments, computes
1194 * twilight points to represent segments, and finally calls
1195 * `bci_hint_glyph' to handle the rest.
1197 * in: num_packed_segments
1201 * [contour_last 0 (if wrap-around segment)]
1202 * [contour_first 0 (if wrap-around segment)]
1205 * [contour_last 0 (if wrap-around segment)]
1206 * [contour_first 0 (if wrap-around segment)]
1208 * segment_start_(N-1)
1210 * [contour_last (N-1) (if wrap-around segment)]
1211 * [contour_first (N-1) (if wrap-around segment)]
1212 * ... stuff for bci_hint_glyph ...
1214 * sal: sal_i (start of current segment)
1215 * sal_j (current twilight point)
1216 * sal_num_packed_segments
1217 * sal_base (the base for delta values in nibbles)
1219 * CVT: cvtl_is_subglyph
1221 * uses: bci_create_segment
1225 * If `num_packed_segments' is set to p, the first p start/end pairs are
1226 * stored as delta values in nibbles, with the `start' delta in the lower
1227 * nibble (and there are no wrap-around segments). For example, if the
1228 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1229 * stack are 0x21, 0x32, and 0x14.
1233 unsigned char FPGM(bci_create_segments
) [] =
1237 bci_create_segments
,
1240 /* only do something if we are not a subglyph */
1247 /* all our measurements are taken along the y axis */
1251 sal_num_packed_segments
,
1259 SUB
, /* delta = (2*num_segments - 1) */
1269 WS
, /* sal_base = 0 */
1270 WS
, /* sal_j = 0 (point offset) */
1273 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1275 /* `bci_create_segment_point' also increases the loop counter by 1; */
1276 /* this effectively means we have a loop step of 2 */
1296 * bci_create_segments_X
1298 * Top-level routines for calling `bci_create_segments'.
1301 unsigned char FPGM(bci_create_segments_0
) [] =
1305 bci_create_segments_0
,
1310 bci_create_segments
,
1317 unsigned char FPGM(bci_create_segments_1
) [] =
1321 bci_create_segments_1
,
1326 bci_create_segments
,
1333 unsigned char FPGM(bci_create_segments_2
) [] =
1337 bci_create_segments_2
,
1342 bci_create_segments
,
1349 unsigned char FPGM(bci_create_segments_3
) [] =
1353 bci_create_segments_3
,
1358 bci_create_segments
,
1365 unsigned char FPGM(bci_create_segments_4
) [] =
1369 bci_create_segments_4
,
1374 bci_create_segments
,
1381 unsigned char FPGM(bci_create_segments_5
) [] =
1385 bci_create_segments_5
,
1390 bci_create_segments
,
1397 unsigned char FPGM(bci_create_segments_6
) [] =
1401 bci_create_segments_6
,
1406 bci_create_segments
,
1413 unsigned char FPGM(bci_create_segments_7
) [] =
1417 bci_create_segments_7
,
1422 bci_create_segments
,
1429 unsigned char FPGM(bci_create_segments_8
) [] =
1433 bci_create_segments_8
,
1438 bci_create_segments
,
1445 unsigned char FPGM(bci_create_segments_9
) [] =
1449 bci_create_segments_9
,
1454 bci_create_segments
,
1463 * bci_create_segments_composite
1465 * The same as `bci_create_segments'.
1466 * It also decrements the composite component counter.
1468 * sal: sal_num_packed_segments
1469 * sal_segment_offset
1471 * CVT: cvtl_is_subglyph
1473 * uses: bci_decrement_component_counter
1474 * bci_create_segment
1479 unsigned char FPGM(bci_create_segments_composite
) [] =
1483 bci_create_segments_composite
,
1487 bci_decrement_component_counter
,
1490 /* only do something if we are not a subglyph */
1497 /* all our measurements are taken along the y axis */
1501 sal_num_packed_segments
,
1509 SUB
, /* delta = (2*num_segments - 1) */
1519 WS
, /* sal_base = 0 */
1520 WS
, /* sal_j = 0 (point offset) */
1523 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1525 /* `bci_create_segment_point' also increases the loop counter by 1; */
1526 /* this effectively means we have a loop step of 2 */
1546 * bci_create_segments_composite_X
1548 * Top-level routines for calling `bci_create_segments_composite'.
1551 unsigned char FPGM(bci_create_segments_composite_0
) [] =
1555 bci_create_segments_composite_0
,
1560 bci_create_segments_composite
,
1567 unsigned char FPGM(bci_create_segments_composite_1
) [] =
1571 bci_create_segments_composite_1
,
1576 bci_create_segments_composite
,
1583 unsigned char FPGM(bci_create_segments_composite_2
) [] =
1587 bci_create_segments_composite_2
,
1592 bci_create_segments_composite
,
1599 unsigned char FPGM(bci_create_segments_composite_3
) [] =
1603 bci_create_segments_composite_3
,
1608 bci_create_segments_composite
,
1615 unsigned char FPGM(bci_create_segments_composite_4
) [] =
1619 bci_create_segments_composite_4
,
1624 bci_create_segments_composite
,
1631 unsigned char FPGM(bci_create_segments_composite_5
) [] =
1635 bci_create_segments_composite_5
,
1640 bci_create_segments_composite
,
1647 unsigned char FPGM(bci_create_segments_composite_6
) [] =
1651 bci_create_segments_composite_6
,
1656 bci_create_segments_composite
,
1663 unsigned char FPGM(bci_create_segments_composite_7
) [] =
1667 bci_create_segments_composite_7
,
1672 bci_create_segments_composite
,
1679 unsigned char FPGM(bci_create_segments_composite_8
) [] =
1683 bci_create_segments_composite_8
,
1688 bci_create_segments_composite
,
1695 unsigned char FPGM(bci_create_segments_composite_9
) [] =
1699 bci_create_segments_composite_9
,
1704 bci_create_segments_composite
,
1715 * Align all points in a segment to the twilight point in rp0.
1716 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1720 * sal: sal_segment_offset
1723 unsigned char FPGM(bci_align_segment
) [] =
1730 /* we need the values of `sal_segment_offset + 2*segment_index' */
1731 /* and `sal_segment_offset + 2*segment_index + 1' */
1743 RS
, /* s: first last */
1748 CINDEX
, /* s: first last first */
1751 CINDEX
, /* s: first last first last */
1752 LTEQ
, /* first <= end */
1753 IF
, /* s: first last */
1755 DUP
, /* s: last first first */
1756 ALIGNRP
, /* align point with index `first' with rp0 */
1760 ADD
, /* first = first + 1 */
1761 SWAP
, /* s: first last */
1766 JMPR
, /* goto start_loop */
1779 * bci_align_segments
1781 * Align segments to the twilight point in rp0.
1782 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1791 * uses: bci_align_segment
1794 unsigned char FPGM(bci_align_segments
) [] =
1817 * Scale a contour using two points giving the maximum and minimum
1820 * It expects that no point on the contour is touched.
1829 unsigned char FPGM(bci_scale_contour
) [] =
1840 DO_SCALE
, /* min_pos_new = min_pos * scale */
1845 /* don't scale a single-point contour twice */
1854 DO_SCALE
, /* max_pos_new = max_pos * scale */
1871 * Scale a glyph using a list of points (two points per contour, giving
1872 * the maximum and mininum coordinates).
1874 * It expects that no point in the glyph is touched.
1876 * Note that the point numbers are sorted in ascending order;
1877 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
1878 * contour without specifying which one is the minimum and maximum.
1880 * in: num_contours (N)
1889 * CVT: cvtl_is_subglyph
1891 * uses: bci_scale_contour
1894 unsigned char FPGM(bci_scale_glyph
) [] =
1901 /* only do something if we are not a subglyph */
1908 /* all our measurements are taken along the y axis */
1913 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1921 SZP2
, /* set zp2 to normal zone 1 */
1934 * bci_scale_composite_glyph
1936 * The same as `bci_scale_composite_glyph'.
1937 * It also decrements the composite component counter.
1939 * CVT: cvtl_is_subglyph
1941 * uses: bci_decrement_component_counter
1945 unsigned char FPGM(bci_scale_composite_glyph
) [] =
1949 bci_scale_composite_glyph
,
1953 bci_decrement_component_counter
,
1956 /* only do something if we are not a subglyph */
1963 /* all our measurements are taken along the y axis */
1968 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1976 SZP2
, /* set zp2 to normal zone 1 */
1991 * Shift a contour by a given amount.
1993 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1994 * point to the normal zone 1.
2000 unsigned char FPGM(bci_shift_contour
) [] =
2008 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2020 * bci_shift_subglyph
2022 * Shift a subglyph. To be more specific, it corrects the already applied
2023 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2026 * If this function is called, a point `x' in the subglyph has been scaled
2027 * already (during the hinting of the subglyph itself), and `offset' has
2028 * been applied also:
2030 * x -> x * scale + offset (1)
2032 * However, the offset should be applied first, then the scaling:
2034 * x -> (x + offset) * scale (2)
2036 * Our job is now to transform (1) to (2); a simple calculation shows that
2037 * we have to shift all points of the subglyph by
2039 * offset * scale - offset = offset * (scale - 1)
2041 * Note that `cvtl_scale' is equal to the above `scale - 1'.
2043 * in: offset (in FUnits)
2047 * CVT: cvtl_funits_to_pixels
2055 unsigned char FPGM(bci_shift_subglyph
) [] =
2065 cvtl_funits_to_pixels
,
2066 RCVT
, /* scaling factor FUnits -> pixels */
2073 /* the autohinter always rounds offsets */
2076 CALL
, /* offset = round(offset) */
2085 DIV
, /* delta = offset * (scale - 1) */
2087 /* and round again */
2090 CALL
, /* offset = round(offset) */
2094 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2096 /* we create twilight point 0 as a reference point, */
2097 /* setting the original position to zero (using `cvtl_temp') */
2105 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
2107 SWAP
, /* s: first_contour num_contours 0 delta */
2108 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
2113 SZP2
, /* set zp2 to normal zone 1 */
2122 * bci_ip_outer_align_point
2124 * Auxiliary function for `bci_action_ip_before' and
2125 * `bci_action_ip_after'.
2127 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2128 * zone, and both zp1 and zp2 set to normal zone.
2132 * sal: sal_i (edge_orig_pos)
2138 unsigned char FPGM(bci_ip_outer_align_point
) [] =
2142 bci_ip_outer_align_point
,
2146 ALIGNRP
, /* align `point' with `edge' */
2149 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2154 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2163 * bci_ip_on_align_points
2165 * Auxiliary function for `bci_action_ip_on'.
2167 * in: edge (in twilight zone)
2175 unsigned char FPGM(bci_ip_on_align_points
) [] =
2179 bci_ip_on_align_points
,
2182 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2193 * bci_ip_between_align_point
2195 * Auxiliary function for `bci_ip_between_align_points'.
2197 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2198 * zone, and both zp1 and zp2 set to normal zone.
2202 * sal: sal_i (edge_orig_pos)
2203 * sal_j (stretch_factor)
2209 unsigned char FPGM(bci_ip_between_align_point
) [] =
2213 bci_ip_between_align_point
,
2217 ALIGNRP
, /* align `point' with `edge' */
2220 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2225 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2229 MUL
, /* s: point delta */
2238 * bci_ip_between_align_points
2240 * Auxiliary function for `bci_action_ip_between'.
2242 * in: after_edge (in twilight zone)
2243 * before_edge (in twilight zone)
2250 * sal: sal_i (before_orig_pos)
2251 * sal_j (stretch_factor)
2253 * uses: bci_ip_between_align_point
2256 unsigned char FPGM(bci_ip_between_align_points
) [] =
2260 bci_ip_between_align_points
,
2266 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2268 DUP
, /* s: ... before after before before */
2269 MDAP_noround
, /* set rp0 and rp1 to `before' */
2271 GC_orig
, /* s: ... before after before before_orig_pos */
2275 WS
, /* sal_i = before_orig_pos */
2278 CINDEX
, /* s: ... before after before after */
2279 MD_cur
, /* a = after_pos - before_pos */
2282 MD_orig_ZP2_0
, /* b = after_orig_pos - before_orig_pos */
2288 POP
, /* avoid division by zero */
2294 WS
, /* sal_j = stretch_factor */
2297 bci_ip_between_align_point
,
2300 SZP2
, /* set zp2 to normal zone 1 */
2301 SZP1
, /* set zp1 to normal zone 1 */
2310 * bci_action_ip_before
2312 * Handle `ip_before' data to align points located before the first edge.
2314 * in: first_edge (in twilight zone)
2321 * sal: sal_i (first_edge_orig_pos)
2323 * uses: bci_ip_outer_align_point
2326 unsigned char FPGM(bci_action_ip_before
) [] =
2330 bci_action_ip_before
,
2335 SZP2
, /* set zp2 to twilight zone 0 */
2342 WS
, /* sal_i = first_edge_orig_pos */
2348 SZP2
, /* set zp2 to normal zone 1 */
2349 SZP1
, /* set zp1 to normal zone 1 */
2350 SZP0
, /* set zp0 to twilight zone 0 */
2352 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
2355 bci_ip_outer_align_point
,
2364 * bci_action_ip_after
2366 * Handle `ip_after' data to align points located after the last edge.
2368 * in: last_edge (in twilight zone)
2375 * sal: sal_i (last_edge_orig_pos)
2377 * uses: bci_ip_outer_align_point
2380 unsigned char FPGM(bci_action_ip_after
) [] =
2384 bci_action_ip_after
,
2389 SZP2
, /* set zp2 to twilight zone 0 */
2396 WS
, /* sal_i = last_edge_orig_pos */
2402 SZP2
, /* set zp2 to normal zone 1 */
2403 SZP1
, /* set zp1 to normal zone 1 */
2404 SZP0
, /* set zp0 to twilight zone 0 */
2406 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
2409 bci_ip_outer_align_point
,
2420 * Handle `ip_on' data to align points located on an edge coordinate (but
2421 * not part of an edge).
2423 * in: loop_counter (M)
2424 * edge_1 (in twilight zone)
2425 * loop_counter (N_1)
2430 * edge_2 (in twilight zone)
2431 * loop_counter (N_2)
2437 * edge_M (in twilight zone)
2438 * loop_counter (N_M)
2444 * uses: bci_ip_on_align_points
2447 unsigned char FPGM(bci_action_ip_on
) [] =
2457 SZP1
, /* set zp1 to normal zone 1 */
2458 SZP0
, /* set zp0 to twilight zone 0 */
2461 bci_ip_on_align_points
,
2470 * bci_action_ip_between
2472 * Handle `ip_between' data to align points located between two edges.
2474 * in: loop_counter (M)
2475 * before_edge_1 (in twilight zone)
2476 * after_edge_1 (in twilight zone)
2477 * loop_counter (N_1)
2482 * before_edge_2 (in twilight zone)
2483 * after_edge_2 (in twilight zone)
2484 * loop_counter (N_2)
2490 * before_edge_M (in twilight zone)
2491 * after_edge_M (in twilight zone)
2492 * loop_counter (N_M)
2498 * uses: bci_ip_between_align_points
2501 unsigned char FPGM(bci_action_ip_between
) [] =
2505 bci_action_ip_between
,
2509 bci_ip_between_align_points
,
2520 * Common code for bci_action_adjust routines.
2522 * uses: func[cvtl_stem_width_function]
2525 unsigned char FPGM(bci_adjust_common
) [] =
2534 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2538 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
2541 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2542 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
2545 cvtl_stem_width_function
,
2548 NEG
, /* s: [...] edge2 edge -cur_len */
2550 ROLL
, /* s: [...] edge -cur_len edge2 */
2551 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2554 DUP
, /* s: [...] -cur_len edge edge edge */
2555 ALIGNRP
, /* align `edge' with `edge2' */
2557 SHPIX
, /* shift `edge' by -cur_len */
2567 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2568 * edge of the stem has already been moved, then moving it again if
2569 * necessary to stay bound.
2571 * in: edge2_is_serif
2573 * edge_point (in twilight zone)
2574 * edge2_point (in twilight zone)
2575 * edge[-1] (in twilight zone)
2576 * ... stuff for bci_align_segments (edge) ...
2578 * uses: bci_adjust_common
2579 * bci_align_segments
2582 unsigned char FPGM(bci_adjust_bound
) [] =
2593 SWAP
, /* s: edge edge[-1] */
2595 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2600 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2601 GT
, /* edge_pos < edge[-1]_pos */
2604 ALIGNRP
, /* align `edge' to `edge[-1]' */
2607 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2612 SZP1
, /* set zp1 to normal zone 1 */
2621 * bci_action_adjust_bound
2622 * bci_action_adjust_bound_serif
2623 * bci_action_adjust_bound_round
2624 * bci_action_adjust_bound_round_serif
2626 * Higher-level routines for calling `bci_adjust_bound'.
2629 unsigned char FPGM(bci_action_adjust_bound
) [] =
2633 bci_action_adjust_bound
,
2646 unsigned char FPGM(bci_action_adjust_bound_serif
) [] =
2650 bci_action_adjust_bound_serif
,
2663 unsigned char FPGM(bci_action_adjust_bound_round
) [] =
2667 bci_action_adjust_bound_round
,
2680 unsigned char FPGM(bci_action_adjust_bound_round_serif
) [] =
2684 bci_action_adjust_bound_round_serif
,
2701 * Handle the ADJUST action to align an edge of a stem if the other edge
2702 * of the stem has already been moved.
2704 * in: edge2_is_serif
2706 * edge_point (in twilight zone)
2707 * edge2_point (in twilight zone)
2708 * ... stuff for bci_align_segments (edge) ...
2710 * uses: bci_adjust_common
2711 * bci_align_segments
2714 unsigned char FPGM(bci_adjust
) [] =
2725 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2730 SZP1
, /* set zp1 to normal zone 1 */
2740 * bci_action_adjust_serif
2741 * bci_action_adjust_round
2742 * bci_action_adjust_round_serif
2744 * Higher-level routines for calling `bci_adjust'.
2747 unsigned char FPGM(bci_action_adjust
) [] =
2764 unsigned char FPGM(bci_action_adjust_serif
) [] =
2768 bci_action_adjust_serif
,
2781 unsigned char FPGM(bci_action_adjust_round
) [] =
2785 bci_action_adjust_round
,
2798 unsigned char FPGM(bci_action_adjust_round_serif
) [] =
2802 bci_action_adjust_round_serif
,
2819 * Common code for bci_action_stem routines.
2826 * uses: func[cvtl_stem_width_function]
2831 #define sal_u_off sal_temp1
2833 #define sal_d_off sal_temp2
2835 #define sal_org_len sal_temp3
2837 #define sal_edge2 sal_temp3
2839 unsigned char FPGM(bci_stem_common
) [] =
2848 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2856 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
2857 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2859 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
2867 cvtl_stem_width_function
,
2869 CALL
, /* s: [...] edge2 edge cur_len */
2874 LT
, /* cur_len < 96 */
2879 LTEQ
, /* cur_len <= 64 */
2897 SWAP
, /* s: [...] edge2 cur_len edge */
2902 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
2908 ADD
, /* s: [...] edge2 cur_len edge org_pos */
2915 ADD
, /* s: [...] edge2 cur_len edge org_center */
2920 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
2925 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
2932 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2939 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
2941 LT
, /* delta1 < delta2 */
2946 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2952 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2953 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
2961 SUB
, /* arg = cur_pos1 - cur_len/2 */
2963 SWAP
, /* s: [...] edge2 cur_len arg edge */
2969 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
2972 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2975 SWAP
, /* s: [...] edge2 cur_len edge */
2979 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
2987 ADD
, /* s: [...] edge2 cur_len edge org_pos */
2996 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
3002 CALL
, /* cur_pos1 = ROUND(org_pos) */
3014 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3025 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3032 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3038 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3039 LT
, /* delta1 < delta2 */
3041 POP
, /* arg = cur_pos1 */
3045 POP
, /* arg = cur_pos2 */
3046 EIF
, /* s: [...] edge2 cur_len edge arg */
3053 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3056 SHPIX
, /* edge = arg */
3057 EIF
, /* s: [...] edge2 cur_len edge */
3067 * Handle the STEM action to align two edges of a stem, then moving one
3068 * edge again if necessary to stay bound.
3070 * The code after computing `cur_len' to shift `edge' and `edge2'
3071 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3074 * if cur_len < = 64:
3081 * org_pos = anchor + (edge_orig - anchor_orig);
3082 * org_center = org_pos + org_len / 2;
3084 * cur_pos1 = ROUND(org_center)
3085 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3086 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3087 * if (delta1 < delta2):
3088 * cur_pos1 = cur_pos1 - u_off
3090 * cur_pos1 = cur_pos1 + d_off
3092 * edge = cur_pos1 - cur_len / 2
3095 * org_pos = anchor + (edge_orig - anchor_orig)
3096 * org_center = org_pos + org_len / 2;
3098 * cur_pos1 = ROUND(org_pos)
3099 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3100 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3101 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3103 * if (delta1 < delta2):
3108 * edge2 = edge + cur_len
3110 * in: edge2_is_serif
3112 * edge_point (in twilight zone)
3113 * edge2_point (in twilight zone)
3114 * edge[-1] (in twilight zone)
3115 * ... stuff for bci_align_segments (edge) ...
3116 * ... stuff for bci_align_segments (edge2)...
3123 * uses: bci_stem_common
3124 * bci_align_segments
3127 unsigned char FPGM(bci_stem_bound
) [] =
3138 ROLL
, /* s: edge[-1] cur_len edge edge2 */
3141 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3145 WS
, /* s: edge[-1] cur_len edge edge2 */
3147 SHPIX
, /* edge2 = edge + cur_len */
3149 SWAP
, /* s: edge edge[-1] */
3151 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3156 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3157 GT
, /* edge_pos < edge[-1]_pos */
3160 ALIGNRP
, /* align `edge' to `edge[-1]' */
3163 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3168 SZP1
, /* set zp1 to normal zone 1 */
3174 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3186 * bci_action_stem_bound
3187 * bci_action_stem_bound_serif
3188 * bci_action_stem_bound_round
3189 * bci_action_stem_bound_round_serif
3191 * Higher-level routines for calling `bci_stem_bound'.
3194 unsigned char FPGM(bci_action_stem_bound
) [] =
3198 bci_action_stem_bound
,
3211 unsigned char FPGM(bci_action_stem_bound_serif
) [] =
3215 bci_action_stem_bound_serif
,
3228 unsigned char FPGM(bci_action_stem_bound_round
) [] =
3232 bci_action_stem_bound_round
,
3245 unsigned char FPGM(bci_action_stem_bound_round_serif
) [] =
3249 bci_action_stem_bound_round_serif
,
3266 * Handle the STEM action to align two edges of a stem.
3268 * See `bci_stem_bound' for more details.
3270 * in: edge2_is_serif
3272 * edge_point (in twilight zone)
3273 * edge2_point (in twilight zone)
3274 * ... stuff for bci_align_segments (edge) ...
3275 * ... stuff for bci_align_segments (edge2)...
3282 * uses: bci_stem_common
3283 * bci_align_segments
3286 unsigned char FPGM(bci_stem
) [] =
3298 SWAP
, /* s: cur_len edge2 */
3301 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3305 WS
, /* s: cur_len edge2 */
3307 SHPIX
, /* edge2 = edge + cur_len */
3312 SZP1
, /* set zp1 to normal zone 1 */
3318 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3330 * bci_action_stem_serif
3331 * bci_action_stem_round
3332 * bci_action_stem_round_serif
3334 * Higher-level routines for calling `bci_stem'.
3337 unsigned char FPGM(bci_action_stem
) [] =
3354 unsigned char FPGM(bci_action_stem_serif
) [] =
3358 bci_action_stem_serif
,
3371 unsigned char FPGM(bci_action_stem_round
) [] =
3375 bci_action_stem_round
,
3388 unsigned char FPGM(bci_action_stem_round_serif
) [] =
3392 bci_action_stem_round_serif
,
3409 * Handle the LINK action to link an edge to another one.
3413 * base_point (in twilight zone)
3414 * stem_point (in twilight zone)
3415 * ... stuff for bci_align_segments (base) ...
3417 * uses: func[cvtl_stem_width_function]
3418 * bci_align_segments
3421 unsigned char FPGM(bci_link
) [] =
3430 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3438 DUP
, /* s: stem is_round is_serif stem base base */
3439 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3441 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
3444 cvtl_stem_width_function
,
3446 CALL
, /* s: stem new_dist */
3450 ALIGNRP
, /* align `stem_point' with `base_point' */
3452 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
3454 SHPIX
, /* stem_point = base_point + new_dist */
3459 SZP1
, /* set zp1 to normal zone 1 */
3469 * bci_action_link_serif
3470 * bci_action_link_round
3471 * bci_action_link_round_serif
3473 * Higher-level routines for calling `bci_link'.
3476 unsigned char FPGM(bci_action_link
) [] =
3493 unsigned char FPGM(bci_action_link_serif
) [] =
3497 bci_action_link_serif
,
3510 unsigned char FPGM(bci_action_link_round
) [] =
3514 bci_action_link_round
,
3527 unsigned char FPGM(bci_action_link_round_serif
) [] =
3531 bci_action_link_round_serif
,
3548 * Handle the ANCHOR action to align two edges
3549 * and to set the edge anchor.
3551 * The code after computing `cur_len' to shift `edge' and `edge2'
3552 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3555 * if cur_len < = 64:
3562 * org_center = edge_orig + org_len / 2
3563 * cur_pos1 = ROUND(org_center)
3565 * error1 = ABS(org_center - (cur_pos1 - u_off))
3566 * error2 = ABS(org_center - (cur_pos1 + d_off))
3567 * if (error1 < error2):
3568 * cur_pos1 = cur_pos1 - u_off
3570 * cur_pos1 = cur_pos1 + d_off
3572 * edge = cur_pos1 - cur_len / 2
3573 * edge2 = edge + cur_len
3576 * edge = ROUND(edge_orig)
3578 * in: edge2_is_serif
3580 * edge_point (in twilight zone)
3581 * edge2_point (in twilight zone)
3582 * ... stuff for bci_align_segments (edge) ...
3589 * uses: func[cvtl_stem_width_function]
3591 * bci_align_segments
3595 #define sal_u_off sal_temp1
3597 #define sal_d_off sal_temp2
3599 #define sal_org_len sal_temp3
3601 unsigned char FPGM(bci_anchor
) [] =
3608 /* store anchor point number in `sal_anchor' */
3613 WS
, /* sal_anchor = edge_point */
3617 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3625 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
3626 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3628 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
3636 cvtl_stem_width_function
,
3638 CALL
, /* s: edge2 edge cur_len */
3643 LT
, /* cur_len < 96 */
3648 LTEQ
, /* cur_len <= 64 */
3666 SWAP
, /* s: edge2 cur_len edge */
3667 DUP
, /* s: edge2 cur_len edge edge */
3676 ADD
, /* s: edge2 cur_len edge org_center */
3681 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
3686 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
3693 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
3700 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
3702 LT
, /* error1 < error2 */
3707 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3713 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3714 EIF
, /* s: edge2 cur_len edge cur_pos1 */
3722 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
3726 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
3729 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3731 SWAP
, /* s: cur_len edge2 */
3733 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3735 SHPIX
, /* edge2 = edge1 + cur_len */
3738 POP
, /* s: edge2 edge */
3746 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
3749 SHPIX
, /* edge = round(edge_orig) */
3751 /* clean up stack */
3758 SZP1
, /* set zp1 to normal zone 1 */
3768 * bci_action_anchor_serif
3769 * bci_action_anchor_round
3770 * bci_action_anchor_round_serif
3772 * Higher-level routines for calling `bci_anchor'.
3775 unsigned char FPGM(bci_action_anchor
) [] =
3792 unsigned char FPGM(bci_action_anchor_serif
) [] =
3796 bci_action_anchor_serif
,
3809 unsigned char FPGM(bci_action_anchor_round
) [] =
3813 bci_action_anchor_round
,
3826 unsigned char FPGM(bci_action_anchor_round_serif
) [] =
3830 bci_action_anchor_round_serif
,
3845 * bci_action_blue_anchor
3847 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
3848 * and to set the edge anchor.
3850 * in: anchor_point (in twilight zone)
3852 * edge_point (in twilight zone)
3853 * ... stuff for bci_align_segments (edge) ...
3857 * uses: bci_action_blue
3860 unsigned char FPGM(bci_action_blue_anchor
) [] =
3864 bci_action_blue_anchor
,
3867 /* store anchor point number in `sal_anchor' */
3885 * Handle the BLUE action to align an edge with a blue zone.
3888 * edge_point (in twilight zone)
3889 * ... stuff for bci_align_segments (edge) ...
3891 * uses: bci_align_segments
3894 unsigned char FPGM(bci_action_blue
) [] =
3903 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3905 /* move `edge_point' to `blue_cvt_idx' position; */
3906 /* note that we can't use MIAP since this would modify */
3907 /* the twilight point's original coordinates also */
3911 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3913 GC_cur
, /* s: new_pos edge edge_pos */
3916 SUB
, /* s: edge (new_pos - edge_pos) */
3922 SZP1
, /* set zp1 to normal zone 1 */
3933 * Common code for bci_action_serif routines.
3936 unsigned char FPGM(bci_serif_common
) [] =
3945 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3952 MINDEX
, /* s: [...] serif serif serif serif base */
3954 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
3957 ALIGNRP
, /* align `serif_point' with `base_point' */
3958 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
3968 * Move an edge if necessary to stay within a lower bound.
3973 * uses: bci_align_segments
3976 unsigned char FPGM(bci_lower_bound
) [] =
3983 SWAP
, /* s: edge bound */
3985 MDAP_noround
, /* set rp0 and rp1 to `bound' */
3990 GC_cur
, /* s: edge bound_pos edge_pos */
3991 GT
, /* edge_pos < bound_pos */
3994 ALIGNRP
, /* align `edge' to `bound' */
3997 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4002 SZP1
, /* set zp1 to normal zone 1 */
4013 * Move an edge if necessary to stay within an upper bound.
4018 * uses: bci_align_segments
4021 unsigned char FPGM(bci_upper_bound
) [] =
4028 SWAP
, /* s: edge bound */
4030 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4035 GC_cur
, /* s: edge bound_pos edge_pos */
4036 LT
, /* edge_pos > bound_pos */
4039 ALIGNRP
, /* align `edge' to `bound' */
4042 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4047 SZP1
, /* set zp1 to normal zone 1 */
4056 * bci_upper_lower_bound
4058 * Move an edge if necessary to stay within a lower and lower bound.
4064 * uses: bci_align_segments
4067 unsigned char FPGM(bci_upper_lower_bound
) [] =
4071 bci_upper_lower_bound
,
4074 SWAP
, /* s: upper serif lower */
4076 MDAP_noround
, /* set rp0 and rp1 to `lower' */
4081 GC_cur
, /* s: upper serif lower_pos serif_pos */
4082 GT
, /* serif_pos < lower_pos */
4085 ALIGNRP
, /* align `serif' to `lower' */
4088 SWAP
, /* s: serif upper */
4090 MDAP_noround
, /* set rp0 and rp1 to `upper' */
4095 GC_cur
, /* s: serif upper_pos serif_pos */
4096 LT
, /* serif_pos > upper_pos */
4099 ALIGNRP
, /* align `serif' to `upper' */
4102 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4107 SZP1
, /* set zp1 to normal zone 1 */
4118 * Handle the SERIF action to align a serif with its base.
4120 * in: serif_point (in twilight zone)
4121 * base_point (in twilight zone)
4122 * ... stuff for bci_align_segments (serif) ...
4124 * uses: bci_serif_common
4125 * bci_align_segments
4128 unsigned char FPGM(bci_action_serif
) [] =
4139 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4144 SZP1
, /* set zp1 to normal zone 1 */
4153 * bci_action_serif_lower_bound
4155 * Handle the SERIF action to align a serif with its base, then moving it
4156 * again if necessary to stay within a lower bound.
4158 * in: serif_point (in twilight zone)
4159 * base_point (in twilight zone)
4160 * edge[-1] (in twilight zone)
4161 * ... stuff for bci_align_segments (serif) ...
4163 * uses: bci_serif_common
4167 unsigned char FPGM(bci_action_serif_lower_bound
) [] =
4171 bci_action_serif_lower_bound
,
4188 * bci_action_serif_upper_bound
4190 * Handle the SERIF action to align a serif with its base, then moving it
4191 * again if necessary to stay within an upper bound.
4193 * in: serif_point (in twilight zone)
4194 * base_point (in twilight zone)
4195 * edge[1] (in twilight zone)
4196 * ... stuff for bci_align_segments (serif) ...
4198 * uses: bci_serif_common
4202 unsigned char FPGM(bci_action_serif_upper_bound
) [] =
4206 bci_action_serif_upper_bound
,
4223 * bci_action_serif_upper_lower_bound
4225 * Handle the SERIF action to align a serif with its base, then moving it
4226 * again if necessary to stay within a lower and upper bound.
4228 * in: serif_point (in twilight zone)
4229 * base_point (in twilight zone)
4230 * edge[-1] (in twilight zone)
4231 * edge[1] (in twilight zone)
4232 * ... stuff for bci_align_segments (serif) ...
4234 * uses: bci_serif_common
4235 * bci_upper_lower_bound
4238 unsigned char FPGM(bci_action_serif_upper_lower_bound
) [] =
4242 bci_action_serif_upper_lower_bound
,
4247 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4254 bci_upper_lower_bound
,
4263 * bci_serif_anchor_common
4265 * Common code for bci_action_serif_anchor routines.
4272 unsigned char FPGM(bci_serif_anchor_common
) [] =
4276 bci_serif_anchor_common
,
4281 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4287 WS
, /* sal_anchor = edge_point */
4297 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4300 SHPIX
, /* edge = round(edge_orig) */
4308 * bci_action_serif_anchor
4310 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4313 * in: edge_point (in twilight zone)
4314 * ... stuff for bci_align_segments (edge) ...
4316 * uses: bci_serif_anchor_common
4317 * bci_align_segments
4320 unsigned char FPGM(bci_action_serif_anchor
) [] =
4324 bci_action_serif_anchor
,
4328 bci_serif_anchor_common
,
4331 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4336 SZP1
, /* set zp1 to normal zone 1 */
4345 * bci_action_serif_anchor_lower_bound
4347 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4348 * anchor, then moving it again if necessary to stay within a lower
4351 * in: edge_point (in twilight zone)
4352 * edge[-1] (in twilight zone)
4353 * ... stuff for bci_align_segments (edge) ...
4355 * uses: bci_serif_anchor_common
4359 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
4363 bci_action_serif_anchor_lower_bound
,
4367 bci_serif_anchor_common
,
4380 * bci_action_serif_anchor_upper_bound
4382 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4383 * anchor, then moving it again if necessary to stay within an upper
4386 * in: edge_point (in twilight zone)
4387 * edge[1] (in twilight zone)
4388 * ... stuff for bci_align_segments (edge) ...
4390 * uses: bci_serif_anchor_common
4394 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
4398 bci_action_serif_anchor_upper_bound
,
4402 bci_serif_anchor_common
,
4415 * bci_action_serif_anchor_upper_lower_bound
4417 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4418 * anchor, then moving it again if necessary to stay within a lower and
4421 * in: edge_point (in twilight zone)
4422 * edge[-1] (in twilight zone)
4423 * edge[1] (in twilight zone)
4424 * ... stuff for bci_align_segments (edge) ...
4426 * uses: bci_serif_anchor_common
4427 * bci_upper_lower_bound
4430 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound
) [] =
4434 bci_action_serif_anchor_upper_lower_bound
,
4438 bci_serif_anchor_common
,
4442 bci_upper_lower_bound
,
4451 * bci_serif_link1_common
4453 * Common code for bci_action_serif_link1 routines.
4458 unsigned char FPGM(bci_serif_link1_common
) [] =
4462 bci_serif_link1_common
,
4467 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4471 CINDEX
, /* s: [...] after edge before after */
4474 CINDEX
, /* s: [...] after edge before after before */
4478 EQ
, /* after_orig_pos == before_orig_pos */
4479 IF
, /* s: [...] after edge before */
4480 MDAP_noround
, /* set rp0 and rp1 to `before' */
4482 ALIGNRP
, /* align `edge' with `before' */
4487 /* we have to execute `a*b/c', with b/c very near to 1: */
4488 /* to avoid overflow while retaining precision, */
4489 /* we transform this to `a + a * (b-c)/c' */
4493 CINDEX
, /* s: [...] after edge before edge */
4496 CINDEX
, /* s: [...] after edge before edge before */
4497 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
4502 CINDEX
, /* s: [...] after edge before a a after */
4505 CINDEX
, /* s: [...] after edge before a a after before */
4506 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
4510 CINDEX
, /* s: [...] after edge before a a c after */
4513 CINDEX
, /* s: [...] after edge before a a c after before */
4514 MD_cur
, /* b = after_pos - before_pos */
4518 CINDEX
, /* s: [...] after edge before a a c b c */
4524 MUL
, /* (b-c) in 16.16 format */
4529 DIV
, /* s: [...] after edge before a a (b-c)/c */
4531 POP
, /* avoid division by zero */
4534 MUL
, /* a * (b-c)/c * 2^10 */
4538 DIV
, /* a * (b-c)/c */
4542 MDAP_noround
, /* set rp0 and rp1 to `before' */
4543 SWAP
, /* s: [...] after a*b/c edge */
4546 ALIGNRP
, /* align `edge' with `before' */
4548 SHPIX
, /* shift `edge' by `a*b/c' */
4550 SWAP
, /* s: [...] edge after */
4560 * bci_action_serif_link1
4562 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4565 * in: before_point (in twilight zone)
4566 * edge_point (in twilight zone)
4567 * after_point (in twilight zone)
4568 * ... stuff for bci_align_segments (edge) ...
4570 * uses: bci_serif_link1_common
4571 * bci_align_segments
4574 unsigned char FPGM(bci_action_serif_link1
) [] =
4578 bci_action_serif_link1
,
4582 bci_serif_link1_common
,
4585 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4590 SZP1
, /* set zp1 to normal zone 1 */
4599 * bci_action_serif_link1_lower_bound
4601 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4602 * before and after. Additionally, move the serif again if necessary to
4603 * stay within a lower bound.
4605 * in: before_point (in twilight zone)
4606 * edge_point (in twilight zone)
4607 * after_point (in twilight zone)
4608 * edge[-1] (in twilight zone)
4609 * ... stuff for bci_align_segments (edge) ...
4611 * uses: bci_serif_link1_common
4615 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
4619 bci_action_serif_link1_lower_bound
,
4623 bci_serif_link1_common
,
4636 * bci_action_serif_link1_upper_bound
4638 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4639 * before and after. Additionally, move the serif again if necessary to
4640 * stay within an upper bound.
4642 * in: before_point (in twilight zone)
4643 * edge_point (in twilight zone)
4644 * after_point (in twilight zone)
4645 * edge[1] (in twilight zone)
4646 * ... stuff for bci_align_segments (edge) ...
4648 * uses: bci_serif_link1_common
4652 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
4656 bci_action_serif_link1_upper_bound
,
4660 bci_serif_link1_common
,
4673 * bci_action_serif_link1_upper_lower_bound
4675 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4676 * before and after. Additionally, move the serif again if necessary to
4677 * stay within a lower and upper bound.
4679 * in: before_point (in twilight zone)
4680 * edge_point (in twilight zone)
4681 * after_point (in twilight zone)
4682 * edge[-1] (in twilight zone)
4683 * edge[1] (in twilight zone)
4684 * ... stuff for bci_align_segments (edge) ...
4686 * uses: bci_serif_link1_common
4687 * bci_upper_lower_bound
4690 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound
) [] =
4694 bci_action_serif_link1_upper_lower_bound
,
4698 bci_serif_link1_common
,
4702 bci_upper_lower_bound
,
4711 * bci_serif_link2_common
4713 * Common code for bci_action_serif_link2 routines.
4718 unsigned char FPGM(bci_serif_link2_common
) [] =
4722 bci_serif_link2_common
,
4727 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4729 DUP
, /* s: [...] edge edge */
4733 DUP
, /* s: [...] edge edge anchor anchor */
4734 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
4745 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
4750 ALIGNRP
, /* align `edge' with `sal_anchor' */
4752 SHPIX
, /* shift `edge' by `delta' */
4760 * bci_action_serif_link2
4762 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4764 * in: edge_point (in twilight zone)
4765 * ... stuff for bci_align_segments (edge) ...
4767 * uses: bci_serif_link2_common
4768 * bci_align_segments
4771 unsigned char FPGM(bci_action_serif_link2
) [] =
4775 bci_action_serif_link2
,
4779 bci_serif_link2_common
,
4782 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4787 SZP1
, /* set zp1 to normal zone 1 */
4796 * bci_action_serif_link2_lower_bound
4798 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4799 * Additionally, move the serif again if necessary to stay within a lower
4802 * in: edge_point (in twilight zone)
4803 * edge[-1] (in twilight zone)
4804 * ... stuff for bci_align_segments (edge) ...
4806 * uses: bci_serif_link2_common
4810 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
4814 bci_action_serif_link2_lower_bound
,
4818 bci_serif_link2_common
,
4831 * bci_action_serif_link2_upper_bound
4833 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4834 * Additionally, move the serif again if necessary to stay within an upper
4837 * in: edge_point (in twilight zone)
4838 * edge[1] (in twilight zone)
4839 * ... stuff for bci_align_segments (edge) ...
4841 * uses: bci_serif_link2_common
4845 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
4849 bci_action_serif_link2_upper_bound
,
4853 bci_serif_link2_common
,
4866 * bci_action_serif_link2_upper_lower_bound
4868 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
4869 * Additionally, move the serif again if necessary to stay within a lower
4872 * in: edge_point (in twilight zone)
4873 * edge[-1] (in twilight zone)
4874 * edge[1] (in twilight zone)
4875 * ... stuff for bci_align_segments (edge) ...
4877 * uses: bci_serif_link2_common
4878 * bci_upper_lower_bound
4881 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound
) [] =
4885 bci_action_serif_link2_upper_lower_bound
,
4889 bci_serif_link2_common
,
4893 bci_upper_lower_bound
,
4904 * This is the top-level glyph hinting function which parses the arguments
4905 * on the stack and calls subroutines.
4907 * in: action_0_func_idx
4913 * CVT: cvtl_is_subglyph
4915 * uses: bci_action_ip_before
4916 * bci_action_ip_after
4918 * bci_action_ip_between
4920 * bci_action_adjust_bound
4921 * bci_action_adjust_bound_serif
4922 * bci_action_adjust_bound_round
4923 * bci_action_adjust_bound_round_serif
4925 * bci_action_stem_bound
4926 * bci_action_stem_bound_serif
4927 * bci_action_stem_bound_round
4928 * bci_action_stem_bound_round_serif
4931 * bci_action_link_serif
4932 * bci_action_link_round
4933 * bci_action_link_round_serif
4936 * bci_action_anchor_serif
4937 * bci_action_anchor_round
4938 * bci_action_anchor_round_serif
4940 * bci_action_blue_anchor
4943 * bci_action_adjust_serif
4944 * bci_action_adjust_round
4945 * bci_action_adjust_round_serif
4948 * bci_action_stem_serif
4949 * bci_action_stem_round
4950 * bci_action_stem_round_serif
4955 * bci_action_serif_lower_bound
4956 * bci_action_serif_upper_bound
4957 * bci_action_serif_upper_lower_bound
4959 * bci_action_serif_anchor
4960 * bci_action_serif_anchor_lower_bound
4961 * bci_action_serif_anchor_upper_bound
4962 * bci_action_serif_anchor_upper_lower_bound
4964 * bci_action_serif_link1
4965 * bci_action_serif_link1_lower_bound
4966 * bci_action_serif_link1_upper_bound
4967 * bci_action_serif_link1_upper_lower_bound
4969 * bci_action_serif_link2
4970 * bci_action_serif_link2_lower_bound
4971 * bci_action_serif_link2_upper_bound
4972 * bci_action_serif_link2_upper_lower_bound
4975 unsigned char FPGM(bci_hint_glyph
) [] =
4983 /* loop until all data on stack is used */
4992 JROT
, /* goto start_loop */
4996 SZP2
, /* set zp2 to normal zone 1 */
5004 #define COPY_FPGM(func_name) \
5005 memcpy(buf_p, fpgm_ ## func_name, \
5006 sizeof (fpgm_ ## func_name)); \
5007 buf_p += sizeof (fpgm_ ## func_name) \
5010 TA_table_build_fpgm(FT_Byte
** fpgm
,
5020 /* for compatibility with dumb bytecode interpreters or analyzers, */
5021 /* FDEFs are stored in ascending index order, without holes -- */
5022 /* note that some FDEFs are not always needed */
5023 /* (depending on options of `TTFautohint'), */
5024 /* but implementing dynamic FDEF indices would be a lot of work */
5026 buf_len
= sizeof (FPGM(bci_round
))
5027 + sizeof (FPGM(bci_smooth_stem_width_a
))
5029 + sizeof (FPGM(bci_smooth_stem_width_b
))
5031 + sizeof (FPGM(bci_smooth_stem_width_c
))
5032 + sizeof (FPGM(bci_get_best_width
))
5033 + sizeof (FPGM(bci_strong_stem_width_a
))
5035 + sizeof (FPGM(bci_strong_stem_width_b
))
5036 + sizeof (FPGM(bci_loop
))
5037 + sizeof (FPGM(bci_cvt_rescale
))
5038 + sizeof (FPGM(bci_blue_round_a
))
5040 + sizeof (FPGM(bci_blue_round_b
))
5041 + sizeof (FPGM(bci_decrement_component_counter
))
5042 + sizeof (FPGM(bci_get_point_extrema
))
5043 + sizeof (FPGM(bci_nibbles
))
5044 + sizeof (FPGM(bci_number_set_is_element
))
5045 + sizeof (FPGM(bci_number_set_is_element2
))
5047 + sizeof (FPGM(bci_create_segment
))
5048 + sizeof (FPGM(bci_create_segments
))
5050 + sizeof (FPGM(bci_create_segments_0
))
5051 + sizeof (FPGM(bci_create_segments_1
))
5052 + sizeof (FPGM(bci_create_segments_2
))
5053 + sizeof (FPGM(bci_create_segments_3
))
5054 + sizeof (FPGM(bci_create_segments_4
))
5055 + sizeof (FPGM(bci_create_segments_5
))
5056 + sizeof (FPGM(bci_create_segments_6
))
5057 + sizeof (FPGM(bci_create_segments_7
))
5058 + sizeof (FPGM(bci_create_segments_8
))
5059 + sizeof (FPGM(bci_create_segments_9
))
5061 + sizeof (FPGM(bci_create_segments_composite
))
5063 + sizeof (FPGM(bci_create_segments_composite_0
))
5064 + sizeof (FPGM(bci_create_segments_composite_1
))
5065 + sizeof (FPGM(bci_create_segments_composite_2
))
5066 + sizeof (FPGM(bci_create_segments_composite_3
))
5067 + sizeof (FPGM(bci_create_segments_composite_4
))
5068 + sizeof (FPGM(bci_create_segments_composite_5
))
5069 + sizeof (FPGM(bci_create_segments_composite_6
))
5070 + sizeof (FPGM(bci_create_segments_composite_7
))
5071 + sizeof (FPGM(bci_create_segments_composite_8
))
5072 + sizeof (FPGM(bci_create_segments_composite_9
))
5074 + sizeof (FPGM(bci_align_segment
))
5075 + sizeof (FPGM(bci_align_segments
))
5077 + sizeof (FPGM(bci_scale_contour
))
5078 + sizeof (FPGM(bci_scale_glyph
))
5079 + sizeof (FPGM(bci_scale_composite_glyph
))
5080 + sizeof (FPGM(bci_shift_contour
))
5081 + sizeof (FPGM(bci_shift_subglyph
))
5083 + sizeof (FPGM(bci_ip_outer_align_point
))
5084 + sizeof (FPGM(bci_ip_on_align_points
))
5085 + sizeof (FPGM(bci_ip_between_align_point
))
5086 + sizeof (FPGM(bci_ip_between_align_points
))
5088 + sizeof (FPGM(bci_adjust_common
))
5089 + sizeof (FPGM(bci_stem_common
))
5090 + sizeof (FPGM(bci_serif_common
))
5091 + sizeof (FPGM(bci_serif_anchor_common
))
5092 + sizeof (FPGM(bci_serif_link1_common
))
5093 + sizeof (FPGM(bci_serif_link2_common
))
5095 + sizeof (FPGM(bci_lower_bound
))
5096 + sizeof (FPGM(bci_upper_bound
))
5097 + sizeof (FPGM(bci_upper_lower_bound
))
5099 + sizeof (FPGM(bci_adjust_bound
))
5100 + sizeof (FPGM(bci_stem_bound
))
5101 + sizeof (FPGM(bci_link
))
5102 + sizeof (FPGM(bci_anchor
))
5103 + sizeof (FPGM(bci_adjust
))
5104 + sizeof (FPGM(bci_stem
))
5106 + sizeof (FPGM(bci_action_ip_before
))
5107 + sizeof (FPGM(bci_action_ip_after
))
5108 + sizeof (FPGM(bci_action_ip_on
))
5109 + sizeof (FPGM(bci_action_ip_between
))
5111 + sizeof (FPGM(bci_action_blue
))
5112 + sizeof (FPGM(bci_action_blue_anchor
))
5114 + sizeof (FPGM(bci_action_anchor
))
5115 + sizeof (FPGM(bci_action_anchor_serif
))
5116 + sizeof (FPGM(bci_action_anchor_round
))
5117 + sizeof (FPGM(bci_action_anchor_round_serif
))
5119 + sizeof (FPGM(bci_action_adjust
))
5120 + sizeof (FPGM(bci_action_adjust_serif
))
5121 + sizeof (FPGM(bci_action_adjust_round
))
5122 + sizeof (FPGM(bci_action_adjust_round_serif
))
5123 + sizeof (FPGM(bci_action_adjust_bound
))
5124 + sizeof (FPGM(bci_action_adjust_bound_serif
))
5125 + sizeof (FPGM(bci_action_adjust_bound_round
))
5126 + sizeof (FPGM(bci_action_adjust_bound_round_serif
))
5128 + sizeof (FPGM(bci_action_link
))
5129 + sizeof (FPGM(bci_action_link_serif
))
5130 + sizeof (FPGM(bci_action_link_round
))
5131 + sizeof (FPGM(bci_action_link_round_serif
))
5133 + sizeof (FPGM(bci_action_stem
))
5134 + sizeof (FPGM(bci_action_stem_serif
))
5135 + sizeof (FPGM(bci_action_stem_round
))
5136 + sizeof (FPGM(bci_action_stem_round_serif
))
5137 + sizeof (FPGM(bci_action_stem_bound
))
5138 + sizeof (FPGM(bci_action_stem_bound_serif
))
5139 + sizeof (FPGM(bci_action_stem_bound_round
))
5140 + sizeof (FPGM(bci_action_stem_bound_round_serif
))
5142 + sizeof (FPGM(bci_action_serif
))
5143 + sizeof (FPGM(bci_action_serif_lower_bound
))
5144 + sizeof (FPGM(bci_action_serif_upper_bound
))
5145 + sizeof (FPGM(bci_action_serif_upper_lower_bound
))
5147 + sizeof (FPGM(bci_action_serif_anchor
))
5148 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
5149 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
5150 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound
))
5152 + sizeof (FPGM(bci_action_serif_link1
))
5153 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
5154 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
5155 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound
))
5157 + sizeof (FPGM(bci_action_serif_link2
))
5158 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
5159 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
5160 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound
))
5162 + sizeof (FPGM(bci_hint_glyph
));
5164 /* buffer length must be a multiple of four */
5165 len
= (buf_len
+ 3) & ~3;
5166 buf
= (FT_Byte
*)malloc(len
);
5168 return FT_Err_Out_Of_Memory
;
5170 /* pad end of buffer with zeros */
5171 buf
[len
- 1] = 0x00;
5172 buf
[len
- 2] = 0x00;
5173 buf
[len
- 3] = 0x00;
5175 /* copy font program into buffer and fill in the missing variables */
5178 COPY_FPGM(bci_round
);
5179 COPY_FPGM(bci_smooth_stem_width_a
);
5180 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5181 COPY_FPGM(bci_smooth_stem_width_b
);
5182 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5183 COPY_FPGM(bci_smooth_stem_width_c
);
5184 COPY_FPGM(bci_get_best_width
);
5185 COPY_FPGM(bci_strong_stem_width_a
);
5186 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
5187 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_SIZE(font
);
5188 COPY_FPGM(bci_strong_stem_width_b
);
5189 COPY_FPGM(bci_loop
);
5190 COPY_FPGM(bci_cvt_rescale
);
5191 COPY_FPGM(bci_blue_round_a
);
5192 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
5193 COPY_FPGM(bci_blue_round_b
);
5194 COPY_FPGM(bci_decrement_component_counter
);
5195 COPY_FPGM(bci_get_point_extrema
);
5196 COPY_FPGM(bci_nibbles
);
5197 COPY_FPGM(bci_number_set_is_element
);
5198 COPY_FPGM(bci_number_set_is_element2
);
5200 COPY_FPGM(bci_create_segment
);
5201 COPY_FPGM(bci_create_segments
);
5203 COPY_FPGM(bci_create_segments_0
);
5204 COPY_FPGM(bci_create_segments_1
);
5205 COPY_FPGM(bci_create_segments_2
);
5206 COPY_FPGM(bci_create_segments_3
);
5207 COPY_FPGM(bci_create_segments_4
);
5208 COPY_FPGM(bci_create_segments_5
);
5209 COPY_FPGM(bci_create_segments_6
);
5210 COPY_FPGM(bci_create_segments_7
);
5211 COPY_FPGM(bci_create_segments_8
);
5212 COPY_FPGM(bci_create_segments_9
);
5214 COPY_FPGM(bci_create_segments_composite
);
5216 COPY_FPGM(bci_create_segments_composite_0
);
5217 COPY_FPGM(bci_create_segments_composite_1
);
5218 COPY_FPGM(bci_create_segments_composite_2
);
5219 COPY_FPGM(bci_create_segments_composite_3
);
5220 COPY_FPGM(bci_create_segments_composite_4
);
5221 COPY_FPGM(bci_create_segments_composite_5
);
5222 COPY_FPGM(bci_create_segments_composite_6
);
5223 COPY_FPGM(bci_create_segments_composite_7
);
5224 COPY_FPGM(bci_create_segments_composite_8
);
5225 COPY_FPGM(bci_create_segments_composite_9
);
5227 COPY_FPGM(bci_align_segment
);
5228 COPY_FPGM(bci_align_segments
);
5230 COPY_FPGM(bci_scale_contour
);
5231 COPY_FPGM(bci_scale_glyph
);
5232 COPY_FPGM(bci_scale_composite_glyph
);
5233 COPY_FPGM(bci_shift_contour
);
5234 COPY_FPGM(bci_shift_subglyph
);
5236 COPY_FPGM(bci_ip_outer_align_point
);
5237 COPY_FPGM(bci_ip_on_align_points
);
5238 COPY_FPGM(bci_ip_between_align_point
);
5239 COPY_FPGM(bci_ip_between_align_points
);
5241 COPY_FPGM(bci_adjust_common
);
5242 COPY_FPGM(bci_stem_common
);
5243 COPY_FPGM(bci_serif_common
);
5244 COPY_FPGM(bci_serif_anchor_common
);
5245 COPY_FPGM(bci_serif_link1_common
);
5246 COPY_FPGM(bci_serif_link2_common
);
5248 COPY_FPGM(bci_lower_bound
);
5249 COPY_FPGM(bci_upper_bound
);
5250 COPY_FPGM(bci_upper_lower_bound
);
5252 COPY_FPGM(bci_adjust_bound
);
5253 COPY_FPGM(bci_stem_bound
);
5254 COPY_FPGM(bci_link
);
5255 COPY_FPGM(bci_anchor
);
5256 COPY_FPGM(bci_adjust
);
5257 COPY_FPGM(bci_stem
);
5259 COPY_FPGM(bci_action_ip_before
);
5260 COPY_FPGM(bci_action_ip_after
);
5261 COPY_FPGM(bci_action_ip_on
);
5262 COPY_FPGM(bci_action_ip_between
);
5264 COPY_FPGM(bci_action_blue
);
5265 COPY_FPGM(bci_action_blue_anchor
);
5267 COPY_FPGM(bci_action_anchor
);
5268 COPY_FPGM(bci_action_anchor_serif
);
5269 COPY_FPGM(bci_action_anchor_round
);
5270 COPY_FPGM(bci_action_anchor_round_serif
);
5272 COPY_FPGM(bci_action_adjust
);
5273 COPY_FPGM(bci_action_adjust_serif
);
5274 COPY_FPGM(bci_action_adjust_round
);
5275 COPY_FPGM(bci_action_adjust_round_serif
);
5276 COPY_FPGM(bci_action_adjust_bound
);
5277 COPY_FPGM(bci_action_adjust_bound_serif
);
5278 COPY_FPGM(bci_action_adjust_bound_round
);
5279 COPY_FPGM(bci_action_adjust_bound_round_serif
);
5281 COPY_FPGM(bci_action_link
);
5282 COPY_FPGM(bci_action_link_serif
);
5283 COPY_FPGM(bci_action_link_round
);
5284 COPY_FPGM(bci_action_link_round_serif
);
5286 COPY_FPGM(bci_action_stem
);
5287 COPY_FPGM(bci_action_stem_serif
);
5288 COPY_FPGM(bci_action_stem_round
);
5289 COPY_FPGM(bci_action_stem_round_serif
);
5290 COPY_FPGM(bci_action_stem_bound
);
5291 COPY_FPGM(bci_action_stem_bound_serif
);
5292 COPY_FPGM(bci_action_stem_bound_round
);
5293 COPY_FPGM(bci_action_stem_bound_round_serif
);
5295 COPY_FPGM(bci_action_serif
);
5296 COPY_FPGM(bci_action_serif_lower_bound
);
5297 COPY_FPGM(bci_action_serif_upper_bound
);
5298 COPY_FPGM(bci_action_serif_upper_lower_bound
);
5300 COPY_FPGM(bci_action_serif_anchor
);
5301 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
5302 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
5303 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound
);
5305 COPY_FPGM(bci_action_serif_link1
);
5306 COPY_FPGM(bci_action_serif_link1_lower_bound
);
5307 COPY_FPGM(bci_action_serif_link1_upper_bound
);
5308 COPY_FPGM(bci_action_serif_link1_upper_lower_bound
);
5310 COPY_FPGM(bci_action_serif_link2
);
5311 COPY_FPGM(bci_action_serif_link2_lower_bound
);
5312 COPY_FPGM(bci_action_serif_link2_upper_bound
);
5313 COPY_FPGM(bci_action_serif_link2_upper_lower_bound
);
5315 COPY_FPGM(bci_hint_glyph
);
5318 *fpgm_len
= buf_len
;
5325 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
5328 FT_Error error
= FT_Err_Ok
;
5330 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5331 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5337 error
= TA_sfnt_add_table_info(sfnt
);
5341 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5342 if (glyf_table
->processed
)
5344 sfnt
->table_infos
[sfnt
->num_table_infos
- 1] = data
->fpgm_idx
;
5348 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
5352 if (fpgm_len
> sfnt
->max_instructions
)
5353 sfnt
->max_instructions
= fpgm_len
;
5355 /* in case of success, `fpgm_buf' gets linked */
5356 /* and is eventually freed in `TA_font_unload' */
5357 error
= TA_font_add_table(font
,
5358 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
5359 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
5363 data
->fpgm_idx
= sfnt
->table_infos
[sfnt
->num_table_infos
- 1];
5369 /* end of tafpgm.c */