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
145 * CVT: cvtl_is_extra_light
149 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
152 bci_compute_stem_width
,
156 ABS
, /* s: base_is_round stem_is_serif width dist */
161 LT
, /* dist < 3*64 */
165 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
166 AND
, /* stem_is_serif && dist < 3*64 */
171 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
173 IF
, /* s: base_is_round width dist */
179 ROLL
, /* s: width dist base_is_round */
180 IF
, /* s: width dist */
185 IF
, /* s: width dist */
196 IF
, /* s: width dist */
203 DUP
, /* s: width dist dist */
208 /* %c, index of std_width */
210 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
214 ABS
, /* s: width dist delta */
219 IF
, /* s: width dist */
225 /* %c, index of std_width */
227 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
229 RCVT
, /* dist = std_width */
241 DUP
, /* s: width dist dist */
244 LT
, /* dist < 3*64 */
246 DUP
, /* s: width delta dist */
247 FLOOR
, /* dist = FLOOR(dist) */
248 DUP
, /* s: width delta dist dist */
250 ROLL
, /* s: width dist delta dist */
251 SUB
, /* delta = delta - dist */
253 DUP
, /* s: width dist delta delta */
257 IF
, /* s: width dist delta */
258 ADD
, /* dist = dist + delta */
269 ADD
, /* dist = dist + 10 */
280 ADD
, /* dist = dist + 54 */
283 ADD
, /* dist = dist + delta */
292 CALL
, /* dist = round(dist) */
297 SWAP
, /* s: dist width */
302 NEG
, /* dist = -dist */
314 * Take a range and a function number and apply the function to all
315 * elements of the range.
321 * sal: sal_i (counter initialized with `start')
323 * sal_func (`func_num')
326 unsigned char FPGM(bci_loop
) [] = {
335 WS
, /* sal_func = func_num */
339 WS
, /* sal_limit = end */
343 WS
, /* sal_i = start */
352 LTEQ
, /* start <= end */
363 ADD
, /* start = start + 1 */
369 JMPR
, /* goto start_loop */
380 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
382 * sal: sal_i (CVT index)
388 unsigned char FPGM(bci_cvt_rescale
) [] = {
402 MUL
, /* CVT * scale * 2^10 */
406 DIV
, /* CVT * scale */
418 * Round a blue ref value and adjust its corresponding shoot value.
420 * sal: sal_i (CVT index)
424 unsigned char FPGM(bci_blue_round_a
) [] = {
434 RCVT
, /* s: ref_idx ref */
440 SWAP
, /* s: ref_idx round(ref) ref */
448 unsigned char FPGM(bci_blue_round_b
) [] = {
452 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
454 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
456 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
458 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
460 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
485 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
490 NEG
, /* delta = -delta */
497 SUB
, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
508 * bci_get_point_extrema
510 * An auxiliary function for `bci_create_segment'.
519 unsigned char FPGM(bci_get_point_extrema
) [] = {
522 bci_get_point_extrema
,
531 /* check whether `point' is a new minimum */
534 RS
, /* s: point point point point_min */
536 /* if distance is negative, we have a new minimum */
540 IF
, /* s: point point */
548 /* check whether `point' is a new maximum */
551 RS
, /* s: point point point_max */
553 /* if distance is positive, we have a new maximum */
573 * Store start and end point of a segment in the storage area,
574 * then construct a point in the twilight zone to represent it.
576 * This function is used by `bci_create_segment_points'.
580 * [last (if wrap-around segment)]
581 * [first (if wrap-around segment)]
583 * uses: bci_get_point_extrema
585 * sal: sal_i (start of current segment)
586 * sal_j (current twilight point)
595 unsigned char FPGM(bci_create_segment
) [] = {
607 WS
, /* sal[sal_i] = start */
609 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
615 ADD
, /* sal_i = sal_i + 1 */
618 /* initialize inner loop(s) */
623 WS
, /* sal_point_min = start */
628 WS
, /* sal_point_max = start */
632 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
638 CINDEX
, /* s: start end end start */
639 LT
, /* start > end */
641 /* we have a wrap-around segment with two more arguments */
642 /* to give the last and first point of the contour, respectively; */
643 /* our job is to store a segment `start'-`last', */
644 /* and to get extrema for the two segments */
645 /* `start'-`last' and `first'-`end' */
647 /* s: first last start end */
654 WS
, /* sal[sal_i] = last */
657 ROLL
, /* s: first end last start */
660 SWAP
, /* s: first end start last start */
661 SUB
, /* s: first end start loop_count */
664 bci_get_point_extrema
,
669 SWAP
, /* s: end first */
674 ROLL
, /* s: (first - 1) (first - 1) end */
676 SUB
, /* s: (first - 1) loop_count */
679 bci_get_point_extrema
,
684 ELSE
, /* s: start end */
691 WS
, /* sal[sal_i] = end */
696 SUB
, /* s: start loop_count */
699 bci_get_point_extrema
,
705 /* the twilight point representing a segment */
706 /* is in the middle between the minimum and maximum */
718 DIV
, /* s: middle_pos */
724 MUL
, /* middle_pos * scale * 2^10 */
728 DIV
, /* middle_pos = middle_pos * scale */
730 /* write it to temporary CVT location */
734 SZP0
, /* set zp0 to twilight zone 0 */
738 /* create twilight point with index `sal_j' */
751 ADD
, /* twilight_point = twilight_point + 1 */
760 * bci_create_segments
762 * Set up segments by defining point ranges which defines them
763 * and computing twilight points to represent them.
765 * in: num_segments (N)
768 * [contour_last 0 (if wrap-around segment)]
769 * [contour_first 0 (if wrap-around segment)]
772 * [contour_last 0 (if wrap-around segment)]
773 * [contour_first 0 (if wrap-around segment)]
775 * segment_start_(N-1)
777 * [contour_last (N-1) (if wrap-around segment)]
778 * [contour_first (N-1) (if wrap-around segment)]
780 * uses: bci_create_segment
782 * sal: sal_i (start of current segment)
783 * sal_j (current twilight point)
786 unsigned char FPGM(bci_create_segments
) [] = {
792 /* all our measurements are taken along the y axis */
799 SUB
, /* delta = (2*num_segments - 1) */
807 WS
, /* sal_j = 0 (point offset) */
810 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
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.
938 unsigned char FPGM(bci_scale_contour
) [] = {
951 MUL
, /* min_pos * scale * 2^10 */
955 DIV
, /* min_pos_new = min_pos * scale */
960 /* don't scale a single-point contour twice */
972 MUL
, /* max_pos * scale * 2^10 */
976 DIV
, /* max_pos_new = max_pos * scale */
993 * Scale a glyph using a list of points (two points per contour, giving
994 * the maximum and mininum coordinates).
996 * It expects that no point in the glyph is touched.
998 * in: num_contours (N)
1007 * uses: bci_scale_contour
1010 unsigned char FPGM(bci_scale_glyph
) [] = {
1020 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1028 SZP2
, /* set zp2 to normal zone 1 */
1039 * Shift a contour by a given amount.
1041 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1042 * point to the normal zone 1.
1048 unsigned char FPGM(bci_shift_contour
) [] = {
1055 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1067 * bci_shift_subglyph
1069 * Shift a subglyph. To be more specific, it corrects the already applied
1070 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1073 * If this function is called, a point `x' in the subglyph has been scaled
1074 * by `cvtl_scale' already (during the hinting of the subglyph itself), and
1075 * `offset' has been applied also:
1077 * x -> x * scale + offset (1)
1079 * However, the offset should be applied first, then the scaling:
1081 * x -> (x + offset) * scale (2)
1083 * Our job is now to transform (1) to (2); a simple calculation shows that
1084 * we have to shift all points of the subglyph by
1086 * offset * scale - offset = offset * (scale - 1)
1088 * in: offset (in FUnits)
1092 * CVT: cvtl_funits_to_pixels
1097 unsigned char FPGM(bci_shift_subglyph
) [] = {
1106 cvtl_funits_to_pixels
,
1107 RCVT
, /* scaling factor FUnits -> pixels */
1114 /* the autohinter always rounds offsets */
1117 CALL
, /* offset = round(offset) */
1125 SUB
, /* scale - 1 (in 16.16 format) */
1130 DIV
, /* delta = offset * (scale - 1) */
1132 /* and round again */
1135 CALL
, /* offset = round(offset) */
1139 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1141 /* we create twilight point 0 as a reference point, */
1142 /* setting the original position to zero (using `cvtl_temp') */
1150 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
1152 SWAP
, /* s: first_contour num_contours 0 delta */
1153 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
1158 SZP2
, /* set zp2 to normal zone 1 */
1167 * bci_ip_outer_align_point
1169 * Auxiliary function for `bci_action_ip_before' and
1170 * `bci_action_ip_after'.
1172 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1173 * zone, and both zp1 and zp2 set to normal zone.
1177 * sal: sal_i (edge_orig_pos)
1183 unsigned char FPGM(bci_ip_outer_align_point
) [] = {
1186 bci_ip_outer_align_point
,
1190 ALIGNRP
, /* align `point' with `edge' */
1197 MUL
, /* point_orig_pos * scale * 2^10 */
1201 DIV
, /* point_orig_pos = point_orig_pos * scale */
1206 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1215 * bci_ip_on_align_points
1217 * Auxiliary function for `bci_action_ip_on'.
1219 * in: edge (in twilight zone)
1227 unsigned char FPGM(bci_ip_on_align_points
) [] = {
1230 bci_ip_on_align_points
,
1233 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1244 * bci_ip_between_align_point
1246 * Auxiliary function for `bci_ip_between_align_points'.
1248 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1249 * zone, and both zp1 and zp2 set to normal zone.
1253 * sal: sal_i (edge_orig_pos)
1254 * sal_j (stretch_factor)
1260 unsigned char FPGM(bci_ip_between_align_point
) [] = {
1263 bci_ip_between_align_point
,
1267 ALIGNRP
, /* align `point' with `edge' */
1274 MUL
, /* point_orig_pos * scale * 2^10 */
1278 DIV
, /* point_orig_pos = point_orig_pos * scale */
1283 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1287 MUL
, /* s: point delta */
1296 * bci_ip_between_align_points
1298 * Auxiliary function for `bci_action_ip_between'.
1300 * in: after_edge (in twilight zone)
1301 * before_edge (in twilight zone)
1308 * sal: sal_i (before_orig_pos)
1309 * sal_j (stretch_factor)
1311 * uses: bci_ip_between_align_point
1314 unsigned char FPGM(bci_ip_between_align_points
) [] = {
1317 bci_ip_between_align_points
,
1323 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1325 DUP
, /* s: ... before after before before */
1326 MDAP_noround
, /* set rp0 and rp1 to `before' */
1328 GC_orig
, /* s: ... before after before before_orig_pos */
1332 WS
, /* sal_i = before_orig_pos */
1335 CINDEX
, /* s: ... before after before after */
1336 MD_cur
, /* b = after_pos - before_pos */
1339 MD_orig_ZP2_0
, /* a = after_orig_pos - before_orig_pos */
1344 WS
, /* sal_j = stretch_factor */
1347 bci_ip_between_align_point
,
1350 SZP2
, /* set zp2 to normal zone 1 */
1351 SZP1
, /* set zp1 to normal zone 1 */
1360 * bci_action_ip_before
1362 * Handle `ip_before' data to align points located before the first edge.
1364 * in: first_edge (in twilight zone)
1371 * sal: sal_i (first_edge_orig_pos)
1373 * uses: bci_ip_outer_align_point
1376 unsigned char FPGM(bci_action_ip_before
) [] = {
1379 bci_action_ip_before
,
1384 SZP2
, /* set zp2 to twilight zone 0 */
1391 WS
, /* sal_i = first_edge_orig_pos */
1397 SZP2
, /* set zp2 to normal zone 1 */
1398 SZP1
, /* set zp1 to normal zone 1 */
1399 SZP0
, /* set zp0 to twilight zone 0 */
1401 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
1404 bci_ip_outer_align_point
,
1413 * bci_action_ip_after
1415 * Handle `ip_after' data to align points located after the last edge.
1417 * in: last_edge (in twilight zone)
1424 * sal: sal_i (last_edge_orig_pos)
1426 * uses: bci_ip_outer_align_point
1429 unsigned char FPGM(bci_action_ip_after
) [] = {
1432 bci_action_ip_after
,
1437 SZP2
, /* set zp2 to twilight zone 0 */
1444 WS
, /* sal_i = last_edge_orig_pos */
1450 SZP2
, /* set zp2 to normal zone 1 */
1451 SZP1
, /* set zp1 to normal zone 1 */
1452 SZP0
, /* set zp0 to twilight zone 0 */
1454 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
1457 bci_ip_outer_align_point
,
1468 * Handle `ip_on' data to align points located on an edge coordinate (but
1469 * not part of an edge).
1471 * in: loop_counter (M)
1472 * edge_1 (in twilight zone)
1473 * loop_counter (N_1)
1478 * edge_2 (in twilight zone)
1479 * loop_counter (N_2)
1485 * edge_M (in twilight zone)
1486 * loop_counter (N_M)
1492 * uses: bci_ip_on_align_points
1495 unsigned char FPGM(bci_action_ip_on
) [] = {
1504 SZP1
, /* set zp1 to normal zone 1 */
1505 SZP0
, /* set zp0 to twilight zone 0 */
1508 bci_ip_on_align_points
,
1517 * bci_action_ip_between
1519 * Handle `ip_between' data to align points located between two edges.
1521 * in: loop_counter (M)
1522 * before_edge_1 (in twilight zone)
1523 * after_edge_1 (in twilight zone)
1524 * loop_counter (N_1)
1529 * before_edge_2 (in twilight zone)
1530 * after_edge_2 (in twilight zone)
1531 * loop_counter (N_2)
1537 * before_edge_M (in twilight zone)
1538 * after_edge_M (in twilight zone)
1539 * loop_counter (N_M)
1545 * uses: bci_ip_between_align_points
1548 unsigned char FPGM(bci_action_ip_between
) [] = {
1551 bci_action_ip_between
,
1555 bci_ip_between_align_points
,
1564 * bci_action_adjust_bound
1566 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1567 * edge of the stem has already been moved, then moving it again if
1568 * necessary to stay bound.
1570 * in: edge2_is_serif
1572 * edge_point (in twilight zone)
1573 * edge2_point (in twilight zone)
1574 * edge[-1] (in twilight zone)
1575 * ... stuff for bci_align_segments (edge) ...
1578 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1581 bci_action_adjust_bound
,
1586 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1590 CINDEX
, /* s: edge[-1] edge2 edge is_round is_serif edge2 */
1593 CINDEX
, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge */
1594 MD_orig_ZP2_0
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1597 bci_compute_stem_width
,
1599 NEG
, /* s: edge[-1] edge2 edge -cur_len */
1601 ROLL
, /* s: edge[-1] edge -cur_len edge2 */
1602 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1605 DUP
, /* s: edge[-1] -cur_len edge edge edge */
1606 ALIGNRP
, /* align `edge' with `edge2' */
1608 SHPIX
, /* shift `edge' by -cur_len */
1610 SWAP
, /* s: edge edge[-1] */
1612 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1617 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1618 GT
, /* edge_pos < edge[-1]_pos */
1621 ALIGNRP
, /* align `edge' to `edge[-1]' */
1624 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1629 SZP1
, /* set zp1 to normal zone 1 */
1638 * bci_action_stem_bound
1640 * Handle the STEM action to align two edges of a stem, then moving one
1641 * edge again if necessary to stay bound.
1643 * The code after computing `cur_len' to shift `edge' and `edge2'
1644 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1647 * if cur_len < = 64:
1654 * org_pos = anchor + (edge_orig - anchor_orig);
1655 * org_center = org_pos + org_len / 2;
1657 * cur_pos1 = ROUND(org_center)
1658 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1659 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1660 * if (delta1 < delta2):
1661 * cur_pos1 = cur_pos1 - u_off
1663 * cur_pos1 = cur_pos1 + d_off
1665 * edge = cur_pos1 - cur_len / 2
1668 * org_pos = anchor + (edge_orig - anchor_orig)
1669 * org_center = org_pos + org_len / 2;
1671 * cur_pos1 = ROUND(org_pos)
1672 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1673 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1674 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1676 * if (delta1 < delta2):
1681 * edge2 = edge + cur_len
1683 * in: edge2_is_serif
1685 * edge_point (in twilight zone)
1686 * edge2_point (in twilight zone)
1687 * edge[-1] (in twilight zone)
1688 * ... stuff for bci_align_segments (edge) ...
1689 * ... stuff for bci_align_segments (edge2)...
1698 #define sal_u_off sal_temp1
1700 #define sal_d_off sal_temp2
1702 #define sal_org_len sal_temp3
1704 #define sal_edge2 sal_temp3
1706 unsigned char FPGM(bci_action_stem_bound
) [] = {
1709 bci_action_stem_bound
,
1714 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1722 DUP
, /* s: edge[-1] edge2 edge is_round is_serif edge2 edge edge */
1723 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1725 MD_orig_ZP2_0
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1733 bci_compute_stem_width
,
1734 CALL
, /* s: edge[-1] edge2 edge cur_len */
1739 LT
, /* cur_len < 96 */
1744 LTEQ
, /* cur_len <= 64 */
1762 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1767 DUP
, /* s: edge[-1] edge2 cur_len edge edge anchor anchor */
1773 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos */
1780 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1785 CALL
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1790 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1797 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1804 ABS
, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1806 LT
, /* delta1 < delta2 */
1811 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1817 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1818 EIF
, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1826 SUB
, /* arg = cur_pos1 - cur_len/2 */
1828 SWAP
, /* s: edge[-1] edge2 cur_len arg edge */
1834 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1837 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1840 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1844 GC_cur
, /* s: edge[-1] edge2 cur_len edge anchor_pos */
1852 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos */
1861 ADD
, /* s: edge[-1] edge2 cur_len edge org_pos org_center */
1867 CALL
, /* cur_pos1 = ROUND(org_pos) */
1879 SUB
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1890 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1897 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1903 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1904 LT
, /* delta1 < delta2 */
1906 POP
, /* arg = cur_pos1 */
1910 POP
, /* arg = cur_pos2 */
1911 EIF
, /* s: edge[-1] edge2 cur_len edge arg */
1918 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1921 SHPIX
, /* edge = arg */
1922 EIF
, /* s: edge[-1] edge2 cur_len edge */
1924 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1927 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1931 WS
, /* s: edge[-1] cur_len edge edge2 */
1933 SHPIX
, /* edge2 = edge + cur_len */
1935 SWAP
, /* s: edge edge[-1] */
1937 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1942 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1943 GT
, /* edge_pos < edge[-1]_pos */
1946 ALIGNRP
, /* align `edge' to `edge[-1]' */
1949 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1954 SZP1
, /* set zp1 to normal zone 1 */
1960 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1974 * Handle the LINK action to link an edge to another one.
1978 * base_point (in twilight zone)
1979 * stem_point (in twilight zone)
1980 * ... stuff for bci_align_segments (base) ...
1983 unsigned char FPGM(bci_action_link
) [] = {
1991 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1999 DUP
, /* s: stem is_round is_serif stem base base */
2000 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2002 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
2005 bci_compute_stem_width
,
2006 CALL
, /* s: stem new_dist */
2010 ALIGNRP
, /* align `stem_point' with `base_point' */
2012 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
2014 SHPIX
, /* stem_point = base_point + new_dist */
2019 SZP1
, /* set zp1 to normal zone 1 */
2030 * Handle the ANCHOR action to align two edges
2031 * and to set the edge anchor.
2033 * The code after computing `cur_len' to shift `edge' and `edge2'
2034 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2037 * if cur_len < = 64:
2044 * org_center = edge_orig + org_len / 2
2045 * cur_pos1 = ROUND(org_center)
2047 * error1 = ABS(org_center - (cur_pos1 - u_off))
2048 * error2 = ABS(org_center - (cur_pos1 + d_off))
2049 * if (error1 < error2):
2050 * cur_pos1 = cur_pos1 - u_off
2052 * cur_pos1 = cur_pos1 + d_off
2054 * edge = cur_pos1 - cur_len / 2
2055 * edge2 = edge + cur_len
2058 * edge = ROUND(edge_orig)
2060 * in: edge2_is_serif
2062 * edge_point (in twilight zone)
2063 * edge2_point (in twilight zone)
2064 * ... stuff for bci_align_segments (edge) ...
2073 #define sal_u_off sal_temp1
2075 #define sal_d_off sal_temp2
2077 #define sal_org_len sal_temp3
2079 unsigned char FPGM(bci_action_anchor
) [] = {
2085 /* store anchor point number in `sal_anchor' */
2090 WS
, /* sal_anchor = edge_point */
2094 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2102 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2103 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2105 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2113 bci_compute_stem_width
,
2114 CALL
, /* s: edge2 edge cur_len */
2119 LT
, /* cur_len < 96 */
2124 LTEQ
, /* cur_len <= 64 */
2142 SWAP
, /* s: edge2 cur_len edge */
2143 DUP
, /* s: edge2 cur_len edge edge */
2152 ADD
, /* s: edge2 cur_len edge org_center */
2157 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2162 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2169 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2176 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2178 LT
, /* error1 < error2 */
2183 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2189 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2190 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2198 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2202 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2205 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2207 SWAP
, /* s: cur_len edge2 */
2209 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2211 SHPIX
, /* edge2 = edge1 + cur_len */
2214 POP
, /* s: edge2 edge */
2222 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2225 SHPIX
, /* edge = round(edge_orig) */
2227 /* clean up stack */
2234 SZP1
, /* set zp1 to normal zone 1 */
2243 * bci_action_blue_anchor
2245 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2246 * and to set the edge anchor.
2248 * in: anchor_point (in twilight zone)
2250 * edge_point (in twilight zone)
2251 * ... stuff for bci_align_segments (edge) ...
2256 unsigned char FPGM(bci_action_blue_anchor
) [] = {
2259 bci_action_blue_anchor
,
2262 /* store anchor point number in `sal_anchor' */
2270 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2272 /* move `edge_point' to `blue_cvt_idx' position; */
2273 /* note that we can't use MIAP since this would modify */
2274 /* the twilight point's original coordinates also */
2278 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2280 GC_cur
, /* s: new_pos edge edge_pos */
2283 SUB
, /* s: edge (new_pos - edge_pos) */
2289 SZP1
, /* set zp1 to normal zone 1 */
2300 * Handle the ADJUST action to align an edge of a stem if the other edge
2301 * of the stem has already been moved.
2303 * in: edge2_is_serif
2305 * edge_point (in twilight zone)
2306 * edge2_point (in twilight zone)
2307 * ... stuff for bci_align_segments (edge) ...
2310 unsigned char FPGM(bci_action_adjust
) [] = {
2318 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2322 CINDEX
, /* s: edge2 edge is_round is_serif edge2 */
2325 CINDEX
, /* s: edge2 edge is_round is_serif edge2 edge */
2326 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2329 bci_compute_stem_width
,
2331 NEG
, /* s: edge2 edge -cur_len */
2334 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2337 DUP
, /* s: -cur_len edge edge edge */
2338 ALIGNRP
, /* align `edge' with `edge2' */
2340 SHPIX
, /* shift `edge' by -cur_len */
2342 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2347 SZP1
, /* set zp1 to normal zone 1 */
2358 * Handle the STEM action to align two edges of a stem.
2360 * The code after computing `cur_len' to shift `edge' and `edge2'
2361 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2364 * if cur_len < = 64:
2371 * org_pos = anchor + (edge_orig - anchor_orig);
2372 * org_center = org_pos + org_len / 2;
2374 * cur_pos1 = ROUND(org_center)
2375 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2376 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2377 * if (delta1 < delta2):
2378 * cur_pos1 = cur_pos1 - u_off
2380 * cur_pos1 = cur_pos1 + d_off
2382 * edge = cur_pos1 - cur_len / 2
2385 * org_pos = anchor + (edge_orig - anchor_orig)
2386 * org_center = org_pos + org_len / 2;
2388 * cur_pos1 = ROUND(org_pos)
2389 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2390 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2391 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2393 * if (delta1 < delta2):
2398 * edge2 = edge + cur_len
2400 * in: edge2_is_serif
2402 * edge_point (in twilight zone)
2403 * edge2_point (in twilight zone)
2404 * ... stuff for bci_align_segments (edge) ...
2405 * ... stuff for bci_align_segments (edge2)...
2414 #define sal_u_off sal_temp1
2416 #define sal_d_off sal_temp2
2418 #define sal_org_len sal_temp3
2420 #define sal_edge2 sal_temp3
2422 unsigned char FPGM(bci_action_stem
) [] = {
2430 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2438 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2439 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2441 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2449 bci_compute_stem_width
,
2450 CALL
, /* s: edge2 edge cur_len */
2455 LT
, /* cur_len < 96 */
2460 LTEQ
, /* cur_len <= 64 */
2478 SWAP
, /* s: edge2 cur_len edge */
2483 DUP
, /* s: edge2 cur_len edge edge anchor anchor */
2489 ADD
, /* s: edge2 cur_len edge org_pos */
2496 ADD
, /* s: edge2 cur_len edge org_center */
2501 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2506 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2513 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2520 ABS
, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2522 LT
, /* delta1 < delta2 */
2527 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2533 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2534 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2542 SUB
, /* arg = cur_pos1 - cur_len/2 */
2544 SWAP
, /* s: edge2 cur_len arg edge */
2549 SWAP
, /* s: edge2 cur_len edge arg edge */
2552 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2555 SWAP
, /* s: edge2 cur_len edge */
2559 GC_cur
, /* s: edge2 cur_len edge anchor_pos */
2567 ADD
, /* s: edge2 cur_len edge org_pos */
2576 ADD
, /* s: edge2 cur_len edge org_pos org_center */
2582 CALL
, /* cur_pos1 = ROUND(org_pos) */
2594 SUB
, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2605 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2612 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2618 ABS
, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2619 LT
, /* delta1 < delta2 */
2621 POP
, /* arg = cur_pos1 */
2625 POP
, /* arg = cur_pos2 */
2626 EIF
, /* s: edge2 cur_len edge arg */
2632 SWAP
, /* s: edge2 cur_len edge arg edge */
2635 SHPIX
, /* edge = arg */
2636 EIF
, /* s: edge2 cur_len */
2638 SWAP
, /* s: cur_len edge2 */
2641 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2645 WS
, /* s: cur_len edge2 */
2647 SHPIX
, /* edge2 = edge + cur_len */
2652 SZP1
, /* set zp1 to normal zone 1 */
2658 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2671 * Handle the BLUE action to align an edge with a blue zone.
2674 * edge_point (in twilight zone)
2675 * ... stuff for bci_align_segments (edge) ...
2678 unsigned char FPGM(bci_action_blue
) [] = {
2686 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2688 /* move `edge_point' to `blue_cvt_idx' position; */
2689 /* note that we can't use MIAP since this would modify */
2690 /* the twilight point's original coordinates also */
2694 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2696 GC_cur
, /* s: new_pos edge edge_pos */
2699 SUB
, /* s: edge (new_pos - edge_pos) */
2705 SZP1
, /* set zp1 to normal zone 1 */
2716 * Handle the SERIF action to align a serif with its base.
2718 * in: serif_point (in twilight zone)
2719 * base_point (in twilight zone)
2720 * ... stuff for bci_align_segments (serif) ...
2723 unsigned char FPGM(bci_action_serif
) [] = {
2731 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2738 MINDEX
, /* s: serif serif serif serif base */
2740 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2743 ALIGNRP
, /* align `serif_point' with `base_point' */
2744 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2746 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2751 SZP1
, /* set zp1 to normal zone 1 */
2760 * bci_action_serif_lower_bound
2762 * Handle the SERIF action to align a serif with its base, then moving it
2763 * again if necessary to stay within a lower bound.
2765 * in: serif_point (in twilight zone)
2766 * base_point (in twilight zone)
2767 * edge[-1] (in twilight zone)
2768 * ... stuff for bci_align_segments (serif) ...
2771 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2774 bci_action_serif_lower_bound
,
2779 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2786 MINDEX
, /* s: edge[-1] serif serif serif serif base */
2788 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2791 ALIGNRP
, /* align `serif_point' with `base_point' */
2792 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2794 SWAP
, /* s: serif edge[-1] */
2796 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2801 GC_cur
, /* s: serif edge[-1]_pos serif_pos */
2802 GT
, /* serif_pos < edge[-1]_pos */
2805 ALIGNRP
, /* align `serif' to `edge[-1]' */
2808 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2813 SZP1
, /* set zp1 to normal zone 1 */
2822 * bci_action_serif_upper_bound
2824 * Handle the SERIF action to align a serif with its base, then moving it
2825 * again if necessary to stay within an upper bound.
2827 * in: serif_point (in twilight zone)
2828 * base_point (in twilight zone)
2829 * edge[1] (in twilight zone)
2830 * ... stuff for bci_align_segments (serif) ...
2833 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2836 bci_action_serif_upper_bound
,
2841 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2848 MINDEX
, /* s: edge[1] serif serif serif serif base */
2850 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2853 ALIGNRP
, /* align `serif_point' with `base_point' */
2854 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2856 SWAP
, /* s: serif edge[1] */
2858 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2863 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2864 LT
, /* serif_pos > edge[1]_pos */
2867 ALIGNRP
, /* align `serif' to `edge[1]' */
2870 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2875 SZP1
, /* set zp1 to normal zone 1 */
2884 * bci_action_serif_lower_upper_bound
2886 * Handle the SERIF action to align a serif with its base, then moving it
2887 * again if necessary to stay within a lower and upper bound.
2889 * in: serif_point (in twilight zone)
2890 * base_point (in twilight zone)
2891 * edge[-1] (in twilight zone)
2892 * edge[1] (in twilight zone)
2893 * ... stuff for bci_align_segments (serif) ...
2896 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2899 bci_action_serif_lower_upper_bound
,
2904 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2911 MINDEX
, /* s: edge[1] edge[-1] serif serif serif serif base */
2913 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2916 ALIGNRP
, /* align `serif_point' with `base_point' */
2917 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2919 SWAP
, /* s: edge[1] serif edge[-1] */
2921 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2926 GC_cur
, /* s: edge[1] serif edge[-1]_pos serif_pos */
2927 GT
, /* serif_pos < edge[-1]_pos */
2930 ALIGNRP
, /* align `serif' to `edge[-1]' */
2933 SWAP
, /* s: serif edge[1] */
2935 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2940 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2941 LT
, /* serif_pos > edge[1]_pos */
2944 ALIGNRP
, /* align `serif' to `edge[1]' */
2947 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2952 SZP1
, /* set zp1 to normal zone 1 */
2961 * bci_action_serif_anchor
2963 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2966 * in: edge_point (in twilight zone)
2967 * ... stuff for bci_align_segments (edge) ...
2970 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2973 bci_action_serif_anchor
,
2978 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2984 WS
, /* sal_anchor = edge_point */
2994 CALL
, /* s: edge edge edge_pos round(edge_orig_pos) */
2997 SHPIX
, /* edge = round(edge_orig) */
2999 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3004 SZP1
, /* set zp1 to normal zone 1 */
3013 * bci_action_serif_anchor_lower_bound
3015 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3016 * anchor, then moving it again if necessary to stay within a lower
3019 * in: edge_point (in twilight zone)
3020 * edge[-1] (in twilight zone)
3021 * ... stuff for bci_align_segments (edge) ...
3024 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
3027 bci_action_serif_anchor_lower_bound
,
3032 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3038 WS
, /* sal_anchor = edge_point */
3048 CALL
, /* s: edge[-1] edge edge edge_pos round(edge_orig_pos) */
3051 SHPIX
, /* edge = round(edge_orig) */
3053 SWAP
, /* s: edge edge[-1] */
3055 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3060 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3061 GT
, /* edge_pos < edge[-1]_pos */
3064 ALIGNRP
, /* align `edge' to `edge[-1]' */
3067 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3072 SZP1
, /* set zp1 to normal zone 1 */
3081 * bci_action_serif_anchor_upper_bound
3083 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3084 * anchor, then moving it again if necessary to stay within an upper
3087 * in: edge_point (in twilight zone)
3088 * edge[1] (in twilight zone)
3089 * ... stuff for bci_align_segments (edge) ...
3092 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
3095 bci_action_serif_anchor_upper_bound
,
3100 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3106 WS
, /* sal_anchor = edge_point */
3116 CALL
, /* s: edge[1] edge edge edge_pos round(edge_orig_pos) */
3119 SHPIX
, /* edge = round(edge_orig) */
3121 SWAP
, /* s: edge edge[1] */
3123 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3128 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3129 LT
, /* edge_pos > edge[1]_pos */
3132 ALIGNRP
, /* align `edge' to `edge[1]' */
3135 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3140 SZP1
, /* set zp1 to normal zone 1 */
3149 * bci_action_serif_anchor_lower_upper_bound
3151 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
3152 * anchor, then moving it again if necessary to stay within a lower and
3155 * in: edge_point (in twilight zone)
3156 * edge[-1] (in twilight zone)
3157 * edge[1] (in twilight zone)
3158 * ... stuff for bci_align_segments (edge) ...
3161 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
3164 bci_action_serif_anchor_lower_upper_bound
,
3169 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3175 WS
, /* sal_anchor = edge_point */
3185 CALL
, /* s: edge[1] edge[-1] edge edge edge_pos round(edge_orig_pos) */
3188 SHPIX
, /* edge = round(edge_orig) */
3190 SWAP
, /* s: edge[1] edge edge[-1] */
3192 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3197 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3198 GT
, /* edge_pos < edge[-1]_pos */
3201 ALIGNRP
, /* align `edge' to `edge[-1]' */
3204 SWAP
, /* s: edge edge[1] */
3206 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3211 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3212 LT
, /* edge_pos > edge[1]_pos */
3215 ALIGNRP
, /* align `edge' to `edge[1]' */
3218 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3223 SZP1
, /* set zp1 to normal zone 1 */
3232 * bci_action_serif_link1
3234 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3237 * in: before_point (in twilight zone)
3238 * edge_point (in twilight zone)
3239 * after_point (in twilight zone)
3240 * ... stuff for bci_align_segments (edge) ...
3243 unsigned char FPGM(bci_action_serif_link1
) [] = {
3246 bci_action_serif_link1
,
3251 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3255 CINDEX
, /* s: after edge before after */
3258 CINDEX
, /* s: after edge before after before */
3262 EQ
, /* after_orig_pos == before_orig_pos */
3263 IF
, /* s: after edge before */
3264 MDAP_noround
, /* set rp0 and rp1 to `before' */
3266 ALIGNRP
, /* align `edge' with `before' */
3273 CINDEX
, /* s: ... after edge before edge */
3276 CINDEX
, /* s: ... after edge before edge before */
3277 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3285 CINDEX
, /* s: ... after edge before a*64 after */
3288 CINDEX
, /* s: ... after edge before a*64 after before */
3289 MD_cur
, /* b = after_pos - before_pos */
3290 MUL
, /* s: ... after edge before a*b */
3294 CINDEX
, /* s: ... after edge before a*b after */
3297 CINDEX
, /* s: ... after edge before a*b after before */
3298 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3304 DIV
, /* s: after edge before a*b/c */
3307 MDAP_noround
, /* set rp0 and rp1 to `before' */
3308 SWAP
, /* s: after a*b/c edge */
3311 ALIGNRP
, /* align `edge' with `before' */
3313 SHPIX
, /* shift `edge' by `a*b/c' */
3315 SWAP
, /* s: edge after */
3319 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3324 SZP1
, /* set zp1 to normal zone 1 */
3333 * bci_action_serif_link1_lower_bound
3335 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3336 * before and after. Additionally, move the serif again if necessary to
3337 * stay within a lower bound.
3339 * in: before_point (in twilight zone)
3340 * edge_point (in twilight zone)
3341 * after_point (in twilight zone)
3342 * edge[-1] (in twilight zone)
3343 * ... stuff for bci_align_segments (edge) ...
3346 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3349 bci_action_serif_link1_lower_bound
,
3354 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3358 CINDEX
, /* s: edge[-1] after edge before after */
3361 CINDEX
, /* s: edge[-1] after edge before after before */
3365 EQ
, /* after_orig_pos == before_orig_pos */
3366 IF
, /* s: edge[-1] after edge before */
3367 MDAP_noround
, /* set rp0 and rp1 to `before' */
3369 ALIGNRP
, /* align `edge' with `before' */
3376 CINDEX
, /* s: ... after edge before edge */
3379 CINDEX
, /* s: ... after edge before edge before */
3380 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3388 CINDEX
, /* s: ... after edge before a*64 after */
3391 CINDEX
, /* s: ... after edge before a*64 after before */
3392 MD_cur
, /* b = after_pos - before_pos */
3393 MUL
, /* s: ... after edge before a*b */
3397 CINDEX
, /* s: ... after edge before a*b after */
3400 CINDEX
, /* s: ... after edge before a*b after before */
3401 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3407 DIV
, /* s: edge[-1] after edge before a*b/c */
3410 MDAP_noround
, /* set rp0 and rp1 to `before' */
3411 SWAP
, /* s: edge[-1] after a*b/c edge */
3414 ALIGNRP
, /* align `edge' with `before' */
3416 SHPIX
, /* shift `edge' by `a*b/c' */
3418 SWAP
, /* s: edge[-1] edge after */
3422 SWAP
, /* s: edge edge[-1] */
3424 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3429 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3430 GT
, /* edge_pos < edge[-1]_pos */
3433 ALIGNRP
, /* align `edge' to `edge[-1]' */
3436 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3441 SZP1
, /* set zp1 to normal zone 1 */
3449 * bci_action_serif_link1_upper_bound
3451 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3452 * before and after. Additionally, move the serif again if necessary to
3453 * stay within an upper bound.
3455 * in: before_point (in twilight zone)
3456 * edge_point (in twilight zone)
3457 * after_point (in twilight zone)
3458 * edge[1] (in twilight zone)
3459 * ... stuff for bci_align_segments (edge) ...
3462 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3465 bci_action_serif_link1_upper_bound
,
3470 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3474 CINDEX
, /* s: edge[1] after edge before after */
3477 CINDEX
, /* s: edge[1] after edge before after before */
3481 EQ
, /* after_orig_pos == before_orig_pos */
3482 IF
, /* s: edge[1] after edge before */
3483 MDAP_noround
, /* set rp0 and rp1 to `before' */
3485 ALIGNRP
, /* align `edge' with `before' */
3492 CINDEX
, /* s: ... after edge before edge */
3495 CINDEX
, /* s: ... after edge before edge before */
3496 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3504 CINDEX
, /* s: ... after edge before a*64 after */
3507 CINDEX
, /* s: ... after edge before a*64 after before */
3508 MD_cur
, /* b = after_pos - before_pos */
3509 MUL
, /* s: ... after edge before a*b */
3513 CINDEX
, /* s: ... after edge before a*b after */
3516 CINDEX
, /* s: ... after edge before a*b after before */
3517 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3523 DIV
, /* s: edge[1] after edge before a*b/c */
3526 MDAP_noround
, /* set rp0 and rp1 to `before' */
3527 SWAP
, /* s: edge[1] after a*b/c edge */
3530 ALIGNRP
, /* align `edge' with `before' */
3532 SHPIX
, /* shift `edge' by `a*b/c' */
3534 SWAP
, /* s: edge[1] edge after */
3538 SWAP
, /* s: edge edge[1] */
3540 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3545 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3546 LT
, /* edge_pos > edge[1]_pos */
3549 ALIGNRP
, /* align `edge' to `edge[1]' */
3552 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3557 SZP1
, /* set zp1 to normal zone 1 */
3566 * bci_action_serif_link1_lower_upper_bound
3568 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3569 * before and after. Additionally, move the serif again if necessary to
3570 * stay within a lower and upper bound.
3572 * in: before_point (in twilight zone)
3573 * edge_point (in twilight zone)
3574 * after_point (in twilight zone)
3575 * edge[-1] (in twilight zone)
3576 * edge[1] (in twilight zone)
3577 * ... stuff for bci_align_segments (edge) ...
3580 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3583 bci_action_serif_link1_lower_upper_bound
,
3588 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3592 CINDEX
, /* s: edge[1] edge[-1] after edge before after */
3595 CINDEX
, /* s: edge[1] edge[-1] after edge before after before */
3599 EQ
, /* after_orig_pos == before_orig_pos */
3600 IF
, /* s: edge[1] edge[-1] after edge before */
3601 MDAP_noround
, /* set rp0 and rp1 to `before' */
3603 ALIGNRP
, /* align `edge' with `before' */
3610 CINDEX
, /* s: ... after edge before edge */
3613 CINDEX
, /* s: ... after edge before edge before */
3614 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
3622 CINDEX
, /* s: ... after edge before a*64 after */
3625 CINDEX
, /* s: ... after edge before a*64 after before */
3626 MD_cur
, /* b = after_pos - before_pos */
3627 MUL
, /* s: ... after edge before a*b */
3631 CINDEX
, /* s: ... after edge before a*b after */
3634 CINDEX
, /* s: ... after edge before a*b after_orig before */
3635 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
3641 DIV
, /* s: edge[1] edge[-1] after edge before a*b/c */
3644 MDAP_noround
, /* set rp0 and rp1 to `before' */
3645 SWAP
, /* s: edge[1] edge[-1] after a*b/c edge */
3648 ALIGNRP
, /* align `edge' with `before' */
3650 SHPIX
, /* shift `edge' by `a*b/c' */
3652 SWAP
, /* s: edge[1] edge[-1] edge after */
3656 SWAP
, /* s: edge[1] edge edge[-1] */
3658 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3663 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3664 GT
, /* edge_pos < edge[-1]_pos */
3667 ALIGNRP
, /* align `edge' to `edge[-1]' */
3670 SWAP
, /* s: edge edge[1] */
3672 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3677 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3678 LT
, /* edge_pos > edge[1]_pos */
3681 ALIGNRP
, /* align `edge' to `edge[1]' */
3684 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3689 SZP1
, /* set zp1 to normal zone 1 */
3698 * bci_action_serif_link2
3700 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3702 * in: edge_point (in twilight zone)
3703 * ... stuff for bci_align_segments (edge) ...
3706 unsigned char FPGM(bci_action_serif_link2
) [] = {
3709 bci_action_serif_link2
,
3714 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3716 DUP
, /* s: edge edge */
3720 DUP
, /* s: edge edge anchor anchor */
3721 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3732 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3737 ALIGNRP
, /* align `edge' with `sal_anchor' */
3739 SHPIX
, /* shift `edge' by `delta' */
3741 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3746 SZP1
, /* set zp1 to normal zone 1 */
3755 * bci_action_serif_link2_lower_bound
3757 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3758 * Additionally, move the serif again if necessary to stay within a lower
3761 * in: edge_point (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_bound
) [] = {
3769 bci_action_serif_link2_lower_bound
,
3774 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3776 DUP
, /* s: edge[-1] edge edge */
3780 DUP
, /* s: edge[-1] edge edge anchor anchor */
3781 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3792 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3797 ALIGNRP
, /* align `edge' with `sal_anchor' */
3799 SHPIX
, /* shift `edge' by `delta' */
3801 SWAP
, /* s: edge edge[-1] */
3803 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3808 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3809 GT
, /* edge_pos < edge[-1]_pos */
3812 ALIGNRP
, /* align `edge' to `edge[-1]' */
3815 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3820 SZP1
, /* set zp1 to normal zone 1 */
3829 * bci_action_serif_link2_upper_bound
3831 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3832 * Additionally, move the serif again if necessary to stay within an upper
3835 * in: edge_point (in twilight zone)
3836 * edge[1] (in twilight zone)
3837 * ... stuff for bci_align_segments (edge) ...
3840 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3843 bci_action_serif_link2_upper_bound
,
3848 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3850 DUP
, /* s: edge[1] edge edge */
3854 DUP
, /* s: edge[1] edge edge anchor anchor */
3855 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3866 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3871 ALIGNRP
, /* align `edge' with `sal_anchor' */
3873 SHPIX
, /* shift `edge' by `delta' */
3875 SWAP
, /* s: edge edge[1] */
3877 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3882 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3883 LT
, /* edge_pos > edge[1]_pos */
3886 ALIGNRP
, /* align `edge' to `edge[1]' */
3889 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3894 SZP1
, /* set zp1 to normal zone 1 */
3903 * bci_action_serif_link2_lower_upper_bound
3905 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3906 * Additionally, move the serif again if necessary to stay within a lower
3909 * in: edge_point (in twilight zone)
3910 * edge[-1] (in twilight zone)
3911 * edge[1] (in twilight zone)
3912 * ... stuff for bci_align_segments (edge) ...
3915 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3918 bci_action_serif_link2_lower_upper_bound
,
3923 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3925 DUP
, /* s: edge[1] edge[-1] edge edge */
3929 DUP
, /* s: edge[1] edge[-1] edge edge anchor anchor */
3930 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3941 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3946 ALIGNRP
, /* align `edge' with `sal_anchor' */
3948 SHPIX
, /* shift `edge' by `delta' */
3950 SWAP
, /* s: edge[1] edge edge[-1] */
3952 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3957 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3958 GT
, /* edge_pos < edge[-1]_pos */
3961 ALIGNRP
, /* align `edge' to `edge[-1]' */
3964 SWAP
, /* s: edge edge[1] */
3966 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3971 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3972 LT
, /* edge_pos > edge[1]_pos */
3975 ALIGNRP
, /* align `edge' to `edge[1]' */
3978 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3983 SZP1
, /* set zp1 to normal zone 1 */
3996 * in: function_index
3999 unsigned char FPGM(bci_handle_action
) [] = {
4015 * This is the top-level glyph hinting function
4016 * which parses the arguments on the stack and calls subroutines.
4018 * in: num_actions (M)
4027 * uses: bci_handle_action
4029 * bci_action_ip_before
4030 * bci_action_ip_after
4032 * bci_action_ip_between
4034 * bci_action_adjust_bound
4035 * bci_action_stem_bound
4039 * bci_action_blue_anchor
4045 * bci_action_serif_lower_bound
4046 * bci_action_serif_upper_bound
4047 * bci_action_serif_lower_upper_bound
4049 * bci_action_serif_anchor
4050 * bci_action_serif_anchor_lower_bound
4051 * bci_action_serif_anchor_upper_bound
4052 * bci_action_serif_anchor_lower_upper_bound
4054 * bci_action_serif_link1
4055 * bci_action_serif_link1_lower_bound
4056 * bci_action_serif_link1_upper_bound
4057 * bci_action_serif_link1_lower_upper_bound
4059 * bci_action_serif_link2
4060 * bci_action_serif_link2_lower_bound
4061 * bci_action_serif_link2_upper_bound
4062 * bci_action_serif_link2_lower_upper_bound
4065 unsigned char FPGM(bci_hint_glyph
) [] = {
4077 SZP2
, /* set zp2 to normal zone 1 */
4085 #define COPY_FPGM(func_name) \
4086 memcpy(buf_p, fpgm_ ## func_name, \
4087 sizeof (fpgm_ ## func_name)); \
4088 buf_p += sizeof (fpgm_ ## func_name) \
4091 TA_table_build_fpgm(FT_Byte
** fpgm
,
4101 buf_len
= sizeof (FPGM(bci_round
))
4102 + sizeof (FPGM(bci_compute_stem_width_a
))
4104 + sizeof (FPGM(bci_compute_stem_width_b
))
4106 + sizeof (FPGM(bci_compute_stem_width_c
))
4107 + sizeof (FPGM(bci_loop
))
4108 + sizeof (FPGM(bci_cvt_rescale
))
4109 + sizeof (FPGM(bci_blue_round_a
))
4111 + sizeof (FPGM(bci_blue_round_b
))
4112 + sizeof (FPGM(bci_get_point_extrema
))
4114 + sizeof (FPGM(bci_create_segment
))
4115 + sizeof (FPGM(bci_create_segments
))
4116 + sizeof (FPGM(bci_align_segment
))
4117 + sizeof (FPGM(bci_align_segments
))
4119 + sizeof (FPGM(bci_scale_contour
))
4120 + sizeof (FPGM(bci_scale_glyph
))
4121 + sizeof (FPGM(bci_shift_contour
))
4122 + sizeof (FPGM(bci_shift_subglyph
))
4124 + sizeof (FPGM(bci_ip_outer_align_point
))
4125 + sizeof (FPGM(bci_ip_on_align_points
))
4126 + sizeof (FPGM(bci_ip_between_align_point
))
4127 + sizeof (FPGM(bci_ip_between_align_points
))
4129 + sizeof (FPGM(bci_action_ip_before
))
4130 + sizeof (FPGM(bci_action_ip_after
))
4131 + sizeof (FPGM(bci_action_ip_on
))
4132 + sizeof (FPGM(bci_action_ip_between
))
4134 + sizeof (FPGM(bci_action_adjust_bound
))
4135 + sizeof (FPGM(bci_action_stem_bound
))
4136 + sizeof (FPGM(bci_action_link
))
4137 + sizeof (FPGM(bci_action_anchor
))
4138 + sizeof (FPGM(bci_action_blue_anchor
))
4139 + sizeof (FPGM(bci_action_adjust
))
4140 + sizeof (FPGM(bci_action_stem
))
4141 + sizeof (FPGM(bci_action_blue
))
4142 + sizeof (FPGM(bci_action_serif
))
4143 + sizeof (FPGM(bci_action_serif_lower_bound
))
4144 + sizeof (FPGM(bci_action_serif_upper_bound
))
4145 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
4146 + sizeof (FPGM(bci_action_serif_anchor
))
4147 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
4148 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
4149 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
4150 + sizeof (FPGM(bci_action_serif_link1
))
4151 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
4152 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
4153 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
4154 + sizeof (FPGM(bci_action_serif_link2
))
4155 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
4156 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
4157 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
4159 + sizeof (FPGM(bci_handle_action
))
4160 + sizeof (FPGM(bci_hint_glyph
));
4161 /* buffer length must be a multiple of four */
4162 len
= (buf_len
+ 3) & ~3;
4163 buf
= (FT_Byte
*)malloc(len
);
4165 return FT_Err_Out_Of_Memory
;
4167 /* pad end of buffer with zeros */
4168 buf
[len
- 1] = 0x00;
4169 buf
[len
- 2] = 0x00;
4170 buf
[len
- 3] = 0x00;
4172 /* copy font program into buffer and fill in the missing variables */
4175 COPY_FPGM(bci_round
);
4176 COPY_FPGM(bci_compute_stem_width_a
);
4177 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4178 COPY_FPGM(bci_compute_stem_width_b
);
4179 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4180 COPY_FPGM(bci_compute_stem_width_c
);
4181 COPY_FPGM(bci_loop
);
4182 COPY_FPGM(bci_cvt_rescale
);
4183 COPY_FPGM(bci_blue_round_a
);
4184 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
4185 COPY_FPGM(bci_blue_round_b
);
4186 COPY_FPGM(bci_get_point_extrema
);
4188 COPY_FPGM(bci_create_segment
);
4189 COPY_FPGM(bci_create_segments
);
4190 COPY_FPGM(bci_align_segment
);
4191 COPY_FPGM(bci_align_segments
);
4193 COPY_FPGM(bci_scale_contour
);
4194 COPY_FPGM(bci_scale_glyph
);
4195 COPY_FPGM(bci_shift_contour
);
4196 COPY_FPGM(bci_shift_subglyph
);
4198 COPY_FPGM(bci_ip_outer_align_point
);
4199 COPY_FPGM(bci_ip_on_align_points
);
4200 COPY_FPGM(bci_ip_between_align_point
);
4201 COPY_FPGM(bci_ip_between_align_points
);
4203 COPY_FPGM(bci_action_ip_before
);
4204 COPY_FPGM(bci_action_ip_after
);
4205 COPY_FPGM(bci_action_ip_on
);
4206 COPY_FPGM(bci_action_ip_between
);
4208 COPY_FPGM(bci_action_adjust_bound
);
4209 COPY_FPGM(bci_action_stem_bound
);
4210 COPY_FPGM(bci_action_link
);
4211 COPY_FPGM(bci_action_anchor
);
4212 COPY_FPGM(bci_action_blue_anchor
);
4213 COPY_FPGM(bci_action_adjust
);
4214 COPY_FPGM(bci_action_stem
);
4215 COPY_FPGM(bci_action_blue
);
4216 COPY_FPGM(bci_action_serif
);
4217 COPY_FPGM(bci_action_serif_lower_bound
);
4218 COPY_FPGM(bci_action_serif_upper_bound
);
4219 COPY_FPGM(bci_action_serif_lower_upper_bound
);
4220 COPY_FPGM(bci_action_serif_anchor
);
4221 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
4222 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
4223 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
4224 COPY_FPGM(bci_action_serif_link1
);
4225 COPY_FPGM(bci_action_serif_link1_lower_bound
);
4226 COPY_FPGM(bci_action_serif_link1_upper_bound
);
4227 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
4228 COPY_FPGM(bci_action_serif_link2
);
4229 COPY_FPGM(bci_action_serif_link2_lower_bound
);
4230 COPY_FPGM(bci_action_serif_link2_upper_bound
);
4231 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
4233 COPY_FPGM(bci_handle_action
);
4234 COPY_FPGM(bci_hint_glyph
);
4237 *fpgm_len
= buf_len
;
4244 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
4253 error
= TA_sfnt_add_table_info(sfnt
);
4257 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
4261 if (fpgm_len
> sfnt
->max_instructions
)
4262 sfnt
->max_instructions
= fpgm_len
;
4264 /* in case of success, `fpgm_buf' gets linked */
4265 /* and is eventually freed in `TA_font_unload' */
4266 error
= TA_font_add_table(font
,
4267 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
4268 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
4278 /* end of tafpgm.c */