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 */
300 * bci_compute_stem_width
302 * This is the equivalent to the following code from function
303 * `ta_latin_compute_stem_width':
311 * else if base_is_round:
317 * delta = ABS(dist - std_width)
328 * delta = delta - dist
331 * dist = dist + delta
332 * else if delta < 32:
334 * else if delta < 54:
337 * dist = dist + delta
351 * sal: sal_is_extra_light
355 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
358 bci_compute_stem_width
,
362 ABS
, /* s: base_is_round stem_is_serif width dist */
367 LT
, /* dist < 3*64 */
371 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
372 AND
, /* stem_is_serif && dist < 3*64 */
377 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
379 IF
, /* s: base_is_round width dist */
385 ROLL
, /* s: width dist base_is_round */
386 IF
, /* s: width dist */
391 IF
, /* s: width dist */
402 IF
, /* s: width dist */
409 DUP
, /* s: width dist dist */
414 /* %c, index of std_width */
416 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
420 ABS
, /* s: width dist delta */
425 IF
, /* s: width dist */
431 /* %c, index of std_width */
433 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
435 RCVT
, /* dist = std_width */
447 DUP
, /* s: width dist dist */
450 LT
, /* dist < 3*64 */
452 DUP
, /* s: width delta dist */
453 FLOOR
, /* dist = FLOOR(dist) */
454 DUP
, /* s: width delta dist dist */
456 ROLL
, /* s: width dist delta dist */
457 SUB
, /* delta = delta - dist */
459 DUP
, /* s: width dist delta delta */
463 IF
, /* s: width dist delta */
464 ADD
, /* dist = dist + delta */
475 ADD
, /* dist = dist + 10 */
486 ADD
, /* dist = dist + 54 */
489 ADD
, /* dist = dist + delta */
499 FLOOR
, /* dist = round(dist) */
504 SWAP
, /* s: dist width */
509 NEG
, /* dist = -dist */
522 * Take a range and a function number and apply the function to all
523 * elements of the range.
529 * uses: sal_i (counter initialized with `start')
531 * sal_func (`func_num')
534 unsigned char FPGM(bci_loop
) [] = {
543 WS
, /* sal_func = func_num */
547 WS
, /* sal_limit = end */
551 WS
, /* sal_i = start */
560 LTEQ
, /* start <= end */
571 ADD
, /* start = start + 1 */
577 JMPR
, /* goto start_loop */
588 * Rescale CVT value by a given factor.
590 * uses: sal_i (CVT index)
591 * sal_scale (scale in 16.16 format)
594 unsigned char FPGM(bci_cvt_rescale
) [] = {
608 MUL
, /* CVT * scale * 2^10 */
612 DIV
, /* CVT * scale */
624 * Round a blue ref value and adjust its corresponding shoot value.
626 * uses: sal_i (CVT index)
630 unsigned char FPGM(bci_blue_round_a
) [] = {
640 RCVT
, /* s: ref_idx ref */
647 SWAP
, /* s: ref_idx round(ref) ref */
655 unsigned char FPGM(bci_blue_round_b
) [] = {
659 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
661 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
663 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
665 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
667 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
692 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
697 NEG
, /* delta = -delta */
703 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
714 * bci_get_point_extrema
716 * An auxiliary function for `bci_create_segment'.
725 unsigned char FPGM(bci_get_point_extrema
) [] = {
728 bci_get_point_extrema
,
737 /* check whether `point' is a new minimum */
740 RS
, /* s: point point point point_min */
742 /* if distance is negative, we have a new minimum */
746 IF
, /* s: point point */
754 /* check whether `point' is a new maximum */
757 RS
, /* s: point point point_max */
759 /* if distance is positive, we have a new maximum */
779 * Store start and end point of a segment in the storage area,
780 * then construct two points in the twilight zone to represent it:
781 * an original one (which stays unmodified) and a hinted one,
782 * initialized with the original value.
784 * This function is used by `bci_create_segment_points'.
788 * [last (if wrap-around segment)]
789 * [first (if wrap-around segment)]
791 * uses: bci_get_point_extrema
793 * sal: sal_i (start of current segment)
794 * sal_j (current original twilight point)
795 * sal_k (current hinted twilight point)
800 unsigned char FPGM(bci_create_segment
) [] = {
812 WS
, /* sal[sal_i] = start */
814 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
820 ADD
, /* sal_i = sal_i + 1 */
823 /* initialize inner loop(s) */
828 WS
, /* sal_point_min = start */
833 WS
, /* sal_point_max = start */
837 SZPS
, /* set zp0, zp1, and zp2 to normal zone 1 */
843 CINDEX
, /* s: start end end start */
844 LT
, /* start > end */
846 /* we have a wrap-around segment with two more arguments */
847 /* to give the last and first point of the contour, respectively; */
848 /* our job is to store a segment `start'-`last', */
849 /* and to get extrema for the two segments */
850 /* `start'-`last' and `first'-`end' */
852 /* s: first last start end */
859 WS
, /* sal[sal_i] = last */
862 ROLL
, /* s: first end last start */
865 SWAP
, /* s: first end start last start */
866 SUB
, /* s: first end start loop_count */
869 bci_get_point_extrema
,
874 SWAP
, /* s: end first */
879 ROLL
, /* s: (first - 1) (first - 1) end */
881 SUB
, /* s: (first - 1) loop_count */
884 bci_get_point_extrema
,
889 ELSE
, /* s: start end */
896 WS
, /* sal[sal_i] = end */
901 SUB
, /* s: start loop_count */
904 bci_get_point_extrema
,
910 /* the twilight point representing a segment */
911 /* is in the middle between the minimum and maximum */
929 MDAP_noround
, /* set rp0 and rp1 to `sal_point_min' */
930 SZP1
, /* set zp1 to twilight zone 0 */
931 SZP2
, /* set zp2 to twilight zone 0 */
934 DUP
, /* s: delta point[sal_j] point[sal_j] */
935 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
938 CINDEX
, /* s: delta point[sal_j] delta */
939 SHPIX
, /* shift `point[sal_j]' by `delta' */
944 DUP
, /* s: delta point[sal_k] point[sal_k] */
945 ALIGNRP
, /* align `point[sal_k]' with `sal_point_min' */
947 SHPIX
, /* shift `point[sal_k]' by `delta' */
957 ADD
, /* original_twilight_point = original_twilight_point + 1 */
960 ADD
, /* hinted_twilight_point = hinted_twilight_point + 1 */
969 * bci_create_segments
971 * Set up segments by defining point ranges which defines them
972 * and computing twilight points to represent them.
974 * in: num_segments (N)
977 * [contour_last 0 (if wrap-around segment)]
978 * [contour_first 0 (if wrap-around segment)]
981 * [contour_last 0 (if wrap-around segment)]
982 * [contour_first 0 (if wrap-around segment)]
984 * segment_start_(N-1)
986 * [contour_last (N-1) (if wrap-around segment)]
987 * [contour_first (N-1) (if wrap-around segment)]
989 * uses: bci_create_segment
991 * sal: sal_i (start of current segment)
992 * sal_j (current original twilight point)
993 * sal_k (current hinted twilight point)
997 unsigned char FPGM(bci_create_segments
) [] = {
1000 bci_create_segments
,
1003 /* all our measurements are taken along the y axis */
1009 WS
, /* sal_num_segments = num_segments */
1021 WS
, /* sal_j = num_segments (offset for original points) */
1022 WS
, /* sal_k = 0 (offset for hinted points) */
1030 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1032 /* `bci_create_segment_point' also increases the loop counter by 1; */
1033 /* this effectively means we have a loop step of 2 */
1043 unsigned char FPGM(bci_handle_segment
) [] = {
1049 POP
, /* XXX segment */
1059 * Align all points in a segment to the twilight point in rp0.
1060 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1065 unsigned char FPGM(bci_align_segment
) [] = {
1071 /* we need the values of `sal_segment_offset + 2*segment_index' */
1072 /* and `sal_segment_offset + 2*segment_index + 1' */
1084 RS
, /* s: first last */
1089 CINDEX
, /* s: first last first */
1092 CINDEX
, /* s: first last first last */
1093 LTEQ
, /* first <= end */
1094 IF
, /* s: first last */
1096 DUP
, /* s: last first first */
1097 ALIGNRP
, /* align point with index `first' with rp0 */
1101 ADD
, /* first = first + 1 */
1102 SWAP
, /* s: first last */
1107 JMPR
, /* goto start_loop */
1118 unsigned char FPGM(bci_handle_segments
) [] = {
1121 bci_handle_segments
,
1124 POP
, /* XXX first segment */
1136 * bci_align_segments
1138 * Align segments to the twilight point in rp0.
1139 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1148 * uses: handle_segment
1152 unsigned char FPGM(bci_align_segments
) [] = {
1172 * bci_action_adjust_bound
1174 * Handle the ADJUST_BOUND action to align an edge of a stem if the other
1175 * edge of the stem has already been moved, then moving it again if
1176 * necessary to stay bound.
1178 * in: edge2_is_serif
1180 * edge_point (in twilight zone)
1181 * edge2_point (in twilight zone)
1182 * edge[-1] (in twilight zone)
1183 * ... stuff for bci_align_segments (edge) ...
1186 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1189 bci_action_adjust_bound
,
1194 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1202 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig */
1209 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1210 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1213 bci_compute_stem_width
,
1215 NEG
, /* s: edge[-1] edge2 edge -cur_len */
1217 ROLL
, /* s: edge[-1] edge -cur_len edge2 */
1218 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1221 DUP
, /* s: edge[-1] -cur_len edge edge edge */
1222 ALIGNRP
, /* align `edge' with `edge2' */
1224 SHPIX
, /* shift `edge' by -cur_len */
1226 SWAP
, /* s: edge edge[-1] */
1228 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1233 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1234 GT
, /* edge_pos < edge[-1]_pos */
1237 ALIGNRP
, /* align `edge' to `edge[-1]' */
1240 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1245 SZP1
, /* set zp1 to normal zone 1 */
1254 * bci_action_stem_bound
1256 * Handle the STEM action to align two edges of a stem, then moving one
1257 * edge again if necessary to stay bound.
1259 * The code after computing `cur_len' to shift `edge' and `edge2'
1260 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1263 * if cur_len < = 64:
1270 * org_center = edge_orig + org_len / 2
1271 * cur_pos1 = ROUND(org_center)
1273 * delta1 = ABS(org_center - (cur_pos1 - u_off))
1274 * delta2 = ABS(org_center - (cur_pos1 + d_off))
1275 * if (delta1 < delta2):
1276 * cur_pos1 = cur_pos1 - u_off
1278 * cur_pos1 = cur_pos1 + d_off
1280 * edge = cur_pos1 - cur_len / 2
1283 * org_pos = anchor + (edge_orig - anchor_orig)
1284 * org_center = edge_orig + org_len / 2
1286 * cur_pos1 = ROUND(org_pos)
1287 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
1288 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
1289 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
1291 * if (delta1 < delta2):
1296 * edge2 = edge + cur_len
1298 * in: edge2_is_serif
1300 * edge_point (in twilight zone)
1301 * edge2_point (in twilight zone)
1302 * edge[-1] (in twilight zone)
1303 * ... stuff for bci_align_segments (edge) ...
1304 * ... stuff for bci_align_segments (edge2)...
1314 #define sal_u_off sal_temp1
1316 #define sal_d_off sal_temp2
1318 #define sal_org_len sal_temp3
1320 #define sal_edge2 sal_temp3
1322 unsigned char FPGM(bci_action_stem_bound
) [] = {
1325 bci_action_stem_bound
,
1330 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1343 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1347 ADD
, /* s: edge[-1] edge2 edge is_round is_serif edge2_orig edge_orig */
1349 MD_cur
, /* s: edge[-1] edge2 edge is_round is_serif org_len */
1357 bci_compute_stem_width
,
1358 CALL
, /* s: edge[-1] edge2 edge cur_len */
1363 LT
, /* cur_len < 96 */
1368 LTEQ
, /* cur_len <= 64 */
1386 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1391 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1400 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1406 FLOOR
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 */
1411 SUB
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) */
1418 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
1425 ABS
, /* s: edge[-1] edge2 cur_len edge cur_pos1 delta1 delta2 */
1427 LT
, /* delta1 < delta2 */
1432 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1438 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1439 EIF
, /* s: edge[-1] edge2 cur_len edge cur_pos1 */
1447 SUB
, /* arg = cur_pos1 - cur_len/2 */
1449 SWAP
, /* s: edge[-1] edge2 cur_len arg edge */
1455 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1458 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1461 SWAP
, /* s: edge[-1] edge2 cur_len edge */
1466 ADD
, /* s: edge[-1] edge2 cur_len edge edge_orig */
1475 ADD
, /* s: edge[-1] edge2 cur_len edge org_center */
1480 GC_cur
, /* s: edge[-1] edge2 cur_len edge org_center anchor_pos */
1496 ADD
, /* s: edge[-1] edge2 cur_len edge org_center org_pos */
1502 FLOOR
, /* cur_pos1 = ROUND(org_pos) */
1515 SUB
, /* s: edge[-1] edge2 cur_len edge org_center cur_pos1 cur_pos2 */
1526 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
1533 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
1539 ABS
, /* s: ... edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
1540 LT
, /* delta1 < delta2 */
1542 POP
, /* arg = cur_pos1 */
1545 POP
, /* arg = cur_pos2 */
1546 EIF
, /* s: edge[-1] edge2 cur_len edge arg */
1553 SWAP
, /* s: edge[-1] edge2 cur_len edge edge arg edge */
1556 SHPIX
, /* edge = arg */
1557 EIF
, /* s: edge[-1] edge2 cur_len edge */
1559 ROLL
, /* s: edge[-1] cur_len edge edge2 */
1562 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1566 WS
, /* s: edge[-1] cur_len edge edge2 */
1568 SHPIX
, /* edge2 = edge + cur_len */
1570 SWAP
, /* s: edge edge[-1] */
1572 MDAP_noround
, /* set rp0 and rp1 to `edge[-1]' */
1577 GC_cur
, /* s: edge edge[-1]_pos edge_pos */
1578 GT
, /* edge_pos < edge[-1]_pos */
1581 ALIGNRP
, /* align `edge' to `edge[-1]' */
1584 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1589 SZP1
, /* set zp1 to normal zone 1 */
1595 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1609 * Handle the LINK action to link an edge to another one.
1613 * base_point (in twilight zone)
1614 * stem_point (in twilight zone)
1615 * ... stuff for bci_align_segments (base) ...
1618 unsigned char FPGM(bci_action_link
) [] = {
1626 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1639 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1643 ADD
, /* s: stem is_round is_serif stem_orig base_orig */
1645 MD_cur
, /* s: stem is_round is_serif dist_orig */
1648 bci_compute_stem_width
,
1649 CALL
, /* s: stem new_dist */
1653 ALIGNRP
, /* align `stem_point' with `base_point' */
1655 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
1657 SHPIX
, /* stem_point = base_point + new_dist */
1662 SZP1
, /* set zp1 to normal zone 1 */
1673 * Handle the ANCHOR action to align two edges
1674 * and to set the edge anchor.
1676 * The code after computing `cur_len' to shift `edge' and `edge2'
1677 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1680 * if cur_len < = 64:
1687 * org_center = edge_orig + org_len / 2
1688 * cur_pos1 = ROUND(org_center)
1690 * error1 = ABS(org_center - (cur_pos1 - u_off))
1691 * error2 = ABS(org_center - (cur_pos1 + d_off))
1692 * if (error1 < error2):
1693 * cur_pos1 = cur_pos1 - u_off
1695 * cur_pos1 = cur_pos1 + d_off
1697 * edge = cur_pos1 - cur_len / 2
1698 * edge2 = edge + cur_len
1701 * edge = ROUND(edge_orig)
1703 * in: edge2_is_serif
1705 * edge_point (in twilight zone)
1706 * edge2_point (in twilight zone)
1707 * ... stuff for bci_align_segments (edge) ...
1716 #define sal_u_off sal_temp1
1718 #define sal_d_off sal_temp2
1720 #define sal_org_len sal_temp3
1722 unsigned char FPGM(bci_action_anchor
) [] = {
1728 /* store anchor point number in `sal_anchor' */
1733 WS
, /* sal_anchor = edge_point */
1737 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1750 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1754 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
1756 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
1764 bci_compute_stem_width
,
1765 CALL
, /* s: edge2 edge cur_len */
1770 LT
, /* cur_len < 96 */
1775 LTEQ
, /* cur_len <= 64 */
1793 SWAP
, /* s: edge2 cur_len edge */
1798 ADD
, /* s: edge2 cur_len edge edge_orig */
1807 ADD
, /* s: edge2 cur_len edge org_center */
1813 FLOOR
, /* s: edge2 cur_len edge org_center cur_pos1 */
1818 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1825 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1832 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1834 LT
, /* error1 < error2 */
1839 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1845 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1846 EIF
, /* s: edge2 cur_len edge cur_pos1 */
1854 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1858 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1861 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1863 SWAP
, /* s: cur_len edge2 */
1865 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1867 SHPIX
, /* edge2 = edge1 + cur_len */
1870 POP
, /* s: edge2 edge */
1875 ADD
, /* s: edge2 edge edge_orig */
1877 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
1879 ALIGNRP
, /* align `edge' with `edge_orig' */
1880 MDAP_round
, /* round `edge' */
1882 /* clean up stack */
1889 SZP1
, /* set zp1 to normal zone 1 */
1898 * bci_action_blue_anchor
1900 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1901 * and to set the edge anchor.
1903 * in: anchor_point (in twilight zone)
1905 * edge_point (in twilight zone)
1906 * ... stuff for bci_align_segments (edge) ...
1911 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1914 bci_action_blue_anchor
,
1917 /* store anchor point number in `sal_anchor' */
1925 SZP0
, /* set zp0 to twilight zone 0 */
1927 /* move `edge_point' to `blue_cvt_idx' position */
1928 MIAP_noround
, /* this also sets rp0 */
1933 SZP1
, /* set zp1 to normal zone 1 */
1944 * Handle the ADJUST action to align an edge of a stem if the other edge
1945 * of the stem has already been moved.
1947 * in: edge2_is_serif
1949 * edge_point (in twilight zone)
1950 * edge2_point (in twilight zone)
1951 * ... stuff for bci_align_segments (edge) ...
1954 unsigned char FPGM(bci_action_adjust
) [] = {
1962 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1970 ADD
, /* s: edge2 edge is_round is_serif edge2_orig */
1977 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
1978 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
1981 bci_compute_stem_width
,
1983 NEG
, /* s: edge2 edge -cur_len */
1986 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
1989 DUP
, /* s: -cur_len edge edge edge */
1990 ALIGNRP
, /* align `edge' with `edge2' */
1992 SHPIX
, /* shift `edge' by -cur_len */
1994 MDAP_noround
, /* set rp0 and rp1 to `edge' */
1999 SZP1
, /* set zp1 to normal zone 1 */
2010 * Handle the STEM action to align two edges of a stem.
2012 * The code after computing `cur_len' to shift `edge' and `edge2'
2013 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
2016 * if cur_len < = 64:
2023 * org_center = edge_orig + org_len / 2
2024 * cur_pos1 = ROUND(org_center)
2026 * delta1 = ABS(org_center - (cur_pos1 - u_off))
2027 * delta2 = ABS(org_center - (cur_pos1 + d_off))
2028 * if (delta1 < delta2):
2029 * cur_pos1 = cur_pos1 - u_off
2031 * cur_pos1 = cur_pos1 + d_off
2033 * edge = cur_pos1 - cur_len / 2
2036 * org_pos = anchor + (edge_orig - anchor_orig)
2037 * org_center = edge_orig + org_len / 2
2039 * cur_pos1 = ROUND(org_pos)
2040 * delta1 = ABS(cur_pos1 + cur_len / 2 - org_center)
2041 * cur_pos2 = ROUND(org_pos + org_len) - cur_len
2042 * delta2 = ABS(cur_pos2 + cur_len / 2 - org_center)
2044 * if (delta1 < delta2):
2049 * edge2 = edge + cur_len
2051 * in: edge2_is_serif
2053 * edge_point (in twilight zone)
2054 * edge2_point (in twilight zone)
2055 * ... stuff for bci_align_segments (edge) ...
2056 * ... stuff for bci_align_segments (edge2)...
2066 #define sal_u_off sal_temp1
2068 #define sal_d_off sal_temp2
2070 #define sal_org_len sal_temp3
2072 #define sal_edge2 sal_temp3
2074 unsigned char FPGM(bci_action_stem
) [] = {
2082 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
2095 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
2099 ADD
, /* s: edge2 edge is_round is_serif edge2_orig edge_orig */
2101 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
2109 bci_compute_stem_width
,
2110 CALL
, /* s: edge2 edge cur_len */
2115 LT
, /* cur_len < 96 */
2120 LTEQ
, /* cur_len <= 64 */
2138 SWAP
, /* s: edge2 cur_len edge */
2143 ADD
, /* s: edge2 cur_len edge edge_orig */
2152 ADD
, /* s: edge2 cur_len edge org_center */
2158 FLOOR
, /* s: edge2 cur_len edge org_center cur_pos1 */
2163 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
2170 ABS
, /* s: ... cur_len edge cur_pos1 (org_center - cur_pos1) delta1 */
2177 ABS
, /* s: edge2 cur_len edge cur_pos1 delta1 delta2 */
2179 LT
, /* delta1 < delta2 */
2184 SUB
, /* cur_pos1 = cur_pos1 - u_off */
2190 ADD
, /* cur_pos1 = cur_pos1 + d_off */
2191 EIF
, /* s: edge2 cur_len edge cur_pos1 */
2199 SUB
, /* arg = cur_pos1 - cur_len/2 */
2201 SWAP
, /* s: edge2 cur_len arg edge */
2206 SWAP
, /* s: edge2 cur_len edge arg edge */
2209 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
2212 SWAP
, /* s: edge2 cur_len edge */
2217 ADD
, /* s: edge2 cur_len edge edge_orig */
2226 ADD
, /* s: edge2 cur_len edge org_center */
2231 GC_cur
, /* s: edge2 cur_len edge org_center anchor_pos */
2247 ADD
, /* s: edge2 cur_len edge org_center org_pos */
2253 FLOOR
, /* cur_pos1 = ROUND(org_pos) */
2266 SUB
, /* s: edge2 cur_len edge org_center cur_pos1 cur_pos2 */
2277 SUB
, /* s: ... cur_len edge cur_pos1 cur_pos2 (cur_len/2 - org_center) */
2284 ABS
, /* delta1 = ABS(cur_pos1 + cur_len / 2 - org_center) */
2290 ABS
, /* s: edge2 cur_len edge cur_pos1 cur_pos2 delta1 delta2 */
2291 LT
, /* delta1 < delta2 */
2293 POP
, /* arg = cur_pos1 */
2296 POP
, /* arg = cur_pos2 */
2297 EIF
, /* s: edge2 cur_len edge arg */
2303 SWAP
, /* s: edge2 cur_len edge arg edge */
2306 SHPIX
, /* edge = arg */
2307 EIF
, /* s: edge2 cur_len */
2309 SWAP
, /* s: cur_len edge2 */
2312 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
2316 WS
, /* s: cur_len edge2 */
2318 SHPIX
, /* edge2 = edge + cur_len */
2323 SZP1
, /* set zp1 to normal zone 1 */
2329 MDAP_noround
, /* set rp0 and rp1 to `edge2' */
2342 * Handle the BLUE action to align an edge with a blue zone.
2345 * edge_point (in twilight zone)
2346 * ... stuff for bci_align_segments (edge) ...
2349 unsigned char FPGM(bci_action_blue
) [] = {
2357 SZP0
, /* set zp0 to twilight zone 0 */
2359 /* move `edge_point' to `blue_cvt_idx' position */
2360 MIAP_noround
, /* this also sets rp0 */
2365 SZP1
, /* set zp1 to normal zone 1 */
2372 unsigned char FPGM(bci_action_serif
) [] = {
2379 bci_handle_segments
,
2388 unsigned char FPGM(bci_action_serif_anchor
) [] = {
2391 bci_action_serif_anchor
,
2395 bci_handle_segments
,
2404 unsigned char FPGM(bci_action_serif_link1
) [] = {
2407 bci_action_serif_link1
,
2411 bci_handle_segments
,
2420 unsigned char FPGM(bci_action_serif_link2
) [] = {
2423 bci_action_serif_link2
,
2427 bci_handle_segments
,
2442 * in: function_index
2445 unsigned char FPGM(bci_handle_action
) [] = {
2461 * This is the top-level glyph hinting function
2462 * which parses the arguments on the stack and calls subroutines.
2464 * in: num_actions (M)
2473 * uses: bci_handle_action
2474 * bci_action_adjust_bound
2475 * bci_action_stem_bound
2479 * bci_action_blue_anchor
2485 * bci_action_serif_anchor
2486 * bci_action_serif_link1
2487 * bci_action_serif_link2
2490 unsigned char FPGM(bci_hint_glyph
) [] = {
2505 #define COPY_FPGM(func_name) \
2506 memcpy(buf_p, fpgm_ ## func_name, \
2507 sizeof (fpgm_ ## func_name)); \
2508 buf_p += sizeof (fpgm_ ## func_name) \
2511 TA_table_build_fpgm(FT_Byte
** fpgm
,
2521 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
2523 + sizeof (FPGM(bci_compute_stem_width_b
))
2525 + sizeof (FPGM(bci_compute_stem_width_c
))
2526 + sizeof (FPGM(bci_loop
))
2527 + sizeof (FPGM(bci_cvt_rescale
))
2528 + sizeof (FPGM(bci_blue_round_a
))
2530 + sizeof (FPGM(bci_blue_round_b
))
2531 + sizeof (FPGM(bci_get_point_extrema
))
2532 + sizeof (FPGM(bci_create_segment
))
2533 + sizeof (FPGM(bci_create_segments
))
2534 + sizeof (FPGM(bci_handle_segment
))
2535 + sizeof (FPGM(bci_align_segment
))
2536 + sizeof (FPGM(bci_handle_segments
))
2537 + sizeof (FPGM(bci_align_segments
))
2538 + sizeof (FPGM(bci_action_adjust_bound
))
2539 + sizeof (FPGM(bci_action_stem_bound
))
2540 + sizeof (FPGM(bci_action_link
))
2541 + sizeof (FPGM(bci_action_anchor
))
2542 + sizeof (FPGM(bci_action_blue_anchor
))
2543 + sizeof (FPGM(bci_action_adjust
))
2544 + sizeof (FPGM(bci_action_stem
))
2545 + sizeof (FPGM(bci_action_blue
))
2546 + sizeof (FPGM(bci_action_serif
))
2547 + sizeof (FPGM(bci_action_serif_anchor
))
2548 + sizeof (FPGM(bci_action_serif_link1
))
2549 + sizeof (FPGM(bci_action_serif_link2
))
2550 + sizeof (FPGM(bci_handle_action
))
2551 + sizeof (FPGM(bci_hint_glyph
));
2552 /* buffer length must be a multiple of four */
2553 len
= (buf_len
+ 3) & ~3;
2554 buf
= (FT_Byte
*)malloc(len
);
2556 return FT_Err_Out_Of_Memory
;
2558 /* pad end of buffer with zeros */
2559 buf
[len
- 1] = 0x00;
2560 buf
[len
- 2] = 0x00;
2561 buf
[len
- 3] = 0x00;
2563 /* copy font program into buffer and fill in the missing variables */
2566 COPY_FPGM(bci_compute_stem_width_a
);
2567 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
2568 COPY_FPGM(bci_compute_stem_width_b
);
2569 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
2570 COPY_FPGM(bci_compute_stem_width_c
);
2571 COPY_FPGM(bci_loop
);
2572 COPY_FPGM(bci_cvt_rescale
);
2573 COPY_FPGM(bci_blue_round_a
);
2574 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
2575 COPY_FPGM(bci_blue_round_b
);
2576 COPY_FPGM(bci_get_point_extrema
);
2577 COPY_FPGM(bci_create_segment
);
2578 COPY_FPGM(bci_create_segments
);
2579 COPY_FPGM(bci_handle_segment
);
2580 COPY_FPGM(bci_align_segment
);
2581 COPY_FPGM(bci_handle_segments
);
2582 COPY_FPGM(bci_align_segments
);
2583 COPY_FPGM(bci_action_adjust_bound
);
2584 COPY_FPGM(bci_action_stem_bound
);
2585 COPY_FPGM(bci_action_link
);
2586 COPY_FPGM(bci_action_anchor
);
2587 COPY_FPGM(bci_action_blue_anchor
);
2588 COPY_FPGM(bci_action_adjust
);
2589 COPY_FPGM(bci_action_stem
);
2590 COPY_FPGM(bci_action_blue
);
2591 COPY_FPGM(bci_action_serif
);
2592 COPY_FPGM(bci_action_serif_anchor
);
2593 COPY_FPGM(bci_action_serif_link1
);
2594 COPY_FPGM(bci_action_serif_link2
);
2595 COPY_FPGM(bci_handle_action
);
2596 COPY_FPGM(bci_hint_glyph
);
2599 *fpgm_len
= buf_len
;
2606 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
2615 error
= TA_sfnt_add_table_info(sfnt
);
2619 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
2623 /* in case of success, `fpgm_buf' gets linked */
2624 /* and is eventually freed in `TA_font_unload' */
2625 error
= TA_font_add_table(font
,
2626 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
2627 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
2638 /* the `prep' instructions */
2640 #define PREP(snippet_name) prep_ ## snippet_name
2642 /* we often need 0x10000 which can't be pushed directly onto the stack, */
2643 /* thus we provide it in the storage area */
2645 unsigned char PREP(store_0x10000
) [] = {
2659 unsigned char PREP(align_top_a
) [] = {
2661 /* optimize the alignment of the top of small letters to the pixel grid */
2667 /* %c, index of alignment blue zone */
2669 unsigned char PREP(align_top_b
) [] = {
2677 FLOOR
, /* fitted = FLOOR(scaled + 40) */
2678 DUP
, /* s: scaled scaled fitted fitted */
2681 IF
, /* s: scaled fitted */
2685 MUL
, /* scaled in 16.16 format */
2687 DIV
, /* (fitted / scaled) in 16.16 format */
2696 unsigned char PREP(loop_cvt_a
) [] = {
2698 /* loop over vertical CVT entries */
2703 /* %c, first vertical index */
2704 /* %c, last vertical index */
2706 unsigned char PREP(loop_cvt_b
) [] = {
2712 /* loop over blue refs */
2717 /* %c, first blue ref index */
2718 /* %c, last blue ref index */
2720 unsigned char PREP(loop_cvt_c
) [] = {
2726 /* loop over blue shoots */
2731 /* %c, first blue shoot index */
2732 /* %c, last blue shoot index */
2734 unsigned char PREP(loop_cvt_d
) [] = {
2743 unsigned char PREP(compute_extra_light_a
) [] = {
2745 /* compute (vertical) `extra_light' flag */
2752 /* %c, index of vertical standard_width */
2754 unsigned char PREP(compute_extra_light_b
) [] = {
2757 GT
, /* standard_width < 40 */
2762 unsigned char PREP(round_blues_a
) [] = {
2764 /* use discrete values for blue zone widths */
2769 /* %c, first blue ref index */
2770 /* %c, last blue ref index */
2772 unsigned char PREP(round_blues_b
) [] = {
2780 /* XXX talatin.c: 1671 */
2781 /* XXX talatin.c: 1708 */
2782 /* XXX talatin.c: 2182 */
2785 #define COPY_PREP(snippet_name) \
2786 memcpy(buf_p, prep_ ## snippet_name, \
2787 sizeof (prep_ ## snippet_name)); \
2788 buf_p += sizeof (prep_ ## snippet_name);
2791 TA_table_build_prep(FT_Byte
** prep
,
2796 TA_LatinBlue blue_adjustment
;
2805 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
2806 blue_adjustment
= NULL
;
2808 for (i
= 0; i
< vaxis
->blue_count
; i
++)
2810 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
2812 blue_adjustment
= &vaxis
->blues
[i
];
2817 buf_len
= sizeof (PREP(store_0x10000
));
2819 if (blue_adjustment
)
2820 buf_len
+= sizeof (PREP(align_top_a
))
2822 + sizeof (PREP(align_top_b
))
2823 + sizeof (PREP(loop_cvt_a
))
2825 + sizeof (PREP(loop_cvt_b
))
2827 + sizeof (PREP(loop_cvt_c
))
2829 + sizeof (PREP(loop_cvt_d
));
2831 buf_len
+= sizeof (PREP(compute_extra_light_a
))
2833 + sizeof (PREP(compute_extra_light_b
));
2835 if (CVT_BLUES_SIZE(font
))
2836 buf_len
+= sizeof (PREP(round_blues_a
))
2838 + sizeof (PREP(round_blues_b
));
2840 /* buffer length must be a multiple of four */
2841 len
= (buf_len
+ 3) & ~3;
2842 buf
= (FT_Byte
*)malloc(len
);
2844 return FT_Err_Out_Of_Memory
;
2846 /* pad end of buffer with zeros */
2847 buf
[len
- 1] = 0x00;
2848 buf
[len
- 2] = 0x00;
2849 buf
[len
- 3] = 0x00;
2851 /* copy cvt program into buffer and fill in the missing variables */
2854 COPY_PREP(store_0x10000
);
2856 if (blue_adjustment
)
2858 COPY_PREP(align_top_a
);
2859 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
2860 + blue_adjustment
- vaxis
->blues
);
2861 COPY_PREP(align_top_b
);
2863 COPY_PREP(loop_cvt_a
);
2864 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
2865 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
2866 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
2867 COPY_PREP(loop_cvt_b
);
2868 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
2869 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
2870 + CVT_BLUES_SIZE(font
) - 1);
2871 COPY_PREP(loop_cvt_c
);
2872 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
2873 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
2874 + CVT_BLUES_SIZE(font
) - 1);
2875 COPY_PREP(loop_cvt_d
);
2878 COPY_PREP(compute_extra_light_a
);
2879 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
2880 COPY_PREP(compute_extra_light_b
);
2882 if (CVT_BLUES_SIZE(font
))
2884 COPY_PREP(round_blues_a
);
2885 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
2886 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
2887 + CVT_BLUES_SIZE(font
) - 1);
2888 COPY_PREP(round_blues_b
);
2892 *prep_len
= buf_len
;
2899 TA_sfnt_build_prep_table(SFNT
* sfnt
,
2908 error
= TA_sfnt_add_table_info(sfnt
);
2912 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
2916 /* in case of success, `prep_buf' gets linked */
2917 /* and is eventually freed in `TA_font_unload' */
2918 error
= TA_font_add_table(font
,
2919 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
2920 TTAG_prep
, prep_len
, prep_buf
);
2931 /* we store the segments in the storage area; */
2932 /* each segment record consists of the first and last point */
2935 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
2939 FONT
* font
= recorder
->font
;
2940 TA_GlyphHints hints
= &font
->loader
->hints
;
2941 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2942 TA_Point points
= hints
->points
;
2943 TA_Segment segments
= axis
->segments
;
2945 TA_Segment seg_limit
;
2947 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
2953 FT_UInt num_segments
;
2955 FT_UInt
* wrap_around_segment
;
2956 FT_UInt num_wrap_around_segments
;
2958 FT_Bool need_words
= 0;
2962 FT_UInt num_storage
;
2963 FT_UInt num_stack_elements
;
2964 FT_UInt num_twilight_points
;
2967 seg_limit
= segments
+ axis
->num_segments
;
2968 num_segments
= axis
->num_segments
;
2970 /* some segments can `wrap around' */
2971 /* a contour's start point like 24-25-26-0-1-2 */
2972 /* (there can be at most one such segment per contour); */
2973 /* we thus append additional records to split them into 24-26 and 0-2 */
2974 wrap_around_segment
= recorder
->wrap_around_segments
;
2975 for (seg
= segments
; seg
< seg_limit
; seg
++)
2976 if (seg
->first
> seg
->last
)
2978 /* the stored data is used later for edge linking */
2979 *(wrap_around_segment
++) = seg
- segments
;
2982 num_wrap_around_segments
= wrap_around_segment
2983 - recorder
->wrap_around_segments
;
2984 num_segments
+= num_wrap_around_segments
;
2986 /* wrap-around segments are pushed with four arguments */
2987 num_args
= 2 * num_segments
+ 2 * num_wrap_around_segments
+ 2;
2989 /* collect all arguments temporarily in an array (in reverse order) */
2990 /* so that we can easily split into chunks of 255 args */
2991 /* as needed by NPUSHB and NPUSHW, respectively */
2992 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
2996 arg
= args
+ num_args
- 1;
2998 if (num_segments
> 0xFF)
3001 *(arg
--) = bci_create_segments
;
3002 *(arg
--) = num_segments
;
3004 for (seg
= segments
; seg
< seg_limit
; seg
++)
3006 FT_UInt first
= seg
->first
- points
;
3007 FT_UInt last
= seg
->last
- points
;
3013 /* we push the last and first contour point */
3014 /* as a third and fourth argument in wrap-around segments */
3017 for (n
= 0; n
< outline
.n_contours
; n
++)
3019 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
3031 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
3041 /* emit the second part of wrap-around segments as separate segments */
3042 /* so that edges can easily link to them */
3043 for (seg
= segments
; seg
< seg_limit
; seg
++)
3045 FT_UInt first
= seg
->first
- points
;
3046 FT_UInt last
= seg
->last
- points
;
3051 for (n
= 0; n
< outline
.n_contours
; n
++)
3053 if (first
<= (FT_UInt
)outline
.contours
[n
])
3058 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
3066 /* with most fonts it is very rare */
3067 /* that any of the pushed arguments is larger than 0xFF, */
3068 /* thus we refrain from further optimizing this case */
3074 for (i
= 0; i
< num_args
; i
+= 255)
3076 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
3080 for (j
= 0; j
< nargs
; j
++)
3090 for (i
= 0; i
< num_args
; i
+= 255)
3092 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
3096 for (j
= 0; j
< nargs
; j
++)
3106 num_storage
= sal_segment_offset
+ num_segments
* 2;
3107 if (num_storage
> sfnt
->max_storage
)
3108 sfnt
->max_storage
= num_storage
;
3110 num_twilight_points
= num_segments
* 2;
3111 if (num_twilight_points
> sfnt
->max_twilight_points
)
3112 sfnt
->max_twilight_points
= num_twilight_points
;
3114 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
3115 if (num_stack_elements
> sfnt
->max_stack_elements
)
3116 sfnt
->max_stack_elements
= num_stack_elements
;
3125 TA_hints_record_is_different(Hints_Record
* hints_records
,
3126 FT_UInt num_hints_records
,
3130 Hints_Record last_hints_record
;
3136 /* we only need to compare with the last hints record */
3137 last_hints_record
= hints_records
[num_hints_records
- 1];
3139 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
3142 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
3150 TA_add_hints_record(Hints_Record
** hints_records
,
3151 FT_UInt
* num_hints_records
,
3153 Hints_Record hints_record
)
3155 Hints_Record
* hints_records_new
;
3157 /* at this point, `hints_record.buf' still points into `ins_buf' */
3158 FT_Byte
* end
= hints_record
.buf
;
3161 buf_len
= (FT_UInt
)(end
- start
);
3163 /* now fill the structure completely */
3164 hints_record
.buf_len
= buf_len
;
3165 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
3166 if (!hints_record
.buf
)
3167 return FT_Err_Out_Of_Memory
;
3169 memcpy(hints_record
.buf
, start
, buf_len
);
3171 (*num_hints_records
)++;
3173 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
3174 * sizeof (Hints_Record
));
3175 if (!hints_records_new
)
3177 free(hints_record
.buf
);
3178 (*num_hints_records
)--;
3179 return FT_Err_Out_Of_Memory
;
3182 *hints_records
= hints_records_new
;
3184 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
3191 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
3192 Hints_Record
* hints_record
,
3197 FT_Bool need_words
= 0;
3200 FT_UInt num_arguments
;
3202 FT_UInt num_stack_elements
;
3205 /* check whether any argument is larger than 0xFF */
3206 endp
= hints_record
->buf
+ hints_record
->buf_len
;
3207 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
3211 /* with most fonts it is very rare */
3212 /* that any of the pushed arguments is larger than 0xFF, */
3213 /* thus we refrain from further optimizing this case */
3215 num_arguments
= hints_record
->buf_len
/ 2;
3220 for (i
= 0; i
< num_arguments
; i
+= 255)
3222 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
3226 for (j
= 0; j
< num_args
; j
++)
3236 /* we only need the lower bytes */
3239 for (i
= 0; i
< num_arguments
; i
+= 255)
3241 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
3245 for (j
= 0; j
< num_args
; j
++)
3253 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
3254 if (num_stack_elements
> sfnt
->max_stack_elements
)
3255 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
3262 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
3263 Hints_Record
* hints_records
,
3264 FT_UInt num_hints_records
,
3268 Hints_Record
* hints_record
;
3271 hints_record
= hints_records
;
3273 for (i
= 0; i
< num_hints_records
- 1; i
++)
3276 if (hints_record
->size
> 0xFF)
3279 BCI(HIGH((hints_record
+ 1)->size
));
3280 BCI(LOW((hints_record
+ 1)->size
));
3285 BCI((hints_record
+ 1)->size
);
3289 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
3295 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
3297 for (i
= 0; i
< num_hints_records
- 1; i
++)
3301 BCI(bci_hint_glyph
);
3309 TA_free_hints_records(Hints_Record
* hints_records
,
3310 FT_UInt num_hints_records
)
3315 for (i
= 0; i
< num_hints_records
; i
++)
3316 free(hints_records
[i
].buf
);
3318 free(hints_records
);
3323 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
3328 TA_Segment segments
= axis
->segments
;
3331 FT_UInt num_segs
= 0;
3335 seg_idx
= edge
->first
- segments
;
3337 /* we store everything as 16bit numbers */
3338 *(bufp
++) = HIGH(seg_idx
);
3339 *(bufp
++) = LOW(seg_idx
);
3341 /* wrap-around segments are stored as two segments */
3342 if (edge
->first
->first
> edge
->first
->last
)
3345 seg
= edge
->first
->edge_next
;
3346 while (seg
!= edge
->first
)
3350 if (seg
->first
> seg
->last
)
3353 seg
= seg
->edge_next
;
3356 *(bufp
++) = HIGH(num_segs
);
3357 *(bufp
++) = LOW(num_segs
);
3359 if (edge
->first
->first
> edge
->first
->last
)
3361 /* emit second part of wrap-around segment; */
3362 /* the bytecode positions such segments after `normal' ones */
3366 if (seg_idx
== *wrap
)
3371 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
3372 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
3375 seg
= edge
->first
->edge_next
;
3376 while (seg
!= edge
->first
)
3378 seg_idx
= seg
- segments
;
3380 *(bufp
++) = HIGH(seg_idx
);
3381 *(bufp
++) = LOW(seg_idx
);
3383 if (seg
->first
> seg
->last
)
3388 if (seg_idx
== *wrap
)
3393 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
3394 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
3397 seg
= seg
->edge_next
;
3405 TA_hints_recorder(TA_Action action
,
3406 TA_GlyphHints hints
,
3412 TA_AxisHints axis
= &hints
->axis
[dim
];
3413 TA_Segment segments
= axis
->segments
;
3415 Recorder
* recorder
= (Recorder
*)hints
->user
;
3416 FONT
* font
= recorder
->font
;
3417 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
3418 FT_Byte
* p
= recorder
->hints_record
.buf
;
3421 if (dim
== TA_DIMENSION_HORZ
)
3424 /* we ignore the BOUND action since the information is handled */
3425 /* in `ta_adjust_bound' and `ta_stem_bound' */
3426 if (action
== ta_bound
)
3430 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
3434 case ta_adjust_bound
:
3436 TA_Edge edge
= (TA_Edge
)arg1
;
3437 TA_Edge edge2
= (TA_Edge
)arg2
;
3438 TA_Edge edge_minus_one
= (TA_Edge
)arg3
;
3442 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3444 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3445 *(p
++) = HIGH(edge
->first
- segments
);
3446 *(p
++) = LOW(edge
->first
- segments
);
3447 *(p
++) = HIGH(edge2
->first
- segments
);
3448 *(p
++) = LOW(edge2
->first
- segments
);
3449 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
3450 *(p
++) = LOW(edge_minus_one
->first
- segments
);
3452 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3458 TA_Edge edge
= (TA_Edge
)arg1
;
3459 TA_Edge edge2
= (TA_Edge
)arg2
;
3460 TA_Edge edge_minus_one
= (TA_Edge
)arg3
;
3464 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3466 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3467 *(p
++) = HIGH(edge
->first
- segments
);
3468 *(p
++) = LOW(edge
->first
- segments
);
3469 *(p
++) = HIGH(edge2
->first
- segments
);
3470 *(p
++) = LOW(edge2
->first
- segments
);
3471 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
3472 *(p
++) = LOW(edge_minus_one
->first
- segments
);
3474 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3475 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
3481 TA_Edge base_edge
= (TA_Edge
)arg1
;
3482 TA_Edge stem_edge
= (TA_Edge
)arg2
;
3486 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
3488 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
3489 *(p
++) = HIGH(base_edge
->first
- segments
);
3490 *(p
++) = LOW(base_edge
->first
- segments
);
3491 *(p
++) = HIGH(stem_edge
->first
- segments
);
3492 *(p
++) = LOW(stem_edge
->first
- segments
);
3494 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
3501 TA_Edge edge
= (TA_Edge
)arg1
;
3502 TA_Edge edge2
= (TA_Edge
)arg2
;
3506 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3508 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3509 *(p
++) = HIGH(edge
->first
- segments
);
3510 *(p
++) = LOW(edge
->first
- segments
);
3511 *(p
++) = HIGH(edge2
->first
- segments
);
3512 *(p
++) = LOW(edge2
->first
- segments
);
3514 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3518 case ta_blue_anchor
:
3520 TA_Edge edge
= (TA_Edge
)arg1
;
3521 TA_Edge blue
= (TA_Edge
)arg2
;
3524 *(p
++) = HIGH(blue
->first
- segments
);
3525 *(p
++) = LOW(blue
->first
- segments
);
3527 if (edge
->best_blue_is_shoot
)
3529 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3530 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3534 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3535 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3538 *(p
++) = HIGH(edge
->first
- segments
);
3539 *(p
++) = LOW(edge
->first
- segments
);
3541 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3547 TA_Edge edge
= (TA_Edge
)arg1
;
3548 TA_Edge edge2
= (TA_Edge
)arg2
;
3552 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
3554 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
3555 *(p
++) = HIGH(edge
->first
- segments
);
3556 *(p
++) = LOW(edge
->first
- segments
);
3557 *(p
++) = HIGH(edge2
->first
- segments
);
3558 *(p
++) = LOW(edge2
->first
- segments
);
3560 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3561 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
3567 TA_Edge edge
= (TA_Edge
)arg1
;
3570 if (edge
->best_blue_is_shoot
)
3572 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3573 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
3577 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3578 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
3581 *(p
++) = HIGH(edge
->first
- segments
);
3582 *(p
++) = LOW(edge
->first
- segments
);
3584 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
3589 p
= TA_hints_recorder_handle_segments(p
, axis
, (TA_Edge
)arg1
, wraps
);
3592 case ta_serif_anchor
:
3593 p
= TA_hints_recorder_handle_segments(p
, axis
, (TA_Edge
)arg1
, wraps
);
3596 case ta_serif_link1
:
3597 p
= TA_hints_recorder_handle_segments(p
, axis
, (TA_Edge
)arg1
, wraps
);
3600 case ta_serif_link2
:
3601 p
= TA_hints_recorder_handle_segments(p
, axis
, (TA_Edge
)arg1
, wraps
);
3604 /* to pacify the compiler */
3609 recorder
->hints_record
.num_actions
++;
3610 recorder
->hints_record
.buf
= p
;
3615 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
3619 FT_Face face
= sfnt
->face
;
3626 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
3627 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
3628 GLYPH
* glyph
= &data
->glyphs
[idx
];
3630 TA_GlyphHints hints
;
3632 FT_UInt num_hints_records
;
3633 Hints_Record
* hints_records
;
3641 return FT_Err_Invalid_Argument
;
3643 /* computing the segments is resolution independent, */
3644 /* thus the pixel size in this call is arbitrary */
3645 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
3649 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
3650 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
3654 /* do nothing if we have an empty glyph */
3655 if (!face
->glyph
->outline
.n_contours
)
3658 /* do nothing if the dummy hinter has been used */
3659 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
3662 hints
= &font
->loader
->hints
;
3664 /* we allocate a buffer which is certainly large enough */
3665 /* to hold all of the created bytecode instructions; */
3666 /* later on it gets reallocated to its real size */
3667 ins_len
= hints
->num_points
* 1000;
3668 ins_buf
= (FT_Byte
*)malloc(ins_len
);
3670 return FT_Err_Out_Of_Memory
;
3672 /* initialize array with an invalid bytecode */
3673 /* so that we can easily find the array length at reallocation time */
3674 memset(ins_buf
, INS_A0
, ins_len
);
3676 recorder
.font
= font
;
3677 recorder
.wrap_around_segments
=
3678 (FT_UInt
*)malloc(face
->glyph
->outline
.n_contours
* sizeof (FT_UInt
));
3680 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
3682 /* now we loop over a large range of pixel sizes */
3683 /* to find hints records which get pushed onto the bytecode stack */
3684 num_hints_records
= 0;
3685 hints_records
= NULL
;
3688 printf("glyph %ld\n", idx
);
3691 /* we temporarily use `ins_buf' to record the current glyph hints, */
3692 /* leaving two bytes at the beginning so that the number of actions */
3693 /* can be inserted later on */
3694 ta_loader_register_hints_recorder(font
->loader
,
3698 for (size
= 8; size
<= 1000; size
++)
3700 /* rewind buffer pointer for recorder */
3701 recorder
.hints_record
.buf
= bufp
+ 2;
3702 recorder
.hints_record
.num_actions
= 0;
3703 recorder
.hints_record
.size
= size
;
3705 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
3709 /* calling `ta_loader_load_glyph' uses the */
3710 /* `TA_hints_recorder' function as a callback, */
3711 /* modifying `hints_record' */
3712 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
3716 /* store the number of actions in `ins_buf' */
3717 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
3718 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
3720 if (TA_hints_record_is_different(hints_records
,
3722 bufp
, recorder
.hints_record
.buf
))
3729 printf(" %d:\n", size
);
3730 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
3731 printf(" %2d", *p
* 256 + *(p
+ 1));
3736 error
= TA_add_hints_record(&hints_records
,
3738 bufp
, recorder
.hints_record
);
3744 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
3746 /* don't emit anything if we only have a single empty record */
3754 /* otherwise, clear the temporarily used part of `ins_buf' */
3755 while (*p
!= INS_A0
)
3758 bufp
= TA_sfnt_emit_hints_records(sfnt
,
3759 hints_records
, num_hints_records
,
3762 /* we are done, so reallocate the instruction array to its real size */
3763 if (*bufp
== INS_A0
)
3765 /* search backwards */
3766 while (*bufp
== INS_A0
)
3772 /* search forwards */
3773 while (*bufp
!= INS_A0
)
3777 ins_len
= bufp
- ins_buf
;
3780 if (ins_len
> sfnt
->max_instructions
)
3781 sfnt
->max_instructions
= ins_len
;
3783 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
3784 glyph
->ins_len
= ins_len
;
3786 TA_free_hints_records(hints_records
, num_hints_records
);
3787 free(recorder
.wrap_around_segments
);
3792 TA_free_hints_records(hints_records
, num_hints_records
);
3793 free(recorder
.wrap_around_segments
);
3801 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
3804 FT_Face face
= sfnt
->face
;
3809 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
3811 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
3819 /* end of tabytecode.c */