4 * Copyright (C) 2011-2015 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 const 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 const 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 const 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 const unsigned char FPGM(bci_align_top_b2
) [] =
235 FLOOR
, /* fitted = FLOOR(blue + 40) */
241 const 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 const 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 const 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 const 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'):
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 const 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 */
688 sal_vwidth_data_offset
,
694 /* %c, number of used styles */
696 const unsigned char FPGM(bci_strong_stem_width_b
) [] =
700 RCVT
, /* number of vertical widths */
701 MUL
, /* divide by 64 */
707 POP
, /* s: width dist */
711 RS
, /* s: width dist dist reference */
718 CALL
, /* s: width dist reference dist dist ROUND(reference) */
722 CINDEX
, /* s: width dist reference dist dist ROUND(reference) 48 reference */
725 MINDEX
, /* s: width dist reference dist ROUND(reference) 48 reference dist */
727 LTEQ
, /* dist >= reference */
728 IF
, /* s: width dist reference dist ROUND(reference) 48 */
730 LT
, /* dist < ROUND(reference) + 48 */
734 GT
, /* dist > ROUND(reference) - 48 */
738 SWAP
, /* s: width reference dist */
745 GTEQ
, /* dist >= 64 */
749 CALL
, /* dist = ROUND(dist) */
757 SWAP
, /* s: dist width */
762 NEG
, /* dist = -dist */
773 * An auxiliary function for `bci_loop'.
775 * sal: sal_i (gets incremented by 2 after execution)
778 * uses: func[sal_func]
781 const unsigned char FPGM(bci_loop_do
) [] =
798 ADD
, /* sal_i = sal_i + 2 */
809 * Take a range `start'..`end' and a function number and apply the
810 * associated function to the range elements `start', `start+2',
817 * sal: sal_i (counter initialized with `start')
818 * sal_func (`func_num')
823 const unsigned char FPGM(bci_loop
) [] =
833 WS
, /* sal_func = func_num */
840 WS
, /* sal_i = start */
846 ADD
, /* number of loops ((end - start) / 2 + 1) */
860 * Rescale CVT value by `sal_scale' (in 16.16 format).
862 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
863 * consequently, the calculation `a * b/c' is done as `a + delta' with
864 * `delta = a * (b-c)/c'. This avoids overflow.
873 const unsigned char FPGM(bci_cvt_rescale
) [] =
896 * bci_cvt_rescale_range
898 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
901 * This function gets used in the `prep' table.
906 * sal: sal_i (CVT index of the style's scaling value;
907 * gets incremented by 1 after execution)
910 * uses: bci_cvt_rescale
913 const unsigned char FPGM(bci_cvt_rescale_range
) [] =
917 bci_cvt_rescale_range
,
920 /* store scaling value in `sal_scale' */
927 WS
, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
937 ADD
, /* sal_i = sal_i + 1 */
946 * bci_vwidth_data_store
948 * Store a vertical width array value.
950 * This function gets used in the `prep' table.
954 * sal: sal_i (CVT index of the style's vwidth data;
955 * gets incremented by 1 after execution)
958 const unsigned char FPGM(bci_vwidth_data_store
) [] =
962 bci_vwidth_data_store
,
976 ADD
, /* sal_i = sal_i + 1 */
985 * bci_smooth_blue_round
987 * Round a blue ref value and adjust its corresponding shoot value.
989 * This is the equivalent to the following code (function
990 * `ta_latin_metrics_scale_dim':
998 * else if delta < 48:
1008 * sal: sal_i (number of blue zones)
1015 const unsigned char FPGM(bci_smooth_blue_round
) [] =
1019 bci_smooth_blue_round
,
1024 RCVT
, /* s: ref_idx ref_idx ref */
1030 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
1038 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1040 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1042 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1044 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1046 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1051 LT
, /* delta < 32 */
1060 LT
, /* delta < 48 */
1063 32, /* delta = 32 */
1067 64, /* delta = 64 */
1071 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1076 NEG
, /* delta = -delta */
1083 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1090 ADD
, /* s: (ref_idx + 1) */
1098 * bci_strong_blue_round
1100 * Round a blue ref value and adjust its corresponding shoot value.
1102 * This is the equivalent to the following code:
1116 * It doesn't have corresponding code in talatin.c; however, some tests
1117 * have shown that the `smooth' code works just fine for this case also.
1121 * sal: sal_i (number of blue zones)
1128 const unsigned char FPGM(bci_strong_blue_round
) [] =
1132 bci_strong_blue_round
,
1137 RCVT
, /* s: ref_idx ref_idx ref */
1143 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
1151 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1153 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1155 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1157 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1159 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1163 LT
, /* delta < 36 */
1166 0, /* delta = 0 (set overshoot to zero if < 0.56 pixel units) */
1170 64, /* delta = 64 (one pixel unit) */
1173 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1178 NEG
, /* delta = -delta */
1185 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1192 ADD
, /* s: (ref_idx + 1) */
1200 * bci_blue_round_range
1202 * Round a range of blue zones (both reference and shoot values).
1204 * This function gets used in the `prep' table.
1206 * in: num_blue_zones
1209 * sal: sal_i (holds a copy of `num_blue_zones' for blue rounding function)
1211 * uses: bci_smooth_blue_round
1212 * bci_strong_blue_round
1215 const unsigned char FPGM(bci_blue_round_range
) [] =
1219 bci_blue_round_range
,
1228 /* select blue rounding function based on flag in CVT */
1230 bci_strong_blue_round
,
1231 bci_smooth_blue_round
,
1232 cvtl_use_strong_functions
,
1251 * bci_decrement_component_counter
1253 * An auxiliary function for composite glyphs.
1255 * CVT: cvtl_is_subglyph
1258 const unsigned char FPGM(bci_decrement_component_counter
) [] =
1262 bci_decrement_component_counter
,
1265 /* decrement `cvtl_is_subglyph' counter */
1281 * bci_get_point_extrema
1283 * An auxiliary function for `bci_create_segment'.
1289 * sal: sal_point_min
1293 const unsigned char FPGM(bci_get_point_extrema
) [] =
1297 bci_get_point_extrema
,
1306 /* check whether `point' is a new minimum */
1309 RS
, /* s: point point point point_min */
1311 /* if distance is negative, we have a new minimum */
1315 IF
, /* s: point point */
1323 /* check whether `point' is a new maximum */
1326 RS
, /* s: point point point_max */
1328 /* if distance is positive, we have a new maximum */
1348 * Pop a byte with two delta arguments in its nibbles and push the
1349 * expanded arguments separately as two bytes.
1351 * in: 16 * (end - start) + (start - base)
1356 * sal: sal_base (set to `end' at return)
1360 const unsigned char FPGM(bci_nibbles
) [] =
1367 PUSHB_1
, /* cf. DIV_POS_BY_2 macro */
1373 MUL
, /* s: in hnibble */
1378 MUL
, /* s: in hnibble (hnibble * 16) */
1381 SUB
, /* s: hnibble lnibble */
1386 ADD
, /* s: hnibble start */
1389 ADD
, /* s: start end */
1395 WS
, /* sal_base = end */
1405 * bci_number_set_is_element
1407 * Pop values from stack until it is empty. If one of them is equal to
1408 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1415 * CVT: cvtl_is_element
1418 const unsigned char FPGM(bci_number_set_is_element
) [] =
1422 bci_number_set_is_element
,
1440 JROT
, /* goto start_loop if stack depth != 0 */
1448 * bci_number_set_is_element2
1450 * Pop value ranges from stack until it is empty. If one of them contains
1451 * the current PPEM value, set `cvtl_is_element' to 100 (and to 0
1454 * in: ppem_range_1_start
1456 * ppem_range_2_start
1460 * CVT: cvtl_is_element
1463 const unsigned char FPGM(bci_number_set_is_element2
) [] =
1467 bci_number_set_is_element2
,
1491 JROT
, /* goto start_loop if stack depth != 0 */
1499 * bci_create_segment
1501 * Store start and end point of a segment in the storage area,
1502 * then construct a point in the twilight zone to represent it.
1504 * This function is used by `bci_create_segments'.
1508 * [last (if wrap-around segment)]
1509 * [first (if wrap-around segment)]
1511 * sal: sal_i (start of current segment)
1512 * sal_j (current twilight point)
1516 * sal_num_packed_segments
1521 * uses: bci_get_point_extrema
1524 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1525 * delta values in nibbles (without a wrap-around segment).
1528 const unsigned char FPGM(bci_create_segment
) [] =
1537 sal_num_packed_segments
,
1542 sal_num_packed_segments
,
1543 sal_num_packed_segments
,
1548 WS
, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1561 WS
, /* sal[sal_i] = start */
1563 /* initialize inner loop(s) */
1568 WS
, /* sal_point_min = start */
1573 WS
, /* sal_point_max = start */
1577 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1583 CINDEX
, /* s: start end end start */
1584 LT
, /* start > end */
1586 /* we have a wrap-around segment with two more arguments */
1587 /* to give the last and first point of the contour, respectively; */
1588 /* our job is to store a segment `start'-`last', */
1589 /* and to get extrema for the two segments */
1590 /* `start'-`last' and `first'-`end' */
1592 /* s: first last start end */
1601 WS
, /* sal[sal_i + 1] = last */
1604 ROLL
, /* s: first end last start */
1607 SWAP
, /* s: first end start last start */
1608 SUB
, /* s: first end start loop_count */
1611 bci_get_point_extrema
,
1613 /* clean up stack */
1616 SWAP
, /* s: end first */
1621 ROLL
, /* s: (first - 1) (first - 1) end */
1623 SUB
, /* s: (first - 1) loop_count */
1626 bci_get_point_extrema
,
1628 /* clean up stack */
1631 ELSE
, /* s: start end */
1640 WS
, /* sal[sal_i + 1] = end */
1645 SUB
, /* s: start loop_count */
1648 bci_get_point_extrema
,
1650 /* clean up stack */
1654 /* the twilight point representing a segment */
1655 /* is in the middle between the minimum and maximum */
1665 DIV_BY_2
, /* s: middle_pos */
1667 DO_SCALE
, /* middle_pos = middle_pos * scale */
1669 /* write it to temporary CVT location */
1673 SZP0
, /* set zp0 to twilight zone 0 */
1677 /* create twilight point with index `sal_j' */
1690 ADD
, /* twilight_point = twilight_point + 1 */
1699 * bci_create_segments
1701 * This is the top-level entry function.
1703 * It pops point ranges from the stack to define segments, computes
1704 * twilight points to represent segments, and finally calls
1705 * `bci_hint_glyph' to handle the rest.
1707 * The second argument (`data_offset') addresses three CVT arrays in
1711 * the current style's scaling value (stored in `sal_scale')
1713 * data_offset + num_used_styles:
1714 * offset to the current style's vwidth index array (this value gets
1715 * stored in `sal_vwidth_data_offset')
1717 * data_offset + 2*num_used_styles:
1718 * offset to the current style's vwidth size
1720 * This addressing scheme ensures that (a) we only need a single argument,
1721 * and (b) this argument supports up to (256-cvtl_max_runtime) styles,
1722 * which should be sufficient for a long time.
1724 * in: num_packed_segments
1729 * [contour_last 0 (if wrap-around segment)]
1730 * [contour_first 0 (if wrap-around segment)]
1733 * [contour_last 0 (if wrap-around segment)]
1734 * [contour_first 0 (if wrap-around segment)]
1736 * segment_start_(N-1)
1738 * [contour_last (N-1) (if wrap-around segment)]
1739 * [contour_first (N-1) (if wrap-around segment)]
1740 * ... stuff for bci_hint_glyph ...
1742 * sal: sal_i (start of current segment)
1743 * sal_j (current twilight point)
1744 * sal_num_packed_segments
1745 * sal_base (the base for delta values in nibbles)
1746 * sal_vwidth_data_offset
1749 * CVT: cvtl_is_subglyph
1751 * uses: bci_create_segment
1755 * If `num_packed_segments' is set to p, the first p start/end pairs are
1756 * stored as delta values in nibbles, with the `start' delta in the lower
1757 * nibble (and there are no wrap-around segments). For example, if the
1758 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1759 * stack are 0x21, 0x32, and 0x14.
1763 const unsigned char FPGM(bci_create_segments_a
) [] =
1767 bci_create_segments
,
1770 /* all our measurements are taken along the y axis */
1773 /* only do something if we are not a subglyph */
1781 sal_num_packed_segments
,
1788 sal_scale
, /* sal_scale = CVT(data_offset) */
1793 sal_vwidth_data_offset
,
1799 /* %c, number of used styles */
1801 const unsigned char FPGM(bci_create_segments_b
) [] =
1805 WS
, /* sal_vwidth_data_offset = data_offset + num_used_styles */
1811 SUB
, /* delta = (2*num_segments - 1) */
1821 WS
, /* sal_base = 0 */
1822 WS
, /* sal_j = 0 (point offset) */
1825 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1838 /* used if we have delta exceptions */
1840 const unsigned char FPGM(bci_create_segments_c
) [] =
1849 const unsigned char FPGM(bci_create_segments_d
) [] =
1862 * bci_create_segments_X
1864 * Top-level routines for calling `bci_create_segments'.
1867 const unsigned char FPGM(bci_create_segments_0
) [] =
1871 bci_create_segments_0
,
1876 bci_create_segments
,
1883 const unsigned char FPGM(bci_create_segments_1
) [] =
1887 bci_create_segments_1
,
1892 bci_create_segments
,
1899 const unsigned char FPGM(bci_create_segments_2
) [] =
1903 bci_create_segments_2
,
1908 bci_create_segments
,
1915 const unsigned char FPGM(bci_create_segments_3
) [] =
1919 bci_create_segments_3
,
1924 bci_create_segments
,
1931 const unsigned char FPGM(bci_create_segments_4
) [] =
1935 bci_create_segments_4
,
1940 bci_create_segments
,
1947 const unsigned char FPGM(bci_create_segments_5
) [] =
1951 bci_create_segments_5
,
1956 bci_create_segments
,
1963 const unsigned char FPGM(bci_create_segments_6
) [] =
1967 bci_create_segments_6
,
1972 bci_create_segments
,
1979 const unsigned char FPGM(bci_create_segments_7
) [] =
1983 bci_create_segments_7
,
1988 bci_create_segments
,
1995 const unsigned char FPGM(bci_create_segments_8
) [] =
1999 bci_create_segments_8
,
2004 bci_create_segments
,
2011 const unsigned char FPGM(bci_create_segments_9
) [] =
2015 bci_create_segments_9
,
2020 bci_create_segments
,
2031 * Wrapper functions around DELTAP[123] that touch the affected points
2032 * before applying the delta. This is necessary for ClearType.
2034 * While DELTAP[123] implicitly do a loop, we have to process the
2035 * arguments sequentially by calling `bci_deltaX' with LOOPCALL.
2041 const unsigned char FPGM(bci_deltap1
) [] =
2049 MDAP_noround
, /* touch `point' */
2053 DELTAP1
, /* process one `(point,arg)' pair */
2059 const unsigned char FPGM(bci_deltap2
) [] =
2067 MDAP_noround
, /* touch `point' */
2071 DELTAP2
, /* process one `(point,arg)' pair */
2077 const unsigned char FPGM(bci_deltap3
) [] =
2085 MDAP_noround
, /* touch `point' */
2089 DELTAP3
, /* process one `(point,arg)' pair */
2097 * bci_create_segments_composite
2099 * The same as `bci_create_segments'.
2100 * It also decrements the composite component counter.
2102 * sal: sal_num_packed_segments
2103 * sal_segment_offset
2104 * sal_vwidth_data_offset
2106 * CVT: cvtl_is_subglyph
2108 * uses: bci_decrement_component_counter
2109 * bci_create_segment
2114 const unsigned char FPGM(bci_create_segments_composite_a
) [] =
2118 bci_create_segments_composite
,
2121 /* all our measurements are taken along the y axis */
2125 bci_decrement_component_counter
,
2128 /* only do something if we are not a subglyph */
2136 sal_num_packed_segments
,
2143 sal_scale
, /* sal_scale = CVT(data_offset) */
2148 sal_vwidth_data_offset
,
2154 /* %c, number of used styles */
2156 const unsigned char FPGM(bci_create_segments_composite_b
) [] =
2160 WS
, /* sal_vwidth_data_offset = data_offset + num_used_styles */
2166 SUB
, /* delta = (2*num_segments - 1) */
2176 WS
, /* sal_base = 0 */
2177 WS
, /* sal_j = 0 (point offset) */
2180 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
2193 /* used if we have delta exceptions */
2195 const unsigned char FPGM(bci_create_segments_composite_c
) [] =
2204 const unsigned char FPGM(bci_create_segments_composite_d
) [] =
2217 * bci_create_segments_composite_X
2219 * Top-level routines for calling `bci_create_segments_composite'.
2222 const unsigned char FPGM(bci_create_segments_composite_0
) [] =
2226 bci_create_segments_composite_0
,
2231 bci_create_segments_composite
,
2238 const unsigned char FPGM(bci_create_segments_composite_1
) [] =
2242 bci_create_segments_composite_1
,
2247 bci_create_segments_composite
,
2254 const unsigned char FPGM(bci_create_segments_composite_2
) [] =
2258 bci_create_segments_composite_2
,
2263 bci_create_segments_composite
,
2270 const unsigned char FPGM(bci_create_segments_composite_3
) [] =
2274 bci_create_segments_composite_3
,
2279 bci_create_segments_composite
,
2286 const unsigned char FPGM(bci_create_segments_composite_4
) [] =
2290 bci_create_segments_composite_4
,
2295 bci_create_segments_composite
,
2302 const unsigned char FPGM(bci_create_segments_composite_5
) [] =
2306 bci_create_segments_composite_5
,
2311 bci_create_segments_composite
,
2318 const unsigned char FPGM(bci_create_segments_composite_6
) [] =
2322 bci_create_segments_composite_6
,
2327 bci_create_segments_composite
,
2334 const unsigned char FPGM(bci_create_segments_composite_7
) [] =
2338 bci_create_segments_composite_7
,
2343 bci_create_segments_composite
,
2350 const unsigned char FPGM(bci_create_segments_composite_8
) [] =
2354 bci_create_segments_composite_8
,
2359 bci_create_segments_composite
,
2366 const unsigned char FPGM(bci_create_segments_composite_9
) [] =
2370 bci_create_segments_composite_9
,
2375 bci_create_segments_composite
,
2386 * An auxiliary function for `bci_align_segment'.
2393 const unsigned char FPGM(bci_align_point
) [] =
2401 ALIGNRP
, /* align point with rp0 */
2415 * Align all points in a segment to the twilight point in rp0.
2416 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2420 * sal: sal_segment_offset
2422 * uses: bci_align_point
2425 const unsigned char FPGM(bci_align_segment
) [] =
2432 /* we need the values of `sal_segment_offset + 2*segment_index' */
2433 /* and `sal_segment_offset + 2*segment_index + 1' */
2445 RS
, /* s: first last */
2449 CINDEX
, /* s: first last first */
2453 ADD
, /* s: first loop_count */
2458 /* clean up stack */
2467 * bci_align_segments
2469 * Align segments to the twilight point in rp0.
2470 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2479 * uses: bci_align_segment
2482 const unsigned char FPGM(bci_align_segments
) [] =
2505 * Scale a contour using two points giving the maximum and minimum
2508 * It expects that no point on the contour is touched.
2516 const unsigned char FPGM(bci_scale_contour
) [] =
2527 DO_SCALE
, /* min_pos_new = min_pos * scale */
2532 /* don't scale a single-point contour twice */
2541 DO_SCALE
, /* max_pos_new = max_pos * scale */
2558 * Scale a glyph using a list of points (two points per contour, giving
2559 * the maximum and mininum coordinates).
2561 * It expects that no point in the glyph is touched.
2563 * Note that the point numbers are sorted in ascending order;
2564 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2565 * contour without specifying which one is the minimum and maximum.
2567 * in: num_contours (N)
2576 * CVT: cvtl_is_subglyph
2579 * uses: bci_scale_contour
2582 const unsigned char FPGM(bci_scale_glyph
) [] =
2589 /* all our measurements are taken along the y axis */
2592 /* only do something if we are not a subglyph */
2601 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2610 SZP2
, /* set zp2 to normal zone 1 */
2626 * bci_scale_composite_glyph
2628 * The same as `bci_scale_glyph'.
2629 * It also decrements the composite component counter.
2631 * CVT: cvtl_is_subglyph
2634 * uses: bci_decrement_component_counter
2638 const unsigned char FPGM(bci_scale_composite_glyph
) [] =
2642 bci_scale_composite_glyph
,
2645 /* all our measurements are taken along the y axis */
2649 bci_decrement_component_counter
,
2652 /* only do something if we are not a subglyph */
2661 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2670 SZP2
, /* set zp2 to normal zone 1 */
2688 * Shift a contour by a given amount.
2690 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2691 * point to the normal zone 1.
2698 const unsigned char FPGM(bci_shift_contour
) [] =
2706 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2718 * bci_shift_subglyph
2720 * Shift a subglyph. To be more specific, it corrects the already applied
2721 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2724 * If this function is called, a point `x' in the subglyph has been scaled
2725 * already (during the hinting of the subglyph itself), and `offset' has
2726 * been applied also:
2728 * x -> x * scale + offset (1)
2730 * However, the offset should be applied first, then the scaling:
2732 * x -> (x + offset) * scale (2)
2734 * Our job is now to transform (1) to (2); a simple calculation shows that
2735 * we have to shift all points of the subglyph by
2737 * offset * scale - offset = offset * (scale - 1)
2739 * Note that `sal_scale' is equal to the above `scale - 1'.
2741 * in: offset (in FUnits)
2745 * CVT: cvtl_funits_to_pixels
2753 const unsigned char FPGM(bci_shift_subglyph_a
) [] =
2760 /* all our measurements are taken along the y axis */
2764 cvtl_funits_to_pixels
,
2765 RCVT
, /* scaling factor FUnits -> pixels */
2769 /* the autohinter always rounds offsets */
2772 CALL
, /* offset = round(offset) */
2778 DIV_BY_1024
, /* delta = offset * (scale - 1) */
2780 /* and round again */
2783 CALL
, /* offset = round(offset) */
2787 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2789 /* we create twilight point 0 as a reference point, */
2790 /* setting the original position to zero (using `cvtl_temp') */
2798 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
2800 SWAP
, /* s: first_contour num_contours 0 delta */
2801 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
2806 SZP2
, /* set zp2 to normal zone 1 */
2811 /* used if we have delta exceptions */
2813 const unsigned char FPGM(bci_shift_subglyph_b
) [] =
2822 const unsigned char FPGM(bci_shift_subglyph_c
) [] =
2831 * bci_ip_outer_align_point
2833 * Auxiliary function for `bci_action_ip_before' and
2834 * `bci_action_ip_after'.
2836 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2837 * zone, and both zp1 and zp2 set to normal zone.
2841 * sal: sal_i (edge_orig_pos)
2845 const unsigned char FPGM(bci_ip_outer_align_point
) [] =
2849 bci_ip_outer_align_point
,
2853 ALIGNRP
, /* align `point' with `edge' */
2856 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2861 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2870 * bci_ip_on_align_points
2872 * Auxiliary function for `bci_action_ip_on'.
2874 * in: edge (in twilight zone)
2882 const unsigned char FPGM(bci_ip_on_align_points
) [] =
2886 bci_ip_on_align_points
,
2889 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2900 * bci_ip_between_align_point
2902 * Auxiliary function for `bci_ip_between_align_points'.
2904 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2905 * zone, and both zp1 and zp2 set to normal zone.
2909 * sal: sal_i (edge_orig_pos)
2910 * sal_j (stretch_factor)
2914 const unsigned char FPGM(bci_ip_between_align_point
) [] =
2918 bci_ip_between_align_point
,
2922 ALIGNRP
, /* align `point' with `edge' */
2925 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2930 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2934 MUL
, /* s: point delta */
2943 * bci_ip_between_align_points
2945 * Auxiliary function for `bci_action_ip_between'.
2947 * in: after_edge (in twilight zone)
2948 * before_edge (in twilight zone)
2955 * sal: sal_i (before_orig_pos)
2956 * sal_j (stretch_factor)
2958 * uses: bci_ip_between_align_point
2961 const unsigned char FPGM(bci_ip_between_align_points
) [] =
2965 bci_ip_between_align_points
,
2971 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2973 DUP
, /* s: ... before after before before */
2974 MDAP_noround
, /* set rp0 and rp1 to `before' */
2976 GC_orig
, /* s: ... before after before before_orig_pos */
2980 WS
, /* sal_i = before_orig_pos */
2983 CINDEX
, /* s: ... before after before after */
2984 MD_cur
, /* a = after_pos - before_pos */
2987 MD_orig_ZP2_0
, /* b = after_orig_pos - before_orig_pos */
2993 POP
, /* avoid division by zero */
2999 WS
, /* sal_j = stretch_factor */
3002 bci_ip_between_align_point
,
3005 SZP2
, /* set zp2 to normal zone 1 */
3006 SZP1
, /* set zp1 to normal zone 1 */
3015 * bci_action_ip_before
3017 * Handle `ip_before' data to align points located before the first edge.
3019 * in: first_edge (in twilight zone)
3026 * sal: sal_i (first_edge_orig_pos)
3028 * uses: bci_ip_outer_align_point
3031 const unsigned char FPGM(bci_action_ip_before
) [] =
3035 bci_action_ip_before
,
3040 SZP2
, /* set zp2 to twilight zone 0 */
3047 WS
, /* sal_i = first_edge_orig_pos */
3053 SZP2
, /* set zp2 to normal zone 1 */
3054 SZP1
, /* set zp1 to normal zone 1 */
3055 SZP0
, /* set zp0 to twilight zone 0 */
3057 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
3060 bci_ip_outer_align_point
,
3069 * bci_action_ip_after
3071 * Handle `ip_after' data to align points located after the last edge.
3073 * in: last_edge (in twilight zone)
3080 * sal: sal_i (last_edge_orig_pos)
3082 * uses: bci_ip_outer_align_point
3085 const unsigned char FPGM(bci_action_ip_after
) [] =
3089 bci_action_ip_after
,
3094 SZP2
, /* set zp2 to twilight zone 0 */
3101 WS
, /* sal_i = last_edge_orig_pos */
3107 SZP2
, /* set zp2 to normal zone 1 */
3108 SZP1
, /* set zp1 to normal zone 1 */
3109 SZP0
, /* set zp0 to twilight zone 0 */
3111 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
3114 bci_ip_outer_align_point
,
3125 * Handle `ip_on' data to align points located on an edge coordinate (but
3126 * not part of an edge).
3128 * in: loop_counter (M)
3129 * edge_1 (in twilight zone)
3130 * loop_counter (N_1)
3135 * edge_2 (in twilight zone)
3136 * loop_counter (N_2)
3142 * edge_M (in twilight zone)
3143 * loop_counter (N_M)
3149 * uses: bci_ip_on_align_points
3152 const unsigned char FPGM(bci_action_ip_on
) [] =
3162 SZP1
, /* set zp1 to normal zone 1 */
3163 SZP0
, /* set zp0 to twilight zone 0 */
3166 bci_ip_on_align_points
,
3175 * bci_action_ip_between
3177 * Handle `ip_between' data to align points located between two edges.
3179 * in: loop_counter (M)
3180 * before_edge_1 (in twilight zone)
3181 * after_edge_1 (in twilight zone)
3182 * loop_counter (N_1)
3187 * before_edge_2 (in twilight zone)
3188 * after_edge_2 (in twilight zone)
3189 * loop_counter (N_2)
3195 * before_edge_M (in twilight zone)
3196 * after_edge_M (in twilight zone)
3197 * loop_counter (N_M)
3203 * uses: bci_ip_between_align_points
3206 const unsigned char FPGM(bci_action_ip_between
) [] =
3210 bci_action_ip_between
,
3214 bci_ip_between_align_points
,
3225 * Common code for bci_action_adjust routines.
3227 * uses: func[sal_stem_width_function]
3230 const unsigned char FPGM(bci_adjust_common
) [] =
3239 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3243 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
3246 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
3247 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
3250 sal_stem_width_function
,
3253 NEG
, /* s: [...] edge2 edge -cur_len */
3255 ROLL
, /* s: [...] edge -cur_len edge2 */
3256 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3259 DUP
, /* s: [...] -cur_len edge edge edge */
3260 ALIGNRP
, /* align `edge' with `edge2' */
3262 SHPIX
, /* shift `edge' by -cur_len */
3272 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
3273 * edge of the stem has already been moved, then moving it again if
3274 * necessary to stay bound.
3276 * in: edge2_is_serif
3278 * edge_point (in twilight zone)
3279 * edge2_point (in twilight zone)
3280 * edge[-1] (in twilight zone)
3281 * ... stuff for bci_align_segments (edge) ...
3283 * uses: bci_adjust_common
3284 * bci_align_segments
3287 const unsigned char FPGM(bci_adjust_bound
) [] =
3298 SWAP
, /* s: edge edge[-1] */
3300 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3305 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3306 GT
, /* edge_pos < edge[-1]_pos */
3309 ALIGNRP
, /* align `edge' to `edge[-1]' */
3312 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3317 SZP1
, /* set zp1 to normal zone 1 */
3326 * bci_action_adjust_bound
3327 * bci_action_adjust_bound_serif
3328 * bci_action_adjust_bound_round
3329 * bci_action_adjust_bound_round_serif
3331 * Higher-level routines for calling `bci_adjust_bound'.
3334 const unsigned char FPGM(bci_action_adjust_bound
) [] =
3338 bci_action_adjust_bound
,
3351 const unsigned char FPGM(bci_action_adjust_bound_serif
) [] =
3355 bci_action_adjust_bound_serif
,
3368 const unsigned char FPGM(bci_action_adjust_bound_round
) [] =
3372 bci_action_adjust_bound_round
,
3385 const unsigned char FPGM(bci_action_adjust_bound_round_serif
) [] =
3389 bci_action_adjust_bound_round_serif
,
3406 * Handle the ADJUST action to align an edge of a stem if the other edge
3407 * of the stem has already been moved.
3409 * in: edge2_is_serif
3411 * edge_point (in twilight zone)
3412 * edge2_point (in twilight zone)
3413 * ... stuff for bci_align_segments (edge) ...
3415 * uses: bci_adjust_common
3416 * bci_align_segments
3419 const unsigned char FPGM(bci_adjust
) [] =
3430 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3435 SZP1
, /* set zp1 to normal zone 1 */
3445 * bci_action_adjust_serif
3446 * bci_action_adjust_round
3447 * bci_action_adjust_round_serif
3449 * Higher-level routines for calling `bci_adjust'.
3452 const unsigned char FPGM(bci_action_adjust
) [] =
3469 const unsigned char FPGM(bci_action_adjust_serif
) [] =
3473 bci_action_adjust_serif
,
3486 const unsigned char FPGM(bci_action_adjust_round
) [] =
3490 bci_action_adjust_round
,
3503 const unsigned char FPGM(bci_action_adjust_round_serif
) [] =
3507 bci_action_adjust_round_serif
,
3524 * Common code for bci_action_stem routines.
3531 * uses: func[sal_stem_width_function]
3536 #define sal_u_off sal_temp1
3538 #define sal_d_off sal_temp2
3540 #define sal_org_len sal_temp3
3542 #define sal_edge2 sal_temp3
3544 const unsigned char FPGM(bci_stem_common
) [] =
3553 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3561 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3562 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3564 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
3572 sal_stem_width_function
,
3574 CALL
, /* s: [...] edge2 edge cur_len */
3579 LT
, /* cur_len < 96 */
3584 LTEQ
, /* cur_len <= 64 */
3602 SWAP
, /* s: [...] edge2 cur_len edge */
3607 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
3613 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3618 ADD
, /* s: [...] edge2 cur_len edge org_center */
3623 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3628 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3635 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3642 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3644 LT
, /* delta1 < delta2 */
3649 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3655 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3656 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
3662 SUB
, /* arg = cur_pos1 - cur_len/2 */
3664 SWAP
, /* s: [...] edge2 cur_len arg edge */
3670 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3673 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3676 SWAP
, /* s: [...] edge2 cur_len edge */
3680 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
3688 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3695 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
3701 CALL
, /* cur_pos1 = ROUND(org_pos) */
3713 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3722 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3729 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3735 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3736 LT
, /* delta1 < delta2 */
3738 POP
, /* arg = cur_pos1 */
3742 POP
, /* arg = cur_pos2 */
3743 EIF
, /* s: [...] edge2 cur_len edge arg */
3750 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3753 SHPIX
, /* edge = arg */
3754 EIF
, /* s: [...] edge2 cur_len edge */
3764 * Handle the STEM action to align two edges of a stem, then moving one
3765 * edge again if necessary to stay bound.
3767 * The code after computing `cur_len' to shift `edge' and `edge2'
3768 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3771 * if cur_len < = 64:
3778 * org_pos = anchor + (edge_orig - anchor_orig)
3779 * org_center = org_pos + org_len / 2
3781 * cur_pos1 = ROUND(org_center)
3782 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3783 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3784 * if (delta1 < delta2):
3785 * cur_pos1 = cur_pos1 - u_off
3787 * cur_pos1 = cur_pos1 + d_off
3789 * edge = cur_pos1 - cur_len / 2
3792 * org_pos = anchor + (edge_orig - anchor_orig)
3793 * org_center = org_pos + org_len / 2
3795 * cur_pos1 = ROUND(org_pos)
3796 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3797 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3798 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3800 * if (delta1 < delta2):
3805 * edge2 = edge + cur_len
3807 * in: edge2_is_serif
3809 * edge_point (in twilight zone)
3810 * edge2_point (in twilight zone)
3811 * edge[-1] (in twilight zone)
3812 * ... stuff for bci_align_segments (edge) ...
3813 * ... stuff for bci_align_segments (edge2)...
3820 * uses: bci_stem_common
3821 * bci_align_segments
3824 const unsigned char FPGM(bci_stem_bound
) [] =
3835 ROLL
, /* s: edge[-1] cur_len edge edge2 */
3838 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3842 WS
, /* s: edge[-1] cur_len edge edge2 */
3844 SHPIX
, /* edge2 = edge + cur_len */
3846 SWAP
, /* s: edge edge[-1] */
3848 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3853 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3854 GT
, /* edge_pos < edge[-1]_pos */
3857 ALIGNRP
, /* align `edge' to `edge[-1]' */
3860 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3865 SZP1
, /* set zp1 to normal zone 1 */
3871 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3883 * bci_action_stem_bound
3884 * bci_action_stem_bound_serif
3885 * bci_action_stem_bound_round
3886 * bci_action_stem_bound_round_serif
3888 * Higher-level routines for calling `bci_stem_bound'.
3891 const unsigned char FPGM(bci_action_stem_bound
) [] =
3895 bci_action_stem_bound
,
3908 const unsigned char FPGM(bci_action_stem_bound_serif
) [] =
3912 bci_action_stem_bound_serif
,
3925 const unsigned char FPGM(bci_action_stem_bound_round
) [] =
3929 bci_action_stem_bound_round
,
3942 const unsigned char FPGM(bci_action_stem_bound_round_serif
) [] =
3946 bci_action_stem_bound_round_serif
,
3963 * Handle the STEM action to align two edges of a stem.
3965 * See `bci_stem_bound' for more details.
3967 * in: edge2_is_serif
3969 * edge_point (in twilight zone)
3970 * edge2_point (in twilight zone)
3971 * ... stuff for bci_align_segments (edge) ...
3972 * ... stuff for bci_align_segments (edge2)...
3979 * uses: bci_stem_common
3980 * bci_align_segments
3983 const unsigned char FPGM(bci_stem
) [] =
3995 SWAP
, /* s: cur_len edge2 */
3998 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
4002 WS
, /* s: cur_len edge2 */
4004 SHPIX
, /* edge2 = edge + cur_len */
4009 SZP1
, /* set zp1 to normal zone 1 */
4015 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
4027 * bci_action_stem_serif
4028 * bci_action_stem_round
4029 * bci_action_stem_round_serif
4031 * Higher-level routines for calling `bci_stem'.
4034 const unsigned char FPGM(bci_action_stem
) [] =
4051 const unsigned char FPGM(bci_action_stem_serif
) [] =
4055 bci_action_stem_serif
,
4068 const unsigned char FPGM(bci_action_stem_round
) [] =
4072 bci_action_stem_round
,
4085 const unsigned char FPGM(bci_action_stem_round_serif
) [] =
4089 bci_action_stem_round_serif
,
4106 * Handle the LINK action to link an edge to another one.
4110 * base_point (in twilight zone)
4111 * stem_point (in twilight zone)
4112 * ... stuff for bci_align_segments (base) ...
4114 * uses: func[sal_stem_width_function]
4115 * bci_align_segments
4118 const unsigned char FPGM(bci_link
) [] =
4127 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4135 DUP
, /* s: stem is_round is_serif stem base base */
4136 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
4138 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
4141 sal_stem_width_function
,
4143 CALL
, /* s: stem new_dist */
4147 ALIGNRP
, /* align `stem_point' with `base_point' */
4149 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
4151 SHPIX
, /* stem_point = base_point + new_dist */
4156 SZP1
, /* set zp1 to normal zone 1 */
4166 * bci_action_link_serif
4167 * bci_action_link_round
4168 * bci_action_link_round_serif
4170 * Higher-level routines for calling `bci_link'.
4173 const unsigned char FPGM(bci_action_link
) [] =
4190 const unsigned char FPGM(bci_action_link_serif
) [] =
4194 bci_action_link_serif
,
4207 const unsigned char FPGM(bci_action_link_round
) [] =
4211 bci_action_link_round
,
4224 const unsigned char FPGM(bci_action_link_round_serif
) [] =
4228 bci_action_link_round_serif
,
4245 * Handle the ANCHOR action to align two edges
4246 * and to set the edge anchor.
4248 * The code after computing `cur_len' to shift `edge' and `edge2'
4249 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
4252 * if cur_len < = 64:
4259 * org_center = edge_orig + org_len / 2
4260 * cur_pos1 = ROUND(org_center)
4262 * error1 = ABS(org_center - (cur_pos1 - u_off))
4263 * error2 = ABS(org_center - (cur_pos1 + d_off))
4264 * if (error1 < error2):
4265 * cur_pos1 = cur_pos1 - u_off
4267 * cur_pos1 = cur_pos1 + d_off
4269 * edge = cur_pos1 - cur_len / 2
4270 * edge2 = edge + cur_len
4273 * edge = ROUND(edge_orig)
4275 * in: edge2_is_serif
4277 * edge_point (in twilight zone)
4278 * edge2_point (in twilight zone)
4279 * ... stuff for bci_align_segments (edge) ...
4286 * uses: func[sal_stem_width_function]
4288 * bci_align_segments
4292 #define sal_u_off sal_temp1
4294 #define sal_d_off sal_temp2
4296 #define sal_org_len sal_temp3
4298 const unsigned char FPGM(bci_anchor
) [] =
4305 /* store anchor point number in `sal_anchor' */
4310 WS
, /* sal_anchor = edge_point */
4314 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4322 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
4323 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4325 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
4333 sal_stem_width_function
,
4335 CALL
, /* s: edge2 edge cur_len */
4340 LT
, /* cur_len < 96 */
4345 LTEQ
, /* cur_len <= 64 */
4363 SWAP
, /* s: edge2 cur_len edge */
4364 DUP
, /* s: edge2 cur_len edge edge */
4371 ADD
, /* s: edge2 cur_len edge org_center */
4376 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
4381 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4388 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4395 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4397 LT
, /* error1 < error2 */
4402 SUB
, /* cur_pos1 = cur_pos1 - u_off */
4408 ADD
, /* cur_pos1 = cur_pos1 + d_off */
4409 EIF
, /* s: edge2 cur_len edge cur_pos1 */
4415 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4419 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4422 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
4424 SWAP
, /* s: cur_len edge2 */
4426 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
4428 SHPIX
, /* edge2 = edge1 + cur_len */
4431 POP
, /* s: edge2 edge */
4439 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4442 SHPIX
, /* edge = round(edge_orig) */
4444 /* clean up stack */
4451 SZP1
, /* set zp1 to normal zone 1 */
4461 * bci_action_anchor_serif
4462 * bci_action_anchor_round
4463 * bci_action_anchor_round_serif
4465 * Higher-level routines for calling `bci_anchor'.
4468 const unsigned char FPGM(bci_action_anchor
) [] =
4485 const unsigned char FPGM(bci_action_anchor_serif
) [] =
4489 bci_action_anchor_serif
,
4502 const unsigned char FPGM(bci_action_anchor_round
) [] =
4506 bci_action_anchor_round
,
4519 const unsigned char FPGM(bci_action_anchor_round_serif
) [] =
4523 bci_action_anchor_round_serif
,
4538 * bci_action_blue_anchor
4540 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4541 * and to set the edge anchor.
4543 * in: anchor_point (in twilight zone)
4545 * edge_point (in twilight zone)
4546 * ... stuff for bci_align_segments (edge) ...
4550 * uses: bci_action_blue
4553 const unsigned char FPGM(bci_action_blue_anchor
) [] =
4557 bci_action_blue_anchor
,
4560 /* store anchor point number in `sal_anchor' */
4578 * Handle the BLUE action to align an edge with a blue zone.
4581 * edge_point (in twilight zone)
4582 * ... stuff for bci_align_segments (edge) ...
4584 * uses: bci_align_segments
4587 const unsigned char FPGM(bci_action_blue
) [] =
4596 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4598 /* move `edge_point' to `blue_cvt_idx' position; */
4599 /* note that we can't use MIAP since this would modify */
4600 /* the twilight point's original coordinates also */
4604 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4606 GC_cur
, /* s: new_pos edge edge_pos */
4609 SUB
, /* s: edge (new_pos - edge_pos) */
4615 SZP1
, /* set zp1 to normal zone 1 */
4626 * Common code for bci_action_serif routines.
4629 const unsigned char FPGM(bci_serif_common
) [] =
4638 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4645 MINDEX
, /* s: [...] serif serif serif serif base */
4647 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
4650 ALIGNRP
, /* align `serif_point' with `base_point' */
4651 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
4661 * Move an edge if necessary to stay within a lower bound.
4666 * uses: bci_align_segments
4669 const unsigned char FPGM(bci_lower_bound
) [] =
4676 SWAP
, /* s: edge bound */
4678 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4683 GC_cur
, /* s: edge bound_pos edge_pos */
4684 GT
, /* edge_pos < bound_pos */
4687 ALIGNRP
, /* align `edge' to `bound' */
4690 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4695 SZP1
, /* set zp1 to normal zone 1 */
4706 * Move an edge if necessary to stay within an upper bound.
4711 * uses: bci_align_segments
4714 const unsigned char FPGM(bci_upper_bound
) [] =
4721 SWAP
, /* s: edge bound */
4723 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4728 GC_cur
, /* s: edge bound_pos edge_pos */
4729 LT
, /* edge_pos > bound_pos */
4732 ALIGNRP
, /* align `edge' to `bound' */
4735 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4740 SZP1
, /* set zp1 to normal zone 1 */
4749 * bci_upper_lower_bound
4751 * Move an edge if necessary to stay within a lower and lower bound.
4757 * uses: bci_align_segments
4760 const unsigned char FPGM(bci_upper_lower_bound
) [] =
4764 bci_upper_lower_bound
,
4767 SWAP
, /* s: upper serif lower */
4769 MDAP_noround
, /* set rp0 and rp1 to `lower' */
4774 GC_cur
, /* s: upper serif lower_pos serif_pos */
4775 GT
, /* serif_pos < lower_pos */
4778 ALIGNRP
, /* align `serif' to `lower' */
4781 SWAP
, /* s: serif upper */
4783 MDAP_noround
, /* set rp0 and rp1 to `upper' */
4788 GC_cur
, /* s: serif upper_pos serif_pos */
4789 LT
, /* serif_pos > upper_pos */
4792 ALIGNRP
, /* align `serif' to `upper' */
4795 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4800 SZP1
, /* set zp1 to normal zone 1 */
4811 * Handle the SERIF action to align a serif with its base.
4813 * in: serif_point (in twilight zone)
4814 * base_point (in twilight zone)
4815 * ... stuff for bci_align_segments (serif) ...
4817 * uses: bci_serif_common
4818 * bci_align_segments
4821 const unsigned char FPGM(bci_action_serif
) [] =
4832 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4837 SZP1
, /* set zp1 to normal zone 1 */
4846 * bci_action_serif_lower_bound
4848 * Handle the SERIF action to align a serif with its base, then moving it
4849 * again if necessary to stay within a lower bound.
4851 * in: serif_point (in twilight zone)
4852 * base_point (in twilight zone)
4853 * edge[-1] (in twilight zone)
4854 * ... stuff for bci_align_segments (serif) ...
4856 * uses: bci_serif_common
4860 const unsigned char FPGM(bci_action_serif_lower_bound
) [] =
4864 bci_action_serif_lower_bound
,
4881 * bci_action_serif_upper_bound
4883 * Handle the SERIF action to align a serif with its base, then moving it
4884 * again if necessary to stay within an upper bound.
4886 * in: serif_point (in twilight zone)
4887 * base_point (in twilight zone)
4888 * edge[1] (in twilight zone)
4889 * ... stuff for bci_align_segments (serif) ...
4891 * uses: bci_serif_common
4895 const unsigned char FPGM(bci_action_serif_upper_bound
) [] =
4899 bci_action_serif_upper_bound
,
4916 * bci_action_serif_upper_lower_bound
4918 * Handle the SERIF action to align a serif with its base, then moving it
4919 * again if necessary to stay within a lower and upper bound.
4921 * in: serif_point (in twilight zone)
4922 * base_point (in twilight zone)
4923 * edge[-1] (in twilight zone)
4924 * edge[1] (in twilight zone)
4925 * ... stuff for bci_align_segments (serif) ...
4927 * uses: bci_serif_common
4928 * bci_upper_lower_bound
4931 const unsigned char FPGM(bci_action_serif_upper_lower_bound
) [] =
4935 bci_action_serif_upper_lower_bound
,
4940 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4947 bci_upper_lower_bound
,
4956 * bci_serif_anchor_common
4958 * Common code for bci_action_serif_anchor routines.
4965 const unsigned char FPGM(bci_serif_anchor_common
) [] =
4969 bci_serif_anchor_common
,
4974 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4980 WS
, /* sal_anchor = edge_point */
4990 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4993 SHPIX
, /* edge = round(edge_orig) */
5001 * bci_action_serif_anchor
5003 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5006 * in: edge_point (in twilight zone)
5007 * ... stuff for bci_align_segments (edge) ...
5009 * uses: bci_serif_anchor_common
5010 * bci_align_segments
5013 const unsigned char FPGM(bci_action_serif_anchor
) [] =
5017 bci_action_serif_anchor
,
5021 bci_serif_anchor_common
,
5024 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5029 SZP1
, /* set zp1 to normal zone 1 */
5038 * bci_action_serif_anchor_lower_bound
5040 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5041 * anchor, then moving it again if necessary to stay within a lower
5044 * in: edge_point (in twilight zone)
5045 * edge[-1] (in twilight zone)
5046 * ... stuff for bci_align_segments (edge) ...
5048 * uses: bci_serif_anchor_common
5052 const unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
5056 bci_action_serif_anchor_lower_bound
,
5060 bci_serif_anchor_common
,
5073 * bci_action_serif_anchor_upper_bound
5075 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5076 * anchor, then moving it again if necessary to stay within an upper
5079 * in: edge_point (in twilight zone)
5080 * edge[1] (in twilight zone)
5081 * ... stuff for bci_align_segments (edge) ...
5083 * uses: bci_serif_anchor_common
5087 const unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
5091 bci_action_serif_anchor_upper_bound
,
5095 bci_serif_anchor_common
,
5108 * bci_action_serif_anchor_upper_lower_bound
5110 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
5111 * anchor, then moving it again if necessary to stay within a lower and
5114 * in: edge_point (in twilight zone)
5115 * edge[-1] (in twilight zone)
5116 * edge[1] (in twilight zone)
5117 * ... stuff for bci_align_segments (edge) ...
5119 * uses: bci_serif_anchor_common
5120 * bci_upper_lower_bound
5123 const unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound
) [] =
5127 bci_action_serif_anchor_upper_lower_bound
,
5131 bci_serif_anchor_common
,
5135 bci_upper_lower_bound
,
5144 * bci_serif_link1_common
5146 * Common code for bci_action_serif_link1 routines.
5149 const unsigned char FPGM(bci_serif_link1_common
) [] =
5153 bci_serif_link1_common
,
5158 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
5162 CINDEX
, /* s: [...] after edge before after */
5165 CINDEX
, /* s: [...] after edge before after before */
5169 EQ
, /* after_orig_pos == before_orig_pos */
5170 IF
, /* s: [...] after edge before */
5171 MDAP_noround
, /* set rp0 and rp1 to `before' */
5173 ALIGNRP
, /* align `edge' with `before' */
5178 /* we have to execute `a*b/c', with b/c very near to 1: */
5179 /* to avoid overflow while retaining precision, */
5180 /* we transform this to `a + a * (b-c)/c' */
5184 CINDEX
, /* s: [...] after edge before edge */
5187 CINDEX
, /* s: [...] after edge before edge before */
5188 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
5193 CINDEX
, /* s: [...] after edge before a a after */
5196 CINDEX
, /* s: [...] after edge before a a after before */
5197 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
5201 CINDEX
, /* s: [...] after edge before a a c after */
5204 CINDEX
, /* s: [...] after edge before a a c after before */
5205 MD_cur
, /* b = after_pos - before_pos */
5209 CINDEX
, /* s: [...] after edge before a a c b c */
5218 MUL
, /* (b-c) in 16.16 format */
5223 DIV
, /* s: [...] after edge before a a (b-c)/c */
5225 POP
, /* avoid division by zero */
5228 MUL
, /* a * (b-c)/c * 2^10 */
5229 DIV_BY_1024
, /* a * (b-c)/c */
5233 MDAP_noround
, /* set rp0 and rp1 to `before' */
5234 SWAP
, /* s: [...] after a*b/c edge */
5237 ALIGNRP
, /* align `edge' with `before' */
5239 SHPIX
, /* shift `edge' by `a*b/c' */
5241 SWAP
, /* s: [...] edge after */
5251 * bci_action_serif_link1
5253 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5256 * in: before_point (in twilight zone)
5257 * edge_point (in twilight zone)
5258 * after_point (in twilight zone)
5259 * ... stuff for bci_align_segments (edge) ...
5261 * uses: bci_serif_link1_common
5262 * bci_align_segments
5265 const unsigned char FPGM(bci_action_serif_link1
) [] =
5269 bci_action_serif_link1
,
5273 bci_serif_link1_common
,
5276 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5281 SZP1
, /* set zp1 to normal zone 1 */
5290 * bci_action_serif_link1_lower_bound
5292 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5293 * before and after. Additionally, move the serif again if necessary to
5294 * stay within a lower bound.
5296 * in: before_point (in twilight zone)
5297 * edge_point (in twilight zone)
5298 * after_point (in twilight zone)
5299 * edge[-1] (in twilight zone)
5300 * ... stuff for bci_align_segments (edge) ...
5302 * uses: bci_serif_link1_common
5306 const unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
5310 bci_action_serif_link1_lower_bound
,
5314 bci_serif_link1_common
,
5327 * bci_action_serif_link1_upper_bound
5329 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5330 * before and after. Additionally, move the serif again if necessary to
5331 * stay within an upper bound.
5333 * in: before_point (in twilight zone)
5334 * edge_point (in twilight zone)
5335 * after_point (in twilight zone)
5336 * edge[1] (in twilight zone)
5337 * ... stuff for bci_align_segments (edge) ...
5339 * uses: bci_serif_link1_common
5343 const unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
5347 bci_action_serif_link1_upper_bound
,
5351 bci_serif_link1_common
,
5364 * bci_action_serif_link1_upper_lower_bound
5366 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5367 * before and after. Additionally, move the serif again if necessary to
5368 * stay within a lower and upper bound.
5370 * in: before_point (in twilight zone)
5371 * edge_point (in twilight zone)
5372 * after_point (in twilight zone)
5373 * edge[-1] (in twilight zone)
5374 * edge[1] (in twilight zone)
5375 * ... stuff for bci_align_segments (edge) ...
5377 * uses: bci_serif_link1_common
5378 * bci_upper_lower_bound
5381 const unsigned char FPGM(bci_action_serif_link1_upper_lower_bound
) [] =
5385 bci_action_serif_link1_upper_lower_bound
,
5389 bci_serif_link1_common
,
5393 bci_upper_lower_bound
,
5402 * bci_serif_link2_common
5404 * Common code for bci_action_serif_link2 routines.
5409 const unsigned char FPGM(bci_serif_link2_common
) [] =
5413 bci_serif_link2_common
,
5418 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
5420 DUP
, /* s: [...] edge edge */
5424 DUP
, /* s: [...] edge edge anchor anchor */
5425 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
5434 DIV_BY_2
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5439 ALIGNRP
, /* align `edge' with `sal_anchor' */
5441 SHPIX
, /* shift `edge' by `delta' */
5449 * bci_action_serif_link2
5451 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5453 * in: edge_point (in twilight zone)
5454 * ... stuff for bci_align_segments (edge) ...
5456 * uses: bci_serif_link2_common
5457 * bci_align_segments
5460 const unsigned char FPGM(bci_action_serif_link2
) [] =
5464 bci_action_serif_link2
,
5468 bci_serif_link2_common
,
5471 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5476 SZP1
, /* set zp1 to normal zone 1 */
5485 * bci_action_serif_link2_lower_bound
5487 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5488 * Additionally, move the serif again if necessary to stay within a lower
5491 * in: edge_point (in twilight zone)
5492 * edge[-1] (in twilight zone)
5493 * ... stuff for bci_align_segments (edge) ...
5495 * uses: bci_serif_link2_common
5499 const unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
5503 bci_action_serif_link2_lower_bound
,
5507 bci_serif_link2_common
,
5520 * bci_action_serif_link2_upper_bound
5522 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5523 * Additionally, move the serif again if necessary to stay within an upper
5526 * in: edge_point (in twilight zone)
5527 * edge[1] (in twilight zone)
5528 * ... stuff for bci_align_segments (edge) ...
5530 * uses: bci_serif_link2_common
5534 const unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
5538 bci_action_serif_link2_upper_bound
,
5542 bci_serif_link2_common
,
5555 * bci_action_serif_link2_upper_lower_bound
5557 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5558 * Additionally, move the serif again if necessary to stay within a lower
5561 * in: edge_point (in twilight zone)
5562 * edge[-1] (in twilight zone)
5563 * edge[1] (in twilight zone)
5564 * ... stuff for bci_align_segments (edge) ...
5566 * uses: bci_serif_link2_common
5567 * bci_upper_lower_bound
5570 const unsigned char FPGM(bci_action_serif_link2_upper_lower_bound
) [] =
5574 bci_action_serif_link2_upper_lower_bound
,
5578 bci_serif_link2_common
,
5582 bci_upper_lower_bound
,
5593 * This is the top-level glyph hinting function which parses the arguments
5594 * on the stack and calls subroutines.
5596 * in: action_0_func_idx
5602 * CVT: cvtl_is_subglyph
5603 * cvtl_use_strong_functions
5606 * sal: sal_stem_width_function
5608 * uses: bci_action_ip_before
5609 * bci_action_ip_after
5611 * bci_action_ip_between
5613 * bci_action_adjust_bound
5614 * bci_action_adjust_bound_serif
5615 * bci_action_adjust_bound_round
5616 * bci_action_adjust_bound_round_serif
5618 * bci_action_stem_bound
5619 * bci_action_stem_bound_serif
5620 * bci_action_stem_bound_round
5621 * bci_action_stem_bound_round_serif
5624 * bci_action_link_serif
5625 * bci_action_link_round
5626 * bci_action_link_round_serif
5629 * bci_action_anchor_serif
5630 * bci_action_anchor_round
5631 * bci_action_anchor_round_serif
5633 * bci_action_blue_anchor
5636 * bci_action_adjust_serif
5637 * bci_action_adjust_round
5638 * bci_action_adjust_round_serif
5641 * bci_action_stem_serif
5642 * bci_action_stem_round
5643 * bci_action_stem_round_serif
5648 * bci_action_serif_lower_bound
5649 * bci_action_serif_upper_bound
5650 * bci_action_serif_upper_lower_bound
5652 * bci_action_serif_anchor
5653 * bci_action_serif_anchor_lower_bound
5654 * bci_action_serif_anchor_upper_bound
5655 * bci_action_serif_anchor_upper_lower_bound
5657 * bci_action_serif_link1
5658 * bci_action_serif_link1_lower_bound
5659 * bci_action_serif_link1_upper_bound
5660 * bci_action_serif_link1_upper_lower_bound
5662 * bci_action_serif_link2
5663 * bci_action_serif_link2_lower_bound
5664 * bci_action_serif_link2_upper_bound
5665 * bci_action_serif_link2_upper_lower_bound
5668 const unsigned char FPGM(bci_hint_glyph
) [] =
5675 /* set up stem width function based on flag in CVT */
5677 sal_stem_width_function
,
5678 bci_strong_stem_width
,
5679 bci_smooth_stem_width
,
5680 cvtl_use_strong_functions
,
5693 /* loop until all data on stack is used */
5702 JROT
, /* goto start_loop */
5707 SZP2
, /* set zp2 to normal zone 1 */
5718 #define COPY_FPGM(func_name) \
5721 memcpy(bufp, fpgm_ ## func_name, \
5722 sizeof (fpgm_ ## func_name)); \
5723 bufp += sizeof (fpgm_ ## func_name); \
5727 TA_table_build_fpgm(FT_Byte
** fpgm
,
5732 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5733 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5741 /* for compatibility with dumb bytecode interpreters or analyzers, */
5742 /* FDEFs are stored in ascending index order, without holes -- */
5743 /* note that some FDEFs are not always needed */
5744 /* (depending on options of `TTFautohint'), */
5745 /* but implementing dynamic FDEF indices would be a lot of work */
5747 buf_len
= sizeof (FPGM(bci_align_top_a
))
5748 + (font
->increase_x_height
5749 ? (sizeof (FPGM(bci_align_top_b1a
))
5751 + sizeof (FPGM(bci_align_top_b1b
)))
5752 : sizeof (FPGM(bci_align_top_b2
)))
5753 + sizeof (FPGM(bci_align_top_c
))
5754 + sizeof (FPGM(bci_round
))
5755 + sizeof (FPGM(bci_smooth_stem_width
))
5756 + sizeof (FPGM(bci_get_best_width
))
5757 + sizeof (FPGM(bci_strong_stem_width_a
))
5759 + sizeof (FPGM(bci_strong_stem_width_b
))
5760 + sizeof (FPGM(bci_loop_do
))
5761 + sizeof (FPGM(bci_loop
))
5762 + sizeof (FPGM(bci_cvt_rescale
))
5763 + sizeof (FPGM(bci_cvt_rescale_range
))
5764 + sizeof (FPGM(bci_vwidth_data_store
))
5765 + sizeof (FPGM(bci_smooth_blue_round
))
5766 + sizeof (FPGM(bci_strong_blue_round
))
5767 + sizeof (FPGM(bci_blue_round_range
))
5768 + sizeof (FPGM(bci_decrement_component_counter
))
5769 + sizeof (FPGM(bci_get_point_extrema
))
5770 + sizeof (FPGM(bci_nibbles
))
5771 + sizeof (FPGM(bci_number_set_is_element
))
5772 + sizeof (FPGM(bci_number_set_is_element2
))
5774 + sizeof (FPGM(bci_create_segment
))
5775 + sizeof (FPGM(bci_create_segments_a
))
5777 + sizeof (FPGM(bci_create_segments_b
))
5778 + (font
->control_data_head
!= 0
5779 ? sizeof (FPGM(bci_create_segments_c
))
5781 + sizeof (FPGM(bci_create_segments_d
))
5783 + sizeof (FPGM(bci_create_segments_0
))
5784 + sizeof (FPGM(bci_create_segments_1
))
5785 + sizeof (FPGM(bci_create_segments_2
))
5786 + sizeof (FPGM(bci_create_segments_3
))
5787 + sizeof (FPGM(bci_create_segments_4
))
5788 + sizeof (FPGM(bci_create_segments_5
))
5789 + sizeof (FPGM(bci_create_segments_6
))
5790 + sizeof (FPGM(bci_create_segments_7
))
5791 + sizeof (FPGM(bci_create_segments_8
))
5792 + sizeof (FPGM(bci_create_segments_9
))
5794 + sizeof (FPGM(bci_deltap1
))
5795 + sizeof (FPGM(bci_deltap2
))
5796 + sizeof (FPGM(bci_deltap3
))
5798 + sizeof (FPGM(bci_create_segments_composite_a
))
5800 + sizeof (FPGM(bci_create_segments_composite_b
))
5801 + (font
->control_data_head
!= 0
5802 ? sizeof (FPGM(bci_create_segments_composite_c
))
5804 + sizeof (FPGM(bci_create_segments_composite_d
))
5806 + sizeof (FPGM(bci_create_segments_composite_0
))
5807 + sizeof (FPGM(bci_create_segments_composite_1
))
5808 + sizeof (FPGM(bci_create_segments_composite_2
))
5809 + sizeof (FPGM(bci_create_segments_composite_3
))
5810 + sizeof (FPGM(bci_create_segments_composite_4
))
5811 + sizeof (FPGM(bci_create_segments_composite_5
))
5812 + sizeof (FPGM(bci_create_segments_composite_6
))
5813 + sizeof (FPGM(bci_create_segments_composite_7
))
5814 + sizeof (FPGM(bci_create_segments_composite_8
))
5815 + sizeof (FPGM(bci_create_segments_composite_9
))
5817 + sizeof (FPGM(bci_align_point
))
5818 + sizeof (FPGM(bci_align_segment
))
5819 + sizeof (FPGM(bci_align_segments
))
5821 + sizeof (FPGM(bci_scale_contour
))
5822 + sizeof (FPGM(bci_scale_glyph
))
5823 + sizeof (FPGM(bci_scale_composite_glyph
))
5824 + sizeof (FPGM(bci_shift_contour
))
5825 + sizeof (FPGM(bci_shift_subglyph_a
))
5826 + (font
->control_data_head
!= 0
5827 ? sizeof (FPGM(bci_shift_subglyph_b
))
5829 + sizeof (FPGM(bci_shift_subglyph_c
))
5831 + sizeof (FPGM(bci_ip_outer_align_point
))
5832 + sizeof (FPGM(bci_ip_on_align_points
))
5833 + sizeof (FPGM(bci_ip_between_align_point
))
5834 + sizeof (FPGM(bci_ip_between_align_points
))
5836 + sizeof (FPGM(bci_adjust_common
))
5837 + sizeof (FPGM(bci_stem_common
))
5838 + sizeof (FPGM(bci_serif_common
))
5839 + sizeof (FPGM(bci_serif_anchor_common
))
5840 + sizeof (FPGM(bci_serif_link1_common
))
5841 + sizeof (FPGM(bci_serif_link2_common
))
5843 + sizeof (FPGM(bci_lower_bound
))
5844 + sizeof (FPGM(bci_upper_bound
))
5845 + sizeof (FPGM(bci_upper_lower_bound
))
5847 + sizeof (FPGM(bci_adjust_bound
))
5848 + sizeof (FPGM(bci_stem_bound
))
5849 + sizeof (FPGM(bci_link
))
5850 + sizeof (FPGM(bci_anchor
))
5851 + sizeof (FPGM(bci_adjust
))
5852 + sizeof (FPGM(bci_stem
))
5854 + sizeof (FPGM(bci_action_ip_before
))
5855 + sizeof (FPGM(bci_action_ip_after
))
5856 + sizeof (FPGM(bci_action_ip_on
))
5857 + sizeof (FPGM(bci_action_ip_between
))
5859 + sizeof (FPGM(bci_action_blue
))
5860 + sizeof (FPGM(bci_action_blue_anchor
))
5862 + sizeof (FPGM(bci_action_anchor
))
5863 + sizeof (FPGM(bci_action_anchor_serif
))
5864 + sizeof (FPGM(bci_action_anchor_round
))
5865 + sizeof (FPGM(bci_action_anchor_round_serif
))
5867 + sizeof (FPGM(bci_action_adjust
))
5868 + sizeof (FPGM(bci_action_adjust_serif
))
5869 + sizeof (FPGM(bci_action_adjust_round
))
5870 + sizeof (FPGM(bci_action_adjust_round_serif
))
5871 + sizeof (FPGM(bci_action_adjust_bound
))
5872 + sizeof (FPGM(bci_action_adjust_bound_serif
))
5873 + sizeof (FPGM(bci_action_adjust_bound_round
))
5874 + sizeof (FPGM(bci_action_adjust_bound_round_serif
))
5876 + sizeof (FPGM(bci_action_link
))
5877 + sizeof (FPGM(bci_action_link_serif
))
5878 + sizeof (FPGM(bci_action_link_round
))
5879 + sizeof (FPGM(bci_action_link_round_serif
))
5881 + sizeof (FPGM(bci_action_stem
))
5882 + sizeof (FPGM(bci_action_stem_serif
))
5883 + sizeof (FPGM(bci_action_stem_round
))
5884 + sizeof (FPGM(bci_action_stem_round_serif
))
5885 + sizeof (FPGM(bci_action_stem_bound
))
5886 + sizeof (FPGM(bci_action_stem_bound_serif
))
5887 + sizeof (FPGM(bci_action_stem_bound_round
))
5888 + sizeof (FPGM(bci_action_stem_bound_round_serif
))
5890 + sizeof (FPGM(bci_action_serif
))
5891 + sizeof (FPGM(bci_action_serif_lower_bound
))
5892 + sizeof (FPGM(bci_action_serif_upper_bound
))
5893 + sizeof (FPGM(bci_action_serif_upper_lower_bound
))
5895 + sizeof (FPGM(bci_action_serif_anchor
))
5896 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
5897 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
5898 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound
))
5900 + sizeof (FPGM(bci_action_serif_link1
))
5901 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
5902 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
5903 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound
))
5905 + sizeof (FPGM(bci_action_serif_link2
))
5906 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
5907 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
5908 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound
))
5910 + sizeof (FPGM(bci_hint_glyph
));
5912 /* buffer length must be a multiple of four */
5913 len
= (buf_len
+ 3) & ~3;
5914 buf
= (FT_Byte
*)malloc(len
);
5916 return FT_Err_Out_Of_Memory
;
5918 /* pad end of buffer with zeros */
5919 buf
[len
- 1] = 0x00;
5920 buf
[len
- 2] = 0x00;
5921 buf
[len
- 3] = 0x00;
5923 /* copy font program into buffer and fill in the missing variables */
5926 COPY_FPGM(bci_align_top_a
);
5927 if (font
->increase_x_height
)
5929 COPY_FPGM(bci_align_top_b1a
);
5930 *(bufp
++) = HIGH(font
->increase_x_height
);
5931 *(bufp
++) = LOW(font
->increase_x_height
);
5932 COPY_FPGM(bci_align_top_b1b
);
5935 COPY_FPGM(bci_align_top_b2
);
5936 COPY_FPGM(bci_align_top_c
);
5938 COPY_FPGM(bci_round
);
5939 COPY_FPGM(bci_smooth_stem_width
);
5940 COPY_FPGM(bci_get_best_width
);
5941 COPY_FPGM(bci_strong_stem_width_a
);
5942 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5943 COPY_FPGM(bci_strong_stem_width_b
);
5944 COPY_FPGM(bci_loop_do
);
5945 COPY_FPGM(bci_loop
);
5946 COPY_FPGM(bci_cvt_rescale
);
5947 COPY_FPGM(bci_cvt_rescale_range
);
5948 COPY_FPGM(bci_vwidth_data_store
);
5949 COPY_FPGM(bci_smooth_blue_round
);
5950 COPY_FPGM(bci_strong_blue_round
);
5951 COPY_FPGM(bci_blue_round_range
);
5952 COPY_FPGM(bci_decrement_component_counter
);
5953 COPY_FPGM(bci_get_point_extrema
);
5954 COPY_FPGM(bci_nibbles
);
5955 COPY_FPGM(bci_number_set_is_element
);
5956 COPY_FPGM(bci_number_set_is_element2
);
5958 COPY_FPGM(bci_create_segment
);
5959 COPY_FPGM(bci_create_segments_a
);
5960 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5961 COPY_FPGM(bci_create_segments_b
);
5962 if (font
->control_data_head
)
5963 COPY_FPGM(bci_create_segments_c
);
5964 COPY_FPGM(bci_create_segments_d
);
5966 COPY_FPGM(bci_create_segments_0
);
5967 COPY_FPGM(bci_create_segments_1
);
5968 COPY_FPGM(bci_create_segments_2
);
5969 COPY_FPGM(bci_create_segments_3
);
5970 COPY_FPGM(bci_create_segments_4
);
5971 COPY_FPGM(bci_create_segments_5
);
5972 COPY_FPGM(bci_create_segments_6
);
5973 COPY_FPGM(bci_create_segments_7
);
5974 COPY_FPGM(bci_create_segments_8
);
5975 COPY_FPGM(bci_create_segments_9
);
5977 COPY_FPGM(bci_deltap1
);
5978 COPY_FPGM(bci_deltap2
);
5979 COPY_FPGM(bci_deltap3
);
5981 COPY_FPGM(bci_create_segments_composite_a
);
5982 *(bufp
++) = (unsigned char)data
->num_used_styles
;
5983 COPY_FPGM(bci_create_segments_composite_b
);
5984 if (font
->control_data_head
)
5985 COPY_FPGM(bci_create_segments_composite_c
);
5986 COPY_FPGM(bci_create_segments_composite_d
);
5988 COPY_FPGM(bci_create_segments_composite_0
);
5989 COPY_FPGM(bci_create_segments_composite_1
);
5990 COPY_FPGM(bci_create_segments_composite_2
);
5991 COPY_FPGM(bci_create_segments_composite_3
);
5992 COPY_FPGM(bci_create_segments_composite_4
);
5993 COPY_FPGM(bci_create_segments_composite_5
);
5994 COPY_FPGM(bci_create_segments_composite_6
);
5995 COPY_FPGM(bci_create_segments_composite_7
);
5996 COPY_FPGM(bci_create_segments_composite_8
);
5997 COPY_FPGM(bci_create_segments_composite_9
);
5999 COPY_FPGM(bci_align_point
);
6000 COPY_FPGM(bci_align_segment
);
6001 COPY_FPGM(bci_align_segments
);
6003 COPY_FPGM(bci_scale_contour
);
6004 COPY_FPGM(bci_scale_glyph
);
6005 COPY_FPGM(bci_scale_composite_glyph
);
6006 COPY_FPGM(bci_shift_contour
);
6007 COPY_FPGM(bci_shift_subglyph_a
);
6008 if (font
->control_data_head
)
6009 COPY_FPGM(bci_shift_subglyph_b
);
6010 COPY_FPGM(bci_shift_subglyph_c
);
6012 COPY_FPGM(bci_ip_outer_align_point
);
6013 COPY_FPGM(bci_ip_on_align_points
);
6014 COPY_FPGM(bci_ip_between_align_point
);
6015 COPY_FPGM(bci_ip_between_align_points
);
6017 COPY_FPGM(bci_adjust_common
);
6018 COPY_FPGM(bci_stem_common
);
6019 COPY_FPGM(bci_serif_common
);
6020 COPY_FPGM(bci_serif_anchor_common
);
6021 COPY_FPGM(bci_serif_link1_common
);
6022 COPY_FPGM(bci_serif_link2_common
);
6024 COPY_FPGM(bci_lower_bound
);
6025 COPY_FPGM(bci_upper_bound
);
6026 COPY_FPGM(bci_upper_lower_bound
);
6028 COPY_FPGM(bci_adjust_bound
);
6029 COPY_FPGM(bci_stem_bound
);
6030 COPY_FPGM(bci_link
);
6031 COPY_FPGM(bci_anchor
);
6032 COPY_FPGM(bci_adjust
);
6033 COPY_FPGM(bci_stem
);
6035 COPY_FPGM(bci_action_ip_before
);
6036 COPY_FPGM(bci_action_ip_after
);
6037 COPY_FPGM(bci_action_ip_on
);
6038 COPY_FPGM(bci_action_ip_between
);
6040 COPY_FPGM(bci_action_blue
);
6041 COPY_FPGM(bci_action_blue_anchor
);
6043 COPY_FPGM(bci_action_anchor
);
6044 COPY_FPGM(bci_action_anchor_serif
);
6045 COPY_FPGM(bci_action_anchor_round
);
6046 COPY_FPGM(bci_action_anchor_round_serif
);
6048 COPY_FPGM(bci_action_adjust
);
6049 COPY_FPGM(bci_action_adjust_serif
);
6050 COPY_FPGM(bci_action_adjust_round
);
6051 COPY_FPGM(bci_action_adjust_round_serif
);
6052 COPY_FPGM(bci_action_adjust_bound
);
6053 COPY_FPGM(bci_action_adjust_bound_serif
);
6054 COPY_FPGM(bci_action_adjust_bound_round
);
6055 COPY_FPGM(bci_action_adjust_bound_round_serif
);
6057 COPY_FPGM(bci_action_link
);
6058 COPY_FPGM(bci_action_link_serif
);
6059 COPY_FPGM(bci_action_link_round
);
6060 COPY_FPGM(bci_action_link_round_serif
);
6062 COPY_FPGM(bci_action_stem
);
6063 COPY_FPGM(bci_action_stem_serif
);
6064 COPY_FPGM(bci_action_stem_round
);
6065 COPY_FPGM(bci_action_stem_round_serif
);
6066 COPY_FPGM(bci_action_stem_bound
);
6067 COPY_FPGM(bci_action_stem_bound_serif
);
6068 COPY_FPGM(bci_action_stem_bound_round
);
6069 COPY_FPGM(bci_action_stem_bound_round_serif
);
6071 COPY_FPGM(bci_action_serif
);
6072 COPY_FPGM(bci_action_serif_lower_bound
);
6073 COPY_FPGM(bci_action_serif_upper_bound
);
6074 COPY_FPGM(bci_action_serif_upper_lower_bound
);
6076 COPY_FPGM(bci_action_serif_anchor
);
6077 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
6078 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
6079 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound
);
6081 COPY_FPGM(bci_action_serif_link1
);
6082 COPY_FPGM(bci_action_serif_link1_lower_bound
);
6083 COPY_FPGM(bci_action_serif_link1_upper_bound
);
6084 COPY_FPGM(bci_action_serif_link1_upper_lower_bound
);
6086 COPY_FPGM(bci_action_serif_link2
);
6087 COPY_FPGM(bci_action_serif_link2_lower_bound
);
6088 COPY_FPGM(bci_action_serif_link2_upper_bound
);
6089 COPY_FPGM(bci_action_serif_link2_upper_lower_bound
);
6091 COPY_FPGM(bci_hint_glyph
);
6094 *fpgm_len
= buf_len
;
6101 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
6106 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
6107 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
6113 error
= TA_sfnt_add_table_info(sfnt
);
6117 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
6118 if (glyf_table
->processed
)
6120 sfnt
->table_infos
[sfnt
->num_table_infos
- 1] = data
->fpgm_idx
;
6124 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, sfnt
, font
);
6128 if (fpgm_len
> sfnt
->max_instructions
)
6129 sfnt
->max_instructions
= fpgm_len
;
6131 /* in case of success, `fpgm_buf' gets linked */
6132 /* and is eventually freed in `TA_font_unload' */
6133 error
= TA_font_add_table(font
,
6134 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
6135 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
6139 data
->fpgm_idx
= sfnt
->table_infos
[sfnt
->num_table_infos
- 1];
6145 /* end of tafpgm.c */