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
;
42 TA_sfnt_compute_global_hints(SFNT
* sfnt
,
46 FT_Face face
= sfnt
->face
;
50 static const FT_Encoding latin_encs
[] =
53 FT_ENCODING_APPLE_ROMAN
,
54 FT_ENCODING_ADOBE_STANDARD
,
55 FT_ENCODING_ADOBE_LATIN_1
,
57 FT_ENCODING_NONE
/* end of list */
61 error
= ta_loader_init(font
->loader
);
65 /* try to select a latin charmap */
66 for (enc
= 0; latin_encs
[enc
] != FT_ENCODING_NONE
; enc
++)
68 error
= FT_Select_Charmap(face
, latin_encs
[enc
]);
73 /* load latin glyph `a' to trigger all initializations */
74 idx
= FT_Get_Char_Index(face
, 'a');
75 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
82 TA_table_build_cvt(FT_Byte
** cvt
,
99 error
= TA_sfnt_compute_global_hints(sfnt
, font
);
103 /* XXX check validity of pointers */
104 haxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[0];
105 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
110 + 2 * vaxis
->blue_count
);
112 /* buffer length must be a multiple of four */
113 len
= (buf_len
+ 3) & ~3;
114 buf
= (FT_Byte
*)malloc(len
);
116 return FT_Err_Out_Of_Memory
;
118 /* pad end of buffer with zeros */
125 if (haxis
->width_count
> 0)
127 *(buf_p
++) = HIGH(haxis
->widths
[0].org
);
128 *(buf_p
++) = LOW(haxis
->widths
[0].org
);
135 if (vaxis
->width_count
> 0)
137 *(buf_p
++) = HIGH(vaxis
->widths
[0].org
);
138 *(buf_p
++) = LOW(vaxis
->widths
[0].org
);
146 for (i
= 0; i
< haxis
->width_count
; i
++)
148 if (haxis
->widths
[i
].org
> 0xFFFF)
150 *(buf_p
++) = HIGH(haxis
->widths
[i
].org
);
151 *(buf_p
++) = LOW(haxis
->widths
[i
].org
);
154 for (i
= 0; i
< vaxis
->width_count
; i
++)
156 if (vaxis
->widths
[i
].org
> 0xFFFF)
158 *(buf_p
++) = HIGH(vaxis
->widths
[i
].org
);
159 *(buf_p
++) = LOW(vaxis
->widths
[i
].org
);
162 for (i
= 0; i
< vaxis
->blue_count
; i
++)
164 if (vaxis
->blues
[i
].ref
.org
> 0xFFFF)
166 *(buf_p
++) = HIGH(vaxis
->blues
[i
].ref
.org
);
167 *(buf_p
++) = LOW(vaxis
->blues
[i
].ref
.org
);
170 for (i
= 0; i
< vaxis
->blue_count
; i
++)
172 if (vaxis
->blues
[i
].shoot
.org
> 0xFFFF)
174 *(buf_p
++) = HIGH(vaxis
->blues
[i
].shoot
.org
);
175 *(buf_p
++) = LOW(vaxis
->blues
[i
].shoot
.org
);
179 TA_LOG(("--------------------------------------------------\n"));
180 TA_LOG(("glyph %d:\n", idx
));
181 ta_glyph_hints_dump_edges(_ta_debug_hints
);
182 ta_glyph_hints_dump_segments(_ta_debug_hints
);
183 ta_glyph_hints_dump_points(_ta_debug_hints
);
193 return TA_Err_Hinter_Overflow
;
198 TA_sfnt_build_cvt_table(SFNT
* sfnt
,
207 error
= TA_sfnt_add_table_info(sfnt
);
211 error
= TA_table_build_cvt(&cvt_buf
, &cvt_len
, sfnt
, font
);
215 /* in case of success, `cvt_buf' gets linked */
216 /* and is eventually freed in `TA_font_unload' */
217 error
= TA_font_add_table(font
,
218 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
219 TTAG_cvt
, cvt_len
, cvt_buf
);
230 /* the horizontal and vertical standard widths */
231 #define CVT_HORZ_STANDARD_WIDTH_OFFSET(font) 0
232 #define CVT_VERT_STANDARD_WIDTH_OFFSET(font) \
233 CVT_HORZ_STANDARD_WIDTH_OFFSET(font) + 1
235 /* the horizontal stem widths */
236 #define CVT_HORZ_WIDTHS_OFFSET(font) \
237 CVT_VERT_STANDARD_WIDTH_OFFSET(font) + 1
238 #define CVT_HORZ_WIDTHS_SIZE(font) \
239 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
241 /* the vertical stem widths */
242 #define CVT_VERT_WIDTHS_OFFSET(font) \
243 CVT_HORZ_WIDTHS_OFFSET(font) + CVT_HORZ_WIDTHS_SIZE(font)
244 #define CVT_VERT_WIDTHS_SIZE(font) \
245 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
247 /* the number of blue zones */
248 #define CVT_BLUES_SIZE(font) \
249 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
251 /* the blue zone values for flat and round edges */
252 #define CVT_BLUE_REFS_OFFSET(font) \
253 CVT_VERT_WIDTHS_OFFSET(font) + CVT_VERT_WIDTHS_SIZE(font)
254 #define CVT_BLUE_SHOOTS_OFFSET(font) \
255 CVT_BLUE_REFS_OFFSET(font) + CVT_BLUES_SIZE(font)
258 /* symbolic names for storage area locations */
261 #define sal_j sal_i + 1
262 #define sal_k sal_j + 1
263 #define sal_temp1 sal_k + 1
264 #define sal_temp2 sal_temp1 + 1
265 #define sal_temp3 sal_temp2 + 1
266 #define sal_temp4 sal_temp3 + 1
267 #define sal_limit sal_temp4 + 1
268 #define sal_num_segments sal_limit + 1
269 #define sal_scale sal_num_segments + 1
270 #define sal_0x10000 sal_scale + 1
271 #define sal_is_extra_light sal_0x10000 + 1
272 #define sal_anchor sal_is_extra_light + 1
273 #define sal_point_min sal_anchor + 1
274 #define sal_point_max sal_point_min + 1
275 #define sal_segment_offset sal_point_max + 1 /* must be last */
278 /* we need the following macro */
279 /* so that `func_name' doesn't get replaced with its #defined value */
280 /* (as defined in `tabytecode.h') */
282 #define FPGM(func_name) fpgm_ ## func_name
285 /* in the comments below, the top of the stack (`s:') */
286 /* is the rightmost element; the stack is shown */
287 /* after the instruction on the same line has been executed */
289 /* we use two sets of points in the twilight zone (zp0): */
290 /* one set to hold the unhinted segment positions, */
291 /* and another one to track the positions as changed by the hinting -- */
292 /* this is necessary since all points in zp0 */
293 /* have (0,0) as the original coordinates, */
294 /* making e.g. `MD_orig' return useless results */
298 * bci_compute_stem_width
300 * This is the equivalent to the following code from function
301 * `ta_latin_compute_stem_width':
309 * else if base_is_round:
315 * delta = ABS(dist - std_width)
318 * dist = MIN(48, std_width)
324 * delta = delta - dist
327 * dist = dist + delta
328 * else if delta < 32:
330 * else if delta < 54:
333 * dist = dist + delta
347 * sal: sal_is_extra_light
351 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
354 bci_compute_stem_width
,
358 ABS
, /* s: base_is_round stem_is_serif width dist */
363 LT
, /* dist < 3*64 */
367 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
368 AND
, /* stem_is_serif && dist < 3*64 */
373 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
375 IF
, /* s: base_is_round width dist */
381 ROLL
, /* s: width dist base_is_round */
382 IF
, /* s: width dist */
387 IF
, /* s: width dist */
398 IF
, /* s: width dist */
405 DUP
, /* s: width dist dist */
410 /* %c, index of std_width */
412 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
416 ABS
, /* s: width dist delta */
421 IF
, /* s: width dist */
428 /* %c, index of std_width */
430 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
433 MIN
, /* dist = min(48, std_width) */
436 DUP
, /* s: width dist dist */
439 LT
, /* dist < 3*64 */
441 DUP
, /* s: width delta dist */
442 FLOOR
, /* dist = FLOOR(dist) */
443 DUP
, /* s: width delta dist dist */
445 ROLL
, /* s: width dist delta dist */
446 SUB
, /* delta = delta - dist */
448 DUP
, /* s: width dist delta delta */
452 IF
, /* s: width dist delta */
453 ADD
, /* dist = dist + delta */
464 ADD
, /* dist = dist + 10 */
475 ADD
, /* dist = dist + 54 */
478 ADD
, /* dist = dist + delta */
488 FLOOR
, /* dist = round(dist) */
493 SWAP
, /* s: dist width */
498 NEG
, /* dist = -dist */
511 * Take a range and a function number and apply the function to all
512 * elements of the range. The called function must not change the
519 * uses: sal_i (counter initialized with `start')
523 unsigned char FPGM(bci_loop
) [] = {
530 ROLL
, /* s: func_num start end */
548 LTEQ
, /* start <= end */
549 IF
, /* s: func_num */
557 ADD
, /* start = start + 1 */
563 JMPR
, /* goto start_loop */
576 * Rescale CVT value by a given factor.
578 * uses: sal_i (CVT index)
579 * sal_scale (scale in 16.16 format)
582 unsigned char FPGM(bci_cvt_rescale
) [] = {
596 MUL
, /* CVT * scale * 2^10 */
600 DIV
, /* CVT * scale */
612 * Auxiliary function for `bci_set_up_segments'.
620 unsigned char FPGM(bci_sal_assign
) [] = {
627 ROLL
, /* s: offset offset data */
632 ADD
, /* s: (offset + 1) */
640 * bci_set_up_segments
642 * Set up segments by defining the point ranges which defines them
643 * and computing twilight points to represent them.
645 * in: num_segments (N)
652 * segment_start_(N-1)
655 * sal: sal_num_segments
657 * uses: bci_sal_assign
660 unsigned char FPGM(bci_set_up_segments
) [] = {
672 /* we have 2*num_segments arguments */
676 /* process the stack, popping off the elements in a loop */
685 bci_create_segment_points
,
696 * Round a blue ref value and adjust its corresponding shoot value.
698 * uses: sal_i (CVT index)
702 unsigned char FPGM(bci_blue_round_a
) [] = {
712 RCVT
, /* s: ref_idx ref */
719 SWAP
, /* s: ref_idx round(ref) ref */
727 unsigned char FPGM(bci_blue_round_b
) [] = {
731 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
733 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
735 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
737 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
739 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
764 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
769 NEG
, /* delta = -delta */
775 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
786 * bci_get_point_extrema
788 * An auxiliary function for `bci_create_segment_point'.
797 unsigned char FPGM(bci_get_point_extrema
) [] = {
800 bci_get_point_extrema
,
809 /* check whether `point' is a new minimum */
812 RS
, /* s: point point point point_min */
814 /* if distance is negative, we have a new minimum */
818 IF
, /* s: point point */
826 /* check whether `point' is a new maximum */
829 RS
, /* s: point point point_max */
831 /* if distance is positive, we have a new maximum */
849 * bci_create_segment_point
851 * Construct two points in the twilight zone to represent a segment:
852 * an original one (which stays unmodified) and a hinted one,
853 * initialized with the original value.
855 * This function is used by `bci_create_segment_points'.
857 * uses: bci_get_point_extrema
859 * sal: sal_i (start of current segment)
860 * sal_j (current original twilight point)
861 * sal_k (current hinted twilight point)
866 unsigned char FPGM(bci_create_segment_point
) [] = {
869 bci_create_segment_point
,
875 RS
, /* s: start_point */
878 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
890 SWAP
, /* s: start_point end_point start_point */
892 /* initialize inner loop */
897 WS
, /* sal_point_min = start_point */
902 WS
, /* sal_point_max = start_point */
904 SUB
, /* s: start_point loop_count */
909 SZP0
, /* set zp0 to normal zone 1 */
910 SZP1
, /* set zp1 to normal zone 1 */
912 /* all our measurements are taken along the y axis */
916 bci_get_point_extrema
,
921 /* the twilight point representing a segment */
922 /* is in the middle between the minimum and maximum */
940 MDAP_noround
, /* set rp0 and rp1 to `sal_point_min' */
941 SZP1
, /* set zp1 to twilight zone 0 */
942 SZP2
, /* set zp2 to twilight zone 0 */
945 DUP
, /* s: delta point[sal_j] point[sal_j] */
946 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
949 CINDEX
, /* s: delta point[sal_j] delta */
950 SHPIX
, /* shift `point[sal_j]' by `delta' */
955 DUP
, /* s: delta point[sal_k] point[sal_k] */
956 ALIGNRP
, /* align `point[sal_k]' with `sal_point_min' */
958 SHPIX
, /* shift `point[sal_k]' by `delta' */
968 ADD
, /* original_twilight_point = original_twilight_point + 1 */
971 ADD
, /* hinted_twilight_point = hinted_twilight_point + 1 */
980 * bci_create_segment_points
982 * Construct two sets of points in the twilight zone to represent segments.
983 * This function searches the points of a segment with the minimum and
984 * maximum y-values, then takes the median.
986 * uses: bci_create_segment_point
988 * sal: sal_i (start of current segment)
989 * sal_j (current original twilight point)
990 * sal_k (current hinted twilight point)
994 unsigned char FPGM(bci_create_segment_points
) [] = {
997 bci_create_segment_points
,
1010 WS
, /* sal_j = num_segments (offset for original points) */
1011 WS
, /* sal_k = 0 (offset for hinted points) */
1019 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1022 bci_create_segment_point
,
1030 unsigned char FPGM(bci_handle_segment
) [] = {
1036 POP
, /* XXX segment */
1046 * Align all points in a segment to the twilight point in rp0.
1047 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1052 unsigned char FPGM(bci_align_segment
) [] = {
1058 /* we need the values of `sal_segment_offset + 2*segment_index' */
1059 /* and `sal_segment_offset + 2*segment_index + 1' */
1071 RS
, /* s: first last */
1076 CINDEX
, /* s: first last first */
1079 CINDEX
, /* s: first last first last */
1080 LTEQ
, /* first <= end */
1081 IF
, /* s: first last */
1083 DUP
, /* s: last first first */
1084 ALIGNRP
, /* align point with index `first' with rp0 */
1088 ADD
, /* first = first + 1 */
1089 SWAP
, /* s: first last */
1094 JMPR
, /* goto start_loop */
1104 unsigned char FPGM(bci_handle_segments
) [] = {
1107 bci_handle_segments
,
1110 POP
, /* XXX first segment */
1122 * bci_align_segments
1124 * Align segments to the twilight point in rp0.
1125 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1134 * uses: handle_segment
1138 unsigned char FPGM(bci_align_segments
) [] = {
1157 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1160 bci_action_adjust_bound
,
1164 bci_handle_segments
,
1167 bci_handle_segments
,
1170 bci_handle_segments
,
1179 unsigned char FPGM(bci_action_stem_bound
) [] = {
1182 bci_action_stem_bound
,
1186 bci_handle_segments
,
1189 bci_handle_segments
,
1192 bci_handle_segments
,
1205 * Handle the LINK action to link an edge to another one.
1209 * base_point (in twilight zone)
1210 * stem_point (in twilight zone)
1211 * ... stuff for bci_align_segments ...
1214 unsigned char FPGM(bci_action_link
) [] = {
1222 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1235 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1239 ADD
, /* s: stem is_round is_serif stem_orig base_orig */
1241 MD_cur
, /* s: stem is_round is_serif dist_orig */
1244 bci_compute_stem_width
,
1245 CALL
, /* s: stem new_dist */
1249 ALIGNRP
, /* align `stem_point' with `base_point' */
1251 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
1253 SHPIX
, /* stem_point = base_point + new_dist */
1258 SZP1
, /* set zp1 to normal zone 1 */
1269 * Handle the ANCHOR action to align two edges
1270 * and to set the edge anchor.
1272 * The code after computing `cur_len' to shift `edge' and `edge2'
1273 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1276 * if cur_len < = 64:
1283 * org_center = edge_orig + org_len / 2
1284 * cur_pos1 = ROUND(org_center)
1286 * error1 = ABS(org_center - (cur_pos1 - u_off))
1287 * error2 = ABS(org_center - (cur_pos1 + d_off))
1288 * if (error1 < error2):
1289 * cur_pos1 = cur_pos1 - u_off
1291 * cur_pos1 = cur_pos1 + d_off
1293 * edge = cur_pos1 - cur_len / 2
1294 * edge2 = edge + cur_len
1297 * edge = ROUND(edge_orig)
1299 * in: edge2_is_serif
1301 * edge_point (in twilight zone)
1302 * edge2_point (in twilight zone)
1303 * ... stuff for bci_align_segments...
1306 #define sal_u_off sal_temp1
1307 #define sal_d_off sal_temp2
1308 #define sal_org_len sal_temp3
1310 unsigned char FPGM(bci_action_anchor
) [] = {
1316 /* store anchor point number in `sal_anchor' */
1321 WS
, /* sal_anchor = edge_point */
1325 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1338 MDAP_noround
, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1342 ADD
, /* s: edge2 edge is_round is_serif stem_orig edge_orig */
1344 MD_cur
, /* s: edge2 edge is_round is_serif org_len */
1352 bci_compute_stem_width
,
1353 CALL
, /* s: edge2 edge cur_len */
1358 LT
, /* cur_len < 96 */
1363 LTEQ
, /* cur_len <= 64 */
1380 SWAP
, /* s: edge2 cur_len edge */
1385 ADD
, /* s: edge2 cur_len edge edge_orig */
1394 ADD
, /* s: edge2 cur_len edge org_center */
1400 FLOOR
, /* s: edge2 cur_len edge org_center cur_pos1 */
1405 SUB
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1412 ABS
, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1419 ABS
, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1421 LT
, /* error1 < error2 */
1426 SUB
, /* cur_pos1 = cur_pos1 - u_off */
1431 ADD
, /* cur_pos1 = cur_pos1 + d_off */
1432 EIF
, /* s: edge2 cur_len edge cur_pos1 */
1440 SUB
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1444 CINDEX
, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1447 SHPIX
, /* edge = cur_pos1 - cur_len/2 */
1449 SWAP
, /* s: cur_len edge2 */
1451 ALIGNRP
, /* align `edge2' with rp0 (still `edge') */
1453 SHPIX
, /* edge2 = edge1 + cur_len */
1456 POP
, /* s: edge2 edge */
1461 ADD
, /* s: edge2 edge edge_orig */
1463 MDAP_noround
, /* set rp0 and rp1 to `edge_orig' */
1465 ALIGNRP
, /* align `edge' with `edge_orig' */
1466 MDAP_round
, /* round `edge' */
1468 /* clean up stack */
1475 SZP1
, /* set zp1 to normal zone 1 */
1484 * bci_action_blue_anchor
1486 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1487 * and to set the edge anchor.
1489 * in: anchor_point (in twilight zone)
1491 * edge_point (in twilight zone)
1492 * ... stuff for bci_align_segments ...
1497 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1500 bci_action_blue_anchor
,
1503 /* store anchor point number in `sal_anchor' */
1511 SZP0
, /* set zp0 to twilight zone 0 */
1513 /* move `edge_point' to `blue_cvt_idx' position */
1514 MIAP_noround
, /* this also sets rp0 */
1519 SZP1
, /* set zp1 to normal zone 1 */
1526 unsigned char FPGM(bci_action_adjust
) [] = {
1533 bci_handle_segments
,
1536 bci_handle_segments
,
1545 unsigned char FPGM(bci_action_stem
) [] = {
1552 bci_handle_segments
,
1555 bci_handle_segments
,
1568 * Handle the BLUE action to align an edge with a blue zone.
1571 * edge_point (in twilight zone)
1572 * ... stuff for bci_align_segments ...
1575 unsigned char FPGM(bci_action_blue
) [] = {
1583 SZP0
, /* set zp0 to twilight zone 0 */
1585 /* move `edge_point' to `blue_cvt_idx' position */
1586 MIAP_noround
, /* this also sets rp0 */
1591 SZP1
, /* set zp1 to normal zone 1 */
1598 unsigned char FPGM(bci_action_serif
) [] = {
1605 bci_handle_segments
,
1614 unsigned char FPGM(bci_action_serif_anchor
) [] = {
1617 bci_action_serif_anchor
,
1621 bci_handle_segments
,
1630 unsigned char FPGM(bci_action_serif_link1
) [] = {
1633 bci_action_serif_link1
,
1637 bci_handle_segments
,
1646 unsigned char FPGM(bci_action_serif_link2
) [] = {
1649 bci_action_serif_link2
,
1653 bci_handle_segments
,
1668 * in: function_index
1671 unsigned char FPGM(bci_handle_action
) [] = {
1687 * This is the top-level glyph hinting function
1688 * which parses the arguments on the stack and calls subroutines.
1690 * in: num_actions (M)
1699 * uses: bci_handle_action
1700 * bci_action_adjust_bound
1701 * bci_action_stem_bound
1705 * bci_action_blue_anchor
1711 * bci_action_serif_anchor
1712 * bci_action_serif_link1
1713 * bci_action_serif_link2
1716 unsigned char FPGM(bci_hint_glyph
) [] = {
1731 #define COPY_FPGM(func_name) \
1732 memcpy(buf_p, fpgm_ ## func_name, \
1733 sizeof (fpgm_ ## func_name)); \
1734 buf_p += sizeof (fpgm_ ## func_name) \
1737 TA_table_build_fpgm(FT_Byte
** fpgm
,
1747 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
1749 + sizeof (FPGM(bci_compute_stem_width_b
))
1751 + sizeof (FPGM(bci_compute_stem_width_c
))
1752 + sizeof (FPGM(bci_loop
))
1753 + sizeof (FPGM(bci_cvt_rescale
))
1754 + sizeof (FPGM(bci_sal_assign
))
1755 + sizeof (FPGM(bci_set_up_segments
))
1756 + sizeof (FPGM(bci_blue_round_a
))
1758 + sizeof (FPGM(bci_blue_round_b
))
1759 + sizeof (FPGM(bci_get_point_extrema
))
1760 + sizeof (FPGM(bci_create_segment_point
))
1761 + sizeof (FPGM(bci_create_segment_points
))
1762 + sizeof (FPGM(bci_handle_segment
))
1763 + sizeof (FPGM(bci_align_segment
))
1764 + sizeof (FPGM(bci_handle_segments
))
1765 + sizeof (FPGM(bci_align_segments
))
1766 + sizeof (FPGM(bci_action_adjust_bound
))
1767 + sizeof (FPGM(bci_action_stem_bound
))
1768 + sizeof (FPGM(bci_action_link
))
1769 + sizeof (FPGM(bci_action_anchor
))
1770 + sizeof (FPGM(bci_action_blue_anchor
))
1771 + sizeof (FPGM(bci_action_adjust
))
1772 + sizeof (FPGM(bci_action_stem
))
1773 + sizeof (FPGM(bci_action_blue
))
1774 + sizeof (FPGM(bci_action_serif
))
1775 + sizeof (FPGM(bci_action_serif_anchor
))
1776 + sizeof (FPGM(bci_action_serif_link1
))
1777 + sizeof (FPGM(bci_action_serif_link2
))
1778 + sizeof (FPGM(bci_handle_action
))
1779 + sizeof (FPGM(bci_hint_glyph
));
1780 /* buffer length must be a multiple of four */
1781 len
= (buf_len
+ 3) & ~3;
1782 buf
= (FT_Byte
*)malloc(len
);
1784 return FT_Err_Out_Of_Memory
;
1786 /* pad end of buffer with zeros */
1787 buf
[len
- 1] = 0x00;
1788 buf
[len
- 2] = 0x00;
1789 buf
[len
- 3] = 0x00;
1791 /* copy font program into buffer and fill in the missing variables */
1794 COPY_FPGM(bci_compute_stem_width_a
);
1795 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1796 COPY_FPGM(bci_compute_stem_width_b
);
1797 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1798 COPY_FPGM(bci_compute_stem_width_c
);
1799 COPY_FPGM(bci_loop
);
1800 COPY_FPGM(bci_cvt_rescale
);
1801 COPY_FPGM(bci_sal_assign
);
1802 COPY_FPGM(bci_set_up_segments
);
1803 COPY_FPGM(bci_blue_round_a
);
1804 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
1805 COPY_FPGM(bci_blue_round_b
);
1806 COPY_FPGM(bci_get_point_extrema
);
1807 COPY_FPGM(bci_create_segment_point
);
1808 COPY_FPGM(bci_create_segment_points
);
1809 COPY_FPGM(bci_handle_segment
);
1810 COPY_FPGM(bci_align_segment
);
1811 COPY_FPGM(bci_handle_segments
);
1812 COPY_FPGM(bci_align_segments
);
1813 COPY_FPGM(bci_action_adjust_bound
);
1814 COPY_FPGM(bci_action_stem_bound
);
1815 COPY_FPGM(bci_action_link
);
1816 COPY_FPGM(bci_action_anchor
);
1817 COPY_FPGM(bci_action_blue_anchor
);
1818 COPY_FPGM(bci_action_adjust
);
1819 COPY_FPGM(bci_action_stem
);
1820 COPY_FPGM(bci_action_blue
);
1821 COPY_FPGM(bci_action_serif
);
1822 COPY_FPGM(bci_action_serif_anchor
);
1823 COPY_FPGM(bci_action_serif_link1
);
1824 COPY_FPGM(bci_action_serif_link2
);
1825 COPY_FPGM(bci_handle_action
);
1826 COPY_FPGM(bci_hint_glyph
);
1829 *fpgm_len
= buf_len
;
1836 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
1845 error
= TA_sfnt_add_table_info(sfnt
);
1849 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
1853 /* in case of success, `fpgm_buf' gets linked */
1854 /* and is eventually freed in `TA_font_unload' */
1855 error
= TA_font_add_table(font
,
1856 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1857 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
1868 /* the `prep' instructions */
1870 #define PREP(snippet_name) prep_ ## snippet_name
1872 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1873 /* thus we provide it in the storage area */
1875 unsigned char PREP(store_0x10000
) [] = {
1889 unsigned char PREP(align_top_a
) [] = {
1891 /* optimize the alignment of the top of small letters to the pixel grid */
1897 /* %c, index of alignment blue zone */
1899 unsigned char PREP(align_top_b
) [] = {
1907 FLOOR
, /* fitted = FLOOR(scaled + 40) */
1908 DUP
, /* s: scaled scaled fitted fitted */
1911 IF
, /* s: scaled fitted */
1915 MUL
, /* scaled in 16.16 format */
1917 DIV
, /* (fitted / scaled) in 16.16 format */
1926 unsigned char PREP(loop_cvt_a
) [] = {
1928 /* loop over vertical CVT entries */
1933 /* %c, first vertical index */
1934 /* %c, last vertical index */
1936 unsigned char PREP(loop_cvt_b
) [] = {
1942 /* loop over blue refs */
1947 /* %c, first blue ref index */
1948 /* %c, last blue ref index */
1950 unsigned char PREP(loop_cvt_c
) [] = {
1956 /* loop over blue shoots */
1961 /* %c, first blue shoot index */
1962 /* %c, last blue shoot index */
1964 unsigned char PREP(loop_cvt_d
) [] = {
1973 unsigned char PREP(compute_extra_light_a
) [] = {
1975 /* compute (vertical) `extra_light' flag */
1982 /* %c, index of vertical standard_width */
1984 unsigned char PREP(compute_extra_light_b
) [] = {
1987 GT
, /* standard_width < 40 */
1992 unsigned char PREP(round_blues_a
) [] = {
1994 /* use discrete values for blue zone widths */
1999 /* %c, first blue ref index */
2000 /* %c, last blue ref index */
2002 unsigned char PREP(round_blues_b
) [] = {
2010 /* XXX talatin.c: 1671 */
2011 /* XXX talatin.c: 1708 */
2012 /* XXX talatin.c: 2182 */
2015 #define COPY_PREP(snippet_name) \
2016 memcpy(buf_p, prep_ ## snippet_name, \
2017 sizeof (prep_ ## snippet_name)); \
2018 buf_p += sizeof (prep_ ## snippet_name);
2021 TA_table_build_prep(FT_Byte
** prep
,
2026 TA_LatinBlue blue_adjustment
;
2035 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
2036 blue_adjustment
= NULL
;
2038 for (i
= 0; i
< vaxis
->blue_count
; i
++)
2040 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
2042 blue_adjustment
= &vaxis
->blues
[i
];
2047 buf_len
= sizeof (PREP(store_0x10000
));
2049 if (blue_adjustment
)
2050 buf_len
+= sizeof (PREP(align_top_a
))
2052 + sizeof (PREP(align_top_b
))
2053 + sizeof (PREP(loop_cvt_a
))
2055 + sizeof (PREP(loop_cvt_b
))
2057 + sizeof (PREP(loop_cvt_c
))
2059 + sizeof (PREP(loop_cvt_d
));
2061 buf_len
+= sizeof (PREP(compute_extra_light_a
))
2063 + sizeof (PREP(compute_extra_light_b
));
2065 if (CVT_BLUES_SIZE(font
))
2066 buf_len
+= sizeof (PREP(round_blues_a
))
2068 + sizeof (PREP(round_blues_b
));
2070 /* buffer length must be a multiple of four */
2071 len
= (buf_len
+ 3) & ~3;
2072 buf
= (FT_Byte
*)malloc(len
);
2074 return FT_Err_Out_Of_Memory
;
2076 /* pad end of buffer with zeros */
2077 buf
[len
- 1] = 0x00;
2078 buf
[len
- 2] = 0x00;
2079 buf
[len
- 3] = 0x00;
2081 /* copy cvt program into buffer and fill in the missing variables */
2084 COPY_PREP(store_0x10000
);
2086 if (blue_adjustment
)
2088 COPY_PREP(align_top_a
);
2089 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
2090 + blue_adjustment
- vaxis
->blues
);
2091 COPY_PREP(align_top_b
);
2093 COPY_PREP(loop_cvt_a
);
2094 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
2095 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
2096 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
2097 COPY_PREP(loop_cvt_b
);
2098 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
2099 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
2100 + CVT_BLUES_SIZE(font
) - 1);
2101 COPY_PREP(loop_cvt_c
);
2102 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
2103 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
2104 + CVT_BLUES_SIZE(font
) - 1);
2105 COPY_PREP(loop_cvt_d
);
2108 COPY_PREP(compute_extra_light_a
);
2109 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
2110 COPY_PREP(compute_extra_light_b
);
2112 if (CVT_BLUES_SIZE(font
))
2114 COPY_PREP(round_blues_a
);
2115 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
2116 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
2117 + CVT_BLUES_SIZE(font
) - 1);
2118 COPY_PREP(round_blues_b
);
2122 *prep_len
= buf_len
;
2129 TA_sfnt_build_prep_table(SFNT
* sfnt
,
2138 error
= TA_sfnt_add_table_info(sfnt
);
2142 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
2146 /* in case of success, `prep_buf' gets linked */
2147 /* and is eventually freed in `TA_font_unload' */
2148 error
= TA_font_add_table(font
,
2149 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
2150 TTAG_prep
, prep_len
, prep_buf
);
2161 /* we store the segments in the storage area; */
2162 /* each segment record consists of the first and last point */
2165 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
2169 TA_GlyphHints hints
= &font
->loader
->hints
;
2170 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2171 TA_Point points
= hints
->points
;
2172 TA_Segment segments
= axis
->segments
;
2174 TA_Segment seg_limit
;
2181 FT_Bool need_words
= 0;
2184 FT_UInt num_storage
;
2185 FT_UInt num_stack_elements
;
2186 FT_UInt num_twilight_points
;
2189 seg_limit
= segments
+ axis
->num_segments
;
2190 num_args
= 2 * axis
->num_segments
+ 3;
2192 /* collect all arguments temporarily in an array (in reverse order) */
2193 /* so that we can easily split into chunks of 255 args */
2194 /* as needed by NPUSHB and NPUSHW, respectively */
2195 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
2199 arg
= args
+ num_args
- 1;
2201 if (axis
->num_segments
> 0xFF)
2204 *(arg
--) = bci_set_up_segments
;
2205 *(arg
--) = axis
->num_segments
;
2206 *(arg
--) = sal_segment_offset
;
2208 for (seg
= segments
; seg
< seg_limit
; seg
++)
2210 FT_UInt first
= seg
->first
- points
;
2211 FT_UInt last
= seg
->last
- points
;
2217 if (first
> 0xFF || last
> 0xFF)
2221 /* with most fonts it is very rare */
2222 /* that any of the pushed arguments is larger than 0xFF, */
2223 /* thus we refrain from further optimizing this case */
2229 for (i
= 0; i
< num_args
; i
+= 255)
2231 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
2235 for (j
= 0; j
< nargs
; j
++)
2245 for (i
= 0; i
< num_args
; i
+= 255)
2247 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
2251 for (j
= 0; j
< nargs
; j
++)
2261 num_storage
= sal_segment_offset
+ axis
->num_segments
* 2;
2262 if (num_storage
> sfnt
->max_storage
)
2263 sfnt
->max_storage
= num_storage
;
2265 num_twilight_points
= axis
->num_segments
* 2;
2266 if (num_twilight_points
> sfnt
->max_twilight_points
)
2267 sfnt
->max_twilight_points
= num_twilight_points
;
2269 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
2270 if (num_stack_elements
> sfnt
->max_stack_elements
)
2271 sfnt
->max_stack_elements
= num_stack_elements
;
2280 TA_hints_record_is_different(Hints_Record
* hints_records
,
2281 FT_UInt num_hints_records
,
2285 Hints_Record last_hints_record
;
2291 /* we only need to compare with the last hints record */
2292 last_hints_record
= hints_records
[num_hints_records
- 1];
2294 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
2297 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
2305 TA_add_hints_record(Hints_Record
** hints_records
,
2306 FT_UInt
* num_hints_records
,
2308 Hints_Record hints_record
)
2310 Hints_Record
* hints_records_new
;
2312 /* at this point, `hints_record.buf' still points into `ins_buf' */
2313 FT_Byte
* end
= hints_record
.buf
;
2316 buf_len
= (FT_UInt
)(end
- start
);
2318 /* now fill the structure completely */
2319 hints_record
.buf_len
= buf_len
;
2320 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
2321 if (!hints_record
.buf
)
2322 return FT_Err_Out_Of_Memory
;
2324 memcpy(hints_record
.buf
, start
, buf_len
);
2326 (*num_hints_records
)++;
2328 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
2329 * sizeof (Hints_Record
));
2330 if (!hints_records_new
)
2332 free(hints_record
.buf
);
2333 (*num_hints_records
)--;
2334 return FT_Err_Out_Of_Memory
;
2337 *hints_records
= hints_records_new
;
2339 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
2346 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
2347 Hints_Record
* hints_record
,
2352 FT_Bool need_words
= 0;
2355 FT_UInt num_arguments
;
2357 FT_UInt num_stack_elements
;
2360 /* check whether any argument is larger than 0xFF */
2361 endp
= hints_record
->buf
+ hints_record
->buf_len
;
2362 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
2366 /* with most fonts it is very rare */
2367 /* that any of the pushed arguments is larger than 0xFF, */
2368 /* thus we refrain from further optimizing this case */
2370 num_arguments
= hints_record
->buf_len
/ 2;
2375 for (i
= 0; i
< num_arguments
; i
+= 255)
2377 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2381 for (j
= 0; j
< num_args
; j
++)
2391 /* we only need the lower bytes */
2394 for (i
= 0; i
< num_arguments
; i
+= 255)
2396 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2400 for (j
= 0; j
< num_args
; j
++)
2408 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
2409 if (num_stack_elements
> sfnt
->max_stack_elements
)
2410 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
2417 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
2418 Hints_Record
* hints_records
,
2419 FT_UInt num_hints_records
,
2423 Hints_Record
* hints_record
;
2426 hints_record
= hints_records
;
2428 for (i
= 0; i
< num_hints_records
- 1; i
++)
2431 if (hints_record
->size
> 0xFF)
2434 BCI(HIGH((hints_record
+ 1)->size
));
2435 BCI(LOW((hints_record
+ 1)->size
));
2440 BCI((hints_record
+ 1)->size
);
2444 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2450 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2452 for (i
= 0; i
< num_hints_records
- 1; i
++)
2456 BCI(bci_hint_glyph
);
2464 TA_free_hints_records(Hints_Record
* hints_records
,
2465 FT_UInt num_hints_records
)
2470 for (i
= 0; i
< num_hints_records
; i
++)
2471 free(hints_records
[i
].buf
);
2473 free(hints_records
);
2478 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
2479 TA_Segment segments
,
2484 FT_UInt num_segs
= 0;
2487 seg_idx
= edge
->first
- segments
;
2489 /* we store everything as 16bit numbers */
2490 *(bufp
++) = HIGH(seg_idx
);
2491 *(bufp
++) = LOW(seg_idx
);
2493 seg
= edge
->first
->edge_next
;
2494 while (seg
!= edge
->first
)
2496 seg
= seg
->edge_next
;
2500 *(bufp
++) = HIGH(num_segs
);
2501 *(bufp
++) = LOW(num_segs
);
2503 seg
= edge
->first
->edge_next
;
2504 while (seg
!= edge
->first
)
2506 seg_idx
= seg
- segments
;
2507 seg
= seg
->edge_next
;
2509 *(bufp
++) = HIGH(seg_idx
);
2510 *(bufp
++) = LOW(seg_idx
);
2518 TA_hints_recorder(TA_Action action
,
2519 TA_GlyphHints hints
,
2525 TA_AxisHints axis
= &hints
->axis
[dim
];
2526 TA_Segment segments
= axis
->segments
;
2528 Recorder
* recorder
= (Recorder
*)hints
->user
;
2529 FONT
* font
= recorder
->font
;
2530 FT_Byte
* p
= recorder
->hints_record
.buf
;
2533 if (dim
== TA_DIMENSION_HORZ
)
2536 /* we ignore the BOUND action since the information is handled */
2537 /* in `ta_adjust_bound' and `ta_stem_bound' */
2538 if (action
== ta_bound
)
2542 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2546 case ta_adjust_bound
:
2547 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2548 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2549 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2553 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2554 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2555 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2560 TA_Edge base_edge
= (TA_Edge
)arg1
;
2561 TA_Edge stem_edge
= (TA_Edge
)arg2
;
2565 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
2567 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
2568 *(p
++) = HIGH(base_edge
->first
- segments
);
2569 *(p
++) = LOW(base_edge
->first
- segments
);
2570 *(p
++) = HIGH(stem_edge
->first
- segments
);
2571 *(p
++) = LOW(stem_edge
->first
- segments
);
2573 p
= TA_hints_recorder_handle_segments(p
, segments
, stem_edge
);
2579 TA_Edge edge
= (TA_Edge
)arg1
;
2580 TA_Edge edge2
= (TA_Edge
)arg2
;
2584 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
2586 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
2587 *(p
++) = HIGH(edge
->first
- segments
);
2588 *(p
++) = LOW(edge
->first
- segments
);
2589 *(p
++) = HIGH(edge2
->first
- segments
);
2590 *(p
++) = LOW(edge2
->first
- segments
);
2592 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2596 case ta_blue_anchor
:
2598 TA_Edge edge
= (TA_Edge
)arg1
;
2599 TA_Edge blue
= (TA_Edge
)arg2
;
2602 *(p
++) = HIGH(blue
->first
- segments
);
2603 *(p
++) = LOW(blue
->first
- segments
);
2605 if (edge
->best_blue_is_shoot
)
2607 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2608 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2612 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2613 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2616 *(p
++) = HIGH(edge
->first
- segments
);
2617 *(p
++) = LOW(edge
->first
- segments
);
2619 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2624 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2625 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2629 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2630 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2635 TA_Edge edge
= (TA_Edge
)arg1
;
2638 if (edge
->best_blue_is_shoot
)
2640 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2641 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2645 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2646 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2649 *(p
++) = HIGH(edge
->first
- segments
);
2650 *(p
++) = LOW(edge
->first
- segments
);
2652 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2657 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2660 case ta_serif_anchor
:
2661 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2664 case ta_serif_link1
:
2665 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2668 case ta_serif_link2
:
2669 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2672 /* to pacify the compiler */
2677 recorder
->hints_record
.num_actions
++;
2678 recorder
->hints_record
.buf
= p
;
2683 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2687 FT_Face face
= sfnt
->face
;
2694 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2695 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2696 GLYPH
* glyph
= &data
->glyphs
[idx
];
2698 TA_GlyphHints hints
;
2700 FT_UInt num_hints_records
;
2701 Hints_Record
* hints_records
;
2709 return FT_Err_Invalid_Argument
;
2711 /* computing the segments is resolution independent, */
2712 /* thus the pixel size in this call is arbitrary */
2713 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
2717 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2718 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
2722 /* do nothing if we have an empty glyph */
2723 if (!face
->glyph
->outline
.n_contours
)
2726 hints
= &font
->loader
->hints
;
2728 /* we allocate a buffer which is certainly large enough */
2729 /* to hold all of the created bytecode instructions; */
2730 /* later on it gets reallocated to its real size */
2731 ins_len
= hints
->num_points
* 1000;
2732 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2734 return FT_Err_Out_Of_Memory
;
2736 /* initialize array with an invalid bytecode */
2737 /* so that we can easily find the array length at reallocation time */
2738 memset(ins_buf
, INS_A0
, ins_len
);
2740 bufp
= TA_sfnt_build_glyph_segments(sfnt
, font
, ins_buf
);
2742 /* now we loop over a large range of pixel sizes */
2743 /* to find hints records which get pushed onto the bytecode stack */
2744 num_hints_records
= 0;
2745 hints_records
= NULL
;
2748 printf("glyph %ld\n", idx
);
2751 /* we temporarily use `ins_buf' to record the current glyph hints, */
2752 /* leaving two bytes at the beginning so that the number of actions */
2753 /* can be inserted later on */
2754 recorder
.font
= font
;
2755 ta_loader_register_hints_recorder(font
->loader
,
2759 for (size
= 8; size
<= 1000; size
++)
2761 /* rewind buffer pointer for recorder */
2762 recorder
.hints_record
.buf
= bufp
+ 2;
2763 recorder
.hints_record
.num_actions
= 0;
2764 recorder
.hints_record
.size
= size
;
2766 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2770 /* calling `ta_loader_load_glyph' uses the */
2771 /* `TA_hints_recorder' function as a callback, */
2772 /* modifying `hints_record' */
2773 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
2777 /* store the number of actions in `ins_buf' */
2778 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
2779 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
2781 if (TA_hints_record_is_different(hints_records
,
2783 bufp
, recorder
.hints_record
.buf
))
2790 printf(" %d:\n", size
);
2791 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
2792 printf(" %2d", *p
* 256 + *(p
+ 1));
2797 error
= TA_add_hints_record(&hints_records
,
2799 bufp
, recorder
.hints_record
);
2805 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
2807 /* don't emit anything if we only have a single empty record */
2815 /* otherwise, clear the temporarily used part of `ins_buf' */
2816 while (*p
!= INS_A0
)
2819 bufp
= TA_sfnt_emit_hints_records(sfnt
,
2820 hints_records
, num_hints_records
,
2823 /* we are done, so reallocate the instruction array to its real size */
2824 if (*bufp
== INS_A0
)
2826 /* search backwards */
2827 while (*bufp
== INS_A0
)
2833 /* search forwards */
2834 while (*bufp
!= INS_A0
)
2838 ins_len
= bufp
- ins_buf
;
2841 if (ins_len
> sfnt
->max_instructions
)
2842 sfnt
->max_instructions
= ins_len
;
2844 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2845 glyph
->ins_len
= ins_len
;
2847 TA_free_hints_records(hints_records
, num_hints_records
);
2852 TA_free_hints_records(hints_records
, num_hints_records
);
2860 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
2863 FT_Face face
= sfnt
->face
;
2868 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
2870 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
2878 /* end of tabytecode.c */