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_limit sal_k + 1
264 #define sal_num_segments sal_limit + 1
265 #define sal_scale sal_num_segments + 1
266 #define sal_0x10000 sal_scale + 1
267 #define sal_is_extra_light sal_0x10000 + 1
268 #define sal_anchor sal_is_extra_light + 1
269 #define sal_point_min sal_anchor + 1
270 #define sal_point_max sal_point_min + 1
271 #define sal_segment_offset sal_point_max + 1 /* must be last */
274 /* we need the following macro */
275 /* so that `func_name' doesn't get replaced with its #defined value */
276 /* (as defined in `tabytecode.h') */
278 #define FPGM(func_name) fpgm_ ## func_name
281 /* in the comments below, the top of the stack (`s:') */
282 /* is the rightmost element; the stack is shown */
283 /* after the instruction on the same line has been executed */
285 /* we use two sets of points in the twilight zone (zp0): */
286 /* one set to hold the unhinted segment positions, */
287 /* and another one to track the positions as changed by the hinting -- */
288 /* this is necessary since all points in zp0 */
289 /* have (0,0) as the original coordinates, */
290 /* making e.g. `MD_cur' return useless results */
294 * bci_compute_stem_width
296 * This is the equivalent to the following code from function
297 * `ta_latin_compute_stem_width':
305 * else if base_is_round:
311 * delta = ABS(dist - std_width)
314 * dist = MIN(48, std_width)
320 * delta = delta - dist
323 * dist = dist + delta
324 * else if delta < 32:
326 * else if delta < 54:
329 * dist = dist + delta
343 * sal: sal_is_extra_light
347 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
350 bci_compute_stem_width
,
354 ABS
, /* s: base_is_round stem_is_serif width dist */
359 LT
, /* dist < 3*64 */
363 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
364 AND
, /* stem_is_serif && dist < 3*64 */
369 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
371 IF
, /* s: base_is_round width dist */
377 ROLL
, /* s: width dist base_is_round */
378 IF
, /* s: width dist */
383 IF
, /* s: width dist */
394 IF
, /* s: width dist */
401 DUP
, /* s: width dist dist */
406 /* %c, index of std_width */
408 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
412 ABS
, /* s: width dist delta */
417 IF
, /* s: width dist */
424 /* %c, index of std_width */
426 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
429 MIN
, /* dist = min(48, std_width) */
432 DUP
, /* s: width dist dist */
435 LT
, /* dist < 3*64 */
437 DUP
, /* s: width delta dist */
438 FLOOR
, /* dist = FLOOR(dist) */
439 DUP
, /* s: width delta dist dist */
441 ROLL
, /* s: width dist delta dist */
442 SUB
, /* delta = delta - dist */
444 DUP
, /* s: width dist delta delta */
448 IF
, /* s: width dist delta */
449 ADD
, /* dist = dist + delta */
460 ADD
, /* dist = dist + 10 */
471 ADD
, /* dist = dist + 54 */
474 ADD
, /* dist = dist + delta */
484 FLOOR
, /* dist = round(dist) */
489 SWAP
, /* s: dist width */
494 NEG
, /* dist = -dist */
507 * Take a range and a function number and apply the function to all
508 * elements of the range. The called function must not change the
515 * uses: sal_i (counter initialized with `start')
519 unsigned char FPGM(bci_loop
) [] = {
526 ROLL
, /* s: func_num start end */
544 LTEQ
, /* start <= end */
545 IF
, /* s: func_num */
553 ADD
, /* start = start + 1 */
559 JMPR
, /* goto start_loop */
572 * Rescale CVT value by a given factor.
574 * uses: sal_i (CVT index)
575 * sal_scale (scale in 16.16 format)
578 unsigned char FPGM(bci_cvt_rescale
) [] = {
592 MUL
, /* CVT * scale * 2^10 */
596 DIV
, /* CVT * scale */
608 * Auxiliary function for `bci_set_up_segments'.
616 unsigned char FPGM(bci_sal_assign
) [] = {
623 ROLL
, /* s: offset offset data */
628 ADD
, /* s: (offset + 1) */
636 * bci_set_up_segments
638 * Set up segments by defining the point ranges which defines them
639 * and computing twilight points to represent them.
641 * in: num_segments (N)
648 * segment_start_(N-1)
651 * sal: sal_num_segments
653 * uses: bci_sal_assign
656 unsigned char FPGM(bci_set_up_segments
) [] = {
668 /* we have 2*num_segments arguments */
672 /* process the stack, popping off the elements in a loop */
681 bci_create_segment_points
,
692 * Round a blue ref value and adjust its corresponding shoot value.
694 * uses: sal_i (CVT index)
698 unsigned char FPGM(bci_blue_round_a
) [] = {
708 RCVT
, /* s: ref_idx ref */
715 SWAP
, /* s: ref_idx round(ref) ref */
723 unsigned char FPGM(bci_blue_round_b
) [] = {
727 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
729 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
731 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
733 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
735 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
760 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
765 NEG
, /* delta = -delta */
771 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
782 * bci_get_point_extrema
784 * An auxiliary function for `bci_create_segment_point'.
793 unsigned char FPGM(bci_get_point_extrema
) [] = {
796 bci_get_point_extrema
,
805 /* check whether `point' is a new minimum */
808 RS
, /* s: point point point point_min */
810 /* if distance is negative, we have a new minimum */
814 IF
, /* s: point point */
822 /* check whether `point' is a new maximum */
825 RS
, /* s: point point point_max */
827 /* if distance is positive, we have a new maximum */
845 * bci_create_segment_point
847 * Construct two points in the twilight zone to represent a segment:
848 * an original one (which stays unmodified) and a hinted one,
849 * initialized with the original value.
851 * This function is used by `bci_create_segment_points'.
853 * uses: bci_get_point_extrema
855 * sal: sal_i (start of current segment)
856 * sal_j (current original twilight point)
857 * sal_k (current hinted twilight point)
862 unsigned char FPGM(bci_create_segment_point
) [] = {
865 bci_create_segment_point
,
871 RS
, /* s: start_point */
874 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
886 SWAP
, /* s: start_point end_point start_point */
888 /* initialize inner loop */
893 WS
, /* sal_point_min = start_point */
898 WS
, /* sal_point_max = start_point */
900 SUB
, /* s: start_point loop_count */
905 SZP0
, /* set zp0 to normal zone 1 */
906 SZP1
, /* set zp1 to normal zone 1 */
908 /* all our measurements are taken along the y axis */
912 bci_get_point_extrema
,
917 /* the twilight point representing a segment */
918 /* is in the middle between the minimum and maximum */
936 MDAP_noround
, /* set rp0 and rp1 to `sal_point_min' */
937 SZP1
, /* set zp1 to twilight zone 0 */
938 SZP2
, /* set zp2 to twilight zone 0 */
941 DUP
, /* s: delta point[sal_j] point[sal_j] */
942 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
945 CINDEX
, /* s: delta point[sal_j] delta */
946 SHPIX
, /* shift `point[sal_j]' by `delta' */
951 DUP
, /* s: delta point[sal_k] point[sal_k] */
952 ALIGNRP
, /* align `point[sal_k]' with `sal_point_min' */
954 SHPIX
, /* shift `point[sal_k]' by `delta' */
964 ADD
, /* original_twilight_point = original_twilight_point + 1 */
967 ADD
, /* hinted_twilight_point = hinted_twilight_point + 1 */
976 * bci_create_segment_points
978 * Construct two sets of points in the twilight zone to represent segments.
979 * This function searches the points of a segment with the minimum and
980 * maximum y-values, then takes the median.
982 * uses: bci_create_segment_point
984 * sal: sal_i (start of current segment)
985 * sal_j (current original twilight point)
986 * sal_k (current hinted twilight point)
990 unsigned char FPGM(bci_create_segment_points
) [] = {
993 bci_create_segment_points
,
1006 WS
, /* sal_j = num_segments (offset for original points) */
1007 WS
, /* sal_k = 0 (offset for hinted points) */
1015 SUB
, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1018 bci_create_segment_point
,
1026 unsigned char FPGM(bci_handle_segment
) [] = {
1032 POP
, /* XXX segment */
1042 * Align all points in a segment to the twilight point in rp0.
1043 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1048 unsigned char FPGM(bci_align_segment
) [] = {
1054 /* we need the values of `sal_segment_offset + 2*segment_index' */
1055 /* and `sal_segment_offset + 2*segment_index + 1' */
1067 RS
, /* s: first last */
1072 CINDEX
, /* s: first last first */
1075 CINDEX
, /* s: first last first last */
1076 LTEQ
, /* first <= end */
1077 IF
, /* s: first last */
1079 DUP
, /* s: last first first */
1080 ALIGNRP
, /* align point with index `first' with rp0 */
1084 ADD
, /* first = first + 1 */
1085 SWAP
, /* s: first last */
1090 JMPR
, /* goto start_loop */
1100 unsigned char FPGM(bci_handle_segments
) [] = {
1103 bci_handle_segments
,
1106 POP
, /* XXX first segment */
1118 * bci_align_segments
1120 * Align segments to the twilight point in rp0.
1121 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1130 * uses: handle_segment
1134 unsigned char FPGM(bci_align_segments
) [] = {
1153 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1156 bci_action_adjust_bound
,
1160 bci_handle_segments
,
1163 bci_handle_segments
,
1166 bci_handle_segments
,
1175 unsigned char FPGM(bci_action_stem_bound
) [] = {
1178 bci_action_stem_bound
,
1182 bci_handle_segments
,
1185 bci_handle_segments
,
1188 bci_handle_segments
,
1201 * Handle the LINK action to link an edge to another one.
1205 * base_point (in twilight zone)
1206 * stem_point (in twilight zone)
1207 * ... stuff for bci_align_segments ...
1210 unsigned char FPGM(bci_action_link
) [] = {
1218 SZPS
, /* set zp0, zp1, and zp2 to twilight zone 0 */
1231 MDAP_noround
, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1235 ADD
, /* s: stem is_round is_serif stem_orig base_orig */
1237 MD_cur
, /* s: stem is_round is_serif dist_orig */
1240 bci_compute_stem_width
,
1241 CALL
, /* s: stem new_dist */
1245 ALIGNRP
, /* align `stem_point' with `base_point' */
1247 MDAP_noround
, /* set rp0 and rp1 to `stem_point' */
1249 SHPIX
, /* stem_point = base_point + new_dist */
1254 SZP1
, /* set zp1 to normal zone 1 */
1261 unsigned char FPGM(bci_action_anchor
) [] = {
1268 bci_handle_segments
,
1271 bci_handle_segments
,
1282 * bci_action_blue_anchor
1284 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1285 * and to set the edge anchor.
1287 * in: anchor_point (in twilight zone)
1289 * edge_point (in twilight zone)
1290 * ... stuff for bci_align_segments ...
1295 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1298 bci_action_blue_anchor
,
1301 /* store anchor point number in `sal_anchor' */
1309 SZP0
, /* set zp0 to twilight zone 0 */
1311 /* move `edge_point' to `blue_cvt_idx' position */
1312 MIAP_noround
, /* this also sets rp0 */
1317 SZP1
, /* set zp1 to normal zone 1 */
1324 unsigned char FPGM(bci_action_adjust
) [] = {
1331 bci_handle_segments
,
1334 bci_handle_segments
,
1343 unsigned char FPGM(bci_action_stem
) [] = {
1350 bci_handle_segments
,
1353 bci_handle_segments
,
1366 * Handle the BLUE action to align an edge with a blue zone.
1369 * edge_point (in twilight zone)
1370 * ... stuff for bci_align_segments ...
1373 unsigned char FPGM(bci_action_blue
) [] = {
1381 SZP0
, /* set zp0 to twilight zone 0 */
1383 /* move `edge_point' to `blue_cvt_idx' position */
1384 MIAP_noround
, /* this also sets rp0 */
1389 SZP1
, /* set zp1 to normal zone 1 */
1396 unsigned char FPGM(bci_action_serif
) [] = {
1403 bci_handle_segments
,
1412 unsigned char FPGM(bci_action_serif_anchor
) [] = {
1415 bci_action_serif_anchor
,
1419 bci_handle_segments
,
1428 unsigned char FPGM(bci_action_serif_link1
) [] = {
1431 bci_action_serif_link1
,
1435 bci_handle_segments
,
1444 unsigned char FPGM(bci_action_serif_link2
) [] = {
1447 bci_action_serif_link2
,
1451 bci_handle_segments
,
1466 * in: function_index
1469 unsigned char FPGM(bci_handle_action
) [] = {
1485 * This is the top-level glyph hinting function
1486 * which parses the arguments on the stack and calls subroutines.
1488 * in: num_actions (M)
1497 * uses: bci_handle_action
1498 * bci_action_adjust_bound
1499 * bci_action_stem_bound
1503 * bci_action_blue_anchor
1509 * bci_action_serif_anchor
1510 * bci_action_serif_link1
1511 * bci_action_serif_link2
1514 unsigned char FPGM(bci_hint_glyph
) [] = {
1529 #define COPY_FPGM(func_name) \
1530 memcpy(buf_p, fpgm_ ## func_name, \
1531 sizeof (fpgm_ ## func_name)); \
1532 buf_p += sizeof (fpgm_ ## func_name) \
1535 TA_table_build_fpgm(FT_Byte
** fpgm
,
1545 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
1547 + sizeof (FPGM(bci_compute_stem_width_b
))
1549 + sizeof (FPGM(bci_compute_stem_width_c
))
1550 + sizeof (FPGM(bci_loop
))
1551 + sizeof (FPGM(bci_cvt_rescale
))
1552 + sizeof (FPGM(bci_sal_assign
))
1553 + sizeof (FPGM(bci_set_up_segments
))
1554 + sizeof (FPGM(bci_blue_round_a
))
1556 + sizeof (FPGM(bci_blue_round_b
))
1557 + sizeof (FPGM(bci_get_point_extrema
))
1558 + sizeof (FPGM(bci_create_segment_point
))
1559 + sizeof (FPGM(bci_create_segment_points
))
1560 + sizeof (FPGM(bci_handle_segment
))
1561 + sizeof (FPGM(bci_align_segment
))
1562 + sizeof (FPGM(bci_handle_segments
))
1563 + sizeof (FPGM(bci_align_segments
))
1564 + sizeof (FPGM(bci_action_adjust_bound
))
1565 + sizeof (FPGM(bci_action_stem_bound
))
1566 + sizeof (FPGM(bci_action_link
))
1567 + sizeof (FPGM(bci_action_anchor
))
1568 + sizeof (FPGM(bci_action_blue_anchor
))
1569 + sizeof (FPGM(bci_action_adjust
))
1570 + sizeof (FPGM(bci_action_stem
))
1571 + sizeof (FPGM(bci_action_blue
))
1572 + sizeof (FPGM(bci_action_serif
))
1573 + sizeof (FPGM(bci_action_serif_anchor
))
1574 + sizeof (FPGM(bci_action_serif_link1
))
1575 + sizeof (FPGM(bci_action_serif_link2
))
1576 + sizeof (FPGM(bci_handle_action
))
1577 + sizeof (FPGM(bci_hint_glyph
));
1578 /* buffer length must be a multiple of four */
1579 len
= (buf_len
+ 3) & ~3;
1580 buf
= (FT_Byte
*)malloc(len
);
1582 return FT_Err_Out_Of_Memory
;
1584 /* pad end of buffer with zeros */
1585 buf
[len
- 1] = 0x00;
1586 buf
[len
- 2] = 0x00;
1587 buf
[len
- 3] = 0x00;
1589 /* copy font program into buffer and fill in the missing variables */
1592 COPY_FPGM(bci_compute_stem_width_a
);
1593 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1594 COPY_FPGM(bci_compute_stem_width_b
);
1595 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1596 COPY_FPGM(bci_compute_stem_width_c
);
1597 COPY_FPGM(bci_loop
);
1598 COPY_FPGM(bci_cvt_rescale
);
1599 COPY_FPGM(bci_sal_assign
);
1600 COPY_FPGM(bci_set_up_segments
);
1601 COPY_FPGM(bci_blue_round_a
);
1602 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
1603 COPY_FPGM(bci_blue_round_b
);
1604 COPY_FPGM(bci_get_point_extrema
);
1605 COPY_FPGM(bci_create_segment_point
);
1606 COPY_FPGM(bci_create_segment_points
);
1607 COPY_FPGM(bci_handle_segment
);
1608 COPY_FPGM(bci_align_segment
);
1609 COPY_FPGM(bci_handle_segments
);
1610 COPY_FPGM(bci_align_segments
);
1611 COPY_FPGM(bci_action_adjust_bound
);
1612 COPY_FPGM(bci_action_stem_bound
);
1613 COPY_FPGM(bci_action_link
);
1614 COPY_FPGM(bci_action_anchor
);
1615 COPY_FPGM(bci_action_blue_anchor
);
1616 COPY_FPGM(bci_action_adjust
);
1617 COPY_FPGM(bci_action_stem
);
1618 COPY_FPGM(bci_action_blue
);
1619 COPY_FPGM(bci_action_serif
);
1620 COPY_FPGM(bci_action_serif_anchor
);
1621 COPY_FPGM(bci_action_serif_link1
);
1622 COPY_FPGM(bci_action_serif_link2
);
1623 COPY_FPGM(bci_handle_action
);
1624 COPY_FPGM(bci_hint_glyph
);
1627 *fpgm_len
= buf_len
;
1634 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
1643 error
= TA_sfnt_add_table_info(sfnt
);
1647 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
1651 /* in case of success, `fpgm_buf' gets linked */
1652 /* and is eventually freed in `TA_font_unload' */
1653 error
= TA_font_add_table(font
,
1654 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1655 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
1666 /* the `prep' instructions */
1668 #define PREP(snippet_name) prep_ ## snippet_name
1670 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1671 /* thus we provide it in the storage area */
1673 unsigned char PREP(store_0x10000
) [] = {
1687 unsigned char PREP(align_top_a
) [] = {
1689 /* optimize the alignment of the top of small letters to the pixel grid */
1695 /* %c, index of alignment blue zone */
1697 unsigned char PREP(align_top_b
) [] = {
1705 FLOOR
, /* fitted = FLOOR(scaled + 40) */
1706 DUP
, /* s: scaled scaled fitted fitted */
1709 IF
, /* s: scaled fitted */
1713 MUL
, /* scaled in 16.16 format */
1715 DIV
, /* (fitted / scaled) in 16.16 format */
1724 unsigned char PREP(loop_cvt_a
) [] = {
1726 /* loop over vertical CVT entries */
1731 /* %c, first vertical index */
1732 /* %c, last vertical index */
1734 unsigned char PREP(loop_cvt_b
) [] = {
1740 /* loop over blue refs */
1745 /* %c, first blue ref index */
1746 /* %c, last blue ref index */
1748 unsigned char PREP(loop_cvt_c
) [] = {
1754 /* loop over blue shoots */
1759 /* %c, first blue shoot index */
1760 /* %c, last blue shoot index */
1762 unsigned char PREP(loop_cvt_d
) [] = {
1771 unsigned char PREP(compute_extra_light_a
) [] = {
1773 /* compute (vertical) `extra_light' flag */
1780 /* %c, index of vertical standard_width */
1782 unsigned char PREP(compute_extra_light_b
) [] = {
1785 GT
, /* standard_width < 40 */
1790 unsigned char PREP(round_blues_a
) [] = {
1792 /* use discrete values for blue zone widths */
1797 /* %c, first blue ref index */
1798 /* %c, last blue ref index */
1800 unsigned char PREP(round_blues_b
) [] = {
1808 /* XXX talatin.c: 1671 */
1809 /* XXX talatin.c: 1708 */
1810 /* XXX talatin.c: 2182 */
1813 #define COPY_PREP(snippet_name) \
1814 memcpy(buf_p, prep_ ## snippet_name, \
1815 sizeof (prep_ ## snippet_name)); \
1816 buf_p += sizeof (prep_ ## snippet_name);
1819 TA_table_build_prep(FT_Byte
** prep
,
1824 TA_LatinBlue blue_adjustment
;
1833 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
1834 blue_adjustment
= NULL
;
1836 for (i
= 0; i
< vaxis
->blue_count
; i
++)
1838 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
1840 blue_adjustment
= &vaxis
->blues
[i
];
1845 buf_len
= sizeof (PREP(store_0x10000
));
1847 if (blue_adjustment
)
1848 buf_len
+= sizeof (PREP(align_top_a
))
1850 + sizeof (PREP(align_top_b
))
1851 + sizeof (PREP(loop_cvt_a
))
1853 + sizeof (PREP(loop_cvt_b
))
1855 + sizeof (PREP(loop_cvt_c
))
1857 + sizeof (PREP(loop_cvt_d
));
1859 buf_len
+= sizeof (PREP(compute_extra_light_a
))
1861 + sizeof (PREP(compute_extra_light_b
));
1863 if (CVT_BLUES_SIZE(font
))
1864 buf_len
+= sizeof (PREP(round_blues_a
))
1866 + sizeof (PREP(round_blues_b
));
1868 /* buffer length must be a multiple of four */
1869 len
= (buf_len
+ 3) & ~3;
1870 buf
= (FT_Byte
*)malloc(len
);
1872 return FT_Err_Out_Of_Memory
;
1874 /* pad end of buffer with zeros */
1875 buf
[len
- 1] = 0x00;
1876 buf
[len
- 2] = 0x00;
1877 buf
[len
- 3] = 0x00;
1879 /* copy cvt program into buffer and fill in the missing variables */
1882 COPY_PREP(store_0x10000
);
1884 if (blue_adjustment
)
1886 COPY_PREP(align_top_a
);
1887 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1888 + blue_adjustment
- vaxis
->blues
);
1889 COPY_PREP(align_top_b
);
1891 COPY_PREP(loop_cvt_a
);
1892 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1893 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
1894 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
1895 COPY_PREP(loop_cvt_b
);
1896 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1897 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1898 + CVT_BLUES_SIZE(font
) - 1);
1899 COPY_PREP(loop_cvt_c
);
1900 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
1901 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1902 + CVT_BLUES_SIZE(font
) - 1);
1903 COPY_PREP(loop_cvt_d
);
1906 COPY_PREP(compute_extra_light_a
);
1907 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
1908 COPY_PREP(compute_extra_light_b
);
1910 if (CVT_BLUES_SIZE(font
))
1912 COPY_PREP(round_blues_a
);
1913 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1914 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1915 + CVT_BLUES_SIZE(font
) - 1);
1916 COPY_PREP(round_blues_b
);
1920 *prep_len
= buf_len
;
1927 TA_sfnt_build_prep_table(SFNT
* sfnt
,
1936 error
= TA_sfnt_add_table_info(sfnt
);
1940 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
1944 /* in case of success, `prep_buf' gets linked */
1945 /* and is eventually freed in `TA_font_unload' */
1946 error
= TA_font_add_table(font
,
1947 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1948 TTAG_prep
, prep_len
, prep_buf
);
1959 /* we store the segments in the storage area; */
1960 /* each segment record consists of the first and last point */
1963 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
1967 TA_GlyphHints hints
= &font
->loader
->hints
;
1968 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1969 TA_Point points
= hints
->points
;
1970 TA_Segment segments
= axis
->segments
;
1972 TA_Segment seg_limit
;
1979 FT_Bool need_words
= 0;
1982 FT_UInt num_storage
;
1983 FT_UInt num_stack_elements
;
1984 FT_UInt num_twilight_points
;
1987 seg_limit
= segments
+ axis
->num_segments
;
1988 num_args
= 2 * axis
->num_segments
+ 3;
1990 /* collect all arguments temporarily in an array (in reverse order) */
1991 /* so that we can easily split into chunks of 255 args */
1992 /* as needed by NPUSHB and NPUSHW, respectively */
1993 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1997 arg
= args
+ num_args
- 1;
1999 if (axis
->num_segments
> 0xFF)
2002 *(arg
--) = bci_set_up_segments
;
2003 *(arg
--) = axis
->num_segments
;
2004 *(arg
--) = sal_segment_offset
;
2006 for (seg
= segments
; seg
< seg_limit
; seg
++)
2008 FT_UInt first
= seg
->first
- points
;
2009 FT_UInt last
= seg
->last
- points
;
2015 if (first
> 0xFF || last
> 0xFF)
2019 /* with most fonts it is very rare */
2020 /* that any of the pushed arguments is larger than 0xFF, */
2021 /* thus we refrain from further optimizing this case */
2027 for (i
= 0; i
< num_args
; i
+= 255)
2029 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
2033 for (j
= 0; j
< nargs
; j
++)
2043 for (i
= 0; i
< num_args
; i
+= 255)
2045 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
2049 for (j
= 0; j
< nargs
; j
++)
2059 num_storage
= sal_segment_offset
+ axis
->num_segments
* 2;
2060 if (num_storage
> sfnt
->max_storage
)
2061 sfnt
->max_storage
= num_storage
;
2063 num_twilight_points
= axis
->num_segments
* 2;
2064 if (num_twilight_points
> sfnt
->max_twilight_points
)
2065 sfnt
->max_twilight_points
= num_twilight_points
;
2067 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
2068 if (num_stack_elements
> sfnt
->max_stack_elements
)
2069 sfnt
->max_stack_elements
= num_stack_elements
;
2078 TA_hints_record_is_different(Hints_Record
* hints_records
,
2079 FT_UInt num_hints_records
,
2083 Hints_Record last_hints_record
;
2089 /* we only need to compare with the last hints record */
2090 last_hints_record
= hints_records
[num_hints_records
- 1];
2092 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
2095 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
2103 TA_add_hints_record(Hints_Record
** hints_records
,
2104 FT_UInt
* num_hints_records
,
2106 Hints_Record hints_record
)
2108 Hints_Record
* hints_records_new
;
2110 /* at this point, `hints_record.buf' still points into `ins_buf' */
2111 FT_Byte
* end
= hints_record
.buf
;
2114 buf_len
= (FT_UInt
)(end
- start
);
2116 /* now fill the structure completely */
2117 hints_record
.buf_len
= buf_len
;
2118 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
2119 if (!hints_record
.buf
)
2120 return FT_Err_Out_Of_Memory
;
2122 memcpy(hints_record
.buf
, start
, buf_len
);
2124 (*num_hints_records
)++;
2126 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
2127 * sizeof (Hints_Record
));
2128 if (!hints_records_new
)
2130 free(hints_record
.buf
);
2131 (*num_hints_records
)--;
2132 return FT_Err_Out_Of_Memory
;
2135 *hints_records
= hints_records_new
;
2137 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
2144 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
2145 Hints_Record
* hints_record
,
2150 FT_Bool need_words
= 0;
2153 FT_UInt num_arguments
;
2155 FT_UInt num_stack_elements
;
2158 /* check whether any argument is larger than 0xFF */
2159 endp
= hints_record
->buf
+ hints_record
->buf_len
;
2160 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
2164 /* with most fonts it is very rare */
2165 /* that any of the pushed arguments is larger than 0xFF, */
2166 /* thus we refrain from further optimizing this case */
2168 num_arguments
= hints_record
->buf_len
/ 2;
2173 for (i
= 0; i
< num_arguments
; i
+= 255)
2175 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2179 for (j
= 0; j
< num_args
; j
++)
2189 /* we only need the lower bytes */
2192 for (i
= 0; i
< num_arguments
; i
+= 255)
2194 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2198 for (j
= 0; j
< num_args
; j
++)
2206 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
2207 if (num_stack_elements
> sfnt
->max_stack_elements
)
2208 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
2215 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
2216 Hints_Record
* hints_records
,
2217 FT_UInt num_hints_records
,
2221 Hints_Record
* hints_record
;
2224 hints_record
= hints_records
;
2226 for (i
= 0; i
< num_hints_records
- 1; i
++)
2229 if (hints_record
->size
> 0xFF)
2232 BCI(HIGH((hints_record
+ 1)->size
));
2233 BCI(LOW((hints_record
+ 1)->size
));
2238 BCI((hints_record
+ 1)->size
);
2242 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2248 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2250 for (i
= 0; i
< num_hints_records
- 1; i
++)
2254 BCI(bci_hint_glyph
);
2262 TA_free_hints_records(Hints_Record
* hints_records
,
2263 FT_UInt num_hints_records
)
2268 for (i
= 0; i
< num_hints_records
; i
++)
2269 free(hints_records
[i
].buf
);
2271 free(hints_records
);
2276 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
2277 TA_Segment segments
,
2282 FT_UInt num_segs
= 0;
2285 seg_idx
= edge
->first
- segments
;
2287 /* we store everything as 16bit numbers */
2288 *(bufp
++) = HIGH(seg_idx
);
2289 *(bufp
++) = LOW(seg_idx
);
2291 seg
= edge
->first
->edge_next
;
2292 while (seg
!= edge
->first
)
2294 seg
= seg
->edge_next
;
2298 *(bufp
++) = HIGH(num_segs
);
2299 *(bufp
++) = LOW(num_segs
);
2301 seg
= edge
->first
->edge_next
;
2302 while (seg
!= edge
->first
)
2304 seg_idx
= seg
- segments
;
2305 seg
= seg
->edge_next
;
2307 *(bufp
++) = HIGH(seg_idx
);
2308 *(bufp
++) = LOW(seg_idx
);
2316 TA_hints_recorder(TA_Action action
,
2317 TA_GlyphHints hints
,
2323 TA_AxisHints axis
= &hints
->axis
[dim
];
2324 TA_Segment segments
= axis
->segments
;
2326 Recorder
* recorder
= (Recorder
*)hints
->user
;
2327 FONT
* font
= recorder
->font
;
2328 FT_Byte
* p
= recorder
->hints_record
.buf
;
2331 if (dim
== TA_DIMENSION_HORZ
)
2334 /* we ignore the BOUND action since the information is handled */
2335 /* in `ta_adjust_bound' and `ta_stem_bound' */
2336 if (action
== ta_bound
)
2340 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2344 case ta_adjust_bound
:
2345 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2346 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2347 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2351 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2352 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2353 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2358 TA_Edge base_edge
= (TA_Edge
)arg1
;
2359 TA_Edge stem_edge
= (TA_Edge
)arg2
;
2363 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
2365 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
2366 *(p
++) = HIGH(base_edge
->first
- segments
);
2367 *(p
++) = LOW(base_edge
->first
- segments
);
2368 *(p
++) = HIGH(stem_edge
->first
- segments
);
2369 *(p
++) = LOW(stem_edge
->first
- segments
);
2371 p
= TA_hints_recorder_handle_segments(p
, segments
, stem_edge
);
2376 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2377 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2380 case ta_blue_anchor
:
2382 TA_Edge edge
= (TA_Edge
)arg1
;
2383 TA_Edge blue
= (TA_Edge
)arg2
;
2386 *(p
++) = HIGH(blue
->first
- segments
);
2387 *(p
++) = LOW(blue
->first
- segments
);
2389 if (edge
->best_blue_is_shoot
)
2391 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2392 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2396 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2397 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2400 *(p
++) = HIGH(edge
->first
- segments
);
2401 *(p
++) = LOW(edge
->first
- segments
);
2403 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2408 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2409 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2413 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2414 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2419 TA_Edge edge
= (TA_Edge
)arg1
;
2422 if (edge
->best_blue_is_shoot
)
2424 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2425 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2429 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2430 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2433 *(p
++) = HIGH(edge
->first
- segments
);
2434 *(p
++) = LOW(edge
->first
- segments
);
2436 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2441 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2444 case ta_serif_anchor
:
2445 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2448 case ta_serif_link1
:
2449 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2452 case ta_serif_link2
:
2453 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2456 /* to pacify the compiler */
2461 recorder
->hints_record
.num_actions
++;
2462 recorder
->hints_record
.buf
= p
;
2467 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2471 FT_Face face
= sfnt
->face
;
2478 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2479 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2480 GLYPH
* glyph
= &data
->glyphs
[idx
];
2482 TA_GlyphHints hints
;
2484 FT_UInt num_hints_records
;
2485 Hints_Record
* hints_records
;
2493 return FT_Err_Invalid_Argument
;
2495 /* computing the segments is resolution independent, */
2496 /* thus the pixel size in this call is arbitrary */
2497 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
2501 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2502 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
2506 /* do nothing if we have an empty glyph */
2507 if (!face
->glyph
->outline
.n_contours
)
2510 hints
= &font
->loader
->hints
;
2512 /* we allocate a buffer which is certainly large enough */
2513 /* to hold all of the created bytecode instructions; */
2514 /* later on it gets reallocated to its real size */
2515 ins_len
= hints
->num_points
* 1000;
2516 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2518 return FT_Err_Out_Of_Memory
;
2520 /* initialize array with an invalid bytecode */
2521 /* so that we can easily find the array length at reallocation time */
2522 memset(ins_buf
, INS_A0
, ins_len
);
2524 bufp
= TA_sfnt_build_glyph_segments(sfnt
, font
, ins_buf
);
2526 /* now we loop over a large range of pixel sizes */
2527 /* to find hints records which get pushed onto the bytecode stack */
2528 num_hints_records
= 0;
2529 hints_records
= NULL
;
2532 printf("glyph %ld\n", idx
);
2535 /* we temporarily use `ins_buf' to record the current glyph hints, */
2536 /* leaving two bytes at the beginning so that the number of actions */
2537 /* can be inserted later on */
2538 recorder
.font
= font
;
2539 ta_loader_register_hints_recorder(font
->loader
,
2543 for (size
= 8; size
<= 1000; size
++)
2545 /* rewind buffer pointer for recorder */
2546 recorder
.hints_record
.buf
= bufp
+ 2;
2547 recorder
.hints_record
.num_actions
= 0;
2548 recorder
.hints_record
.size
= size
;
2550 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2554 /* calling `ta_loader_load_glyph' uses the */
2555 /* `TA_hints_recorder' function as a callback, */
2556 /* modifying `hints_record' */
2557 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
2561 /* store the number of actions in `ins_buf' */
2562 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
2563 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
2565 if (TA_hints_record_is_different(hints_records
,
2567 bufp
, recorder
.hints_record
.buf
))
2574 printf(" %d:\n", size
);
2575 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
2576 printf(" %2d", *p
* 256 + *(p
+ 1));
2581 error
= TA_add_hints_record(&hints_records
,
2583 bufp
, recorder
.hints_record
);
2589 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
2591 /* don't emit anything if we only have a single empty record */
2599 /* otherwise, clear the temporarily used part of `ins_buf' */
2600 while (*p
!= INS_A0
)
2603 bufp
= TA_sfnt_emit_hints_records(sfnt
,
2604 hints_records
, num_hints_records
,
2607 /* we are done, so reallocate the instruction array to its real size */
2608 if (*bufp
== INS_A0
)
2610 /* search backwards */
2611 while (*bufp
== INS_A0
)
2617 /* search forwards */
2618 while (*bufp
!= INS_A0
)
2622 ins_len
= bufp
- ins_buf
;
2625 if (ins_len
> sfnt
->max_instructions
)
2626 sfnt
->max_instructions
= ins_len
;
2628 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2629 glyph
->ins_len
= ins_len
;
2631 TA_free_hints_records(hints_records
, num_hints_records
);
2636 TA_free_hints_records(hints_records
, num_hints_records
);
2644 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
2647 FT_Face face
= sfnt
->face
;
2652 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
2654 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
2662 /* end of tabytecode.c */