3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
5 #include "tabytecode.h"
8 /* we need the following macro */
9 /* so that `func_name' doesn't get replaced with its #defined value */
10 /* (as defined in `tabytecode.h') */
12 #define FPGM(func_name) fpgm_ ## func_name
15 /* in the comments below, the top of the stack (`s:') */
16 /* is the rightmost element; the stack is shown */
17 /* after the instruction on the same line has been executed */
19 /* we use two sets of points in the twilight zone (zp0): */
20 /* one set to hold the unhinted segment positions, */
21 /* and another one to track the positions as changed by the hinting -- */
22 /* this is necessary since all points in zp0 */
23 /* have (0,0) as the original coordinates, */
24 /* making e.g. `MD_orig' return useless results */
30 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
31 * engine specific corrections are applied.
37 unsigned char FPGM(bci_round
) [] = {
63 * bci_compute_stem_width
65 * This is the equivalent to the following code from function
66 * `ta_latin_compute_stem_width':
74 * else if base_is_round:
80 * delta = ABS(dist - std_width)
91 * delta = delta - dist
100 * dist = dist + delta
114 * sal: sal_is_extra_light
118 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
121 bci_compute_stem_width
,
125 ABS
, /* s: base_is_round stem_is_serif width dist */
130 LT
, /* dist < 3*64 */
134 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
135 AND
, /* stem_is_serif && dist < 3*64 */
140 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
142 IF
, /* s: base_is_round width dist */
148 ROLL
, /* s: width dist base_is_round */
149 IF
, /* s: width dist */
154 IF
, /* s: width dist */
165 IF
, /* s: width dist */
172 DUP
, /* s: width dist dist */
177 /* %c, index of std_width */
179 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
183 ABS
, /* s: width dist delta */
188 IF
, /* s: width dist */
194 /* %c, index of std_width */
196 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
198 RCVT
, /* dist = std_width */
210 DUP
, /* s: width dist dist */
213 LT
, /* dist < 3*64 */
215 DUP
, /* s: width delta dist */
216 FLOOR
, /* dist = FLOOR(dist) */
217 DUP
, /* s: width delta dist dist */
219 ROLL
, /* s: width dist delta dist */
220 SUB
, /* delta = delta - dist */
222 DUP
, /* s: width dist delta delta */
226 IF
, /* s: width dist delta */
227 ADD
, /* dist = dist + delta */
238 ADD
, /* dist = dist + 10 */
249 ADD
, /* dist = dist + 54 */
252 ADD
, /* dist = dist + delta */
261 CALL
, /* dist = round(dist) */
266 SWAP
, /* s: dist width */
271 NEG
, /* dist = -dist */
284 * Take a range and a function number and apply the function to all
285 * elements of the range.
291 * uses: sal_i (counter initialized with `start')
293 * sal_func (`func_num')
296 unsigned char FPGM(bci_loop
) [] = {
305 WS
, /* sal_func = func_num */
309 WS
, /* sal_limit = end */
313 WS
, /* sal_i = start */
322 LTEQ
, /* start <= end */
333 ADD
, /* start = start + 1 */
339 JMPR
, /* goto start_loop */
350 * Rescale CVT value by a given factor.
352 * uses: sal_i (CVT index)
353 * sal_scale (scale in 16.16 format)
356 unsigned char FPGM(bci_cvt_rescale
) [] = {
370 MUL
, /* CVT * scale * 2^10 */
374 DIV
, /* CVT * scale */
386 * Round a blue ref value and adjust its corresponding shoot value.
388 * uses: sal_i (CVT index)
392 unsigned char FPGM(bci_blue_round_a
) [] = {
402 RCVT
, /* s: ref_idx ref */
408 SWAP
, /* s: ref_idx round(ref) ref */
416 unsigned char FPGM(bci_blue_round_b
) [] = {
420 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
422 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
424 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
426 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
428 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
453 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
458 NEG
, /* delta = -delta */
464 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
475 * bci_get_point_extrema
477 * An auxiliary function for `bci_create_segment'.
486 unsigned char FPGM(bci_get_point_extrema
) [] = {
489 bci_get_point_extrema
,
498 /* check whether `point' is a new minimum */
501 RS
, /* s: point point point point_min */
503 /* if distance is negative, we have a new minimum */
507 IF
, /* s: point point */
515 /* check whether `point' is a new maximum */
518 RS
, /* s: point point point_max */
520 /* if distance is positive, we have a new maximum */
540 * Store start and end point of a segment in the storage area,
541 * then construct two points in the twilight zone to represent it:
542 * an original one (which stays unmodified) and a hinted one,
543 * initialized with the original value.
545 * This function is used by `bci_create_segment_points'.
549 * [last (if wrap-around segment)]
550 * [first (if wrap-around segment)]
552 * uses: bci_get_point_extrema
554 * sal: sal_i (start of current segment)
555 * sal_j (current original twilight point)
556 * sal_k (current hinted twilight point)
561 unsigned char FPGM(bci_create_segment
) [] = {
573 WS
, /* sal[sal_i] = start */
575 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
581 ADD
, /* sal_i = sal_i + 1 */
584 /* initialize inner loop(s) */
589 WS
, /* sal_point_min = start */
594 WS
, /* sal_point_max = start */
598 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
604 CINDEX
, /* s: start end end start */
605 LT
, /* start > end */
607 /* we have a wrap-around segment with two more arguments */
608 /* to give the last and first point of the contour, respectively; */
609 /* our job is to store a segment `start'-`last', */
610 /* and to get extrema for the two segments */
611 /* `start'-`last' and `first'-`end' */
613 /* s: first last start end */
620 WS
, /* sal[sal_i] = last */
623 ROLL
, /* s: first end last start */
626 SWAP
, /* s: first end start last start */
627 SUB
, /* s: first end start loop_count */
630 bci_get_point_extrema
,
635 SWAP
, /* s: end first */
640 ROLL
, /* s: (first - 1) (first - 1) end */
642 SUB
, /* s: (first - 1) loop_count */
645 bci_get_point_extrema
,
650 ELSE
, /* s: start end */
657 WS
, /* sal[sal_i] = end */
662 SUB
, /* s: start loop_count */
665 bci_get_point_extrema
,
671 /* the twilight point representing a segment */
672 /* is in the middle between the minimum and maximum */
690 MDAP_noround
, /* set rp0 and rp1 to `sal_point_min' */
691 SZP1
, /* set zp1 to twilight zone 0 */
692 SZP2
, /* set zp2 to twilight zone 0 */
695 DUP
, /* s: delta point[sal_j] point[sal_j] */
696 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
699 CINDEX
, /* s: delta point[sal_j] delta */
700 SHPIX
, /* shift `point[sal_j]' by `delta' */
705 DUP
, /* s: delta point[sal_k] point[sal_k] */
706 ALIGNRP
, /* align `point[sal_k]' with `sal_point_min' */
708 SHPIX
, /* shift `point[sal_k]' by `delta' */
718 ADD
, /* original_twilight_point = original_twilight_point + 1 */
721 ADD
, /* hinted_twilight_point = hinted_twilight_point + 1 */
730 * bci_create_segments
732 * Set up segments by defining point ranges which defines them
733 * and computing twilight points to represent them.
735 * in: num_segments (N)
738 * [contour_last 0 (if wrap-around segment)]
739 * [contour_first 0 (if wrap-around segment)]
742 * [contour_last 0 (if wrap-around segment)]
743 * [contour_first 0 (if wrap-around segment)]
745 * segment_start_(N-1)
747 * [contour_last (N-1) (if wrap-around segment)]
748 * [contour_first (N-1) (if wrap-around segment)]
750 * uses: bci_create_segment
752 * sal: sal_i (start of current segment)
753 * sal_j (current original twilight point)
754 * sal_k (current hinted twilight point)
758 unsigned char FPGM(bci_create_segments
) [] = {
764 /* all our measurements are taken along the y axis */
770 WS
, /* sal_num_segments = num_segments */
782 WS
, /* sal_j = num_segments (offset for original points) */
783 WS
, /* sal_k = 0 (offset for hinted points) */
791 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
793 /* `bci_create_segment_point' also increases the loop counter by 1; */
794 /* this effectively means we have a loop step of 2 */
808 * Align all points in a segment to the twilight point in rp0.
809 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
814 unsigned char FPGM(bci_align_segment
) [] = {
820 /* we need the values of `sal_segment_offset + 2*segment_index' */
821 /* and `sal_segment_offset + 2*segment_index + 1' */
833 RS
, /* s: first last */
838 CINDEX
, /* s: first last first */
841 CINDEX
, /* s: first last first last */
842 LTEQ
, /* first <= end */
843 IF
, /* s: first last */
845 DUP
, /* s: last first first */
846 ALIGNRP
, /* align point with index `first' with rp0 */
850 ADD
, /* first = first + 1 */
851 SWAP
, /* s: first last */
856 JMPR
, /* goto start_loop */
870 * Align segments to the twilight point in rp0.
871 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
880 * uses: handle_segment
884 unsigned char FPGM(bci_align_segments
) [] = {
904 * bci_ip_before_align_point
906 * Auxiliary function for `bci_action_ip_before'.
911 unsigned char FPGM(bci_ip_before_align_point
) [] = {
914 bci_ip_before_align_point
,
925 * bci_ip_after_align_point
927 * Auxiliary function for `bci_action_ip_after'.
932 unsigned char FPGM(bci_ip_after_align_point
) [] = {
935 bci_ip_after_align_point
,
946 * bci_ip_on_align_point
948 * Auxiliary function for `bci_ip_on_align_points'.
953 unsigned char FPGM(bci_ip_on_align_point
) [] = {
956 bci_ip_on_align_point
,
967 * bci_ip_on_align_points
969 * Auxiliary function for `bci_action_ip_on'.
978 * uses: bci_ip_on_align_point
981 unsigned char FPGM(bci_ip_on_align_points
) [] = {
984 bci_ip_on_align_points
,
990 bci_ip_on_align_point
,
999 * bci_ip_between_align_point
1001 * Auxiliary function for `bci_ip_between_align_points'.
1006 unsigned char FPGM(bci_ip_between_align_point
) [] = {
1009 bci_ip_between_align_point
,
1020 * bci_ip_between_align_points
1022 * Auxiliary function for `bci_action_ip_between'.
1032 * uses: bci_ip_between_align_point
1035 unsigned char FPGM(bci_ip_between_align_points
) [] = {
1038 bci_ip_between_align_points
,
1045 bci_ip_between_align_point
,
1054 * bci_action_ip_before
1056 * Handle `ip_before' data to align points located before the first edge.
1065 * uses: bci_ip_before_align_point
1068 unsigned char FPGM(bci_action_ip_before
) [] = {
1071 bci_action_ip_before
,
1077 bci_ip_before_align_point
,
1086 * bci_action_ip_after
1088 * Handle `ip_after' data to align points located after the last edge.
1097 * uses: bci_ip_after_align_point
1100 unsigned char FPGM(bci_action_ip_after
) [] = {
1103 bci_action_ip_after
,
1109 bci_ip_after_align_point
,
1120 * Handle `ip_on' data to align points located on an edge coordinate (but
1121 * not part of an edge).
1123 * in: loop_counter (M)
1125 * loop_counter (N_1)
1131 * loop_counter (N_2)
1138 * loop_counter (N_M)
1144 * uses: bci_ip_on_align_points
1147 unsigned char FPGM(bci_action_ip_on
) [] = {
1154 bci_ip_on_align_points
,
1163 * bci_action_ip_between
1165 * Handle `ip_between' data to align points located between two edges.
1167 * in: loop_counter (M)
1170 * loop_counter (N_1)
1177 * loop_counter (N_2)
1185 * loop_counter (N_M)
1191 * uses: bci_ip_between_align_points
1194 unsigned char FPGM(bci_action_ip_between
) [] = {
1197 bci_action_ip_between
,
1201 bci_ip_between_align_points
,
1210 * bci_action_adjust_bound
1212 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1213 * edge of the stem has already been moved, then moving it again if
1214 * necessary to stay bound.
1216 * in: edge2_is_serif
1218 * edge_point (in twilight zone)
1219 * edge2_point (in twilight zone)
1220 * edge[-1] (in twilight zone)
1221 * ... stuff for bci_align_segments (edge) ...
1224 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1227 bci_action_adjust_bound
,
1232 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1240 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig */
1247 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1248 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1251 bci_compute_stem_width
,
1253 NEG
, /* s: edge[-1] edge2 edge -cur_len */
1255 ROLL
, /* s: edge[-1] edge -cur_len edge2 */
1256 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1259 DUP
, /* s: edge[-1] -cur_len edge edge edge */
1260 ALIGNRP
, /* align `edge' with `edge2' */
1262 SHPIX
, /* shift `edge' by -cur_len */
1264 SWAP
, /* s: edge edge[-1] */
1266 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1271 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1272 GT
, /* edge_pos < edge[-1]_pos */
1275 ALIGNRP
, /* align `edge' to `edge[-1]' */
1278 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1283 SZP1
, /* set zp1 to normal zone 1 */
1292 * bci_action_stem_bound
1294 * Handle the STEM action to align two edges of a stem, then moving one
1295 * edge again if necessary to stay bound.
1297 * The code after computing `cur_len' to shift `edge' and `edge2'
1298 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1301 * if cur_len < = 64:
1308 * org_center = edge_orig + org_len / 2
1309 * cur_pos1 = ROUND(org_center)
1311 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1312 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1313 * if (delta1 < delta2):
1314 * cur_pos1 = cur_pos1 - u_off
1316 * cur_pos1 = cur_pos1 + d_off
1318 * edge = cur_pos1 - cur_len / 2
1321 * org_pos = anchor + (edge_orig - anchor_orig)
1322 * org_center = edge_orig + org_len / 2
1324 * cur_pos1 = ROUND(org_pos)
1325 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1326 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1327 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1329 * if (delta1 < delta2):
1334 * edge2 = edge + cur_len
1336 * in: edge2_is_serif
1338 * edge_point (in twilight zone)
1339 * edge2_point (in twilight zone)
1340 * edge[-1] (in twilight zone)
1341 * ... stuff for bci_align_segments (edge) ...
1342 * ... stuff for bci_align_segments (edge2)...
1352 #define sal_u_off sal_temp1
1354 #define sal_d_off sal_temp2
1356 #define sal_org_len sal_temp3
1358 #define sal_edge2 sal_temp3
1360 unsigned char FPGM(bci_action_stem_bound
) [] = {
1363 bci_action_stem_bound
,
1368 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1381 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1385 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1387 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1395 bci_compute_stem_width
,
1396 CALL
, /* s: edge[-1] edge2 edge cur_len */
1401 LT
, /* cur_len < 96 */
1406 LTEQ
, /* cur_len <= 64 */
1424 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1429 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1438 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1443 CALL
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1448 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1455 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1462 ABS
, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1464 LT
, /* delta1 < delta2 */
1469 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1475 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1476 EIF
, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1484 SUB
, /* arg = cur_pos1 - cur_len/2 */
1486 SWAP
, /* s: edge[-1] edge2 cur_len arg edge */
1492 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1495 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1498 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1503 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1512 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1517 GC_cur
, /* s: edge[-1] edge2 cur_len edge org_center anchor_pos */
1533 ADD
, /* s: edge[-1] edge2 cur_len edge org_center org_pos */
1538 CALL
, /* cur_pos1 = ROUND(org_pos) */
1550 SUB
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1561 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1568 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1574 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1575 LT
, /* delta1 < delta2 */
1577 POP
, /* arg = cur_pos1 */
1580 POP
, /* arg = cur_pos2 */
1581 EIF
, /* s: edge[-1] edge2 cur_len edge arg */
1588 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1591 SHPIX
, /* edge = arg */
1592 EIF
, /* s: edge[-1] edge2 cur_len edge */
1594 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1597 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1601 WS
, /* s: edge[-1] cur_len edge edge2 */
1603 SHPIX
, /* edge2 = edge + cur_len */
1605 SWAP
, /* s: edge edge[-1] */
1607 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1612 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1613 GT
, /* edge_pos < edge[-1]_pos */
1616 ALIGNRP
, /* align `edge' to `edge[-1]' */
1619 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1624 SZP1
, /* set zp1 to normal zone 1 */
1630 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1644 * Handle the LINK action to link an edge to another one.
1648 * base_point (in twilight zone)
1649 * stem_point (in twilight zone)
1650 * ... stuff for bci_align_segments (base) ...
1653 unsigned char FPGM(bci_action_link
) [] = {
1661 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1674 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1678 ADD
, /* s: stem is_round is_serif stem_orig base_orig */
1680 MD_cur
, /* s: stem is_round is_serif dist_orig */
1683 bci_compute_stem_width
,
1684 CALL
, /* s: stem new_dist */
1688 ALIGNRP
, /* align `stem_point' with `base_point' */
1690 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
1692 SHPIX
, /* stem_point = base_point + new_dist */
1697 SZP1
, /* set zp1 to normal zone 1 */
1708 * Handle the ANCHOR action to align two edges
1709 * and to set the edge anchor.
1711 * The code after computing `cur_len' to shift `edge' and `edge2'
1712 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1715 * if cur_len < = 64:
1722 * org_center = edge_orig + org_len / 2
1723 * cur_pos1 = ROUND(org_center)
1725 * error1 = ABS(org_center - (cur_pos1 - u_off))
1726 * error2 = ABS(org_center - (cur_pos1 + d_off))
1727 * if (error1 < error2):
1728 * cur_pos1 = cur_pos1 - u_off
1730 * cur_pos1 = cur_pos1 + d_off
1732 * edge = cur_pos1 - cur_len / 2
1733 * edge2 = edge + cur_len
1736 * edge = ROUND(edge_orig)
1738 * in: edge2_is_serif
1740 * edge_point (in twilight zone)
1741 * edge2_point (in twilight zone)
1742 * ... stuff for bci_align_segments (edge) ...
1751 #define sal_u_off sal_temp1
1753 #define sal_d_off sal_temp2
1755 #define sal_org_len sal_temp3
1757 unsigned char FPGM(bci_action_anchor
) [] = {
1763 /* store anchor point number in `sal_anchor' */
1768 WS
, /* sal_anchor = edge_point */
1772 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1785 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1789 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
1791 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
1799 bci_compute_stem_width
,
1800 CALL
, /* s: edge2 edge cur_len */
1805 LT
, /* cur_len < 96 */
1810 LTEQ
, /* cur_len <= 64 */
1828 SWAP
, /* s: edge2 cur_len edge */
1833 ADD
, /* s: edge2 cur_len edge edge_orig */
1842 ADD
, /* s: edge2 cur_len edge org_center */
1847 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
1852 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1859 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1866 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1868 LT
, /* error1 < error2 */
1873 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1879 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1880 EIF
, /* s: edge2 cur_len edge cur_pos1 */
1888 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1892 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1895 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1897 SWAP
, /* s: cur_len edge2 */
1899 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1901 SHPIX
, /* edge2 = edge1 + cur_len */
1904 POP
, /* s: edge2 edge */
1909 ADD
, /* s: edge2 edge edge_orig */
1911 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
1913 ALIGNRP
, /* align `edge' with `edge_orig' */
1914 MDAP_round
, /* round `edge' */
1916 /* clean up stack */
1923 SZP1
, /* set zp1 to normal zone 1 */
1932 * bci_action_blue_anchor
1934 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1935 * and to set the edge anchor.
1937 * in: anchor_point (in twilight zone)
1939 * edge_point (in twilight zone)
1940 * ... stuff for bci_align_segments (edge) ...
1945 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1948 bci_action_blue_anchor
,
1951 /* store anchor point number in `sal_anchor' */
1959 SZP0
, /* set zp0 to twilight zone 0 */
1961 /* move `edge_point' to `blue_cvt_idx' position */
1962 MIAP_noround
, /* this also sets rp0 */
1967 SZP1
, /* set zp1 to normal zone 1 */
1978 * Handle the ADJUST action to align an edge of a stem if the other edge
1979 * of the stem has already been moved.
1981 * in: edge2_is_serif
1983 * edge_point (in twilight zone)
1984 * edge2_point (in twilight zone)
1985 * ... stuff for bci_align_segments (edge) ...
1988 unsigned char FPGM(bci_action_adjust
) [] = {
1996 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2004 ADD
, /* s: edge2 edge is_round is_serif edge2_orig */
2011 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2012 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
2015 bci_compute_stem_width
,
2017 NEG
, /* s: edge2 edge -cur_len */
2020 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2023 DUP
, /* s: -cur_len edge edge edge */
2024 ALIGNRP
, /* align `edge' with `edge2' */
2026 SHPIX
, /* shift `edge' by -cur_len */
2028 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2033 SZP1
, /* set zp1 to normal zone 1 */
2044 * Handle the STEM action to align two edges of a stem.
2046 * The code after computing `cur_len' to shift `edge' and `edge2'
2047 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2050 * if cur_len < = 64:
2057 * org_center = edge_orig + org_len / 2
2058 * cur_pos1 = ROUND(org_center)
2060 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2061 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2062 * if (delta1 < delta2):
2063 * cur_pos1 = cur_pos1 - u_off
2065 * cur_pos1 = cur_pos1 + d_off
2067 * edge = cur_pos1 - cur_len / 2
2070 * org_pos = anchor + (edge_orig - anchor_orig)
2071 * org_center = edge_orig + org_len / 2
2073 * cur_pos1 = ROUND(org_pos)
2074 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2075 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2076 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2078 * if (delta1 < delta2):
2083 * edge2 = edge + cur_len
2085 * in: edge2_is_serif
2087 * edge_point (in twilight zone)
2088 * edge2_point (in twilight zone)
2089 * ... stuff for bci_align_segments (edge) ...
2090 * ... stuff for bci_align_segments (edge2)...
2100 #define sal_u_off sal_temp1
2102 #define sal_d_off sal_temp2
2104 #define sal_org_len sal_temp3
2106 #define sal_edge2 sal_temp3
2108 unsigned char FPGM(bci_action_stem
) [] = {
2116 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2129 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2133 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2135 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
2143 bci_compute_stem_width
,
2144 CALL
, /* s: edge2 edge cur_len */
2149 LT
, /* cur_len < 96 */
2154 LTEQ
, /* cur_len <= 64 */
2172 SWAP
, /* s: edge2 cur_len edge */
2177 ADD
, /* s: edge2 cur_len edge edge_orig */
2186 ADD
, /* s: edge2 cur_len edge org_center */
2191 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2196 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2203 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2210 ABS
, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2212 LT
, /* delta1 < delta2 */
2217 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2223 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2224 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2232 SUB
, /* arg = cur_pos1 - cur_len/2 */
2234 SWAP
, /* s: edge2 cur_len arg edge */
2239 SWAP
, /* s: edge2 cur_len edge arg edge */
2242 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2245 SWAP
, /* s: edge2 cur_len edge */
2250 ADD
, /* s: edge2 cur_len edge edge_orig */
2259 ADD
, /* s: edge2 cur_len edge org_center */
2264 GC_cur
, /* s: edge2 cur_len edge org_center anchor_pos */
2280 ADD
, /* s: edge2 cur_len edge org_center org_pos */
2285 CALL
, /* cur_pos1 = ROUND(org_pos) */
2297 SUB
, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2308 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2315 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2321 ABS
, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2322 LT
, /* delta1 < delta2 */
2324 POP
, /* arg = cur_pos1 */
2327 POP
, /* arg = cur_pos2 */
2328 EIF
, /* s: edge2 cur_len edge arg */
2334 SWAP
, /* s: edge2 cur_len edge arg edge */
2337 SHPIX
, /* edge = arg */
2338 EIF
, /* s: edge2 cur_len */
2340 SWAP
, /* s: cur_len edge2 */
2343 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2347 WS
, /* s: cur_len edge2 */
2349 SHPIX
, /* edge2 = edge + cur_len */
2354 SZP1
, /* set zp1 to normal zone 1 */
2360 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2373 * Handle the BLUE action to align an edge with a blue zone.
2376 * edge_point (in twilight zone)
2377 * ... stuff for bci_align_segments (edge) ...
2380 unsigned char FPGM(bci_action_blue
) [] = {
2388 SZP0
, /* set zp0 to twilight zone 0 */
2390 /* move `edge_point' to `blue_cvt_idx' position */
2391 MIAP_noround
, /* this also sets rp0 */
2396 SZP1
, /* set zp1 to normal zone 1 */
2407 * Handle the SERIF action to align a serif with its base.
2409 * in: serif_point (in twilight zone)
2410 * base_point (in twilight zone)
2411 * ... stuff for bci_align_segments (serif) ...
2414 unsigned char FPGM(bci_action_serif
) [] = {
2422 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2428 MINDEX
, /* s: serif serif serif base */
2435 ADD
, /* s: serif serif serif base serif_orig */
2438 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2442 ADD
, /* s: serif serif serif serif_orig base_orig */
2445 ALIGNRP
, /* align `serif_point' with `base_point' */
2446 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2448 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2453 SZP1
, /* set zp1 to normal zone 1 */
2462 * bci_action_serif_lower_bound
2464 * Handle the SERIF action to align a serif with its base, then moving it
2465 * again if necessary to stay within a lower bound.
2467 * in: serif_point (in twilight zone)
2468 * base_point (in twilight zone)
2469 * edge[-1] (in twilight zone)
2470 * ... stuff for bci_align_segments (serif) ...
2473 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2476 bci_action_serif_lower_bound
,
2481 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2487 MINDEX
, /* s: edge[-1] serif serif serif base */
2494 ADD
, /* s: edge[-1] serif serif serif base serif_orig */
2497 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2501 ADD
, /* s: edge[-1] serif serif serif serif_orig base_orig */
2504 ALIGNRP
, /* align `serif_point' with `base_point' */
2505 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2507 SWAP
, /* s: serif edge[-1] */
2509 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2514 GC_cur
, /* s: serif edge[-1]_pos serif_pos */
2515 GT
, /* serif_pos < edge[-1]_pos */
2518 ALIGNRP
, /* align `serif' to `edge[-1]' */
2521 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2526 SZP1
, /* set zp1 to normal zone 1 */
2535 * bci_action_serif_upper_bound
2537 * Handle the SERIF action to align a serif with its base, then moving it
2538 * again if necessary to stay within an upper bound.
2540 * in: serif_point (in twilight zone)
2541 * base_point (in twilight zone)
2542 * edge[1] (in twilight zone)
2543 * ... stuff for bci_align_segments (serif) ...
2546 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2549 bci_action_serif_upper_bound
,
2554 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2560 MINDEX
, /* s: edge[1] serif serif serif base */
2567 ADD
, /* s: edge[1] serif serif serif base serif_orig */
2570 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2574 ADD
, /* s: edge[1] serif serif serif serif_orig base_orig */
2577 ALIGNRP
, /* align `serif_point' with `base_point' */
2578 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2580 SWAP
, /* s: serif edge[1] */
2582 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2587 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2588 LT
, /* serif_pos > edge[1]_pos */
2591 ALIGNRP
, /* align `serif' to `edge[1]' */
2594 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2599 SZP1
, /* set zp1 to normal zone 1 */
2608 * bci_action_serif_lower_upper_bound
2610 * Handle the SERIF action to align a serif with its base, then moving it
2611 * again if necessary to stay within a lower and upper bound.
2613 * in: serif_point (in twilight zone)
2614 * base_point (in twilight zone)
2615 * edge[-1] (in twilight zone)
2616 * edge[1] (in twilight zone)
2617 * ... stuff for bci_align_segments (serif) ...
2620 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2623 bci_action_serif_lower_upper_bound
,
2628 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2634 MINDEX
, /* s: edge[1] edge[-1] serif serif serif base */
2641 ADD
, /* s: edge[1] edge[-1] serif serif serif base serif_orig */
2644 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2648 ADD
, /* s: edge[1] edge[-1] serif serif serif serif_orig base_orig */
2651 ALIGNRP
, /* align `serif_point' with `base_point' */
2652 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2654 SWAP
, /* s: edge[1] serif edge[-1] */
2656 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2661 GC_cur
, /* s: edge[1] serif edge[-1]_pos serif_pos */
2662 GT
, /* serif_pos < edge[-1]_pos */
2665 ALIGNRP
, /* align `serif' to `edge[-1]' */
2668 SWAP
, /* s: serif edge[1] */
2670 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2675 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2676 LT
, /* serif_pos > edge[1]_pos */
2679 ALIGNRP
, /* align `serif' to `edge[1]' */
2682 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2687 SZP1
, /* set zp1 to normal zone 1 */
2696 * bci_action_serif_anchor
2698 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2701 * in: edge_point (in twilight zone)
2702 * ... stuff for bci_align_segments (edge) ...
2705 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2708 bci_action_serif_anchor
,
2713 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2719 WS
, /* sal_anchor = edge_point */
2725 ADD
, /* s: edge edge_orig */
2727 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2730 ALIGNRP
, /* align `edge' with `edge_orig' */
2731 MDAP_round
, /* round `edge' */
2733 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2738 SZP1
, /* set zp1 to normal zone 1 */
2747 * bci_action_serif_anchor_lower_bound
2749 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2750 * anchor, then moving it again if necessary to stay within a lower
2753 * in: edge_point (in twilight zone)
2754 * edge[-1] (in twilight zone)
2755 * ... stuff for bci_align_segments (edge) ...
2758 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
2761 bci_action_serif_anchor_lower_bound
,
2766 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2772 WS
, /* sal_anchor = edge_point */
2778 ADD
, /* s: edge[-1] edge edge_orig */
2780 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2783 ALIGNRP
, /* align `edge' with `edge_orig' */
2784 MDAP_round
, /* round `edge' */
2786 SWAP
, /* s: edge edge[-1] */
2788 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2793 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2794 GT
, /* edge_pos < edge[-1]_pos */
2797 ALIGNRP
, /* align `edge' to `edge[-1]' */
2800 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2805 SZP1
, /* set zp1 to normal zone 1 */
2814 * bci_action_serif_anchor_upper_bound
2816 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2817 * anchor, then moving it again if necessary to stay within an upper
2820 * in: edge_point (in twilight zone)
2821 * edge[1] (in twilight zone)
2822 * ... stuff for bci_align_segments (edge) ...
2825 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
2828 bci_action_serif_anchor_upper_bound
,
2833 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2839 WS
, /* sal_anchor = edge_point */
2845 ADD
, /* s: edge[1] edge edge_orig */
2847 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2850 ALIGNRP
, /* align `edge' with `edge_orig' */
2851 MDAP_round
, /* round `edge' */
2853 SWAP
, /* s: edge edge[1] */
2855 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2860 GC_cur
, /* s: edge edge[1]_pos edge_pos */
2861 LT
, /* edge_pos > edge[1]_pos */
2864 ALIGNRP
, /* align `edge' to `edge[1]' */
2867 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2872 SZP1
, /* set zp1 to normal zone 1 */
2881 * bci_action_serif_anchor_lower_upper_bound
2883 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2884 * anchor, then moving it again if necessary to stay within a lower and
2887 * in: edge_point (in twilight zone)
2888 * edge[-1] (in twilight zone)
2889 * edge[1] (in twilight zone)
2890 * ... stuff for bci_align_segments (edge) ...
2893 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
2896 bci_action_serif_anchor_lower_upper_bound
,
2901 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2907 WS
, /* sal_anchor = edge_point */
2913 ADD
, /* s: edge[1] edge[-1] edge edge_orig */
2915 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2918 ALIGNRP
, /* align `edge' with `edge_orig' */
2919 MDAP_round
, /* round `edge' */
2921 SWAP
, /* s: edge[1] edge edge[-1] */
2923 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2928 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
2929 GT
, /* edge_pos < edge[-1]_pos */
2932 ALIGNRP
, /* align `edge' to `edge[-1]' */
2935 SWAP
, /* s: edge edge[1] */
2937 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2942 GC_cur
, /* s: edge edge[1]_pos edge_pos */
2943 LT
, /* edge_pos > edge[1]_pos */
2946 ALIGNRP
, /* align `edge' to `edge[1]' */
2949 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2954 SZP1
, /* set zp1 to normal zone 1 */
2963 * bci_action_serif_link1
2965 * Handle the SERIF_LINK1 action to align a serif, depending on edges
2968 * in: before_point (in twilight zone)
2969 * edge_point (in twilight zone)
2970 * after_point (in twilight zone)
2971 * ... stuff for bci_align_segments (edge) ...
2974 unsigned char FPGM(bci_action_serif_link1
) [] = {
2977 bci_action_serif_link1
,
2982 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2990 ADD
, /* s: after edge before after_orig */
2997 ADD
, /* s: after edge before after_orig before_orig */
3001 EQ
, /* after_orig_pos == before_orig_pos */
3002 IF
, /* s: after edge before */
3003 MDAP_noround
, /* set rp0 and rp1 to `before' */
3005 ALIGNRP
, /* align `edge' with `before' */
3016 ADD
, /* s: ... after edge before edge_orig */
3023 ADD
, /* s: ... after edge before edge_orig before_orig */
3024 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3032 CINDEX
, /* s: ... after edge before a*64 after */
3035 CINDEX
, /* s: ... after edge before a*64 after before */
3036 MD_cur
, /* b = after_pos - before_pos */
3037 MUL
, /* s: ... after edge before a*b */
3045 ADD
, /* s: ... after edge before a*b after_orig */
3052 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3053 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3059 DIV
, /* s: after edge before a*b/c */
3062 MDAP_noround
, /* set rp0 and rp1 to `before' */
3063 SWAP
, /* s: after a*b/c edge */
3066 ALIGNRP
, /* align `edge' with `before' */
3068 SHPIX
, /* shift `edge' by `a*b/c' */
3070 SWAP
, /* s: edge after */
3074 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3079 SZP1
, /* set zp1 to normal zone 1 */
3088 * bci_action_serif_link1_lower_bound
3090 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3091 * before and after. Additionally, move the serif again if necessary to
3092 * stay within a lower bound.
3094 * in: before_point (in twilight zone)
3095 * edge_point (in twilight zone)
3096 * after_point (in twilight zone)
3097 * edge[-1] (in twilight zone)
3098 * ... stuff for bci_align_segments (edge) ...
3101 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3104 bci_action_serif_link1_lower_bound
,
3109 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3117 ADD
, /* s: edge[-1] after edge before after_orig */
3124 ADD
, /* s: edge[-1] after edge before after_orig before_orig */
3128 EQ
, /* after_orig_pos == before_orig_pos */
3129 IF
, /* s: edge[-1] after edge before */
3130 MDAP_noround
, /* set rp0 and rp1 to `before' */
3132 ALIGNRP
, /* align `edge' with `before' */
3143 ADD
, /* s: ... after edge before edge_orig */
3150 ADD
, /* s: ... after edge before edge_orig before_orig */
3151 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3159 CINDEX
, /* s: ... after edge before a*64 after */
3162 CINDEX
, /* s: ... after edge before a*64 after before */
3163 MD_cur
, /* b = after_pos - before_pos */
3164 MUL
, /* s: ... after edge before a*b */
3172 ADD
, /* s: ... after edge before a*b after_orig */
3179 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3180 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3186 DIV
, /* s: edge[-1] after edge before a*b/c */
3189 MDAP_noround
, /* set rp0 and rp1 to `before' */
3190 SWAP
, /* s: edge[-1] after a*b/c edge */
3193 ALIGNRP
, /* align `edge' with `before' */
3195 SHPIX
, /* shift `edge' by `a*b/c' */
3197 SWAP
, /* s: edge[-1] edge after */
3201 SWAP
, /* s: edge edge[-1] */
3203 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3208 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3209 GT
, /* edge_pos < edge[-1]_pos */
3212 ALIGNRP
, /* align `edge' to `edge[-1]' */
3215 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3220 SZP1
, /* set zp1 to normal zone 1 */
3228 * bci_action_serif_link1_upper_bound
3230 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3231 * before and after. Additionally, move the serif again if necessary to
3232 * stay within an upper bound.
3234 * in: before_point (in twilight zone)
3235 * edge_point (in twilight zone)
3236 * after_point (in twilight zone)
3237 * edge[1] (in twilight zone)
3238 * ... stuff for bci_align_segments (edge) ...
3241 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3244 bci_action_serif_link1_upper_bound
,
3249 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3257 ADD
, /* s: edge[1] after edge before after_orig */
3264 ADD
, /* s: edge[1] after edge before after_orig before_orig */
3268 EQ
, /* after_orig_pos == before_orig_pos */
3269 IF
, /* s: edge[1] after edge before */
3270 MDAP_noround
, /* set rp0 and rp1 to `before' */
3272 ALIGNRP
, /* align `edge' with `before' */
3283 ADD
, /* s: ... after edge before edge_orig */
3290 ADD
, /* s: ... after edge before edge_orig before_orig */
3291 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3299 CINDEX
, /* s: ... after edge before a*64 after */
3302 CINDEX
, /* s: ... after edge before a*64 after before */
3303 MD_cur
, /* b = after_pos - before_pos */
3304 MUL
, /* s: ... after edge before a*b */
3312 ADD
, /* s: ... after edge before a*b after_orig */
3319 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3320 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3326 DIV
, /* s: edge[1] after edge before a*b/c */
3329 MDAP_noround
, /* set rp0 and rp1 to `before' */
3330 SWAP
, /* s: edge[1] after a*b/c edge */
3333 ALIGNRP
, /* align `edge' with `before' */
3335 SHPIX
, /* shift `edge' by `a*b/c' */
3337 SWAP
, /* s: edge[1] edge after */
3341 SWAP
, /* s: edge edge[1] */
3343 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3348 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3349 LT
, /* edge_pos > edge[1]_pos */
3352 ALIGNRP
, /* align `edge' to `edge[1]' */
3355 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3360 SZP1
, /* set zp1 to normal zone 1 */
3369 * bci_action_serif_link1_lower_upper_bound
3371 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3372 * before and after. Additionally, move the serif again if necessary to
3373 * stay within a lower and upper bound.
3375 * in: before_point (in twilight zone)
3376 * edge_point (in twilight zone)
3377 * after_point (in twilight zone)
3378 * edge[-1] (in twilight zone)
3379 * edge[1] (in twilight zone)
3380 * ... stuff for bci_align_segments (edge) ...
3383 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3386 bci_action_serif_link1_lower_upper_bound
,
3391 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3399 ADD
, /* s: edge[1] edge[-1] after edge before after_orig */
3406 ADD
, /* s: edge[1] edge[-1] after edge before after_orig before_orig */
3410 EQ
, /* after_orig_pos == before_orig_pos */
3411 IF
, /* s: edge[1] edge[-1] after edge before */
3412 MDAP_noround
, /* set rp0 and rp1 to `before' */
3414 ALIGNRP
, /* align `edge' with `before' */
3425 ADD
, /* s: ... after edge before edge_orig */
3432 ADD
, /* s: ... after edge before edge_orig before_orig */
3433 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3441 CINDEX
, /* s: ... after edge before a*64 after */
3444 CINDEX
, /* s: ... after edge before a*64 after before */
3445 MD_cur
, /* b = after_pos - before_pos */
3446 MUL
, /* s: ... after edge before a*b */
3454 ADD
, /* s: ... after edge before a*b after_orig */
3461 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3462 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3468 DIV
, /* s: edge[1] edge[-1] after edge before a*b/c */
3471 MDAP_noround
, /* set rp0 and rp1 to `before' */
3472 SWAP
, /* s: edge[1] edge[-1] after a*b/c edge */
3475 ALIGNRP
, /* align `edge' with `before' */
3477 SHPIX
, /* shift `edge' by `a*b/c' */
3479 SWAP
, /* s: edge[1] edge[-1] edge after */
3483 SWAP
, /* s: edge[1] edge edge[-1] */
3485 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3490 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3491 GT
, /* edge_pos < edge[-1]_pos */
3494 ALIGNRP
, /* align `edge' to `edge[-1]' */
3497 SWAP
, /* s: edge edge[1] */
3499 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3504 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3505 LT
, /* edge_pos > edge[1]_pos */
3508 ALIGNRP
, /* align `edge' to `edge[1]' */
3511 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3516 SZP1
, /* set zp1 to normal zone 1 */
3525 * bci_action_serif_link2
3527 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3529 * in: edge_point (in twilight zone)
3530 * ... stuff for bci_align_segments (edge) ...
3533 unsigned char FPGM(bci_action_serif_link2
) [] = {
3536 bci_action_serif_link2
,
3541 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3547 ADD
, /* s: edge edge_orig */
3552 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3556 ADD
, /* s: edge edge_orig anchor_orig */
3567 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3572 ALIGNRP
, /* align `edge' with `sal_anchor' */
3574 SHPIX
, /* shift `edge' by `delta' */
3576 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3581 SZP1
, /* set zp1 to normal zone 1 */
3590 * bci_action_serif_link2_lower_bound
3592 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3593 * Additionally, move the serif again if necessary to stay within a lower
3596 * in: edge_point (in twilight zone)
3597 * edge[-1] (in twilight zone)
3598 * ... stuff for bci_align_segments (edge) ...
3601 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
3604 bci_action_serif_link2_lower_bound
,
3609 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3615 ADD
, /* s: edge[-1] edge edge_orig */
3620 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3624 ADD
, /* s: edge[-1] edge edge_orig anchor_orig */
3635 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3640 ALIGNRP
, /* align `edge' with `sal_anchor' */
3642 SHPIX
, /* shift `edge' by `delta' */
3644 SWAP
, /* s: edge edge[-1] */
3646 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3651 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3652 GT
, /* edge_pos < edge[-1]_pos */
3655 ALIGNRP
, /* align `edge' to `edge[-1]' */
3658 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3663 SZP1
, /* set zp1 to normal zone 1 */
3672 * bci_action_serif_link2_upper_bound
3674 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3675 * Additionally, move the serif again if necessary to stay within an upper
3678 * in: edge_point (in twilight zone)
3679 * edge[1] (in twilight zone)
3680 * ... stuff for bci_align_segments (edge) ...
3683 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3686 bci_action_serif_link2_upper_bound
,
3691 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3697 ADD
, /* s: edge[1] edge edge_orig */
3702 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3706 ADD
, /* s: edge[1] edge edge_orig anchor_orig */
3717 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3722 ALIGNRP
, /* align `edge' with `sal_anchor' */
3724 SHPIX
, /* shift `edge' by `delta' */
3726 SWAP
, /* s: edge edge[1] */
3728 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3733 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3734 LT
, /* edge_pos > edge[1]_pos */
3737 ALIGNRP
, /* align `edge' to `edge[1]' */
3740 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3745 SZP1
, /* set zp1 to normal zone 1 */
3754 * bci_action_serif_link2_lower_upper_bound
3756 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3757 * Additionally, move the serif again if necessary to stay within a lower
3760 * in: edge_point (in twilight zone)
3761 * edge[-1] (in twilight zone)
3762 * edge[1] (in twilight zone)
3763 * ... stuff for bci_align_segments (edge) ...
3766 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3769 bci_action_serif_link2_lower_upper_bound
,
3774 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3780 ADD
, /* s: edge[1] edge[-1] edge edge_orig */
3785 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3789 ADD
, /* s: edge[1] edge[-1] edge edge_orig anchor_orig */
3800 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3805 ALIGNRP
, /* align `edge' with `sal_anchor' */
3807 SHPIX
, /* shift `edge' by `delta' */
3809 SWAP
, /* s: edge[1] edge edge[-1] */
3811 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3816 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3817 GT
, /* edge_pos < edge[-1]_pos */
3820 ALIGNRP
, /* align `edge' to `edge[-1]' */
3823 SWAP
, /* s: edge edge[1] */
3825 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3830 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3831 LT
, /* edge_pos > edge[1]_pos */
3834 ALIGNRP
, /* align `edge' to `edge[1]' */
3837 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3842 SZP1
, /* set zp1 to normal zone 1 */
3855 * in: function_index
3858 unsigned char FPGM(bci_handle_action
) [] = {
3874 * This is the top-level glyph hinting function
3875 * which parses the arguments on the stack and calls subroutines.
3877 * in: num_actions (M)
3886 * uses: bci_handle_action
3887 * bci_action_adjust_bound
3888 * bci_action_stem_bound
3892 * bci_action_blue_anchor
3898 * bci_action_serif_anchor
3899 * bci_action_serif_link1
3900 * bci_action_serif_link2
3903 unsigned char FPGM(bci_hint_glyph
) [] = {
3918 #define COPY_FPGM(func_name) \
3919 memcpy(buf_p, fpgm_ ## func_name, \
3920 sizeof (fpgm_ ## func_name)); \
3921 buf_p += sizeof (fpgm_ ## func_name) \
3924 TA_table_build_fpgm(FT_Byte
** fpgm
,
3934 buf_len
= sizeof (FPGM(bci_round
))
3935 + sizeof (FPGM(bci_compute_stem_width_a
))
3937 + sizeof (FPGM(bci_compute_stem_width_b
))
3939 + sizeof (FPGM(bci_compute_stem_width_c
))
3940 + sizeof (FPGM(bci_loop
))
3941 + sizeof (FPGM(bci_cvt_rescale
))
3942 + sizeof (FPGM(bci_blue_round_a
))
3944 + sizeof (FPGM(bci_blue_round_b
))
3945 + sizeof (FPGM(bci_get_point_extrema
))
3947 + sizeof (FPGM(bci_create_segment
))
3948 + sizeof (FPGM(bci_create_segments
))
3949 + sizeof (FPGM(bci_align_segment
))
3950 + sizeof (FPGM(bci_align_segments
))
3952 + sizeof (FPGM(bci_ip_before_align_point
))
3953 + sizeof (FPGM(bci_ip_after_align_point
))
3954 + sizeof (FPGM(bci_ip_on_align_point
))
3955 + sizeof (FPGM(bci_ip_on_align_points
))
3956 + sizeof (FPGM(bci_ip_between_align_point
))
3957 + sizeof (FPGM(bci_ip_between_align_points
))
3959 + sizeof (FPGM(bci_action_ip_before
))
3960 + sizeof (FPGM(bci_action_ip_after
))
3961 + sizeof (FPGM(bci_action_ip_on
))
3962 + sizeof (FPGM(bci_action_ip_between
))
3964 + sizeof (FPGM(bci_action_adjust_bound
))
3965 + sizeof (FPGM(bci_action_stem_bound
))
3966 + sizeof (FPGM(bci_action_link
))
3967 + sizeof (FPGM(bci_action_anchor
))
3968 + sizeof (FPGM(bci_action_blue_anchor
))
3969 + sizeof (FPGM(bci_action_adjust
))
3970 + sizeof (FPGM(bci_action_stem
))
3971 + sizeof (FPGM(bci_action_blue
))
3972 + sizeof (FPGM(bci_action_serif
))
3973 + sizeof (FPGM(bci_action_serif_lower_bound
))
3974 + sizeof (FPGM(bci_action_serif_upper_bound
))
3975 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
3976 + sizeof (FPGM(bci_action_serif_anchor
))
3977 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
3978 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
3979 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3980 + sizeof (FPGM(bci_action_serif_link1
))
3981 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3982 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3983 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3984 + sizeof (FPGM(bci_action_serif_link2
))
3985 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3986 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3987 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3989 + sizeof (FPGM(bci_handle_action
))
3990 + sizeof (FPGM(bci_hint_glyph
));
3991 /* buffer length must be a multiple of four */
3992 len
= (buf_len
+ 3) & ~3;
3993 buf
= (FT_Byte
*)malloc(len
);
3995 return FT_Err_Out_Of_Memory
;
3997 /* pad end of buffer with zeros */
3998 buf
[len
- 1] = 0x00;
3999 buf
[len
- 2] = 0x00;
4000 buf
[len
- 3] = 0x00;
4002 /* copy font program into buffer and fill in the missing variables */
4005 COPY_FPGM(bci_round
);
4006 COPY_FPGM(bci_compute_stem_width_a
);
4007 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4008 COPY_FPGM(bci_compute_stem_width_b
);
4009 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4010 COPY_FPGM(bci_compute_stem_width_c
);
4011 COPY_FPGM(bci_loop
);
4012 COPY_FPGM(bci_cvt_rescale
);
4013 COPY_FPGM(bci_blue_round_a
);
4014 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
4015 COPY_FPGM(bci_blue_round_b
);
4016 COPY_FPGM(bci_get_point_extrema
);
4018 COPY_FPGM(bci_create_segment
);
4019 COPY_FPGM(bci_create_segments
);
4020 COPY_FPGM(bci_align_segment
);
4021 COPY_FPGM(bci_align_segments
);
4023 COPY_FPGM(bci_ip_before_align_point
);
4024 COPY_FPGM(bci_ip_after_align_point
);
4025 COPY_FPGM(bci_ip_on_align_point
);
4026 COPY_FPGM(bci_ip_on_align_points
);
4027 COPY_FPGM(bci_ip_between_align_point
);
4028 COPY_FPGM(bci_ip_between_align_points
);
4030 COPY_FPGM(bci_action_ip_before
);
4031 COPY_FPGM(bci_action_ip_after
);
4032 COPY_FPGM(bci_action_ip_on
);
4033 COPY_FPGM(bci_action_ip_between
);
4035 COPY_FPGM(bci_action_adjust_bound
);
4036 COPY_FPGM(bci_action_stem_bound
);
4037 COPY_FPGM(bci_action_link
);
4038 COPY_FPGM(bci_action_anchor
);
4039 COPY_FPGM(bci_action_blue_anchor
);
4040 COPY_FPGM(bci_action_adjust
);
4041 COPY_FPGM(bci_action_stem
);
4042 COPY_FPGM(bci_action_blue
);
4043 COPY_FPGM(bci_action_serif
);
4044 COPY_FPGM(bci_action_serif_lower_bound
);
4045 COPY_FPGM(bci_action_serif_upper_bound
);
4046 COPY_FPGM(bci_action_serif_lower_upper_bound
);
4047 COPY_FPGM(bci_action_serif_anchor
);
4048 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
4049 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
4050 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
4051 COPY_FPGM(bci_action_serif_link1
);
4052 COPY_FPGM(bci_action_serif_link1_lower_bound
);
4053 COPY_FPGM(bci_action_serif_link1_upper_bound
);
4054 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
4055 COPY_FPGM(bci_action_serif_link2
);
4056 COPY_FPGM(bci_action_serif_link2_lower_bound
);
4057 COPY_FPGM(bci_action_serif_link2_upper_bound
);
4058 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
4060 COPY_FPGM(bci_handle_action
);
4061 COPY_FPGM(bci_hint_glyph
);
4064 *fpgm_len
= buf_len
;
4071 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
4080 error
= TA_sfnt_add_table_info(sfnt
);
4084 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
4088 /* in case of success, `fpgm_buf' gets linked */
4089 /* and is eventually freed in `TA_font_unload' */
4090 error
= TA_font_add_table(font
,
4091 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
4092 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
4102 /* end of tafpgm.c */