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
) [] = {
106 * bci_compute_stem_width
108 * This is the equivalent to the following code from function
109 * `ta_latin_compute_stem_width':
117 * else if base_is_round:
123 * delta = ABS(dist - std_width)
134 * delta = delta - dist
137 * dist = dist + delta
138 * else if delta < 32:
140 * else if delta < 54:
143 * dist = dist + delta
159 * CVT: cvtl_is_extra_light
163 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
166 bci_compute_stem_width
,
170 ABS
, /* s: base_is_round stem_is_serif width dist */
175 LT
, /* dist < 3*64 */
179 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
180 AND
, /* stem_is_serif && dist < 3*64 */
185 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
187 IF
, /* s: base_is_round width dist */
193 ROLL
, /* s: width dist base_is_round */
194 IF
, /* s: width dist */
199 IF
, /* s: width dist */
210 IF
, /* s: width dist */
217 DUP
, /* s: width dist dist */
222 /* %c, index of std_width */
224 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
228 ABS
, /* s: width dist delta */
233 IF
, /* s: width dist */
239 /* %c, index of std_width */
241 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
243 RCVT
, /* dist = std_width */
255 DUP
, /* s: width dist dist */
258 LT
, /* dist < 3*64 */
260 DUP
, /* s: width delta dist */
261 FLOOR
, /* dist = FLOOR(dist) */
262 DUP
, /* s: width delta dist dist */
264 ROLL
, /* s: width dist delta dist */
265 SUB
, /* delta = delta - dist */
267 DUP
, /* s: width dist delta delta */
271 IF
, /* s: width dist delta */
272 ADD
, /* dist = dist + delta */
283 ADD
, /* dist = dist + 10 */
294 ADD
, /* dist = dist + 54 */
297 ADD
, /* dist = dist + delta */
306 CALL
, /* dist = round(dist) */
311 SWAP
, /* s: dist width */
316 NEG
, /* dist = -dist */
328 * Take a range and a function number and apply the function to all
329 * elements of the range.
335 * sal: sal_i (counter initialized with `start')
337 * sal_func (`func_num')
340 unsigned char FPGM(bci_loop
) [] = {
349 WS
, /* sal_func = func_num */
353 WS
, /* sal_limit = end */
357 WS
, /* sal_i = start */
366 LTEQ
, /* start <= end */
377 ADD
, /* start = start + 1 */
383 JMPR
, /* goto start_loop */
394 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
396 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
397 * consequently, the calculation `a * b/c' is done as `a + delta' with
398 * `delta = a * (b-c)/c'. This avoids overflow.
400 * sal: sal_i (CVT index)
406 unsigned char FPGM(bci_cvt_rescale
) [] = {
428 * Round a blue ref value and adjust its corresponding shoot value.
430 * sal: sal_i (CVT index)
434 unsigned char FPGM(bci_blue_round_a
) [] = {
444 RCVT
, /* s: ref_idx ref */
450 SWAP
, /* s: ref_idx round(ref) ref */
458 unsigned char FPGM(bci_blue_round_b
) [] = {
462 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
464 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
466 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
468 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
470 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
495 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
500 NEG
, /* delta = -delta */
507 SUB
, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
518 * bci_decrement_component_counter
520 * An auxiliary function for composite glyphs.
522 * CVT: cvtl_is_subglyph
525 unsigned char FPGM(bci_decrement_component_counter
) [] = {
528 bci_decrement_component_counter
,
531 /* decrement `cvtl_is_subglyph' counter */
547 * bci_get_point_extrema
549 * An auxiliary function for `bci_create_segment'.
558 unsigned char FPGM(bci_get_point_extrema
) [] = {
561 bci_get_point_extrema
,
570 /* check whether `point' is a new minimum */
573 RS
, /* s: point point point point_min */
575 /* if distance is negative, we have a new minimum */
579 IF
, /* s: point point */
587 /* check whether `point' is a new maximum */
590 RS
, /* s: point point point_max */
592 /* if distance is positive, we have a new maximum */
612 * Store start and end point of a segment in the storage area,
613 * then construct a point in the twilight zone to represent it.
615 * This function is used by `bci_create_segment_points'.
619 * [last (if wrap-around segment)]
620 * [first (if wrap-around segment)]
622 * uses: bci_get_point_extrema
624 * sal: sal_i (start of current segment)
625 * sal_j (current twilight point)
634 unsigned char FPGM(bci_create_segment
) [] = {
646 WS
, /* sal[sal_i] = start */
648 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
654 ADD
, /* sal_i = sal_i + 1 */
657 /* initialize inner loop(s) */
662 WS
, /* sal_point_min = start */
667 WS
, /* sal_point_max = start */
671 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
677 CINDEX
, /* s: start end end start */
678 LT
, /* start > end */
680 /* we have a wrap-around segment with two more arguments */
681 /* to give the last and first point of the contour, respectively; */
682 /* our job is to store a segment `start'-`last', */
683 /* and to get extrema for the two segments */
684 /* `start'-`last' and `first'-`end' */
686 /* s: first last start end */
693 WS
, /* sal[sal_i] = last */
696 ROLL
, /* s: first end last start */
699 SWAP
, /* s: first end start last start */
700 SUB
, /* s: first end start loop_count */
703 bci_get_point_extrema
,
708 SWAP
, /* s: end first */
713 ROLL
, /* s: (first - 1) (first - 1) end */
715 SUB
, /* s: (first - 1) loop_count */
718 bci_get_point_extrema
,
723 ELSE
, /* s: start end */
730 WS
, /* sal[sal_i] = end */
735 SUB
, /* s: start loop_count */
738 bci_get_point_extrema
,
744 /* the twilight point representing a segment */
745 /* is in the middle between the minimum and maximum */
757 DIV
, /* s: middle_pos */
759 DO_SCALE
, /* middle_pos = middle_pos * scale */
761 /* write it to temporary CVT location */
765 SZP0
, /* set zp0 to twilight zone 0 */
769 /* create twilight point with index `sal_j' */
782 ADD
, /* twilight_point = twilight_point + 1 */
791 * bci_create_segments
793 * Set up segments by defining point ranges which defines them
794 * and computing twilight points to represent them.
796 * in: num_segments (N)
799 * [contour_last 0 (if wrap-around segment)]
800 * [contour_first 0 (if wrap-around segment)]
803 * [contour_last 0 (if wrap-around segment)]
804 * [contour_first 0 (if wrap-around segment)]
806 * segment_start_(N-1)
808 * [contour_last (N-1) (if wrap-around segment)]
809 * [contour_first (N-1) (if wrap-around segment)]
811 * uses: bci_create_segment
813 * sal: sal_i (start of current segment)
814 * sal_j (current twilight point)
816 * CVT: cvtl_is_subglyph
819 unsigned char FPGM(bci_create_segments
) [] = {
825 /* only do something if we are not a subglyph */
832 /* all our measurements are taken along the y axis */
839 SUB
, /* delta = (2*num_segments - 1) */
847 WS
, /* sal_j = 0 (point offset) */
850 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
852 /* `bci_create_segment_point' also increases the loop counter by 1; */
853 /* this effectively means we have a loop step of 2 */
869 * bci_create_segments_composite
871 * The same as `bci_create_composite'.
872 * It also decrements the composite component counter.
874 * uses: bci_decrement_composite_counter
876 * CVT: cvtl_is_subglyph
879 unsigned char FPGM(bci_create_segments_composite
) [] = {
882 bci_create_segments_composite
,
886 bci_decrement_component_counter
,
889 /* only do something if we are not a subglyph */
896 /* all our measurements are taken along the y axis */
903 SUB
, /* delta = (2*num_segments - 1) */
911 WS
, /* sal_j = 0 (point offset) */
914 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
916 /* `bci_create_segment_point' also increases the loop counter by 1; */
917 /* this effectively means we have a loop step of 2 */
935 * Align all points in a segment to the twilight point in rp0.
936 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
941 unsigned char FPGM(bci_align_segment
) [] = {
947 /* we need the values of `sal_segment_offset + 2*segment_index' */
948 /* and `sal_segment_offset + 2*segment_index + 1' */
960 RS
, /* s: first last */
965 CINDEX
, /* s: first last first */
968 CINDEX
, /* s: first last first last */
969 LTEQ
, /* first <= end */
970 IF
, /* s: first last */
972 DUP
, /* s: last first first */
973 ALIGNRP
, /* align point with index `first' with rp0 */
977 ADD
, /* first = first + 1 */
978 SWAP
, /* s: first last */
983 JMPR
, /* goto start_loop */
998 * Align segments to the twilight point in rp0.
999 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1008 * uses: handle_segment
1012 unsigned char FPGM(bci_align_segments
) [] = {
1034 * Scale a contour using two points giving the maximum and minimum
1037 * It expects that no point on the contour is touched.
1046 unsigned char FPGM(bci_scale_contour
) [] = {
1056 DO_SCALE
, /* min_pos_new = min_pos * scale */
1061 /* don't scale a single-point contour twice */
1070 DO_SCALE
, /* max_pos_new = max_pos * scale */
1087 * Scale a glyph using a list of points (two points per contour, giving
1088 * the maximum and mininum coordinates).
1090 * It expects that no point in the glyph is touched.
1092 * in: num_contours (N)
1101 * uses: bci_scale_contour
1103 * CVT: cvtl_is_subglyph
1106 unsigned char FPGM(bci_scale_glyph
) [] = {
1112 /* only do something if we are not a subglyph */
1119 /* all our measurements are taken along the y axis */
1124 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1132 SZP2
, /* set zp2 to normal zone 1 */
1145 * bci_scale_composite_glyph
1147 * The same as `bci_scale_composite_glyph'.
1148 * It also decrements the composite component counter.
1150 * uses: bci_decrement_component_counter
1152 * CVT: cvtl_is_subglyph
1155 unsigned char FPGM(bci_scale_composite_glyph
) [] = {
1158 bci_scale_composite_glyph
,
1162 bci_decrement_component_counter
,
1165 /* only do something if we are not a subglyph */
1172 /* all our measurements are taken along the y axis */
1177 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1185 SZP2
, /* set zp2 to normal zone 1 */
1200 * Shift a contour by a given amount.
1202 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1203 * point to the normal zone 1.
1209 unsigned char FPGM(bci_shift_contour
) [] = {
1216 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1228 * bci_shift_subglyph
1230 * Shift a subglyph. To be more specific, it corrects the already applied
1231 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1234 * If this function is called, a point `x' in the subglyph has been scaled
1235 * already (during the hinting of the subglyph itself), and `offset' has
1236 * been applied also:
1238 * x -> x * scale + offset (1)
1240 * However, the offset should be applied first, then the scaling:
1242 * x -> (x + offset) * scale (2)
1244 * Our job is now to transform (1) to (2); a simple calculation shows that
1245 * we have to shift all points of the subglyph by
1247 * offset * scale - offset = offset * (scale - 1)
1249 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1251 * in: offset (in FUnits)
1255 * CVT: cvtl_funits_to_pixels
1260 unsigned char FPGM(bci_shift_subglyph
) [] = {
1269 cvtl_funits_to_pixels
,
1270 RCVT
, /* scaling factor FUnits -> pixels */
1277 /* the autohinter always rounds offsets */
1280 CALL
, /* offset = round(offset) */
1289 DIV
, /* delta = offset * (scale - 1) */
1291 /* and round again */
1294 CALL
, /* offset = round(offset) */
1298 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1300 /* we create twilight point 0 as a reference point, */
1301 /* setting the original position to zero (using `cvtl_temp') */
1309 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
1311 SWAP
, /* s: first_contour num_contours 0 delta */
1312 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
1317 SZP2
, /* set zp2 to normal zone 1 */
1326 * bci_ip_outer_align_point
1328 * Auxiliary function for `bci_action_ip_before' and
1329 * `bci_action_ip_after'.
1331 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1332 * zone, and both zp1 and zp2 set to normal zone.
1336 * sal: sal_i (edge_orig_pos)
1342 unsigned char FPGM(bci_ip_outer_align_point
) [] = {
1345 bci_ip_outer_align_point
,
1349 ALIGNRP
, /* align `point' with `edge' */
1352 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1357 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1366 * bci_ip_on_align_points
1368 * Auxiliary function for `bci_action_ip_on'.
1370 * in: edge (in twilight zone)
1378 unsigned char FPGM(bci_ip_on_align_points
) [] = {
1381 bci_ip_on_align_points
,
1384 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1395 * bci_ip_between_align_point
1397 * Auxiliary function for `bci_ip_between_align_points'.
1399 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1400 * zone, and both zp1 and zp2 set to normal zone.
1404 * sal: sal_i (edge_orig_pos)
1405 * sal_j (stretch_factor)
1411 unsigned char FPGM(bci_ip_between_align_point
) [] = {
1414 bci_ip_between_align_point
,
1418 ALIGNRP
, /* align `point' with `edge' */
1421 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1426 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1430 MUL
, /* s: point delta */
1439 * bci_ip_between_align_points
1441 * Auxiliary function for `bci_action_ip_between'.
1443 * in: after_edge (in twilight zone)
1444 * before_edge (in twilight zone)
1451 * sal: sal_i (before_orig_pos)
1452 * sal_j (stretch_factor)
1454 * uses: bci_ip_between_align_point
1457 unsigned char FPGM(bci_ip_between_align_points
) [] = {
1460 bci_ip_between_align_points
,
1466 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1468 DUP
, /* s: ... before after before before */
1469 MDAP_noround
, /* set rp0 and rp1 to `before' */
1471 GC_orig
, /* s: ... before after before before_orig_pos */
1475 WS
, /* sal_i = before_orig_pos */
1478 CINDEX
, /* s: ... before after before after */
1479 MD_cur
, /* b = after_pos - before_pos */
1482 MD_orig_ZP2_0
, /* a = after_orig_pos - before_orig_pos */
1487 WS
, /* sal_j = stretch_factor */
1490 bci_ip_between_align_point
,
1493 SZP2
, /* set zp2 to normal zone 1 */
1494 SZP1
, /* set zp1 to normal zone 1 */
1503 * bci_action_ip_before
1505 * Handle `ip_before' data to align points located before the first edge.
1507 * in: first_edge (in twilight zone)
1514 * sal: sal_i (first_edge_orig_pos)
1516 * uses: bci_ip_outer_align_point
1519 unsigned char FPGM(bci_action_ip_before
) [] = {
1522 bci_action_ip_before
,
1527 SZP2
, /* set zp2 to twilight zone 0 */
1534 WS
, /* sal_i = first_edge_orig_pos */
1540 SZP2
, /* set zp2 to normal zone 1 */
1541 SZP1
, /* set zp1 to normal zone 1 */
1542 SZP0
, /* set zp0 to twilight zone 0 */
1544 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
1547 bci_ip_outer_align_point
,
1556 * bci_action_ip_after
1558 * Handle `ip_after' data to align points located after the last edge.
1560 * in: last_edge (in twilight zone)
1567 * sal: sal_i (last_edge_orig_pos)
1569 * uses: bci_ip_outer_align_point
1572 unsigned char FPGM(bci_action_ip_after
) [] = {
1575 bci_action_ip_after
,
1580 SZP2
, /* set zp2 to twilight zone 0 */
1587 WS
, /* sal_i = last_edge_orig_pos */
1593 SZP2
, /* set zp2 to normal zone 1 */
1594 SZP1
, /* set zp1 to normal zone 1 */
1595 SZP0
, /* set zp0 to twilight zone 0 */
1597 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
1600 bci_ip_outer_align_point
,
1611 * Handle `ip_on' data to align points located on an edge coordinate (but
1612 * not part of an edge).
1614 * in: loop_counter (M)
1615 * edge_1 (in twilight zone)
1616 * loop_counter (N_1)
1621 * edge_2 (in twilight zone)
1622 * loop_counter (N_2)
1628 * edge_M (in twilight zone)
1629 * loop_counter (N_M)
1635 * uses: bci_ip_on_align_points
1638 unsigned char FPGM(bci_action_ip_on
) [] = {
1647 SZP1
, /* set zp1 to normal zone 1 */
1648 SZP0
, /* set zp0 to twilight zone 0 */
1651 bci_ip_on_align_points
,
1660 * bci_action_ip_between
1662 * Handle `ip_between' data to align points located between two edges.
1664 * in: loop_counter (M)
1665 * before_edge_1 (in twilight zone)
1666 * after_edge_1 (in twilight zone)
1667 * loop_counter (N_1)
1672 * before_edge_2 (in twilight zone)
1673 * after_edge_2 (in twilight zone)
1674 * loop_counter (N_2)
1680 * before_edge_M (in twilight zone)
1681 * after_edge_M (in twilight zone)
1682 * loop_counter (N_M)
1688 * uses: bci_ip_between_align_points
1691 unsigned char FPGM(bci_action_ip_between
) [] = {
1694 bci_action_ip_between
,
1698 bci_ip_between_align_points
,
1707 * bci_action_adjust_common
1709 * Common code for bci_action_adjust routines.
1712 unsigned char FPGM(bci_action_adjust_common
) [] = {
1715 bci_action_adjust_common
,
1720 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1724 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
1727 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1728 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1731 bci_compute_stem_width
,
1733 NEG
, /* s: [...] edge2 edge -cur_len */
1735 ROLL
, /* s: [...] edge -cur_len edge2 */
1736 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1739 DUP
, /* s: [...] -cur_len edge edge edge */
1740 ALIGNRP
, /* align `edge' with `edge2' */
1742 SHPIX
, /* shift `edge' by -cur_len */
1750 * bci_action_adjust_bound
1752 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1753 * edge of the stem has already been moved, then moving it again if
1754 * necessary to stay bound.
1756 * in: edge2_is_serif
1758 * edge_point (in twilight zone)
1759 * edge2_point (in twilight zone)
1760 * edge[-1] (in twilight zone)
1761 * ... stuff for bci_align_segments (edge) ...
1763 * uses: bci_action_adjust_common
1766 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1769 bci_action_adjust_bound
,
1773 bci_action_adjust_common
,
1776 SWAP
, /* s: edge edge[-1] */
1778 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1783 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1784 GT
, /* edge_pos < edge[-1]_pos */
1787 ALIGNRP
, /* align `edge' to `edge[-1]' */
1790 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1795 SZP1
, /* set zp1 to normal zone 1 */
1806 * Handle the ADJUST action to align an edge of a stem if the other edge
1807 * of the stem has already been moved.
1809 * in: edge2_is_serif
1811 * edge_point (in twilight zone)
1812 * edge2_point (in twilight zone)
1813 * ... stuff for bci_align_segments (edge) ...
1815 * uses: bci_action_adjust_common
1818 unsigned char FPGM(bci_action_adjust
) [] = {
1825 bci_action_adjust_common
,
1828 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1833 SZP1
, /* set zp1 to normal zone 1 */
1842 * bci_action_stem_common
1844 * Common code for bci_action_stem routines.
1848 #define sal_u_off sal_temp1
1850 #define sal_d_off sal_temp2
1852 #define sal_org_len sal_temp3
1854 #define sal_edge2 sal_temp3
1856 unsigned char FPGM(bci_action_stem_common
) [] = {
1859 bci_action_stem_common
,
1864 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1872 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1873 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1875 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1883 bci_compute_stem_width
,
1884 CALL
, /* s: [...] edge2 edge cur_len */
1889 LT
, /* cur_len < 96 */
1894 LTEQ
, /* cur_len <= 64 */
1912 SWAP
, /* s: [...] edge2 cur_len edge */
1917 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
1923 ADD
, /* s: [...] edge2 cur_len edge org_pos */
1930 ADD
, /* s: [...] edge2 cur_len edge org_center */
1935 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1940 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1947 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1954 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1956 LT
, /* delta1 < delta2 */
1961 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1967 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1968 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
1976 SUB
, /* arg = cur_pos1 - cur_len/2 */
1978 SWAP
, /* s: [...] edge2 cur_len arg edge */
1984 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
1987 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1990 SWAP
, /* s: [...] edge2 cur_len edge */
1994 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
2002 ADD
, /* s: [...] edge2 cur_len edge org_pos */
2011 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
2017 CALL
, /* cur_pos1 = ROUND(org_pos) */
2029 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2040 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2047 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2053 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2054 LT
, /* delta1 < delta2 */
2056 POP
, /* arg = cur_pos1 */
2060 POP
, /* arg = cur_pos2 */
2061 EIF
, /* s: [...] edge2 cur_len edge arg */
2068 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
2071 SHPIX
, /* edge = arg */
2072 EIF
, /* s: [...] edge2 cur_len edge */
2080 * bci_action_stem_bound
2082 * Handle the STEM action to align two edges of a stem, then moving one
2083 * edge again if necessary to stay bound.
2085 * The code after computing `cur_len' to shift `edge' and `edge2'
2086 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2089 * if cur_len < = 64:
2096 * org_pos = anchor + (edge_orig - anchor_orig);
2097 * org_center = org_pos + org_len / 2;
2099 * cur_pos1 = ROUND(org_center)
2100 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2101 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2102 * if (delta1 < delta2):
2103 * cur_pos1 = cur_pos1 - u_off
2105 * cur_pos1 = cur_pos1 + d_off
2107 * edge = cur_pos1 - cur_len / 2
2110 * org_pos = anchor + (edge_orig - anchor_orig)
2111 * org_center = org_pos + org_len / 2;
2113 * cur_pos1 = ROUND(org_pos)
2114 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2115 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2116 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2118 * if (delta1 < delta2):
2123 * edge2 = edge + cur_len
2125 * in: edge2_is_serif
2127 * edge_point (in twilight zone)
2128 * edge2_point (in twilight zone)
2129 * edge[-1] (in twilight zone)
2130 * ... stuff for bci_align_segments (edge) ...
2131 * ... stuff for bci_align_segments (edge2)...
2138 * uses: bci_action_stem_common
2141 unsigned char FPGM(bci_action_stem_bound
) [] = {
2144 bci_action_stem_bound
,
2148 bci_action_stem_common
,
2151 ROLL
, /* s: edge[-1] cur_len edge edge2 */
2154 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2158 WS
, /* s: edge[-1] cur_len edge edge2 */
2160 SHPIX
, /* edge2 = edge + cur_len */
2162 SWAP
, /* s: edge edge[-1] */
2164 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2169 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2170 GT
, /* edge_pos < edge[-1]_pos */
2173 ALIGNRP
, /* align `edge' to `edge[-1]' */
2176 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2181 SZP1
, /* set zp1 to normal zone 1 */
2187 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2201 * Handle the STEM action to align two edges of a stem.
2203 * See `bci_action_stem_bound' for more details.
2205 * in: edge2_is_serif
2207 * edge_point (in twilight zone)
2208 * edge2_point (in twilight zone)
2209 * ... stuff for bci_align_segments (edge) ...
2210 * ... stuff for bci_align_segments (edge2)...
2217 * uses: bci_action_stem_common
2220 unsigned char FPGM(bci_action_stem
) [] = {
2227 bci_action_stem_common
,
2231 SWAP
, /* s: cur_len edge2 */
2234 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2238 WS
, /* s: cur_len edge2 */
2240 SHPIX
, /* edge2 = edge + cur_len */
2245 SZP1
, /* set zp1 to normal zone 1 */
2251 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2264 * Handle the LINK action to link an edge to another one.
2268 * base_point (in twilight zone)
2269 * stem_point (in twilight zone)
2270 * ... stuff for bci_align_segments (base) ...
2273 unsigned char FPGM(bci_action_link
) [] = {
2281 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2289 DUP
, /* s: stem is_round is_serif stem base base */
2290 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2292 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
2295 bci_compute_stem_width
,
2296 CALL
, /* s: stem new_dist */
2300 ALIGNRP
, /* align `stem_point' with `base_point' */
2302 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
2304 SHPIX
, /* stem_point = base_point + new_dist */
2309 SZP1
, /* set zp1 to normal zone 1 */
2320 * Handle the ANCHOR action to align two edges
2321 * and to set the edge anchor.
2323 * The code after computing `cur_len' to shift `edge' and `edge2'
2324 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2327 * if cur_len < = 64:
2334 * org_center = edge_orig + org_len / 2
2335 * cur_pos1 = ROUND(org_center)
2337 * error1 = ABS(org_center - (cur_pos1 - u_off))
2338 * error2 = ABS(org_center - (cur_pos1 + d_off))
2339 * if (error1 < error2):
2340 * cur_pos1 = cur_pos1 - u_off
2342 * cur_pos1 = cur_pos1 + d_off
2344 * edge = cur_pos1 - cur_len / 2
2345 * edge2 = edge + cur_len
2348 * edge = ROUND(edge_orig)
2350 * in: edge2_is_serif
2352 * edge_point (in twilight zone)
2353 * edge2_point (in twilight zone)
2354 * ... stuff for bci_align_segments (edge) ...
2363 #define sal_u_off sal_temp1
2365 #define sal_d_off sal_temp2
2367 #define sal_org_len sal_temp3
2369 unsigned char FPGM(bci_action_anchor
) [] = {
2375 /* store anchor point number in `sal_anchor' */
2380 WS
, /* sal_anchor = edge_point */
2384 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2392 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2393 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2395 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2403 bci_compute_stem_width
,
2404 CALL
, /* s: edge2 edge cur_len */
2409 LT
, /* cur_len < 96 */
2414 LTEQ
, /* cur_len <= 64 */
2432 SWAP
, /* s: edge2 cur_len edge */
2433 DUP
, /* s: edge2 cur_len edge edge */
2442 ADD
, /* s: edge2 cur_len edge org_center */
2447 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2452 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2459 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2466 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2468 LT
, /* error1 < error2 */
2473 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2479 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2480 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2488 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2492 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2495 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2497 SWAP
, /* s: cur_len edge2 */
2499 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2501 SHPIX
, /* edge2 = edge1 + cur_len */
2504 POP
, /* s: edge2 edge */
2512 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2515 SHPIX
, /* edge = round(edge_orig) */
2517 /* clean up stack */
2524 SZP1
, /* set zp1 to normal zone 1 */
2533 * bci_action_blue_anchor
2535 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2536 * and to set the edge anchor.
2538 * in: anchor_point (in twilight zone)
2540 * edge_point (in twilight zone)
2541 * ... stuff for bci_align_segments (edge) ...
2545 * uses: bci_action_blue
2548 unsigned char FPGM(bci_action_blue_anchor
) [] = {
2551 bci_action_blue_anchor
,
2554 /* store anchor point number in `sal_anchor' */
2572 * Handle the BLUE action to align an edge with a blue zone.
2575 * edge_point (in twilight zone)
2576 * ... stuff for bci_align_segments (edge) ...
2579 unsigned char FPGM(bci_action_blue
) [] = {
2587 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2589 /* move `edge_point' to `blue_cvt_idx' position; */
2590 /* note that we can't use MIAP since this would modify */
2591 /* the twilight point's original coordinates also */
2595 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2597 GC_cur
, /* s: new_pos edge edge_pos */
2600 SUB
, /* s: edge (new_pos - edge_pos) */
2606 SZP1
, /* set zp1 to normal zone 1 */
2615 * bci_action_serif_common
2617 * Common code for bci_action_serif routines.
2620 unsigned char FPGM(bci_action_serif_common
) [] = {
2623 bci_action_serif_common
,
2628 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2635 MINDEX
, /* s: [...] serif serif serif serif base */
2637 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2640 ALIGNRP
, /* align `serif_point' with `base_point' */
2641 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2651 * Move an edge if necessary to stay within a lower bound.
2657 unsigned char FPGM(bci_lower_bound
) [] = {
2663 SWAP
, /* s: edge bound */
2665 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2670 GC_cur
, /* s: edge bound_pos edge_pos */
2671 GT
, /* edge_pos < bound_pos */
2674 ALIGNRP
, /* align `edge' to `bound' */
2677 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2682 SZP1
, /* set zp1 to normal zone 1 */
2693 * Move an edge if necessary to stay within an upper bound.
2699 unsigned char FPGM(bci_upper_bound
) [] = {
2705 SWAP
, /* s: edge bound */
2707 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2712 GC_cur
, /* s: edge bound_pos edge_pos */
2713 LT
, /* edge_pos > bound_pos */
2716 ALIGNRP
, /* align `edge' to `bound' */
2719 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2724 SZP1
, /* set zp1 to normal zone 1 */
2733 * bci_lower_upper_bound
2735 * Move an edge if necessary to stay within a lower and lower bound.
2742 unsigned char FPGM(bci_lower_upper_bound
) [] = {
2745 bci_lower_upper_bound
,
2748 SWAP
, /* s: upper serif lower */
2750 MDAP_noround
, /* set rp0 and rp1 to `lower' */
2755 GC_cur
, /* s: upper serif lower_pos serif_pos */
2756 GT
, /* serif_pos < lower_pos */
2759 ALIGNRP
, /* align `serif' to `lower' */
2762 SWAP
, /* s: serif upper */
2764 MDAP_noround
, /* set rp0 and rp1 to `upper' */
2769 GC_cur
, /* s: serif upper_pos serif_pos */
2770 LT
, /* serif_pos > upper_pos */
2773 ALIGNRP
, /* align `serif' to `upper' */
2776 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2781 SZP1
, /* set zp1 to normal zone 1 */
2792 * Handle the SERIF action to align a serif with its base.
2794 * in: serif_point (in twilight zone)
2795 * base_point (in twilight zone)
2796 * ... stuff for bci_align_segments (serif) ...
2798 * uses: bci_action_serif_common
2801 unsigned char FPGM(bci_action_serif
) [] = {
2808 bci_action_serif_common
,
2811 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2816 SZP1
, /* set zp1 to normal zone 1 */
2825 * bci_action_serif_lower_bound
2827 * Handle the SERIF action to align a serif with its base, then moving it
2828 * again if necessary to stay within a lower bound.
2830 * in: serif_point (in twilight zone)
2831 * base_point (in twilight zone)
2832 * edge[-1] (in twilight zone)
2833 * ... stuff for bci_align_segments (serif) ...
2835 * uses: bci_action_serif_common
2839 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2842 bci_action_serif_lower_bound
,
2846 bci_action_serif_common
,
2859 * bci_action_serif_upper_bound
2861 * Handle the SERIF action to align a serif with its base, then moving it
2862 * again if necessary to stay within an upper bound.
2864 * in: serif_point (in twilight zone)
2865 * base_point (in twilight zone)
2866 * edge[1] (in twilight zone)
2867 * ... stuff for bci_align_segments (serif) ...
2869 * uses: bci_action_serif_common
2873 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2876 bci_action_serif_upper_bound
,
2880 bci_action_serif_common
,
2893 * bci_action_serif_lower_upper_bound
2895 * Handle the SERIF action to align a serif with its base, then moving it
2896 * again if necessary to stay within a lower and upper bound.
2898 * in: serif_point (in twilight zone)
2899 * base_point (in twilight zone)
2900 * edge[-1] (in twilight zone)
2901 * edge[1] (in twilight zone)
2902 * ... stuff for bci_align_segments (serif) ...
2904 * uses: bci_action_serif_common
2905 * bci_lower_upper_bound
2908 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2911 bci_action_serif_lower_upper_bound
,
2916 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2919 bci_action_serif_common
,
2923 bci_lower_upper_bound
,
2932 * bci_action_serif_anchor_common
2934 * Common code for bci_action_serif_anchor routines.
2937 unsigned char FPGM(bci_action_serif_anchor_common
) [] = {
2940 bci_action_serif_anchor_common
,
2945 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2951 WS
, /* sal_anchor = edge_point */
2961 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
2964 SHPIX
, /* edge = round(edge_orig) */
2972 * bci_action_serif_anchor
2974 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2977 * in: edge_point (in twilight zone)
2978 * ... stuff for bci_align_segments (edge) ...
2980 * uses: bci_action_serif_anchor_common
2983 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2986 bci_action_serif_anchor
,
2990 bci_action_serif_anchor_common
,
2993 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2998 SZP1
, /* set zp1 to normal zone 1 */
3007 * bci_action_serif_anchor_lower_bound
3009 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3010 * anchor, then moving it again if necessary to stay within a lower
3013 * in: edge_point (in twilight zone)
3014 * edge[-1] (in twilight zone)
3015 * ... stuff for bci_align_segments (edge) ...
3017 * uses: bci_action_serif_anchor_common
3021 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
3024 bci_action_serif_anchor_lower_bound
,
3028 bci_action_serif_anchor_common
,
3041 * bci_action_serif_anchor_upper_bound
3043 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3044 * anchor, then moving it again if necessary to stay within an upper
3047 * in: edge_point (in twilight zone)
3048 * edge[1] (in twilight zone)
3049 * ... stuff for bci_align_segments (edge) ...
3051 * uses: bci_action_serif_anchor_common
3055 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
3058 bci_action_serif_anchor_upper_bound
,
3062 bci_action_serif_anchor_common
,
3075 * bci_action_serif_anchor_lower_upper_bound
3077 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3078 * anchor, then moving it again if necessary to stay within a lower and
3081 * in: edge_point (in twilight zone)
3082 * edge[-1] (in twilight zone)
3083 * edge[1] (in twilight zone)
3084 * ... stuff for bci_align_segments (edge) ...
3086 * uses: bci_action_serif_anchor_common
3087 * bci_lower_upper_bound
3090 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
3093 bci_action_serif_anchor_lower_upper_bound
,
3097 bci_action_serif_anchor_common
,
3101 bci_lower_upper_bound
,
3110 * bci_action_serif_link1_common
3112 * Common code for bci_action_serif_link1 routines.
3115 unsigned char FPGM(bci_action_serif_link1_common
) [] = {
3118 bci_action_serif_link1_common
,
3123 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3127 CINDEX
, /* s: [...] after edge before after */
3130 CINDEX
, /* s: [...] after edge before after before */
3134 EQ
, /* after_orig_pos == before_orig_pos */
3135 IF
, /* s: [...] after edge before */
3136 MDAP_noround
, /* set rp0 and rp1 to `before' */
3138 ALIGNRP
, /* align `edge' with `before' */
3143 /* we have to execute `a*b/c', with b/c very near to 1: */
3144 /* to avoid overflow while retaining precision, */
3145 /* we transform this to `a + a * (b-c)/c' */
3149 CINDEX
, /* s: [...] after edge before edge */
3152 CINDEX
, /* s: [...] after edge before edge before */
3153 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3158 CINDEX
, /* s: [...] after edge before a a after */
3161 CINDEX
, /* s: [...] after edge before a a after before */
3162 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3166 CINDEX
, /* s: [...] after edge before a a c after */
3169 CINDEX
, /* s: [...] after edge before a a c after before */
3170 MD_cur
, /* b = after_pos - before_pos */
3174 CINDEX
, /* s: [...] after edge before a a c b c */
3180 MUL
, /* (b-c) in 16.16 format */
3182 DIV
, /* s: [...] after edge before a a (b-c)/c */
3184 MUL
, /* a * (b-c)/c * 2^10 */
3188 DIV
, /* a * (b-c)/c */
3192 MDAP_noround
, /* set rp0 and rp1 to `before' */
3193 SWAP
, /* s: [...] after a*b/c edge */
3196 ALIGNRP
, /* align `edge' with `before' */
3198 SHPIX
, /* shift `edge' by `a*b/c' */
3200 SWAP
, /* s: [...] edge after */
3210 * bci_action_serif_link1
3212 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3215 * in: before_point (in twilight zone)
3216 * edge_point (in twilight zone)
3217 * after_point (in twilight zone)
3218 * ... stuff for bci_align_segments (edge) ...
3220 * uses: bci_action_serif_link1_common
3223 unsigned char FPGM(bci_action_serif_link1
) [] = {
3226 bci_action_serif_link1
,
3230 bci_action_serif_link1_common
,
3233 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3238 SZP1
, /* set zp1 to normal zone 1 */
3247 * bci_action_serif_link1_lower_bound
3249 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3250 * before and after. Additionally, move the serif again if necessary to
3251 * stay within a lower bound.
3253 * in: before_point (in twilight zone)
3254 * edge_point (in twilight zone)
3255 * after_point (in twilight zone)
3256 * edge[-1] (in twilight zone)
3257 * ... stuff for bci_align_segments (edge) ...
3259 * uses: bci_action_serif_link1_common
3263 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3266 bci_action_serif_link1_lower_bound
,
3270 bci_action_serif_link1_common
,
3283 * bci_action_serif_link1_upper_bound
3285 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3286 * before and after. Additionally, move the serif again if necessary to
3287 * stay within an upper bound.
3289 * in: before_point (in twilight zone)
3290 * edge_point (in twilight zone)
3291 * after_point (in twilight zone)
3292 * edge[1] (in twilight zone)
3293 * ... stuff for bci_align_segments (edge) ...
3295 * uses: bci_action_serif_link1_common
3299 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3302 bci_action_serif_link1_upper_bound
,
3306 bci_action_serif_link1_common
,
3319 * bci_action_serif_link1_lower_upper_bound
3321 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3322 * before and after. Additionally, move the serif again if necessary to
3323 * stay within a lower and upper bound.
3325 * in: before_point (in twilight zone)
3326 * edge_point (in twilight zone)
3327 * after_point (in twilight zone)
3328 * edge[-1] (in twilight zone)
3329 * edge[1] (in twilight zone)
3330 * ... stuff for bci_align_segments (edge) ...
3332 * uses: bci_action_serif_link1_common
3333 * bci_lower_upper_bound
3336 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3339 bci_action_serif_link1_lower_upper_bound
,
3343 bci_action_serif_link1_common
,
3347 bci_lower_upper_bound
,
3356 * bci_action_serif_link2_common
3358 * Common code for bci_action_serif_link2 routines.
3361 unsigned char FPGM(bci_action_serif_link2_common
) [] = {
3364 bci_action_serif_link2_common
,
3369 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3371 DUP
, /* s: [...] edge edge */
3375 DUP
, /* s: [...] edge edge anchor anchor */
3376 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3387 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3392 ALIGNRP
, /* align `edge' with `sal_anchor' */
3394 SHPIX
, /* shift `edge' by `delta' */
3402 * bci_action_serif_link2
3404 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3406 * in: edge_point (in twilight zone)
3407 * ... stuff for bci_align_segments (edge) ...
3409 * uses: bci_action_serif_link2_common
3412 unsigned char FPGM(bci_action_serif_link2
) [] = {
3415 bci_action_serif_link2
,
3419 bci_action_serif_link2_common
,
3422 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3427 SZP1
, /* set zp1 to normal zone 1 */
3436 * bci_action_serif_link2_lower_bound
3438 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3439 * Additionally, move the serif again if necessary to stay within a lower
3442 * in: edge_point (in twilight zone)
3443 * edge[-1] (in twilight zone)
3444 * ... stuff for bci_align_segments (edge) ...
3446 * uses: bci_action_serif_link2_common
3450 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
3453 bci_action_serif_link2_lower_bound
,
3457 bci_action_serif_link2_common
,
3470 * bci_action_serif_link2_upper_bound
3472 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3473 * Additionally, move the serif again if necessary to stay within an upper
3476 * in: edge_point (in twilight zone)
3477 * edge[1] (in twilight zone)
3478 * ... stuff for bci_align_segments (edge) ...
3480 * uses: bci_action_serif_link2_common
3484 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3487 bci_action_serif_link2_upper_bound
,
3491 bci_action_serif_link2_common
,
3504 * bci_action_serif_link2_lower_upper_bound
3506 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3507 * Additionally, move the serif again if necessary to stay within a lower
3510 * in: edge_point (in twilight zone)
3511 * edge[-1] (in twilight zone)
3512 * edge[1] (in twilight zone)
3513 * ... stuff for bci_align_segments (edge) ...
3515 * uses: bci_action_serif_link2_common
3516 * bci_lower_upper_bound
3519 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3522 bci_action_serif_link2_lower_upper_bound
,
3526 bci_action_serif_link2_common
,
3530 bci_lower_upper_bound
,
3543 * in: function_index
3546 unsigned char FPGM(bci_handle_action
) [] = {
3562 * This is the top-level glyph hinting function
3563 * which parses the arguments on the stack and calls subroutines.
3565 * in: num_actions (M)
3574 * uses: bci_handle_action
3576 * bci_action_ip_before
3577 * bci_action_ip_after
3579 * bci_action_ip_between
3581 * bci_action_adjust_bound
3582 * bci_action_stem_bound
3586 * bci_action_blue_anchor
3592 * bci_action_serif_lower_bound
3593 * bci_action_serif_upper_bound
3594 * bci_action_serif_lower_upper_bound
3596 * bci_action_serif_anchor
3597 * bci_action_serif_anchor_lower_bound
3598 * bci_action_serif_anchor_upper_bound
3599 * bci_action_serif_anchor_lower_upper_bound
3601 * bci_action_serif_link1
3602 * bci_action_serif_link1_lower_bound
3603 * bci_action_serif_link1_upper_bound
3604 * bci_action_serif_link1_lower_upper_bound
3606 * bci_action_serif_link2
3607 * bci_action_serif_link2_lower_bound
3608 * bci_action_serif_link2_upper_bound
3609 * bci_action_serif_link2_lower_upper_bound
3611 * CVT: cvtl_is_subglyph
3614 unsigned char FPGM(bci_hint_glyph
) [] = {
3626 /* only do something if we are not a subglyph */
3633 SZP2
, /* set zp2 to normal zone 1 */
3645 #define COPY_FPGM(func_name) \
3646 memcpy(buf_p, fpgm_ ## func_name, \
3647 sizeof (fpgm_ ## func_name)); \
3648 buf_p += sizeof (fpgm_ ## func_name) \
3651 TA_table_build_fpgm(FT_Byte
** fpgm
,
3661 buf_len
= sizeof (FPGM(bci_round
))
3662 + sizeof (FPGM(bci_compute_stem_width_a
))
3664 + sizeof (FPGM(bci_compute_stem_width_b
))
3666 + sizeof (FPGM(bci_compute_stem_width_c
))
3667 + sizeof (FPGM(bci_loop
))
3668 + sizeof (FPGM(bci_cvt_rescale
))
3669 + sizeof (FPGM(bci_blue_round_a
))
3671 + sizeof (FPGM(bci_blue_round_b
))
3672 + sizeof (FPGM(bci_decrement_component_counter
))
3673 + sizeof (FPGM(bci_get_point_extrema
))
3675 + sizeof (FPGM(bci_create_segment
))
3676 + sizeof (FPGM(bci_create_segments
))
3677 + sizeof (FPGM(bci_create_segments_composite
))
3678 + sizeof (FPGM(bci_align_segment
))
3679 + sizeof (FPGM(bci_align_segments
))
3681 + sizeof (FPGM(bci_scale_contour
))
3682 + sizeof (FPGM(bci_scale_glyph
))
3683 + sizeof (FPGM(bci_scale_composite_glyph
))
3684 + sizeof (FPGM(bci_shift_contour
))
3685 + sizeof (FPGM(bci_shift_subglyph
))
3687 + sizeof (FPGM(bci_ip_outer_align_point
))
3688 + sizeof (FPGM(bci_ip_on_align_points
))
3689 + sizeof (FPGM(bci_ip_between_align_point
))
3690 + sizeof (FPGM(bci_ip_between_align_points
))
3692 + sizeof (FPGM(bci_action_adjust_common
))
3693 + sizeof (FPGM(bci_action_stem_common
))
3694 + sizeof (FPGM(bci_action_serif_common
))
3695 + sizeof (FPGM(bci_action_serif_anchor_common
))
3696 + sizeof (FPGM(bci_action_serif_link1_common
))
3697 + sizeof (FPGM(bci_action_serif_link2_common
))
3699 + sizeof (FPGM(bci_lower_bound
))
3700 + sizeof (FPGM(bci_upper_bound
))
3701 + sizeof (FPGM(bci_lower_upper_bound
))
3703 + sizeof (FPGM(bci_action_ip_before
))
3704 + sizeof (FPGM(bci_action_ip_after
))
3705 + sizeof (FPGM(bci_action_ip_on
))
3706 + sizeof (FPGM(bci_action_ip_between
))
3708 + sizeof (FPGM(bci_action_adjust_bound
))
3709 + sizeof (FPGM(bci_action_stem_bound
))
3710 + sizeof (FPGM(bci_action_link
))
3711 + sizeof (FPGM(bci_action_anchor
))
3712 + sizeof (FPGM(bci_action_blue_anchor
))
3713 + sizeof (FPGM(bci_action_adjust
))
3714 + sizeof (FPGM(bci_action_stem
))
3715 + sizeof (FPGM(bci_action_blue
))
3716 + sizeof (FPGM(bci_action_serif
))
3717 + sizeof (FPGM(bci_action_serif_lower_bound
))
3718 + sizeof (FPGM(bci_action_serif_upper_bound
))
3719 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
3720 + sizeof (FPGM(bci_action_serif_anchor
))
3721 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
3722 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
3723 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3724 + sizeof (FPGM(bci_action_serif_link1
))
3725 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3726 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3727 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3728 + sizeof (FPGM(bci_action_serif_link2
))
3729 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3730 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3731 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3733 + sizeof (FPGM(bci_handle_action
))
3734 + sizeof (FPGM(bci_hint_glyph
));
3736 /* buffer length must be a multiple of four */
3737 len
= (buf_len
+ 3) & ~3;
3738 buf
= (FT_Byte
*)malloc(len
);
3740 return FT_Err_Out_Of_Memory
;
3742 /* pad end of buffer with zeros */
3743 buf
[len
- 1] = 0x00;
3744 buf
[len
- 2] = 0x00;
3745 buf
[len
- 3] = 0x00;
3747 /* copy font program into buffer and fill in the missing variables */
3750 COPY_FPGM(bci_round
);
3751 COPY_FPGM(bci_compute_stem_width_a
);
3752 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3753 COPY_FPGM(bci_compute_stem_width_b
);
3754 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3755 COPY_FPGM(bci_compute_stem_width_c
);
3756 COPY_FPGM(bci_loop
);
3757 COPY_FPGM(bci_cvt_rescale
);
3758 COPY_FPGM(bci_blue_round_a
);
3759 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
3760 COPY_FPGM(bci_blue_round_b
);
3761 COPY_FPGM(bci_decrement_component_counter
);
3762 COPY_FPGM(bci_get_point_extrema
);
3764 COPY_FPGM(bci_create_segment
);
3765 COPY_FPGM(bci_create_segments
);
3766 COPY_FPGM(bci_create_segments_composite
);
3767 COPY_FPGM(bci_align_segment
);
3768 COPY_FPGM(bci_align_segments
);
3770 COPY_FPGM(bci_scale_contour
);
3771 COPY_FPGM(bci_scale_glyph
);
3772 COPY_FPGM(bci_scale_composite_glyph
);
3773 COPY_FPGM(bci_shift_contour
);
3774 COPY_FPGM(bci_shift_subglyph
);
3776 COPY_FPGM(bci_ip_outer_align_point
);
3777 COPY_FPGM(bci_ip_on_align_points
);
3778 COPY_FPGM(bci_ip_between_align_point
);
3779 COPY_FPGM(bci_ip_between_align_points
);
3781 COPY_FPGM(bci_action_adjust_common
);
3782 COPY_FPGM(bci_action_stem_common
);
3783 COPY_FPGM(bci_action_serif_common
);
3784 COPY_FPGM(bci_action_serif_anchor_common
);
3785 COPY_FPGM(bci_action_serif_link1_common
);
3786 COPY_FPGM(bci_action_serif_link2_common
);
3788 COPY_FPGM(bci_lower_bound
);
3789 COPY_FPGM(bci_upper_bound
);
3790 COPY_FPGM(bci_lower_upper_bound
);
3792 COPY_FPGM(bci_action_ip_before
);
3793 COPY_FPGM(bci_action_ip_after
);
3794 COPY_FPGM(bci_action_ip_on
);
3795 COPY_FPGM(bci_action_ip_between
);
3797 COPY_FPGM(bci_action_adjust_bound
);
3798 COPY_FPGM(bci_action_stem_bound
);
3799 COPY_FPGM(bci_action_link
);
3800 COPY_FPGM(bci_action_anchor
);
3801 COPY_FPGM(bci_action_blue_anchor
);
3802 COPY_FPGM(bci_action_adjust
);
3803 COPY_FPGM(bci_action_stem
);
3804 COPY_FPGM(bci_action_blue
);
3805 COPY_FPGM(bci_action_serif
);
3806 COPY_FPGM(bci_action_serif_lower_bound
);
3807 COPY_FPGM(bci_action_serif_upper_bound
);
3808 COPY_FPGM(bci_action_serif_lower_upper_bound
);
3809 COPY_FPGM(bci_action_serif_anchor
);
3810 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
3811 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
3812 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
3813 COPY_FPGM(bci_action_serif_link1
);
3814 COPY_FPGM(bci_action_serif_link1_lower_bound
);
3815 COPY_FPGM(bci_action_serif_link1_upper_bound
);
3816 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
3817 COPY_FPGM(bci_action_serif_link2
);
3818 COPY_FPGM(bci_action_serif_link2_lower_bound
);
3819 COPY_FPGM(bci_action_serif_link2_upper_bound
);
3820 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
3822 COPY_FPGM(bci_handle_action
);
3823 COPY_FPGM(bci_hint_glyph
);
3826 *fpgm_len
= buf_len
;
3833 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
3842 error
= TA_sfnt_add_table_info(sfnt
);
3846 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
3850 if (fpgm_len
> sfnt
->max_instructions
)
3851 sfnt
->max_instructions
= fpgm_len
;
3853 /* in case of success, `fpgm_buf' gets linked */
3854 /* and is eventually freed in `TA_font_unload' */
3855 error
= TA_font_add_table(font
,
3856 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3857 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
3867 /* end of tafpgm.c */