4 * Copyright (C) 2011-2014 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 \
52 * Older versions of Monotype's `iType' bytecode interpreter have a serious
53 * bug: The DIV instruction rounds the result, while the correct operation
54 * is truncation. (Note, however, that MUL always rounds the result.)
55 * Since many printers contain this rasterizer without any possibility to
56 * update to a non-buggy version, we have to work around the problem.
58 * DIV and MUL work on 26.6 numbers which means that the numerator gets
59 * multiplied by 64 before the division, and the product gets divided by 64
60 * after the multiplication, respectively. For example, to divide 2 by 3,
68 * The correct formula to divide two values in 26.6 format with truncation
73 * while older `iType' versions incorrectly apply rounding by using
77 * Doing our 2/3 division, we have a=2 and b=3*64, so we get
79 * (2*64 + (3*64)/2) / (3*64) = 1
81 * instead of the correct result 0.
83 * The solution to the rounding issue is to use a 26.6 value as an
84 * intermediate result so that we can truncate to the nearest integer (in
85 * 26.6 format) with the FLOOR operator before converting back to a plain
86 * integer (in 32.0 format).
88 * For the common divisions by 2 and 2^10 we define macros.
90 #define DIV_POS_BY_2 \
93 DIV, /* multiply by 64, then divide by 2 */ \
97 MUL /* multiply by 1, then divide by 64 */
110 ADD, /* add 1 if value is negative */ \
117 #define DIV_BY_1024 \
137 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
143 MUL, /* delta * 2^10 */ \
144 DIV_BY_1024, /* delta */ \
148 /* in the comments below, the top of the stack (`s:') */
149 /* is the rightmost element; the stack is shown */
150 /* after the instruction on the same line has been executed */
156 * Optimize the alignment of the top of small letters to the pixel grid.
158 * This function gets used in the `prep' table.
160 * in: blue_idx (CVT index for the style's top of small letters blue zone)
162 * sal: sal_i (CVT index of the style's scaling value;
163 * gets incremented by 1 after execution)
166 unsigned char FPGM(bci_align_top_a
) [] =
173 /* only get CVT value for non-zero index */
182 DUP
, /* s: blue blue blue */
186 /* if (font->increase_x_height) */
189 unsigned char FPGM(bci_align_top_b1a
) [] =
192 /* apply much `stronger' rounding up of x height for */
193 /* 6 <= PPEM <= increase_x_height */
199 /* %d, x height increase limit */
201 unsigned char FPGM(bci_align_top_b1b
) [] =
212 52, /* threshold = 52 */
216 40, /* threshold = 40 */
220 FLOOR
, /* fitted = FLOOR(blue + threshold) */
226 /* if (!font->increase_x_height) */
229 unsigned char FPGM(bci_align_top_b2
) [] =
235 FLOOR
, /* fitted = FLOOR(blue + 40) */
241 unsigned char FPGM(bci_align_top_c
) [] =
244 DUP
, /* s: blue blue fitted fitted */
247 IF
, /* s: blue fitted */
251 SUB
, /* s: blue (fitted-blue) */
258 MUL
, /* (fitted-blue) in 16.16 format */
260 DIV
, /* factor = ((fitted-blue) / blue) in 16.16 format */
272 RS
, /* s: factor idx */
281 ADD
, /* sal_i = sal_i + 1 */
292 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
293 * engine specific corrections are applied.
300 unsigned char FPGM(bci_round
) [] =
318 * bci_smooth_stem_width
320 * This is the equivalent to the following code from function
321 * `ta_latin_compute_stem_width':
329 * else if base_is_round:
335 * delta = ABS(dist - std_width)
346 * delta = delta - dist
349 * dist = dist + delta
350 * else if delta < 32:
352 * else if delta < 54:
355 * dist = dist + delta
370 * sal: sal_vwidth_data_offset
377 unsigned char FPGM(bci_smooth_stem_width
) [] =
381 bci_smooth_stem_width
,
385 ABS
, /* s: base_is_round stem_is_serif width dist */
390 LT
, /* dist < 3*64 */
394 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
395 AND
, /* stem_is_serif && dist < 3*64 */
400 sal_vwidth_data_offset
,
402 RCVT
, /* first indirection */
403 MUL
, /* divide by 64 */
404 RCVT
, /* second indirection */
405 GT
, /* standard_width < 40 */
406 OR
, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
408 IF
, /* s: base_is_round width dist */
414 ROLL
, /* s: width dist base_is_round */
415 IF
, /* s: width dist */
420 IF
, /* s: width dist */
431 IF
, /* s: width dist */
438 DUP
, /* s: width dist dist */
441 sal_vwidth_data_offset
,
443 RCVT
, /* first indirection */
444 MUL
, /* divide by 64 */
445 RCVT
, /* second indirection */
447 ABS
, /* s: width dist delta */
452 IF
, /* s: width dist */
456 sal_vwidth_data_offset
,
458 RCVT
, /* first indirection */
459 MUL
, /* divide by 64 */
460 RCVT
, /* second indirection; dist = std_width */
472 DUP
, /* s: width dist dist */
475 LT
, /* dist < 3*64 */
477 DUP
, /* s: width delta dist */
478 FLOOR
, /* dist = FLOOR(dist) */
479 DUP
, /* s: width delta dist dist */
481 ROLL
, /* s: width dist delta dist */
482 SUB
, /* delta = delta - dist */
484 DUP
, /* s: width dist delta delta */
488 IF
, /* s: width dist delta */
489 ADD
, /* dist = dist + delta */
500 ADD
, /* dist = dist + 10 */
511 ADD
, /* dist = dist + 54 */
514 ADD
, /* dist = dist + delta */
523 CALL
, /* dist = round(dist) */
528 SWAP
, /* s: dist width */
533 NEG
, /* dist = -dist */
545 * An auxiliary function for `bci_strong_stem_width'.
547 * in: n (initialized with CVT index for first vertical width)
559 unsigned char FPGM(bci_get_best_width
) [] =
567 RCVT
, /* s: dist n w */
571 CINDEX
, /* s: dist n w w dist */
573 ABS
, /* s: dist n w d */
577 RS
, /* s: dist n w d d best */
587 WS
, /* reference = w */
604 * bci_strong_stem_width
606 * This is the equivalent to the following code (function
607 * `ta_latin_snap_width' and some lines from
608 * `ta_latin_compute_stem_width'):
610 * best = 64 + 32 + 2;
614 * for n in 0 .. num_widths:
622 * if dist >= reference:
623 * if dist < ROUND(reference) + 48:
626 * if dist > ROUND(reference) - 48:
639 * stem_is_serif (unused)
640 * base_is_round (unused)
646 * sal_vwidth_data_offset
650 * uses: bci_get_best_width
654 unsigned char FPGM(bci_strong_stem_width_a
) [] =
658 bci_strong_stem_width
,
666 ABS
, /* s: width dist */
671 WS
, /* sal_best = 98 */
677 WS
, /* sal_ref = width */
681 sal_vwidth_data_offset
,
684 MUL
, /* divide by 64; first index of vertical widths */
687 sal_vwidth_data_offset
,
693 /* %c, number of used styles */
695 unsigned char FPGM(bci_strong_stem_width_b
) [] =
699 RCVT
, /* number of vertical widths */
705 POP
, /* s: width dist */
709 RS
, /* s: width dist dist reference */
716 CALL
, /* s: width dist reference dist dist ROUND(reference) */
721 ROLL
, /* s: width dist reference dist ROUND(reference) 48 reference dist */
723 LTEQ
, /* dist >= reference */
724 IF
, /* s: width dist reference dist ROUND(reference) 48 */
726 LT
, /* dist < ROUND(reference) + 48 */
730 GT
, /* dist > ROUND(reference) - 48 */
734 SWAP
, /* s: width reference dist */
741 GTEQ
, /* dist >= 64 */
745 CALL
, /* dist = ROUND(dist) */
753 SWAP
, /* s: dist width */
758 NEG
, /* dist = -dist */
769 * An auxiliary function for `bci_loop'.
771 * sal: sal_i (gets incremented by 2 after execution)
774 * uses: func[sal_func]
777 unsigned char FPGM(bci_loop_do
) [] =
794 ADD
, /* sal_i = sal_i + 2 */
805 * Take a range `start'..`end' and a function number and apply the
806 * associated function to the range elements `start', `start+2',
813 * sal: sal_i (counter initialized with `start')
814 * sal_func (`func_num')
819 unsigned char FPGM(bci_loop
) [] =
829 WS
, /* sal_func = func_num */
836 WS
, /* sal_i = start */
842 ADD
, /* number of loops ((end - start) / 2 + 1) */
856 * Rescale CVT value by `sal_scale' (in 16.16 format).
858 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
859 * consequently, the calculation `a * b/c' is done as `a + delta' with
860 * `delta = a * (b-c)/c'. This avoids overflow.
869 unsigned char FPGM(bci_cvt_rescale
) [] =
892 * bci_cvt_rescale_range
894 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
897 * This function gets used in the `prep' table.
902 * sal: sal_i (CVT index of the style's scaling value;
903 * gets incremented by 1 after execution)
906 * uses: bci_cvt_rescale
909 unsigned char FPGM(bci_cvt_rescale_range
) [] =
913 bci_cvt_rescale_range
,
916 /* store scaling value in `sal_scale' */
923 WS
, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
933 ADD
, /* sal_i = sal_i + 1 */
942 * bci_vwidth_data_store
944 * Store a vertical width array value.
946 * This function gets used in the `prep' table.
950 * sal: sal_i (CVT index of the style's vwidth data;
951 * gets incremented by 1 after execution)
954 unsigned char FPGM(bci_vwidth_data_store
) [] =
958 bci_vwidth_data_store
,
972 ADD
, /* sal_i = sal_i + 1 */
981 * bci_smooth_blue_round
983 * Round a blue ref value and adjust its corresponding shoot value.
985 * This is the equivalent to the following code (function
986 * `ta_latin_metrics_scale_dim':
994 * else if (delta < 48)
1004 * sal: sal_i (number of blue zones)
1011 unsigned char FPGM(bci_smooth_blue_round
) [] =
1015 bci_smooth_blue_round
,
1020 RCVT
, /* s: ref_idx ref_idx ref */
1026 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
1034 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1036 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1038 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1040 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1042 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1047 LT
, /* delta < 32 */
1056 LT
, /* delta < 48 */
1059 32, /* delta = 32 */
1063 64, /* delta = 64 */
1067 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1072 NEG
, /* delta = -delta */
1079 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1086 ADD
, /* s: (ref_idx + 1) */
1094 * bci_strong_blue_round
1096 * Round a blue ref value and adjust its corresponding shoot value.
1098 * This is the equivalent to the following code:
1112 * It doesn't have corresponding code in talatin.c; however, some tests
1113 * have shown that the `smooth' code works just fine for this case also.
1117 * sal: sal_i (number of blue zones)
1124 unsigned char FPGM(bci_strong_blue_round
) [] =
1128 bci_strong_blue_round
,
1133 RCVT
, /* s: ref_idx ref_idx ref */
1139 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
1147 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1149 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1151 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1153 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1155 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1159 LT
, /* delta < 36 */
1162 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1166 64, /* delta = 64 (one pixel unit) */
1169 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1174 NEG
, /* delta = -delta */
1181 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1188 ADD
, /* s: (ref_idx + 1) */
1196 * bci_blue_round_range
1198 * Round a range of blue zones (both reference and shoot values).
1200 * This function gets used in the `prep' table.
1202 * in: num_blue_zones
1205 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1207 * uses: bci_smooth_blue_round
1208 * bci_strong_blue_round
1211 unsigned char FPGM(bci_blue_round_range
) [] =
1215 bci_blue_round_range
,
1224 /* select blue rounding function based on flag in CVT */
1226 bci_strong_blue_round
,
1227 bci_smooth_blue_round
,
1228 cvtl_use_strong_functions
,
1247 * bci_decrement_component_counter
1249 * An auxiliary function for composite glyphs.
1251 * CVT: cvtl_is_subglyph
1254 unsigned char FPGM(bci_decrement_component_counter
) [] =
1258 bci_decrement_component_counter
,
1261 /* decrement `cvtl_is_subglyph' counter */
1277 * bci_get_point_extrema
1279 * An auxiliary function for `bci_create_segment'.
1285 * sal: sal_point_min
1289 unsigned char FPGM(bci_get_point_extrema
) [] =
1293 bci_get_point_extrema
,
1302 /* check whether `point' is a new minimum */
1305 RS
, /* s: point point point point_min */
1307 /* if distance is negative, we have a new minimum */
1311 IF
, /* s: point point */
1319 /* check whether `point' is a new maximum */
1322 RS
, /* s: point point point_max */
1324 /* if distance is positive, we have a new maximum */
1344 * Pop a byte with two delta arguments in its nibbles and push the
1345 * expanded arguments separately as two bytes.
1347 * in: 16 * (end - start) + (start - base)
1352 * sal: sal_base (set to `end' at return)
1356 unsigned char FPGM(bci_nibbles
) [] =
1363 PUSHB_1
, /* cf. DIV_POS_BY_2 macro */
1369 MUL
, /* s: in hnibble */
1374 MUL
, /* s: in hnibble (hnibble * 16) */
1377 SUB
, /* s: hnibble lnibble */
1382 ADD
, /* s: hnibble start */
1385 ADD
, /* s: start end */
1391 WS
, /* sal_base = end */
1401 * bci_number_set_is_element
1403 * Pop values from stack until it is empty. If one of them is equal to
1404 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1411 * CVT: cvtl_is_element
1414 unsigned char FPGM(bci_number_set_is_element
) [] =
1418 bci_number_set_is_element
,
1436 JROT
, /* goto start_loop if stack depth != 0 */
1444 * bci_number_set_is_element2
1446 * Pop value ranges from stack until it is empty. If one of them contains
1447 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1450 * in: ppem_range_1_start
1452 * ppem_range_2_start
1456 * CVT: cvtl_is_element
1459 unsigned char FPGM(bci_number_set_is_element2
) [] =
1463 bci_number_set_is_element2
,
1487 JROT
, /* goto start_loop if stack depth != 0 */
1495 * bci_create_segment
1497 * Store start and end point of a segment in the storage area,
1498 * then construct a point in the twilight zone to represent it.
1500 * This function is used by `bci_create_segments'.
1504 * [last (if wrap-around segment)]
1505 * [first (if wrap-around segment)]
1507 * sal: sal_i (start of current segment)
1508 * sal_j (current twilight point)
1512 * sal_num_packed_segments
1517 * uses: bci_get_point_extrema
1520 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1521 * delta values in nibbles (without a wrap-around segment).
1524 unsigned char FPGM(bci_create_segment
) [] =
1533 sal_num_packed_segments
,
1538 sal_num_packed_segments
,
1539 sal_num_packed_segments
,
1544 WS
, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1557 WS
, /* sal[sal_i] = start */
1559 /* initialize inner loop(s) */
1564 WS
, /* sal_point_min = start */
1569 WS
, /* sal_point_max = start */
1573 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1579 CINDEX
, /* s: start end end start */
1580 LT
, /* start > end */
1582 /* we have a wrap-around segment with two more arguments */
1583 /* to give the last and first point of the contour, respectively; */
1584 /* our job is to store a segment `start'-`last', */
1585 /* and to get extrema for the two segments */
1586 /* `start'-`last' and `first'-`end' */
1588 /* s: first last start end */
1597 WS
, /* sal[sal_i + 1] = last */
1600 ROLL
, /* s: first end last start */
1603 SWAP
, /* s: first end start last start */
1604 SUB
, /* s: first end start loop_count */
1607 bci_get_point_extrema
,
1609 /* clean up stack */
1612 SWAP
, /* s: end first */
1617 ROLL
, /* s: (first - 1) (first - 1) end */
1619 SUB
, /* s: (first - 1) loop_count */
1622 bci_get_point_extrema
,
1624 /* clean up stack */
1627 ELSE
, /* s: start end */
1636 WS
, /* sal[sal_i + 1] = end */
1641 SUB
, /* s: start loop_count */
1644 bci_get_point_extrema
,
1646 /* clean up stack */
1650 /* the twilight point representing a segment */
1651 /* is in the middle between the minimum and maximum */
1661 DIV_BY_2
, /* s: middle_pos */
1663 DO_SCALE
, /* middle_pos = middle_pos * scale */
1665 /* write it to temporary CVT location */
1669 SZP0
, /* set zp0 to twilight zone 0 */
1673 /* create twilight point with index `sal_j' */
1686 ADD
, /* twilight_point = twilight_point + 1 */
1695 * bci_create_segments
1697 * This is the top-level entry function.
1699 * It pops point ranges from the stack to define segments, computes
1700 * twilight points to represent segments, and finally calls
1701 * `bci_hint_glyph' to handle the rest.
1703 * The second argument (`data_offset') addresses three CVT arrays in
1707 * the current style's scaling value (stored in `sal_scale')
1709 * data_offset + num_used_styles:
1710 * offset to the current style's vwidth index array (this value gets
1711 * stored in `sal_vwidth_data_offset')
1713 * data_offset + 2*num_used_styles:
1714 * offset to the current style's vwidth size
1716 * This addressing scheme ensures that (a) we only need a single argument,
1717 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1718 * which should be sufficient for a long time.
1720 * in: num_packed_segments
1725 * [contour_last 0 (if wrap-around segment)]
1726 * [contour_first 0 (if wrap-around segment)]
1729 * [contour_last 0 (if wrap-around segment)]
1730 * [contour_first 0 (if wrap-around segment)]
1732 * segment_start_(N-1)
1734 * [contour_last (N-1) (if wrap-around segment)]
1735 * [contour_first (N-1) (if wrap-around segment)]
1736 * ... stuff for bci_hint_glyph ...
1738 * sal: sal_i (start of current segment)
1739 * sal_j (current twilight point)
1740 * sal_num_packed_segments
1741 * sal_base (the base for delta values in nibbles)
1742 * sal_vwidth_data_offset
1745 * CVT: cvtl_is_subglyph
1747 * uses: bci_create_segment
1751 * If `num_packed_segments' is set to p, the first p start/end pairs are
1752 * stored as delta values in nibbles, with the `start' delta in the lower
1753 * nibble (and there are no wrap-around segments). For example, if the
1754 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1755 * stack are 0x21, 0x32, and 0x14.
1759 unsigned char FPGM(bci_create_segments_a
) [] =
1763 bci_create_segments
,
1766 /* all our measurements are taken along the y axis */
1769 /* only do something if we are not a subglyph */
1777 sal_num_packed_segments
,
1784 sal_scale
, /* sal_scale = CVT(data_offset) */
1789 sal_vwidth_data_offset
,
1795 /* %c, number of used styles */
1797 unsigned char FPGM(bci_create_segments_b
) [] =
1801 WS
, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1807 SUB
, /* delta = (2*num_segments - 1) */
1817 WS
, /* sal_base = 0 */
1818 WS
, /* sal_j = 0 (point offset) */
1821 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1842 * bci_create_segments_X
1844 * Top-level routines for calling `bci_create_segments'.
1847 unsigned char FPGM(bci_create_segments_0
) [] =
1851 bci_create_segments_0
,
1856 bci_create_segments
,
1863 unsigned char FPGM(bci_create_segments_1
) [] =
1867 bci_create_segments_1
,
1872 bci_create_segments
,
1879 unsigned char FPGM(bci_create_segments_2
) [] =
1883 bci_create_segments_2
,
1888 bci_create_segments
,
1895 unsigned char FPGM(bci_create_segments_3
) [] =
1899 bci_create_segments_3
,
1904 bci_create_segments
,
1911 unsigned char FPGM(bci_create_segments_4
) [] =
1915 bci_create_segments_4
,
1920 bci_create_segments
,
1927 unsigned char FPGM(bci_create_segments_5
) [] =
1931 bci_create_segments_5
,
1936 bci_create_segments
,
1943 unsigned char FPGM(bci_create_segments_6
) [] =
1947 bci_create_segments_6
,
1952 bci_create_segments
,
1959 unsigned char FPGM(bci_create_segments_7
) [] =
1963 bci_create_segments_7
,
1968 bci_create_segments
,
1975 unsigned char FPGM(bci_create_segments_8
) [] =
1979 bci_create_segments_8
,
1984 bci_create_segments
,
1991 unsigned char FPGM(bci_create_segments_9
) [] =
1995 bci_create_segments_9
,
2000 bci_create_segments
,
2009 * bci_create_segments_composite
2011 * The same as `bci_create_segments'.
2012 * It also decrements the composite component counter.
2014 * sal: sal_num_packed_segments
2015 * sal_segment_offset
2016 * sal_vwidth_data_offset
2018 * CVT: cvtl_is_subglyph
2020 * uses: bci_decrement_component_counter
2021 * bci_create_segment
2026 unsigned char FPGM(bci_create_segments_composite_a
) [] =
2030 bci_create_segments_composite
,
2033 /* all our measurements are taken along the y axis */
2037 bci_decrement_component_counter
,
2040 /* only do something if we are not a subglyph */
2048 sal_num_packed_segments
,
2055 sal_scale
, /* sal_scale = CVT(data_offset) */
2060 sal_vwidth_data_offset
,
2066 /* %c, number of used styles */
2068 unsigned char FPGM(bci_create_segments_composite_b
) [] =
2072 WS
, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2078 SUB
, /* delta = (2*num_segments - 1) */
2088 WS
, /* sal_base = 0 */
2089 WS
, /* sal_j = 0 (point offset) */
2092 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2113 * bci_create_segments_composite_X
2115 * Top-level routines for calling `bci_create_segments_composite'.
2118 unsigned char FPGM(bci_create_segments_composite_0
) [] =
2122 bci_create_segments_composite_0
,
2127 bci_create_segments_composite
,
2134 unsigned char FPGM(bci_create_segments_composite_1
) [] =
2138 bci_create_segments_composite_1
,
2143 bci_create_segments_composite
,
2150 unsigned char FPGM(bci_create_segments_composite_2
) [] =
2154 bci_create_segments_composite_2
,
2159 bci_create_segments_composite
,
2166 unsigned char FPGM(bci_create_segments_composite_3
) [] =
2170 bci_create_segments_composite_3
,
2175 bci_create_segments_composite
,
2182 unsigned char FPGM(bci_create_segments_composite_4
) [] =
2186 bci_create_segments_composite_4
,
2191 bci_create_segments_composite
,
2198 unsigned char FPGM(bci_create_segments_composite_5
) [] =
2202 bci_create_segments_composite_5
,
2207 bci_create_segments_composite
,
2214 unsigned char FPGM(bci_create_segments_composite_6
) [] =
2218 bci_create_segments_composite_6
,
2223 bci_create_segments_composite
,
2230 unsigned char FPGM(bci_create_segments_composite_7
) [] =
2234 bci_create_segments_composite_7
,
2239 bci_create_segments_composite
,
2246 unsigned char FPGM(bci_create_segments_composite_8
) [] =
2250 bci_create_segments_composite_8
,
2255 bci_create_segments_composite
,
2262 unsigned char FPGM(bci_create_segments_composite_9
) [] =
2266 bci_create_segments_composite_9
,
2271 bci_create_segments_composite
,
2282 * An auxiliary function for `bci_align_segment'.
2289 unsigned char FPGM(bci_align_point
) [] =
2297 ALIGNRP
, /* align point with rp0 */
2311 * Align all points in a segment to the twilight point in rp0.
2312 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2316 * sal: sal_segment_offset
2318 * uses: bci_align_point
2321 unsigned char FPGM(bci_align_segment
) [] =
2328 /* we need the values of `sal_segment_offset + 2*segment_index' */
2329 /* and `sal_segment_offset + 2*segment_index + 1' */
2341 RS
, /* s: first last */
2345 CINDEX
, /* s: first last first */
2349 ADD
, /* s: first loop_count */
2354 /* clean up stack */
2363 * bci_align_segments
2365 * Align segments to the twilight point in rp0.
2366 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2375 * uses: bci_align_segment
2378 unsigned char FPGM(bci_align_segments
) [] =
2401 * Scale a contour using two points giving the maximum and minimum
2404 * It expects that no point on the contour is touched.
2412 unsigned char FPGM(bci_scale_contour
) [] =
2423 DO_SCALE
, /* min_pos_new = min_pos * scale */
2428 /* don't scale a single-point contour twice */
2437 DO_SCALE
, /* max_pos_new = max_pos * scale */
2454 * Scale a glyph using a list of points (two points per contour, giving
2455 * the maximum and mininum coordinates).
2457 * It expects that no point in the glyph is touched.
2459 * Note that the point numbers are sorted in ascending order;
2460 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2461 * contour without specifying which one is the minimum and maximum.
2463 * in: num_contours (N)
2472 * CVT: cvtl_is_subglyph
2474 * uses: bci_scale_contour
2477 unsigned char FPGM(bci_scale_glyph
) [] =
2484 /* all our measurements are taken along the y axis */
2487 /* only do something if we are not a subglyph */
2496 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2504 SZP2
, /* set zp2 to normal zone 1 */
2517 * bci_scale_composite_glyph
2519 * The same as `bci_scale_glyph'.
2520 * It also decrements the composite component counter.
2522 * CVT: cvtl_is_subglyph
2524 * uses: bci_decrement_component_counter
2528 unsigned char FPGM(bci_scale_composite_glyph
) [] =
2532 bci_scale_composite_glyph
,
2535 /* all our measurements are taken along the y axis */
2539 bci_decrement_component_counter
,
2542 /* only do something if we are not a subglyph */
2551 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2559 SZP2
, /* set zp2 to normal zone 1 */
2574 * Shift a contour by a given amount.
2576 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2577 * point to the normal zone 1.
2584 unsigned char FPGM(bci_shift_contour
) [] =
2592 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2604 * bci_shift_subglyph
2606 * Shift a subglyph. To be more specific, it corrects the already applied
2607 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2610 * If this function is called, a point `x' in the subglyph has been scaled
2611 * already (during the hinting of the subglyph itself), and `offset' has
2612 * been applied also:
2614 * x -> x * scale + offset (1)
2616 * However, the offset should be applied first, then the scaling:
2618 * x -> (x + offset) * scale (2)
2620 * Our job is now to transform (1) to (2); a simple calculation shows that
2621 * we have to shift all points of the subglyph by
2623 * offset * scale - offset = offset * (scale - 1)
2625 * Note that `sal_scale' is equal to the above `scale - 1'.
2627 * in: offset (in FUnits)
2631 * CVT: cvtl_funits_to_pixels
2639 unsigned char FPGM(bci_shift_subglyph
) [] =
2646 /* all our measurements are taken along the y axis */
2650 cvtl_funits_to_pixels
,
2651 RCVT
, /* scaling factor FUnits -> pixels */
2655 /* the autohinter always rounds offsets */
2658 CALL
, /* offset = round(offset) */
2664 DIV_BY_1024
, /* delta = offset * (scale - 1) */
2666 /* and round again */
2669 CALL
, /* offset = round(offset) */
2673 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2675 /* we create twilight point 0 as a reference point, */
2676 /* setting the original position to zero (using `cvtl_temp') */
2684 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
2686 SWAP
, /* s: first_contour num_contours 0 delta */
2687 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
2692 SZP2
, /* set zp2 to normal zone 1 */
2701 * bci_ip_outer_align_point
2703 * Auxiliary function for `bci_action_ip_before' and
2704 * `bci_action_ip_after'.
2706 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2707 * zone, and both zp1 and zp2 set to normal zone.
2711 * sal: sal_i (edge_orig_pos)
2715 unsigned char FPGM(bci_ip_outer_align_point
) [] =
2719 bci_ip_outer_align_point
,
2723 ALIGNRP
, /* align `point' with `edge' */
2726 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2731 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2740 * bci_ip_on_align_points
2742 * Auxiliary function for `bci_action_ip_on'.
2744 * in: edge (in twilight zone)
2752 unsigned char FPGM(bci_ip_on_align_points
) [] =
2756 bci_ip_on_align_points
,
2759 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2770 * bci_ip_between_align_point
2772 * Auxiliary function for `bci_ip_between_align_points'.
2774 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2775 * zone, and both zp1 and zp2 set to normal zone.
2779 * sal: sal_i (edge_orig_pos)
2780 * sal_j (stretch_factor)
2784 unsigned char FPGM(bci_ip_between_align_point
) [] =
2788 bci_ip_between_align_point
,
2792 ALIGNRP
, /* align `point' with `edge' */
2795 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2800 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2804 MUL
, /* s: point delta */
2813 * bci_ip_between_align_points
2815 * Auxiliary function for `bci_action_ip_between'.
2817 * in: after_edge (in twilight zone)
2818 * before_edge (in twilight zone)
2825 * sal: sal_i (before_orig_pos)
2826 * sal_j (stretch_factor)
2828 * uses: bci_ip_between_align_point
2831 unsigned char FPGM(bci_ip_between_align_points
) [] =
2835 bci_ip_between_align_points
,
2841 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2843 DUP
, /* s: ... before after before before */
2844 MDAP_noround
, /* set rp0 and rp1 to `before' */
2846 GC_orig
, /* s: ... before after before before_orig_pos */
2850 WS
, /* sal_i = before_orig_pos */
2853 CINDEX
, /* s: ... before after before after */
2854 MD_cur
, /* a = after_pos - before_pos */
2857 MD_orig_ZP2_0
, /* b = after_orig_pos - before_orig_pos */
2863 POP
, /* avoid division by zero */
2869 WS
, /* sal_j = stretch_factor */
2872 bci_ip_between_align_point
,
2875 SZP2
, /* set zp2 to normal zone 1 */
2876 SZP1
, /* set zp1 to normal zone 1 */
2885 * bci_action_ip_before
2887 * Handle `ip_before' data to align points located before the first edge.
2889 * in: first_edge (in twilight zone)
2896 * sal: sal_i (first_edge_orig_pos)
2898 * uses: bci_ip_outer_align_point
2901 unsigned char FPGM(bci_action_ip_before
) [] =
2905 bci_action_ip_before
,
2910 SZP2
, /* set zp2 to twilight zone 0 */
2917 WS
, /* sal_i = first_edge_orig_pos */
2923 SZP2
, /* set zp2 to normal zone 1 */
2924 SZP1
, /* set zp1 to normal zone 1 */
2925 SZP0
, /* set zp0 to twilight zone 0 */
2927 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
2930 bci_ip_outer_align_point
,
2939 * bci_action_ip_after
2941 * Handle `ip_after' data to align points located after the last edge.
2943 * in: last_edge (in twilight zone)
2950 * sal: sal_i (last_edge_orig_pos)
2952 * uses: bci_ip_outer_align_point
2955 unsigned char FPGM(bci_action_ip_after
) [] =
2959 bci_action_ip_after
,
2964 SZP2
, /* set zp2 to twilight zone 0 */
2971 WS
, /* sal_i = last_edge_orig_pos */
2977 SZP2
, /* set zp2 to normal zone 1 */
2978 SZP1
, /* set zp1 to normal zone 1 */
2979 SZP0
, /* set zp0 to twilight zone 0 */
2981 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
2984 bci_ip_outer_align_point
,
2995 * Handle `ip_on' data to align points located on an edge coordinate (but
2996 * not part of an edge).
2998 * in: loop_counter (M)
2999 * edge_1 (in twilight zone)
3000 * loop_counter (N_1)
3005 * edge_2 (in twilight zone)
3006 * loop_counter (N_2)
3012 * edge_M (in twilight zone)
3013 * loop_counter (N_M)
3019 * uses: bci_ip_on_align_points
3022 unsigned char FPGM(bci_action_ip_on
) [] =
3032 SZP1
, /* set zp1 to normal zone 1 */
3033 SZP0
, /* set zp0 to twilight zone 0 */
3036 bci_ip_on_align_points
,
3045 * bci_action_ip_between
3047 * Handle `ip_between' data to align points located between two edges.
3049 * in: loop_counter (M)
3050 * before_edge_1 (in twilight zone)
3051 * after_edge_1 (in twilight zone)
3052 * loop_counter (N_1)
3057 * before_edge_2 (in twilight zone)
3058 * after_edge_2 (in twilight zone)
3059 * loop_counter (N_2)
3065 * before_edge_M (in twilight zone)
3066 * after_edge_M (in twilight zone)
3067 * loop_counter (N_M)
3073 * uses: bci_ip_between_align_points
3076 unsigned char FPGM(bci_action_ip_between
) [] =
3080 bci_action_ip_between
,
3084 bci_ip_between_align_points
,
3095 * Common code for bci_action_adjust routines.
3097 * uses: func[sal_stem_width_function]
3100 unsigned char FPGM(bci_adjust_common
) [] =
3109 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3113 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
3116 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3117 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
3120 sal_stem_width_function
,
3123 NEG
, /* s: [...] edge2 edge -cur_len */
3125 ROLL
, /* s: [...] edge -cur_len edge2 */
3126 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3129 DUP
, /* s: [...] -cur_len edge edge edge */
3130 ALIGNRP
, /* align `edge' with `edge2' */
3132 SHPIX
, /* shift `edge' by -cur_len */
3142 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3143 * edge of the stem has already been moved, then moving it again if
3144 * necessary to stay bound.
3146 * in: edge2_is_serif
3148 * edge_point (in twilight zone)
3149 * edge2_point (in twilight zone)
3150 * edge[-1] (in twilight zone)
3151 * ... stuff for bci_align_segments (edge) ...
3153 * uses: bci_adjust_common
3154 * bci_align_segments
3157 unsigned char FPGM(bci_adjust_bound
) [] =
3168 SWAP
, /* s: edge edge[-1] */
3170 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3175 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3176 GT
, /* edge_pos < edge[-1]_pos */
3179 ALIGNRP
, /* align `edge' to `edge[-1]' */
3182 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3187 SZP1
, /* set zp1 to normal zone 1 */
3196 * bci_action_adjust_bound
3197 * bci_action_adjust_bound_serif
3198 * bci_action_adjust_bound_round
3199 * bci_action_adjust_bound_round_serif
3201 * Higher-level routines for calling `bci_adjust_bound'.
3204 unsigned char FPGM(bci_action_adjust_bound
) [] =
3208 bci_action_adjust_bound
,
3221 unsigned char FPGM(bci_action_adjust_bound_serif
) [] =
3225 bci_action_adjust_bound_serif
,
3238 unsigned char FPGM(bci_action_adjust_bound_round
) [] =
3242 bci_action_adjust_bound_round
,
3255 unsigned char FPGM(bci_action_adjust_bound_round_serif
) [] =
3259 bci_action_adjust_bound_round_serif
,
3276 * Handle the ADJUST action to align an edge of a stem if the other edge
3277 * of the stem has already been moved.
3279 * in: edge2_is_serif
3281 * edge_point (in twilight zone)
3282 * edge2_point (in twilight zone)
3283 * ... stuff for bci_align_segments (edge) ...
3285 * uses: bci_adjust_common
3286 * bci_align_segments
3289 unsigned char FPGM(bci_adjust
) [] =
3300 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3305 SZP1
, /* set zp1 to normal zone 1 */
3315 * bci_action_adjust_serif
3316 * bci_action_adjust_round
3317 * bci_action_adjust_round_serif
3319 * Higher-level routines for calling `bci_adjust'.
3322 unsigned char FPGM(bci_action_adjust
) [] =
3339 unsigned char FPGM(bci_action_adjust_serif
) [] =
3343 bci_action_adjust_serif
,
3356 unsigned char FPGM(bci_action_adjust_round
) [] =
3360 bci_action_adjust_round
,
3373 unsigned char FPGM(bci_action_adjust_round_serif
) [] =
3377 bci_action_adjust_round_serif
,
3394 * Common code for bci_action_stem routines.
3401 * uses: func[sal_stem_width_function]
3406 #define sal_u_off sal_temp1
3408 #define sal_d_off sal_temp2
3410 #define sal_org_len sal_temp3
3412 #define sal_edge2 sal_temp3
3414 unsigned char FPGM(bci_stem_common
) [] =
3423 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3431 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3432 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3434 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
3442 sal_stem_width_function
,
3444 CALL
, /* s: [...] edge2 edge cur_len */
3449 LT
, /* cur_len < 96 */
3454 LTEQ
, /* cur_len <= 64 */
3472 SWAP
, /* s: [...] edge2 cur_len edge */
3477 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
3483 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3488 ADD
, /* s: [...] edge2 cur_len edge org_center */
3493 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3498 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3505 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3512 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3514 LT
, /* delta1 < delta2 */
3519 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3525 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3526 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
3532 SUB
, /* arg = cur_pos1 - cur_len/2 */
3534 SWAP
, /* s: [...] edge2 cur_len arg edge */
3540 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3543 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3546 SWAP
, /* s: [...] edge2 cur_len edge */
3550 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
3558 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3565 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
3571 CALL
, /* cur_pos1 = ROUND(org_pos) */
3583 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3592 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3599 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3605 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3606 LT
, /* delta1 < delta2 */
3608 POP
, /* arg = cur_pos1 */
3612 POP
, /* arg = cur_pos2 */
3613 EIF
, /* s: [...] edge2 cur_len edge arg */
3620 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3623 SHPIX
, /* edge = arg */
3624 EIF
, /* s: [...] edge2 cur_len edge */
3634 * Handle the STEM action to align two edges of a stem, then moving one
3635 * edge again if necessary to stay bound.
3637 * The code after computing `cur_len' to shift `edge' and `edge2'
3638 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3641 * if cur_len < = 64:
3648 * org_pos = anchor + (edge_orig - anchor_orig);
3649 * org_center = org_pos + org_len / 2;
3651 * cur_pos1 = ROUND(org_center)
3652 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3653 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3654 * if (delta1 < delta2):
3655 * cur_pos1 = cur_pos1 - u_off
3657 * cur_pos1 = cur_pos1 + d_off
3659 * edge = cur_pos1 - cur_len / 2
3662 * org_pos = anchor + (edge_orig - anchor_orig)
3663 * org_center = org_pos + org_len / 2;
3665 * cur_pos1 = ROUND(org_pos)
3666 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3667 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3668 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3670 * if (delta1 < delta2):
3675 * edge2 = edge + cur_len
3677 * in: edge2_is_serif
3679 * edge_point (in twilight zone)
3680 * edge2_point (in twilight zone)
3681 * edge[-1] (in twilight zone)
3682 * ... stuff for bci_align_segments (edge) ...
3683 * ... stuff for bci_align_segments (edge2)...
3690 * uses: bci_stem_common
3691 * bci_align_segments
3694 unsigned char FPGM(bci_stem_bound
) [] =
3705 ROLL
, /* s: edge[-1] cur_len edge edge2 */
3708 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3712 WS
, /* s: edge[-1] cur_len edge edge2 */
3714 SHPIX
, /* edge2 = edge + cur_len */
3716 SWAP
, /* s: edge edge[-1] */
3718 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3723 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3724 GT
, /* edge_pos < edge[-1]_pos */
3727 ALIGNRP
, /* align `edge' to `edge[-1]' */
3730 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3735 SZP1
, /* set zp1 to normal zone 1 */
3741 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3753 * bci_action_stem_bound
3754 * bci_action_stem_bound_serif
3755 * bci_action_stem_bound_round
3756 * bci_action_stem_bound_round_serif
3758 * Higher-level routines for calling `bci_stem_bound'.
3761 unsigned char FPGM(bci_action_stem_bound
) [] =
3765 bci_action_stem_bound
,
3778 unsigned char FPGM(bci_action_stem_bound_serif
) [] =
3782 bci_action_stem_bound_serif
,
3795 unsigned char FPGM(bci_action_stem_bound_round
) [] =
3799 bci_action_stem_bound_round
,
3812 unsigned char FPGM(bci_action_stem_bound_round_serif
) [] =
3816 bci_action_stem_bound_round_serif
,
3833 * Handle the STEM action to align two edges of a stem.
3835 * See `bci_stem_bound' for more details.
3837 * in: edge2_is_serif
3839 * edge_point (in twilight zone)
3840 * edge2_point (in twilight zone)
3841 * ... stuff for bci_align_segments (edge) ...
3842 * ... stuff for bci_align_segments (edge2)...
3849 * uses: bci_stem_common
3850 * bci_align_segments
3853 unsigned char FPGM(bci_stem
) [] =
3865 SWAP
, /* s: cur_len edge2 */
3868 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3872 WS
, /* s: cur_len edge2 */
3874 SHPIX
, /* edge2 = edge + cur_len */
3879 SZP1
, /* set zp1 to normal zone 1 */
3885 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3897 * bci_action_stem_serif
3898 * bci_action_stem_round
3899 * bci_action_stem_round_serif
3901 * Higher-level routines for calling `bci_stem'.
3904 unsigned char FPGM(bci_action_stem
) [] =
3921 unsigned char FPGM(bci_action_stem_serif
) [] =
3925 bci_action_stem_serif
,
3938 unsigned char FPGM(bci_action_stem_round
) [] =
3942 bci_action_stem_round
,
3955 unsigned char FPGM(bci_action_stem_round_serif
) [] =
3959 bci_action_stem_round_serif
,
3976 * Handle the LINK action to link an edge to another one.
3980 * base_point (in twilight zone)
3981 * stem_point (in twilight zone)
3982 * ... stuff for bci_align_segments (base) ...
3984 * uses: func[sal_stem_width_function]
3985 * bci_align_segments
3988 unsigned char FPGM(bci_link
) [] =
3997 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4005 DUP
, /* s: stem is_round is_serif stem base base */
4006 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4008 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
4011 sal_stem_width_function
,
4013 CALL
, /* s: stem new_dist */
4017 ALIGNRP
, /* align `stem_point' with `base_point' */
4019 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
4021 SHPIX
, /* stem_point = base_point + new_dist */
4026 SZP1
, /* set zp1 to normal zone 1 */
4036 * bci_action_link_serif
4037 * bci_action_link_round
4038 * bci_action_link_round_serif
4040 * Higher-level routines for calling `bci_link'.
4043 unsigned char FPGM(bci_action_link
) [] =
4060 unsigned char FPGM(bci_action_link_serif
) [] =
4064 bci_action_link_serif
,
4077 unsigned char FPGM(bci_action_link_round
) [] =
4081 bci_action_link_round
,
4094 unsigned char FPGM(bci_action_link_round_serif
) [] =
4098 bci_action_link_round_serif
,
4115 * Handle the ANCHOR action to align two edges
4116 * and to set the edge anchor.
4118 * The code after computing `cur_len' to shift `edge' and `edge2'
4119 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4122 * if cur_len < = 64:
4129 * org_center = edge_orig + org_len / 2
4130 * cur_pos1 = ROUND(org_center)
4132 * error1 = ABS(org_center - (cur_pos1 - u_off))
4133 * error2 = ABS(org_center - (cur_pos1 + d_off))
4134 * if (error1 < error2):
4135 * cur_pos1 = cur_pos1 - u_off
4137 * cur_pos1 = cur_pos1 + d_off
4139 * edge = cur_pos1 - cur_len / 2
4140 * edge2 = edge + cur_len
4143 * edge = ROUND(edge_orig)
4145 * in: edge2_is_serif
4147 * edge_point (in twilight zone)
4148 * edge2_point (in twilight zone)
4149 * ... stuff for bci_align_segments (edge) ...
4156 * uses: func[sal_stem_width_function]
4158 * bci_align_segments
4162 #define sal_u_off sal_temp1
4164 #define sal_d_off sal_temp2
4166 #define sal_org_len sal_temp3
4168 unsigned char FPGM(bci_anchor
) [] =
4175 /* store anchor point number in `sal_anchor' */
4180 WS
, /* sal_anchor = edge_point */
4184 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4192 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
4193 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4195 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
4203 sal_stem_width_function
,
4205 CALL
, /* s: edge2 edge cur_len */
4210 LT
, /* cur_len < 96 */
4215 LTEQ
, /* cur_len <= 64 */
4233 SWAP
, /* s: edge2 cur_len edge */
4234 DUP
, /* s: edge2 cur_len edge edge */
4241 ADD
, /* s: edge2 cur_len edge org_center */
4246 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
4251 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4258 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4265 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4267 LT
, /* error1 < error2 */
4272 SUB
, /* cur_pos1 = cur_pos1 - u_off */
4278 ADD
, /* cur_pos1 = cur_pos1 + d_off */
4279 EIF
, /* s: edge2 cur_len edge cur_pos1 */
4285 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4289 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4292 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
4294 SWAP
, /* s: cur_len edge2 */
4296 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
4298 SHPIX
, /* edge2 = edge1 + cur_len */
4301 POP
, /* s: edge2 edge */
4309 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4312 SHPIX
, /* edge = round(edge_orig) */
4314 /* clean up stack */
4321 SZP1
, /* set zp1 to normal zone 1 */
4331 * bci_action_anchor_serif
4332 * bci_action_anchor_round
4333 * bci_action_anchor_round_serif
4335 * Higher-level routines for calling `bci_anchor'.
4338 unsigned char FPGM(bci_action_anchor
) [] =
4355 unsigned char FPGM(bci_action_anchor_serif
) [] =
4359 bci_action_anchor_serif
,
4372 unsigned char FPGM(bci_action_anchor_round
) [] =
4376 bci_action_anchor_round
,
4389 unsigned char FPGM(bci_action_anchor_round_serif
) [] =
4393 bci_action_anchor_round_serif
,
4408 * bci_action_blue_anchor
4410 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4411 * and to set the edge anchor.
4413 * in: anchor_point (in twilight zone)
4415 * edge_point (in twilight zone)
4416 * ... stuff for bci_align_segments (edge) ...
4420 * uses: bci_action_blue
4423 unsigned char FPGM(bci_action_blue_anchor
) [] =
4427 bci_action_blue_anchor
,
4430 /* store anchor point number in `sal_anchor' */
4448 * Handle the BLUE action to align an edge with a blue zone.
4451 * edge_point (in twilight zone)
4452 * ... stuff for bci_align_segments (edge) ...
4454 * uses: bci_align_segments
4457 unsigned char FPGM(bci_action_blue
) [] =
4466 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4468 /* move `edge_point' to `blue_cvt_idx' position; */
4469 /* note that we can't use MIAP since this would modify */
4470 /* the twilight point's original coordinates also */
4474 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4476 GC_cur
, /* s: new_pos edge edge_pos */
4479 SUB
, /* s: edge (new_pos - edge_pos) */
4485 SZP1
, /* set zp1 to normal zone 1 */
4496 * Common code for bci_action_serif routines.
4499 unsigned char FPGM(bci_serif_common
) [] =
4508 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4515 MINDEX
, /* s: [...] serif serif serif serif base */
4517 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
4520 ALIGNRP
, /* align `serif_point' with `base_point' */
4521 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
4531 * Move an edge if necessary to stay within a lower bound.
4536 * uses: bci_align_segments
4539 unsigned char FPGM(bci_lower_bound
) [] =
4546 SWAP
, /* s: edge bound */
4548 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4553 GC_cur
, /* s: edge bound_pos edge_pos */
4554 GT
, /* edge_pos < bound_pos */
4557 ALIGNRP
, /* align `edge' to `bound' */
4560 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4565 SZP1
, /* set zp1 to normal zone 1 */
4576 * Move an edge if necessary to stay within an upper bound.
4581 * uses: bci_align_segments
4584 unsigned char FPGM(bci_upper_bound
) [] =
4591 SWAP
, /* s: edge bound */
4593 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4598 GC_cur
, /* s: edge bound_pos edge_pos */
4599 LT
, /* edge_pos > bound_pos */
4602 ALIGNRP
, /* align `edge' to `bound' */
4605 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4610 SZP1
, /* set zp1 to normal zone 1 */
4619 * bci_upper_lower_bound
4621 * Move an edge if necessary to stay within a lower and lower bound.
4627 * uses: bci_align_segments
4630 unsigned char FPGM(bci_upper_lower_bound
) [] =
4634 bci_upper_lower_bound
,
4637 SWAP
, /* s: upper serif lower */
4639 MDAP_noround
, /* set rp0 and rp1 to `lower' */
4644 GC_cur
, /* s: upper serif lower_pos serif_pos */
4645 GT
, /* serif_pos < lower_pos */
4648 ALIGNRP
, /* align `serif' to `lower' */
4651 SWAP
, /* s: serif upper */
4653 MDAP_noround
, /* set rp0 and rp1 to `upper' */
4658 GC_cur
, /* s: serif upper_pos serif_pos */
4659 LT
, /* serif_pos > upper_pos */
4662 ALIGNRP
, /* align `serif' to `upper' */
4665 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4670 SZP1
, /* set zp1 to normal zone 1 */
4681 * Handle the SERIF action to align a serif with its base.
4683 * in: serif_point (in twilight zone)
4684 * base_point (in twilight zone)
4685 * ... stuff for bci_align_segments (serif) ...
4687 * uses: bci_serif_common
4688 * bci_align_segments
4691 unsigned char FPGM(bci_action_serif
) [] =
4702 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4707 SZP1
, /* set zp1 to normal zone 1 */
4716 * bci_action_serif_lower_bound
4718 * Handle the SERIF action to align a serif with its base, then moving it
4719 * again if necessary to stay within a lower bound.
4721 * in: serif_point (in twilight zone)
4722 * base_point (in twilight zone)
4723 * edge[-1] (in twilight zone)
4724 * ... stuff for bci_align_segments (serif) ...
4726 * uses: bci_serif_common
4730 unsigned char FPGM(bci_action_serif_lower_bound
) [] =
4734 bci_action_serif_lower_bound
,
4751 * bci_action_serif_upper_bound
4753 * Handle the SERIF action to align a serif with its base, then moving it
4754 * again if necessary to stay within an upper bound.
4756 * in: serif_point (in twilight zone)
4757 * base_point (in twilight zone)
4758 * edge[1] (in twilight zone)
4759 * ... stuff for bci_align_segments (serif) ...
4761 * uses: bci_serif_common
4765 unsigned char FPGM(bci_action_serif_upper_bound
) [] =
4769 bci_action_serif_upper_bound
,
4786 * bci_action_serif_upper_lower_bound
4788 * Handle the SERIF action to align a serif with its base, then moving it
4789 * again if necessary to stay within a lower and upper bound.
4791 * in: serif_point (in twilight zone)
4792 * base_point (in twilight zone)
4793 * edge[-1] (in twilight zone)
4794 * edge[1] (in twilight zone)
4795 * ... stuff for bci_align_segments (serif) ...
4797 * uses: bci_serif_common
4798 * bci_upper_lower_bound
4801 unsigned char FPGM(bci_action_serif_upper_lower_bound
) [] =
4805 bci_action_serif_upper_lower_bound
,
4810 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4817 bci_upper_lower_bound
,
4826 * bci_serif_anchor_common
4828 * Common code for bci_action_serif_anchor routines.
4835 unsigned char FPGM(bci_serif_anchor_common
) [] =
4839 bci_serif_anchor_common
,
4844 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4850 WS
, /* sal_anchor = edge_point */
4860 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4863 SHPIX
, /* edge = round(edge_orig) */
4871 * bci_action_serif_anchor
4873 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4876 * in: edge_point (in twilight zone)
4877 * ... stuff for bci_align_segments (edge) ...
4879 * uses: bci_serif_anchor_common
4880 * bci_align_segments
4883 unsigned char FPGM(bci_action_serif_anchor
) [] =
4887 bci_action_serif_anchor
,
4891 bci_serif_anchor_common
,
4894 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4899 SZP1
, /* set zp1 to normal zone 1 */
4908 * bci_action_serif_anchor_lower_bound
4910 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4911 * anchor, then moving it again if necessary to stay within a lower
4914 * in: edge_point (in twilight zone)
4915 * edge[-1] (in twilight zone)
4916 * ... stuff for bci_align_segments (edge) ...
4918 * uses: bci_serif_anchor_common
4922 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
4926 bci_action_serif_anchor_lower_bound
,
4930 bci_serif_anchor_common
,
4943 * bci_action_serif_anchor_upper_bound
4945 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4946 * anchor, then moving it again if necessary to stay within an upper
4949 * in: edge_point (in twilight zone)
4950 * edge[1] (in twilight zone)
4951 * ... stuff for bci_align_segments (edge) ...
4953 * uses: bci_serif_anchor_common
4957 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
4961 bci_action_serif_anchor_upper_bound
,
4965 bci_serif_anchor_common
,
4978 * bci_action_serif_anchor_upper_lower_bound
4980 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4981 * anchor, then moving it again if necessary to stay within a lower and
4984 * in: edge_point (in twilight zone)
4985 * edge[-1] (in twilight zone)
4986 * edge[1] (in twilight zone)
4987 * ... stuff for bci_align_segments (edge) ...
4989 * uses: bci_serif_anchor_common
4990 * bci_upper_lower_bound
4993 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound
) [] =
4997 bci_action_serif_anchor_upper_lower_bound
,
5001 bci_serif_anchor_common
,
5005 bci_upper_lower_bound
,
5014 * bci_serif_link1_common
5016 * Common code for bci_action_serif_link1 routines.
5019 unsigned char FPGM(bci_serif_link1_common
) [] =
5023 bci_serif_link1_common
,
5028 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
5032 CINDEX
, /* s: [...] after edge before after */
5035 CINDEX
, /* s: [...] after edge before after before */
5039 EQ
, /* after_orig_pos == before_orig_pos */
5040 IF
, /* s: [...] after edge before */
5041 MDAP_noround
, /* set rp0 and rp1 to `before' */
5043 ALIGNRP
, /* align `edge' with `before' */
5048 /* we have to execute `a*b/c', with b/c very near to 1: */
5049 /* to avoid overflow while retaining precision, */
5050 /* we transform this to `a + a * (b-c)/c' */
5054 CINDEX
, /* s: [...] after edge before edge */
5057 CINDEX
, /* s: [...] after edge before edge before */
5058 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
5063 CINDEX
, /* s: [...] after edge before a a after */
5066 CINDEX
, /* s: [...] after edge before a a after before */
5067 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
5071 CINDEX
, /* s: [...] after edge before a a c after */
5074 CINDEX
, /* s: [...] after edge before a a c after before */
5075 MD_cur
, /* b = after_pos - before_pos */
5079 CINDEX
, /* s: [...] after edge before a a c b c */
5088 MUL
, /* (b-c) in 16.16 format */
5093 DIV
, /* s: [...] after edge before a a (b-c)/c */
5095 POP
, /* avoid division by zero */
5098 MUL
, /* a * (b-c)/c * 2^10 */
5099 DIV_BY_1024
, /* a * (b-c)/c */
5103 MDAP_noround
, /* set rp0 and rp1 to `before' */
5104 SWAP
, /* s: [...] after a*b/c edge */
5107 ALIGNRP
, /* align `edge' with `before' */
5109 SHPIX
, /* shift `edge' by `a*b/c' */
5111 SWAP
, /* s: [...] edge after */
5121 * bci_action_serif_link1
5123 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5126 * in: before_point (in twilight zone)
5127 * edge_point (in twilight zone)
5128 * after_point (in twilight zone)
5129 * ... stuff for bci_align_segments (edge) ...
5131 * uses: bci_serif_link1_common
5132 * bci_align_segments
5135 unsigned char FPGM(bci_action_serif_link1
) [] =
5139 bci_action_serif_link1
,
5143 bci_serif_link1_common
,
5146 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5151 SZP1
, /* set zp1 to normal zone 1 */
5160 * bci_action_serif_link1_lower_bound
5162 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5163 * before and after. Additionally, move the serif again if necessary to
5164 * stay within a lower bound.
5166 * in: before_point (in twilight zone)
5167 * edge_point (in twilight zone)
5168 * after_point (in twilight zone)
5169 * edge[-1] (in twilight zone)
5170 * ... stuff for bci_align_segments (edge) ...
5172 * uses: bci_serif_link1_common
5176 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
5180 bci_action_serif_link1_lower_bound
,
5184 bci_serif_link1_common
,
5197 * bci_action_serif_link1_upper_bound
5199 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5200 * before and after. Additionally, move the serif again if necessary to
5201 * stay within an upper bound.
5203 * in: before_point (in twilight zone)
5204 * edge_point (in twilight zone)
5205 * after_point (in twilight zone)
5206 * edge[1] (in twilight zone)
5207 * ... stuff for bci_align_segments (edge) ...
5209 * uses: bci_serif_link1_common
5213 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
5217 bci_action_serif_link1_upper_bound
,
5221 bci_serif_link1_common
,
5234 * bci_action_serif_link1_upper_lower_bound
5236 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5237 * before and after. Additionally, move the serif again if necessary to
5238 * stay within a lower and upper bound.
5240 * in: before_point (in twilight zone)
5241 * edge_point (in twilight zone)
5242 * after_point (in twilight zone)
5243 * edge[-1] (in twilight zone)
5244 * edge[1] (in twilight zone)
5245 * ... stuff for bci_align_segments (edge) ...
5247 * uses: bci_serif_link1_common
5248 * bci_upper_lower_bound
5251 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound
) [] =
5255 bci_action_serif_link1_upper_lower_bound
,
5259 bci_serif_link1_common
,
5263 bci_upper_lower_bound
,
5272 * bci_serif_link2_common
5274 * Common code for bci_action_serif_link2 routines.
5279 unsigned char FPGM(bci_serif_link2_common
) [] =
5283 bci_serif_link2_common
,
5288 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
5290 DUP
, /* s: [...] edge edge */
5294 DUP
, /* s: [...] edge edge anchor anchor */
5295 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
5304 DIV_BY_2
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5309 ALIGNRP
, /* align `edge' with `sal_anchor' */
5311 SHPIX
, /* shift `edge' by `delta' */
5319 * bci_action_serif_link2
5321 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5323 * in: edge_point (in twilight zone)
5324 * ... stuff for bci_align_segments (edge) ...
5326 * uses: bci_serif_link2_common
5327 * bci_align_segments
5330 unsigned char FPGM(bci_action_serif_link2
) [] =
5334 bci_action_serif_link2
,
5338 bci_serif_link2_common
,
5341 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5346 SZP1
, /* set zp1 to normal zone 1 */
5355 * bci_action_serif_link2_lower_bound
5357 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5358 * Additionally, move the serif again if necessary to stay within a lower
5361 * in: edge_point (in twilight zone)
5362 * edge[-1] (in twilight zone)
5363 * ... stuff for bci_align_segments (edge) ...
5365 * uses: bci_serif_link2_common
5369 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
5373 bci_action_serif_link2_lower_bound
,
5377 bci_serif_link2_common
,
5390 * bci_action_serif_link2_upper_bound
5392 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5393 * Additionally, move the serif again if necessary to stay within an upper
5396 * in: edge_point (in twilight zone)
5397 * edge[1] (in twilight zone)
5398 * ... stuff for bci_align_segments (edge) ...
5400 * uses: bci_serif_link2_common
5404 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
5408 bci_action_serif_link2_upper_bound
,
5412 bci_serif_link2_common
,
5425 * bci_action_serif_link2_upper_lower_bound
5427 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5428 * Additionally, move the serif again if necessary to stay within a lower
5431 * in: edge_point (in twilight zone)
5432 * edge[-1] (in twilight zone)
5433 * edge[1] (in twilight zone)
5434 * ... stuff for bci_align_segments (edge) ...
5436 * uses: bci_serif_link2_common
5437 * bci_upper_lower_bound
5440 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound
) [] =
5444 bci_action_serif_link2_upper_lower_bound
,
5448 bci_serif_link2_common
,
5452 bci_upper_lower_bound
,
5463 * This is the top-level glyph hinting function which parses the arguments
5464 * on the stack and calls subroutines.
5466 * in: action_0_func_idx
5472 * CVT: cvtl_is_subglyph
5473 * cvtl_use_strong_functions
5475 * sal: sal_stem_width_function
5477 * uses: bci_action_ip_before
5478 * bci_action_ip_after
5480 * bci_action_ip_between
5482 * bci_action_adjust_bound
5483 * bci_action_adjust_bound_serif
5484 * bci_action_adjust_bound_round
5485 * bci_action_adjust_bound_round_serif
5487 * bci_action_stem_bound
5488 * bci_action_stem_bound_serif
5489 * bci_action_stem_bound_round
5490 * bci_action_stem_bound_round_serif
5493 * bci_action_link_serif
5494 * bci_action_link_round
5495 * bci_action_link_round_serif
5498 * bci_action_anchor_serif
5499 * bci_action_anchor_round
5500 * bci_action_anchor_round_serif
5502 * bci_action_blue_anchor
5505 * bci_action_adjust_serif
5506 * bci_action_adjust_round
5507 * bci_action_adjust_round_serif
5510 * bci_action_stem_serif
5511 * bci_action_stem_round
5512 * bci_action_stem_round_serif
5517 * bci_action_serif_lower_bound
5518 * bci_action_serif_upper_bound
5519 * bci_action_serif_upper_lower_bound
5521 * bci_action_serif_anchor
5522 * bci_action_serif_anchor_lower_bound
5523 * bci_action_serif_anchor_upper_bound
5524 * bci_action_serif_anchor_upper_lower_bound
5526 * bci_action_serif_link1
5527 * bci_action_serif_link1_lower_bound
5528 * bci_action_serif_link1_upper_bound
5529 * bci_action_serif_link1_upper_lower_bound
5531 * bci_action_serif_link2
5532 * bci_action_serif_link2_lower_bound
5533 * bci_action_serif_link2_upper_bound
5534 * bci_action_serif_link2_upper_lower_bound
5537 unsigned char FPGM(bci_hint_glyph
) [] =
5544 /* set up stem width function based on flag in CVT */
5546 sal_stem_width_function
,
5547 bci_strong_stem_width
,
5548 bci_smooth_stem_width
,
5549 cvtl_use_strong_functions
,
5562 /* loop until all data on stack is used */
5571 JROT
, /* goto start_loop */
5575 SZP2
, /* set zp2 to normal zone 1 */
5583 #define COPY_FPGM(func_name) \
5586 memcpy(bufp, fpgm_ ## func_name, \
5587 sizeof (fpgm_ ## func_name)); \
5588 bufp += sizeof (fpgm_ ## func_name); \
5592 TA_table_build_fpgm(FT_Byte
** fpgm
,
5597 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5598 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5606 /* for compatibility with dumb bytecode interpreters or analyzers, */
5607 /* FDEFs are stored in ascending index order, without holes -- */
5608 /* note that some FDEFs are not always needed */
5609 /* (depending on options of `TTFautohint'), */
5610 /* but implementing dynamic FDEF indices would be a lot of work */
5612 buf_len
= sizeof (FPGM(bci_align_top_a
))
5613 + (font
->increase_x_height
5614 ? (sizeof (FPGM(bci_align_top_b1a
))
5616 + sizeof (FPGM(bci_align_top_b1b
)))
5617 : sizeof (FPGM(bci_align_top_b2
)))
5618 + sizeof (FPGM(bci_align_top_c
))
5619 + sizeof (FPGM(bci_round
))
5620 + sizeof (FPGM(bci_smooth_stem_width
))
5621 + sizeof (FPGM(bci_get_best_width
))
5622 + sizeof (FPGM(bci_strong_stem_width_a
))
5624 + sizeof (FPGM(bci_strong_stem_width_b
))
5625 + sizeof (FPGM(bci_loop_do
))
5626 + sizeof (FPGM(bci_loop
))
5627 + sizeof (FPGM(bci_cvt_rescale
))
5628 + sizeof (FPGM(bci_cvt_rescale_range
))
5629 + sizeof (FPGM(bci_vwidth_data_store
))
5630 + sizeof (FPGM(bci_smooth_blue_round
))
5631 + sizeof (FPGM(bci_strong_blue_round
))
5632 + sizeof (FPGM(bci_blue_round_range
))
5633 + sizeof (FPGM(bci_decrement_component_counter
))
5634 + sizeof (FPGM(bci_get_point_extrema
))
5635 + sizeof (FPGM(bci_nibbles
))
5636 + sizeof (FPGM(bci_number_set_is_element
))
5637 + sizeof (FPGM(bci_number_set_is_element2
))
5639 + sizeof (FPGM(bci_create_segment
))
5640 + sizeof (FPGM(bci_create_segments_a
))
5642 + sizeof (FPGM(bci_create_segments_b
))
5644 + sizeof (FPGM(bci_create_segments_0
))
5645 + sizeof (FPGM(bci_create_segments_1
))
5646 + sizeof (FPGM(bci_create_segments_2
))
5647 + sizeof (FPGM(bci_create_segments_3
))
5648 + sizeof (FPGM(bci_create_segments_4
))
5649 + sizeof (FPGM(bci_create_segments_5
))
5650 + sizeof (FPGM(bci_create_segments_6
))
5651 + sizeof (FPGM(bci_create_segments_7
))
5652 + sizeof (FPGM(bci_create_segments_8
))
5653 + sizeof (FPGM(bci_create_segments_9
))
5655 + sizeof (FPGM(bci_create_segments_composite_a
))
5657 + sizeof (FPGM(bci_create_segments_composite_b
))
5659 + sizeof (FPGM(bci_create_segments_composite_0
))
5660 + sizeof (FPGM(bci_create_segments_composite_1
))
5661 + sizeof (FPGM(bci_create_segments_composite_2
))
5662 + sizeof (FPGM(bci_create_segments_composite_3
))
5663 + sizeof (FPGM(bci_create_segments_composite_4
))
5664 + sizeof (FPGM(bci_create_segments_composite_5
))
5665 + sizeof (FPGM(bci_create_segments_composite_6
))
5666 + sizeof (FPGM(bci_create_segments_composite_7
))
5667 + sizeof (FPGM(bci_create_segments_composite_8
))
5668 + sizeof (FPGM(bci_create_segments_composite_9
))
5670 + sizeof (FPGM(bci_align_point
))
5671 + sizeof (FPGM(bci_align_segment
))
5672 + sizeof (FPGM(bci_align_segments
))
5674 + sizeof (FPGM(bci_scale_contour
))
5675 + sizeof (FPGM(bci_scale_glyph
))
5676 + sizeof (FPGM(bci_scale_composite_glyph
))
5677 + sizeof (FPGM(bci_shift_contour
))
5678 + sizeof (FPGM(bci_shift_subglyph
))
5680 + sizeof (FPGM(bci_ip_outer_align_point
))
5681 + sizeof (FPGM(bci_ip_on_align_points
))
5682 + sizeof (FPGM(bci_ip_between_align_point
))
5683 + sizeof (FPGM(bci_ip_between_align_points
))
5685 + sizeof (FPGM(bci_adjust_common
))
5686 + sizeof (FPGM(bci_stem_common
))
5687 + sizeof (FPGM(bci_serif_common
))
5688 + sizeof (FPGM(bci_serif_anchor_common
))
5689 + sizeof (FPGM(bci_serif_link1_common
))
5690 + sizeof (FPGM(bci_serif_link2_common
))
5692 + sizeof (FPGM(bci_lower_bound
))
5693 + sizeof (FPGM(bci_upper_bound
))
5694 + sizeof (FPGM(bci_upper_lower_bound
))
5696 + sizeof (FPGM(bci_adjust_bound
))
5697 + sizeof (FPGM(bci_stem_bound
))
5698 + sizeof (FPGM(bci_link
))
5699 + sizeof (FPGM(bci_anchor
))
5700 + sizeof (FPGM(bci_adjust
))
5701 + sizeof (FPGM(bci_stem
))
5703 + sizeof (FPGM(bci_action_ip_before
))
5704 + sizeof (FPGM(bci_action_ip_after
))
5705 + sizeof (FPGM(bci_action_ip_on
))
5706 + sizeof (FPGM(bci_action_ip_between
))
5708 + sizeof (FPGM(bci_action_blue
))
5709 + sizeof (FPGM(bci_action_blue_anchor
))
5711 + sizeof (FPGM(bci_action_anchor
))
5712 + sizeof (FPGM(bci_action_anchor_serif
))
5713 + sizeof (FPGM(bci_action_anchor_round
))
5714 + sizeof (FPGM(bci_action_anchor_round_serif
))
5716 + sizeof (FPGM(bci_action_adjust
))
5717 + sizeof (FPGM(bci_action_adjust_serif
))
5718 + sizeof (FPGM(bci_action_adjust_round
))
5719 + sizeof (FPGM(bci_action_adjust_round_serif
))
5720 + sizeof (FPGM(bci_action_adjust_bound
))
5721 + sizeof (FPGM(bci_action_adjust_bound_serif
))
5722 + sizeof (FPGM(bci_action_adjust_bound_round
))
5723 + sizeof (FPGM(bci_action_adjust_bound_round_serif
))
5725 + sizeof (FPGM(bci_action_link
))
5726 + sizeof (FPGM(bci_action_link_serif
))
5727 + sizeof (FPGM(bci_action_link_round
))
5728 + sizeof (FPGM(bci_action_link_round_serif
))
5730 + sizeof (FPGM(bci_action_stem
))
5731 + sizeof (FPGM(bci_action_stem_serif
))
5732 + sizeof (FPGM(bci_action_stem_round
))
5733 + sizeof (FPGM(bci_action_stem_round_serif
))
5734 + sizeof (FPGM(bci_action_stem_bound
))
5735 + sizeof (FPGM(bci_action_stem_bound_serif
))
5736 + sizeof (FPGM(bci_action_stem_bound_round
))
5737 + sizeof (FPGM(bci_action_stem_bound_round_serif
))
5739 + sizeof (FPGM(bci_action_serif
))
5740 + sizeof (FPGM(bci_action_serif_lower_bound
))
5741 + sizeof (FPGM(bci_action_serif_upper_bound
))
5742 + sizeof (FPGM(bci_action_serif_upper_lower_bound
))
5744 + sizeof (FPGM(bci_action_serif_anchor
))
5745 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
5746 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
5747 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound
))
5749 + sizeof (FPGM(bci_action_serif_link1
))
5750 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
5751 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
5752 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound
))
5754 + sizeof (FPGM(bci_action_serif_link2
))
5755 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
5756 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
5757 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound
))
5759 + sizeof (FPGM(bci_hint_glyph
));
5761 /* buffer length must be a multiple of four */
5762 len
= (buf_len
+ 3) & ~3;
5763 buf
= (FT_Byte
*)malloc(len
);
5765 return FT_Err_Out_Of_Memory
;
5767 /* pad end of buffer with zeros */
5768 buf
[len
- 1] = 0x00;
5769 buf
[len
- 2] = 0x00;
5770 buf
[len
- 3] = 0x00;
5772 /* copy font program into buffer and fill in the missing variables */
5775 COPY_FPGM(bci_align_top_a
);
5776 if (font
->increase_x_height
)
5778 COPY_FPGM(bci_align_top_b1a
);
5779 *(bufp
++) = HIGH(font
->increase_x_height
);
5780 *(bufp
++) = LOW(font
->increase_x_height
);
5781 COPY_FPGM(bci_align_top_b1b
);
5784 COPY_FPGM(bci_align_top_b2
);
5785 COPY_FPGM(bci_align_top_c
);
5787 COPY_FPGM(bci_round
);
5788 COPY_FPGM(bci_smooth_stem_width
);
5789 COPY_FPGM(bci_get_best_width
);
5790 COPY_FPGM(bci_strong_stem_width_a
);
5791 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5792 COPY_FPGM(bci_strong_stem_width_b
);
5793 COPY_FPGM(bci_loop_do
);
5794 COPY_FPGM(bci_loop
);
5795 COPY_FPGM(bci_cvt_rescale
);
5796 COPY_FPGM(bci_cvt_rescale_range
);
5797 COPY_FPGM(bci_vwidth_data_store
);
5798 COPY_FPGM(bci_smooth_blue_round
);
5799 COPY_FPGM(bci_strong_blue_round
);
5800 COPY_FPGM(bci_blue_round_range
);
5801 COPY_FPGM(bci_decrement_component_counter
);
5802 COPY_FPGM(bci_get_point_extrema
);
5803 COPY_FPGM(bci_nibbles
);
5804 COPY_FPGM(bci_number_set_is_element
);
5805 COPY_FPGM(bci_number_set_is_element2
);
5807 COPY_FPGM(bci_create_segment
);
5808 COPY_FPGM(bci_create_segments_a
);
5809 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5810 COPY_FPGM(bci_create_segments_b
);
5812 COPY_FPGM(bci_create_segments_0
);
5813 COPY_FPGM(bci_create_segments_1
);
5814 COPY_FPGM(bci_create_segments_2
);
5815 COPY_FPGM(bci_create_segments_3
);
5816 COPY_FPGM(bci_create_segments_4
);
5817 COPY_FPGM(bci_create_segments_5
);
5818 COPY_FPGM(bci_create_segments_6
);
5819 COPY_FPGM(bci_create_segments_7
);
5820 COPY_FPGM(bci_create_segments_8
);
5821 COPY_FPGM(bci_create_segments_9
);
5823 COPY_FPGM(bci_create_segments_composite_a
);
5824 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5825 COPY_FPGM(bci_create_segments_composite_b
);
5827 COPY_FPGM(bci_create_segments_composite_0
);
5828 COPY_FPGM(bci_create_segments_composite_1
);
5829 COPY_FPGM(bci_create_segments_composite_2
);
5830 COPY_FPGM(bci_create_segments_composite_3
);
5831 COPY_FPGM(bci_create_segments_composite_4
);
5832 COPY_FPGM(bci_create_segments_composite_5
);
5833 COPY_FPGM(bci_create_segments_composite_6
);
5834 COPY_FPGM(bci_create_segments_composite_7
);
5835 COPY_FPGM(bci_create_segments_composite_8
);
5836 COPY_FPGM(bci_create_segments_composite_9
);
5838 COPY_FPGM(bci_align_point
);
5839 COPY_FPGM(bci_align_segment
);
5840 COPY_FPGM(bci_align_segments
);
5842 COPY_FPGM(bci_scale_contour
);
5843 COPY_FPGM(bci_scale_glyph
);
5844 COPY_FPGM(bci_scale_composite_glyph
);
5845 COPY_FPGM(bci_shift_contour
);
5846 COPY_FPGM(bci_shift_subglyph
);
5848 COPY_FPGM(bci_ip_outer_align_point
);
5849 COPY_FPGM(bci_ip_on_align_points
);
5850 COPY_FPGM(bci_ip_between_align_point
);
5851 COPY_FPGM(bci_ip_between_align_points
);
5853 COPY_FPGM(bci_adjust_common
);
5854 COPY_FPGM(bci_stem_common
);
5855 COPY_FPGM(bci_serif_common
);
5856 COPY_FPGM(bci_serif_anchor_common
);
5857 COPY_FPGM(bci_serif_link1_common
);
5858 COPY_FPGM(bci_serif_link2_common
);
5860 COPY_FPGM(bci_lower_bound
);
5861 COPY_FPGM(bci_upper_bound
);
5862 COPY_FPGM(bci_upper_lower_bound
);
5864 COPY_FPGM(bci_adjust_bound
);
5865 COPY_FPGM(bci_stem_bound
);
5866 COPY_FPGM(bci_link
);
5867 COPY_FPGM(bci_anchor
);
5868 COPY_FPGM(bci_adjust
);
5869 COPY_FPGM(bci_stem
);
5871 COPY_FPGM(bci_action_ip_before
);
5872 COPY_FPGM(bci_action_ip_after
);
5873 COPY_FPGM(bci_action_ip_on
);
5874 COPY_FPGM(bci_action_ip_between
);
5876 COPY_FPGM(bci_action_blue
);
5877 COPY_FPGM(bci_action_blue_anchor
);
5879 COPY_FPGM(bci_action_anchor
);
5880 COPY_FPGM(bci_action_anchor_serif
);
5881 COPY_FPGM(bci_action_anchor_round
);
5882 COPY_FPGM(bci_action_anchor_round_serif
);
5884 COPY_FPGM(bci_action_adjust
);
5885 COPY_FPGM(bci_action_adjust_serif
);
5886 COPY_FPGM(bci_action_adjust_round
);
5887 COPY_FPGM(bci_action_adjust_round_serif
);
5888 COPY_FPGM(bci_action_adjust_bound
);
5889 COPY_FPGM(bci_action_adjust_bound_serif
);
5890 COPY_FPGM(bci_action_adjust_bound_round
);
5891 COPY_FPGM(bci_action_adjust_bound_round_serif
);
5893 COPY_FPGM(bci_action_link
);
5894 COPY_FPGM(bci_action_link_serif
);
5895 COPY_FPGM(bci_action_link_round
);
5896 COPY_FPGM(bci_action_link_round_serif
);
5898 COPY_FPGM(bci_action_stem
);
5899 COPY_FPGM(bci_action_stem_serif
);
5900 COPY_FPGM(bci_action_stem_round
);
5901 COPY_FPGM(bci_action_stem_round_serif
);
5902 COPY_FPGM(bci_action_stem_bound
);
5903 COPY_FPGM(bci_action_stem_bound_serif
);
5904 COPY_FPGM(bci_action_stem_bound_round
);
5905 COPY_FPGM(bci_action_stem_bound_round_serif
);
5907 COPY_FPGM(bci_action_serif
);
5908 COPY_FPGM(bci_action_serif_lower_bound
);
5909 COPY_FPGM(bci_action_serif_upper_bound
);
5910 COPY_FPGM(bci_action_serif_upper_lower_bound
);
5912 COPY_FPGM(bci_action_serif_anchor
);
5913 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
5914 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
5915 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound
);
5917 COPY_FPGM(bci_action_serif_link1
);
5918 COPY_FPGM(bci_action_serif_link1_lower_bound
);
5919 COPY_FPGM(bci_action_serif_link1_upper_bound
);
5920 COPY_FPGM(bci_action_serif_link1_upper_lower_bound
);
5922 COPY_FPGM(bci_action_serif_link2
);
5923 COPY_FPGM(bci_action_serif_link2_lower_bound
);
5924 COPY_FPGM(bci_action_serif_link2_upper_bound
);
5925 COPY_FPGM(bci_action_serif_link2_upper_lower_bound
);
5927 COPY_FPGM(bci_hint_glyph
);
5930 *fpgm_len
= buf_len
;
5937 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
5942 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5943 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5949 error
= TA_sfnt_add_table_info(sfnt
);
5953 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5954 if (glyf_table
->processed
)
5956 sfnt
->table_infos
[sfnt
->num_table_infos
- 1] = data
->fpgm_idx
;
5960 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, sfnt
, font
);
5964 if (fpgm_len
> sfnt
->max_instructions
)
5965 sfnt
->max_instructions
= fpgm_len
;
5967 /* in case of success, `fpgm_buf' gets linked */
5968 /* and is eventually freed in `TA_font_unload' */
5969 error
= TA_font_add_table(font
,
5970 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
5971 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
5975 data
->fpgm_idx
= sfnt
->table_infos
[sfnt
->num_table_infos
- 1];
5981 /* end of tafpgm.c */