4 * Copyright (C) 2011 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.
16 #include "tabytecode.h"
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 /* in the comments below, the top of the stack (`s:') */
52 /* is the rightmost element; the stack is shown */
53 /* after the instruction on the same line has been executed */
59 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
60 * engine specific corrections are applied.
66 unsigned char FPGM(bci_round
) [] = {
92 * bci_compute_stem_width
94 * This is the equivalent to the following code from function
95 * `ta_latin_compute_stem_width':
103 * else if base_is_round:
109 * delta = ABS(dist - std_width)
120 * delta = delta - dist
123 * dist = dist + delta
124 * else if delta < 32:
126 * else if delta < 54:
129 * dist = dist + delta
143 * sal: sal_is_extra_light
147 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
150 bci_compute_stem_width
,
154 ABS
, /* s: base_is_round stem_is_serif width dist */
159 LT
, /* dist < 3*64 */
163 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
164 AND
, /* stem_is_serif && dist < 3*64 */
169 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
171 IF
, /* s: base_is_round width dist */
177 ROLL
, /* s: width dist base_is_round */
178 IF
, /* s: width dist */
183 IF
, /* s: width dist */
194 IF
, /* s: width dist */
201 DUP
, /* s: width dist dist */
206 /* %c, index of std_width */
208 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
212 ABS
, /* s: width dist delta */
217 IF
, /* s: width dist */
223 /* %c, index of std_width */
225 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
227 RCVT
, /* dist = std_width */
239 DUP
, /* s: width dist dist */
242 LT
, /* dist < 3*64 */
244 DUP
, /* s: width delta dist */
245 FLOOR
, /* dist = FLOOR(dist) */
246 DUP
, /* s: width delta dist dist */
248 ROLL
, /* s: width dist delta dist */
249 SUB
, /* delta = delta - dist */
251 DUP
, /* s: width dist delta delta */
255 IF
, /* s: width dist delta */
256 ADD
, /* dist = dist + delta */
267 ADD
, /* dist = dist + 10 */
278 ADD
, /* dist = dist + 54 */
281 ADD
, /* dist = dist + delta */
290 CALL
, /* dist = round(dist) */
295 SWAP
, /* s: dist width */
300 NEG
, /* dist = -dist */
312 * Take a range and a function number and apply the function to all
313 * elements of the range.
319 * uses: sal_i (counter initialized with `start')
321 * sal_func (`func_num')
324 unsigned char FPGM(bci_loop
) [] = {
333 WS
, /* sal_func = func_num */
337 WS
, /* sal_limit = end */
341 WS
, /* sal_i = start */
350 LTEQ
, /* start <= end */
361 ADD
, /* start = start + 1 */
367 JMPR
, /* goto start_loop */
378 * Rescale CVT value by a given factor.
380 * uses: sal_i (CVT index)
381 * sal_scale (scale in 16.16 format)
384 unsigned char FPGM(bci_cvt_rescale
) [] = {
398 MUL
, /* CVT * scale * 2^10 */
402 DIV
, /* CVT * scale */
414 * Round a blue ref value and adjust its corresponding shoot value.
416 * uses: sal_i (CVT index)
420 unsigned char FPGM(bci_blue_round_a
) [] = {
430 RCVT
, /* s: ref_idx ref */
436 SWAP
, /* s: ref_idx round(ref) ref */
444 unsigned char FPGM(bci_blue_round_b
) [] = {
448 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
450 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
452 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
454 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
456 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
481 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
486 NEG
, /* delta = -delta */
493 SUB
, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
504 * bci_get_point_extrema
506 * An auxiliary function for `bci_create_segment'.
515 unsigned char FPGM(bci_get_point_extrema
) [] = {
518 bci_get_point_extrema
,
527 /* check whether `point' is a new minimum */
530 RS
, /* s: point point point point_min */
532 /* if distance is negative, we have a new minimum */
536 IF
, /* s: point point */
544 /* check whether `point' is a new maximum */
547 RS
, /* s: point point point_max */
549 /* if distance is positive, we have a new maximum */
569 * Store start and end point of a segment in the storage area,
570 * then construct a point in the twilight zone to represent it.
572 * This function is used by `bci_create_segment_points'.
576 * [last (if wrap-around segment)]
577 * [first (if wrap-around segment)]
579 * uses: bci_get_point_extrema
581 * sal: sal_i (start of current segment)
582 * sal_j (current twilight point)
588 unsigned char FPGM(bci_create_segment
) [] = {
600 WS
, /* sal[sal_i] = start */
602 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
608 ADD
, /* sal_i = sal_i + 1 */
611 /* initialize inner loop(s) */
616 WS
, /* sal_point_min = start */
621 WS
, /* sal_point_max = start */
625 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
631 CINDEX
, /* s: start end end start */
632 LT
, /* start > end */
634 /* we have a wrap-around segment with two more arguments */
635 /* to give the last and first point of the contour, respectively; */
636 /* our job is to store a segment `start'-`last', */
637 /* and to get extrema for the two segments */
638 /* `start'-`last' and `first'-`end' */
640 /* s: first last start end */
647 WS
, /* sal[sal_i] = last */
650 ROLL
, /* s: first end last start */
653 SWAP
, /* s: first end start last start */
654 SUB
, /* s: first end start loop_count */
657 bci_get_point_extrema
,
662 SWAP
, /* s: end first */
667 ROLL
, /* s: (first - 1) (first - 1) end */
669 SUB
, /* s: (first - 1) loop_count */
672 bci_get_point_extrema
,
677 ELSE
, /* s: start end */
684 WS
, /* sal[sal_i] = end */
689 SUB
, /* s: start loop_count */
692 bci_get_point_extrema
,
698 /* the twilight point representing a segment */
699 /* is in the middle between the minimum and maximum */
711 DIV
, /* s: middle_pos */
717 MUL
, /* middle_pos * scale * 2^10 */
721 DIV
, /* middle_pos = middle_pos * scale */
723 /* write it to temporary CVT location */
727 SZP0
, /* set zp0 to twilight zone 0 */
731 /* create twilight point with index `sal_j' */
744 ADD
, /* twilight_point = twilight_point + 1 */
753 * bci_create_segments
755 * Set up segments by defining point ranges which defines them
756 * and computing twilight points to represent them.
758 * in: num_segments (N)
761 * [contour_last 0 (if wrap-around segment)]
762 * [contour_first 0 (if wrap-around segment)]
765 * [contour_last 0 (if wrap-around segment)]
766 * [contour_first 0 (if wrap-around segment)]
768 * segment_start_(N-1)
770 * [contour_last (N-1) (if wrap-around segment)]
771 * [contour_first (N-1) (if wrap-around segment)]
773 * uses: bci_create_segment
775 * sal: sal_i (start of current segment)
776 * sal_j (current twilight point)
781 unsigned char FPGM(bci_create_segments
) [] = {
787 /* all our measurements are taken along the y axis */
793 WS
, /* sal_num_segments = num_segments */
802 WS
, /* sal_j = 0 (point offset) */
810 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
812 /* `bci_create_segment_point' also increases the loop counter by 1; */
813 /* this effectively means we have a loop step of 2 */
827 * Align all points in a segment to the twilight point in rp0.
828 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
833 unsigned char FPGM(bci_align_segment
) [] = {
839 /* we need the values of `sal_segment_offset + 2*segment_index' */
840 /* and `sal_segment_offset + 2*segment_index + 1' */
852 RS
, /* s: first last */
857 CINDEX
, /* s: first last first */
860 CINDEX
, /* s: first last first last */
861 LTEQ
, /* first <= end */
862 IF
, /* s: first last */
864 DUP
, /* s: last first first */
865 ALIGNRP
, /* align point with index `first' with rp0 */
869 ADD
, /* first = first + 1 */
870 SWAP
, /* s: first last */
875 JMPR
, /* goto start_loop */
890 * Align segments to the twilight point in rp0.
891 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
900 * uses: handle_segment
904 unsigned char FPGM(bci_align_segments
) [] = {
926 * Scale a contour using two points giving the maximum and minimum
929 * It expects that no point on the contour is touched.
937 unsigned char FPGM(bci_scale_contour
) [] = {
950 MUL
, /* min_pos * scale * 2^10 */
954 DIV
, /* min_pos_new = min_pos * scale */
959 /* don't scale a single-point contour twice */
971 MUL
, /* max_pos * scale * 2^10 */
975 DIV
, /* max_pos_new = max_pos * scale */
992 * Scale a glyph using a list of points (two points per contour, giving
993 * the maximum and mininum coordinates).
995 * It expects that no point in the glyph is touched.
997 * in: num_contours (N)
1008 * uses: bci_scale_contour
1011 unsigned char FPGM(bci_scale_glyph
) [] = {
1021 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1029 SZP2
, /* set zp2 to normal zone 1 */
1040 * Shift a contour by a given amount.
1042 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1043 * point to the normal zone 1.
1049 unsigned char FPGM(bci_shift_contour
) [] = {
1056 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1068 * bci_shift_subglyph
1070 * Shift a subglyph. To be more specific, it corrects the already applied
1071 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1074 * If this function is called, a point `x' in the subglyph has been scaled
1075 * by `sal_scale' already (during the hinting of the subglyph itself), and
1076 * `offset' has been applied also:
1078 * x -> x * scale + offset (1)
1080 * However, the offset should be applied first, then the scaling:
1082 * x -> (x + offset) * scale (2)
1084 * Our job is now to transform (1) to (2); a simple calculation shows that
1085 * we have to shift all points of the subglyph by
1087 * offset * scale - offset = offset * (scale - 1)
1089 * in: offset (in FUnits)
1096 unsigned char FPGM(bci_shift_subglyph
) [] = {
1106 RCVT
, /* scaling factor FUnits -> pixels */
1113 /* the autohinter always rounds offsets */
1116 CALL
, /* offset = round(offset) */
1124 SUB
, /* scale - 1 (in 16.16 format) */
1129 DIV
, /* delta = offset * (scale - 1) */
1131 /* and round again */
1134 CALL
, /* offset = round(offset) */
1138 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1140 /* we create twilight point 0 as a reference point, */
1141 /* setting the original position to zero (using `cvtl_temp') */
1149 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
1151 SWAP
, /* s: first_contour num_contours 0 delta */
1152 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
1157 SZP2
, /* set zp2 to normal zone 1 */
1166 * bci_ip_outer_align_point
1168 * Auxiliary function for `bci_action_ip_before' and
1169 * `bci_action_ip_after'.
1171 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1172 * zone, and both zp1 and zp2 set to normal zone.
1176 * sal: sal_i (edge_orig_pos)
1179 unsigned char FPGM(bci_ip_outer_align_point
) [] = {
1182 bci_ip_outer_align_point
,
1186 ALIGNRP
, /* align `point' with `edge' */
1193 MUL
, /* point_orig_pos * scale * 2^10 */
1197 DIV
, /* point_orig_pos = point_orig_pos * scale */
1202 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1211 * bci_ip_on_align_points
1213 * Auxiliary function for `bci_action_ip_on'.
1215 * in: edge (in twilight zone)
1223 unsigned char FPGM(bci_ip_on_align_points
) [] = {
1226 bci_ip_on_align_points
,
1229 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1240 * bci_ip_between_align_point
1242 * Auxiliary function for `bci_ip_between_align_points'.
1244 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1245 * zone, and both zp1 and zp2 set to normal zone.
1249 * sal: sal_i (edge_orig_pos)
1250 * sal_j (stretch_factor)
1253 unsigned char FPGM(bci_ip_between_align_point
) [] = {
1256 bci_ip_between_align_point
,
1260 ALIGNRP
, /* align `point' with `edge' */
1267 MUL
, /* point_orig_pos * scale * 2^10 */
1271 DIV
, /* point_orig_pos = point_orig_pos * scale */
1276 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1280 MUL
, /* s: point delta */
1289 * bci_ip_between_align_points
1291 * Auxiliary function for `bci_action_ip_between'.
1293 * in: after_edge (in twilight zone)
1294 * before_edge (in twilight zone)
1301 * sal: sal_i (before_orig_pos)
1302 * sal_j (stretch_factor)
1304 * uses: bci_ip_between_align_point
1307 unsigned char FPGM(bci_ip_between_align_points
) [] = {
1310 bci_ip_between_align_points
,
1316 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1318 DUP
, /* s: ... before after before before */
1319 MDAP_noround
, /* set rp0 and rp1 to `before' */
1321 GC_orig
, /* s: ... before after before before_orig_pos */
1325 WS
, /* sal_i = before_orig_pos */
1328 CINDEX
, /* s: ... before after before after */
1329 MD_cur
, /* b = after_pos - before_pos */
1332 MD_orig_ZP2_0
, /* a = after_orig_pos - before_orig_pos */
1337 WS
, /* sal_j = stretch_factor */
1340 bci_ip_between_align_point
,
1343 SZP2
, /* set zp2 to normal zone 1 */
1344 SZP1
, /* set zp1 to normal zone 1 */
1353 * bci_action_ip_before
1355 * Handle `ip_before' data to align points located before the first edge.
1357 * in: first_edge (in twilight zone)
1364 * sal: sal_i (first_edge_orig_pos)
1366 * uses: bci_ip_outer_align_point
1369 unsigned char FPGM(bci_action_ip_before
) [] = {
1372 bci_action_ip_before
,
1377 SZP2
, /* set zp2 to twilight zone 0 */
1384 WS
, /* sal_i = first_edge_orig_pos */
1390 SZP2
, /* set zp2 to normal zone 1 */
1391 SZP1
, /* set zp1 to normal zone 1 */
1392 SZP0
, /* set zp0 to twilight zone 0 */
1394 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
1397 bci_ip_outer_align_point
,
1406 * bci_action_ip_after
1408 * Handle `ip_after' data to align points located after the last edge.
1410 * in: last_edge (in twilight zone)
1417 * sal: sal_i (last_edge_orig_pos)
1419 * uses: bci_ip_outer_align_point
1422 unsigned char FPGM(bci_action_ip_after
) [] = {
1425 bci_action_ip_after
,
1430 SZP2
, /* set zp2 to twilight zone 0 */
1437 WS
, /* sal_i = last_edge_orig_pos */
1443 SZP2
, /* set zp2 to normal zone 1 */
1444 SZP1
, /* set zp1 to normal zone 1 */
1445 SZP0
, /* set zp0 to twilight zone 0 */
1447 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
1450 bci_ip_outer_align_point
,
1461 * Handle `ip_on' data to align points located on an edge coordinate (but
1462 * not part of an edge).
1464 * in: loop_counter (M)
1465 * edge_1 (in twilight zone)
1466 * loop_counter (N_1)
1471 * edge_2 (in twilight zone)
1472 * loop_counter (N_2)
1478 * edge_M (in twilight zone)
1479 * loop_counter (N_M)
1485 * uses: bci_ip_on_align_points
1488 unsigned char FPGM(bci_action_ip_on
) [] = {
1497 SZP1
, /* set zp1 to normal zone 1 */
1498 SZP0
, /* set zp0 to twilight zone 0 */
1501 bci_ip_on_align_points
,
1510 * bci_action_ip_between
1512 * Handle `ip_between' data to align points located between two edges.
1514 * in: loop_counter (M)
1515 * before_edge_1 (in twilight zone)
1516 * after_edge_1 (in twilight zone)
1517 * loop_counter (N_1)
1522 * before_edge_2 (in twilight zone)
1523 * after_edge_2 (in twilight zone)
1524 * loop_counter (N_2)
1530 * before_edge_M (in twilight zone)
1531 * after_edge_M (in twilight zone)
1532 * loop_counter (N_M)
1538 * uses: bci_ip_between_align_points
1541 unsigned char FPGM(bci_action_ip_between
) [] = {
1544 bci_action_ip_between
,
1548 bci_ip_between_align_points
,
1557 * bci_action_adjust_bound
1559 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1560 * edge of the stem has already been moved, then moving it again if
1561 * necessary to stay bound.
1563 * in: edge2_is_serif
1565 * edge_point (in twilight zone)
1566 * edge2_point (in twilight zone)
1567 * edge[-1] (in twilight zone)
1568 * ... stuff for bci_align_segments (edge) ...
1571 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1574 bci_action_adjust_bound
,
1579 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1583 CINDEX
, /* s: edge[-1] edge2 edge is_round is_serif edge2 */
1586 CINDEX
, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge */
1587 MD_orig_ZP2_0
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1590 bci_compute_stem_width
,
1592 NEG
, /* s: edge[-1] edge2 edge -cur_len */
1594 ROLL
, /* s: edge[-1] edge -cur_len edge2 */
1595 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1598 DUP
, /* s: edge[-1] -cur_len edge edge edge */
1599 ALIGNRP
, /* align `edge' with `edge2' */
1601 SHPIX
, /* shift `edge' by -cur_len */
1603 SWAP
, /* s: edge edge[-1] */
1605 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1610 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1611 GT
, /* edge_pos < edge[-1]_pos */
1614 ALIGNRP
, /* align `edge' to `edge[-1]' */
1617 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1622 SZP1
, /* set zp1 to normal zone 1 */
1631 * bci_action_stem_bound
1633 * Handle the STEM action to align two edges of a stem, then moving one
1634 * edge again if necessary to stay bound.
1636 * The code after computing `cur_len' to shift `edge' and `edge2'
1637 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1640 * if cur_len < = 64:
1647 * org_pos = anchor + (edge_orig - anchor_orig);
1648 * org_center = org_pos + org_len / 2;
1650 * cur_pos1 = ROUND(org_center)
1651 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1652 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1653 * if (delta1 < delta2):
1654 * cur_pos1 = cur_pos1 - u_off
1656 * cur_pos1 = cur_pos1 + d_off
1658 * edge = cur_pos1 - cur_len / 2
1661 * org_pos = anchor + (edge_orig - anchor_orig)
1662 * org_center = org_pos + org_len / 2;
1664 * cur_pos1 = ROUND(org_pos)
1665 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1666 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1667 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1669 * if (delta1 < delta2):
1674 * edge2 = edge + cur_len
1676 * in: edge2_is_serif
1678 * edge_point (in twilight zone)
1679 * edge2_point (in twilight zone)
1680 * edge[-1] (in twilight zone)
1681 * ... stuff for bci_align_segments (edge) ...
1682 * ... stuff for bci_align_segments (edge2)...
1692 #define sal_u_off sal_temp1
1694 #define sal_d_off sal_temp2
1696 #define sal_org_len sal_temp3
1698 #define sal_edge2 sal_temp3
1700 unsigned char FPGM(bci_action_stem_bound
) [] = {
1703 bci_action_stem_bound
,
1708 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1716 DUP
, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge edge */
1717 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1719 MD_orig_ZP2_0
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1727 bci_compute_stem_width
,
1728 CALL
, /* s: edge[-1] edge2 edge cur_len */
1733 LT
, /* cur_len < 96 */
1738 LTEQ
, /* cur_len <= 64 */
1756 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1761 DUP
, /* s: edge[-1] edge2 cur_len edge edge anchor anchor */
1767 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos */
1774 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1779 CALL
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1784 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1791 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1798 ABS
, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1800 LT
, /* delta1 < delta2 */
1805 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1811 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1812 EIF
, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1820 SUB
, /* arg = cur_pos1 - cur_len/2 */
1822 SWAP
, /* s: edge[-1] edge2 cur_len arg edge */
1828 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1831 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1834 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1838 GC_cur
, /* s: edge[-1] edge2 cur_len edge anchor_pos */
1846 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos */
1855 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos org_center */
1861 CALL
, /* cur_pos1 = ROUND(org_pos) */
1873 SUB
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1884 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1891 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1897 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1898 LT
, /* delta1 < delta2 */
1900 POP
, /* arg = cur_pos1 */
1904 POP
, /* arg = cur_pos2 */
1905 EIF
, /* s: edge[-1] edge2 cur_len edge arg */
1912 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1915 SHPIX
, /* edge = arg */
1916 EIF
, /* s: edge[-1] edge2 cur_len edge */
1918 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1921 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1925 WS
, /* s: edge[-1] cur_len edge edge2 */
1927 SHPIX
, /* edge2 = edge + cur_len */
1929 SWAP
, /* s: edge edge[-1] */
1931 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1936 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1937 GT
, /* edge_pos < edge[-1]_pos */
1940 ALIGNRP
, /* align `edge' to `edge[-1]' */
1943 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1948 SZP1
, /* set zp1 to normal zone 1 */
1954 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1968 * Handle the LINK action to link an edge to another one.
1972 * base_point (in twilight zone)
1973 * stem_point (in twilight zone)
1974 * ... stuff for bci_align_segments (base) ...
1977 unsigned char FPGM(bci_action_link
) [] = {
1985 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1993 DUP
, /* s: stem is_round is_serif stem base base */
1994 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1996 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
1999 bci_compute_stem_width
,
2000 CALL
, /* s: stem new_dist */
2004 ALIGNRP
, /* align `stem_point' with `base_point' */
2006 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
2008 SHPIX
, /* stem_point = base_point + new_dist */
2013 SZP1
, /* set zp1 to normal zone 1 */
2024 * Handle the ANCHOR action to align two edges
2025 * and to set the edge anchor.
2027 * The code after computing `cur_len' to shift `edge' and `edge2'
2028 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2031 * if cur_len < = 64:
2038 * org_center = edge_orig + org_len / 2
2039 * cur_pos1 = ROUND(org_center)
2041 * error1 = ABS(org_center - (cur_pos1 - u_off))
2042 * error2 = ABS(org_center - (cur_pos1 + d_off))
2043 * if (error1 < error2):
2044 * cur_pos1 = cur_pos1 - u_off
2046 * cur_pos1 = cur_pos1 + d_off
2048 * edge = cur_pos1 - cur_len / 2
2049 * edge2 = edge + cur_len
2052 * edge = ROUND(edge_orig)
2054 * in: edge2_is_serif
2056 * edge_point (in twilight zone)
2057 * edge2_point (in twilight zone)
2058 * ... stuff for bci_align_segments (edge) ...
2067 #define sal_u_off sal_temp1
2069 #define sal_d_off sal_temp2
2071 #define sal_org_len sal_temp3
2073 unsigned char FPGM(bci_action_anchor
) [] = {
2079 /* store anchor point number in `sal_anchor' */
2084 WS
, /* sal_anchor = edge_point */
2088 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2096 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2097 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2099 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2107 bci_compute_stem_width
,
2108 CALL
, /* s: edge2 edge cur_len */
2113 LT
, /* cur_len < 96 */
2118 LTEQ
, /* cur_len <= 64 */
2136 SWAP
, /* s: edge2 cur_len edge */
2137 DUP
, /* s: edge2 cur_len edge edge */
2146 ADD
, /* s: edge2 cur_len edge org_center */
2151 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2156 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2163 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2170 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2172 LT
, /* error1 < error2 */
2177 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2183 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2184 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2192 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2196 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2199 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2201 SWAP
, /* s: cur_len edge2 */
2203 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2205 SHPIX
, /* edge2 = edge1 + cur_len */
2208 POP
, /* s: edge2 edge */
2216 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2219 SHPIX
, /* edge = round(edge_orig) */
2221 /* clean up stack */
2228 SZP1
, /* set zp1 to normal zone 1 */
2237 * bci_action_blue_anchor
2239 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2240 * and to set the edge anchor.
2242 * in: anchor_point (in twilight zone)
2244 * edge_point (in twilight zone)
2245 * ... stuff for bci_align_segments (edge) ...
2250 unsigned char FPGM(bci_action_blue_anchor
) [] = {
2253 bci_action_blue_anchor
,
2256 /* store anchor point number in `sal_anchor' */
2264 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2266 /* move `edge_point' to `blue_cvt_idx' position; */
2267 /* note that we can't use MIAP since this would modify */
2268 /* the twilight point's original coordinates also */
2272 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2274 GC_cur
, /* s: new_pos edge edge_pos */
2277 SUB
, /* s: edge (new_pos - edge_pos) */
2283 SZP1
, /* set zp1 to normal zone 1 */
2294 * Handle the ADJUST action to align an edge of a stem if the other edge
2295 * of the stem has already been moved.
2297 * in: edge2_is_serif
2299 * edge_point (in twilight zone)
2300 * edge2_point (in twilight zone)
2301 * ... stuff for bci_align_segments (edge) ...
2304 unsigned char FPGM(bci_action_adjust
) [] = {
2312 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2316 CINDEX
, /* s: edge2 edge is_round is_serif edge2 */
2319 CINDEX
, /* s: edge2 edge is_round is_serif edge2 edge */
2320 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2323 bci_compute_stem_width
,
2325 NEG
, /* s: edge2 edge -cur_len */
2328 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2331 DUP
, /* s: -cur_len edge edge edge */
2332 ALIGNRP
, /* align `edge' with `edge2' */
2334 SHPIX
, /* shift `edge' by -cur_len */
2336 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2341 SZP1
, /* set zp1 to normal zone 1 */
2352 * Handle the STEM action to align two edges of a stem.
2354 * The code after computing `cur_len' to shift `edge' and `edge2'
2355 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2358 * if cur_len < = 64:
2365 * org_pos = anchor + (edge_orig - anchor_orig);
2366 * org_center = org_pos + org_len / 2;
2368 * cur_pos1 = ROUND(org_center)
2369 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2370 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2371 * if (delta1 < delta2):
2372 * cur_pos1 = cur_pos1 - u_off
2374 * cur_pos1 = cur_pos1 + d_off
2376 * edge = cur_pos1 - cur_len / 2
2379 * org_pos = anchor + (edge_orig - anchor_orig)
2380 * org_center = org_pos + org_len / 2;
2382 * cur_pos1 = ROUND(org_pos)
2383 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2384 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2385 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2387 * if (delta1 < delta2):
2392 * edge2 = edge + cur_len
2394 * in: edge2_is_serif
2396 * edge_point (in twilight zone)
2397 * edge2_point (in twilight zone)
2398 * ... stuff for bci_align_segments (edge) ...
2399 * ... stuff for bci_align_segments (edge2)...
2409 #define sal_u_off sal_temp1
2411 #define sal_d_off sal_temp2
2413 #define sal_org_len sal_temp3
2415 #define sal_edge2 sal_temp3
2417 unsigned char FPGM(bci_action_stem
) [] = {
2425 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2433 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2434 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2436 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2444 bci_compute_stem_width
,
2445 CALL
, /* s: edge2 edge cur_len */
2450 LT
, /* cur_len < 96 */
2455 LTEQ
, /* cur_len <= 64 */
2473 SWAP
, /* s: edge2 cur_len edge */
2478 DUP
, /* s: edge2 cur_len edge edge anchor anchor */
2484 ADD
, /* s: edge2 cur_len edge org_pos */
2491 ADD
, /* s: edge2 cur_len edge org_center */
2496 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2501 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2508 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2515 ABS
, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2517 LT
, /* delta1 < delta2 */
2522 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2528 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2529 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2537 SUB
, /* arg = cur_pos1 - cur_len/2 */
2539 SWAP
, /* s: edge2 cur_len arg edge */
2544 SWAP
, /* s: edge2 cur_len edge arg edge */
2547 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2550 SWAP
, /* s: edge2 cur_len edge */
2554 GC_cur
, /* s: edge2 cur_len edge anchor_pos */
2562 ADD
, /* s: edge2 cur_len edge org_pos */
2571 ADD
, /* s: edge2 cur_len edge org_pos org_center */
2577 CALL
, /* cur_pos1 = ROUND(org_pos) */
2589 SUB
, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2600 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2607 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2613 ABS
, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2614 LT
, /* delta1 < delta2 */
2616 POP
, /* arg = cur_pos1 */
2620 POP
, /* arg = cur_pos2 */
2621 EIF
, /* s: edge2 cur_len edge arg */
2627 SWAP
, /* s: edge2 cur_len edge arg edge */
2630 SHPIX
, /* edge = arg */
2631 EIF
, /* s: edge2 cur_len */
2633 SWAP
, /* s: cur_len edge2 */
2636 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2640 WS
, /* s: cur_len edge2 */
2642 SHPIX
, /* edge2 = edge + cur_len */
2647 SZP1
, /* set zp1 to normal zone 1 */
2653 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2666 * Handle the BLUE action to align an edge with a blue zone.
2669 * edge_point (in twilight zone)
2670 * ... stuff for bci_align_segments (edge) ...
2673 unsigned char FPGM(bci_action_blue
) [] = {
2681 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2683 /* move `edge_point' to `blue_cvt_idx' position; */
2684 /* note that we can't use MIAP since this would modify */
2685 /* the twilight point's original coordinates also */
2689 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2691 GC_cur
, /* s: new_pos edge edge_pos */
2694 SUB
, /* s: edge (new_pos - edge_pos) */
2700 SZP1
, /* set zp1 to normal zone 1 */
2711 * Handle the SERIF action to align a serif with its base.
2713 * in: serif_point (in twilight zone)
2714 * base_point (in twilight zone)
2715 * ... stuff for bci_align_segments (serif) ...
2718 unsigned char FPGM(bci_action_serif
) [] = {
2726 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2733 MINDEX
, /* s: serif serif serif serif base */
2735 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2738 ALIGNRP
, /* align `serif_point' with `base_point' */
2739 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2741 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2746 SZP1
, /* set zp1 to normal zone 1 */
2755 * bci_action_serif_lower_bound
2757 * Handle the SERIF action to align a serif with its base, then moving it
2758 * again if necessary to stay within a lower bound.
2760 * in: serif_point (in twilight zone)
2761 * base_point (in twilight zone)
2762 * edge[-1] (in twilight zone)
2763 * ... stuff for bci_align_segments (serif) ...
2766 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2769 bci_action_serif_lower_bound
,
2774 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2781 MINDEX
, /* s: edge[-1] serif serif serif serif base */
2783 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2786 ALIGNRP
, /* align `serif_point' with `base_point' */
2787 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2789 SWAP
, /* s: serif edge[-1] */
2791 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2796 GC_cur
, /* s: serif edge[-1]_pos serif_pos */
2797 GT
, /* serif_pos < edge[-1]_pos */
2800 ALIGNRP
, /* align `serif' to `edge[-1]' */
2803 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2808 SZP1
, /* set zp1 to normal zone 1 */
2817 * bci_action_serif_upper_bound
2819 * Handle the SERIF action to align a serif with its base, then moving it
2820 * again if necessary to stay within an upper bound.
2822 * in: serif_point (in twilight zone)
2823 * base_point (in twilight zone)
2824 * edge[1] (in twilight zone)
2825 * ... stuff for bci_align_segments (serif) ...
2828 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2831 bci_action_serif_upper_bound
,
2836 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2843 MINDEX
, /* s: edge[1] serif serif serif serif base */
2845 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2848 ALIGNRP
, /* align `serif_point' with `base_point' */
2849 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2851 SWAP
, /* s: serif edge[1] */
2853 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2858 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2859 LT
, /* serif_pos > edge[1]_pos */
2862 ALIGNRP
, /* align `serif' to `edge[1]' */
2865 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2870 SZP1
, /* set zp1 to normal zone 1 */
2879 * bci_action_serif_lower_upper_bound
2881 * Handle the SERIF action to align a serif with its base, then moving it
2882 * again if necessary to stay within a lower and upper bound.
2884 * in: serif_point (in twilight zone)
2885 * base_point (in twilight zone)
2886 * edge[-1] (in twilight zone)
2887 * edge[1] (in twilight zone)
2888 * ... stuff for bci_align_segments (serif) ...
2891 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2894 bci_action_serif_lower_upper_bound
,
2899 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2906 MINDEX
, /* s: edge[1] edge[-1] serif serif serif serif base */
2908 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2911 ALIGNRP
, /* align `serif_point' with `base_point' */
2912 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2914 SWAP
, /* s: edge[1] serif edge[-1] */
2916 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2921 GC_cur
, /* s: edge[1] serif edge[-1]_pos serif_pos */
2922 GT
, /* serif_pos < edge[-1]_pos */
2925 ALIGNRP
, /* align `serif' to `edge[-1]' */
2928 SWAP
, /* s: serif edge[1] */
2930 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2935 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2936 LT
, /* serif_pos > edge[1]_pos */
2939 ALIGNRP
, /* align `serif' to `edge[1]' */
2942 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2947 SZP1
, /* set zp1 to normal zone 1 */
2956 * bci_action_serif_anchor
2958 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2961 * in: edge_point (in twilight zone)
2962 * ... stuff for bci_align_segments (edge) ...
2965 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2968 bci_action_serif_anchor
,
2973 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2979 WS
, /* sal_anchor = edge_point */
2989 CALL
, /* s: edge edge edge_pos round(edge_orig_pos) */
2992 SHPIX
, /* edge = round(edge_orig) */
2994 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2999 SZP1
, /* set zp1 to normal zone 1 */
3008 * bci_action_serif_anchor_lower_bound
3010 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3011 * anchor, then moving it again if necessary to stay within a lower
3014 * in: edge_point (in twilight zone)
3015 * edge[-1] (in twilight zone)
3016 * ... stuff for bci_align_segments (edge) ...
3019 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
3022 bci_action_serif_anchor_lower_bound
,
3027 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3033 WS
, /* sal_anchor = edge_point */
3043 CALL
, /* s: edge[-1] edge edge edge_pos round(edge_orig_pos) */
3046 SHPIX
, /* edge = round(edge_orig) */
3048 SWAP
, /* s: edge edge[-1] */
3050 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3055 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3056 GT
, /* edge_pos < edge[-1]_pos */
3059 ALIGNRP
, /* align `edge' to `edge[-1]' */
3062 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3067 SZP1
, /* set zp1 to normal zone 1 */
3076 * bci_action_serif_anchor_upper_bound
3078 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3079 * anchor, then moving it again if necessary to stay within an upper
3082 * in: edge_point (in twilight zone)
3083 * edge[1] (in twilight zone)
3084 * ... stuff for bci_align_segments (edge) ...
3087 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
3090 bci_action_serif_anchor_upper_bound
,
3095 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3101 WS
, /* sal_anchor = edge_point */
3111 CALL
, /* s: edge[1] edge edge edge_pos round(edge_orig_pos) */
3114 SHPIX
, /* edge = round(edge_orig) */
3116 SWAP
, /* s: edge edge[1] */
3118 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3123 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3124 LT
, /* edge_pos > edge[1]_pos */
3127 ALIGNRP
, /* align `edge' to `edge[1]' */
3130 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3135 SZP1
, /* set zp1 to normal zone 1 */
3144 * bci_action_serif_anchor_lower_upper_bound
3146 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3147 * anchor, then moving it again if necessary to stay within a lower and
3150 * in: edge_point (in twilight zone)
3151 * edge[-1] (in twilight zone)
3152 * edge[1] (in twilight zone)
3153 * ... stuff for bci_align_segments (edge) ...
3156 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
3159 bci_action_serif_anchor_lower_upper_bound
,
3164 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3170 WS
, /* sal_anchor = edge_point */
3180 CALL
, /* s: edge[1] edge[-1] edge edge edge_pos round(edge_orig_pos) */
3183 SHPIX
, /* edge = round(edge_orig) */
3185 SWAP
, /* s: edge[1] edge edge[-1] */
3187 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3192 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3193 GT
, /* edge_pos < edge[-1]_pos */
3196 ALIGNRP
, /* align `edge' to `edge[-1]' */
3199 SWAP
, /* s: edge edge[1] */
3201 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3206 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3207 LT
, /* edge_pos > edge[1]_pos */
3210 ALIGNRP
, /* align `edge' to `edge[1]' */
3213 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3218 SZP1
, /* set zp1 to normal zone 1 */
3227 * bci_action_serif_link1
3229 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3232 * in: before_point (in twilight zone)
3233 * edge_point (in twilight zone)
3234 * after_point (in twilight zone)
3235 * ... stuff for bci_align_segments (edge) ...
3238 unsigned char FPGM(bci_action_serif_link1
) [] = {
3241 bci_action_serif_link1
,
3246 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3250 CINDEX
, /* s: after edge before after */
3253 CINDEX
, /* s: after edge before after before */
3257 EQ
, /* after_orig_pos == before_orig_pos */
3258 IF
, /* s: after edge before */
3259 MDAP_noround
, /* set rp0 and rp1 to `before' */
3261 ALIGNRP
, /* align `edge' with `before' */
3268 CINDEX
, /* s: ... after edge before edge */
3271 CINDEX
, /* s: ... after edge before edge before */
3272 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3280 CINDEX
, /* s: ... after edge before a*64 after */
3283 CINDEX
, /* s: ... after edge before a*64 after before */
3284 MD_cur
, /* b = after_pos - before_pos */
3285 MUL
, /* s: ... after edge before a*b */
3289 CINDEX
, /* s: ... after edge before a*b after */
3292 CINDEX
, /* s: ... after edge before a*b after before */
3293 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3299 DIV
, /* s: after edge before a*b/c */
3302 MDAP_noround
, /* set rp0 and rp1 to `before' */
3303 SWAP
, /* s: after a*b/c edge */
3306 ALIGNRP
, /* align `edge' with `before' */
3308 SHPIX
, /* shift `edge' by `a*b/c' */
3310 SWAP
, /* s: edge after */
3314 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3319 SZP1
, /* set zp1 to normal zone 1 */
3328 * bci_action_serif_link1_lower_bound
3330 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3331 * before and after. Additionally, move the serif again if necessary to
3332 * stay within a lower bound.
3334 * in: before_point (in twilight zone)
3335 * edge_point (in twilight zone)
3336 * after_point (in twilight zone)
3337 * edge[-1] (in twilight zone)
3338 * ... stuff for bci_align_segments (edge) ...
3341 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3344 bci_action_serif_link1_lower_bound
,
3349 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3353 CINDEX
, /* s: edge[-1] after edge before after */
3356 CINDEX
, /* s: edge[-1] after edge before after before */
3360 EQ
, /* after_orig_pos == before_orig_pos */
3361 IF
, /* s: edge[-1] after edge before */
3362 MDAP_noround
, /* set rp0 and rp1 to `before' */
3364 ALIGNRP
, /* align `edge' with `before' */
3371 CINDEX
, /* s: ... after edge before edge */
3374 CINDEX
, /* s: ... after edge before edge before */
3375 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3383 CINDEX
, /* s: ... after edge before a*64 after */
3386 CINDEX
, /* s: ... after edge before a*64 after before */
3387 MD_cur
, /* b = after_pos - before_pos */
3388 MUL
, /* s: ... after edge before a*b */
3392 CINDEX
, /* s: ... after edge before a*b after */
3395 CINDEX
, /* s: ... after edge before a*b after before */
3396 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3402 DIV
, /* s: edge[-1] after edge before a*b/c */
3405 MDAP_noround
, /* set rp0 and rp1 to `before' */
3406 SWAP
, /* s: edge[-1] after a*b/c edge */
3409 ALIGNRP
, /* align `edge' with `before' */
3411 SHPIX
, /* shift `edge' by `a*b/c' */
3413 SWAP
, /* s: edge[-1] edge after */
3417 SWAP
, /* s: edge edge[-1] */
3419 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3424 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3425 GT
, /* edge_pos < edge[-1]_pos */
3428 ALIGNRP
, /* align `edge' to `edge[-1]' */
3431 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3436 SZP1
, /* set zp1 to normal zone 1 */
3444 * bci_action_serif_link1_upper_bound
3446 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3447 * before and after. Additionally, move the serif again if necessary to
3448 * stay within an upper bound.
3450 * in: before_point (in twilight zone)
3451 * edge_point (in twilight zone)
3452 * after_point (in twilight zone)
3453 * edge[1] (in twilight zone)
3454 * ... stuff for bci_align_segments (edge) ...
3457 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3460 bci_action_serif_link1_upper_bound
,
3465 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3469 CINDEX
, /* s: edge[1] after edge before after */
3472 CINDEX
, /* s: edge[1] after edge before after before */
3476 EQ
, /* after_orig_pos == before_orig_pos */
3477 IF
, /* s: edge[1] after edge before */
3478 MDAP_noround
, /* set rp0 and rp1 to `before' */
3480 ALIGNRP
, /* align `edge' with `before' */
3487 CINDEX
, /* s: ... after edge before edge */
3490 CINDEX
, /* s: ... after edge before edge before */
3491 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3499 CINDEX
, /* s: ... after edge before a*64 after */
3502 CINDEX
, /* s: ... after edge before a*64 after before */
3503 MD_cur
, /* b = after_pos - before_pos */
3504 MUL
, /* s: ... after edge before a*b */
3508 CINDEX
, /* s: ... after edge before a*b after */
3511 CINDEX
, /* s: ... after edge before a*b after before */
3512 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3518 DIV
, /* s: edge[1] after edge before a*b/c */
3521 MDAP_noround
, /* set rp0 and rp1 to `before' */
3522 SWAP
, /* s: edge[1] after a*b/c edge */
3525 ALIGNRP
, /* align `edge' with `before' */
3527 SHPIX
, /* shift `edge' by `a*b/c' */
3529 SWAP
, /* s: edge[1] edge after */
3533 SWAP
, /* s: edge edge[1] */
3535 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3540 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3541 LT
, /* edge_pos > edge[1]_pos */
3544 ALIGNRP
, /* align `edge' to `edge[1]' */
3547 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3552 SZP1
, /* set zp1 to normal zone 1 */
3561 * bci_action_serif_link1_lower_upper_bound
3563 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3564 * before and after. Additionally, move the serif again if necessary to
3565 * stay within a lower and upper bound.
3567 * in: before_point (in twilight zone)
3568 * edge_point (in twilight zone)
3569 * after_point (in twilight zone)
3570 * edge[-1] (in twilight zone)
3571 * edge[1] (in twilight zone)
3572 * ... stuff for bci_align_segments (edge) ...
3575 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3578 bci_action_serif_link1_lower_upper_bound
,
3583 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3587 CINDEX
, /* s: edge[1] edge[-1] after edge before after */
3590 CINDEX
, /* s: edge[1] edge[-1] after edge before after before */
3594 EQ
, /* after_orig_pos == before_orig_pos */
3595 IF
, /* s: edge[1] edge[-1] after edge before */
3596 MDAP_noround
, /* set rp0 and rp1 to `before' */
3598 ALIGNRP
, /* align `edge' with `before' */
3605 CINDEX
, /* s: ... after edge before edge */
3608 CINDEX
, /* s: ... after edge before edge before */
3609 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3617 CINDEX
, /* s: ... after edge before a*64 after */
3620 CINDEX
, /* s: ... after edge before a*64 after before */
3621 MD_cur
, /* b = after_pos - before_pos */
3622 MUL
, /* s: ... after edge before a*b */
3626 CINDEX
, /* s: ... after edge before a*b after */
3629 CINDEX
, /* s: ... after edge before a*b after_orig before */
3630 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3636 DIV
, /* s: edge[1] edge[-1] after edge before a*b/c */
3639 MDAP_noround
, /* set rp0 and rp1 to `before' */
3640 SWAP
, /* s: edge[1] edge[-1] after a*b/c edge */
3643 ALIGNRP
, /* align `edge' with `before' */
3645 SHPIX
, /* shift `edge' by `a*b/c' */
3647 SWAP
, /* s: edge[1] edge[-1] edge after */
3651 SWAP
, /* s: edge[1] edge edge[-1] */
3653 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3658 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3659 GT
, /* edge_pos < edge[-1]_pos */
3662 ALIGNRP
, /* align `edge' to `edge[-1]' */
3665 SWAP
, /* s: edge edge[1] */
3667 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3672 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3673 LT
, /* edge_pos > edge[1]_pos */
3676 ALIGNRP
, /* align `edge' to `edge[1]' */
3679 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3684 SZP1
, /* set zp1 to normal zone 1 */
3693 * bci_action_serif_link2
3695 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3697 * in: edge_point (in twilight zone)
3698 * ... stuff for bci_align_segments (edge) ...
3701 unsigned char FPGM(bci_action_serif_link2
) [] = {
3704 bci_action_serif_link2
,
3709 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3711 DUP
, /* s: edge edge */
3715 DUP
, /* s: edge edge anchor anchor */
3716 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3727 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3732 ALIGNRP
, /* align `edge' with `sal_anchor' */
3734 SHPIX
, /* shift `edge' by `delta' */
3736 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3741 SZP1
, /* set zp1 to normal zone 1 */
3750 * bci_action_serif_link2_lower_bound
3752 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3753 * Additionally, move the serif again if necessary to stay within a lower
3756 * in: edge_point (in twilight zone)
3757 * edge[-1] (in twilight zone)
3758 * ... stuff for bci_align_segments (edge) ...
3761 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
3764 bci_action_serif_link2_lower_bound
,
3769 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3771 DUP
, /* s: edge[-1] edge edge */
3775 DUP
, /* s: edge[-1] edge edge anchor anchor */
3776 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3787 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3792 ALIGNRP
, /* align `edge' with `sal_anchor' */
3794 SHPIX
, /* shift `edge' by `delta' */
3796 SWAP
, /* s: edge edge[-1] */
3798 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3803 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3804 GT
, /* edge_pos < edge[-1]_pos */
3807 ALIGNRP
, /* align `edge' to `edge[-1]' */
3810 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3815 SZP1
, /* set zp1 to normal zone 1 */
3824 * bci_action_serif_link2_upper_bound
3826 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3827 * Additionally, move the serif again if necessary to stay within an upper
3830 * in: edge_point (in twilight zone)
3831 * edge[1] (in twilight zone)
3832 * ... stuff for bci_align_segments (edge) ...
3835 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3838 bci_action_serif_link2_upper_bound
,
3843 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3845 DUP
, /* s: edge[1] edge edge */
3849 DUP
, /* s: edge[1] edge edge anchor anchor */
3850 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3861 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3866 ALIGNRP
, /* align `edge' with `sal_anchor' */
3868 SHPIX
, /* shift `edge' by `delta' */
3870 SWAP
, /* s: edge edge[1] */
3872 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3877 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3878 LT
, /* edge_pos > edge[1]_pos */
3881 ALIGNRP
, /* align `edge' to `edge[1]' */
3884 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3889 SZP1
, /* set zp1 to normal zone 1 */
3898 * bci_action_serif_link2_lower_upper_bound
3900 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3901 * Additionally, move the serif again if necessary to stay within a lower
3904 * in: edge_point (in twilight zone)
3905 * edge[-1] (in twilight zone)
3906 * edge[1] (in twilight zone)
3907 * ... stuff for bci_align_segments (edge) ...
3910 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3913 bci_action_serif_link2_lower_upper_bound
,
3918 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3920 DUP
, /* s: edge[1] edge[-1] edge edge */
3924 DUP
, /* s: edge[1] edge[-1] edge edge anchor anchor */
3925 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3936 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3941 ALIGNRP
, /* align `edge' with `sal_anchor' */
3943 SHPIX
, /* shift `edge' by `delta' */
3945 SWAP
, /* s: edge[1] edge edge[-1] */
3947 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3952 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3953 GT
, /* edge_pos < edge[-1]_pos */
3956 ALIGNRP
, /* align `edge' to `edge[-1]' */
3959 SWAP
, /* s: edge edge[1] */
3961 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3966 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3967 LT
, /* edge_pos > edge[1]_pos */
3970 ALIGNRP
, /* align `edge' to `edge[1]' */
3973 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3978 SZP1
, /* set zp1 to normal zone 1 */
3991 * in: function_index
3994 unsigned char FPGM(bci_handle_action
) [] = {
4010 * This is the top-level glyph hinting function
4011 * which parses the arguments on the stack and calls subroutines.
4013 * in: num_actions (M)
4022 * uses: bci_handle_action
4024 * bci_action_ip_before
4025 * bci_action_ip_after
4027 * bci_action_ip_between
4029 * bci_action_adjust_bound
4030 * bci_action_stem_bound
4034 * bci_action_blue_anchor
4040 * bci_action_serif_lower_bound
4041 * bci_action_serif_upper_bound
4042 * bci_action_serif_lower_upper_bound
4044 * bci_action_serif_anchor
4045 * bci_action_serif_anchor_lower_bound
4046 * bci_action_serif_anchor_upper_bound
4047 * bci_action_serif_anchor_lower_upper_bound
4049 * bci_action_serif_link1
4050 * bci_action_serif_link1_lower_bound
4051 * bci_action_serif_link1_upper_bound
4052 * bci_action_serif_link1_lower_upper_bound
4054 * bci_action_serif_link2
4055 * bci_action_serif_link2_lower_bound
4056 * bci_action_serif_link2_upper_bound
4057 * bci_action_serif_link2_lower_upper_bound
4060 unsigned char FPGM(bci_hint_glyph
) [] = {
4072 SZP2
, /* set zp2 to normal zone 1 */
4080 #define COPY_FPGM(func_name) \
4081 memcpy(buf_p, fpgm_ ## func_name, \
4082 sizeof (fpgm_ ## func_name)); \
4083 buf_p += sizeof (fpgm_ ## func_name) \
4086 TA_table_build_fpgm(FT_Byte
** fpgm
,
4096 buf_len
= sizeof (FPGM(bci_round
))
4097 + sizeof (FPGM(bci_compute_stem_width_a
))
4099 + sizeof (FPGM(bci_compute_stem_width_b
))
4101 + sizeof (FPGM(bci_compute_stem_width_c
))
4102 + sizeof (FPGM(bci_loop
))
4103 + sizeof (FPGM(bci_cvt_rescale
))
4104 + sizeof (FPGM(bci_blue_round_a
))
4106 + sizeof (FPGM(bci_blue_round_b
))
4107 + sizeof (FPGM(bci_get_point_extrema
))
4109 + sizeof (FPGM(bci_create_segment
))
4110 + sizeof (FPGM(bci_create_segments
))
4111 + sizeof (FPGM(bci_align_segment
))
4112 + sizeof (FPGM(bci_align_segments
))
4114 + sizeof (FPGM(bci_scale_contour
))
4115 + sizeof (FPGM(bci_scale_glyph
))
4116 + sizeof (FPGM(bci_shift_contour
))
4117 + sizeof (FPGM(bci_shift_subglyph
))
4119 + sizeof (FPGM(bci_ip_outer_align_point
))
4120 + sizeof (FPGM(bci_ip_on_align_points
))
4121 + sizeof (FPGM(bci_ip_between_align_point
))
4122 + sizeof (FPGM(bci_ip_between_align_points
))
4124 + sizeof (FPGM(bci_action_ip_before
))
4125 + sizeof (FPGM(bci_action_ip_after
))
4126 + sizeof (FPGM(bci_action_ip_on
))
4127 + sizeof (FPGM(bci_action_ip_between
))
4129 + sizeof (FPGM(bci_action_adjust_bound
))
4130 + sizeof (FPGM(bci_action_stem_bound
))
4131 + sizeof (FPGM(bci_action_link
))
4132 + sizeof (FPGM(bci_action_anchor
))
4133 + sizeof (FPGM(bci_action_blue_anchor
))
4134 + sizeof (FPGM(bci_action_adjust
))
4135 + sizeof (FPGM(bci_action_stem
))
4136 + sizeof (FPGM(bci_action_blue
))
4137 + sizeof (FPGM(bci_action_serif
))
4138 + sizeof (FPGM(bci_action_serif_lower_bound
))
4139 + sizeof (FPGM(bci_action_serif_upper_bound
))
4140 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
4141 + sizeof (FPGM(bci_action_serif_anchor
))
4142 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
4143 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
4144 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
4145 + sizeof (FPGM(bci_action_serif_link1
))
4146 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
4147 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
4148 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
4149 + sizeof (FPGM(bci_action_serif_link2
))
4150 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
4151 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
4152 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
4154 + sizeof (FPGM(bci_handle_action
))
4155 + sizeof (FPGM(bci_hint_glyph
));
4156 /* buffer length must be a multiple of four */
4157 len
= (buf_len
+ 3) & ~3;
4158 buf
= (FT_Byte
*)malloc(len
);
4160 return FT_Err_Out_Of_Memory
;
4162 /* pad end of buffer with zeros */
4163 buf
[len
- 1] = 0x00;
4164 buf
[len
- 2] = 0x00;
4165 buf
[len
- 3] = 0x00;
4167 /* copy font program into buffer and fill in the missing variables */
4170 COPY_FPGM(bci_round
);
4171 COPY_FPGM(bci_compute_stem_width_a
);
4172 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4173 COPY_FPGM(bci_compute_stem_width_b
);
4174 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4175 COPY_FPGM(bci_compute_stem_width_c
);
4176 COPY_FPGM(bci_loop
);
4177 COPY_FPGM(bci_cvt_rescale
);
4178 COPY_FPGM(bci_blue_round_a
);
4179 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
4180 COPY_FPGM(bci_blue_round_b
);
4181 COPY_FPGM(bci_get_point_extrema
);
4183 COPY_FPGM(bci_create_segment
);
4184 COPY_FPGM(bci_create_segments
);
4185 COPY_FPGM(bci_align_segment
);
4186 COPY_FPGM(bci_align_segments
);
4188 COPY_FPGM(bci_scale_contour
);
4189 COPY_FPGM(bci_scale_glyph
);
4190 COPY_FPGM(bci_shift_contour
);
4191 COPY_FPGM(bci_shift_subglyph
);
4193 COPY_FPGM(bci_ip_outer_align_point
);
4194 COPY_FPGM(bci_ip_on_align_points
);
4195 COPY_FPGM(bci_ip_between_align_point
);
4196 COPY_FPGM(bci_ip_between_align_points
);
4198 COPY_FPGM(bci_action_ip_before
);
4199 COPY_FPGM(bci_action_ip_after
);
4200 COPY_FPGM(bci_action_ip_on
);
4201 COPY_FPGM(bci_action_ip_between
);
4203 COPY_FPGM(bci_action_adjust_bound
);
4204 COPY_FPGM(bci_action_stem_bound
);
4205 COPY_FPGM(bci_action_link
);
4206 COPY_FPGM(bci_action_anchor
);
4207 COPY_FPGM(bci_action_blue_anchor
);
4208 COPY_FPGM(bci_action_adjust
);
4209 COPY_FPGM(bci_action_stem
);
4210 COPY_FPGM(bci_action_blue
);
4211 COPY_FPGM(bci_action_serif
);
4212 COPY_FPGM(bci_action_serif_lower_bound
);
4213 COPY_FPGM(bci_action_serif_upper_bound
);
4214 COPY_FPGM(bci_action_serif_lower_upper_bound
);
4215 COPY_FPGM(bci_action_serif_anchor
);
4216 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
4217 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
4218 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
4219 COPY_FPGM(bci_action_serif_link1
);
4220 COPY_FPGM(bci_action_serif_link1_lower_bound
);
4221 COPY_FPGM(bci_action_serif_link1_upper_bound
);
4222 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
4223 COPY_FPGM(bci_action_serif_link2
);
4224 COPY_FPGM(bci_action_serif_link2_lower_bound
);
4225 COPY_FPGM(bci_action_serif_link2_upper_bound
);
4226 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
4228 COPY_FPGM(bci_handle_action
);
4229 COPY_FPGM(bci_hint_glyph
);
4232 *fpgm_len
= buf_len
;
4239 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
4248 error
= TA_sfnt_add_table_info(sfnt
);
4252 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
4256 if (fpgm_len
> sfnt
->max_instructions
)
4257 sfnt
->max_instructions
= fpgm_len
;
4259 /* in case of success, `fpgm_buf' gets linked */
4260 /* and is eventually freed in `TA_font_unload' */
4261 error
= TA_font_add_table(font
,
4262 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
4263 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
4273 /* end of tafpgm.c */