4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
19 /* we need the following macro */
20 /* so that `func_name' doesn't get replaced with its #defined value */
21 /* (as defined in `tabytecode.h') */
23 #define FPGM(func_name) fpgm_ ## func_name
27 * Due to a bug in FreeType up to and including version 2.4.7,
28 * it is not possible to use MD_orig with twilight points.
29 * We circumvent this by using GC_orig.
31 #define MD_orig_fixed \
38 #define MD_orig_ZP2_0 \
41 #define MD_orig_ZP2_1 \
51 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
57 MUL, /* delta * 2^10 */ \
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
80 unsigned char FPGM(bci_round
) [] =
107 * bci_compute_stem_width
109 * This is the equivalent to the following code from function
110 * `ta_latin_compute_stem_width':
118 * else if base_is_round:
124 * delta = ABS(dist - std_width)
135 * delta = delta - dist
138 * dist = dist + delta
139 * else if delta < 32:
141 * else if delta < 54:
144 * dist = dist + delta
160 * CVT: cvtl_is_extra_light
164 unsigned char FPGM(bci_compute_stem_width_a
) [] =
168 bci_compute_stem_width
,
172 ABS
, /* s: base_is_round stem_is_serif width dist */
177 LT
, /* dist < 3*64 */
181 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
182 AND
, /* stem_is_serif && dist < 3*64 */
187 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
189 IF
, /* s: base_is_round width dist */
195 ROLL
, /* s: width dist base_is_round */
196 IF
, /* s: width dist */
201 IF
, /* s: width dist */
212 IF
, /* s: width dist */
219 DUP
, /* s: width dist dist */
224 /* %c, index of std_width */
226 unsigned char FPGM(bci_compute_stem_width_b
) [] =
231 ABS
, /* s: width dist delta */
236 IF
, /* s: width dist */
242 /* %c, index of std_width */
244 unsigned char FPGM(bci_compute_stem_width_c
) [] =
247 RCVT
, /* dist = std_width */
259 DUP
, /* s: width dist dist */
262 LT
, /* dist < 3*64 */
264 DUP
, /* s: width delta dist */
265 FLOOR
, /* dist = FLOOR(dist) */
266 DUP
, /* s: width delta dist dist */
268 ROLL
, /* s: width dist delta dist */
269 SUB
, /* delta = delta - dist */
271 DUP
, /* s: width dist delta delta */
275 IF
, /* s: width dist delta */
276 ADD
, /* dist = dist + delta */
287 ADD
, /* dist = dist + 10 */
298 ADD
, /* dist = dist + 54 */
301 ADD
, /* dist = dist + delta */
310 CALL
, /* dist = round(dist) */
315 SWAP
, /* s: dist width */
320 NEG
, /* dist = -dist */
332 * Take a range and a function number and apply the function to all
333 * elements of the range.
339 * sal: sal_i (counter initialized with `start')
341 * sal_func (`func_num')
344 unsigned char FPGM(bci_loop
) [] =
354 WS
, /* sal_func = func_num */
358 WS
, /* sal_limit = end */
362 WS
, /* sal_i = start */
371 LTEQ
, /* start <= end */
382 ADD
, /* start = start + 1 */
388 JMPR
, /* goto start_loop */
399 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
401 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
402 * consequently, the calculation `a * b/c' is done as `a + delta' with
403 * `delta = a * (b-c)/c'. This avoids overflow.
405 * sal: sal_i (CVT index)
411 unsigned char FPGM(bci_cvt_rescale
) [] =
434 * Round a blue ref value and adjust its corresponding shoot value.
436 * sal: sal_i (CVT index)
440 unsigned char FPGM(bci_blue_round_a
) [] =
451 RCVT
, /* s: ref_idx ref */
457 SWAP
, /* s: ref_idx round(ref) ref */
465 unsigned char FPGM(bci_blue_round_b
) [] =
470 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
472 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
474 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
476 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
478 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
503 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
508 NEG
, /* delta = -delta */
515 SUB
, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
526 * bci_decrement_component_counter
528 * An auxiliary function for composite glyphs.
530 * CVT: cvtl_is_subglyph
533 unsigned char FPGM(bci_decrement_component_counter
) [] =
537 bci_decrement_component_counter
,
540 /* decrement `cvtl_is_subglyph' counter */
556 * bci_get_point_extrema
558 * An auxiliary function for `bci_create_segment'.
567 unsigned char FPGM(bci_get_point_extrema
) [] =
571 bci_get_point_extrema
,
580 /* check whether `point' is a new minimum */
583 RS
, /* s: point point point point_min */
585 /* if distance is negative, we have a new minimum */
589 IF
, /* s: point point */
597 /* check whether `point' is a new maximum */
600 RS
, /* s: point point point_max */
602 /* if distance is positive, we have a new maximum */
622 * Store start and end point of a segment in the storage area,
623 * then construct a point in the twilight zone to represent it.
625 * This function is used by `bci_create_segment_points'.
629 * [last (if wrap-around segment)]
630 * [first (if wrap-around segment)]
632 * uses: bci_get_point_extrema
634 * sal: sal_i (start of current segment)
635 * sal_j (current twilight point)
644 unsigned char FPGM(bci_create_segment
) [] =
657 WS
, /* sal[sal_i] = start */
659 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
665 ADD
, /* sal_i = sal_i + 1 */
668 /* initialize inner loop(s) */
673 WS
, /* sal_point_min = start */
678 WS
, /* sal_point_max = start */
682 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
688 CINDEX
, /* s: start end end start */
689 LT
, /* start > end */
691 /* we have a wrap-around segment with two more arguments */
692 /* to give the last and first point of the contour, respectively; */
693 /* our job is to store a segment `start'-`last', */
694 /* and to get extrema for the two segments */
695 /* `start'-`last' and `first'-`end' */
697 /* s: first last start end */
704 WS
, /* sal[sal_i] = last */
707 ROLL
, /* s: first end last start */
710 SWAP
, /* s: first end start last start */
711 SUB
, /* s: first end start loop_count */
714 bci_get_point_extrema
,
719 SWAP
, /* s: end first */
724 ROLL
, /* s: (first - 1) (first - 1) end */
726 SUB
, /* s: (first - 1) loop_count */
729 bci_get_point_extrema
,
734 ELSE
, /* s: start end */
741 WS
, /* sal[sal_i] = end */
746 SUB
, /* s: start loop_count */
749 bci_get_point_extrema
,
755 /* the twilight point representing a segment */
756 /* is in the middle between the minimum and maximum */
768 DIV
, /* s: middle_pos */
770 DO_SCALE
, /* middle_pos = middle_pos * scale */
772 /* write it to temporary CVT location */
776 SZP0
, /* set zp0 to twilight zone 0 */
780 /* create twilight point with index `sal_j' */
793 ADD
, /* twilight_point = twilight_point + 1 */
802 * bci_create_segments
804 * Set up segments by defining point ranges which defines them
805 * and computing twilight points to represent them.
807 * in: num_segments (N)
810 * [contour_last 0 (if wrap-around segment)]
811 * [contour_first 0 (if wrap-around segment)]
814 * [contour_last 0 (if wrap-around segment)]
815 * [contour_first 0 (if wrap-around segment)]
817 * segment_start_(N-1)
819 * [contour_last (N-1) (if wrap-around segment)]
820 * [contour_first (N-1) (if wrap-around segment)]
822 * uses: bci_create_segment
824 * sal: sal_i (start of current segment)
825 * sal_j (current twilight point)
827 * CVT: cvtl_is_subglyph
830 unsigned char FPGM(bci_create_segments
) [] =
837 /* only do something if we are not a subglyph */
844 /* all our measurements are taken along the y axis */
851 SUB
, /* delta = (2*num_segments - 1) */
859 WS
, /* sal_j = 0 (point offset) */
862 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
864 /* `bci_create_segment_point' also increases the loop counter by 1; */
865 /* this effectively means we have a loop step of 2 */
881 * bci_create_segments_composite
883 * The same as `bci_create_composite'.
884 * It also decrements the composite component counter.
886 * uses: bci_decrement_composite_counter
888 * CVT: cvtl_is_subglyph
891 unsigned char FPGM(bci_create_segments_composite
) [] =
895 bci_create_segments_composite
,
899 bci_decrement_component_counter
,
902 /* only do something if we are not a subglyph */
909 /* all our measurements are taken along the y axis */
916 SUB
, /* delta = (2*num_segments - 1) */
924 WS
, /* sal_j = 0 (point offset) */
927 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
929 /* `bci_create_segment_point' also increases the loop counter by 1; */
930 /* this effectively means we have a loop step of 2 */
948 * Align all points in a segment to the twilight point in rp0.
949 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
954 unsigned char FPGM(bci_align_segment
) [] =
961 /* we need the values of `sal_segment_offset + 2*segment_index' */
962 /* and `sal_segment_offset + 2*segment_index + 1' */
974 RS
, /* s: first last */
979 CINDEX
, /* s: first last first */
982 CINDEX
, /* s: first last first last */
983 LTEQ
, /* first <= end */
984 IF
, /* s: first last */
986 DUP
, /* s: last first first */
987 ALIGNRP
, /* align point with index `first' with rp0 */
991 ADD
, /* first = first + 1 */
992 SWAP
, /* s: first last */
997 JMPR
, /* goto start_loop */
1010 * bci_align_segments
1012 * Align segments to the twilight point in rp0.
1013 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1022 * uses: handle_segment
1026 unsigned char FPGM(bci_align_segments
) [] =
1049 * Scale a contour using two points giving the maximum and minimum
1052 * It expects that no point on the contour is touched.
1061 unsigned char FPGM(bci_scale_contour
) [] =
1072 DO_SCALE
, /* min_pos_new = min_pos * scale */
1077 /* don't scale a single-point contour twice */
1086 DO_SCALE
, /* max_pos_new = max_pos * scale */
1103 * Scale a glyph using a list of points (two points per contour, giving
1104 * the maximum and mininum coordinates).
1106 * It expects that no point in the glyph is touched.
1108 * in: num_contours (N)
1117 * uses: bci_scale_contour
1119 * CVT: cvtl_is_subglyph
1122 unsigned char FPGM(bci_scale_glyph
) [] =
1129 /* only do something if we are not a subglyph */
1136 /* all our measurements are taken along the y axis */
1141 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1149 SZP2
, /* set zp2 to normal zone 1 */
1162 * bci_scale_composite_glyph
1164 * The same as `bci_scale_composite_glyph'.
1165 * It also decrements the composite component counter.
1167 * uses: bci_decrement_component_counter
1169 * CVT: cvtl_is_subglyph
1172 unsigned char FPGM(bci_scale_composite_glyph
) [] =
1176 bci_scale_composite_glyph
,
1180 bci_decrement_component_counter
,
1183 /* only do something if we are not a subglyph */
1190 /* all our measurements are taken along the y axis */
1195 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1203 SZP2
, /* set zp2 to normal zone 1 */
1218 * Shift a contour by a given amount.
1220 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1221 * point to the normal zone 1.
1227 unsigned char FPGM(bci_shift_contour
) [] =
1235 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1247 * bci_shift_subglyph
1249 * Shift a subglyph. To be more specific, it corrects the already applied
1250 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1253 * If this function is called, a point `x' in the subglyph has been scaled
1254 * already (during the hinting of the subglyph itself), and `offset' has
1255 * been applied also:
1257 * x -> x * scale + offset (1)
1259 * However, the offset should be applied first, then the scaling:
1261 * x -> (x + offset) * scale (2)
1263 * Our job is now to transform (1) to (2); a simple calculation shows that
1264 * we have to shift all points of the subglyph by
1266 * offset * scale - offset = offset * (scale - 1)
1268 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1270 * in: offset (in FUnits)
1274 * CVT: cvtl_funits_to_pixels
1279 unsigned char FPGM(bci_shift_subglyph
) [] =
1289 cvtl_funits_to_pixels
,
1290 RCVT
, /* scaling factor FUnits -> pixels */
1297 /* the autohinter always rounds offsets */
1300 CALL
, /* offset = round(offset) */
1309 DIV
, /* delta = offset * (scale - 1) */
1311 /* and round again */
1314 CALL
, /* offset = round(offset) */
1318 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1320 /* we create twilight point 0 as a reference point, */
1321 /* setting the original position to zero (using `cvtl_temp') */
1329 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
1331 SWAP
, /* s: first_contour num_contours 0 delta */
1332 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
1337 SZP2
, /* set zp2 to normal zone 1 */
1346 * bci_ip_outer_align_point
1348 * Auxiliary function for `bci_action_ip_before' and
1349 * `bci_action_ip_after'.
1351 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1352 * zone, and both zp1 and zp2 set to normal zone.
1356 * sal: sal_i (edge_orig_pos)
1362 unsigned char FPGM(bci_ip_outer_align_point
) [] =
1366 bci_ip_outer_align_point
,
1370 ALIGNRP
, /* align `point' with `edge' */
1373 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1378 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1387 * bci_ip_on_align_points
1389 * Auxiliary function for `bci_action_ip_on'.
1391 * in: edge (in twilight zone)
1399 unsigned char FPGM(bci_ip_on_align_points
) [] =
1403 bci_ip_on_align_points
,
1406 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1417 * bci_ip_between_align_point
1419 * Auxiliary function for `bci_ip_between_align_points'.
1421 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1422 * zone, and both zp1 and zp2 set to normal zone.
1426 * sal: sal_i (edge_orig_pos)
1427 * sal_j (stretch_factor)
1433 unsigned char FPGM(bci_ip_between_align_point
) [] =
1437 bci_ip_between_align_point
,
1441 ALIGNRP
, /* align `point' with `edge' */
1444 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1449 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1453 MUL
, /* s: point delta */
1462 * bci_ip_between_align_points
1464 * Auxiliary function for `bci_action_ip_between'.
1466 * in: after_edge (in twilight zone)
1467 * before_edge (in twilight zone)
1474 * sal: sal_i (before_orig_pos)
1475 * sal_j (stretch_factor)
1477 * uses: bci_ip_between_align_point
1480 unsigned char FPGM(bci_ip_between_align_points
) [] =
1484 bci_ip_between_align_points
,
1490 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1492 DUP
, /* s: ... before after before before */
1493 MDAP_noround
, /* set rp0 and rp1 to `before' */
1495 GC_orig
, /* s: ... before after before before_orig_pos */
1499 WS
, /* sal_i = before_orig_pos */
1502 CINDEX
, /* s: ... before after before after */
1503 MD_cur
, /* b = after_pos - before_pos */
1506 MD_orig_ZP2_0
, /* a = after_orig_pos - before_orig_pos */
1511 WS
, /* sal_j = stretch_factor */
1514 bci_ip_between_align_point
,
1517 SZP2
, /* set zp2 to normal zone 1 */
1518 SZP1
, /* set zp1 to normal zone 1 */
1527 * bci_action_ip_before
1529 * Handle `ip_before' data to align points located before the first edge.
1531 * in: first_edge (in twilight zone)
1538 * sal: sal_i (first_edge_orig_pos)
1540 * uses: bci_ip_outer_align_point
1543 unsigned char FPGM(bci_action_ip_before
) [] =
1547 bci_action_ip_before
,
1552 SZP2
, /* set zp2 to twilight zone 0 */
1559 WS
, /* sal_i = first_edge_orig_pos */
1565 SZP2
, /* set zp2 to normal zone 1 */
1566 SZP1
, /* set zp1 to normal zone 1 */
1567 SZP0
, /* set zp0 to twilight zone 0 */
1569 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
1572 bci_ip_outer_align_point
,
1581 * bci_action_ip_after
1583 * Handle `ip_after' data to align points located after the last edge.
1585 * in: last_edge (in twilight zone)
1592 * sal: sal_i (last_edge_orig_pos)
1594 * uses: bci_ip_outer_align_point
1597 unsigned char FPGM(bci_action_ip_after
) [] =
1601 bci_action_ip_after
,
1606 SZP2
, /* set zp2 to twilight zone 0 */
1613 WS
, /* sal_i = last_edge_orig_pos */
1619 SZP2
, /* set zp2 to normal zone 1 */
1620 SZP1
, /* set zp1 to normal zone 1 */
1621 SZP0
, /* set zp0 to twilight zone 0 */
1623 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
1626 bci_ip_outer_align_point
,
1637 * Handle `ip_on' data to align points located on an edge coordinate (but
1638 * not part of an edge).
1640 * in: loop_counter (M)
1641 * edge_1 (in twilight zone)
1642 * loop_counter (N_1)
1647 * edge_2 (in twilight zone)
1648 * loop_counter (N_2)
1654 * edge_M (in twilight zone)
1655 * loop_counter (N_M)
1661 * uses: bci_ip_on_align_points
1664 unsigned char FPGM(bci_action_ip_on
) [] =
1674 SZP1
, /* set zp1 to normal zone 1 */
1675 SZP0
, /* set zp0 to twilight zone 0 */
1678 bci_ip_on_align_points
,
1687 * bci_action_ip_between
1689 * Handle `ip_between' data to align points located between two edges.
1691 * in: loop_counter (M)
1692 * before_edge_1 (in twilight zone)
1693 * after_edge_1 (in twilight zone)
1694 * loop_counter (N_1)
1699 * before_edge_2 (in twilight zone)
1700 * after_edge_2 (in twilight zone)
1701 * loop_counter (N_2)
1707 * before_edge_M (in twilight zone)
1708 * after_edge_M (in twilight zone)
1709 * loop_counter (N_M)
1715 * uses: bci_ip_between_align_points
1718 unsigned char FPGM(bci_action_ip_between
) [] =
1722 bci_action_ip_between
,
1726 bci_ip_between_align_points
,
1735 * bci_action_adjust_common
1737 * Common code for bci_action_adjust routines.
1740 unsigned char FPGM(bci_action_adjust_common
) [] =
1744 bci_action_adjust_common
,
1749 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1753 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
1756 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1757 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1760 bci_compute_stem_width
,
1762 NEG
, /* s: [...] edge2 edge -cur_len */
1764 ROLL
, /* s: [...] edge -cur_len edge2 */
1765 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1768 DUP
, /* s: [...] -cur_len edge edge edge */
1769 ALIGNRP
, /* align `edge' with `edge2' */
1771 SHPIX
, /* shift `edge' by -cur_len */
1779 * bci_action_adjust_bound
1781 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1782 * edge of the stem has already been moved, then moving it again if
1783 * necessary to stay bound.
1785 * in: edge2_is_serif
1787 * edge_point (in twilight zone)
1788 * edge2_point (in twilight zone)
1789 * edge[-1] (in twilight zone)
1790 * ... stuff for bci_align_segments (edge) ...
1792 * uses: bci_action_adjust_common
1795 unsigned char FPGM(bci_action_adjust_bound
) [] =
1799 bci_action_adjust_bound
,
1803 bci_action_adjust_common
,
1806 SWAP
, /* s: edge edge[-1] */
1808 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1813 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1814 GT
, /* edge_pos < edge[-1]_pos */
1817 ALIGNRP
, /* align `edge' to `edge[-1]' */
1820 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1825 SZP1
, /* set zp1 to normal zone 1 */
1836 * Handle the ADJUST action to align an edge of a stem if the other edge
1837 * of the stem has already been moved.
1839 * in: edge2_is_serif
1841 * edge_point (in twilight zone)
1842 * edge2_point (in twilight zone)
1843 * ... stuff for bci_align_segments (edge) ...
1845 * uses: bci_action_adjust_common
1848 unsigned char FPGM(bci_action_adjust
) [] =
1856 bci_action_adjust_common
,
1859 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1864 SZP1
, /* set zp1 to normal zone 1 */
1873 * bci_action_stem_common
1875 * Common code for bci_action_stem routines.
1879 #define sal_u_off sal_temp1
1881 #define sal_d_off sal_temp2
1883 #define sal_org_len sal_temp3
1885 #define sal_edge2 sal_temp3
1887 unsigned char FPGM(bci_action_stem_common
) [] =
1891 bci_action_stem_common
,
1896 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1904 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1905 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1907 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1915 bci_compute_stem_width
,
1916 CALL
, /* s: [...] edge2 edge cur_len */
1921 LT
, /* cur_len < 96 */
1926 LTEQ
, /* cur_len <= 64 */
1944 SWAP
, /* s: [...] edge2 cur_len edge */
1949 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
1955 ADD
, /* s: [...] edge2 cur_len edge org_pos */
1962 ADD
, /* s: [...] edge2 cur_len edge org_center */
1967 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1972 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1979 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1986 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1988 LT
, /* delta1 < delta2 */
1993 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1999 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2000 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
2008 SUB
, /* arg = cur_pos1 - cur_len/2 */
2010 SWAP
, /* s: [...] edge2 cur_len arg edge */
2016 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
2019 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2022 SWAP
, /* s: [...] edge2 cur_len edge */
2026 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
2034 ADD
, /* s: [...] edge2 cur_len edge org_pos */
2043 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
2049 CALL
, /* cur_pos1 = ROUND(org_pos) */
2061 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2072 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2079 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2085 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2086 LT
, /* delta1 < delta2 */
2088 POP
, /* arg = cur_pos1 */
2092 POP
, /* arg = cur_pos2 */
2093 EIF
, /* s: [...] edge2 cur_len edge arg */
2100 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
2103 SHPIX
, /* edge = arg */
2104 EIF
, /* s: [...] edge2 cur_len edge */
2112 * bci_action_stem_bound
2114 * Handle the STEM action to align two edges of a stem, then moving one
2115 * edge again if necessary to stay bound.
2117 * The code after computing `cur_len' to shift `edge' and `edge2'
2118 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2121 * if cur_len < = 64:
2128 * org_pos = anchor + (edge_orig - anchor_orig);
2129 * org_center = org_pos + org_len / 2;
2131 * cur_pos1 = ROUND(org_center)
2132 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2133 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2134 * if (delta1 < delta2):
2135 * cur_pos1 = cur_pos1 - u_off
2137 * cur_pos1 = cur_pos1 + d_off
2139 * edge = cur_pos1 - cur_len / 2
2142 * org_pos = anchor + (edge_orig - anchor_orig)
2143 * org_center = org_pos + org_len / 2;
2145 * cur_pos1 = ROUND(org_pos)
2146 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2147 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2148 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2150 * if (delta1 < delta2):
2155 * edge2 = edge + cur_len
2157 * in: edge2_is_serif
2159 * edge_point (in twilight zone)
2160 * edge2_point (in twilight zone)
2161 * edge[-1] (in twilight zone)
2162 * ... stuff for bci_align_segments (edge) ...
2163 * ... stuff for bci_align_segments (edge2)...
2170 * uses: bci_action_stem_common
2173 unsigned char FPGM(bci_action_stem_bound
) [] =
2177 bci_action_stem_bound
,
2181 bci_action_stem_common
,
2184 ROLL
, /* s: edge[-1] cur_len edge edge2 */
2187 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2191 WS
, /* s: edge[-1] cur_len edge edge2 */
2193 SHPIX
, /* edge2 = edge + cur_len */
2195 SWAP
, /* s: edge edge[-1] */
2197 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2202 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2203 GT
, /* edge_pos < edge[-1]_pos */
2206 ALIGNRP
, /* align `edge' to `edge[-1]' */
2209 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2214 SZP1
, /* set zp1 to normal zone 1 */
2220 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2234 * Handle the STEM action to align two edges of a stem.
2236 * See `bci_action_stem_bound' for more details.
2238 * in: edge2_is_serif
2240 * edge_point (in twilight zone)
2241 * edge2_point (in twilight zone)
2242 * ... stuff for bci_align_segments (edge) ...
2243 * ... stuff for bci_align_segments (edge2)...
2250 * uses: bci_action_stem_common
2253 unsigned char FPGM(bci_action_stem
) [] =
2261 bci_action_stem_common
,
2265 SWAP
, /* s: cur_len edge2 */
2268 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2272 WS
, /* s: cur_len edge2 */
2274 SHPIX
, /* edge2 = edge + cur_len */
2279 SZP1
, /* set zp1 to normal zone 1 */
2285 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2298 * Handle the LINK action to link an edge to another one.
2302 * base_point (in twilight zone)
2303 * stem_point (in twilight zone)
2304 * ... stuff for bci_align_segments (base) ...
2307 unsigned char FPGM(bci_action_link
) [] =
2316 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2324 DUP
, /* s: stem is_round is_serif stem base base */
2325 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2327 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
2330 bci_compute_stem_width
,
2331 CALL
, /* s: stem new_dist */
2335 ALIGNRP
, /* align `stem_point' with `base_point' */
2337 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
2339 SHPIX
, /* stem_point = base_point + new_dist */
2344 SZP1
, /* set zp1 to normal zone 1 */
2355 * Handle the ANCHOR action to align two edges
2356 * and to set the edge anchor.
2358 * The code after computing `cur_len' to shift `edge' and `edge2'
2359 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2362 * if cur_len < = 64:
2369 * org_center = edge_orig + org_len / 2
2370 * cur_pos1 = ROUND(org_center)
2372 * error1 = ABS(org_center - (cur_pos1 - u_off))
2373 * error2 = ABS(org_center - (cur_pos1 + d_off))
2374 * if (error1 < error2):
2375 * cur_pos1 = cur_pos1 - u_off
2377 * cur_pos1 = cur_pos1 + d_off
2379 * edge = cur_pos1 - cur_len / 2
2380 * edge2 = edge + cur_len
2383 * edge = ROUND(edge_orig)
2385 * in: edge2_is_serif
2387 * edge_point (in twilight zone)
2388 * edge2_point (in twilight zone)
2389 * ... stuff for bci_align_segments (edge) ...
2398 #define sal_u_off sal_temp1
2400 #define sal_d_off sal_temp2
2402 #define sal_org_len sal_temp3
2404 unsigned char FPGM(bci_action_anchor
) [] =
2411 /* store anchor point number in `sal_anchor' */
2416 WS
, /* sal_anchor = edge_point */
2420 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2428 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2429 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2431 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2439 bci_compute_stem_width
,
2440 CALL
, /* s: edge2 edge cur_len */
2445 LT
, /* cur_len < 96 */
2450 LTEQ
, /* cur_len <= 64 */
2468 SWAP
, /* s: edge2 cur_len edge */
2469 DUP
, /* s: edge2 cur_len edge edge */
2478 ADD
, /* s: edge2 cur_len edge org_center */
2483 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2488 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2495 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2502 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2504 LT
, /* error1 < error2 */
2509 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2515 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2516 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2524 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2528 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2531 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2533 SWAP
, /* s: cur_len edge2 */
2535 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2537 SHPIX
, /* edge2 = edge1 + cur_len */
2540 POP
, /* s: edge2 edge */
2548 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2551 SHPIX
, /* edge = round(edge_orig) */
2553 /* clean up stack */
2560 SZP1
, /* set zp1 to normal zone 1 */
2569 * bci_action_blue_anchor
2571 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2572 * and to set the edge anchor.
2574 * in: anchor_point (in twilight zone)
2576 * edge_point (in twilight zone)
2577 * ... stuff for bci_align_segments (edge) ...
2581 * uses: bci_action_blue
2584 unsigned char FPGM(bci_action_blue_anchor
) [] =
2588 bci_action_blue_anchor
,
2591 /* store anchor point number in `sal_anchor' */
2609 * Handle the BLUE action to align an edge with a blue zone.
2612 * edge_point (in twilight zone)
2613 * ... stuff for bci_align_segments (edge) ...
2616 unsigned char FPGM(bci_action_blue
) [] =
2625 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2627 /* move `edge_point' to `blue_cvt_idx' position; */
2628 /* note that we can't use MIAP since this would modify */
2629 /* the twilight point's original coordinates also */
2633 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2635 GC_cur
, /* s: new_pos edge edge_pos */
2638 SUB
, /* s: edge (new_pos - edge_pos) */
2644 SZP1
, /* set zp1 to normal zone 1 */
2653 * bci_action_serif_common
2655 * Common code for bci_action_serif routines.
2658 unsigned char FPGM(bci_action_serif_common
) [] =
2662 bci_action_serif_common
,
2667 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2674 MINDEX
, /* s: [...] serif serif serif serif base */
2676 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2679 ALIGNRP
, /* align `serif_point' with `base_point' */
2680 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2690 * Move an edge if necessary to stay within a lower bound.
2696 unsigned char FPGM(bci_lower_bound
) [] =
2703 SWAP
, /* s: edge bound */
2705 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2710 GC_cur
, /* s: edge bound_pos edge_pos */
2711 GT
, /* edge_pos < bound_pos */
2714 ALIGNRP
, /* align `edge' to `bound' */
2717 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2722 SZP1
, /* set zp1 to normal zone 1 */
2733 * Move an edge if necessary to stay within an upper bound.
2739 unsigned char FPGM(bci_upper_bound
) [] =
2746 SWAP
, /* s: edge bound */
2748 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2753 GC_cur
, /* s: edge bound_pos edge_pos */
2754 LT
, /* edge_pos > bound_pos */
2757 ALIGNRP
, /* align `edge' to `bound' */
2760 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2765 SZP1
, /* set zp1 to normal zone 1 */
2774 * bci_lower_upper_bound
2776 * Move an edge if necessary to stay within a lower and lower bound.
2783 unsigned char FPGM(bci_lower_upper_bound
) [] =
2787 bci_lower_upper_bound
,
2790 SWAP
, /* s: upper serif lower */
2792 MDAP_noround
, /* set rp0 and rp1 to `lower' */
2797 GC_cur
, /* s: upper serif lower_pos serif_pos */
2798 GT
, /* serif_pos < lower_pos */
2801 ALIGNRP
, /* align `serif' to `lower' */
2804 SWAP
, /* s: serif upper */
2806 MDAP_noround
, /* set rp0 and rp1 to `upper' */
2811 GC_cur
, /* s: serif upper_pos serif_pos */
2812 LT
, /* serif_pos > upper_pos */
2815 ALIGNRP
, /* align `serif' to `upper' */
2818 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2823 SZP1
, /* set zp1 to normal zone 1 */
2834 * Handle the SERIF action to align a serif with its base.
2836 * in: serif_point (in twilight zone)
2837 * base_point (in twilight zone)
2838 * ... stuff for bci_align_segments (serif) ...
2840 * uses: bci_action_serif_common
2843 unsigned char FPGM(bci_action_serif
) [] =
2851 bci_action_serif_common
,
2854 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2859 SZP1
, /* set zp1 to normal zone 1 */
2868 * bci_action_serif_lower_bound
2870 * Handle the SERIF action to align a serif with its base, then moving it
2871 * again if necessary to stay within a lower bound.
2873 * in: serif_point (in twilight zone)
2874 * base_point (in twilight zone)
2875 * edge[-1] (in twilight zone)
2876 * ... stuff for bci_align_segments (serif) ...
2878 * uses: bci_action_serif_common
2882 unsigned char FPGM(bci_action_serif_lower_bound
) [] =
2886 bci_action_serif_lower_bound
,
2890 bci_action_serif_common
,
2903 * bci_action_serif_upper_bound
2905 * Handle the SERIF action to align a serif with its base, then moving it
2906 * again if necessary to stay within an upper bound.
2908 * in: serif_point (in twilight zone)
2909 * base_point (in twilight zone)
2910 * edge[1] (in twilight zone)
2911 * ... stuff for bci_align_segments (serif) ...
2913 * uses: bci_action_serif_common
2917 unsigned char FPGM(bci_action_serif_upper_bound
) [] =
2921 bci_action_serif_upper_bound
,
2925 bci_action_serif_common
,
2938 * bci_action_serif_lower_upper_bound
2940 * Handle the SERIF action to align a serif with its base, then moving it
2941 * again if necessary to stay within a lower and upper bound.
2943 * in: serif_point (in twilight zone)
2944 * base_point (in twilight zone)
2945 * edge[-1] (in twilight zone)
2946 * edge[1] (in twilight zone)
2947 * ... stuff for bci_align_segments (serif) ...
2949 * uses: bci_action_serif_common
2950 * bci_lower_upper_bound
2953 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] =
2957 bci_action_serif_lower_upper_bound
,
2962 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2965 bci_action_serif_common
,
2969 bci_lower_upper_bound
,
2978 * bci_action_serif_anchor_common
2980 * Common code for bci_action_serif_anchor routines.
2983 unsigned char FPGM(bci_action_serif_anchor_common
) [] =
2987 bci_action_serif_anchor_common
,
2992 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2998 WS
, /* sal_anchor = edge_point */
3008 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
3011 SHPIX
, /* edge = round(edge_orig) */
3019 * bci_action_serif_anchor
3021 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3024 * in: edge_point (in twilight zone)
3025 * ... stuff for bci_align_segments (edge) ...
3027 * uses: bci_action_serif_anchor_common
3030 unsigned char FPGM(bci_action_serif_anchor
) [] =
3034 bci_action_serif_anchor
,
3038 bci_action_serif_anchor_common
,
3041 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3046 SZP1
, /* set zp1 to normal zone 1 */
3055 * bci_action_serif_anchor_lower_bound
3057 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3058 * anchor, then moving it again if necessary to stay within a lower
3061 * in: edge_point (in twilight zone)
3062 * edge[-1] (in twilight zone)
3063 * ... stuff for bci_align_segments (edge) ...
3065 * uses: bci_action_serif_anchor_common
3069 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] =
3073 bci_action_serif_anchor_lower_bound
,
3077 bci_action_serif_anchor_common
,
3090 * bci_action_serif_anchor_upper_bound
3092 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3093 * anchor, then moving it again if necessary to stay within an upper
3096 * in: edge_point (in twilight zone)
3097 * edge[1] (in twilight zone)
3098 * ... stuff for bci_align_segments (edge) ...
3100 * uses: bci_action_serif_anchor_common
3104 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] =
3108 bci_action_serif_anchor_upper_bound
,
3112 bci_action_serif_anchor_common
,
3125 * bci_action_serif_anchor_lower_upper_bound
3127 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3128 * anchor, then moving it again if necessary to stay within a lower and
3131 * in: edge_point (in twilight zone)
3132 * edge[-1] (in twilight zone)
3133 * edge[1] (in twilight zone)
3134 * ... stuff for bci_align_segments (edge) ...
3136 * uses: bci_action_serif_anchor_common
3137 * bci_lower_upper_bound
3140 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] =
3144 bci_action_serif_anchor_lower_upper_bound
,
3148 bci_action_serif_anchor_common
,
3152 bci_lower_upper_bound
,
3161 * bci_action_serif_link1_common
3163 * Common code for bci_action_serif_link1 routines.
3166 unsigned char FPGM(bci_action_serif_link1_common
) [] =
3170 bci_action_serif_link1_common
,
3175 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3179 CINDEX
, /* s: [...] after edge before after */
3182 CINDEX
, /* s: [...] after edge before after before */
3186 EQ
, /* after_orig_pos == before_orig_pos */
3187 IF
, /* s: [...] after edge before */
3188 MDAP_noround
, /* set rp0 and rp1 to `before' */
3190 ALIGNRP
, /* align `edge' with `before' */
3195 /* we have to execute `a*b/c', with b/c very near to 1: */
3196 /* to avoid overflow while retaining precision, */
3197 /* we transform this to `a + a * (b-c)/c' */
3201 CINDEX
, /* s: [...] after edge before edge */
3204 CINDEX
, /* s: [...] after edge before edge before */
3205 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3210 CINDEX
, /* s: [...] after edge before a a after */
3213 CINDEX
, /* s: [...] after edge before a a after before */
3214 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3218 CINDEX
, /* s: [...] after edge before a a c after */
3221 CINDEX
, /* s: [...] after edge before a a c after before */
3222 MD_cur
, /* b = after_pos - before_pos */
3226 CINDEX
, /* s: [...] after edge before a a c b c */
3232 MUL
, /* (b-c) in 16.16 format */
3234 DIV
, /* s: [...] after edge before a a (b-c)/c */
3236 MUL
, /* a * (b-c)/c * 2^10 */
3240 DIV
, /* a * (b-c)/c */
3244 MDAP_noround
, /* set rp0 and rp1 to `before' */
3245 SWAP
, /* s: [...] after a*b/c edge */
3248 ALIGNRP
, /* align `edge' with `before' */
3250 SHPIX
, /* shift `edge' by `a*b/c' */
3252 SWAP
, /* s: [...] edge after */
3262 * bci_action_serif_link1
3264 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3267 * in: before_point (in twilight zone)
3268 * edge_point (in twilight zone)
3269 * after_point (in twilight zone)
3270 * ... stuff for bci_align_segments (edge) ...
3272 * uses: bci_action_serif_link1_common
3275 unsigned char FPGM(bci_action_serif_link1
) [] =
3279 bci_action_serif_link1
,
3283 bci_action_serif_link1_common
,
3286 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3291 SZP1
, /* set zp1 to normal zone 1 */
3300 * bci_action_serif_link1_lower_bound
3302 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3303 * before and after. Additionally, move the serif again if necessary to
3304 * stay within a lower bound.
3306 * in: before_point (in twilight zone)
3307 * edge_point (in twilight zone)
3308 * after_point (in twilight zone)
3309 * edge[-1] (in twilight zone)
3310 * ... stuff for bci_align_segments (edge) ...
3312 * uses: bci_action_serif_link1_common
3316 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] =
3320 bci_action_serif_link1_lower_bound
,
3324 bci_action_serif_link1_common
,
3337 * bci_action_serif_link1_upper_bound
3339 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3340 * before and after. Additionally, move the serif again if necessary to
3341 * stay within an upper bound.
3343 * in: before_point (in twilight zone)
3344 * edge_point (in twilight zone)
3345 * after_point (in twilight zone)
3346 * edge[1] (in twilight zone)
3347 * ... stuff for bci_align_segments (edge) ...
3349 * uses: bci_action_serif_link1_common
3353 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] =
3357 bci_action_serif_link1_upper_bound
,
3361 bci_action_serif_link1_common
,
3374 * bci_action_serif_link1_lower_upper_bound
3376 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3377 * before and after. Additionally, move the serif again if necessary to
3378 * stay within a lower and upper bound.
3380 * in: before_point (in twilight zone)
3381 * edge_point (in twilight zone)
3382 * after_point (in twilight zone)
3383 * edge[-1] (in twilight zone)
3384 * edge[1] (in twilight zone)
3385 * ... stuff for bci_align_segments (edge) ...
3387 * uses: bci_action_serif_link1_common
3388 * bci_lower_upper_bound
3391 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] =
3395 bci_action_serif_link1_lower_upper_bound
,
3399 bci_action_serif_link1_common
,
3403 bci_lower_upper_bound
,
3412 * bci_action_serif_link2_common
3414 * Common code for bci_action_serif_link2 routines.
3417 unsigned char FPGM(bci_action_serif_link2_common
) [] =
3421 bci_action_serif_link2_common
,
3426 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3428 DUP
, /* s: [...] edge edge */
3432 DUP
, /* s: [...] edge edge anchor anchor */
3433 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3444 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3449 ALIGNRP
, /* align `edge' with `sal_anchor' */
3451 SHPIX
, /* shift `edge' by `delta' */
3459 * bci_action_serif_link2
3461 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3463 * in: edge_point (in twilight zone)
3464 * ... stuff for bci_align_segments (edge) ...
3466 * uses: bci_action_serif_link2_common
3469 unsigned char FPGM(bci_action_serif_link2
) [] =
3473 bci_action_serif_link2
,
3477 bci_action_serif_link2_common
,
3480 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3485 SZP1
, /* set zp1 to normal zone 1 */
3494 * bci_action_serif_link2_lower_bound
3496 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3497 * Additionally, move the serif again if necessary to stay within a lower
3500 * in: edge_point (in twilight zone)
3501 * edge[-1] (in twilight zone)
3502 * ... stuff for bci_align_segments (edge) ...
3504 * uses: bci_action_serif_link2_common
3508 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] =
3512 bci_action_serif_link2_lower_bound
,
3516 bci_action_serif_link2_common
,
3529 * bci_action_serif_link2_upper_bound
3531 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3532 * Additionally, move the serif again if necessary to stay within an upper
3535 * in: edge_point (in twilight zone)
3536 * edge[1] (in twilight zone)
3537 * ... stuff for bci_align_segments (edge) ...
3539 * uses: bci_action_serif_link2_common
3543 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] =
3547 bci_action_serif_link2_upper_bound
,
3551 bci_action_serif_link2_common
,
3564 * bci_action_serif_link2_lower_upper_bound
3566 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3567 * Additionally, move the serif again if necessary to stay within a lower
3570 * in: edge_point (in twilight zone)
3571 * edge[-1] (in twilight zone)
3572 * edge[1] (in twilight zone)
3573 * ... stuff for bci_align_segments (edge) ...
3575 * uses: bci_action_serif_link2_common
3576 * bci_lower_upper_bound
3579 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] =
3583 bci_action_serif_link2_lower_upper_bound
,
3587 bci_action_serif_link2_common
,
3591 bci_lower_upper_bound
,
3604 * in: function_index
3607 unsigned char FPGM(bci_handle_action
) [] =
3624 * This is the top-level glyph hinting function
3625 * which parses the arguments on the stack and calls subroutines.
3627 * in: num_actions (M)
3636 * uses: bci_handle_action
3638 * bci_action_ip_before
3639 * bci_action_ip_after
3641 * bci_action_ip_between
3643 * bci_action_adjust_bound
3644 * bci_action_stem_bound
3648 * bci_action_blue_anchor
3654 * bci_action_serif_lower_bound
3655 * bci_action_serif_upper_bound
3656 * bci_action_serif_lower_upper_bound
3658 * bci_action_serif_anchor
3659 * bci_action_serif_anchor_lower_bound
3660 * bci_action_serif_anchor_upper_bound
3661 * bci_action_serif_anchor_lower_upper_bound
3663 * bci_action_serif_link1
3664 * bci_action_serif_link1_lower_bound
3665 * bci_action_serif_link1_upper_bound
3666 * bci_action_serif_link1_lower_upper_bound
3668 * bci_action_serif_link2
3669 * bci_action_serif_link2_lower_bound
3670 * bci_action_serif_link2_upper_bound
3671 * bci_action_serif_link2_lower_upper_bound
3673 * CVT: cvtl_is_subglyph
3676 unsigned char FPGM(bci_hint_glyph
) [] =
3689 /* only do something if we are not a subglyph */
3696 SZP2
, /* set zp2 to normal zone 1 */
3708 #define COPY_FPGM(func_name) \
3709 memcpy(buf_p, fpgm_ ## func_name, \
3710 sizeof (fpgm_ ## func_name)); \
3711 buf_p += sizeof (fpgm_ ## func_name) \
3714 TA_table_build_fpgm(FT_Byte
** fpgm
,
3724 buf_len
= sizeof (FPGM(bci_round
))
3725 + sizeof (FPGM(bci_compute_stem_width_a
))
3727 + sizeof (FPGM(bci_compute_stem_width_b
))
3729 + sizeof (FPGM(bci_compute_stem_width_c
))
3730 + sizeof (FPGM(bci_loop
))
3731 + sizeof (FPGM(bci_cvt_rescale
))
3732 + sizeof (FPGM(bci_blue_round_a
))
3734 + sizeof (FPGM(bci_blue_round_b
))
3735 + sizeof (FPGM(bci_decrement_component_counter
))
3736 + sizeof (FPGM(bci_get_point_extrema
))
3738 + sizeof (FPGM(bci_create_segment
))
3739 + sizeof (FPGM(bci_create_segments
))
3740 + sizeof (FPGM(bci_create_segments_composite
))
3741 + sizeof (FPGM(bci_align_segment
))
3742 + sizeof (FPGM(bci_align_segments
))
3744 + sizeof (FPGM(bci_scale_contour
))
3745 + sizeof (FPGM(bci_scale_glyph
))
3746 + sizeof (FPGM(bci_scale_composite_glyph
))
3747 + sizeof (FPGM(bci_shift_contour
))
3748 + sizeof (FPGM(bci_shift_subglyph
))
3750 + sizeof (FPGM(bci_ip_outer_align_point
))
3751 + sizeof (FPGM(bci_ip_on_align_points
))
3752 + sizeof (FPGM(bci_ip_between_align_point
))
3753 + sizeof (FPGM(bci_ip_between_align_points
))
3755 + sizeof (FPGM(bci_action_adjust_common
))
3756 + sizeof (FPGM(bci_action_stem_common
))
3757 + sizeof (FPGM(bci_action_serif_common
))
3758 + sizeof (FPGM(bci_action_serif_anchor_common
))
3759 + sizeof (FPGM(bci_action_serif_link1_common
))
3760 + sizeof (FPGM(bci_action_serif_link2_common
))
3762 + sizeof (FPGM(bci_lower_bound
))
3763 + sizeof (FPGM(bci_upper_bound
))
3764 + sizeof (FPGM(bci_lower_upper_bound
))
3766 + sizeof (FPGM(bci_action_ip_before
))
3767 + sizeof (FPGM(bci_action_ip_after
))
3768 + sizeof (FPGM(bci_action_ip_on
))
3769 + sizeof (FPGM(bci_action_ip_between
))
3771 + sizeof (FPGM(bci_action_adjust_bound
))
3772 + sizeof (FPGM(bci_action_stem_bound
))
3773 + sizeof (FPGM(bci_action_link
))
3774 + sizeof (FPGM(bci_action_anchor
))
3775 + sizeof (FPGM(bci_action_blue_anchor
))
3776 + sizeof (FPGM(bci_action_adjust
))
3777 + sizeof (FPGM(bci_action_stem
))
3778 + sizeof (FPGM(bci_action_blue
))
3779 + sizeof (FPGM(bci_action_serif
))
3780 + sizeof (FPGM(bci_action_serif_lower_bound
))
3781 + sizeof (FPGM(bci_action_serif_upper_bound
))
3782 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
3783 + sizeof (FPGM(bci_action_serif_anchor
))
3784 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
3785 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
3786 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3787 + sizeof (FPGM(bci_action_serif_link1
))
3788 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3789 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3790 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3791 + sizeof (FPGM(bci_action_serif_link2
))
3792 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3793 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3794 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3796 + sizeof (FPGM(bci_handle_action
))
3797 + sizeof (FPGM(bci_hint_glyph
));
3799 /* buffer length must be a multiple of four */
3800 len
= (buf_len
+ 3) & ~3;
3801 buf
= (FT_Byte
*)malloc(len
);
3803 return FT_Err_Out_Of_Memory
;
3805 /* pad end of buffer with zeros */
3806 buf
[len
- 1] = 0x00;
3807 buf
[len
- 2] = 0x00;
3808 buf
[len
- 3] = 0x00;
3810 /* copy font program into buffer and fill in the missing variables */
3813 COPY_FPGM(bci_round
);
3814 COPY_FPGM(bci_compute_stem_width_a
);
3815 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3816 COPY_FPGM(bci_compute_stem_width_b
);
3817 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3818 COPY_FPGM(bci_compute_stem_width_c
);
3819 COPY_FPGM(bci_loop
);
3820 COPY_FPGM(bci_cvt_rescale
);
3821 COPY_FPGM(bci_blue_round_a
);
3822 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
3823 COPY_FPGM(bci_blue_round_b
);
3824 COPY_FPGM(bci_decrement_component_counter
);
3825 COPY_FPGM(bci_get_point_extrema
);
3827 COPY_FPGM(bci_create_segment
);
3828 COPY_FPGM(bci_create_segments
);
3829 COPY_FPGM(bci_create_segments_composite
);
3830 COPY_FPGM(bci_align_segment
);
3831 COPY_FPGM(bci_align_segments
);
3833 COPY_FPGM(bci_scale_contour
);
3834 COPY_FPGM(bci_scale_glyph
);
3835 COPY_FPGM(bci_scale_composite_glyph
);
3836 COPY_FPGM(bci_shift_contour
);
3837 COPY_FPGM(bci_shift_subglyph
);
3839 COPY_FPGM(bci_ip_outer_align_point
);
3840 COPY_FPGM(bci_ip_on_align_points
);
3841 COPY_FPGM(bci_ip_between_align_point
);
3842 COPY_FPGM(bci_ip_between_align_points
);
3844 COPY_FPGM(bci_action_adjust_common
);
3845 COPY_FPGM(bci_action_stem_common
);
3846 COPY_FPGM(bci_action_serif_common
);
3847 COPY_FPGM(bci_action_serif_anchor_common
);
3848 COPY_FPGM(bci_action_serif_link1_common
);
3849 COPY_FPGM(bci_action_serif_link2_common
);
3851 COPY_FPGM(bci_lower_bound
);
3852 COPY_FPGM(bci_upper_bound
);
3853 COPY_FPGM(bci_lower_upper_bound
);
3855 COPY_FPGM(bci_action_ip_before
);
3856 COPY_FPGM(bci_action_ip_after
);
3857 COPY_FPGM(bci_action_ip_on
);
3858 COPY_FPGM(bci_action_ip_between
);
3860 COPY_FPGM(bci_action_adjust_bound
);
3861 COPY_FPGM(bci_action_stem_bound
);
3862 COPY_FPGM(bci_action_link
);
3863 COPY_FPGM(bci_action_anchor
);
3864 COPY_FPGM(bci_action_blue_anchor
);
3865 COPY_FPGM(bci_action_adjust
);
3866 COPY_FPGM(bci_action_stem
);
3867 COPY_FPGM(bci_action_blue
);
3868 COPY_FPGM(bci_action_serif
);
3869 COPY_FPGM(bci_action_serif_lower_bound
);
3870 COPY_FPGM(bci_action_serif_upper_bound
);
3871 COPY_FPGM(bci_action_serif_lower_upper_bound
);
3872 COPY_FPGM(bci_action_serif_anchor
);
3873 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
3874 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
3875 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
3876 COPY_FPGM(bci_action_serif_link1
);
3877 COPY_FPGM(bci_action_serif_link1_lower_bound
);
3878 COPY_FPGM(bci_action_serif_link1_upper_bound
);
3879 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
3880 COPY_FPGM(bci_action_serif_link2
);
3881 COPY_FPGM(bci_action_serif_link2_lower_bound
);
3882 COPY_FPGM(bci_action_serif_link2_upper_bound
);
3883 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
3885 COPY_FPGM(bci_handle_action
);
3886 COPY_FPGM(bci_hint_glyph
);
3889 *fpgm_len
= buf_len
;
3896 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
3905 error
= TA_sfnt_add_table_info(sfnt
);
3909 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
3913 if (fpgm_len
> sfnt
->max_instructions
)
3914 sfnt
->max_instructions
= fpgm_len
;
3916 /* in case of success, `fpgm_buf' gets linked */
3917 /* and is eventually freed in `TA_font_unload' */
3918 error
= TA_font_add_table(font
,
3919 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3920 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
3930 /* end of tafpgm.c */