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 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 to stay within a 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 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 */
2689 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2692 bci_action_serif_anchor
,
2696 bci_handle_segments
,
2705 unsigned char FPGM(bci_action_serif_anchor_lower_bound
) [] = {
2708 bci_action_serif_anchor_lower_bound
,
2712 bci_handle_segments
,
2721 unsigned char FPGM(bci_action_serif_anchor_upper_bound
) [] = {
2724 bci_action_serif_anchor_upper_bound
,
2728 bci_handle_segments
,
2737 unsigned char FPGM(bci_action_serif_anchor_lower_upper_bound
) [] = {
2740 bci_action_serif_anchor_lower_upper_bound
,
2744 bci_handle_segments
,
2753 unsigned char FPGM(bci_action_serif_link1
) [] = {
2756 bci_action_serif_link1
,
2760 bci_handle_segments
,
2769 unsigned char FPGM(bci_action_serif_link1_lower_bound
) [] = {
2772 bci_action_serif_link1_lower_bound
,
2776 bci_handle_segments
,
2785 unsigned char FPGM(bci_action_serif_link1_upper_bound
) [] = {
2788 bci_action_serif_link1_upper_bound
,
2792 bci_handle_segments
,
2801 unsigned char FPGM(bci_action_serif_link1_lower_upper_bound
) [] = {
2804 bci_action_serif_link1_lower_upper_bound
,
2808 bci_handle_segments
,
2817 unsigned char FPGM(bci_action_serif_link2
) [] = {
2820 bci_action_serif_link2
,
2824 bci_handle_segments
,
2833 unsigned char FPGM(bci_action_serif_link2_lower_bound
) [] = {
2836 bci_action_serif_link2_lower_bound
,
2840 bci_handle_segments
,
2849 unsigned char FPGM(bci_action_serif_link2_upper_bound
) [] = {
2852 bci_action_serif_link2_upper_bound
,
2856 bci_handle_segments
,
2865 unsigned char FPGM(bci_action_serif_link2_lower_upper_bound
) [] = {
2868 bci_action_serif_link2_lower_upper_bound
,
2872 bci_handle_segments
,
2887 * in: function_index
2890 unsigned char FPGM(bci_handle_action
) [] = {
2906 * This is the top-level glyph hinting function
2907 * which parses the arguments on the stack and calls subroutines.
2909 * in: num_actions (M)
2918 * uses: bci_handle_action
2919 * bci_action_adjust_bound
2920 * bci_action_stem_bound
2924 * bci_action_blue_anchor
2930 * bci_action_serif_anchor
2931 * bci_action_serif_link1
2932 * bci_action_serif_link2
2935 unsigned char FPGM(bci_hint_glyph
) [] = {
2950 #define COPY_FPGM(func_name) \
2951 memcpy(buf_p, fpgm_ ## func_name, \
2952 sizeof (fpgm_ ## func_name)); \
2953 buf_p += sizeof (fpgm_ ## func_name) \
2956 TA_table_build_fpgm(FT_Byte
** fpgm
,
2966 buf_len
= sizeof (FPGM(bci_round
))
2967 + sizeof (FPGM(bci_compute_stem_width_a
))
2969 + sizeof (FPGM(bci_compute_stem_width_b
))
2971 + sizeof (FPGM(bci_compute_stem_width_c
))
2972 + sizeof (FPGM(bci_loop
))
2973 + sizeof (FPGM(bci_cvt_rescale
))
2974 + sizeof (FPGM(bci_blue_round_a
))
2976 + sizeof (FPGM(bci_blue_round_b
))
2977 + sizeof (FPGM(bci_get_point_extrema
))
2978 + sizeof (FPGM(bci_create_segment
))
2979 + sizeof (FPGM(bci_create_segments
))
2980 + sizeof (FPGM(bci_handle_segment
))
2981 + sizeof (FPGM(bci_align_segment
))
2982 + sizeof (FPGM(bci_handle_segments
))
2983 + sizeof (FPGM(bci_align_segments
))
2984 + sizeof (FPGM(bci_action_adjust_bound
))
2985 + sizeof (FPGM(bci_action_stem_bound
))
2986 + sizeof (FPGM(bci_action_link
))
2987 + sizeof (FPGM(bci_action_anchor
))
2988 + sizeof (FPGM(bci_action_blue_anchor
))
2989 + sizeof (FPGM(bci_action_adjust
))
2990 + sizeof (FPGM(bci_action_stem
))
2991 + sizeof (FPGM(bci_action_blue
))
2992 + sizeof (FPGM(bci_action_serif
))
2993 + sizeof (FPGM(bci_action_serif_lower_bound
))
2994 + sizeof (FPGM(bci_action_serif_upper_bound
))
2995 + sizeof (FPGM(bci_action_serif_lower_upper_bound
))
2996 + sizeof (FPGM(bci_action_serif_anchor
))
2997 + sizeof (FPGM(bci_action_serif_anchor_lower_bound
))
2998 + sizeof (FPGM(bci_action_serif_anchor_upper_bound
))
2999 + sizeof (FPGM(bci_action_serif_anchor_lower_upper_bound
))
3000 + sizeof (FPGM(bci_action_serif_link1
))
3001 + sizeof (FPGM(bci_action_serif_link1_lower_bound
))
3002 + sizeof (FPGM(bci_action_serif_link1_upper_bound
))
3003 + sizeof (FPGM(bci_action_serif_link1_lower_upper_bound
))
3004 + sizeof (FPGM(bci_action_serif_link2
))
3005 + sizeof (FPGM(bci_action_serif_link2_lower_bound
))
3006 + sizeof (FPGM(bci_action_serif_link2_upper_bound
))
3007 + sizeof (FPGM(bci_action_serif_link2_lower_upper_bound
))
3008 + sizeof (FPGM(bci_handle_action
))
3009 + sizeof (FPGM(bci_hint_glyph
));
3010 /* buffer length must be a multiple of four */
3011 len
= (buf_len
+ 3) & ~3;
3012 buf
= (FT_Byte
*)malloc(len
);
3014 return FT_Err_Out_Of_Memory
;
3016 /* pad end of buffer with zeros */
3017 buf
[len
- 1] = 0x00;
3018 buf
[len
- 2] = 0x00;
3019 buf
[len
- 3] = 0x00;
3021 /* copy font program into buffer and fill in the missing variables */
3024 COPY_FPGM(bci_round
);
3025 COPY_FPGM(bci_compute_stem_width_a
);
3026 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3027 COPY_FPGM(bci_compute_stem_width_b
);
3028 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3029 COPY_FPGM(bci_compute_stem_width_c
);
3030 COPY_FPGM(bci_loop
);
3031 COPY_FPGM(bci_cvt_rescale
);
3032 COPY_FPGM(bci_blue_round_a
);
3033 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
3034 COPY_FPGM(bci_blue_round_b
);
3035 COPY_FPGM(bci_get_point_extrema
);
3036 COPY_FPGM(bci_create_segment
);
3037 COPY_FPGM(bci_create_segments
);
3038 COPY_FPGM(bci_handle_segment
);
3039 COPY_FPGM(bci_align_segment
);
3040 COPY_FPGM(bci_handle_segments
);
3041 COPY_FPGM(bci_align_segments
);
3042 COPY_FPGM(bci_action_adjust_bound
);
3043 COPY_FPGM(bci_action_stem_bound
);
3044 COPY_FPGM(bci_action_link
);
3045 COPY_FPGM(bci_action_anchor
);
3046 COPY_FPGM(bci_action_blue_anchor
);
3047 COPY_FPGM(bci_action_adjust
);
3048 COPY_FPGM(bci_action_stem
);
3049 COPY_FPGM(bci_action_blue
);
3050 COPY_FPGM(bci_action_serif
);
3051 COPY_FPGM(bci_action_serif_lower_bound
);
3052 COPY_FPGM(bci_action_serif_upper_bound
);
3053 COPY_FPGM(bci_action_serif_lower_upper_bound
);
3054 COPY_FPGM(bci_action_serif_anchor
);
3055 COPY_FPGM(bci_action_serif_anchor_lower_bound
);
3056 COPY_FPGM(bci_action_serif_anchor_upper_bound
);
3057 COPY_FPGM(bci_action_serif_anchor_lower_upper_bound
);
3058 COPY_FPGM(bci_action_serif_link1
);
3059 COPY_FPGM(bci_action_serif_link1_lower_bound
);
3060 COPY_FPGM(bci_action_serif_link1_upper_bound
);
3061 COPY_FPGM(bci_action_serif_link1_lower_upper_bound
);
3062 COPY_FPGM(bci_action_serif_link2
);
3063 COPY_FPGM(bci_action_serif_link2_lower_bound
);
3064 COPY_FPGM(bci_action_serif_link2_upper_bound
);
3065 COPY_FPGM(bci_action_serif_link2_lower_upper_bound
);
3066 COPY_FPGM(bci_handle_action
);
3067 COPY_FPGM(bci_hint_glyph
);
3070 *fpgm_len
= buf_len
;
3077 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
3086 error
= TA_sfnt_add_table_info(sfnt
);
3090 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
3094 /* in case of success, `fpgm_buf' gets linked */
3095 /* and is eventually freed in `TA_font_unload' */
3096 error
= TA_font_add_table(font
,
3097 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3098 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
3109 /* the `prep' instructions */
3111 #define PREP(snippet_name) prep_ ## snippet_name
3113 /* we often need 0x10000 which can't be pushed directly onto the stack, */
3114 /* thus we provide it in the storage area */
3116 unsigned char PREP(store_0x10000
) [] = {
3130 unsigned char PREP(align_top_a
) [] = {
3132 /* optimize the alignment of the top of small letters to the pixel grid */
3138 /* %c, index of alignment blue zone */
3140 unsigned char PREP(align_top_b
) [] = {
3148 FLOOR
, /* fitted = FLOOR(scaled + 40) */
3149 DUP
, /* s: scaled scaled fitted fitted */
3152 IF
, /* s: scaled fitted */
3156 MUL
, /* scaled in 16.16 format */
3158 DIV
, /* (fitted / scaled) in 16.16 format */
3167 unsigned char PREP(loop_cvt_a
) [] = {
3169 /* loop over vertical CVT entries */
3174 /* %c, first vertical index */
3175 /* %c, last vertical index */
3177 unsigned char PREP(loop_cvt_b
) [] = {
3183 /* loop over blue refs */
3188 /* %c, first blue ref index */
3189 /* %c, last blue ref index */
3191 unsigned char PREP(loop_cvt_c
) [] = {
3197 /* loop over blue shoots */
3202 /* %c, first blue shoot index */
3203 /* %c, last blue shoot index */
3205 unsigned char PREP(loop_cvt_d
) [] = {
3214 unsigned char PREP(compute_extra_light_a
) [] = {
3216 /* compute (vertical) `extra_light' flag */
3223 /* %c, index of vertical standard_width */
3225 unsigned char PREP(compute_extra_light_b
) [] = {
3228 GT
, /* standard_width < 40 */
3233 unsigned char PREP(round_blues_a
) [] = {
3235 /* use discrete values for blue zone widths */
3240 /* %c, first blue ref index */
3241 /* %c, last blue ref index */
3243 unsigned char PREP(round_blues_b
) [] = {
3251 /* XXX talatin.c: 1671 */
3252 /* XXX talatin.c: 1708 */
3253 /* XXX talatin.c: 2182 */
3256 #define COPY_PREP(snippet_name) \
3257 memcpy(buf_p, prep_ ## snippet_name, \
3258 sizeof (prep_ ## snippet_name)); \
3259 buf_p += sizeof (prep_ ## snippet_name);
3262 TA_table_build_prep(FT_Byte
** prep
,
3267 TA_LatinBlue blue_adjustment
;
3276 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
3277 blue_adjustment
= NULL
;
3279 for (i
= 0; i
< vaxis
->blue_count
; i
++)
3281 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
3283 blue_adjustment
= &vaxis
->blues
[i
];
3288 buf_len
= sizeof (PREP(store_0x10000
));
3290 if (blue_adjustment
)
3291 buf_len
+= sizeof (PREP(align_top_a
))
3293 + sizeof (PREP(align_top_b
))
3294 + sizeof (PREP(loop_cvt_a
))
3296 + sizeof (PREP(loop_cvt_b
))
3298 + sizeof (PREP(loop_cvt_c
))
3300 + sizeof (PREP(loop_cvt_d
));
3302 buf_len
+= sizeof (PREP(compute_extra_light_a
))
3304 + sizeof (PREP(compute_extra_light_b
));
3306 if (CVT_BLUES_SIZE(font
))
3307 buf_len
+= sizeof (PREP(round_blues_a
))
3309 + sizeof (PREP(round_blues_b
));
3311 /* buffer length must be a multiple of four */
3312 len
= (buf_len
+ 3) & ~3;
3313 buf
= (FT_Byte
*)malloc(len
);
3315 return FT_Err_Out_Of_Memory
;
3317 /* pad end of buffer with zeros */
3318 buf
[len
- 1] = 0x00;
3319 buf
[len
- 2] = 0x00;
3320 buf
[len
- 3] = 0x00;
3322 /* copy cvt program into buffer and fill in the missing variables */
3325 COPY_PREP(store_0x10000
);
3327 if (blue_adjustment
)
3329 COPY_PREP(align_top_a
);
3330 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
3331 + blue_adjustment
- vaxis
->blues
);
3332 COPY_PREP(align_top_b
);
3334 COPY_PREP(loop_cvt_a
);
3335 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
3336 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
3337 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
3338 COPY_PREP(loop_cvt_b
);
3339 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
3340 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
3341 + CVT_BLUES_SIZE(font
) - 1);
3342 COPY_PREP(loop_cvt_c
);
3343 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
3344 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
3345 + CVT_BLUES_SIZE(font
) - 1);
3346 COPY_PREP(loop_cvt_d
);
3349 COPY_PREP(compute_extra_light_a
);
3350 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
3351 COPY_PREP(compute_extra_light_b
);
3353 if (CVT_BLUES_SIZE(font
))
3355 COPY_PREP(round_blues_a
);
3356 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
3357 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
3358 + CVT_BLUES_SIZE(font
) - 1);
3359 COPY_PREP(round_blues_b
);
3363 *prep_len
= buf_len
;
3370 TA_sfnt_build_prep_table(SFNT
* sfnt
,
3379 error
= TA_sfnt_add_table_info(sfnt
);
3383 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
3387 /* in case of success, `prep_buf' gets linked */
3388 /* and is eventually freed in `TA_font_unload' */
3389 error
= TA_font_add_table(font
,
3390 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
3391 TTAG_prep
, prep_len
, prep_buf
);
3402 /* we store the segments in the storage area; */
3403 /* each segment record consists of the first and last point */
3406 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
3410 FONT
* font
= recorder
->font
;
3411 TA_GlyphHints hints
= &font
->loader
->hints
;
3412 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
3413 TA_Point points
= hints
->points
;
3414 TA_Segment segments
= axis
->segments
;
3416 TA_Segment seg_limit
;
3418 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
3424 FT_UInt num_segments
;
3426 FT_UInt
* wrap_around_segment
;
3427 FT_UInt num_wrap_around_segments
;
3429 FT_Bool need_words
= 0;
3433 FT_UInt num_storage
;
3434 FT_UInt num_stack_elements
;
3435 FT_UInt num_twilight_points
;
3438 seg_limit
= segments
+ axis
->num_segments
;
3439 num_segments
= axis
->num_segments
;
3441 /* some segments can `wrap around' */
3442 /* a contour's start point like 24-25-26-0-1-2 */
3443 /* (there can be at most one such segment per contour); */
3444 /* we thus append additional records to split them into 24-26 and 0-2 */
3445 wrap_around_segment
= recorder
->wrap_around_segments
;
3446 for (seg
= segments
; seg
< seg_limit
; seg
++)
3447 if (seg
->first
> seg
->last
)
3449 /* the stored data is used later for edge linking */
3450 *(wrap_around_segment
++) = seg
- segments
;
3453 num_wrap_around_segments
= wrap_around_segment
3454 - recorder
->wrap_around_segments
;
3455 num_segments
+= num_wrap_around_segments
;
3457 /* wrap-around segments are pushed with four arguments */
3458 num_args
= 2 * num_segments
+ 2 * num_wrap_around_segments
+ 2;
3460 /* collect all arguments temporarily in an array (in reverse order) */
3461 /* so that we can easily split into chunks of 255 args */
3462 /* as needed by NPUSHB and NPUSHW, respectively */
3463 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
3467 arg
= args
+ num_args
- 1;
3469 if (num_segments
> 0xFF)
3472 *(arg
--) = bci_create_segments
;
3473 *(arg
--) = num_segments
;
3475 for (seg
= segments
; seg
< seg_limit
; seg
++)
3477 FT_UInt first
= seg
->first
- points
;
3478 FT_UInt last
= seg
->last
- points
;
3484 /* we push the last and first contour point */
3485 /* as a third and fourth argument in wrap-around segments */
3488 for (n
= 0; n
< outline
.n_contours
; n
++)
3490 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
3502 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
3512 /* emit the second part of wrap-around segments as separate segments */
3513 /* so that edges can easily link to them */
3514 for (seg
= segments
; seg
< seg_limit
; seg
++)
3516 FT_UInt first
= seg
->first
- points
;
3517 FT_UInt last
= seg
->last
- points
;
3522 for (n
= 0; n
< outline
.n_contours
; n
++)
3524 if (first
<= (FT_UInt
)outline
.contours
[n
])
3529 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
3537 /* with most fonts it is very rare */
3538 /* that any of the pushed arguments is larger than 0xFF, */
3539 /* thus we refrain from further optimizing this case */
3545 for (i
= 0; i
< num_args
; i
+= 255)
3547 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
3551 for (j
= 0; j
< nargs
; j
++)
3561 for (i
= 0; i
< num_args
; i
+= 255)
3563 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
3567 for (j
= 0; j
< nargs
; j
++)
3577 num_storage
= sal_segment_offset
+ num_segments
* 2;
3578 if (num_storage
> sfnt
->max_storage
)
3579 sfnt
->max_storage
= num_storage
;
3581 num_twilight_points
= num_segments
* 2;
3582 if (num_twilight_points
> sfnt
->max_twilight_points
)
3583 sfnt
->max_twilight_points
= num_twilight_points
;
3585 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
3586 if (num_stack_elements
> sfnt
->max_stack_elements
)
3587 sfnt
->max_stack_elements
= num_stack_elements
;
3596 TA_hints_record_is_different(Hints_Record
* hints_records
,
3597 FT_UInt num_hints_records
,
3601 Hints_Record last_hints_record
;
3607 /* we only need to compare with the last hints record */
3608 last_hints_record
= hints_records
[num_hints_records
- 1];
3610 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
3613 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
3621 TA_add_hints_record(Hints_Record
** hints_records
,
3622 FT_UInt
* num_hints_records
,
3624 Hints_Record hints_record
)
3626 Hints_Record
* hints_records_new
;
3628 /* at this point, `hints_record.buf' still points into `ins_buf' */
3629 FT_Byte
* end
= hints_record
.buf
;
3632 buf_len
= (FT_UInt
)(end
- start
);
3634 /* now fill the structure completely */
3635 hints_record
.buf_len
= buf_len
;
3636 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
3637 if (!hints_record
.buf
)
3638 return FT_Err_Out_Of_Memory
;
3640 memcpy(hints_record
.buf
, start
, buf_len
);
3642 (*num_hints_records
)++;
3644 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
3645 * sizeof (Hints_Record
));
3646 if (!hints_records_new
)
3648 free(hints_record
.buf
);
3649 (*num_hints_records
)--;
3650 return FT_Err_Out_Of_Memory
;
3653 *hints_records
= hints_records_new
;
3655 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
3662 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
3663 Hints_Record
* hints_record
,
3668 FT_Bool need_words
= 0;
3671 FT_UInt num_arguments
;
3673 FT_UInt num_stack_elements
;
3676 /* check whether any argument is larger than 0xFF */
3677 endp
= hints_record
->buf
+ hints_record
->buf_len
;
3678 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
3682 /* with most fonts it is very rare */
3683 /* that any of the pushed arguments is larger than 0xFF, */
3684 /* thus we refrain from further optimizing this case */
3686 num_arguments
= hints_record
->buf_len
/ 2;
3691 for (i
= 0; i
< num_arguments
; i
+= 255)
3693 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
3697 for (j
= 0; j
< num_args
; j
++)
3707 /* we only need the lower bytes */
3710 for (i
= 0; i
< num_arguments
; i
+= 255)
3712 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
3716 for (j
= 0; j
< num_args
; j
++)
3724 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
3725 if (num_stack_elements
> sfnt
->max_stack_elements
)
3726 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
3733 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
3734 Hints_Record
* hints_records
,
3735 FT_UInt num_hints_records
,
3739 Hints_Record
* hints_record
;
3742 hints_record
= hints_records
;
3744 for (i
= 0; i
< num_hints_records
- 1; i
++)
3747 if (hints_record
->size
> 0xFF)
3750 BCI(HIGH((hints_record
+ 1)->size
));
3751 BCI(LOW((hints_record
+ 1)->size
));
3756 BCI((hints_record
+ 1)->size
);
3760 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
3766 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
3768 for (i
= 0; i
< num_hints_records
- 1; i
++)
3772 BCI(bci_hint_glyph
);
3780 TA_free_hints_records(Hints_Record
* hints_records
,
3781 FT_UInt num_hints_records
)
3786 for (i
= 0; i
< num_hints_records
; i
++)
3787 free(hints_records
[i
].buf
);
3789 free(hints_records
);
3794 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
3799 TA_Segment segments
= axis
->segments
;
3802 FT_UInt num_segs
= 0;
3806 seg_idx
= edge
->first
- segments
;
3808 /* we store everything as 16bit numbers */
3809 *(bufp
++) = HIGH(seg_idx
);
3810 *(bufp
++) = LOW(seg_idx
);
3812 /* wrap-around segments are stored as two segments */
3813 if (edge
->first
->first
> edge
->first
->last
)
3816 seg
= edge
->first
->edge_next
;
3817 while (seg
!= edge
->first
)
3821 if (seg
->first
> seg
->last
)
3824 seg
= seg
->edge_next
;
3827 *(bufp
++) = HIGH(num_segs
);
3828 *(bufp
++) = LOW(num_segs
);
3830 if (edge
->first
->first
> edge
->first
->last
)
3832 /* emit second part of wrap-around segment; */
3833 /* the bytecode positions such segments after `normal' ones */
3837 if (seg_idx
== *wrap
)
3842 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
3843 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
3846 seg
= edge
->first
->edge_next
;
3847 while (seg
!= edge
->first
)
3849 seg_idx
= seg
- segments
;
3851 *(bufp
++) = HIGH(seg_idx
);
3852 *(bufp
++) = LOW(seg_idx
);
3854 if (seg
->first
> seg
->last
)
3859 if (seg_idx
== *wrap
)
3864 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
3865 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
3868 seg
= seg
->edge_next
;
3876 TA_hints_recorder(TA_Action action
,
3877 TA_GlyphHints hints
,
3882 TA_Edge lower_bound
,
3883 TA_Edge upper_bound
)
3885 TA_AxisHints axis
= &hints
->axis
[dim
];
3886 TA_Segment segments
= axis
->segments
;
3888 Recorder
* recorder
= (Recorder
*)hints
->user
;
3889 FONT
* font
= recorder
->font
;
3890 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
3891 FT_Byte
* p
= recorder
->hints_record
.buf
;
3893 FT_Byte bound_offset
= 0;
3896 if (dim
== TA_DIMENSION_HORZ
)
3899 /* we ignore the BOUND action since we signal this information */
3900 /* with the `bound_offset' parameter */
3901 if (action
== ta_bound
)
3909 /* this reflects the order in the TA_Action enumeration */
3911 *(p
++) = (FT_Byte
)action
+ bound_offset
+ ACTION_OFFSET
;
3917 TA_Edge base_edge
= arg1
;
3918 TA_Edge stem_edge
= arg2
;
3922 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
3924 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
3925 *(p
++) = HIGH(base_edge
->first
- segments
);
3926 *(p
++) = LOW(base_edge
->first
- segments
);
3927 *(p
++) = HIGH(stem_edge
->first
- segments
);
3928 *(p
++) = LOW(stem_edge
->first
- segments
);
3930 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
3936 TA_Edge edge
= arg1
;
3937 TA_Edge edge2
= arg2
;
3941 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3943 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3944 *(p
++) = HIGH(edge
->first
- segments
);
3945 *(p
++) = LOW(edge
->first
- segments
);
3946 *(p
++) = HIGH(edge2
->first
- segments
);
3947 *(p
++) = LOW(edge2
->first
- segments
);
3949 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3955 TA_Edge edge
= arg1
;
3956 TA_Edge edge2
= arg2
;
3957 TA_Edge edge_minus_one
= lower_bound
;
3961 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3963 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3964 *(p
++) = HIGH(edge
->first
- segments
);
3965 *(p
++) = LOW(edge
->first
- segments
);
3966 *(p
++) = HIGH(edge2
->first
- segments
);
3967 *(p
++) = LOW(edge2
->first
- segments
);
3971 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
3972 *(p
++) = LOW(edge_minus_one
->first
- segments
);
3975 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3979 case ta_blue_anchor
:
3981 TA_Edge edge
= arg1
;
3982 TA_Edge blue
= arg2
;
3985 *(p
++) = HIGH(blue
->first
- segments
);
3986 *(p
++) = LOW(blue
->first
- segments
);
3988 if (edge
->best_blue_is_shoot
)
3990 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3991 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3995 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3996 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3999 *(p
++) = HIGH(edge
->first
- segments
);
4000 *(p
++) = LOW(edge
->first
- segments
);
4002 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4008 TA_Edge edge
= arg1
;
4009 TA_Edge edge2
= arg2
;
4010 TA_Edge edge_minus_one
= lower_bound
;
4014 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
4016 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
4017 *(p
++) = HIGH(edge
->first
- segments
);
4018 *(p
++) = LOW(edge
->first
- segments
);
4019 *(p
++) = HIGH(edge2
->first
- segments
);
4020 *(p
++) = LOW(edge2
->first
- segments
);
4024 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
4025 *(p
++) = LOW(edge_minus_one
->first
- segments
);
4028 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4029 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
4035 TA_Edge edge
= arg1
;
4038 if (edge
->best_blue_is_shoot
)
4040 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4041 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
4045 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4046 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
4049 *(p
++) = HIGH(edge
->first
- segments
);
4050 *(p
++) = LOW(edge
->first
- segments
);
4052 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
4058 TA_Edge base
= arg1
->serif
;
4059 TA_Edge serif
= arg1
;
4062 *(p
++) = HIGH(serif
->first
- segments
);
4063 *(p
++) = LOW(serif
->first
- segments
);
4064 *(p
++) = HIGH(base
->first
- segments
);
4065 *(p
++) = LOW(base
->first
- segments
);
4069 *(p
++) = HIGH(lower_bound
->first
- segments
);
4070 *(p
++) = LOW(lower_bound
->first
- segments
);
4074 *(p
++) = HIGH(upper_bound
->first
- segments
);
4075 *(p
++) = LOW(upper_bound
->first
- segments
);
4078 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
4082 case ta_serif_anchor
:
4083 p
= TA_hints_recorder_handle_segments(p
, axis
, arg1
, wraps
);
4086 case ta_serif_link1
:
4087 p
= TA_hints_recorder_handle_segments(p
, axis
, arg1
, wraps
);
4090 case ta_serif_link2
:
4091 p
= TA_hints_recorder_handle_segments(p
, axis
, arg1
, wraps
);
4095 /* there are more cases in the enumeration */
4096 /* which are handled with the `bound_offset' parameter */
4100 recorder
->hints_record
.num_actions
++;
4101 recorder
->hints_record
.buf
= p
;
4106 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
4110 FT_Face face
= sfnt
->face
;
4117 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
4118 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
4119 GLYPH
* glyph
= &data
->glyphs
[idx
];
4121 TA_GlyphHints hints
;
4123 FT_UInt num_hints_records
;
4124 Hints_Record
* hints_records
;
4132 return FT_Err_Invalid_Argument
;
4134 /* computing the segments is resolution independent, */
4135 /* thus the pixel size in this call is arbitrary */
4136 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
4140 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
4141 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
4145 /* do nothing if we have an empty glyph */
4146 if (!face
->glyph
->outline
.n_contours
)
4149 /* do nothing if the dummy hinter has been used */
4150 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
4153 hints
= &font
->loader
->hints
;
4155 /* we allocate a buffer which is certainly large enough */
4156 /* to hold all of the created bytecode instructions; */
4157 /* later on it gets reallocated to its real size */
4158 ins_len
= hints
->num_points
* 1000;
4159 ins_buf
= (FT_Byte
*)malloc(ins_len
);
4161 return FT_Err_Out_Of_Memory
;
4163 /* initialize array with an invalid bytecode */
4164 /* so that we can easily find the array length at reallocation time */
4165 memset(ins_buf
, INS_A0
, ins_len
);
4167 recorder
.font
= font
;
4168 recorder
.wrap_around_segments
=
4169 (FT_UInt
*)malloc(face
->glyph
->outline
.n_contours
* sizeof (FT_UInt
));
4171 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
4173 /* now we loop over a large range of pixel sizes */
4174 /* to find hints records which get pushed onto the bytecode stack */
4175 num_hints_records
= 0;
4176 hints_records
= NULL
;
4179 printf("glyph %ld\n", idx
);
4182 /* we temporarily use `ins_buf' to record the current glyph hints, */
4183 /* leaving two bytes at the beginning so that the number of actions */
4184 /* can be inserted later on */
4185 ta_loader_register_hints_recorder(font
->loader
,
4189 for (size
= 8; size
<= 1000; size
++)
4191 /* rewind buffer pointer for recorder */
4192 recorder
.hints_record
.buf
= bufp
+ 2;
4193 recorder
.hints_record
.num_actions
= 0;
4194 recorder
.hints_record
.size
= size
;
4196 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
4200 /* calling `ta_loader_load_glyph' uses the */
4201 /* `TA_hints_recorder' function as a callback, */
4202 /* modifying `hints_record' */
4203 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
4207 /* store the number of actions in `ins_buf' */
4208 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
4209 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
4211 if (TA_hints_record_is_different(hints_records
,
4213 bufp
, recorder
.hints_record
.buf
))
4220 printf(" %d:\n", size
);
4221 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
4222 printf(" %2d", *p
* 256 + *(p
+ 1));
4227 error
= TA_add_hints_record(&hints_records
,
4229 bufp
, recorder
.hints_record
);
4235 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
4237 /* don't emit anything if we only have a single empty record */
4245 /* otherwise, clear the temporarily used part of `ins_buf' */
4246 while (*p
!= INS_A0
)
4249 bufp
= TA_sfnt_emit_hints_records(sfnt
,
4250 hints_records
, num_hints_records
,
4253 /* we are done, so reallocate the instruction array to its real size */
4254 if (*bufp
== INS_A0
)
4256 /* search backwards */
4257 while (*bufp
== INS_A0
)
4263 /* search forwards */
4264 while (*bufp
!= INS_A0
)
4268 ins_len
= bufp
- ins_buf
;
4271 if (ins_len
> sfnt
->max_instructions
)
4272 sfnt
->max_instructions
= ins_len
;
4274 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
4275 glyph
->ins_len
= ins_len
;
4277 TA_free_hints_records(hints_records
, num_hints_records
);
4278 free(recorder
.wrap_around_segments
);
4283 TA_free_hints_records(hints_records
, num_hints_records
);
4284 free(recorder
.wrap_around_segments
);
4292 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
4295 FT_Face face
= sfnt
->face
;
4300 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
4302 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
4310 /* end of tabytecode.c */