4 * Copyright (C) 2011-2013 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
38 #define MD_orig_ZP2_0 \
41 #define MD_orig_ZP2_1 \
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 script's top of small letters blue zone)
162 * sal: sal_i (CVT index of the script's scaling value;
163 * gets incremented by 1 after execution)
166 unsigned char FPGM(bci_align_top_a
) [] =
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) */
255 MUL
, /* (fitted-blue) in 16.16 format */
257 DIV
, /* factor = ((fitted-blue) / blue) in 16.16 format */
269 RS
, /* s: factor idx */
278 ADD
, /* sal_i = sal_i + 1 */
289 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
290 * engine specific corrections are applied.
297 unsigned char FPGM(bci_round
) [] =
315 * bci_smooth_stem_width
317 * This is the equivalent to the following code from function
318 * `ta_latin_compute_stem_width':
326 * else if base_is_round:
332 * delta = ABS(dist - std_width)
343 * delta = delta - dist
346 * dist = dist + delta
347 * else if delta < 32:
349 * else if delta < 54:
352 * dist = dist + delta
367 * sal: sal_vwidth_data_offset
374 unsigned char FPGM(bci_smooth_stem_width
) [] =
378 bci_smooth_stem_width
,
382 ABS
, /* s: base_is_round stem_is_serif width dist */
387 LT
, /* dist < 3*64 */
391 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
392 AND
, /* stem_is_serif && dist < 3*64 */
396 sal_vwidth_data_offset
,
398 RCVT
, /* double indirection */
400 GT
, /* standard_width < 40 */
401 OR
, /* (stem_is_serif && dist < 3*64) || standard_width < 40 */
403 IF
, /* s: base_is_round width dist */
409 ROLL
, /* s: width dist base_is_round */
410 IF
, /* s: width dist */
415 IF
, /* s: width dist */
426 IF
, /* s: width dist */
433 DUP
, /* s: width dist dist */
435 sal_vwidth_data_offset
,
437 RCVT
, /* double indirection */
440 ABS
, /* s: width dist delta */
445 IF
, /* s: width dist */
448 sal_vwidth_data_offset
,
450 RCVT
, /* double indirection */
451 RCVT
, /* dist = std_width */
463 DUP
, /* s: width dist dist */
466 LT
, /* dist < 3*64 */
468 DUP
, /* s: width delta dist */
469 FLOOR
, /* dist = FLOOR(dist) */
470 DUP
, /* s: width delta dist dist */
472 ROLL
, /* s: width dist delta dist */
473 SUB
, /* delta = delta - dist */
475 DUP
, /* s: width dist delta delta */
479 IF
, /* s: width dist delta */
480 ADD
, /* dist = dist + delta */
491 ADD
, /* dist = dist + 10 */
502 ADD
, /* dist = dist + 54 */
505 ADD
, /* dist = dist + delta */
514 CALL
, /* dist = round(dist) */
519 SWAP
, /* s: dist width */
524 NEG
, /* dist = -dist */
536 * An auxiliary function for `bci_strong_stem_width'.
538 * in: n (initialized with CVT index for first vertical width)
550 unsigned char FPGM(bci_get_best_width
) [] =
558 RCVT
, /* s: dist n w */
562 CINDEX
, /* s: dist n w w dist */
564 ABS
, /* s: dist n w d */
568 RS
, /* s: dist n w d d best */
578 WS
, /* reference = w */
595 * bci_strong_stem_width
597 * This is the equivalent to the following code (function
598 * `ta_latin_snap_width' and some lines from
599 * `ta_latin_compute_stem_width'):
601 * best = 64 + 32 + 2;
605 * for n in 0 .. num_widths:
613 * if dist >= reference:
614 * if dist < ROUND(reference) + 48:
617 * if dist > ROUND(reference) - 48:
630 * stem_is_serif (unused)
631 * base_is_round (unused)
637 * sal_vwidth_data_offset
641 * uses: bci_get_best_width
645 unsigned char FPGM(bci_strong_stem_width
) [] =
649 bci_strong_stem_width
,
657 ABS
, /* s: width dist */
662 WS
, /* sal_best = 98 */
668 WS
, /* sal_ref = width */
671 sal_vwidth_data_offset
,
673 RCVT
, /* first index of vertical widths */
676 sal_vwidth_data_offset
,
679 cvtl_num_used_scripts
,
682 RCVT
, /* number of vertical widths */
688 POP
, /* s: width dist */
692 RS
, /* s: width dist dist reference */
699 CALL
, /* s: width dist reference dist dist ROUND(reference) */
704 ROLL
, /* s: width dist reference dist ROUND(reference) 48 reference dist */
706 LTEQ
, /* dist >= reference */
707 IF
, /* s: width dist reference dist ROUND(reference) 48 */
709 LT
, /* dist < ROUND(reference) + 48 */
713 GT
, /* dist > ROUND(reference) - 48 */
717 SWAP
, /* s: width reference dist */
724 GTEQ
, /* dist >= 64 */
728 CALL
, /* dist = ROUND(dist) */
736 SWAP
, /* s: dist width */
741 NEG
, /* dist = -dist */
752 * An auxiliary function for `bci_loop'.
754 * sal: sal_i (gets incremented by 2 after execution)
757 * uses: func[sal_func]
760 unsigned char FPGM(bci_loop_do
) [] =
777 ADD
, /* sal_i = sal_i + 2 */
788 * Take a range `start'..`end' and a function number and apply the
789 * associated function to the range elements `start', `start+2',
796 * sal: sal_i (counter initialized with `start')
797 * sal_func (`func_num')
802 unsigned char FPGM(bci_loop
) [] =
812 WS
, /* sal_func = func_num */
819 WS
, /* sal_i = start */
825 ADD
, /* number of loops ((end - start) / 2 + 1) */
839 * Rescale CVT value by `sal_scale' (in 16.16 format).
841 * The scaling factor `sal_scale' isn't stored as `b/c' but as `(b-c)/c';
842 * consequently, the calculation `a * b/c' is done as `a + delta' with
843 * `delta = a * (b-c)/c'. This avoids overflow.
852 unsigned char FPGM(bci_cvt_rescale
) [] =
875 * bci_cvt_rescale_range
877 * Rescale a range of CVT values with `bci_cvt_rescale', using a custom
880 * This function gets used in the `prep' table.
885 * sal: sal_i (CVT index of the script's scaling value;
886 * gets incremented by 1 after execution)
889 * uses: bci_cvt_rescale
892 unsigned char FPGM(bci_cvt_rescale_range
) [] =
896 bci_cvt_rescale_range
,
899 /* store scaling value in `sal_scale' */
906 WS
, /* s: cvt_start_idx num_cvt bci_cvt_rescale */
916 ADD
, /* sal_i = sal_i + 1 */
925 * bci_vwidth_data_store
927 * Store a vertical width array value.
929 * This function gets used in the `prep' table.
933 * sal: sal_i (CVT index of the script's vwidth data;
934 * gets incremented by 1 after execution)
937 unsigned char FPGM(bci_vwidth_data_store
) [] =
941 bci_vwidth_data_store
,
955 ADD
, /* sal_i = sal_i + 1 */
966 * Round a blue ref value and adjust its corresponding shoot value.
968 * This is the equivalent to the following code (function
969 * `ta_latin_metrics_scale_dim':
977 * else if (delta < 48)
987 * sal: sal_i (number of blue zones)
994 unsigned char FPGM(bci_blue_round
) [] =
1003 RCVT
, /* s: ref_idx ref_idx ref */
1009 SWAP
, /* s: ref_idx ref_idx round(ref) ref */
1017 ADD
, /* s: ref_idx ref_idx round(ref) ref shoot_idx */
1019 RCVT
, /* s: ref_idx ref_idx round(ref) ref shoot_idx shoot */
1021 ROLL
, /* s: ref_idx ref_idx round(ref) shoot_idx shoot ref */
1023 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx dist */
1025 ABS
, /* s: ref_idx ref_idx round(ref) shoot_idx dist delta */
1030 LT
, /* delta < 32 */
1039 LT
, /* delta < 48 */
1042 32, /* delta = 32 */
1046 64, /* delta = 64 */
1050 SWAP
, /* s: ref_idx ref_idx round(ref) shoot_idx delta dist */
1055 NEG
, /* delta = -delta */
1062 SUB
, /* s: ref_idx ref_idx round(ref) shoot_idx (round(ref) - delta) */
1069 ADD
, /* s: (ref_idx + 1) */
1077 * bci_blue_round_range
1079 * Round a range of blue zones (both reference and shoot values).
1081 * This function gets used in the `prep' table.
1083 * in: num_blue_zones
1086 * sal: sal_i (holds a copy of `num_blue_zones' for `bci_blue_round')
1088 * uses: bci_blue_round
1091 unsigned char FPGM(bci_blue_round_range
) [] =
1095 bci_blue_round_range
,
1115 * bci_decrement_component_counter
1117 * An auxiliary function for composite glyphs.
1119 * CVT: cvtl_is_subglyph
1122 unsigned char FPGM(bci_decrement_component_counter
) [] =
1126 bci_decrement_component_counter
,
1129 /* decrement `cvtl_is_subglyph' counter */
1145 * bci_get_point_extrema
1147 * An auxiliary function for `bci_create_segment'.
1153 * sal: sal_point_min
1157 unsigned char FPGM(bci_get_point_extrema
) [] =
1161 bci_get_point_extrema
,
1170 /* check whether `point' is a new minimum */
1173 RS
, /* s: point point point point_min */
1175 /* if distance is negative, we have a new minimum */
1179 IF
, /* s: point point */
1187 /* check whether `point' is a new maximum */
1190 RS
, /* s: point point point_max */
1192 /* if distance is positive, we have a new maximum */
1212 * Pop a byte with two delta arguments in its nibbles and push the
1213 * expanded arguments separately as two bytes.
1215 * in: 16 * (end - start) + (start - base)
1220 * sal: sal_base (set to `end' at return)
1224 unsigned char FPGM(bci_nibbles
) [] =
1231 PUSHB_1
, /* cf. DIV_POS_BY_2 macro */
1237 MUL
, /* s: in hnibble */
1242 MUL
, /* s: in hnibble (hnibble * 16) */
1245 SUB
, /* s: hnibble lnibble */
1250 ADD
, /* s: hnibble start */
1253 ADD
, /* s: start end */
1259 WS
, /* sal_base = end */
1269 * bci_number_set_is_element
1271 * Pop values from stack until it is empty. If one of them is equal to
1272 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
1279 * CVT: cvtl_is_element
1282 unsigned char FPGM(bci_number_set_is_element
) [] =
1286 bci_number_set_is_element
,
1304 JROT
, /* goto start_loop if stack depth != 0 */
1312 * bci_number_set_is_element2
1314 * Pop value ranges from stack until it is empty. If one of them contains
1315 * the current PPEM value, set `cvtl_is_element' to 1 (and to 0
1318 * in: ppem_range_1_start
1320 * ppem_range_2_start
1324 * CVT: cvtl_is_element
1327 unsigned char FPGM(bci_number_set_is_element2
) [] =
1331 bci_number_set_is_element2
,
1355 JROT
, /* goto start_loop if stack depth != 0 */
1363 * bci_create_segment
1365 * Store start and end point of a segment in the storage area,
1366 * then construct a point in the twilight zone to represent it.
1368 * This function is used by `bci_create_segments'.
1372 * [last (if wrap-around segment)]
1373 * [first (if wrap-around segment)]
1375 * sal: sal_i (start of current segment)
1376 * sal_j (current twilight point)
1380 * sal_num_packed_segments
1385 * uses: bci_get_point_extrema
1388 * If `sal_num_packed_segments' is > 0, the start/end pair is stored as
1389 * delta values in nibbles (without a wrap-around segment).
1392 unsigned char FPGM(bci_create_segment
) [] =
1401 sal_num_packed_segments
,
1406 sal_num_packed_segments
,
1407 sal_num_packed_segments
,
1412 WS
, /* sal_num_packed_segments = sal_num_packed_segments - 1 */
1425 WS
, /* sal[sal_i] = start */
1427 /* initialize inner loop(s) */
1432 WS
, /* sal_point_min = start */
1437 WS
, /* sal_point_max = start */
1441 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1447 CINDEX
, /* s: start end end start */
1448 LT
, /* start > end */
1450 /* we have a wrap-around segment with two more arguments */
1451 /* to give the last and first point of the contour, respectively; */
1452 /* our job is to store a segment `start'-`last', */
1453 /* and to get extrema for the two segments */
1454 /* `start'-`last' and `first'-`end' */
1456 /* s: first last start end */
1465 WS
, /* sal[sal_i + 1] = last */
1468 ROLL
, /* s: first end last start */
1471 SWAP
, /* s: first end start last start */
1472 SUB
, /* s: first end start loop_count */
1475 bci_get_point_extrema
,
1477 /* clean up stack */
1480 SWAP
, /* s: end first */
1485 ROLL
, /* s: (first - 1) (first - 1) end */
1487 SUB
, /* s: (first - 1) loop_count */
1490 bci_get_point_extrema
,
1492 /* clean up stack */
1495 ELSE
, /* s: start end */
1504 WS
, /* sal[sal_i + 1] = end */
1509 SUB
, /* s: start loop_count */
1512 bci_get_point_extrema
,
1514 /* clean up stack */
1518 /* the twilight point representing a segment */
1519 /* is in the middle between the minimum and maximum */
1529 DIV_BY_2
, /* s: middle_pos */
1531 DO_SCALE
, /* middle_pos = middle_pos * scale */
1533 /* write it to temporary CVT location */
1537 SZP0
, /* set zp0 to twilight zone 0 */
1541 /* create twilight point with index `sal_j' */
1554 ADD
, /* twilight_point = twilight_point + 1 */
1563 * bci_create_segments
1565 * This is the top-level entry function.
1567 * It pops point ranges from the stack to define segments, computes
1568 * twilight points to represent segments, and finally calls
1569 * `bci_hint_glyph' to handle the rest.
1571 * The second argument (`data_offset') addresses three CVT arrays in
1575 * the current script's scaling value (stored in `sal_scale')
1577 * data_offset + CVT(cvtl_num_used_scripts):
1578 * offset to the current script's vwidth index array (this value gets
1579 * stored in `sal_vwidth_data_offset')
1581 * data_offset + 2*CVT(cvtl_num_used_scripts):
1582 * offset to the current script's vwidth size
1584 * This addressing scheme ensures that (a) we only need a single argument,
1585 * and (b) this argument supports up to (256-cvtl_max_runtime) scripts,
1586 * which should be sufficient for a long time.
1588 * in: num_packed_segments
1593 * [contour_last 0 (if wrap-around segment)]
1594 * [contour_first 0 (if wrap-around segment)]
1597 * [contour_last 0 (if wrap-around segment)]
1598 * [contour_first 0 (if wrap-around segment)]
1600 * segment_start_(N-1)
1602 * [contour_last (N-1) (if wrap-around segment)]
1603 * [contour_first (N-1) (if wrap-around segment)]
1604 * ... stuff for bci_hint_glyph ...
1606 * sal: sal_i (start of current segment)
1607 * sal_j (current twilight point)
1608 * sal_num_packed_segments
1609 * sal_base (the base for delta values in nibbles)
1610 * sal_vwidth_data_offset
1613 * CVT: cvtl_is_subglyph
1615 * uses: bci_create_segment
1619 * If `num_packed_segments' is set to p, the first p start/end pairs are
1620 * stored as delta values in nibbles, with the `start' delta in the lower
1621 * nibble (and there are no wrap-around segments). For example, if the
1622 * first three pairs are 1/3, 5/8, and 12/13, the topmost three bytes on the
1623 * stack are 0x21, 0x32, and 0x14.
1627 unsigned char FPGM(bci_create_segments
) [] =
1631 bci_create_segments
,
1634 /* only do something if we are not a subglyph */
1641 /* all our measurements are taken along the y axis */
1645 sal_num_packed_segments
,
1652 sal_scale
, /* sal_scale = CVT(data_offset) */
1657 sal_vwidth_data_offset
,
1660 cvtl_num_used_scripts
,
1663 WS
, /* sal_vwidth_data_offset = data_offset + num_used_scripts */
1669 SUB
, /* delta = (2*num_segments - 1) */
1679 WS
, /* sal_base = 0 */
1680 WS
, /* sal_j = 0 (point offset) */
1683 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1704 * bci_create_segments_X
1706 * Top-level routines for calling `bci_create_segments'.
1709 unsigned char FPGM(bci_create_segments_0
) [] =
1713 bci_create_segments_0
,
1718 bci_create_segments
,
1725 unsigned char FPGM(bci_create_segments_1
) [] =
1729 bci_create_segments_1
,
1734 bci_create_segments
,
1741 unsigned char FPGM(bci_create_segments_2
) [] =
1745 bci_create_segments_2
,
1750 bci_create_segments
,
1757 unsigned char FPGM(bci_create_segments_3
) [] =
1761 bci_create_segments_3
,
1766 bci_create_segments
,
1773 unsigned char FPGM(bci_create_segments_4
) [] =
1777 bci_create_segments_4
,
1782 bci_create_segments
,
1789 unsigned char FPGM(bci_create_segments_5
) [] =
1793 bci_create_segments_5
,
1798 bci_create_segments
,
1805 unsigned char FPGM(bci_create_segments_6
) [] =
1809 bci_create_segments_6
,
1814 bci_create_segments
,
1821 unsigned char FPGM(bci_create_segments_7
) [] =
1825 bci_create_segments_7
,
1830 bci_create_segments
,
1837 unsigned char FPGM(bci_create_segments_8
) [] =
1841 bci_create_segments_8
,
1846 bci_create_segments
,
1853 unsigned char FPGM(bci_create_segments_9
) [] =
1857 bci_create_segments_9
,
1862 bci_create_segments
,
1871 * bci_create_segments_composite
1873 * The same as `bci_create_segments'.
1874 * It also decrements the composite component counter.
1876 * sal: sal_num_packed_segments
1877 * sal_segment_offset
1878 * sal_vwidth_data_offset
1880 * CVT: cvtl_is_subglyph
1882 * uses: bci_decrement_component_counter
1883 * bci_create_segment
1888 unsigned char FPGM(bci_create_segments_composite
) [] =
1892 bci_create_segments_composite
,
1896 bci_decrement_component_counter
,
1899 /* only do something if we are not a subglyph */
1906 /* all our measurements are taken along the y axis */
1910 sal_num_packed_segments
,
1917 sal_scale
, /* sal_scale = CVT(data_offset) */
1922 sal_vwidth_data_offset
,
1925 cvtl_num_used_scripts
,
1928 WS
, /* sal_vwidth_data_offset = data_offset + num_used_scripts */
1934 SUB
, /* delta = (2*num_segments - 1) */
1944 WS
, /* sal_base = 0 */
1945 WS
, /* sal_j = 0 (point offset) */
1948 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
1969 * bci_create_segments_composite_X
1971 * Top-level routines for calling `bci_create_segments_composite'.
1974 unsigned char FPGM(bci_create_segments_composite_0
) [] =
1978 bci_create_segments_composite_0
,
1983 bci_create_segments_composite
,
1990 unsigned char FPGM(bci_create_segments_composite_1
) [] =
1994 bci_create_segments_composite_1
,
1999 bci_create_segments_composite
,
2006 unsigned char FPGM(bci_create_segments_composite_2
) [] =
2010 bci_create_segments_composite_2
,
2015 bci_create_segments_composite
,
2022 unsigned char FPGM(bci_create_segments_composite_3
) [] =
2026 bci_create_segments_composite_3
,
2031 bci_create_segments_composite
,
2038 unsigned char FPGM(bci_create_segments_composite_4
) [] =
2042 bci_create_segments_composite_4
,
2047 bci_create_segments_composite
,
2054 unsigned char FPGM(bci_create_segments_composite_5
) [] =
2058 bci_create_segments_composite_5
,
2063 bci_create_segments_composite
,
2070 unsigned char FPGM(bci_create_segments_composite_6
) [] =
2074 bci_create_segments_composite_6
,
2079 bci_create_segments_composite
,
2086 unsigned char FPGM(bci_create_segments_composite_7
) [] =
2090 bci_create_segments_composite_7
,
2095 bci_create_segments_composite
,
2102 unsigned char FPGM(bci_create_segments_composite_8
) [] =
2106 bci_create_segments_composite_8
,
2111 bci_create_segments_composite
,
2118 unsigned char FPGM(bci_create_segments_composite_9
) [] =
2122 bci_create_segments_composite_9
,
2127 bci_create_segments_composite
,
2138 * An auxiliary function for `bci_align_segment'.
2145 unsigned char FPGM(bci_align_point
) [] =
2153 ALIGNRP
, /* align point with rp0 */
2167 * Align all points in a segment to the twilight point in rp0.
2168 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2172 * sal: sal_segment_offset
2174 * uses: bci_align_point
2177 unsigned char FPGM(bci_align_segment
) [] =
2184 /* we need the values of `sal_segment_offset + 2*segment_index' */
2185 /* and `sal_segment_offset + 2*segment_index + 1' */
2197 RS
, /* s: first last */
2201 CINDEX
, /* s: first last first */
2205 ADD
, /* s: first loop_count */
2210 /* clean up stack */
2219 * bci_align_segments
2221 * Align segments to the twilight point in rp0.
2222 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
2231 * uses: bci_align_segment
2234 unsigned char FPGM(bci_align_segments
) [] =
2257 * Scale a contour using two points giving the maximum and minimum
2260 * It expects that no point on the contour is touched.
2268 unsigned char FPGM(bci_scale_contour
) [] =
2279 DO_SCALE
, /* min_pos_new = min_pos * scale */
2284 /* don't scale a single-point contour twice */
2293 DO_SCALE
, /* max_pos_new = max_pos * scale */
2310 * Scale a glyph using a list of points (two points per contour, giving
2311 * the maximum and mininum coordinates).
2313 * It expects that no point in the glyph is touched.
2315 * Note that the point numbers are sorted in ascending order;
2316 * `min_point_X' and `max_point_X' thus refer to the two extrema of a
2317 * contour without specifying which one is the minimum and maximum.
2319 * in: num_contours (N)
2328 * CVT: cvtl_is_subglyph
2330 * uses: bci_scale_contour
2333 unsigned char FPGM(bci_scale_glyph
) [] =
2340 /* only do something if we are not a subglyph */
2347 /* all our measurements are taken along the y axis */
2352 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2360 SZP2
, /* set zp2 to normal zone 1 */
2373 * bci_scale_composite_glyph
2375 * The same as `bci_scale_glyph'.
2376 * It also decrements the composite component counter.
2378 * CVT: cvtl_is_subglyph
2380 * uses: bci_decrement_component_counter
2384 unsigned char FPGM(bci_scale_composite_glyph
) [] =
2388 bci_scale_composite_glyph
,
2392 bci_decrement_component_counter
,
2395 /* only do something if we are not a subglyph */
2402 /* all our measurements are taken along the y axis */
2407 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
2415 SZP2
, /* set zp2 to normal zone 1 */
2430 * Shift a contour by a given amount.
2432 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
2433 * point to the normal zone 1.
2440 unsigned char FPGM(bci_shift_contour
) [] =
2448 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
2460 * bci_shift_subglyph
2462 * Shift a subglyph. To be more specific, it corrects the already applied
2463 * subglyph offset (if any) from the `glyf' table which needs to be scaled
2466 * If this function is called, a point `x' in the subglyph has been scaled
2467 * already (during the hinting of the subglyph itself), and `offset' has
2468 * been applied also:
2470 * x -> x * scale + offset (1)
2472 * However, the offset should be applied first, then the scaling:
2474 * x -> (x + offset) * scale (2)
2476 * Our job is now to transform (1) to (2); a simple calculation shows that
2477 * we have to shift all points of the subglyph by
2479 * offset * scale - offset = offset * (scale - 1)
2481 * Note that `sal_scale' is equal to the above `scale - 1'.
2483 * in: offset (in FUnits)
2487 * CVT: cvtl_funits_to_pixels
2495 unsigned char FPGM(bci_shift_subglyph
) [] =
2505 cvtl_funits_to_pixels
,
2506 RCVT
, /* scaling factor FUnits -> pixels */
2510 /* the autohinter always rounds offsets */
2513 CALL
, /* offset = round(offset) */
2519 DIV_BY_1024
, /* delta = offset * (scale - 1) */
2521 /* and round again */
2524 CALL
, /* offset = round(offset) */
2528 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2530 /* we create twilight point 0 as a reference point, */
2531 /* setting the original position to zero (using `cvtl_temp') */
2539 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
2541 SWAP
, /* s: first_contour num_contours 0 delta */
2542 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
2547 SZP2
, /* set zp2 to normal zone 1 */
2556 * bci_ip_outer_align_point
2558 * Auxiliary function for `bci_action_ip_before' and
2559 * `bci_action_ip_after'.
2561 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2562 * zone, and both zp1 and zp2 set to normal zone.
2566 * sal: sal_i (edge_orig_pos)
2570 unsigned char FPGM(bci_ip_outer_align_point
) [] =
2574 bci_ip_outer_align_point
,
2578 ALIGNRP
, /* align `point' with `edge' */
2581 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2586 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2595 * bci_ip_on_align_points
2597 * Auxiliary function for `bci_action_ip_on'.
2599 * in: edge (in twilight zone)
2607 unsigned char FPGM(bci_ip_on_align_points
) [] =
2611 bci_ip_on_align_points
,
2614 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2625 * bci_ip_between_align_point
2627 * Auxiliary function for `bci_ip_between_align_points'.
2629 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
2630 * zone, and both zp1 and zp2 set to normal zone.
2634 * sal: sal_i (edge_orig_pos)
2635 * sal_j (stretch_factor)
2639 unsigned char FPGM(bci_ip_between_align_point
) [] =
2643 bci_ip_between_align_point
,
2647 ALIGNRP
, /* align `point' with `edge' */
2650 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
2655 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
2659 MUL
, /* s: point delta */
2668 * bci_ip_between_align_points
2670 * Auxiliary function for `bci_action_ip_between'.
2672 * in: after_edge (in twilight zone)
2673 * before_edge (in twilight zone)
2680 * sal: sal_i (before_orig_pos)
2681 * sal_j (stretch_factor)
2683 * uses: bci_ip_between_align_point
2686 unsigned char FPGM(bci_ip_between_align_points
) [] =
2690 bci_ip_between_align_points
,
2696 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2698 DUP
, /* s: ... before after before before */
2699 MDAP_noround
, /* set rp0 and rp1 to `before' */
2701 GC_orig
, /* s: ... before after before before_orig_pos */
2705 WS
, /* sal_i = before_orig_pos */
2708 CINDEX
, /* s: ... before after before after */
2709 MD_cur
, /* a = after_pos - before_pos */
2712 MD_orig_ZP2_0
, /* b = after_orig_pos - before_orig_pos */
2718 POP
, /* avoid division by zero */
2724 WS
, /* sal_j = stretch_factor */
2727 bci_ip_between_align_point
,
2730 SZP2
, /* set zp2 to normal zone 1 */
2731 SZP1
, /* set zp1 to normal zone 1 */
2740 * bci_action_ip_before
2742 * Handle `ip_before' data to align points located before the first edge.
2744 * in: first_edge (in twilight zone)
2751 * sal: sal_i (first_edge_orig_pos)
2753 * uses: bci_ip_outer_align_point
2756 unsigned char FPGM(bci_action_ip_before
) [] =
2760 bci_action_ip_before
,
2765 SZP2
, /* set zp2 to twilight zone 0 */
2772 WS
, /* sal_i = first_edge_orig_pos */
2778 SZP2
, /* set zp2 to normal zone 1 */
2779 SZP1
, /* set zp1 to normal zone 1 */
2780 SZP0
, /* set zp0 to twilight zone 0 */
2782 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
2785 bci_ip_outer_align_point
,
2794 * bci_action_ip_after
2796 * Handle `ip_after' data to align points located after the last edge.
2798 * in: last_edge (in twilight zone)
2805 * sal: sal_i (last_edge_orig_pos)
2807 * uses: bci_ip_outer_align_point
2810 unsigned char FPGM(bci_action_ip_after
) [] =
2814 bci_action_ip_after
,
2819 SZP2
, /* set zp2 to twilight zone 0 */
2826 WS
, /* sal_i = last_edge_orig_pos */
2832 SZP2
, /* set zp2 to normal zone 1 */
2833 SZP1
, /* set zp1 to normal zone 1 */
2834 SZP0
, /* set zp0 to twilight zone 0 */
2836 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
2839 bci_ip_outer_align_point
,
2850 * Handle `ip_on' data to align points located on an edge coordinate (but
2851 * not part of an edge).
2853 * in: loop_counter (M)
2854 * edge_1 (in twilight zone)
2855 * loop_counter (N_1)
2860 * edge_2 (in twilight zone)
2861 * loop_counter (N_2)
2867 * edge_M (in twilight zone)
2868 * loop_counter (N_M)
2874 * uses: bci_ip_on_align_points
2877 unsigned char FPGM(bci_action_ip_on
) [] =
2887 SZP1
, /* set zp1 to normal zone 1 */
2888 SZP0
, /* set zp0 to twilight zone 0 */
2891 bci_ip_on_align_points
,
2900 * bci_action_ip_between
2902 * Handle `ip_between' data to align points located between two edges.
2904 * in: loop_counter (M)
2905 * before_edge_1 (in twilight zone)
2906 * after_edge_1 (in twilight zone)
2907 * loop_counter (N_1)
2912 * before_edge_2 (in twilight zone)
2913 * after_edge_2 (in twilight zone)
2914 * loop_counter (N_2)
2920 * before_edge_M (in twilight zone)
2921 * after_edge_M (in twilight zone)
2922 * loop_counter (N_M)
2928 * uses: bci_ip_between_align_points
2931 unsigned char FPGM(bci_action_ip_between
) [] =
2935 bci_action_ip_between
,
2939 bci_ip_between_align_points
,
2950 * Common code for bci_action_adjust routines.
2952 * uses: func[cvtl_stem_width_function]
2955 unsigned char FPGM(bci_adjust_common
) [] =
2964 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2968 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
2971 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
2972 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
2975 cvtl_stem_width_function
,
2978 NEG
, /* s: [...] edge2 edge -cur_len */
2980 ROLL
, /* s: [...] edge -cur_len edge2 */
2981 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2984 DUP
, /* s: [...] -cur_len edge edge edge */
2985 ALIGNRP
, /* align `edge' with `edge2' */
2987 SHPIX
, /* shift `edge' by -cur_len */
2997 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
2998 * edge of the stem has already been moved, then moving it again if
2999 * necessary to stay bound.
3001 * in: edge2_is_serif
3003 * edge_point (in twilight zone)
3004 * edge2_point (in twilight zone)
3005 * edge[-1] (in twilight zone)
3006 * ... stuff for bci_align_segments (edge) ...
3008 * uses: bci_adjust_common
3009 * bci_align_segments
3012 unsigned char FPGM(bci_adjust_bound
) [] =
3023 SWAP
, /* s: edge edge[-1] */
3025 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3030 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3031 GT
, /* edge_pos < edge[-1]_pos */
3034 ALIGNRP
, /* align `edge' to `edge[-1]' */
3037 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3042 SZP1
, /* set zp1 to normal zone 1 */
3051 * bci_action_adjust_bound
3052 * bci_action_adjust_bound_serif
3053 * bci_action_adjust_bound_round
3054 * bci_action_adjust_bound_round_serif
3056 * Higher-level routines for calling `bci_adjust_bound'.
3059 unsigned char FPGM(bci_action_adjust_bound
) [] =
3063 bci_action_adjust_bound
,
3076 unsigned char FPGM(bci_action_adjust_bound_serif
) [] =
3080 bci_action_adjust_bound_serif
,
3093 unsigned char FPGM(bci_action_adjust_bound_round
) [] =
3097 bci_action_adjust_bound_round
,
3110 unsigned char FPGM(bci_action_adjust_bound_round_serif
) [] =
3114 bci_action_adjust_bound_round_serif
,
3131 * Handle the ADJUST action to align an edge of a stem if the other edge
3132 * of the stem has already been moved.
3134 * in: edge2_is_serif
3136 * edge_point (in twilight zone)
3137 * edge2_point (in twilight zone)
3138 * ... stuff for bci_align_segments (edge) ...
3140 * uses: bci_adjust_common
3141 * bci_align_segments
3144 unsigned char FPGM(bci_adjust
) [] =
3155 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3160 SZP1
, /* set zp1 to normal zone 1 */
3170 * bci_action_adjust_serif
3171 * bci_action_adjust_round
3172 * bci_action_adjust_round_serif
3174 * Higher-level routines for calling `bci_adjust'.
3177 unsigned char FPGM(bci_action_adjust
) [] =
3194 unsigned char FPGM(bci_action_adjust_serif
) [] =
3198 bci_action_adjust_serif
,
3211 unsigned char FPGM(bci_action_adjust_round
) [] =
3215 bci_action_adjust_round
,
3228 unsigned char FPGM(bci_action_adjust_round_serif
) [] =
3232 bci_action_adjust_round_serif
,
3249 * Common code for bci_action_stem routines.
3256 * uses: func[cvtl_stem_width_function]
3261 #define sal_u_off sal_temp1
3263 #define sal_d_off sal_temp2
3265 #define sal_org_len sal_temp3
3267 #define sal_edge2 sal_temp3
3269 unsigned char FPGM(bci_stem_common
) [] =
3278 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3286 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
3287 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
3289 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
3297 cvtl_stem_width_function
,
3299 CALL
, /* s: [...] edge2 edge cur_len */
3304 LT
, /* cur_len < 96 */
3309 LTEQ
, /* cur_len <= 64 */
3327 SWAP
, /* s: [...] edge2 cur_len edge */
3332 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
3338 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3343 ADD
, /* s: [...] edge2 cur_len edge org_center */
3348 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
3353 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
3360 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
3367 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
3369 LT
, /* delta1 < delta2 */
3374 SUB
, /* cur_pos1 = cur_pos1 - u_off */
3380 ADD
, /* cur_pos1 = cur_pos1 + d_off */
3381 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
3387 SUB
, /* arg = cur_pos1 - cur_len/2 */
3389 SWAP
, /* s: [...] edge2 cur_len arg edge */
3395 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3398 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
3401 SWAP
, /* s: [...] edge2 cur_len edge */
3405 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
3413 ADD
, /* s: [...] edge2 cur_len edge org_pos */
3420 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
3426 CALL
, /* cur_pos1 = ROUND(org_pos) */
3438 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
3447 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
3454 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
3460 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
3461 LT
, /* delta1 < delta2 */
3463 POP
, /* arg = cur_pos1 */
3467 POP
, /* arg = cur_pos2 */
3468 EIF
, /* s: [...] edge2 cur_len edge arg */
3475 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
3478 SHPIX
, /* edge = arg */
3479 EIF
, /* s: [...] edge2 cur_len edge */
3489 * Handle the STEM action to align two edges of a stem, then moving one
3490 * edge again if necessary to stay bound.
3492 * The code after computing `cur_len' to shift `edge' and `edge2'
3493 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3496 * if cur_len < = 64:
3503 * org_pos = anchor + (edge_orig - anchor_orig);
3504 * org_center = org_pos + org_len / 2;
3506 * cur_pos1 = ROUND(org_center)
3507 * delta1 = ABS(org_center - (cur_pos1 - u_off))
3508 * delta2 = ABS(org_center - (cur_pos1 + d_off))
3509 * if (delta1 < delta2):
3510 * cur_pos1 = cur_pos1 - u_off
3512 * cur_pos1 = cur_pos1 + d_off
3514 * edge = cur_pos1 - cur_len / 2
3517 * org_pos = anchor + (edge_orig - anchor_orig)
3518 * org_center = org_pos + org_len / 2;
3520 * cur_pos1 = ROUND(org_pos)
3521 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
3522 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
3523 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
3525 * if (delta1 < delta2):
3530 * edge2 = edge + cur_len
3532 * in: edge2_is_serif
3534 * edge_point (in twilight zone)
3535 * edge2_point (in twilight zone)
3536 * edge[-1] (in twilight zone)
3537 * ... stuff for bci_align_segments (edge) ...
3538 * ... stuff for bci_align_segments (edge2)...
3545 * uses: bci_stem_common
3546 * bci_align_segments
3549 unsigned char FPGM(bci_stem_bound
) [] =
3560 ROLL
, /* s: edge[-1] cur_len edge edge2 */
3563 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3567 WS
, /* s: edge[-1] cur_len edge edge2 */
3569 SHPIX
, /* edge2 = edge + cur_len */
3571 SWAP
, /* s: edge edge[-1] */
3573 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3578 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3579 GT
, /* edge_pos < edge[-1]_pos */
3582 ALIGNRP
, /* align `edge' to `edge[-1]' */
3585 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3590 SZP1
, /* set zp1 to normal zone 1 */
3596 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3608 * bci_action_stem_bound
3609 * bci_action_stem_bound_serif
3610 * bci_action_stem_bound_round
3611 * bci_action_stem_bound_round_serif
3613 * Higher-level routines for calling `bci_stem_bound'.
3616 unsigned char FPGM(bci_action_stem_bound
) [] =
3620 bci_action_stem_bound
,
3633 unsigned char FPGM(bci_action_stem_bound_serif
) [] =
3637 bci_action_stem_bound_serif
,
3650 unsigned char FPGM(bci_action_stem_bound_round
) [] =
3654 bci_action_stem_bound_round
,
3667 unsigned char FPGM(bci_action_stem_bound_round_serif
) [] =
3671 bci_action_stem_bound_round_serif
,
3688 * Handle the STEM action to align two edges of a stem.
3690 * See `bci_stem_bound' for more details.
3692 * in: edge2_is_serif
3694 * edge_point (in twilight zone)
3695 * edge2_point (in twilight zone)
3696 * ... stuff for bci_align_segments (edge) ...
3697 * ... stuff for bci_align_segments (edge2)...
3704 * uses: bci_stem_common
3705 * bci_align_segments
3708 unsigned char FPGM(bci_stem
) [] =
3720 SWAP
, /* s: cur_len edge2 */
3723 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
3727 WS
, /* s: cur_len edge2 */
3729 SHPIX
, /* edge2 = edge + cur_len */
3734 SZP1
, /* set zp1 to normal zone 1 */
3740 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
3752 * bci_action_stem_serif
3753 * bci_action_stem_round
3754 * bci_action_stem_round_serif
3756 * Higher-level routines for calling `bci_stem'.
3759 unsigned char FPGM(bci_action_stem
) [] =
3776 unsigned char FPGM(bci_action_stem_serif
) [] =
3780 bci_action_stem_serif
,
3793 unsigned char FPGM(bci_action_stem_round
) [] =
3797 bci_action_stem_round
,
3810 unsigned char FPGM(bci_action_stem_round_serif
) [] =
3814 bci_action_stem_round_serif
,
3831 * Handle the LINK action to link an edge to another one.
3835 * base_point (in twilight zone)
3836 * stem_point (in twilight zone)
3837 * ... stuff for bci_align_segments (base) ...
3839 * uses: func[cvtl_stem_width_function]
3840 * bci_align_segments
3843 unsigned char FPGM(bci_link
) [] =
3852 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3860 DUP
, /* s: stem is_round is_serif stem base base */
3861 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
3863 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
3866 cvtl_stem_width_function
,
3868 CALL
, /* s: stem new_dist */
3872 ALIGNRP
, /* align `stem_point' with `base_point' */
3874 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
3876 SHPIX
, /* stem_point = base_point + new_dist */
3881 SZP1
, /* set zp1 to normal zone 1 */
3891 * bci_action_link_serif
3892 * bci_action_link_round
3893 * bci_action_link_round_serif
3895 * Higher-level routines for calling `bci_link'.
3898 unsigned char FPGM(bci_action_link
) [] =
3915 unsigned char FPGM(bci_action_link_serif
) [] =
3919 bci_action_link_serif
,
3932 unsigned char FPGM(bci_action_link_round
) [] =
3936 bci_action_link_round
,
3949 unsigned char FPGM(bci_action_link_round_serif
) [] =
3953 bci_action_link_round_serif
,
3970 * Handle the ANCHOR action to align two edges
3971 * and to set the edge anchor.
3973 * The code after computing `cur_len' to shift `edge' and `edge2'
3974 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
3977 * if cur_len < = 64:
3984 * org_center = edge_orig + org_len / 2
3985 * cur_pos1 = ROUND(org_center)
3987 * error1 = ABS(org_center - (cur_pos1 - u_off))
3988 * error2 = ABS(org_center - (cur_pos1 + d_off))
3989 * if (error1 < error2):
3990 * cur_pos1 = cur_pos1 - u_off
3992 * cur_pos1 = cur_pos1 + d_off
3994 * edge = cur_pos1 - cur_len / 2
3995 * edge2 = edge + cur_len
3998 * edge = ROUND(edge_orig)
4000 * in: edge2_is_serif
4002 * edge_point (in twilight zone)
4003 * edge2_point (in twilight zone)
4004 * ... stuff for bci_align_segments (edge) ...
4011 * uses: func[cvtl_stem_width_function]
4013 * bci_align_segments
4017 #define sal_u_off sal_temp1
4019 #define sal_d_off sal_temp2
4021 #define sal_org_len sal_temp3
4023 unsigned char FPGM(bci_anchor
) [] =
4030 /* store anchor point number in `sal_anchor' */
4035 WS
, /* sal_anchor = edge_point */
4039 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4047 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
4048 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
4050 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
4058 cvtl_stem_width_function
,
4060 CALL
, /* s: edge2 edge cur_len */
4065 LT
, /* cur_len < 96 */
4070 LTEQ
, /* cur_len <= 64 */
4088 SWAP
, /* s: edge2 cur_len edge */
4089 DUP
, /* s: edge2 cur_len edge edge */
4096 ADD
, /* s: edge2 cur_len edge org_center */
4101 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
4106 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
4113 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
4120 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
4122 LT
, /* error1 < error2 */
4127 SUB
, /* cur_pos1 = cur_pos1 - u_off */
4133 ADD
, /* cur_pos1 = cur_pos1 + d_off */
4134 EIF
, /* s: edge2 cur_len edge cur_pos1 */
4140 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
4144 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
4147 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
4149 SWAP
, /* s: cur_len edge2 */
4151 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
4153 SHPIX
, /* edge2 = edge1 + cur_len */
4156 POP
, /* s: edge2 edge */
4164 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
4167 SHPIX
, /* edge = round(edge_orig) */
4169 /* clean up stack */
4176 SZP1
, /* set zp1 to normal zone 1 */
4186 * bci_action_anchor_serif
4187 * bci_action_anchor_round
4188 * bci_action_anchor_round_serif
4190 * Higher-level routines for calling `bci_anchor'.
4193 unsigned char FPGM(bci_action_anchor
) [] =
4210 unsigned char FPGM(bci_action_anchor_serif
) [] =
4214 bci_action_anchor_serif
,
4227 unsigned char FPGM(bci_action_anchor_round
) [] =
4231 bci_action_anchor_round
,
4244 unsigned char FPGM(bci_action_anchor_round_serif
) [] =
4248 bci_action_anchor_round_serif
,
4263 * bci_action_blue_anchor
4265 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
4266 * and to set the edge anchor.
4268 * in: anchor_point (in twilight zone)
4270 * edge_point (in twilight zone)
4271 * ... stuff for bci_align_segments (edge) ...
4275 * uses: bci_action_blue
4278 unsigned char FPGM(bci_action_blue_anchor
) [] =
4282 bci_action_blue_anchor
,
4285 /* store anchor point number in `sal_anchor' */
4303 * Handle the BLUE action to align an edge with a blue zone.
4306 * edge_point (in twilight zone)
4307 * ... stuff for bci_align_segments (edge) ...
4309 * uses: bci_align_segments
4312 unsigned char FPGM(bci_action_blue
) [] =
4321 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4323 /* move `edge_point' to `blue_cvt_idx' position; */
4324 /* note that we can't use MIAP since this would modify */
4325 /* the twilight point's original coordinates also */
4329 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4331 GC_cur
, /* s: new_pos edge edge_pos */
4334 SUB
, /* s: edge (new_pos - edge_pos) */
4340 SZP1
, /* set zp1 to normal zone 1 */
4351 * Common code for bci_action_serif routines.
4354 unsigned char FPGM(bci_serif_common
) [] =
4363 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4370 MINDEX
, /* s: [...] serif serif serif serif base */
4372 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
4375 ALIGNRP
, /* align `serif_point' with `base_point' */
4376 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
4386 * Move an edge if necessary to stay within a lower bound.
4391 * uses: bci_align_segments
4394 unsigned char FPGM(bci_lower_bound
) [] =
4401 SWAP
, /* s: edge bound */
4403 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4408 GC_cur
, /* s: edge bound_pos edge_pos */
4409 GT
, /* edge_pos < bound_pos */
4412 ALIGNRP
, /* align `edge' to `bound' */
4415 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4420 SZP1
, /* set zp1 to normal zone 1 */
4431 * Move an edge if necessary to stay within an upper bound.
4436 * uses: bci_align_segments
4439 unsigned char FPGM(bci_upper_bound
) [] =
4446 SWAP
, /* s: edge bound */
4448 MDAP_noround
, /* set rp0 and rp1 to `bound' */
4453 GC_cur
, /* s: edge bound_pos edge_pos */
4454 LT
, /* edge_pos > bound_pos */
4457 ALIGNRP
, /* align `edge' to `bound' */
4460 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
4465 SZP1
, /* set zp1 to normal zone 1 */
4474 * bci_upper_lower_bound
4476 * Move an edge if necessary to stay within a lower and lower bound.
4482 * uses: bci_align_segments
4485 unsigned char FPGM(bci_upper_lower_bound
) [] =
4489 bci_upper_lower_bound
,
4492 SWAP
, /* s: upper serif lower */
4494 MDAP_noround
, /* set rp0 and rp1 to `lower' */
4499 GC_cur
, /* s: upper serif lower_pos serif_pos */
4500 GT
, /* serif_pos < lower_pos */
4503 ALIGNRP
, /* align `serif' to `lower' */
4506 SWAP
, /* s: serif upper */
4508 MDAP_noround
, /* set rp0 and rp1 to `upper' */
4513 GC_cur
, /* s: serif upper_pos serif_pos */
4514 LT
, /* serif_pos > upper_pos */
4517 ALIGNRP
, /* align `serif' to `upper' */
4520 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4525 SZP1
, /* set zp1 to normal zone 1 */
4536 * Handle the SERIF action to align a serif with its base.
4538 * in: serif_point (in twilight zone)
4539 * base_point (in twilight zone)
4540 * ... stuff for bci_align_segments (serif) ...
4542 * uses: bci_serif_common
4543 * bci_align_segments
4546 unsigned char FPGM(bci_action_serif
) [] =
4557 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
4562 SZP1
, /* set zp1 to normal zone 1 */
4571 * bci_action_serif_lower_bound
4573 * Handle the SERIF action to align a serif with its base, then moving it
4574 * again if necessary to stay within a lower bound.
4576 * in: serif_point (in twilight zone)
4577 * base_point (in twilight zone)
4578 * edge[-1] (in twilight zone)
4579 * ... stuff for bci_align_segments (serif) ...
4581 * uses: bci_serif_common
4585 unsigned char FPGM(bci_action_serif_lower_bound
) [] =
4589 bci_action_serif_lower_bound
,
4606 * bci_action_serif_upper_bound
4608 * Handle the SERIF action to align a serif with its base, then moving it
4609 * again if necessary to stay within an upper bound.
4611 * in: serif_point (in twilight zone)
4612 * base_point (in twilight zone)
4613 * edge[1] (in twilight zone)
4614 * ... stuff for bci_align_segments (serif) ...
4616 * uses: bci_serif_common
4620 unsigned char FPGM(bci_action_serif_upper_bound
) [] =
4624 bci_action_serif_upper_bound
,
4641 * bci_action_serif_upper_lower_bound
4643 * Handle the SERIF action to align a serif with its base, then moving it
4644 * again if necessary to stay within a lower and upper bound.
4646 * in: serif_point (in twilight zone)
4647 * base_point (in twilight zone)
4648 * edge[-1] (in twilight zone)
4649 * edge[1] (in twilight zone)
4650 * ... stuff for bci_align_segments (serif) ...
4652 * uses: bci_serif_common
4653 * bci_upper_lower_bound
4656 unsigned char FPGM(bci_action_serif_upper_lower_bound
) [] =
4660 bci_action_serif_upper_lower_bound
,
4665 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4672 bci_upper_lower_bound
,
4681 * bci_serif_anchor_common
4683 * Common code for bci_action_serif_anchor routines.
4690 unsigned char FPGM(bci_serif_anchor_common
) [] =
4694 bci_serif_anchor_common
,
4699 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4705 WS
, /* sal_anchor = edge_point */
4715 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
4718 SHPIX
, /* edge = round(edge_orig) */
4726 * bci_action_serif_anchor
4728 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4731 * in: edge_point (in twilight zone)
4732 * ... stuff for bci_align_segments (edge) ...
4734 * uses: bci_serif_anchor_common
4735 * bci_align_segments
4738 unsigned char FPGM(bci_action_serif_anchor
) [] =
4742 bci_action_serif_anchor
,
4746 bci_serif_anchor_common
,
4749 MDAP_noround
, /* set rp0 and rp1 to `edge' */
4754 SZP1
, /* set zp1 to normal zone 1 */
4763 * bci_action_serif_anchor_lower_bound
4765 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4766 * anchor, then moving it again if necessary to stay within a lower
4769 * in: edge_point (in twilight zone)
4770 * edge[-1] (in twilight zone)
4771 * ... stuff for bci_align_segments (edge) ...
4773 * uses: bci_serif_anchor_common
4777 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
4781 bci_action_serif_anchor_lower_bound
,
4785 bci_serif_anchor_common
,
4798 * bci_action_serif_anchor_upper_bound
4800 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4801 * anchor, then moving it again if necessary to stay within an upper
4804 * in: edge_point (in twilight zone)
4805 * edge[1] (in twilight zone)
4806 * ... stuff for bci_align_segments (edge) ...
4808 * uses: bci_serif_anchor_common
4812 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
4816 bci_action_serif_anchor_upper_bound
,
4820 bci_serif_anchor_common
,
4833 * bci_action_serif_anchor_upper_lower_bound
4835 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
4836 * anchor, then moving it again if necessary to stay within a lower and
4839 * in: edge_point (in twilight zone)
4840 * edge[-1] (in twilight zone)
4841 * edge[1] (in twilight zone)
4842 * ... stuff for bci_align_segments (edge) ...
4844 * uses: bci_serif_anchor_common
4845 * bci_upper_lower_bound
4848 unsigned char FPGM(bci_action_serif_anchor_upper_lower_bound
) [] =
4852 bci_action_serif_anchor_upper_lower_bound
,
4856 bci_serif_anchor_common
,
4860 bci_upper_lower_bound
,
4869 * bci_serif_link1_common
4871 * Common code for bci_action_serif_link1 routines.
4876 unsigned char FPGM(bci_serif_link1_common
) [] =
4880 bci_serif_link1_common
,
4885 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
4889 CINDEX
, /* s: [...] after edge before after */
4892 CINDEX
, /* s: [...] after edge before after before */
4896 EQ
, /* after_orig_pos == before_orig_pos */
4897 IF
, /* s: [...] after edge before */
4898 MDAP_noround
, /* set rp0 and rp1 to `before' */
4900 ALIGNRP
, /* align `edge' with `before' */
4905 /* we have to execute `a*b/c', with b/c very near to 1: */
4906 /* to avoid overflow while retaining precision, */
4907 /* we transform this to `a + a * (b-c)/c' */
4911 CINDEX
, /* s: [...] after edge before edge */
4914 CINDEX
, /* s: [...] after edge before edge before */
4915 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
4920 CINDEX
, /* s: [...] after edge before a a after */
4923 CINDEX
, /* s: [...] after edge before a a after before */
4924 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
4928 CINDEX
, /* s: [...] after edge before a a c after */
4931 CINDEX
, /* s: [...] after edge before a a c after before */
4932 MD_cur
, /* b = after_pos - before_pos */
4936 CINDEX
, /* s: [...] after edge before a a c b c */
4942 MUL
, /* (b-c) in 16.16 format */
4947 DIV
, /* s: [...] after edge before a a (b-c)/c */
4949 POP
, /* avoid division by zero */
4952 MUL
, /* a * (b-c)/c * 2^10 */
4953 DIV_BY_1024
, /* a * (b-c)/c */
4957 MDAP_noround
, /* set rp0 and rp1 to `before' */
4958 SWAP
, /* s: [...] after a*b/c edge */
4961 ALIGNRP
, /* align `edge' with `before' */
4963 SHPIX
, /* shift `edge' by `a*b/c' */
4965 SWAP
, /* s: [...] edge after */
4975 * bci_action_serif_link1
4977 * Handle the SERIF_LINK1 action to align a serif, depending on edges
4980 * in: before_point (in twilight zone)
4981 * edge_point (in twilight zone)
4982 * after_point (in twilight zone)
4983 * ... stuff for bci_align_segments (edge) ...
4985 * uses: bci_serif_link1_common
4986 * bci_align_segments
4989 unsigned char FPGM(bci_action_serif_link1
) [] =
4993 bci_action_serif_link1
,
4997 bci_serif_link1_common
,
5000 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5005 SZP1
, /* set zp1 to normal zone 1 */
5014 * bci_action_serif_link1_lower_bound
5016 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5017 * before and after. Additionally, move the serif again if necessary to
5018 * stay within a lower bound.
5020 * in: before_point (in twilight zone)
5021 * edge_point (in twilight zone)
5022 * after_point (in twilight zone)
5023 * edge[-1] (in twilight zone)
5024 * ... stuff for bci_align_segments (edge) ...
5026 * uses: bci_serif_link1_common
5030 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
5034 bci_action_serif_link1_lower_bound
,
5038 bci_serif_link1_common
,
5051 * bci_action_serif_link1_upper_bound
5053 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5054 * before and after. Additionally, move the serif again if necessary to
5055 * stay within an upper bound.
5057 * in: before_point (in twilight zone)
5058 * edge_point (in twilight zone)
5059 * after_point (in twilight zone)
5060 * edge[1] (in twilight zone)
5061 * ... stuff for bci_align_segments (edge) ...
5063 * uses: bci_serif_link1_common
5067 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
5071 bci_action_serif_link1_upper_bound
,
5075 bci_serif_link1_common
,
5088 * bci_action_serif_link1_upper_lower_bound
5090 * Handle the SERIF_LINK1 action to align a serif, depending on edges
5091 * before and after. Additionally, move the serif again if necessary to
5092 * stay within a lower and upper bound.
5094 * in: before_point (in twilight zone)
5095 * edge_point (in twilight zone)
5096 * after_point (in twilight zone)
5097 * edge[-1] (in twilight zone)
5098 * edge[1] (in twilight zone)
5099 * ... stuff for bci_align_segments (edge) ...
5101 * uses: bci_serif_link1_common
5102 * bci_upper_lower_bound
5105 unsigned char FPGM(bci_action_serif_link1_upper_lower_bound
) [] =
5109 bci_action_serif_link1_upper_lower_bound
,
5113 bci_serif_link1_common
,
5117 bci_upper_lower_bound
,
5126 * bci_serif_link2_common
5128 * Common code for bci_action_serif_link2 routines.
5133 unsigned char FPGM(bci_serif_link2_common
) [] =
5137 bci_serif_link2_common
,
5142 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
5144 DUP
, /* s: [...] edge edge */
5148 DUP
, /* s: [...] edge edge anchor anchor */
5149 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
5158 DIV_BY_2
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
5163 ALIGNRP
, /* align `edge' with `sal_anchor' */
5165 SHPIX
, /* shift `edge' by `delta' */
5173 * bci_action_serif_link2
5175 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5177 * in: edge_point (in twilight zone)
5178 * ... stuff for bci_align_segments (edge) ...
5180 * uses: bci_serif_link2_common
5181 * bci_align_segments
5184 unsigned char FPGM(bci_action_serif_link2
) [] =
5188 bci_action_serif_link2
,
5192 bci_serif_link2_common
,
5195 MDAP_noround
, /* set rp0 and rp1 to `edge' */
5200 SZP1
, /* set zp1 to normal zone 1 */
5209 * bci_action_serif_link2_lower_bound
5211 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5212 * Additionally, move the serif again if necessary to stay within a lower
5215 * in: edge_point (in twilight zone)
5216 * edge[-1] (in twilight zone)
5217 * ... stuff for bci_align_segments (edge) ...
5219 * uses: bci_serif_link2_common
5223 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
5227 bci_action_serif_link2_lower_bound
,
5231 bci_serif_link2_common
,
5244 * bci_action_serif_link2_upper_bound
5246 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5247 * Additionally, move the serif again if necessary to stay within an upper
5250 * in: edge_point (in twilight zone)
5251 * edge[1] (in twilight zone)
5252 * ... stuff for bci_align_segments (edge) ...
5254 * uses: bci_serif_link2_common
5258 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
5262 bci_action_serif_link2_upper_bound
,
5266 bci_serif_link2_common
,
5279 * bci_action_serif_link2_upper_lower_bound
5281 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
5282 * Additionally, move the serif again if necessary to stay within a lower
5285 * in: edge_point (in twilight zone)
5286 * edge[-1] (in twilight zone)
5287 * edge[1] (in twilight zone)
5288 * ... stuff for bci_align_segments (edge) ...
5290 * uses: bci_serif_link2_common
5291 * bci_upper_lower_bound
5294 unsigned char FPGM(bci_action_serif_link2_upper_lower_bound
) [] =
5298 bci_action_serif_link2_upper_lower_bound
,
5302 bci_serif_link2_common
,
5306 bci_upper_lower_bound
,
5317 * This is the top-level glyph hinting function which parses the arguments
5318 * on the stack and calls subroutines.
5320 * in: action_0_func_idx
5326 * CVT: cvtl_is_subglyph
5328 * uses: bci_action_ip_before
5329 * bci_action_ip_after
5331 * bci_action_ip_between
5333 * bci_action_adjust_bound
5334 * bci_action_adjust_bound_serif
5335 * bci_action_adjust_bound_round
5336 * bci_action_adjust_bound_round_serif
5338 * bci_action_stem_bound
5339 * bci_action_stem_bound_serif
5340 * bci_action_stem_bound_round
5341 * bci_action_stem_bound_round_serif
5344 * bci_action_link_serif
5345 * bci_action_link_round
5346 * bci_action_link_round_serif
5349 * bci_action_anchor_serif
5350 * bci_action_anchor_round
5351 * bci_action_anchor_round_serif
5353 * bci_action_blue_anchor
5356 * bci_action_adjust_serif
5357 * bci_action_adjust_round
5358 * bci_action_adjust_round_serif
5361 * bci_action_stem_serif
5362 * bci_action_stem_round
5363 * bci_action_stem_round_serif
5368 * bci_action_serif_lower_bound
5369 * bci_action_serif_upper_bound
5370 * bci_action_serif_upper_lower_bound
5372 * bci_action_serif_anchor
5373 * bci_action_serif_anchor_lower_bound
5374 * bci_action_serif_anchor_upper_bound
5375 * bci_action_serif_anchor_upper_lower_bound
5377 * bci_action_serif_link1
5378 * bci_action_serif_link1_lower_bound
5379 * bci_action_serif_link1_upper_bound
5380 * bci_action_serif_link1_upper_lower_bound
5382 * bci_action_serif_link2
5383 * bci_action_serif_link2_lower_bound
5384 * bci_action_serif_link2_upper_bound
5385 * bci_action_serif_link2_upper_lower_bound
5388 unsigned char FPGM(bci_hint_glyph
) [] =
5396 /* loop until all data on stack is used */
5405 JROT
, /* goto start_loop */
5409 SZP2
, /* set zp2 to normal zone 1 */
5417 #define COPY_FPGM(func_name) \
5420 memcpy(bufp, fpgm_ ## func_name, \
5421 sizeof (fpgm_ ## func_name)); \
5422 bufp += sizeof (fpgm_ ## func_name); \
5426 TA_table_build_fpgm(FT_Byte
** fpgm
,
5437 /* for compatibility with dumb bytecode interpreters or analyzers, */
5438 /* FDEFs are stored in ascending index order, without holes -- */
5439 /* note that some FDEFs are not always needed */
5440 /* (depending on options of `TTFautohint'), */
5441 /* but implementing dynamic FDEF indices would be a lot of work */
5443 buf_len
= sizeof (FPGM(bci_align_top_a
))
5444 + (font
->increase_x_height
5445 ? (sizeof (FPGM(bci_align_top_b1a
))
5447 + sizeof (FPGM(bci_align_top_b1b
)))
5448 : sizeof (FPGM(bci_align_top_b2
)))
5449 + sizeof (FPGM(bci_align_top_c
))
5450 + sizeof (FPGM(bci_round
))
5451 + sizeof (FPGM(bci_smooth_stem_width
))
5452 + sizeof (FPGM(bci_get_best_width
))
5453 + sizeof (FPGM(bci_strong_stem_width
))
5454 + sizeof (FPGM(bci_loop_do
))
5455 + sizeof (FPGM(bci_loop
))
5456 + sizeof (FPGM(bci_cvt_rescale
))
5457 + sizeof (FPGM(bci_cvt_rescale_range
))
5458 + sizeof (FPGM(bci_vwidth_data_store
))
5459 + sizeof (FPGM(bci_blue_round
))
5460 + sizeof (FPGM(bci_blue_round_range
))
5461 + sizeof (FPGM(bci_decrement_component_counter
))
5462 + sizeof (FPGM(bci_get_point_extrema
))
5463 + sizeof (FPGM(bci_nibbles
))
5464 + sizeof (FPGM(bci_number_set_is_element
))
5465 + sizeof (FPGM(bci_number_set_is_element2
))
5467 + sizeof (FPGM(bci_create_segment
))
5468 + sizeof (FPGM(bci_create_segments
))
5470 + sizeof (FPGM(bci_create_segments_0
))
5471 + sizeof (FPGM(bci_create_segments_1
))
5472 + sizeof (FPGM(bci_create_segments_2
))
5473 + sizeof (FPGM(bci_create_segments_3
))
5474 + sizeof (FPGM(bci_create_segments_4
))
5475 + sizeof (FPGM(bci_create_segments_5
))
5476 + sizeof (FPGM(bci_create_segments_6
))
5477 + sizeof (FPGM(bci_create_segments_7
))
5478 + sizeof (FPGM(bci_create_segments_8
))
5479 + sizeof (FPGM(bci_create_segments_9
))
5481 + sizeof (FPGM(bci_create_segments_composite
))
5483 + sizeof (FPGM(bci_create_segments_composite_0
))
5484 + sizeof (FPGM(bci_create_segments_composite_1
))
5485 + sizeof (FPGM(bci_create_segments_composite_2
))
5486 + sizeof (FPGM(bci_create_segments_composite_3
))
5487 + sizeof (FPGM(bci_create_segments_composite_4
))
5488 + sizeof (FPGM(bci_create_segments_composite_5
))
5489 + sizeof (FPGM(bci_create_segments_composite_6
))
5490 + sizeof (FPGM(bci_create_segments_composite_7
))
5491 + sizeof (FPGM(bci_create_segments_composite_8
))
5492 + sizeof (FPGM(bci_create_segments_composite_9
))
5494 + sizeof (FPGM(bci_align_point
))
5495 + sizeof (FPGM(bci_align_segment
))
5496 + sizeof (FPGM(bci_align_segments
))
5498 + sizeof (FPGM(bci_scale_contour
))
5499 + sizeof (FPGM(bci_scale_glyph
))
5500 + sizeof (FPGM(bci_scale_composite_glyph
))
5501 + sizeof (FPGM(bci_shift_contour
))
5502 + sizeof (FPGM(bci_shift_subglyph
))
5504 + sizeof (FPGM(bci_ip_outer_align_point
))
5505 + sizeof (FPGM(bci_ip_on_align_points
))
5506 + sizeof (FPGM(bci_ip_between_align_point
))
5507 + sizeof (FPGM(bci_ip_between_align_points
))
5509 + sizeof (FPGM(bci_adjust_common
))
5510 + sizeof (FPGM(bci_stem_common
))
5511 + sizeof (FPGM(bci_serif_common
))
5512 + sizeof (FPGM(bci_serif_anchor_common
))
5513 + sizeof (FPGM(bci_serif_link1_common
))
5514 + sizeof (FPGM(bci_serif_link2_common
))
5516 + sizeof (FPGM(bci_lower_bound
))
5517 + sizeof (FPGM(bci_upper_bound
))
5518 + sizeof (FPGM(bci_upper_lower_bound
))
5520 + sizeof (FPGM(bci_adjust_bound
))
5521 + sizeof (FPGM(bci_stem_bound
))
5522 + sizeof (FPGM(bci_link
))
5523 + sizeof (FPGM(bci_anchor
))
5524 + sizeof (FPGM(bci_adjust
))
5525 + sizeof (FPGM(bci_stem
))
5527 + sizeof (FPGM(bci_action_ip_before
))
5528 + sizeof (FPGM(bci_action_ip_after
))
5529 + sizeof (FPGM(bci_action_ip_on
))
5530 + sizeof (FPGM(bci_action_ip_between
))
5532 + sizeof (FPGM(bci_action_blue
))
5533 + sizeof (FPGM(bci_action_blue_anchor
))
5535 + sizeof (FPGM(bci_action_anchor
))
5536 + sizeof (FPGM(bci_action_anchor_serif
))
5537 + sizeof (FPGM(bci_action_anchor_round
))
5538 + sizeof (FPGM(bci_action_anchor_round_serif
))
5540 + sizeof (FPGM(bci_action_adjust
))
5541 + sizeof (FPGM(bci_action_adjust_serif
))
5542 + sizeof (FPGM(bci_action_adjust_round
))
5543 + sizeof (FPGM(bci_action_adjust_round_serif
))
5544 + sizeof (FPGM(bci_action_adjust_bound
))
5545 + sizeof (FPGM(bci_action_adjust_bound_serif
))
5546 + sizeof (FPGM(bci_action_adjust_bound_round
))
5547 + sizeof (FPGM(bci_action_adjust_bound_round_serif
))
5549 + sizeof (FPGM(bci_action_link
))
5550 + sizeof (FPGM(bci_action_link_serif
))
5551 + sizeof (FPGM(bci_action_link_round
))
5552 + sizeof (FPGM(bci_action_link_round_serif
))
5554 + sizeof (FPGM(bci_action_stem
))
5555 + sizeof (FPGM(bci_action_stem_serif
))
5556 + sizeof (FPGM(bci_action_stem_round
))
5557 + sizeof (FPGM(bci_action_stem_round_serif
))
5558 + sizeof (FPGM(bci_action_stem_bound
))
5559 + sizeof (FPGM(bci_action_stem_bound_serif
))
5560 + sizeof (FPGM(bci_action_stem_bound_round
))
5561 + sizeof (FPGM(bci_action_stem_bound_round_serif
))
5563 + sizeof (FPGM(bci_action_serif
))
5564 + sizeof (FPGM(bci_action_serif_lower_bound
))
5565 + sizeof (FPGM(bci_action_serif_upper_bound
))
5566 + sizeof (FPGM(bci_action_serif_upper_lower_bound
))
5568 + sizeof (FPGM(bci_action_serif_anchor
))
5569 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
5570 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
5571 + sizeof (FPGM(bci_action_serif_anchor_upper_lower_bound
))
5573 + sizeof (FPGM(bci_action_serif_link1
))
5574 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
5575 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
5576 + sizeof (FPGM(bci_action_serif_link1_upper_lower_bound
))
5578 + sizeof (FPGM(bci_action_serif_link2
))
5579 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
5580 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
5581 + sizeof (FPGM(bci_action_serif_link2_upper_lower_bound
))
5583 + sizeof (FPGM(bci_hint_glyph
));
5585 /* buffer length must be a multiple of four */
5586 len
= (buf_len
+ 3) & ~3;
5587 buf
= (FT_Byte
*)malloc(len
);
5589 return FT_Err_Out_Of_Memory
;
5591 /* pad end of buffer with zeros */
5592 buf
[len
- 1] = 0x00;
5593 buf
[len
- 2] = 0x00;
5594 buf
[len
- 3] = 0x00;
5596 /* copy font program into buffer and fill in the missing variables */
5599 COPY_FPGM(bci_align_top_a
);
5600 if (font
->increase_x_height
)
5602 COPY_FPGM(bci_align_top_b1a
);
5603 *(bufp
++) = HIGH(font
->increase_x_height
);
5604 *(bufp
++) = LOW(font
->increase_x_height
);
5605 COPY_FPGM(bci_align_top_b1b
);
5608 COPY_FPGM(bci_align_top_b2
);
5609 COPY_FPGM(bci_align_top_c
);
5611 COPY_FPGM(bci_round
);
5612 COPY_FPGM(bci_smooth_stem_width
);
5613 COPY_FPGM(bci_get_best_width
);
5614 COPY_FPGM(bci_strong_stem_width
);
5615 COPY_FPGM(bci_loop_do
);
5616 COPY_FPGM(bci_loop
);
5617 COPY_FPGM(bci_cvt_rescale
);
5618 COPY_FPGM(bci_cvt_rescale_range
);
5619 COPY_FPGM(bci_vwidth_data_store
);
5620 COPY_FPGM(bci_blue_round
);
5621 COPY_FPGM(bci_blue_round_range
);
5622 COPY_FPGM(bci_decrement_component_counter
);
5623 COPY_FPGM(bci_get_point_extrema
);
5624 COPY_FPGM(bci_nibbles
);
5625 COPY_FPGM(bci_number_set_is_element
);
5626 COPY_FPGM(bci_number_set_is_element2
);
5628 COPY_FPGM(bci_create_segment
);
5629 COPY_FPGM(bci_create_segments
);
5631 COPY_FPGM(bci_create_segments_0
);
5632 COPY_FPGM(bci_create_segments_1
);
5633 COPY_FPGM(bci_create_segments_2
);
5634 COPY_FPGM(bci_create_segments_3
);
5635 COPY_FPGM(bci_create_segments_4
);
5636 COPY_FPGM(bci_create_segments_5
);
5637 COPY_FPGM(bci_create_segments_6
);
5638 COPY_FPGM(bci_create_segments_7
);
5639 COPY_FPGM(bci_create_segments_8
);
5640 COPY_FPGM(bci_create_segments_9
);
5642 COPY_FPGM(bci_create_segments_composite
);
5644 COPY_FPGM(bci_create_segments_composite_0
);
5645 COPY_FPGM(bci_create_segments_composite_1
);
5646 COPY_FPGM(bci_create_segments_composite_2
);
5647 COPY_FPGM(bci_create_segments_composite_3
);
5648 COPY_FPGM(bci_create_segments_composite_4
);
5649 COPY_FPGM(bci_create_segments_composite_5
);
5650 COPY_FPGM(bci_create_segments_composite_6
);
5651 COPY_FPGM(bci_create_segments_composite_7
);
5652 COPY_FPGM(bci_create_segments_composite_8
);
5653 COPY_FPGM(bci_create_segments_composite_9
);
5655 COPY_FPGM(bci_align_point
);
5656 COPY_FPGM(bci_align_segment
);
5657 COPY_FPGM(bci_align_segments
);
5659 COPY_FPGM(bci_scale_contour
);
5660 COPY_FPGM(bci_scale_glyph
);
5661 COPY_FPGM(bci_scale_composite_glyph
);
5662 COPY_FPGM(bci_shift_contour
);
5663 COPY_FPGM(bci_shift_subglyph
);
5665 COPY_FPGM(bci_ip_outer_align_point
);
5666 COPY_FPGM(bci_ip_on_align_points
);
5667 COPY_FPGM(bci_ip_between_align_point
);
5668 COPY_FPGM(bci_ip_between_align_points
);
5670 COPY_FPGM(bci_adjust_common
);
5671 COPY_FPGM(bci_stem_common
);
5672 COPY_FPGM(bci_serif_common
);
5673 COPY_FPGM(bci_serif_anchor_common
);
5674 COPY_FPGM(bci_serif_link1_common
);
5675 COPY_FPGM(bci_serif_link2_common
);
5677 COPY_FPGM(bci_lower_bound
);
5678 COPY_FPGM(bci_upper_bound
);
5679 COPY_FPGM(bci_upper_lower_bound
);
5681 COPY_FPGM(bci_adjust_bound
);
5682 COPY_FPGM(bci_stem_bound
);
5683 COPY_FPGM(bci_link
);
5684 COPY_FPGM(bci_anchor
);
5685 COPY_FPGM(bci_adjust
);
5686 COPY_FPGM(bci_stem
);
5688 COPY_FPGM(bci_action_ip_before
);
5689 COPY_FPGM(bci_action_ip_after
);
5690 COPY_FPGM(bci_action_ip_on
);
5691 COPY_FPGM(bci_action_ip_between
);
5693 COPY_FPGM(bci_action_blue
);
5694 COPY_FPGM(bci_action_blue_anchor
);
5696 COPY_FPGM(bci_action_anchor
);
5697 COPY_FPGM(bci_action_anchor_serif
);
5698 COPY_FPGM(bci_action_anchor_round
);
5699 COPY_FPGM(bci_action_anchor_round_serif
);
5701 COPY_FPGM(bci_action_adjust
);
5702 COPY_FPGM(bci_action_adjust_serif
);
5703 COPY_FPGM(bci_action_adjust_round
);
5704 COPY_FPGM(bci_action_adjust_round_serif
);
5705 COPY_FPGM(bci_action_adjust_bound
);
5706 COPY_FPGM(bci_action_adjust_bound_serif
);
5707 COPY_FPGM(bci_action_adjust_bound_round
);
5708 COPY_FPGM(bci_action_adjust_bound_round_serif
);
5710 COPY_FPGM(bci_action_link
);
5711 COPY_FPGM(bci_action_link_serif
);
5712 COPY_FPGM(bci_action_link_round
);
5713 COPY_FPGM(bci_action_link_round_serif
);
5715 COPY_FPGM(bci_action_stem
);
5716 COPY_FPGM(bci_action_stem_serif
);
5717 COPY_FPGM(bci_action_stem_round
);
5718 COPY_FPGM(bci_action_stem_round_serif
);
5719 COPY_FPGM(bci_action_stem_bound
);
5720 COPY_FPGM(bci_action_stem_bound_serif
);
5721 COPY_FPGM(bci_action_stem_bound_round
);
5722 COPY_FPGM(bci_action_stem_bound_round_serif
);
5724 COPY_FPGM(bci_action_serif
);
5725 COPY_FPGM(bci_action_serif_lower_bound
);
5726 COPY_FPGM(bci_action_serif_upper_bound
);
5727 COPY_FPGM(bci_action_serif_upper_lower_bound
);
5729 COPY_FPGM(bci_action_serif_anchor
);
5730 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
5731 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
5732 COPY_FPGM(bci_action_serif_anchor_upper_lower_bound
);
5734 COPY_FPGM(bci_action_serif_link1
);
5735 COPY_FPGM(bci_action_serif_link1_lower_bound
);
5736 COPY_FPGM(bci_action_serif_link1_upper_bound
);
5737 COPY_FPGM(bci_action_serif_link1_upper_lower_bound
);
5739 COPY_FPGM(bci_action_serif_link2
);
5740 COPY_FPGM(bci_action_serif_link2_lower_bound
);
5741 COPY_FPGM(bci_action_serif_link2_upper_bound
);
5742 COPY_FPGM(bci_action_serif_link2_upper_lower_bound
);
5744 COPY_FPGM(bci_hint_glyph
);
5747 *fpgm_len
= buf_len
;
5754 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
5759 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
5760 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
5766 error
= TA_sfnt_add_table_info(sfnt
);
5770 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
5771 if (glyf_table
->processed
)
5773 sfnt
->table_infos
[sfnt
->num_table_infos
- 1] = data
->fpgm_idx
;
5777 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, sfnt
, font
);
5781 if (fpgm_len
> sfnt
->max_instructions
)
5782 sfnt
->max_instructions
= fpgm_len
;
5784 /* in case of success, `fpgm_buf' gets linked */
5785 /* and is eventually freed in `TA_font_unload' */
5786 error
= TA_font_add_table(font
,
5787 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
5788 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
5792 data
->fpgm_idx
= sfnt
->table_infos
[sfnt
->num_table_infos
- 1];
5798 /* end of tafpgm.c */