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 /* a convenience shorthand for scaling; see `bci_cvt_rescale' for details */
57 MUL, /* delta * 2^10 */ \
65 /* in the comments below, the top of the stack (`s:') */
66 /* is the rightmost element; the stack is shown */
67 /* after the instruction on the same line has been executed */
73 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
74 * engine specific corrections are applied.
80 unsigned char FPGM(bci_round
) [] = {
106 * bci_compute_stem_width
108 * This is the equivalent to the following code from function
109 * `ta_latin_compute_stem_width':
117 * else if base_is_round:
123 * delta = ABS(dist - std_width)
134 * delta = delta - dist
137 * dist = dist + delta
138 * else if delta < 32:
140 * else if delta < 54:
143 * dist = dist + delta
159 * CVT: cvtl_is_extra_light
163 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
166 bci_compute_stem_width
,
170 ABS
, /* s: base_is_round stem_is_serif width dist */
175 LT
, /* dist < 3*64 */
179 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
180 AND
, /* stem_is_serif && dist < 3*64 */
185 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
187 IF
, /* s: base_is_round width dist */
193 ROLL
, /* s: width dist base_is_round */
194 IF
, /* s: width dist */
199 IF
, /* s: width dist */
210 IF
, /* s: width dist */
217 DUP
, /* s: width dist dist */
222 /* %c, index of std_width */
224 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
228 ABS
, /* s: width dist delta */
233 IF
, /* s: width dist */
239 /* %c, index of std_width */
241 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
243 RCVT
, /* dist = std_width */
255 DUP
, /* s: width dist dist */
258 LT
, /* dist < 3*64 */
260 DUP
, /* s: width delta dist */
261 FLOOR
, /* dist = FLOOR(dist) */
262 DUP
, /* s: width delta dist dist */
264 ROLL
, /* s: width dist delta dist */
265 SUB
, /* delta = delta - dist */
267 DUP
, /* s: width dist delta delta */
271 IF
, /* s: width dist delta */
272 ADD
, /* dist = dist + delta */
283 ADD
, /* dist = dist + 10 */
294 ADD
, /* dist = dist + 54 */
297 ADD
, /* dist = dist + delta */
306 CALL
, /* dist = round(dist) */
311 SWAP
, /* s: dist width */
316 NEG
, /* dist = -dist */
328 * Take a range and a function number and apply the function to all
329 * elements of the range.
335 * sal: sal_i (counter initialized with `start')
337 * sal_func (`func_num')
340 unsigned char FPGM(bci_loop
) [] = {
349 WS
, /* sal_func = func_num */
353 WS
, /* sal_limit = end */
357 WS
, /* sal_i = start */
366 LTEQ
, /* start <= end */
377 ADD
, /* start = start + 1 */
383 JMPR
, /* goto start_loop */
394 * Rescale CVT value by `cvtl_scale' (in 16.16 format).
396 * The scaling factor `cvtl_scale' isn't stored as `b/c' but as `(b-c)/c';
397 * consequently, the calculation `a * b/c' is done as `a + delta' with
398 * `delta = a * (b-c)/c'. This avoids overflow.
400 * sal: sal_i (CVT index)
406 unsigned char FPGM(bci_cvt_rescale
) [] = {
428 * Round a blue ref value and adjust its corresponding shoot value.
430 * sal: sal_i (CVT index)
434 unsigned char FPGM(bci_blue_round_a
) [] = {
444 RCVT
, /* s: ref_idx ref */
450 SWAP
, /* s: ref_idx round(ref) ref */
458 unsigned char FPGM(bci_blue_round_b
) [] = {
462 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
464 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
466 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
468 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
470 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
495 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
500 NEG
, /* delta = -delta */
507 SUB
, /* s: ref_idx round(ref) shoot_idx (round(ref) - delta) */
518 * bci_get_point_extrema
520 * An auxiliary function for `bci_create_segment'.
529 unsigned char FPGM(bci_get_point_extrema
) [] = {
532 bci_get_point_extrema
,
541 /* check whether `point' is a new minimum */
544 RS
, /* s: point point point point_min */
546 /* if distance is negative, we have a new minimum */
550 IF
, /* s: point point */
558 /* check whether `point' is a new maximum */
561 RS
, /* s: point point point_max */
563 /* if distance is positive, we have a new maximum */
583 * Store start and end point of a segment in the storage area,
584 * then construct a point in the twilight zone to represent it.
586 * This function is used by `bci_create_segment_points'.
590 * [last (if wrap-around segment)]
591 * [first (if wrap-around segment)]
593 * uses: bci_get_point_extrema
595 * sal: sal_i (start of current segment)
596 * sal_j (current twilight point)
605 unsigned char FPGM(bci_create_segment
) [] = {
617 WS
, /* sal[sal_i] = start */
619 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
625 ADD
, /* sal_i = sal_i + 1 */
628 /* initialize inner loop(s) */
633 WS
, /* sal_point_min = start */
638 WS
, /* sal_point_max = start */
642 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
648 CINDEX
, /* s: start end end start */
649 LT
, /* start > end */
651 /* we have a wrap-around segment with two more arguments */
652 /* to give the last and first point of the contour, respectively; */
653 /* our job is to store a segment `start'-`last', */
654 /* and to get extrema for the two segments */
655 /* `start'-`last' and `first'-`end' */
657 /* s: first last start end */
664 WS
, /* sal[sal_i] = last */
667 ROLL
, /* s: first end last start */
670 SWAP
, /* s: first end start last start */
671 SUB
, /* s: first end start loop_count */
674 bci_get_point_extrema
,
679 SWAP
, /* s: end first */
684 ROLL
, /* s: (first - 1) (first - 1) end */
686 SUB
, /* s: (first - 1) loop_count */
689 bci_get_point_extrema
,
694 ELSE
, /* s: start end */
701 WS
, /* sal[sal_i] = end */
706 SUB
, /* s: start loop_count */
709 bci_get_point_extrema
,
715 /* the twilight point representing a segment */
716 /* is in the middle between the minimum and maximum */
728 DIV
, /* s: middle_pos */
730 DO_SCALE
, /* middle_pos = middle_pos * scale */
732 /* write it to temporary CVT location */
736 SZP0
, /* set zp0 to twilight zone 0 */
740 /* create twilight point with index `sal_j' */
753 ADD
, /* twilight_point = twilight_point + 1 */
762 * bci_create_segments
764 * Set up segments by defining point ranges which defines them
765 * and computing twilight points to represent them.
767 * in: num_segments (N)
770 * [contour_last 0 (if wrap-around segment)]
771 * [contour_first 0 (if wrap-around segment)]
774 * [contour_last 0 (if wrap-around segment)]
775 * [contour_first 0 (if wrap-around segment)]
777 * segment_start_(N-1)
779 * [contour_last (N-1) (if wrap-around segment)]
780 * [contour_first (N-1) (if wrap-around segment)]
782 * uses: bci_create_segment
784 * sal: sal_i (start of current segment)
785 * sal_j (current twilight point)
788 unsigned char FPGM(bci_create_segments
) [] = {
794 /* all our measurements are taken along the y axis */
801 SUB
, /* delta = (2*num_segments - 1) */
809 WS
, /* sal_j = 0 (point offset) */
812 ADD
, /* s: ... sal_segment_offset (sal_segment_offset + delta) */
814 /* `bci_create_segment_point' also increases the loop counter by 1; */
815 /* this effectively means we have a loop step of 2 */
829 * Align all points in a segment to the twilight point in rp0.
830 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
835 unsigned char FPGM(bci_align_segment
) [] = {
841 /* we need the values of `sal_segment_offset + 2*segment_index' */
842 /* and `sal_segment_offset + 2*segment_index + 1' */
854 RS
, /* s: first last */
859 CINDEX
, /* s: first last first */
862 CINDEX
, /* s: first last first last */
863 LTEQ
, /* first <= end */
864 IF
, /* s: first last */
866 DUP
, /* s: last first first */
867 ALIGNRP
, /* align point with index `first' with rp0 */
871 ADD
, /* first = first + 1 */
872 SWAP
, /* s: first last */
877 JMPR
, /* goto start_loop */
892 * Align segments to the twilight point in rp0.
893 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
902 * uses: handle_segment
906 unsigned char FPGM(bci_align_segments
) [] = {
928 * Scale a contour using two points giving the maximum and minimum
931 * It expects that no point on the contour is touched.
940 unsigned char FPGM(bci_scale_contour
) [] = {
950 DO_SCALE
, /* min_pos_new = min_pos * scale */
955 /* don't scale a single-point contour twice */
964 DO_SCALE
, /* max_pos_new = max_pos * scale */
981 * Scale a glyph using a list of points (two points per contour, giving
982 * the maximum and mininum coordinates).
984 * It expects that no point in the glyph is touched.
986 * in: num_contours (N)
995 * uses: bci_scale_contour
998 unsigned char FPGM(bci_scale_glyph
) [] = {
1008 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
1016 SZP2
, /* set zp2 to normal zone 1 */
1027 * Shift a contour by a given amount.
1029 * It expects that rp1 (pointed to by zp0) is set up properly; zp2 must
1030 * point to the normal zone 1.
1036 unsigned char FPGM(bci_shift_contour
) [] = {
1043 SHC_rp1
, /* shift `contour' by (rp1_pos - rp1_orig_pos) */
1055 * bci_shift_subglyph
1057 * Shift a subglyph. To be more specific, it corrects the already applied
1058 * subglyph offset (if any) from the `glyf' table which needs to be scaled
1061 * If this function is called, a point `x' in the subglyph has been scaled
1062 * already (during the hinting of the subglyph itself), and `offset' has
1063 * been applied also:
1065 * x -> x * scale + offset (1)
1067 * However, the offset should be applied first, then the scaling:
1069 * x -> (x + offset) * scale (2)
1071 * Our job is now to transform (1) to (2); a simple calculation shows that
1072 * we have to shift all points of the subglyph by
1074 * offset * scale - offset = offset * (scale - 1)
1076 * Note that `cvtl_scale' is equal to the above `scale - 1'.
1078 * in: offset (in FUnits)
1082 * CVT: cvtl_funits_to_pixels
1087 unsigned char FPGM(bci_shift_subglyph
) [] = {
1096 cvtl_funits_to_pixels
,
1097 RCVT
, /* scaling factor FUnits -> pixels */
1104 /* the autohinter always rounds offsets */
1107 CALL
, /* offset = round(offset) */
1116 DIV
, /* delta = offset * (scale - 1) */
1118 /* and round again */
1121 CALL
, /* offset = round(offset) */
1125 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1127 /* we create twilight point 0 as a reference point, */
1128 /* setting the original position to zero (using `cvtl_temp') */
1136 MIAP_noround
, /* rp0 and rp1 now point to twilight point 0 */
1138 SWAP
, /* s: first_contour num_contours 0 delta */
1139 SHPIX
, /* rp1_pos - rp1_orig_pos = delta */
1144 SZP2
, /* set zp2 to normal zone 1 */
1153 * bci_ip_outer_align_point
1155 * Auxiliary function for `bci_action_ip_before' and
1156 * `bci_action_ip_after'.
1158 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1159 * zone, and both zp1 and zp2 set to normal zone.
1163 * sal: sal_i (edge_orig_pos)
1169 unsigned char FPGM(bci_ip_outer_align_point
) [] = {
1172 bci_ip_outer_align_point
,
1176 ALIGNRP
, /* align `point' with `edge' */
1179 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1184 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1193 * bci_ip_on_align_points
1195 * Auxiliary function for `bci_action_ip_on'.
1197 * in: edge (in twilight zone)
1205 unsigned char FPGM(bci_ip_on_align_points
) [] = {
1208 bci_ip_on_align_points
,
1211 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1222 * bci_ip_between_align_point
1224 * Auxiliary function for `bci_ip_between_align_points'.
1226 * It expects rp0 to contain the edge for alignment, zp0 set to twilight
1227 * zone, and both zp1 and zp2 set to normal zone.
1231 * sal: sal_i (edge_orig_pos)
1232 * sal_j (stretch_factor)
1238 unsigned char FPGM(bci_ip_between_align_point
) [] = {
1241 bci_ip_between_align_point
,
1245 ALIGNRP
, /* align `point' with `edge' */
1248 DO_SCALE
, /* point_orig_pos = point_orig_pos * scale */
1253 SUB
, /* s: point (point_orig_pos - edge_orig_pos) */
1257 MUL
, /* s: point delta */
1266 * bci_ip_between_align_points
1268 * Auxiliary function for `bci_action_ip_between'.
1270 * in: after_edge (in twilight zone)
1271 * before_edge (in twilight zone)
1278 * sal: sal_i (before_orig_pos)
1279 * sal_j (stretch_factor)
1281 * uses: bci_ip_between_align_point
1284 unsigned char FPGM(bci_ip_between_align_points
) [] = {
1287 bci_ip_between_align_points
,
1293 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1295 DUP
, /* s: ... before after before before */
1296 MDAP_noround
, /* set rp0 and rp1 to `before' */
1298 GC_orig
, /* s: ... before after before before_orig_pos */
1302 WS
, /* sal_i = before_orig_pos */
1305 CINDEX
, /* s: ... before after before after */
1306 MD_cur
, /* b = after_pos - before_pos */
1309 MD_orig_ZP2_0
, /* a = after_orig_pos - before_orig_pos */
1314 WS
, /* sal_j = stretch_factor */
1317 bci_ip_between_align_point
,
1320 SZP2
, /* set zp2 to normal zone 1 */
1321 SZP1
, /* set zp1 to normal zone 1 */
1330 * bci_action_ip_before
1332 * Handle `ip_before' data to align points located before the first edge.
1334 * in: first_edge (in twilight zone)
1341 * sal: sal_i (first_edge_orig_pos)
1343 * uses: bci_ip_outer_align_point
1346 unsigned char FPGM(bci_action_ip_before
) [] = {
1349 bci_action_ip_before
,
1354 SZP2
, /* set zp2 to twilight zone 0 */
1361 WS
, /* sal_i = first_edge_orig_pos */
1367 SZP2
, /* set zp2 to normal zone 1 */
1368 SZP1
, /* set zp1 to normal zone 1 */
1369 SZP0
, /* set zp0 to twilight zone 0 */
1371 MDAP_noround
, /* set rp0 and rp1 to `first_edge' */
1374 bci_ip_outer_align_point
,
1383 * bci_action_ip_after
1385 * Handle `ip_after' data to align points located after the last edge.
1387 * in: last_edge (in twilight zone)
1394 * sal: sal_i (last_edge_orig_pos)
1396 * uses: bci_ip_outer_align_point
1399 unsigned char FPGM(bci_action_ip_after
) [] = {
1402 bci_action_ip_after
,
1407 SZP2
, /* set zp2 to twilight zone 0 */
1414 WS
, /* sal_i = last_edge_orig_pos */
1420 SZP2
, /* set zp2 to normal zone 1 */
1421 SZP1
, /* set zp1 to normal zone 1 */
1422 SZP0
, /* set zp0 to twilight zone 0 */
1424 MDAP_noround
, /* set rp0 and rp1 to `last_edge' */
1427 bci_ip_outer_align_point
,
1438 * Handle `ip_on' data to align points located on an edge coordinate (but
1439 * not part of an edge).
1441 * in: loop_counter (M)
1442 * edge_1 (in twilight zone)
1443 * loop_counter (N_1)
1448 * edge_2 (in twilight zone)
1449 * loop_counter (N_2)
1455 * edge_M (in twilight zone)
1456 * loop_counter (N_M)
1462 * uses: bci_ip_on_align_points
1465 unsigned char FPGM(bci_action_ip_on
) [] = {
1474 SZP1
, /* set zp1 to normal zone 1 */
1475 SZP0
, /* set zp0 to twilight zone 0 */
1478 bci_ip_on_align_points
,
1487 * bci_action_ip_between
1489 * Handle `ip_between' data to align points located between two edges.
1491 * in: loop_counter (M)
1492 * before_edge_1 (in twilight zone)
1493 * after_edge_1 (in twilight zone)
1494 * loop_counter (N_1)
1499 * before_edge_2 (in twilight zone)
1500 * after_edge_2 (in twilight zone)
1501 * loop_counter (N_2)
1507 * before_edge_M (in twilight zone)
1508 * after_edge_M (in twilight zone)
1509 * loop_counter (N_M)
1515 * uses: bci_ip_between_align_points
1518 unsigned char FPGM(bci_action_ip_between
) [] = {
1521 bci_action_ip_between
,
1525 bci_ip_between_align_points
,
1534 * bci_action_adjust_common
1536 * Common code for bci_action_adjust routines.
1539 unsigned char FPGM(bci_action_adjust_common
) [] = {
1542 bci_action_adjust_common
,
1547 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1551 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 */
1554 CINDEX
, /* s: [...] edge2 edge is_round is_serif edge2 edge */
1555 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1558 bci_compute_stem_width
,
1560 NEG
, /* s: [...] edge2 edge -cur_len */
1562 ROLL
, /* s: [...] edge -cur_len edge2 */
1563 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1566 DUP
, /* s: [...] -cur_len edge edge edge */
1567 ALIGNRP
, /* align `edge' with `edge2' */
1569 SHPIX
, /* shift `edge' by -cur_len */
1577 * bci_action_adjust_bound
1579 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1580 * edge of the stem has already been moved, then moving it again if
1581 * necessary to stay bound.
1583 * in: edge2_is_serif
1585 * edge_point (in twilight zone)
1586 * edge2_point (in twilight zone)
1587 * edge[-1] (in twilight zone)
1588 * ... stuff for bci_align_segments (edge) ...
1590 * uses: bci_action_adjust_common
1593 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1596 bci_action_adjust_bound
,
1600 bci_action_adjust_common
,
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 */
1633 * Handle the ADJUST action to align an edge of a stem if the other edge
1634 * of the stem has already been moved.
1636 * in: edge2_is_serif
1638 * edge_point (in twilight zone)
1639 * edge2_point (in twilight zone)
1640 * ... stuff for bci_align_segments (edge) ...
1642 * uses: bci_action_adjust_common
1645 unsigned char FPGM(bci_action_adjust
) [] = {
1652 bci_action_adjust_common
,
1655 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1660 SZP1
, /* set zp1 to normal zone 1 */
1669 * bci_action_stem_common
1671 * Common code for bci_action_stem routines.
1675 #define sal_u_off sal_temp1
1677 #define sal_d_off sal_temp2
1679 #define sal_org_len sal_temp3
1681 #define sal_edge2 sal_temp3
1683 unsigned char FPGM(bci_action_stem_common
) [] = {
1686 bci_action_stem_common
,
1691 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1699 DUP
, /* s: [...] edge2 edge is_round is_serif edge2 edge edge */
1700 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1702 MD_orig_ZP2_0
, /* s: [...] edge2 edge is_round is_serif org_len */
1710 bci_compute_stem_width
,
1711 CALL
, /* s: [...] edge2 edge cur_len */
1716 LT
, /* cur_len < 96 */
1721 LTEQ
, /* cur_len <= 64 */
1739 SWAP
, /* s: [...] edge2 cur_len edge */
1744 DUP
, /* s: [...] edge2 cur_len edge edge anchor anchor */
1750 ADD
, /* s: [...] edge2 cur_len edge org_pos */
1757 ADD
, /* s: [...] edge2 cur_len edge org_center */
1762 CALL
, /* s: [...] edge2 cur_len edge org_center cur_pos1 */
1767 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1774 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1781 ABS
, /* s: [...] edge2 cur_len edge cur_pos1 delta1 delta2 */
1783 LT
, /* delta1 < delta2 */
1788 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1794 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1795 EIF
, /* s: [...] edge2 cur_len edge cur_pos1 */
1803 SUB
, /* arg = cur_pos1 - cur_len/2 */
1805 SWAP
, /* s: [...] edge2 cur_len arg edge */
1811 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
1814 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1817 SWAP
, /* s: [...] edge2 cur_len edge */
1821 GC_cur
, /* s: [...] edge2 cur_len edge anchor_pos */
1829 ADD
, /* s: [...] edge2 cur_len edge org_pos */
1838 ADD
, /* s: [...] edge2 cur_len edge org_pos org_center */
1844 CALL
, /* cur_pos1 = ROUND(org_pos) */
1856 SUB
, /* s: [...] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1867 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1874 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1880 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1881 LT
, /* delta1 < delta2 */
1883 POP
, /* arg = cur_pos1 */
1887 POP
, /* arg = cur_pos2 */
1888 EIF
, /* s: [...] edge2 cur_len edge arg */
1895 SWAP
, /* s: [...] edge2 cur_len edge edge arg edge */
1898 SHPIX
, /* edge = arg */
1899 EIF
, /* s: [...] edge2 cur_len edge */
1907 * bci_action_stem_bound
1909 * Handle the STEM action to align two edges of a stem, then moving one
1910 * edge again if necessary to stay bound.
1912 * The code after computing `cur_len' to shift `edge' and `edge2'
1913 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1916 * if cur_len < = 64:
1923 * org_pos = anchor + (edge_orig - anchor_orig);
1924 * org_center = org_pos + org_len / 2;
1926 * cur_pos1 = ROUND(org_center)
1927 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1928 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1929 * if (delta1 < delta2):
1930 * cur_pos1 = cur_pos1 - u_off
1932 * cur_pos1 = cur_pos1 + d_off
1934 * edge = cur_pos1 - cur_len / 2
1937 * org_pos = anchor + (edge_orig - anchor_orig)
1938 * org_center = org_pos + org_len / 2;
1940 * cur_pos1 = ROUND(org_pos)
1941 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1942 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1943 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1945 * if (delta1 < delta2):
1950 * edge2 = edge + cur_len
1952 * in: edge2_is_serif
1954 * edge_point (in twilight zone)
1955 * edge2_point (in twilight zone)
1956 * edge[-1] (in twilight zone)
1957 * ... stuff for bci_align_segments (edge) ...
1958 * ... stuff for bci_align_segments (edge2)...
1965 * uses: bci_action_stem_common
1968 unsigned char FPGM(bci_action_stem_bound
) [] = {
1971 bci_action_stem_bound
,
1975 bci_action_stem_common
,
1978 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1981 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1985 WS
, /* s: edge[-1] cur_len edge edge2 */
1987 SHPIX
, /* edge2 = edge + cur_len */
1989 SWAP
, /* s: edge edge[-1] */
1991 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1996 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1997 GT
, /* edge_pos < edge[-1]_pos */
2000 ALIGNRP
, /* align `edge' to `edge[-1]' */
2003 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2008 SZP1
, /* set zp1 to normal zone 1 */
2014 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2028 * Handle the STEM action to align two edges of a stem.
2030 * See `bci_action_stem_bound' for more details.
2032 * in: edge2_is_serif
2034 * edge_point (in twilight zone)
2035 * edge2_point (in twilight zone)
2036 * ... stuff for bci_align_segments (edge) ...
2037 * ... stuff for bci_align_segments (edge2)...
2044 * uses: bci_action_stem_common
2047 unsigned char FPGM(bci_action_stem
) [] = {
2054 bci_action_stem_common
,
2058 SWAP
, /* s: cur_len edge2 */
2061 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2065 WS
, /* s: cur_len edge2 */
2067 SHPIX
, /* edge2 = edge + cur_len */
2072 SZP1
, /* set zp1 to normal zone 1 */
2078 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2091 * Handle the LINK action to link an edge to another one.
2095 * base_point (in twilight zone)
2096 * stem_point (in twilight zone)
2097 * ... stuff for bci_align_segments (base) ...
2100 unsigned char FPGM(bci_action_link
) [] = {
2108 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2116 DUP
, /* s: stem is_round is_serif stem base base */
2117 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
2119 MD_orig_ZP2_0
, /* s: stem is_round is_serif dist_orig */
2122 bci_compute_stem_width
,
2123 CALL
, /* s: stem new_dist */
2127 ALIGNRP
, /* align `stem_point' with `base_point' */
2129 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
2131 SHPIX
, /* stem_point = base_point + new_dist */
2136 SZP1
, /* set zp1 to normal zone 1 */
2147 * Handle the ANCHOR action to align two edges
2148 * and to set the edge anchor.
2150 * The code after computing `cur_len' to shift `edge' and `edge2'
2151 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2154 * if cur_len < = 64:
2161 * org_center = edge_orig + org_len / 2
2162 * cur_pos1 = ROUND(org_center)
2164 * error1 = ABS(org_center - (cur_pos1 - u_off))
2165 * error2 = ABS(org_center - (cur_pos1 + d_off))
2166 * if (error1 < error2):
2167 * cur_pos1 = cur_pos1 - u_off
2169 * cur_pos1 = cur_pos1 + d_off
2171 * edge = cur_pos1 - cur_len / 2
2172 * edge2 = edge + cur_len
2175 * edge = ROUND(edge_orig)
2177 * in: edge2_is_serif
2179 * edge_point (in twilight zone)
2180 * edge2_point (in twilight zone)
2181 * ... stuff for bci_align_segments (edge) ...
2190 #define sal_u_off sal_temp1
2192 #define sal_d_off sal_temp2
2194 #define sal_org_len sal_temp3
2196 unsigned char FPGM(bci_action_anchor
) [] = {
2202 /* store anchor point number in `sal_anchor' */
2207 WS
, /* sal_anchor = edge_point */
2211 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2219 DUP
, /* s: edge2 edge is_round is_serif edge2 edge edge */
2220 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2222 MD_orig_ZP2_0
, /* s: edge2 edge is_round is_serif org_len */
2230 bci_compute_stem_width
,
2231 CALL
, /* s: edge2 edge cur_len */
2236 LT
, /* cur_len < 96 */
2241 LTEQ
, /* cur_len <= 64 */
2259 SWAP
, /* s: edge2 cur_len edge */
2260 DUP
, /* s: edge2 cur_len edge edge */
2269 ADD
, /* s: edge2 cur_len edge org_center */
2274 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2279 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2286 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
2293 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
2295 LT
, /* error1 < error2 */
2300 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2306 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2307 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2315 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
2319 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
2322 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2324 SWAP
, /* s: cur_len edge2 */
2326 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2328 SHPIX
, /* edge2 = edge1 + cur_len */
2331 POP
, /* s: edge2 edge */
2339 CALL
, /* s: edge2 edge edge_pos round(edge_orig_pos) */
2342 SHPIX
, /* edge = round(edge_orig) */
2344 /* clean up stack */
2351 SZP1
, /* set zp1 to normal zone 1 */
2360 * bci_action_blue_anchor
2362 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
2363 * and to set the edge anchor.
2365 * in: anchor_point (in twilight zone)
2367 * edge_point (in twilight zone)
2368 * ... stuff for bci_align_segments (edge) ...
2372 * uses: bci_action_blue
2375 unsigned char FPGM(bci_action_blue_anchor
) [] = {
2378 bci_action_blue_anchor
,
2381 /* store anchor point number in `sal_anchor' */
2399 * Handle the BLUE action to align an edge with a blue zone.
2402 * edge_point (in twilight zone)
2403 * ... stuff for bci_align_segments (edge) ...
2406 unsigned char FPGM(bci_action_blue
) [] = {
2414 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2416 /* move `edge_point' to `blue_cvt_idx' position; */
2417 /* note that we can't use MIAP since this would modify */
2418 /* the twilight point's original coordinates also */
2422 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2424 GC_cur
, /* s: new_pos edge edge_pos */
2427 SUB
, /* s: edge (new_pos - edge_pos) */
2433 SZP1
, /* set zp1 to normal zone 1 */
2442 * bci_action_serif_common
2444 * Common code for bci_action_serif routines.
2447 unsigned char FPGM(bci_action_serif_common
) [] = {
2450 bci_action_serif_common
,
2455 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2462 MINDEX
, /* s: [...] serif serif serif serif base */
2464 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2467 ALIGNRP
, /* align `serif_point' with `base_point' */
2468 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2478 * Move an edge if necessary to stay within a lower bound.
2484 unsigned char FPGM(bci_lower_bound
) [] = {
2490 SWAP
, /* s: edge bound */
2492 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2497 GC_cur
, /* s: edge bound_pos edge_pos */
2498 GT
, /* edge_pos < bound_pos */
2501 ALIGNRP
, /* align `edge' to `bound' */
2504 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2509 SZP1
, /* set zp1 to normal zone 1 */
2520 * Move an edge if necessary to stay within an upper bound.
2526 unsigned char FPGM(bci_upper_bound
) [] = {
2532 SWAP
, /* s: edge bound */
2534 MDAP_noround
, /* set rp0 and rp1 to `bound' */
2539 GC_cur
, /* s: edge bound_pos edge_pos */
2540 LT
, /* edge_pos > bound_pos */
2543 ALIGNRP
, /* align `edge' to `bound' */
2546 MDAP_noround
, /* set rp0 and rp1 to `edge_point' */
2551 SZP1
, /* set zp1 to normal zone 1 */
2560 * bci_lower_upper_bound
2562 * Move an edge if necessary to stay within a lower and lower bound.
2569 unsigned char FPGM(bci_lower_upper_bound
) [] = {
2572 bci_lower_upper_bound
,
2575 SWAP
, /* s: upper serif lower */
2577 MDAP_noround
, /* set rp0 and rp1 to `lower' */
2582 GC_cur
, /* s: upper serif lower_pos serif_pos */
2583 GT
, /* serif_pos < lower_pos */
2586 ALIGNRP
, /* align `serif' to `lower' */
2589 SWAP
, /* s: serif upper */
2591 MDAP_noround
, /* set rp0 and rp1 to `upper' */
2596 GC_cur
, /* s: serif upper_pos serif_pos */
2597 LT
, /* serif_pos > upper_pos */
2600 ALIGNRP
, /* align `serif' to `upper' */
2603 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2608 SZP1
, /* set zp1 to normal zone 1 */
2619 * Handle the SERIF action to align a serif with its base.
2621 * in: serif_point (in twilight zone)
2622 * base_point (in twilight zone)
2623 * ... stuff for bci_align_segments (serif) ...
2625 * uses: bci_action_serif_common
2628 unsigned char FPGM(bci_action_serif
) [] = {
2635 bci_action_serif_common
,
2638 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2643 SZP1
, /* set zp1 to normal zone 1 */
2652 * bci_action_serif_lower_bound
2654 * Handle the SERIF action to align a serif with its base, then moving it
2655 * again if necessary to stay within a lower bound.
2657 * in: serif_point (in twilight zone)
2658 * base_point (in twilight zone)
2659 * edge[-1] (in twilight zone)
2660 * ... stuff for bci_align_segments (serif) ...
2662 * uses: bci_action_serif_common
2666 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2669 bci_action_serif_lower_bound
,
2673 bci_action_serif_common
,
2686 * bci_action_serif_upper_bound
2688 * Handle the SERIF action to align a serif with its base, then moving it
2689 * again if necessary to stay within an upper bound.
2691 * in: serif_point (in twilight zone)
2692 * base_point (in twilight zone)
2693 * edge[1] (in twilight zone)
2694 * ... stuff for bci_align_segments (serif) ...
2696 * uses: bci_action_serif_common
2700 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2703 bci_action_serif_upper_bound
,
2707 bci_action_serif_common
,
2720 * bci_action_serif_lower_upper_bound
2722 * Handle the SERIF action to align a serif with its base, then moving it
2723 * again if necessary to stay within a lower and upper bound.
2725 * in: serif_point (in twilight zone)
2726 * base_point (in twilight zone)
2727 * edge[-1] (in twilight zone)
2728 * edge[1] (in twilight zone)
2729 * ... stuff for bci_align_segments (serif) ...
2731 * uses: bci_action_serif_common
2732 * bci_lower_upper_bound
2735 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2738 bci_action_serif_lower_upper_bound
,
2743 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2746 bci_action_serif_common
,
2750 bci_lower_upper_bound
,
2759 * bci_action_serif_anchor_common
2761 * Common code for bci_action_serif_anchor routines.
2764 unsigned char FPGM(bci_action_serif_anchor_common
) [] = {
2767 bci_action_serif_anchor_common
,
2772 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2778 WS
, /* sal_anchor = edge_point */
2788 CALL
, /* s: [...] edge edge edge_pos round(edge_orig_pos) */
2791 SHPIX
, /* edge = round(edge_orig) */
2799 * bci_action_serif_anchor
2801 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2804 * in: edge_point (in twilight zone)
2805 * ... stuff for bci_align_segments (edge) ...
2807 * uses: bci_action_serif_anchor_common
2810 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2813 bci_action_serif_anchor
,
2817 bci_action_serif_anchor_common
,
2820 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2825 SZP1
, /* set zp1 to normal zone 1 */
2834 * bci_action_serif_anchor_lower_bound
2836 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2837 * anchor, then moving it again if necessary to stay within a lower
2840 * in: edge_point (in twilight zone)
2841 * edge[-1] (in twilight zone)
2842 * ... stuff for bci_align_segments (edge) ...
2844 * uses: bci_action_serif_anchor_common
2848 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
2851 bci_action_serif_anchor_lower_bound
,
2855 bci_action_serif_anchor_common
,
2868 * bci_action_serif_anchor_upper_bound
2870 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2871 * anchor, then moving it again if necessary to stay within an upper
2874 * in: edge_point (in twilight zone)
2875 * edge[1] (in twilight zone)
2876 * ... stuff for bci_align_segments (edge) ...
2878 * uses: bci_action_serif_anchor_common
2882 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
2885 bci_action_serif_anchor_upper_bound
,
2889 bci_action_serif_anchor_common
,
2902 * bci_action_serif_anchor_lower_upper_bound
2904 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2905 * anchor, then moving it again if necessary to stay within a lower and
2908 * in: edge_point (in twilight zone)
2909 * edge[-1] (in twilight zone)
2910 * edge[1] (in twilight zone)
2911 * ... stuff for bci_align_segments (edge) ...
2913 * uses: bci_action_serif_anchor_common
2914 * bci_lower_upper_bound
2917 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
2920 bci_action_serif_anchor_lower_upper_bound
,
2924 bci_action_serif_anchor_common
,
2928 bci_lower_upper_bound
,
2937 * bci_action_serif_link1_common
2939 * Common code for bci_action_serif_link1 routines.
2942 unsigned char FPGM(bci_action_serif_link1_common
) [] = {
2945 bci_action_serif_link1_common
,
2950 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2954 CINDEX
, /* s: [...] after edge before after */
2957 CINDEX
, /* s: [...] after edge before after before */
2961 EQ
, /* after_orig_pos == before_orig_pos */
2962 IF
, /* s: [...] after edge before */
2963 MDAP_noround
, /* set rp0 and rp1 to `before' */
2965 ALIGNRP
, /* align `edge' with `before' */
2970 /* we have to execute `a*b/c', with b/c very near to 1: */
2971 /* to avoid overflow while retaining precision, */
2972 /* we transform this to `a + a * (b-c)/c' */
2976 CINDEX
, /* s: [...] after edge before edge */
2979 CINDEX
, /* s: [...] after edge before edge before */
2980 MD_orig_ZP2_0
, /* a = edge_orig_pos - before_orig_pos */
2985 CINDEX
, /* s: [...] after edge before a a after */
2988 CINDEX
, /* s: [...] after edge before a a after before */
2989 MD_orig_ZP2_0
, /* c = after_orig_pos - before_orig_pos */
2993 CINDEX
, /* s: [...] after edge before a a c after */
2996 CINDEX
, /* s: [...] after edge before a a c after before */
2997 MD_cur
, /* b = after_pos - before_pos */
3001 CINDEX
, /* s: [...] after edge before a a c b c */
3007 MUL
, /* (b-c) in 16.16 format */
3009 DIV
, /* s: [...] after edge before a a (b-c)/c */
3011 MUL
, /* a * (b-c)/c * 2^10 */
3015 DIV
, /* a * (b-c)/c */
3019 MDAP_noround
, /* set rp0 and rp1 to `before' */
3020 SWAP
, /* s: [...] after a*b/c edge */
3023 ALIGNRP
, /* align `edge' with `before' */
3025 SHPIX
, /* shift `edge' by `a*b/c' */
3027 SWAP
, /* s: [...] edge after */
3037 * bci_action_serif_link1
3039 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3042 * in: before_point (in twilight zone)
3043 * edge_point (in twilight zone)
3044 * after_point (in twilight zone)
3045 * ... stuff for bci_align_segments (edge) ...
3047 * uses: bci_action_serif_link1_common
3050 unsigned char FPGM(bci_action_serif_link1
) [] = {
3053 bci_action_serif_link1
,
3057 bci_action_serif_link1_common
,
3060 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3065 SZP1
, /* set zp1 to normal zone 1 */
3074 * bci_action_serif_link1_lower_bound
3076 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3077 * before and after. Additionally, move the serif again if necessary to
3078 * stay within a lower bound.
3080 * in: before_point (in twilight zone)
3081 * edge_point (in twilight zone)
3082 * after_point (in twilight zone)
3083 * edge[-1] (in twilight zone)
3084 * ... stuff for bci_align_segments (edge) ...
3086 * uses: bci_action_serif_link1_common
3090 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3093 bci_action_serif_link1_lower_bound
,
3097 bci_action_serif_link1_common
,
3110 * bci_action_serif_link1_upper_bound
3112 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3113 * before and after. Additionally, move the serif again if necessary to
3114 * stay within an upper bound.
3116 * in: before_point (in twilight zone)
3117 * edge_point (in twilight zone)
3118 * after_point (in twilight zone)
3119 * edge[1] (in twilight zone)
3120 * ... stuff for bci_align_segments (edge) ...
3122 * uses: bci_action_serif_link1_common
3126 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3129 bci_action_serif_link1_upper_bound
,
3133 bci_action_serif_link1_common
,
3146 * bci_action_serif_link1_lower_upper_bound
3148 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3149 * before and after. Additionally, move the serif again if necessary to
3150 * stay within a lower and upper bound.
3152 * in: before_point (in twilight zone)
3153 * edge_point (in twilight zone)
3154 * after_point (in twilight zone)
3155 * edge[-1] (in twilight zone)
3156 * edge[1] (in twilight zone)
3157 * ... stuff for bci_align_segments (edge) ...
3159 * uses: bci_action_serif_link1_common
3160 * bci_lower_upper_bound
3163 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3166 bci_action_serif_link1_lower_upper_bound
,
3170 bci_action_serif_link1_common
,
3174 bci_lower_upper_bound
,
3183 * bci_action_serif_link2_common
3185 * Common code for bci_action_serif_link2 routines.
3188 unsigned char FPGM(bci_action_serif_link2_common
) [] = {
3191 bci_action_serif_link2_common
,
3196 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3198 DUP
, /* s: [...] edge edge */
3202 DUP
, /* s: [...] edge edge anchor anchor */
3203 MDAP_noround
, /* set rp0 and rp1 to `sal_anchor' */
3214 DIV
, /* delta = (edge_orig_pos - anchor_orig_pos + 16) & ~31 */
3219 ALIGNRP
, /* align `edge' with `sal_anchor' */
3221 SHPIX
, /* shift `edge' by `delta' */
3229 * bci_action_serif_link2
3231 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3233 * in: edge_point (in twilight zone)
3234 * ... stuff for bci_align_segments (edge) ...
3236 * uses: bci_action_serif_link2_common
3239 unsigned char FPGM(bci_action_serif_link2
) [] = {
3242 bci_action_serif_link2
,
3246 bci_action_serif_link2_common
,
3249 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3254 SZP1
, /* set zp1 to normal zone 1 */
3263 * bci_action_serif_link2_lower_bound
3265 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3266 * Additionally, move the serif again if necessary to stay within a lower
3269 * in: edge_point (in twilight zone)
3270 * edge[-1] (in twilight zone)
3271 * ... stuff for bci_align_segments (edge) ...
3273 * uses: bci_action_serif_link2_common
3277 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
3280 bci_action_serif_link2_lower_bound
,
3284 bci_action_serif_link2_common
,
3297 * bci_action_serif_link2_upper_bound
3299 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3300 * Additionally, move the serif again if necessary to stay within an upper
3303 * in: edge_point (in twilight zone)
3304 * edge[1] (in twilight zone)
3305 * ... stuff for bci_align_segments (edge) ...
3307 * uses: bci_action_serif_link2_common
3311 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3314 bci_action_serif_link2_upper_bound
,
3318 bci_action_serif_link2_common
,
3331 * bci_action_serif_link2_lower_upper_bound
3333 * Handle the SERIF_LINK2 action to align a serif relative to the anchor.
3334 * Additionally, move the serif again if necessary to stay within a lower
3337 * in: edge_point (in twilight zone)
3338 * edge[-1] (in twilight zone)
3339 * edge[1] (in twilight zone)
3340 * ... stuff for bci_align_segments (edge) ...
3342 * uses: bci_action_serif_link2_common
3343 * bci_lower_upper_bound
3346 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3349 bci_action_serif_link2_lower_upper_bound
,
3353 bci_action_serif_link2_common
,
3357 bci_lower_upper_bound
,
3370 * in: function_index
3373 unsigned char FPGM(bci_handle_action
) [] = {
3389 * This is the top-level glyph hinting function
3390 * which parses the arguments on the stack and calls subroutines.
3392 * in: num_actions (M)
3401 * uses: bci_handle_action
3403 * bci_action_ip_before
3404 * bci_action_ip_after
3406 * bci_action_ip_between
3408 * bci_action_adjust_bound
3409 * bci_action_stem_bound
3413 * bci_action_blue_anchor
3419 * bci_action_serif_lower_bound
3420 * bci_action_serif_upper_bound
3421 * bci_action_serif_lower_upper_bound
3423 * bci_action_serif_anchor
3424 * bci_action_serif_anchor_lower_bound
3425 * bci_action_serif_anchor_upper_bound
3426 * bci_action_serif_anchor_lower_upper_bound
3428 * bci_action_serif_link1
3429 * bci_action_serif_link1_lower_bound
3430 * bci_action_serif_link1_upper_bound
3431 * bci_action_serif_link1_lower_upper_bound
3433 * bci_action_serif_link2
3434 * bci_action_serif_link2_lower_bound
3435 * bci_action_serif_link2_upper_bound
3436 * bci_action_serif_link2_lower_upper_bound
3439 unsigned char FPGM(bci_hint_glyph
) [] = {
3451 SZP2
, /* set zp2 to normal zone 1 */
3459 #define COPY_FPGM(func_name) \
3460 memcpy(buf_p, fpgm_ ## func_name, \
3461 sizeof (fpgm_ ## func_name)); \
3462 buf_p += sizeof (fpgm_ ## func_name) \
3465 TA_table_build_fpgm(FT_Byte
** fpgm
,
3475 buf_len
= sizeof (FPGM(bci_round
))
3476 + sizeof (FPGM(bci_compute_stem_width_a
))
3478 + sizeof (FPGM(bci_compute_stem_width_b
))
3480 + sizeof (FPGM(bci_compute_stem_width_c
))
3481 + sizeof (FPGM(bci_loop
))
3482 + sizeof (FPGM(bci_cvt_rescale
))
3483 + sizeof (FPGM(bci_blue_round_a
))
3485 + sizeof (FPGM(bci_blue_round_b
))
3486 + sizeof (FPGM(bci_get_point_extrema
))
3488 + sizeof (FPGM(bci_create_segment
))
3489 + sizeof (FPGM(bci_create_segments
))
3490 + sizeof (FPGM(bci_align_segment
))
3491 + sizeof (FPGM(bci_align_segments
))
3493 + sizeof (FPGM(bci_scale_contour
))
3494 + sizeof (FPGM(bci_scale_glyph
))
3495 + sizeof (FPGM(bci_shift_contour
))
3496 + sizeof (FPGM(bci_shift_subglyph
))
3498 + sizeof (FPGM(bci_ip_outer_align_point
))
3499 + sizeof (FPGM(bci_ip_on_align_points
))
3500 + sizeof (FPGM(bci_ip_between_align_point
))
3501 + sizeof (FPGM(bci_ip_between_align_points
))
3503 + sizeof (FPGM(bci_action_adjust_common
))
3504 + sizeof (FPGM(bci_action_stem_common
))
3505 + sizeof (FPGM(bci_action_serif_common
))
3506 + sizeof (FPGM(bci_action_serif_anchor_common
))
3507 + sizeof (FPGM(bci_action_serif_link1_common
))
3508 + sizeof (FPGM(bci_action_serif_link2_common
))
3510 + sizeof (FPGM(bci_lower_bound
))
3511 + sizeof (FPGM(bci_upper_bound
))
3512 + sizeof (FPGM(bci_lower_upper_bound
))
3514 + sizeof (FPGM(bci_action_ip_before
))
3515 + sizeof (FPGM(bci_action_ip_after
))
3516 + sizeof (FPGM(bci_action_ip_on
))
3517 + sizeof (FPGM(bci_action_ip_between
))
3519 + sizeof (FPGM(bci_action_adjust_bound
))
3520 + sizeof (FPGM(bci_action_stem_bound
))
3521 + sizeof (FPGM(bci_action_link
))
3522 + sizeof (FPGM(bci_action_anchor
))
3523 + sizeof (FPGM(bci_action_blue_anchor
))
3524 + sizeof (FPGM(bci_action_adjust
))
3525 + sizeof (FPGM(bci_action_stem
))
3526 + sizeof (FPGM(bci_action_blue
))
3527 + sizeof (FPGM(bci_action_serif
))
3528 + sizeof (FPGM(bci_action_serif_lower_bound
))
3529 + sizeof (FPGM(bci_action_serif_upper_bound
))
3530 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
3531 + sizeof (FPGM(bci_action_serif_anchor
))
3532 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
3533 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
3534 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3535 + sizeof (FPGM(bci_action_serif_link1
))
3536 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3537 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3538 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3539 + sizeof (FPGM(bci_action_serif_link2
))
3540 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3541 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3542 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3544 + sizeof (FPGM(bci_handle_action
))
3545 + sizeof (FPGM(bci_hint_glyph
));
3546 /* buffer length must be a multiple of four */
3547 len
= (buf_len
+ 3) & ~3;
3548 buf
= (FT_Byte
*)malloc(len
);
3550 return FT_Err_Out_Of_Memory
;
3552 /* pad end of buffer with zeros */
3553 buf
[len
- 1] = 0x00;
3554 buf
[len
- 2] = 0x00;
3555 buf
[len
- 3] = 0x00;
3557 /* copy font program into buffer and fill in the missing variables */
3560 COPY_FPGM(bci_round
);
3561 COPY_FPGM(bci_compute_stem_width_a
);
3562 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3563 COPY_FPGM(bci_compute_stem_width_b
);
3564 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3565 COPY_FPGM(bci_compute_stem_width_c
);
3566 COPY_FPGM(bci_loop
);
3567 COPY_FPGM(bci_cvt_rescale
);
3568 COPY_FPGM(bci_blue_round_a
);
3569 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
3570 COPY_FPGM(bci_blue_round_b
);
3571 COPY_FPGM(bci_get_point_extrema
);
3573 COPY_FPGM(bci_create_segment
);
3574 COPY_FPGM(bci_create_segments
);
3575 COPY_FPGM(bci_align_segment
);
3576 COPY_FPGM(bci_align_segments
);
3578 COPY_FPGM(bci_scale_contour
);
3579 COPY_FPGM(bci_scale_glyph
);
3580 COPY_FPGM(bci_shift_contour
);
3581 COPY_FPGM(bci_shift_subglyph
);
3583 COPY_FPGM(bci_ip_outer_align_point
);
3584 COPY_FPGM(bci_ip_on_align_points
);
3585 COPY_FPGM(bci_ip_between_align_point
);
3586 COPY_FPGM(bci_ip_between_align_points
);
3588 COPY_FPGM(bci_action_adjust_common
);
3589 COPY_FPGM(bci_action_stem_common
);
3590 COPY_FPGM(bci_action_serif_common
);
3591 COPY_FPGM(bci_action_serif_anchor_common
);
3592 COPY_FPGM(bci_action_serif_link1_common
);
3593 COPY_FPGM(bci_action_serif_link2_common
);
3595 COPY_FPGM(bci_lower_bound
);
3596 COPY_FPGM(bci_upper_bound
);
3597 COPY_FPGM(bci_lower_upper_bound
);
3599 COPY_FPGM(bci_action_ip_before
);
3600 COPY_FPGM(bci_action_ip_after
);
3601 COPY_FPGM(bci_action_ip_on
);
3602 COPY_FPGM(bci_action_ip_between
);
3604 COPY_FPGM(bci_action_adjust_bound
);
3605 COPY_FPGM(bci_action_stem_bound
);
3606 COPY_FPGM(bci_action_link
);
3607 COPY_FPGM(bci_action_anchor
);
3608 COPY_FPGM(bci_action_blue_anchor
);
3609 COPY_FPGM(bci_action_adjust
);
3610 COPY_FPGM(bci_action_stem
);
3611 COPY_FPGM(bci_action_blue
);
3612 COPY_FPGM(bci_action_serif
);
3613 COPY_FPGM(bci_action_serif_lower_bound
);
3614 COPY_FPGM(bci_action_serif_upper_bound
);
3615 COPY_FPGM(bci_action_serif_lower_upper_bound
);
3616 COPY_FPGM(bci_action_serif_anchor
);
3617 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
3618 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
3619 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
3620 COPY_FPGM(bci_action_serif_link1
);
3621 COPY_FPGM(bci_action_serif_link1_lower_bound
);
3622 COPY_FPGM(bci_action_serif_link1_upper_bound
);
3623 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
3624 COPY_FPGM(bci_action_serif_link2
);
3625 COPY_FPGM(bci_action_serif_link2_lower_bound
);
3626 COPY_FPGM(bci_action_serif_link2_upper_bound
);
3627 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
3629 COPY_FPGM(bci_handle_action
);
3630 COPY_FPGM(bci_hint_glyph
);
3633 *fpgm_len
= buf_len
;
3640 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
3649 error
= TA_sfnt_add_table_info(sfnt
);
3653 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
3657 if (fpgm_len
> sfnt
->max_instructions
)
3658 sfnt
->max_instructions
= fpgm_len
;
3660 /* in case of success, `fpgm_buf' gets linked */
3661 /* and is eventually freed in `TA_font_unload' */
3662 error
= TA_font_add_table(font
,
3663 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3664 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
3674 /* end of tafpgm.c */