3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
6 #include "tabytecode.h"
9 /* a simple macro to emit bytecode instructions */
10 #define BCI(code) *(bufp++) = (code)
12 /* we increase the stack depth by this amount */
13 #define ADDITIONAL_STACK_ELEMENTS 20
16 /* #define DEBUGGING */
21 int _ta_debug_disable_horz_hints
;
22 int _ta_debug_disable_vert_hints
;
23 int _ta_debug_disable_blue_hints
;
24 void* _ta_debug_hints
;
28 typedef struct Hints_Record_
{
35 typedef struct Recorder_
{
37 Hints_Record hints_record
;
38 /* see explanations in `TA_sfnt_build_glyph_segments' */
39 FT_UInt
* wrap_around_segments
;
44 TA_sfnt_compute_global_hints(SFNT
* sfnt
,
48 FT_Face face
= sfnt
->face
;
52 static const FT_Encoding latin_encs
[] =
55 FT_ENCODING_APPLE_ROMAN
,
56 FT_ENCODING_ADOBE_STANDARD
,
57 FT_ENCODING_ADOBE_LATIN_1
,
59 FT_ENCODING_NONE
/* end of list */
63 error
= ta_loader_init(font
->loader
);
67 /* try to select a latin charmap */
68 for (enc
= 0; latin_encs
[enc
] != FT_ENCODING_NONE
; enc
++)
70 error
= FT_Select_Charmap(face
, latin_encs
[enc
]);
75 /* load latin glyph `a' to trigger all initializations */
76 idx
= FT_Get_Char_Index(face
, 'a');
77 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
84 TA_table_build_cvt(FT_Byte
** cvt
,
101 error
= TA_sfnt_compute_global_hints(sfnt
, font
);
105 /* XXX check validity of pointers */
106 haxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[0];
107 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
112 + 2 * vaxis
->blue_count
);
114 /* buffer length must be a multiple of four */
115 len
= (buf_len
+ 3) & ~3;
116 buf
= (FT_Byte
*)malloc(len
);
118 return FT_Err_Out_Of_Memory
;
120 /* pad end of buffer with zeros */
127 if (haxis
->width_count
> 0)
129 *(buf_p
++) = HIGH(haxis
->widths
[0].org
);
130 *(buf_p
++) = LOW(haxis
->widths
[0].org
);
137 if (vaxis
->width_count
> 0)
139 *(buf_p
++) = HIGH(vaxis
->widths
[0].org
);
140 *(buf_p
++) = LOW(vaxis
->widths
[0].org
);
148 for (i
= 0; i
< haxis
->width_count
; i
++)
150 if (haxis
->widths
[i
].org
> 0xFFFF)
152 *(buf_p
++) = HIGH(haxis
->widths
[i
].org
);
153 *(buf_p
++) = LOW(haxis
->widths
[i
].org
);
156 for (i
= 0; i
< vaxis
->width_count
; i
++)
158 if (vaxis
->widths
[i
].org
> 0xFFFF)
160 *(buf_p
++) = HIGH(vaxis
->widths
[i
].org
);
161 *(buf_p
++) = LOW(vaxis
->widths
[i
].org
);
164 for (i
= 0; i
< vaxis
->blue_count
; i
++)
166 if (vaxis
->blues
[i
].ref
.org
> 0xFFFF)
168 *(buf_p
++) = HIGH(vaxis
->blues
[i
].ref
.org
);
169 *(buf_p
++) = LOW(vaxis
->blues
[i
].ref
.org
);
172 for (i
= 0; i
< vaxis
->blue_count
; i
++)
174 if (vaxis
->blues
[i
].shoot
.org
> 0xFFFF)
176 *(buf_p
++) = HIGH(vaxis
->blues
[i
].shoot
.org
);
177 *(buf_p
++) = LOW(vaxis
->blues
[i
].shoot
.org
);
181 TA_LOG(("--------------------------------------------------\n"));
182 TA_LOG(("glyph %d:\n", idx
));
183 ta_glyph_hints_dump_edges(_ta_debug_hints
);
184 ta_glyph_hints_dump_segments(_ta_debug_hints
);
185 ta_glyph_hints_dump_points(_ta_debug_hints
);
195 return TA_Err_Hinter_Overflow
;
200 TA_sfnt_build_cvt_table(SFNT
* sfnt
,
209 error
= TA_sfnt_add_table_info(sfnt
);
213 error
= TA_table_build_cvt(&cvt_buf
, &cvt_len
, sfnt
, font
);
217 /* in case of success, `cvt_buf' gets linked */
218 /* and is eventually freed in `TA_font_unload' */
219 error
= TA_font_add_table(font
,
220 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
221 TTAG_cvt
, cvt_len
, cvt_buf
);
232 /* the horizontal and vertical standard widths */
233 #define CVT_HORZ_STANDARD_WIDTH_OFFSET(font) 0
234 #define CVT_VERT_STANDARD_WIDTH_OFFSET(font) \
235 CVT_HORZ_STANDARD_WIDTH_OFFSET(font) + 1
237 /* the horizontal stem widths */
238 #define CVT_HORZ_WIDTHS_OFFSET(font) \
239 CVT_VERT_STANDARD_WIDTH_OFFSET(font) + 1
240 #define CVT_HORZ_WIDTHS_SIZE(font) \
241 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
243 /* the vertical stem widths */
244 #define CVT_VERT_WIDTHS_OFFSET(font) \
245 CVT_HORZ_WIDTHS_OFFSET(font) + CVT_HORZ_WIDTHS_SIZE(font)
246 #define CVT_VERT_WIDTHS_SIZE(font) \
247 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
249 /* the number of blue zones */
250 #define CVT_BLUES_SIZE(font) \
251 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
253 /* the blue zone values for flat and round edges */
254 #define CVT_BLUE_REFS_OFFSET(font) \
255 CVT_VERT_WIDTHS_OFFSET(font) + CVT_VERT_WIDTHS_SIZE(font)
256 #define CVT_BLUE_SHOOTS_OFFSET(font) \
257 CVT_BLUE_REFS_OFFSET(font) + CVT_BLUES_SIZE(font)
260 /* symbolic names for storage area locations */
263 #define sal_j sal_i + 1
264 #define sal_k sal_j + 1
265 #define sal_temp1 sal_k + 1
266 #define sal_temp2 sal_temp1 + 1
267 #define sal_temp3 sal_temp2 + 1
268 #define sal_limit sal_temp3 + 1
269 #define sal_func sal_limit +1
270 #define sal_num_segments sal_func + 1
271 #define sal_scale sal_num_segments + 1
272 #define sal_0x10000 sal_scale + 1
273 #define sal_is_extra_light sal_0x10000 + 1
274 #define sal_anchor sal_is_extra_light + 1
275 #define sal_point_min sal_anchor + 1
276 #define sal_point_max sal_point_min + 1
277 #define sal_segment_offset sal_point_max + 1 /* must be last */
280 /* we need the following macro */
281 /* so that `func_name' doesn't get replaced with its #defined value */
282 /* (as defined in `tabytecode.h') */
284 #define FPGM(func_name) fpgm_ ## func_name
287 /* in the comments below, the top of the stack (`s:') */
288 /* is the rightmost element; the stack is shown */
289 /* after the instruction on the same line has been executed */
291 /* we use two sets of points in the twilight zone (zp0): */
292 /* one set to hold the unhinted segment positions, */
293 /* and another one to track the positions as changed by the hinting -- */
294 /* this is necessary since all points in zp0 */
295 /* have (0,0) as the original coordinates, */
296 /* making e.g. `MD_orig' return useless results */
302 * Round a 26.6 number. Contrary to the ROUND bytecode instruction, no
303 * engine specific corrections are applied.
309 unsigned char FPGM(bci_round
) [] = {
335 * bci_compute_stem_width
337 * This is the equivalent to the following code from function
338 * `ta_latin_compute_stem_width':
346 * else if base_is_round:
352 * delta = ABS(dist - std_width)
363 * delta = delta - dist
366 * dist = dist + delta
367 * else if delta < 32:
369 * else if delta < 54:
372 * dist = dist + delta
386 * sal: sal_is_extra_light
390 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
393 bci_compute_stem_width
,
397 ABS
, /* s: base_is_round stem_is_serif width dist */
402 LT
, /* dist < 3*64 */
406 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
407 AND
, /* stem_is_serif && dist < 3*64 */
412 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
414 IF
, /* s: base_is_round width dist */
420 ROLL
, /* s: width dist base_is_round */
421 IF
, /* s: width dist */
426 IF
, /* s: width dist */
437 IF
, /* s: width dist */
444 DUP
, /* s: width dist dist */
449 /* %c, index of std_width */
451 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
455 ABS
, /* s: width dist delta */
460 IF
, /* s: width dist */
466 /* %c, index of std_width */
468 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
470 RCVT
, /* dist = std_width */
482 DUP
, /* s: width dist dist */
485 LT
, /* dist < 3*64 */
487 DUP
, /* s: width delta dist */
488 FLOOR
, /* dist = FLOOR(dist) */
489 DUP
, /* s: width delta dist dist */
491 ROLL
, /* s: width dist delta dist */
492 SUB
, /* delta = delta - dist */
494 DUP
, /* s: width dist delta delta */
498 IF
, /* s: width dist delta */
499 ADD
, /* dist = dist + delta */
510 ADD
, /* dist = dist + 10 */
521 ADD
, /* dist = dist + 54 */
524 ADD
, /* dist = dist + delta */
533 CALL
, /* dist = round(dist) */
538 SWAP
, /* s: dist width */
543 NEG
, /* dist = -dist */
556 * Take a range and a function number and apply the function to all
557 * elements of the range.
563 * uses: sal_i (counter initialized with `start')
565 * sal_func (`func_num')
568 unsigned char FPGM(bci_loop
) [] = {
577 WS
, /* sal_func = func_num */
581 WS
, /* sal_limit = end */
585 WS
, /* sal_i = start */
594 LTEQ
, /* start <= end */
605 ADD
, /* start = start + 1 */
611 JMPR
, /* goto start_loop */
622 * Rescale CVT value by a given factor.
624 * uses: sal_i (CVT index)
625 * sal_scale (scale in 16.16 format)
628 unsigned char FPGM(bci_cvt_rescale
) [] = {
642 MUL
, /* CVT * scale * 2^10 */
646 DIV
, /* CVT * scale */
658 * Round a blue ref value and adjust its corresponding shoot value.
660 * uses: sal_i (CVT index)
664 unsigned char FPGM(bci_blue_round_a
) [] = {
674 RCVT
, /* s: ref_idx ref */
680 SWAP
, /* s: ref_idx round(ref) ref */
688 unsigned char FPGM(bci_blue_round_b
) [] = {
692 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
694 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
696 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
698 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
700 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
725 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
730 NEG
, /* delta = -delta */
736 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
747 * bci_get_point_extrema
749 * An auxiliary function for `bci_create_segment'.
758 unsigned char FPGM(bci_get_point_extrema
) [] = {
761 bci_get_point_extrema
,
770 /* check whether `point' is a new minimum */
773 RS
, /* s: point point point point_min */
775 /* if distance is negative, we have a new minimum */
779 IF
, /* s: point point */
787 /* check whether `point' is a new maximum */
790 RS
, /* s: point point point_max */
792 /* if distance is positive, we have a new maximum */
812 * Store start and end point of a segment in the storage area,
813 * then construct two points in the twilight zone to represent it:
814 * an original one (which stays unmodified) and a hinted one,
815 * initialized with the original value.
817 * This function is used by `bci_create_segment_points'.
821 * [last (if wrap-around segment)]
822 * [first (if wrap-around segment)]
824 * uses: bci_get_point_extrema
826 * sal: sal_i (start of current segment)
827 * sal_j (current original twilight point)
828 * sal_k (current hinted twilight point)
833 unsigned char FPGM(bci_create_segment
) [] = {
845 WS
, /* sal[sal_i] = start */
847 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
853 ADD
, /* sal_i = sal_i + 1 */
856 /* initialize inner loop(s) */
861 WS
, /* sal_point_min = start */
866 WS
, /* sal_point_max = start */
870 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
876 CINDEX
, /* s: start end end start */
877 LT
, /* start > end */
879 /* we have a wrap-around segment with two more arguments */
880 /* to give the last and first point of the contour, respectively; */
881 /* our job is to store a segment `start'-`last', */
882 /* and to get extrema for the two segments */
883 /* `start'-`last' and `first'-`end' */
885 /* s: first last start end */
892 WS
, /* sal[sal_i] = last */
895 ROLL
, /* s: first end last start */
898 SWAP
, /* s: first end start last start */
899 SUB
, /* s: first end start loop_count */
902 bci_get_point_extrema
,
907 SWAP
, /* s: end first */
912 ROLL
, /* s: (first - 1) (first - 1) end */
914 SUB
, /* s: (first - 1) loop_count */
917 bci_get_point_extrema
,
922 ELSE
, /* s: start end */
929 WS
, /* sal[sal_i] = end */
934 SUB
, /* s: start loop_count */
937 bci_get_point_extrema
,
943 /* the twilight point representing a segment */
944 /* is in the middle between the minimum and maximum */
962 MDAP_noround
, /* set rp0 and rp1 to `sal_point_min' */
963 SZP1
, /* set zp1 to twilight zone 0 */
964 SZP2
, /* set zp2 to twilight zone 0 */
967 DUP
, /* s: delta point[sal_j] point[sal_j] */
968 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
971 CINDEX
, /* s: delta point[sal_j] delta */
972 SHPIX
, /* shift `point[sal_j]' by `delta' */
977 DUP
, /* s: delta point[sal_k] point[sal_k] */
978 ALIGNRP
, /* align `point[sal_k]' with `sal_point_min' */
980 SHPIX
, /* shift `point[sal_k]' by `delta' */
990 ADD
, /* original_twilight_point = original_twilight_point + 1 */
993 ADD
, /* hinted_twilight_point = hinted_twilight_point + 1 */
1002 * bci_create_segments
1004 * Set up segments by defining point ranges which defines them
1005 * and computing twilight points to represent them.
1007 * in: num_segments (N)
1010 * [contour_last 0 (if wrap-around segment)]
1011 * [contour_first 0 (if wrap-around segment)]
1014 * [contour_last 0 (if wrap-around segment)]
1015 * [contour_first 0 (if wrap-around segment)]
1017 * segment_start_(N-1)
1019 * [contour_last (N-1) (if wrap-around segment)]
1020 * [contour_first (N-1) (if wrap-around segment)]
1022 * uses: bci_create_segment
1024 * sal: sal_i (start of current segment)
1025 * sal_j (current original twilight point)
1026 * sal_k (current hinted twilight point)
1030 unsigned char FPGM(bci_create_segments
) [] = {
1033 bci_create_segments
,
1036 /* all our measurements are taken along the y axis */
1042 WS
, /* sal_num_segments = num_segments */
1054 WS
, /* sal_j = num_segments (offset for original points) */
1055 WS
, /* sal_k = 0 (offset for hinted points) */
1063 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1065 /* `bci_create_segment_point' also increases the loop counter by 1; */
1066 /* this effectively means we have a loop step of 2 */
1076 unsigned char FPGM(bci_handle_segment
) [] = {
1082 POP
, /* XXX segment */
1092 * Align all points in a segment to the twilight point in rp0.
1093 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1098 unsigned char FPGM(bci_align_segment
) [] = {
1104 /* we need the values of `sal_segment_offset + 2*segment_index' */
1105 /* and `sal_segment_offset + 2*segment_index + 1' */
1117 RS
, /* s: first last */
1122 CINDEX
, /* s: first last first */
1125 CINDEX
, /* s: first last first last */
1126 LTEQ
, /* first <= end */
1127 IF
, /* s: first last */
1129 DUP
, /* s: last first first */
1130 ALIGNRP
, /* align point with index `first' with rp0 */
1134 ADD
, /* first = first + 1 */
1135 SWAP
, /* s: first last */
1140 JMPR
, /* goto start_loop */
1151 unsigned char FPGM(bci_handle_segments
) [] = {
1154 bci_handle_segments
,
1157 POP
, /* XXX first segment */
1169 * bci_align_segments
1171 * Align segments to the twilight point in rp0.
1172 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1181 * uses: handle_segment
1185 unsigned char FPGM(bci_align_segments
) [] = {
1205 * bci_action_adjust_bound
1207 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1208 * edge of the stem has already been moved, then moving it again if
1209 * necessary to stay bound.
1211 * in: edge2_is_serif
1213 * edge_point (in twilight zone)
1214 * edge2_point (in twilight zone)
1215 * edge[-1] (in twilight zone)
1216 * ... stuff for bci_align_segments (edge) ...
1219 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1222 bci_action_adjust_bound
,
1227 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1235 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig */
1242 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1243 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1246 bci_compute_stem_width
,
1248 NEG
, /* s: edge[-1] edge2 edge -cur_len */
1250 ROLL
, /* s: edge[-1] edge -cur_len edge2 */
1251 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1254 DUP
, /* s: edge[-1] -cur_len edge edge edge */
1255 ALIGNRP
, /* align `edge' with `edge2' */
1257 SHPIX
, /* shift `edge' by -cur_len */
1259 SWAP
, /* s: edge edge[-1] */
1261 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1266 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1267 GT
, /* edge_pos < edge[-1]_pos */
1270 ALIGNRP
, /* align `edge' to `edge[-1]' */
1273 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1278 SZP1
, /* set zp1 to normal zone 1 */
1287 * bci_action_stem_bound
1289 * Handle the STEM action to align two edges of a stem, then moving one
1290 * edge again if necessary to stay bound.
1292 * The code after computing `cur_len' to shift `edge' and `edge2'
1293 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1296 * if cur_len < = 64:
1303 * org_center = edge_orig + org_len / 2
1304 * cur_pos1 = ROUND(org_center)
1306 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1307 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1308 * if (delta1 < delta2):
1309 * cur_pos1 = cur_pos1 - u_off
1311 * cur_pos1 = cur_pos1 + d_off
1313 * edge = cur_pos1 - cur_len / 2
1316 * org_pos = anchor + (edge_orig - anchor_orig)
1317 * org_center = edge_orig + org_len / 2
1319 * cur_pos1 = ROUND(org_pos)
1320 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1321 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1322 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1324 * if (delta1 < delta2):
1329 * edge2 = edge + cur_len
1331 * in: edge2_is_serif
1333 * edge_point (in twilight zone)
1334 * edge2_point (in twilight zone)
1335 * edge[-1] (in twilight zone)
1336 * ... stuff for bci_align_segments (edge) ...
1337 * ... stuff for bci_align_segments (edge2)...
1347 #define sal_u_off sal_temp1
1349 #define sal_d_off sal_temp2
1351 #define sal_org_len sal_temp3
1353 #define sal_edge2 sal_temp3
1355 unsigned char FPGM(bci_action_stem_bound
) [] = {
1358 bci_action_stem_bound
,
1363 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1376 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1380 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1382 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1390 bci_compute_stem_width
,
1391 CALL
, /* s: edge[-1] edge2 edge cur_len */
1396 LT
, /* cur_len < 96 */
1401 LTEQ
, /* cur_len <= 64 */
1419 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1424 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1433 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1438 CALL
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1443 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1450 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1457 ABS
, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1459 LT
, /* delta1 < delta2 */
1464 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1470 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1471 EIF
, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1479 SUB
, /* arg = cur_pos1 - cur_len/2 */
1481 SWAP
, /* s: edge[-1] edge2 cur_len arg edge */
1487 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1490 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1493 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1498 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1507 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1512 GC_cur
, /* s: edge[-1] edge2 cur_len edge org_center anchor_pos */
1528 ADD
, /* s: edge[-1] edge2 cur_len edge org_center org_pos */
1533 CALL
, /* cur_pos1 = ROUND(org_pos) */
1545 SUB
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1556 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1563 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1569 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1570 LT
, /* delta1 < delta2 */
1572 POP
, /* arg = cur_pos1 */
1575 POP
, /* arg = cur_pos2 */
1576 EIF
, /* s: edge[-1] edge2 cur_len edge arg */
1583 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1586 SHPIX
, /* edge = arg */
1587 EIF
, /* s: edge[-1] edge2 cur_len edge */
1589 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1592 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1596 WS
, /* s: edge[-1] cur_len edge edge2 */
1598 SHPIX
, /* edge2 = edge + cur_len */
1600 SWAP
, /* s: edge edge[-1] */
1602 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1607 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1608 GT
, /* edge_pos < edge[-1]_pos */
1611 ALIGNRP
, /* align `edge' to `edge[-1]' */
1614 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1619 SZP1
, /* set zp1 to normal zone 1 */
1625 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1639 * Handle the LINK action to link an edge to another one.
1643 * base_point (in twilight zone)
1644 * stem_point (in twilight zone)
1645 * ... stuff for bci_align_segments (base) ...
1648 unsigned char FPGM(bci_action_link
) [] = {
1656 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1669 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1673 ADD
, /* s: stem is_round is_serif stem_orig base_orig */
1675 MD_cur
, /* s: stem is_round is_serif dist_orig */
1678 bci_compute_stem_width
,
1679 CALL
, /* s: stem new_dist */
1683 ALIGNRP
, /* align `stem_point' with `base_point' */
1685 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
1687 SHPIX
, /* stem_point = base_point + new_dist */
1692 SZP1
, /* set zp1 to normal zone 1 */
1703 * Handle the ANCHOR action to align two edges
1704 * and to set the edge anchor.
1706 * The code after computing `cur_len' to shift `edge' and `edge2'
1707 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1710 * if cur_len < = 64:
1717 * org_center = edge_orig + org_len / 2
1718 * cur_pos1 = ROUND(org_center)
1720 * error1 = ABS(org_center - (cur_pos1 - u_off))
1721 * error2 = ABS(org_center - (cur_pos1 + d_off))
1722 * if (error1 < error2):
1723 * cur_pos1 = cur_pos1 - u_off
1725 * cur_pos1 = cur_pos1 + d_off
1727 * edge = cur_pos1 - cur_len / 2
1728 * edge2 = edge + cur_len
1731 * edge = ROUND(edge_orig)
1733 * in: edge2_is_serif
1735 * edge_point (in twilight zone)
1736 * edge2_point (in twilight zone)
1737 * ... stuff for bci_align_segments (edge) ...
1746 #define sal_u_off sal_temp1
1748 #define sal_d_off sal_temp2
1750 #define sal_org_len sal_temp3
1752 unsigned char FPGM(bci_action_anchor
) [] = {
1758 /* store anchor point number in `sal_anchor' */
1763 WS
, /* sal_anchor = edge_point */
1767 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1780 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1784 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
1786 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
1794 bci_compute_stem_width
,
1795 CALL
, /* s: edge2 edge cur_len */
1800 LT
, /* cur_len < 96 */
1805 LTEQ
, /* cur_len <= 64 */
1823 SWAP
, /* s: edge2 cur_len edge */
1828 ADD
, /* s: edge2 cur_len edge edge_orig */
1837 ADD
, /* s: edge2 cur_len edge org_center */
1842 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
1847 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1854 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1861 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1863 LT
, /* error1 < error2 */
1868 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1874 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1875 EIF
, /* s: edge2 cur_len edge cur_pos1 */
1883 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1887 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1890 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1892 SWAP
, /* s: cur_len edge2 */
1894 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1896 SHPIX
, /* edge2 = edge1 + cur_len */
1899 POP
, /* s: edge2 edge */
1904 ADD
, /* s: edge2 edge edge_orig */
1906 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
1908 ALIGNRP
, /* align `edge' with `edge_orig' */
1909 MDAP_round
, /* round `edge' */
1911 /* clean up stack */
1918 SZP1
, /* set zp1 to normal zone 1 */
1927 * bci_action_blue_anchor
1929 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1930 * and to set the edge anchor.
1932 * in: anchor_point (in twilight zone)
1934 * edge_point (in twilight zone)
1935 * ... stuff for bci_align_segments (edge) ...
1940 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1943 bci_action_blue_anchor
,
1946 /* store anchor point number in `sal_anchor' */
1954 SZP0
, /* set zp0 to twilight zone 0 */
1956 /* move `edge_point' to `blue_cvt_idx' position */
1957 MIAP_noround
, /* this also sets rp0 */
1962 SZP1
, /* set zp1 to normal zone 1 */
1973 * Handle the ADJUST action to align an edge of a stem if the other edge
1974 * of the stem has already been moved.
1976 * in: edge2_is_serif
1978 * edge_point (in twilight zone)
1979 * edge2_point (in twilight zone)
1980 * ... stuff for bci_align_segments (edge) ...
1983 unsigned char FPGM(bci_action_adjust
) [] = {
1991 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1999 ADD
, /* s: edge2 edge is_round is_serif edge2_orig */
2006 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2007 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
2010 bci_compute_stem_width
,
2012 NEG
, /* s: edge2 edge -cur_len */
2015 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2018 DUP
, /* s: -cur_len edge edge edge */
2019 ALIGNRP
, /* align `edge' with `edge2' */
2021 SHPIX
, /* shift `edge' by -cur_len */
2023 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2028 SZP1
, /* set zp1 to normal zone 1 */
2039 * Handle the STEM action to align two edges of a stem.
2041 * The code after computing `cur_len' to shift `edge' and `edge2'
2042 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2045 * if cur_len < = 64:
2052 * org_center = edge_orig + org_len / 2
2053 * cur_pos1 = ROUND(org_center)
2055 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2056 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2057 * if (delta1 < delta2):
2058 * cur_pos1 = cur_pos1 - u_off
2060 * cur_pos1 = cur_pos1 + d_off
2062 * edge = cur_pos1 - cur_len / 2
2065 * org_pos = anchor + (edge_orig - anchor_orig)
2066 * org_center = edge_orig + org_len / 2
2068 * cur_pos1 = ROUND(org_pos)
2069 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2070 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2071 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2073 * if (delta1 < delta2):
2078 * edge2 = edge + cur_len
2080 * in: edge2_is_serif
2082 * edge_point (in twilight zone)
2083 * edge2_point (in twilight zone)
2084 * ... stuff for bci_align_segments (edge) ...
2085 * ... stuff for bci_align_segments (edge2)...
2095 #define sal_u_off sal_temp1
2097 #define sal_d_off sal_temp2
2099 #define sal_org_len sal_temp3
2101 #define sal_edge2 sal_temp3
2103 unsigned char FPGM(bci_action_stem
) [] = {
2111 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2124 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2128 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2130 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
2138 bci_compute_stem_width
,
2139 CALL
, /* s: edge2 edge cur_len */
2144 LT
, /* cur_len < 96 */
2149 LTEQ
, /* cur_len <= 64 */
2167 SWAP
, /* s: edge2 cur_len edge */
2172 ADD
, /* s: edge2 cur_len edge edge_orig */
2181 ADD
, /* s: edge2 cur_len edge org_center */
2186 CALL
, /* s: edge2 cur_len edge org_center cur_pos1 */
2191 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2198 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2205 ABS
, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2207 LT
, /* delta1 < delta2 */
2212 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2218 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2219 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2227 SUB
, /* arg = cur_pos1 - cur_len/2 */
2229 SWAP
, /* s: edge2 cur_len arg edge */
2234 SWAP
, /* s: edge2 cur_len edge arg edge */
2237 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2240 SWAP
, /* s: edge2 cur_len edge */
2245 ADD
, /* s: edge2 cur_len edge edge_orig */
2254 ADD
, /* s: edge2 cur_len edge org_center */
2259 GC_cur
, /* s: edge2 cur_len edge org_center anchor_pos */
2275 ADD
, /* s: edge2 cur_len edge org_center org_pos */
2280 CALL
, /* cur_pos1 = ROUND(org_pos) */
2292 SUB
, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2303 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2310 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2316 ABS
, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2317 LT
, /* delta1 < delta2 */
2319 POP
, /* arg = cur_pos1 */
2322 POP
, /* arg = cur_pos2 */
2323 EIF
, /* s: edge2 cur_len edge arg */
2329 SWAP
, /* s: edge2 cur_len edge arg edge */
2332 SHPIX
, /* edge = arg */
2333 EIF
, /* s: edge2 cur_len */
2335 SWAP
, /* s: cur_len edge2 */
2338 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2342 WS
, /* s: cur_len edge2 */
2344 SHPIX
, /* edge2 = edge + cur_len */
2349 SZP1
, /* set zp1 to normal zone 1 */
2355 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2368 * Handle the BLUE action to align an edge with a blue zone.
2371 * edge_point (in twilight zone)
2372 * ... stuff for bci_align_segments (edge) ...
2375 unsigned char FPGM(bci_action_blue
) [] = {
2383 SZP0
, /* set zp0 to twilight zone 0 */
2385 /* move `edge_point' to `blue_cvt_idx' position */
2386 MIAP_noround
, /* this also sets rp0 */
2391 SZP1
, /* set zp1 to normal zone 1 */
2402 * Handle the SERIF action to align a serif with its base.
2404 * in: serif_point (in twilight zone)
2405 * base_point (in twilight zone)
2406 * ... stuff for bci_align_segments (serif) ...
2409 unsigned char FPGM(bci_action_serif
) [] = {
2417 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2423 MINDEX
, /* s: serif serif serif base */
2430 ADD
, /* s: serif serif serif base serif_orig */
2433 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2437 ADD
, /* s: serif serif serif serif_orig base_orig */
2440 ALIGNRP
, /* align `serif_point' with `base_point' */
2441 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2443 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2448 SZP1
, /* set zp1 to normal zone 1 */
2457 * bci_action_serif_lower_bound
2459 * Handle the SERIF action to align a serif with its base, then moving it
2460 * again if necessary to stay within a lower bound.
2462 * in: serif_point (in twilight zone)
2463 * base_point (in twilight zone)
2464 * edge[-1] (in twilight zone)
2465 * ... stuff for bci_align_segments (serif) ...
2468 unsigned char FPGM(bci_action_serif_lower_bound
) [] = {
2471 bci_action_serif_lower_bound
,
2476 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2482 MINDEX
, /* s: edge[-1] serif serif serif base */
2489 ADD
, /* s: edge[-1] serif serif serif base serif_orig */
2492 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2496 ADD
, /* s: edge[-1] serif serif serif serif_orig base_orig */
2499 ALIGNRP
, /* align `serif_point' with `base_point' */
2500 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2502 SWAP
, /* s: serif edge[-1] */
2504 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2509 GC_cur
, /* s: serif edge[-1]_pos serif_pos */
2510 GT
, /* serif_pos < edge[-1]_pos */
2513 ALIGNRP
, /* align `serif' to `edge[-1]' */
2516 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2521 SZP1
, /* set zp1 to normal zone 1 */
2530 * bci_action_serif_upper_bound
2532 * Handle the SERIF action to align a serif with its base, then moving it
2533 * again if necessary to stay within an upper bound.
2535 * in: serif_point (in twilight zone)
2536 * base_point (in twilight zone)
2537 * edge[1] (in twilight zone)
2538 * ... stuff for bci_align_segments (serif) ...
2541 unsigned char FPGM(bci_action_serif_upper_bound
) [] = {
2544 bci_action_serif_upper_bound
,
2549 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2555 MINDEX
, /* s: edge[1] serif serif serif base */
2562 ADD
, /* s: edge[1] serif serif serif base serif_orig */
2565 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2569 ADD
, /* s: edge[1] serif serif serif serif_orig base_orig */
2572 ALIGNRP
, /* align `serif_point' with `base_point' */
2573 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2575 SWAP
, /* s: serif edge[1] */
2577 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2582 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2583 LT
, /* serif_pos > edge[1]_pos */
2586 ALIGNRP
, /* align `serif' to `edge[1]' */
2589 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2594 SZP1
, /* set zp1 to normal zone 1 */
2603 * bci_action_serif_lower_upper_bound
2605 * Handle the SERIF action to align a serif with its base, then moving it
2606 * again if necessary to stay within a lower and upper bound.
2608 * in: serif_point (in twilight zone)
2609 * base_point (in twilight zone)
2610 * edge[-1] (in twilight zone)
2611 * edge[1] (in twilight zone)
2612 * ... stuff for bci_align_segments (serif) ...
2615 unsigned char FPGM(bci_action_serif_lower_upper_bound
) [] = {
2618 bci_action_serif_lower_upper_bound
,
2623 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2629 MINDEX
, /* s: edge[1] edge[-1] serif serif serif base */
2636 ADD
, /* s: edge[1] edge[-1] serif serif serif base serif_orig */
2639 MDAP_noround
, /* set rp0 and rp1 to `base_point' */
2643 ADD
, /* s: edge[1] edge[-1] serif serif serif serif_orig base_orig */
2646 ALIGNRP
, /* align `serif_point' with `base_point' */
2647 SHPIX
, /* serif = base + (serif_orig_pos - base_orig_pos) */
2649 SWAP
, /* s: edge[1] serif edge[-1] */
2651 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2656 GC_cur
, /* s: edge[1] serif edge[-1]_pos serif_pos */
2657 GT
, /* serif_pos < edge[-1]_pos */
2660 ALIGNRP
, /* align `serif' to `edge[-1]' */
2663 SWAP
, /* s: serif edge[1] */
2665 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2670 GC_cur
, /* s: serif edge[1]_pos serif_pos */
2671 LT
, /* serif_pos > edge[1]_pos */
2674 ALIGNRP
, /* align `serif' to `edge[1]' */
2677 MDAP_noround
, /* set rp0 and rp1 to `serif_point' */
2682 SZP1
, /* set zp1 to normal zone 1 */
2691 * bci_action_serif_anchor
2693 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2696 * in: edge_point (in twilight zone)
2697 * ... stuff for bci_align_segments (edge) ...
2700 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2703 bci_action_serif_anchor
,
2708 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2714 ADD
, /* s: edge edge_orig */
2716 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2719 ALIGNRP
, /* align `edge' with `edge_orig' */
2720 MDAP_round
, /* round `edge' */
2722 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2727 SZP1
, /* set zp1 to normal zone 1 */
2736 * bci_action_serif_anchor_lower_bound
2738 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2739 * anchor, then moving it again if necessary to stay within a lower
2742 * in: edge_point (in twilight zone)
2743 * edge[-1] (in twilight zone)
2744 * ... stuff for bci_align_segments (edge) ...
2747 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
2750 bci_action_serif_anchor_lower_bound
,
2755 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2761 ADD
, /* s: edge[-1] edge edge_orig */
2763 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2766 ALIGNRP
, /* align `edge' with `edge_orig' */
2767 MDAP_round
, /* round `edge' */
2769 SWAP
, /* s: edge edge[-1] */
2771 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2776 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
2777 GT
, /* edge_pos < edge[-1]_pos */
2780 ALIGNRP
, /* align `edge' to `edge[-1]' */
2783 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2788 SZP1
, /* set zp1 to normal zone 1 */
2797 * bci_action_serif_anchor_upper_bound
2799 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2800 * anchor, then moving it again if necessary to stay within an upper
2803 * in: edge_point (in twilight zone)
2804 * edge[1] (in twilight zone)
2805 * ... stuff for bci_align_segments (edge) ...
2808 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
2811 bci_action_serif_anchor_upper_bound
,
2816 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2822 ADD
, /* s: edge[1] edge edge_orig */
2824 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2827 ALIGNRP
, /* align `edge' with `edge_orig' */
2828 MDAP_round
, /* round `edge' */
2830 SWAP
, /* s: edge edge[1] */
2832 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2837 GC_cur
, /* s: edge edge[1]_pos edge_pos */
2838 LT
, /* edge_pos > edge[1]_pos */
2841 ALIGNRP
, /* align `edge' to `edge[1]' */
2844 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2849 SZP1
, /* set zp1 to normal zone 1 */
2858 * bci_action_serif_anchor_lower_upper_bound
2860 * Handle the SERIF_ANCHOR action to align a serif and to set the edge
2861 * anchor, then moving it again if necessary to stay within a lower and
2864 * in: edge_point (in twilight zone)
2865 * edge[-1] (in twilight zone)
2866 * edge[1] (in twilight zone)
2867 * ... stuff for bci_align_segments (edge) ...
2870 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
2873 bci_action_serif_anchor_lower_upper_bound
,
2878 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2884 ADD
, /* s: edge[1] edge[-1] edge edge_orig */
2886 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
2889 ALIGNRP
, /* align `edge' with `edge_orig' */
2890 MDAP_round
, /* round `edge' */
2892 SWAP
, /* s: edge[1] edge edge[-1] */
2894 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
2899 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
2900 GT
, /* edge_pos < edge[-1]_pos */
2903 ALIGNRP
, /* align `edge' to `edge[-1]' */
2906 SWAP
, /* s: edge edge[1] */
2908 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
2913 GC_cur
, /* s: edge edge[1]_pos edge_pos */
2914 LT
, /* edge_pos > edge[1]_pos */
2917 ALIGNRP
, /* align `edge' to `edge[1]' */
2920 MDAP_noround
, /* set rp0 and rp1 to `edge' */
2925 SZP1
, /* set zp1 to normal zone 1 */
2934 * bci_action_serif_link1
2936 * Handle the SERIF_LINK1 action to align a serif, depending on edges
2939 * in: before_point (in twilight zone)
2940 * edge_point (in twilight zone)
2941 * after_point (in twilight zone)
2942 * ... stuff for bci_align_segments (edge) ...
2945 unsigned char FPGM(bci_action_serif_link1
) [] = {
2948 bci_action_serif_link1
,
2953 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2961 ADD
, /* s: after edge before after_orig */
2968 ADD
, /* s: after edge before after_orig before_orig */
2972 EQ
, /* after_orig_pos == before_orig_pos */
2973 IF
, /* s: after edge before */
2974 MDAP_noround
, /* set rp0 and rp1 to `before' */
2976 ALIGNRP
, /* align `edge' with `before' */
2987 ADD
, /* s: ... after edge before edge_orig */
2994 ADD
, /* s: ... after edge before edge_orig before_orig */
2995 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3003 CINDEX
, /* s: ... after edge before a*64 after */
3006 CINDEX
, /* s: ... after edge before a*64 after before */
3007 MD_cur
, /* b = after_pos - before_pos */
3008 MUL
, /* s: ... after edge before a*b */
3016 ADD
, /* s: ... after edge before a*b after_orig */
3023 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3024 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3030 DIV
, /* s: after edge before a*b/c */
3033 MDAP_noround
, /* set rp0 and rp1 to `before' */
3034 SWAP
, /* s: after a*b/c edge */
3037 ALIGNRP
, /* align `edge' with `before' */
3039 SHPIX
, /* shift `edge' by `a*b/c' */
3041 SWAP
, /* s: edge after */
3045 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3050 SZP1
, /* set zp1 to normal zone 1 */
3059 * bci_action_serif_link1_lower_bound
3061 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3062 * before and after. Additionally, move the serif again if necessary to
3063 * stay within a lower bound.
3065 * in: before_point (in twilight zone)
3066 * edge_point (in twilight zone)
3067 * after_point (in twilight zone)
3068 * edge[-1] (in twilight zone)
3069 * ... stuff for bci_align_segments (edge) ...
3072 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
3075 bci_action_serif_link1_lower_bound
,
3080 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3088 ADD
, /* s: edge[-1] after edge before after_orig */
3095 ADD
, /* s: edge[-1] after edge before after_orig before_orig */
3099 EQ
, /* after_orig_pos == before_orig_pos */
3100 IF
, /* s: edge[-1] after edge before */
3101 MDAP_noround
, /* set rp0 and rp1 to `before' */
3103 ALIGNRP
, /* align `edge' with `before' */
3114 ADD
, /* s: ... after edge before edge_orig */
3121 ADD
, /* s: ... after edge before edge_orig before_orig */
3122 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3130 CINDEX
, /* s: ... after edge before a*64 after */
3133 CINDEX
, /* s: ... after edge before a*64 after before */
3134 MD_cur
, /* b = after_pos - before_pos */
3135 MUL
, /* s: ... after edge before a*b */
3143 ADD
, /* s: ... after edge before a*b after_orig */
3150 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3151 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3157 DIV
, /* s: edge[-1] after edge before a*b/c */
3160 MDAP_noround
, /* set rp0 and rp1 to `before' */
3161 SWAP
, /* s: edge[-1] after a*b/c edge */
3164 ALIGNRP
, /* align `edge' with `before' */
3166 SHPIX
, /* shift `edge' by `a*b/c' */
3168 SWAP
, /* s: edge[-1] edge after */
3172 SWAP
, /* s: edge edge[-1] */
3174 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3179 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
3180 GT
, /* edge_pos < edge[-1]_pos */
3183 ALIGNRP
, /* align `edge' to `edge[-1]' */
3186 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3191 SZP1
, /* set zp1 to normal zone 1 */
3199 * bci_action_serif_link1_upper_bound
3201 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3202 * before and after. Additionally, move the serif again if necessary to
3203 * stay within an upper bound.
3205 * in: before_point (in twilight zone)
3206 * edge_point (in twilight zone)
3207 * after_point (in twilight zone)
3208 * edge[1] (in twilight zone)
3209 * ... stuff for bci_align_segments (edge) ...
3212 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
3215 bci_action_serif_link1_upper_bound
,
3220 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3228 ADD
, /* s: edge[1] after edge before after_orig */
3235 ADD
, /* s: edge[1] after edge before after_orig before_orig */
3239 EQ
, /* after_orig_pos == before_orig_pos */
3240 IF
, /* s: edge[1] after edge before */
3241 MDAP_noround
, /* set rp0 and rp1 to `before' */
3243 ALIGNRP
, /* align `edge' with `before' */
3254 ADD
, /* s: ... after edge before edge_orig */
3261 ADD
, /* s: ... after edge before edge_orig before_orig */
3262 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3270 CINDEX
, /* s: ... after edge before a*64 after */
3273 CINDEX
, /* s: ... after edge before a*64 after before */
3274 MD_cur
, /* b = after_pos - before_pos */
3275 MUL
, /* s: ... after edge before a*b */
3283 ADD
, /* s: ... after edge before a*b after_orig */
3290 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3291 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3297 DIV
, /* s: edge[1] after edge before a*b/c */
3300 MDAP_noround
, /* set rp0 and rp1 to `before' */
3301 SWAP
, /* s: edge[1] after a*b/c edge */
3304 ALIGNRP
, /* align `edge' with `before' */
3306 SHPIX
, /* shift `edge' by `a*b/c' */
3308 SWAP
, /* s: edge[1] edge after */
3312 SWAP
, /* s: edge edge[1] */
3314 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3319 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3320 LT
, /* edge_pos > edge[1]_pos */
3323 ALIGNRP
, /* align `edge' to `edge[1]' */
3326 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3331 SZP1
, /* set zp1 to normal zone 1 */
3340 * bci_action_serif_link1_lower_upper_bound
3342 * Handle the SERIF_LINK1 action to align a serif, depending on edges
3343 * before and after. Additionally, move the serif again if necessary to
3344 * stay within a lower and upper bound.
3346 * in: before_point (in twilight zone)
3347 * edge_point (in twilight zone)
3348 * after_point (in twilight zone)
3349 * edge[-1] (in twilight zone)
3350 * edge[1] (in twilight zone)
3351 * ... stuff for bci_align_segments (edge) ...
3354 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
3357 bci_action_serif_link1_lower_upper_bound
,
3362 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
3370 ADD
, /* s: edge[1] edge[-1] after edge before after_orig */
3377 ADD
, /* s: edge[1] edge[-1] after edge before after_orig before_orig */
3381 EQ
, /* after_orig_pos == before_orig_pos */
3382 IF
, /* s: edge[1] edge[-1] after edge before */
3383 MDAP_noround
, /* set rp0 and rp1 to `before' */
3385 ALIGNRP
, /* align `edge' with `before' */
3396 ADD
, /* s: ... after edge before edge_orig */
3403 ADD
, /* s: ... after edge before edge_orig before_orig */
3404 MD_cur
, /* a = edge_orig_pos - before_orig_pos */
3412 CINDEX
, /* s: ... after edge before a*64 after */
3415 CINDEX
, /* s: ... after edge before a*64 after before */
3416 MD_cur
, /* b = after_pos - before_pos */
3417 MUL
, /* s: ... after edge before a*b */
3425 ADD
, /* s: ... after edge before a*b after_orig */
3432 ADD
, /* s: ... after edge before a*b after_orig before_orig */
3433 MD_cur
, /* c = after_orig_pos - before_orig_pos */
3439 DIV
, /* s: edge[1] edge[-1] after edge before a*b/c */
3442 MDAP_noround
, /* set rp0 and rp1 to `before' */
3443 SWAP
, /* s: edge[1] edge[-1] after a*b/c edge */
3446 ALIGNRP
, /* align `edge' with `before' */
3448 SHPIX
, /* shift `edge' by `a*b/c' */
3450 SWAP
, /* s: edge[1] edge[-1] edge after */
3454 SWAP
, /* s: edge[1] edge edge[-1] */
3456 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
3461 GC_cur
, /* s: edge[1] edge edge[-1]_pos edge_pos */
3462 GT
, /* edge_pos < edge[-1]_pos */
3465 ALIGNRP
, /* align `edge' to `edge[-1]' */
3468 SWAP
, /* s: edge edge[1] */
3470 MDAP_noround
, /* set rp0 and rp1 to `edge[1]' */
3475 GC_cur
, /* s: edge edge[1]_pos edge_pos */
3476 LT
, /* edge_pos > edge[1]_pos */
3479 ALIGNRP
, /* align `edge' to `edge[1]' */
3482 MDAP_noround
, /* set rp0 and rp1 to `edge' */
3487 SZP1
, /* set zp1 to normal zone 1 */
3494 unsigned char FPGM(bci_action_serif_link2
) [] = {
3497 bci_action_serif_link2
,
3501 bci_handle_segments
,
3510 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
3513 bci_action_serif_link2_lower_bound
,
3517 bci_handle_segments
,
3526 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
3529 bci_action_serif_link2_upper_bound
,
3533 bci_handle_segments
,
3542 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
3545 bci_action_serif_link2_lower_upper_bound
,
3549 bci_handle_segments
,
3564 * in: function_index
3567 unsigned char FPGM(bci_handle_action
) [] = {
3583 * This is the top-level glyph hinting function
3584 * which parses the arguments on the stack and calls subroutines.
3586 * in: num_actions (M)
3595 * uses: bci_handle_action
3596 * bci_action_adjust_bound
3597 * bci_action_stem_bound
3601 * bci_action_blue_anchor
3607 * bci_action_serif_anchor
3608 * bci_action_serif_link1
3609 * bci_action_serif_link2
3612 unsigned char FPGM(bci_hint_glyph
) [] = {
3627 #define COPY_FPGM(func_name) \
3628 memcpy(buf_p, fpgm_ ## func_name, \
3629 sizeof (fpgm_ ## func_name)); \
3630 buf_p += sizeof (fpgm_ ## func_name) \
3633 TA_table_build_fpgm(FT_Byte
** fpgm
,
3643 buf_len
= sizeof (FPGM(bci_round
))
3644 + sizeof (FPGM(bci_compute_stem_width_a
))
3646 + sizeof (FPGM(bci_compute_stem_width_b
))
3648 + sizeof (FPGM(bci_compute_stem_width_c
))
3649 + sizeof (FPGM(bci_loop
))
3650 + sizeof (FPGM(bci_cvt_rescale
))
3651 + sizeof (FPGM(bci_blue_round_a
))
3653 + sizeof (FPGM(bci_blue_round_b
))
3654 + sizeof (FPGM(bci_get_point_extrema
))
3655 + sizeof (FPGM(bci_create_segment
))
3656 + sizeof (FPGM(bci_create_segments
))
3657 + sizeof (FPGM(bci_handle_segment
))
3658 + sizeof (FPGM(bci_align_segment
))
3659 + sizeof (FPGM(bci_handle_segments
))
3660 + sizeof (FPGM(bci_align_segments
))
3661 + sizeof (FPGM(bci_action_adjust_bound
))
3662 + sizeof (FPGM(bci_action_stem_bound
))
3663 + sizeof (FPGM(bci_action_link
))
3664 + sizeof (FPGM(bci_action_anchor
))
3665 + sizeof (FPGM(bci_action_blue_anchor
))
3666 + sizeof (FPGM(bci_action_adjust
))
3667 + sizeof (FPGM(bci_action_stem
))
3668 + sizeof (FPGM(bci_action_blue
))
3669 + sizeof (FPGM(bci_action_serif
))
3670 + sizeof (FPGM(bci_action_serif_lower_bound
))
3671 + sizeof (FPGM(bci_action_serif_upper_bound
))
3672 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
3673 + sizeof (FPGM(bci_action_serif_anchor
))
3674 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
3675 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
3676 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3677 + sizeof (FPGM(bci_action_serif_link1
))
3678 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3679 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3680 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3681 + sizeof (FPGM(bci_action_serif_link2
))
3682 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3683 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3684 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3685 + sizeof (FPGM(bci_handle_action
))
3686 + sizeof (FPGM(bci_hint_glyph
));
3687 /* buffer length must be a multiple of four */
3688 len
= (buf_len
+ 3) & ~3;
3689 buf
= (FT_Byte
*)malloc(len
);
3691 return FT_Err_Out_Of_Memory
;
3693 /* pad end of buffer with zeros */
3694 buf
[len
- 1] = 0x00;
3695 buf
[len
- 2] = 0x00;
3696 buf
[len
- 3] = 0x00;
3698 /* copy font program into buffer and fill in the missing variables */
3701 COPY_FPGM(bci_round
);
3702 COPY_FPGM(bci_compute_stem_width_a
);
3703 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3704 COPY_FPGM(bci_compute_stem_width_b
);
3705 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3706 COPY_FPGM(bci_compute_stem_width_c
);
3707 COPY_FPGM(bci_loop
);
3708 COPY_FPGM(bci_cvt_rescale
);
3709 COPY_FPGM(bci_blue_round_a
);
3710 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
3711 COPY_FPGM(bci_blue_round_b
);
3712 COPY_FPGM(bci_get_point_extrema
);
3713 COPY_FPGM(bci_create_segment
);
3714 COPY_FPGM(bci_create_segments
);
3715 COPY_FPGM(bci_handle_segment
);
3716 COPY_FPGM(bci_align_segment
);
3717 COPY_FPGM(bci_handle_segments
);
3718 COPY_FPGM(bci_align_segments
);
3719 COPY_FPGM(bci_action_adjust_bound
);
3720 COPY_FPGM(bci_action_stem_bound
);
3721 COPY_FPGM(bci_action_link
);
3722 COPY_FPGM(bci_action_anchor
);
3723 COPY_FPGM(bci_action_blue_anchor
);
3724 COPY_FPGM(bci_action_adjust
);
3725 COPY_FPGM(bci_action_stem
);
3726 COPY_FPGM(bci_action_blue
);
3727 COPY_FPGM(bci_action_serif
);
3728 COPY_FPGM(bci_action_serif_lower_bound
);
3729 COPY_FPGM(bci_action_serif_upper_bound
);
3730 COPY_FPGM(bci_action_serif_lower_upper_bound
);
3731 COPY_FPGM(bci_action_serif_anchor
);
3732 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
3733 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
3734 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
3735 COPY_FPGM(bci_action_serif_link1
);
3736 COPY_FPGM(bci_action_serif_link1_lower_bound
);
3737 COPY_FPGM(bci_action_serif_link1_upper_bound
);
3738 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
3739 COPY_FPGM(bci_action_serif_link2
);
3740 COPY_FPGM(bci_action_serif_link2_lower_bound
);
3741 COPY_FPGM(bci_action_serif_link2_upper_bound
);
3742 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
3743 COPY_FPGM(bci_handle_action
);
3744 COPY_FPGM(bci_hint_glyph
);
3747 *fpgm_len
= buf_len
;
3754 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
3763 error
= TA_sfnt_add_table_info(sfnt
);
3767 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
3771 /* in case of success, `fpgm_buf' gets linked */
3772 /* and is eventually freed in `TA_font_unload' */
3773 error
= TA_font_add_table(font
,
3774 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3775 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
3786 /* the `prep' instructions */
3788 #define PREP(snippet_name) prep_ ## snippet_name
3790 /* we often need 0x10000 which can't be pushed directly onto the stack, */
3791 /* thus we provide it in the storage area */
3793 unsigned char PREP(store_0x10000
) [] = {
3807 unsigned char PREP(align_top_a
) [] = {
3809 /* optimize the alignment of the top of small letters to the pixel grid */
3815 /* %c, index of alignment blue zone */
3817 unsigned char PREP(align_top_b
) [] = {
3825 FLOOR
, /* fitted = FLOOR(scaled + 40) */
3826 DUP
, /* s: scaled scaled fitted fitted */
3829 IF
, /* s: scaled fitted */
3833 MUL
, /* scaled in 16.16 format */
3835 DIV
, /* (fitted / scaled) in 16.16 format */
3844 unsigned char PREP(loop_cvt_a
) [] = {
3846 /* loop over vertical CVT entries */
3851 /* %c, first vertical index */
3852 /* %c, last vertical index */
3854 unsigned char PREP(loop_cvt_b
) [] = {
3860 /* loop over blue refs */
3865 /* %c, first blue ref index */
3866 /* %c, last blue ref index */
3868 unsigned char PREP(loop_cvt_c
) [] = {
3874 /* loop over blue shoots */
3879 /* %c, first blue shoot index */
3880 /* %c, last blue shoot index */
3882 unsigned char PREP(loop_cvt_d
) [] = {
3891 unsigned char PREP(compute_extra_light_a
) [] = {
3893 /* compute (vertical) `extra_light' flag */
3900 /* %c, index of vertical standard_width */
3902 unsigned char PREP(compute_extra_light_b
) [] = {
3905 GT
, /* standard_width < 40 */
3910 unsigned char PREP(round_blues_a
) [] = {
3912 /* use discrete values for blue zone widths */
3917 /* %c, first blue ref index */
3918 /* %c, last blue ref index */
3920 unsigned char PREP(round_blues_b
) [] = {
3928 /* XXX talatin.c: 1671 */
3929 /* XXX talatin.c: 1708 */
3930 /* XXX talatin.c: 2182 */
3933 #define COPY_PREP(snippet_name) \
3934 memcpy(buf_p, prep_ ## snippet_name, \
3935 sizeof (prep_ ## snippet_name)); \
3936 buf_p += sizeof (prep_ ## snippet_name);
3939 TA_table_build_prep(FT_Byte
** prep
,
3944 TA_LatinBlue blue_adjustment
;
3953 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
3954 blue_adjustment
= NULL
;
3956 for (i
= 0; i
< vaxis
->blue_count
; i
++)
3958 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
3960 blue_adjustment
= &vaxis
->blues
[i
];
3965 buf_len
= sizeof (PREP(store_0x10000
));
3967 if (blue_adjustment
)
3968 buf_len
+= sizeof (PREP(align_top_a
))
3970 + sizeof (PREP(align_top_b
))
3971 + sizeof (PREP(loop_cvt_a
))
3973 + sizeof (PREP(loop_cvt_b
))
3975 + sizeof (PREP(loop_cvt_c
))
3977 + sizeof (PREP(loop_cvt_d
));
3979 buf_len
+= sizeof (PREP(compute_extra_light_a
))
3981 + sizeof (PREP(compute_extra_light_b
));
3983 if (CVT_BLUES_SIZE(font
))
3984 buf_len
+= sizeof (PREP(round_blues_a
))
3986 + sizeof (PREP(round_blues_b
));
3988 /* buffer length must be a multiple of four */
3989 len
= (buf_len
+ 3) & ~3;
3990 buf
= (FT_Byte
*)malloc(len
);
3992 return FT_Err_Out_Of_Memory
;
3994 /* pad end of buffer with zeros */
3995 buf
[len
- 1] = 0x00;
3996 buf
[len
- 2] = 0x00;
3997 buf
[len
- 3] = 0x00;
3999 /* copy cvt program into buffer and fill in the missing variables */
4002 COPY_PREP(store_0x10000
);
4004 if (blue_adjustment
)
4006 COPY_PREP(align_top_a
);
4007 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
4008 + blue_adjustment
- vaxis
->blues
);
4009 COPY_PREP(align_top_b
);
4011 COPY_PREP(loop_cvt_a
);
4012 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
4013 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
4014 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
4015 COPY_PREP(loop_cvt_b
);
4016 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
4017 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
4018 + CVT_BLUES_SIZE(font
) - 1);
4019 COPY_PREP(loop_cvt_c
);
4020 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
4021 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
4022 + CVT_BLUES_SIZE(font
) - 1);
4023 COPY_PREP(loop_cvt_d
);
4026 COPY_PREP(compute_extra_light_a
);
4027 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
4028 COPY_PREP(compute_extra_light_b
);
4030 if (CVT_BLUES_SIZE(font
))
4032 COPY_PREP(round_blues_a
);
4033 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
4034 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
4035 + CVT_BLUES_SIZE(font
) - 1);
4036 COPY_PREP(round_blues_b
);
4040 *prep_len
= buf_len
;
4047 TA_sfnt_build_prep_table(SFNT
* sfnt
,
4056 error
= TA_sfnt_add_table_info(sfnt
);
4060 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
4064 /* in case of success, `prep_buf' gets linked */
4065 /* and is eventually freed in `TA_font_unload' */
4066 error
= TA_font_add_table(font
,
4067 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
4068 TTAG_prep
, prep_len
, prep_buf
);
4079 /* we store the segments in the storage area; */
4080 /* each segment record consists of the first and last point */
4083 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
4087 FONT
* font
= recorder
->font
;
4088 TA_GlyphHints hints
= &font
->loader
->hints
;
4089 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
4090 TA_Point points
= hints
->points
;
4091 TA_Segment segments
= axis
->segments
;
4093 TA_Segment seg_limit
;
4095 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
4101 FT_UInt num_segments
;
4103 FT_UInt
* wrap_around_segment
;
4104 FT_UInt num_wrap_around_segments
;
4106 FT_Bool need_words
= 0;
4110 FT_UInt num_storage
;
4111 FT_UInt num_stack_elements
;
4112 FT_UInt num_twilight_points
;
4115 seg_limit
= segments
+ axis
->num_segments
;
4116 num_segments
= axis
->num_segments
;
4118 /* some segments can `wrap around' */
4119 /* a contour's start point like 24-25-26-0-1-2 */
4120 /* (there can be at most one such segment per contour); */
4121 /* we thus append additional records to split them into 24-26 and 0-2 */
4122 wrap_around_segment
= recorder
->wrap_around_segments
;
4123 for (seg
= segments
; seg
< seg_limit
; seg
++)
4124 if (seg
->first
> seg
->last
)
4126 /* the stored data is used later for edge linking */
4127 *(wrap_around_segment
++) = seg
- segments
;
4130 num_wrap_around_segments
= wrap_around_segment
4131 - recorder
->wrap_around_segments
;
4132 num_segments
+= num_wrap_around_segments
;
4134 /* wrap-around segments are pushed with four arguments */
4135 num_args
= 2 * num_segments
+ 2 * num_wrap_around_segments
+ 2;
4137 /* collect all arguments temporarily in an array (in reverse order) */
4138 /* so that we can easily split into chunks of 255 args */
4139 /* as needed by NPUSHB and NPUSHW, respectively */
4140 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
4144 arg
= args
+ num_args
- 1;
4146 if (num_segments
> 0xFF)
4149 *(arg
--) = bci_create_segments
;
4150 *(arg
--) = num_segments
;
4152 for (seg
= segments
; seg
< seg_limit
; seg
++)
4154 FT_UInt first
= seg
->first
- points
;
4155 FT_UInt last
= seg
->last
- points
;
4161 /* we push the last and first contour point */
4162 /* as a third and fourth argument in wrap-around segments */
4165 for (n
= 0; n
< outline
.n_contours
; n
++)
4167 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
4179 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
4189 /* emit the second part of wrap-around segments as separate segments */
4190 /* so that edges can easily link to them */
4191 for (seg
= segments
; seg
< seg_limit
; seg
++)
4193 FT_UInt first
= seg
->first
- points
;
4194 FT_UInt last
= seg
->last
- points
;
4199 for (n
= 0; n
< outline
.n_contours
; n
++)
4201 if (first
<= (FT_UInt
)outline
.contours
[n
])
4206 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
4214 /* with most fonts it is very rare */
4215 /* that any of the pushed arguments is larger than 0xFF, */
4216 /* thus we refrain from further optimizing this case */
4222 for (i
= 0; i
< num_args
; i
+= 255)
4224 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
4228 for (j
= 0; j
< nargs
; j
++)
4238 for (i
= 0; i
< num_args
; i
+= 255)
4240 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
4244 for (j
= 0; j
< nargs
; j
++)
4254 num_storage
= sal_segment_offset
+ num_segments
* 2;
4255 if (num_storage
> sfnt
->max_storage
)
4256 sfnt
->max_storage
= num_storage
;
4258 num_twilight_points
= num_segments
* 2;
4259 if (num_twilight_points
> sfnt
->max_twilight_points
)
4260 sfnt
->max_twilight_points
= num_twilight_points
;
4262 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
4263 if (num_stack_elements
> sfnt
->max_stack_elements
)
4264 sfnt
->max_stack_elements
= num_stack_elements
;
4273 TA_hints_record_is_different(Hints_Record
* hints_records
,
4274 FT_UInt num_hints_records
,
4278 Hints_Record last_hints_record
;
4284 /* we only need to compare with the last hints record */
4285 last_hints_record
= hints_records
[num_hints_records
- 1];
4287 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
4290 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
4298 TA_add_hints_record(Hints_Record
** hints_records
,
4299 FT_UInt
* num_hints_records
,
4301 Hints_Record hints_record
)
4303 Hints_Record
* hints_records_new
;
4305 /* at this point, `hints_record.buf' still points into `ins_buf' */
4306 FT_Byte
* end
= hints_record
.buf
;
4309 buf_len
= (FT_UInt
)(end
- start
);
4311 /* now fill the structure completely */
4312 hints_record
.buf_len
= buf_len
;
4313 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
4314 if (!hints_record
.buf
)
4315 return FT_Err_Out_Of_Memory
;
4317 memcpy(hints_record
.buf
, start
, buf_len
);
4319 (*num_hints_records
)++;
4321 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
4322 * sizeof (Hints_Record
));
4323 if (!hints_records_new
)
4325 free(hints_record
.buf
);
4326 (*num_hints_records
)--;
4327 return FT_Err_Out_Of_Memory
;
4330 *hints_records
= hints_records_new
;
4332 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
4339 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
4340 Hints_Record
* hints_record
,
4345 FT_Bool need_words
= 0;
4348 FT_UInt num_arguments
;
4350 FT_UInt num_stack_elements
;
4353 /* check whether any argument is larger than 0xFF */
4354 endp
= hints_record
->buf
+ hints_record
->buf_len
;
4355 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
4359 /* with most fonts it is very rare */
4360 /* that any of the pushed arguments is larger than 0xFF, */
4361 /* thus we refrain from further optimizing this case */
4363 num_arguments
= hints_record
->buf_len
/ 2;
4368 for (i
= 0; i
< num_arguments
; i
+= 255)
4370 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
4374 for (j
= 0; j
< num_args
; j
++)
4384 /* we only need the lower bytes */
4387 for (i
= 0; i
< num_arguments
; i
+= 255)
4389 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
4393 for (j
= 0; j
< num_args
; j
++)
4401 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
4402 if (num_stack_elements
> sfnt
->max_stack_elements
)
4403 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
4410 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
4411 Hints_Record
* hints_records
,
4412 FT_UInt num_hints_records
,
4416 Hints_Record
* hints_record
;
4419 hints_record
= hints_records
;
4421 for (i
= 0; i
< num_hints_records
- 1; i
++)
4424 if (hints_record
->size
> 0xFF)
4427 BCI(HIGH((hints_record
+ 1)->size
));
4428 BCI(LOW((hints_record
+ 1)->size
));
4433 BCI((hints_record
+ 1)->size
);
4437 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
4443 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
4445 for (i
= 0; i
< num_hints_records
- 1; i
++)
4449 BCI(bci_hint_glyph
);
4457 TA_free_hints_records(Hints_Record
* hints_records
,
4458 FT_UInt num_hints_records
)
4463 for (i
= 0; i
< num_hints_records
; i
++)
4464 free(hints_records
[i
].buf
);
4466 free(hints_records
);
4471 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
4476 TA_Segment segments
= axis
->segments
;
4479 FT_UInt num_segs
= 0;
4483 seg_idx
= edge
->first
- segments
;
4485 /* we store everything as 16bit numbers */
4486 *(bufp
++) = HIGH(seg_idx
);
4487 *(bufp
++) = LOW(seg_idx
);
4489 /* wrap-around segments are stored as two segments */
4490 if (edge
->first
->first
> edge
->first
->last
)
4493 seg
= edge
->first
->edge_next
;
4494 while (seg
!= edge
->first
)
4498 if (seg
->first
> seg
->last
)
4501 seg
= seg
->edge_next
;
4504 *(bufp
++) = HIGH(num_segs
);
4505 *(bufp
++) = LOW(num_segs
);
4507 if (edge
->first
->first
> edge
->first
->last
)
4509 /* emit second part of wrap-around segment; */
4510 /* the bytecode positions such segments after `normal' ones */
4514 if (seg_idx
== *wrap
)
4519 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
4520 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
4523 seg
= edge
->first
->edge_next
;
4524 while (seg
!= edge
->first
)
4526 seg_idx
= seg
- segments
;
4528 *(bufp
++) = HIGH(seg_idx
);
4529 *(bufp
++) = LOW(seg_idx
);
4531 if (seg
->first
> seg
->last
)
4536 if (seg_idx
== *wrap
)
4541 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
4542 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
4545 seg
= seg
->edge_next
;
4553 TA_hints_recorder(TA_Action action
,
4554 TA_GlyphHints hints
,
4559 TA_Edge lower_bound
,
4560 TA_Edge upper_bound
)
4562 TA_AxisHints axis
= &hints
->axis
[dim
];
4563 TA_Segment segments
= axis
->segments
;
4565 Recorder
* recorder
= (Recorder
*)hints
->user
;
4566 FONT
* font
= recorder
->font
;
4567 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
4568 FT_Byte
* p
= recorder
->hints_record
.buf
;
4570 FT_Byte bound_offset
= 0;
4573 if (dim
== TA_DIMENSION_HORZ
)
4576 /* we ignore the BOUND action since we signal this information */
4577 /* with the `bound_offset' parameter */
4578 if (action
== ta_bound
)
4586 /* this reflects the order in the TA_Action enumeration */
4588 *(p
++) = (FT_Byte
)action
+ bound_offset
+ ACTION_OFFSET
;
4594 TA_Edge base_edge
= arg1
;
4595 TA_Edge stem_edge
= arg2
;
4599 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
4601 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
4602 *(p
++) = HIGH(base_edge
->first
- segments
);
4603 *(p
++) = LOW(base_edge
->first
- segments
);
4604 *(p
++) = HIGH(stem_edge
->first
- segments
);
4605 *(p
++) = LOW(stem_edge
->first
- segments
);
4607 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
4613 TA_Edge edge
= arg1
;
4614 TA_Edge edge2
= arg2
;
4618 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
4620 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
4621 *(p
++) = HIGH(edge
->first
- segments
);
4622 *(p
++) = LOW(edge
->first
- segments
);
4623 *(p
++) = HIGH(edge2
->first
- segments
);
4624 *(p
++) = LOW(edge2
->first
- segments
);
4626 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4632 TA_Edge edge
= arg1
;
4633 TA_Edge edge2
= arg2
;
4634 TA_Edge edge_minus_one
= lower_bound
;
4638 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
4640 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
4641 *(p
++) = HIGH(edge
->first
- segments
);
4642 *(p
++) = LOW(edge
->first
- segments
);
4643 *(p
++) = HIGH(edge2
->first
- segments
);
4644 *(p
++) = LOW(edge2
->first
- segments
);
4648 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
4649 *(p
++) = LOW(edge_minus_one
->first
- segments
);
4652 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4656 case ta_blue_anchor
:
4658 TA_Edge edge
= arg1
;
4659 TA_Edge blue
= arg2
;
4662 *(p
++) = HIGH(blue
->first
- segments
);
4663 *(p
++) = LOW(blue
->first
- segments
);
4665 if (edge
->best_blue_is_shoot
)
4667 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4668 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4672 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4673 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4676 *(p
++) = HIGH(edge
->first
- segments
);
4677 *(p
++) = LOW(edge
->first
- segments
);
4679 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4685 TA_Edge edge
= arg1
;
4686 TA_Edge edge2
= arg2
;
4687 TA_Edge edge_minus_one
= lower_bound
;
4691 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
4693 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
4694 *(p
++) = HIGH(edge
->first
- segments
);
4695 *(p
++) = LOW(edge
->first
- segments
);
4696 *(p
++) = HIGH(edge2
->first
- segments
);
4697 *(p
++) = LOW(edge2
->first
- segments
);
4701 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
4702 *(p
++) = LOW(edge_minus_one
->first
- segments
);
4705 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4706 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
4712 TA_Edge edge
= arg1
;
4715 if (edge
->best_blue_is_shoot
)
4717 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4718 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4722 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4723 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4726 *(p
++) = HIGH(edge
->first
- segments
);
4727 *(p
++) = LOW(edge
->first
- segments
);
4729 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4735 TA_Edge base
= arg1
->serif
;
4736 TA_Edge serif
= arg1
;
4739 *(p
++) = HIGH(serif
->first
- segments
);
4740 *(p
++) = LOW(serif
->first
- segments
);
4741 *(p
++) = HIGH(base
->first
- segments
);
4742 *(p
++) = LOW(base
->first
- segments
);
4746 *(p
++) = HIGH(lower_bound
->first
- segments
);
4747 *(p
++) = LOW(lower_bound
->first
- segments
);
4751 *(p
++) = HIGH(upper_bound
->first
- segments
);
4752 *(p
++) = LOW(upper_bound
->first
- segments
);
4755 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
4759 case ta_serif_anchor
:
4761 TA_Edge edge
= arg1
;
4764 *(p
++) = HIGH(edge
->first
- segments
);
4765 *(p
++) = LOW(edge
->first
- segments
);
4769 *(p
++) = HIGH(lower_bound
->first
- segments
);
4770 *(p
++) = LOW(lower_bound
->first
- segments
);
4774 *(p
++) = HIGH(upper_bound
->first
- segments
);
4775 *(p
++) = LOW(upper_bound
->first
- segments
);
4778 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4782 case ta_serif_link1
:
4784 TA_Edge edge
= arg1
;
4785 TA_Edge before
= arg2
;
4786 TA_Edge after
= arg3
;
4789 *(p
++) = HIGH(before
->first
- segments
);
4790 *(p
++) = LOW(before
->first
- segments
);
4791 *(p
++) = HIGH(edge
->first
- segments
);
4792 *(p
++) = LOW(edge
->first
- segments
);
4793 *(p
++) = HIGH(after
->first
- segments
);
4794 *(p
++) = LOW(after
->first
- segments
);
4798 *(p
++) = HIGH(lower_bound
->first
- segments
);
4799 *(p
++) = LOW(lower_bound
->first
- segments
);
4803 *(p
++) = HIGH(upper_bound
->first
- segments
);
4804 *(p
++) = LOW(upper_bound
->first
- segments
);
4807 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4811 case ta_serif_link2
:
4812 p
= TA_hints_recorder_handle_segments(p
, axis
, arg1
, wraps
);
4816 /* there are more cases in the enumeration */
4817 /* which are handled with the `bound_offset' parameter */
4821 recorder
->hints_record
.num_actions
++;
4822 recorder
->hints_record
.buf
= p
;
4827 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
4831 FT_Face face
= sfnt
->face
;
4838 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
4839 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
4840 GLYPH
* glyph
= &data
->glyphs
[idx
];
4842 TA_GlyphHints hints
;
4844 FT_UInt num_hints_records
;
4845 Hints_Record
* hints_records
;
4853 return FT_Err_Invalid_Argument
;
4855 /* computing the segments is resolution independent, */
4856 /* thus the pixel size in this call is arbitrary */
4857 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
4861 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
4862 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
4866 /* do nothing if we have an empty glyph */
4867 if (!face
->glyph
->outline
.n_contours
)
4870 /* do nothing if the dummy hinter has been used */
4871 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
4874 hints
= &font
->loader
->hints
;
4876 /* we allocate a buffer which is certainly large enough */
4877 /* to hold all of the created bytecode instructions; */
4878 /* later on it gets reallocated to its real size */
4879 ins_len
= hints
->num_points
* 1000;
4880 ins_buf
= (FT_Byte
*)malloc(ins_len
);
4882 return FT_Err_Out_Of_Memory
;
4884 /* initialize array with an invalid bytecode */
4885 /* so that we can easily find the array length at reallocation time */
4886 memset(ins_buf
, INS_A0
, ins_len
);
4888 recorder
.font
= font
;
4889 recorder
.wrap_around_segments
=
4890 (FT_UInt
*)malloc(face
->glyph
->outline
.n_contours
* sizeof (FT_UInt
));
4892 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
4894 /* now we loop over a large range of pixel sizes */
4895 /* to find hints records which get pushed onto the bytecode stack */
4896 num_hints_records
= 0;
4897 hints_records
= NULL
;
4900 printf("glyph %ld\n", idx
);
4903 /* we temporarily use `ins_buf' to record the current glyph hints, */
4904 /* leaving two bytes at the beginning so that the number of actions */
4905 /* can be inserted later on */
4906 ta_loader_register_hints_recorder(font
->loader
,
4910 for (size
= 8; size
<= 1000; size
++)
4912 /* rewind buffer pointer for recorder */
4913 recorder
.hints_record
.buf
= bufp
+ 2;
4914 recorder
.hints_record
.num_actions
= 0;
4915 recorder
.hints_record
.size
= size
;
4917 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
4921 /* calling `ta_loader_load_glyph' uses the */
4922 /* `TA_hints_recorder' function as a callback, */
4923 /* modifying `hints_record' */
4924 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
4928 /* store the number of actions in `ins_buf' */
4929 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
4930 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
4932 if (TA_hints_record_is_different(hints_records
,
4934 bufp
, recorder
.hints_record
.buf
))
4941 printf(" %d:\n", size
);
4942 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
4943 printf(" %2d", *p
* 256 + *(p
+ 1));
4948 error
= TA_add_hints_record(&hints_records
,
4950 bufp
, recorder
.hints_record
);
4956 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
4958 /* don't emit anything if we only have a single empty record */
4966 /* otherwise, clear the temporarily used part of `ins_buf' */
4967 while (*p
!= INS_A0
)
4970 bufp
= TA_sfnt_emit_hints_records(sfnt
,
4971 hints_records
, num_hints_records
,
4974 /* we are done, so reallocate the instruction array to its real size */
4975 if (*bufp
== INS_A0
)
4977 /* search backwards */
4978 while (*bufp
== INS_A0
)
4984 /* search forwards */
4985 while (*bufp
!= INS_A0
)
4989 ins_len
= bufp
- ins_buf
;
4992 if (ins_len
> sfnt
->max_instructions
)
4993 sfnt
->max_instructions
= ins_len
;
4995 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
4996 glyph
->ins_len
= ins_len
;
4998 TA_free_hints_records(hints_records
, num_hints_records
);
4999 free(recorder
.wrap_around_segments
);
5004 TA_free_hints_records(hints_records
, num_hints_records
);
5005 free(recorder
.wrap_around_segments
);
5013 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
5016 FT_Face face
= sfnt
->face
;
5021 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
5023 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
5031 /* end of tabytecode.c */