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_limit sal_j + 1
263 #define sal_scale sal_limit + 1
264 #define sal_0x10000 sal_scale + 1
265 #define sal_is_extra_light sal_0x10000 + 1
266 #define sal_pos sal_is_extra_light + 1
267 #define sal_anchor sal_pos + 1
268 #define sal_point_min sal_anchor + 1
269 #define sal_point_max sal_point_min + 1
270 #define sal_segment_offset sal_point_max + 1 /* must be last */
273 /* we need the following macro */
274 /* so that `func_name' doesn't get replaced with its #defined value */
275 /* (as defined in `tabytecode.h') */
277 #define FPGM(func_name) fpgm_ ## func_name
280 /* in the comments below, the top of the stack (`s:') */
281 /* is the rightmost element; the stack is shown */
282 /* after the instruction on the same line has been executed */
284 /* point 0 in the twilight zone (zp0) is originally located */
285 /* at the origin; we don't change that */
288 * bci_compute_stem_width
290 * This is the equivalent to the following code from function
291 * `ta_latin_compute_stem_width':
299 * else if base_is_round:
305 * delta = ABS(dist - std_width)
308 * dist = MIN(48, std_width)
314 * delta = delta - dist
317 * dist = dist + delta
318 * else if delta < 32:
320 * else if delta < 54:
323 * dist = dist + delta
337 * sal: sal_is_extra_light
341 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
344 bci_compute_stem_width
,
348 ABS
, /* s: base_is_round stem_is_serif width dist */
353 LT
, /* dist < 3*64 */
357 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
358 AND
, /* stem_is_serif && dist < 3*64 */
363 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
365 IF
, /* s: base_is_round width dist */
371 ROLL
, /* s: width dist base_is_round */
372 IF
, /* s: width dist */
377 IF
, /* s: width dist */
388 IF
, /* s: width dist */
395 DUP
, /* s: width dist dist */
400 /* %c, index of std_width */
402 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
406 ABS
, /* s: width dist delta */
411 IF
, /* s: width dist */
418 /* %c, index of std_width */
420 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
423 MIN
, /* dist = min(48, std_width) */
426 DUP
, /* s: width dist dist */
429 LT
, /* dist < 3*64 */
431 DUP
, /* s: width delta dist */
432 FLOOR
, /* dist = FLOOR(dist) */
433 DUP
, /* s: width delta dist dist */
435 ROLL
, /* s: width dist delta dist */
436 SUB
, /* delta = delta - dist */
438 DUP
, /* s: width dist delta delta */
442 IF
, /* s: width dist delta */
443 ADD
, /* dist = dist + delta */
454 ADD
, /* dist = dist + 10 */
465 ADD
, /* dist = dist + 54 */
468 ADD
, /* dist = dist + delta */
478 FLOOR
, /* dist = round(dist) */
483 SWAP
, /* s: dist width */
488 NEG
, /* dist = -dist */
501 * Take a range and a function number and apply the function to all
502 * elements of the range. The called function must not change the
509 * uses: sal_i (counter initialized with `start')
513 unsigned char FPGM(bci_loop
) [] = {
520 ROLL
, /* s: func_num start end */
538 LTEQ
, /* start <= end */
539 IF
, /* s: func_num */
547 ADD
, /* start = start + 1 */
553 JMPR
, /* goto start_loop */
566 * Rescale CVT value by a given factor.
568 * uses: sal_i (CVT index)
569 * sal_scale (scale in 16.16 format)
572 unsigned char FPGM(bci_cvt_rescale
) [] = {
586 MUL
, /* CVT * scale * 2^10 */
590 DIV
, /* CVT * scale */
600 * bci_loop_sal_assign
602 * Apply the WS instruction repeatedly to stack data.
611 * uses: bci_sal_assign
614 unsigned char FPGM(bci_sal_assign
) [] = {
621 ROLL
, /* s: offset offset data */
626 ADD
, /* s: (offset + 1) */
632 unsigned char FPGM(bci_loop_sal_assign
) [] = {
638 /* process the stack, popping off the elements in a loop */
654 * Round a blue ref value and adjust its corresponding shoot value.
656 * uses: sal_i (CVT index)
660 unsigned char FPGM(bci_blue_round_a
) [] = {
670 RCVT
, /* s: ref_idx ref */
677 SWAP
, /* s: ref_idx round(ref) ref */
685 unsigned char FPGM(bci_blue_round_b
) [] = {
689 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
691 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
693 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
695 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
697 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
722 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
727 NEG
, /* delta = -delta */
733 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
744 * bci_get_point_extrema
746 * An auxiliary function for `bci_create_segment_point'.
755 unsigned char FPGM(bci_get_point_extrema
) [] = {
758 bci_get_point_extrema
,
767 /* check whether current point is a new minimum */
770 RS
, /* s: point point point point_min */
772 /* if distance is negative, we have a new minimum */
776 IF
, /* s: point point */
784 /* check whether current point is a new maximum */
787 RS
, /* s: point point point_max */
789 /* if distance is positive, we have a new maximum */
793 IF
, /* s: point point */
808 * bci_create_segment_point
810 * Construct a point in the twilight zone which represents a segment.
811 * This function is used by `bci_create_segment_points'.
813 * uses: bci_get_point_extrema
815 * sal: sal_i (start of current segment)
816 * sal_j (current twilight point)
821 unsigned char FPGM(bci_create_segment_point
) [] = {
824 bci_create_segment_point
,
830 RS
, /* s: start_point */
833 /* increase `sal_i'; with the outer loop, this makes sal_i += 2 */
845 SWAP
, /* s: start_point end_point start_point */
847 /* initialize inner loop */
852 WS
, /* sal_point_min = start_point */
857 WS
, /* sal_point_max = start_point */
859 SUB
, /* s: start_point loop_count */
864 SZP0
, /* set zp0 to normal zone 1 */
865 SZP1
, /* set zp1 to normal zone 1 */
868 bci_get_point_extrema
,
873 /* the twilight point representing a segment */
874 /* is in the middle between the minimum and maximum */
883 32, /* do the division with proper rounding */
895 MDAP_noround
, /* set rp0 and rp1 tp `sal_point_min' */
896 SZP1
, /* set zp1 to twilight zone 0 */
897 SZP2
, /* set zp2 to twilight zone 0 */
900 DUP
, /* delta point[sal_j] point[sal_j] */
901 ALIGNRP
, /* align `point[sal_j]' with `sal_point_min' */
903 SHPIX
, /* shift `point[sal_j]' by `delta' */
910 ADD
, /* twilight_point = twilight_point + 1 */
919 * bci_create_segment_points
921 * Construct points in the twilight zone which represent segments. This
922 * function searches the points of a segment with the minimum and maximum
923 * y-values, then takes the median.
927 * uses: bci_create_segment_point
929 * sal: sal_i (start of current segment)
930 * sal_j (current twilight point)
933 unsigned char FPGM(bci_create_segment_points
) [] = {
936 bci_create_segment_points
,
945 ADD
, /* s: start_seg_1 end_seg_N */
953 bci_create_segment_point
,
964 unsigned char FPGM(bci_handle_segment
) [] = {
970 POP
, /* XXX segment */
980 * Align all points in a segment to the value in `sal_pos'.
987 unsigned char FPGM(bci_align_segment
) [] = {
1000 SZP0
, /* set zp0 to twilight zone 0 */
1001 SZP1
, /* set zp1 to twilight zone 0 */
1003 /* we can't directly set rp0 to a stack value */
1004 MDAP_noround
, /* reset rp0 (and rp1) to the origin in the twilight zone */
1006 MSIRP_rp0
, /* set point 1 and rp0 in the twilight zone to `sal_pos' */
1008 SZP1
, /* set zp1 to normal zone 1 */
1010 /* we need the values of `sal_segment_offset + 2*segment_index' */
1011 /* and `sal_segment_offset + 2*segment_index + 1' */
1023 RS
, /* s: first last */
1028 CINDEX
, /* s: first last first */
1031 CINDEX
, /* s: first last first last */
1032 LTEQ
, /* first <= end */
1033 IF
, /* s: first last */
1035 DUP
, /* s: last first first */
1036 ALIGNRP
, /* align point with index `first' with rp0 */
1040 ADD
, /* first = first + 1 */
1041 SWAP
, /* s: first last */
1046 JMPR
, /* goto start_loop */
1056 unsigned char FPGM(bci_handle_segments
) [] = {
1059 bci_handle_segments
,
1062 POP
, /* XXX first segment */
1074 * bci_align_segments
1076 * Align segments to the value in `sal_pos'.
1087 * uses: handle_segment
1091 unsigned char FPGM(bci_align_segments
) [] = {
1110 unsigned char FPGM(bci_action_adjust_bound
) [] = {
1113 bci_action_adjust_bound
,
1117 bci_handle_segments
,
1120 bci_handle_segments
,
1123 bci_handle_segments
,
1132 unsigned char FPGM(bci_action_stem_bound
) [] = {
1135 bci_action_stem_bound
,
1139 bci_handle_segments
,
1142 bci_handle_segments
,
1145 bci_handle_segments
,
1158 * Handle the LINK action to link an edge to another one.
1164 * ... stuff for bci_align_segments ...
1168 * XXX: Instead of `base_point', use the median of the first segment in the
1172 unsigned char FPGM(bci_action_link
) [] = {
1184 SZP0
, /* set zp0 to normal zone 1 */
1185 SZP1
, /* set zp1 to twilight zone 0 */
1186 CINDEX
, /* s: ... stem_point base_point 1 sal_pos base_point */
1188 /* get distance between base_point and twilight point 0 (at origin) */
1191 MD_cur
, /* s: ... stem_point base_point 1 sal_pos base_point_y_pos */
1192 WS
, /* sal_pos: base_point_y_pos */
1194 SZP1
, /* set zp1 to normal zone 1 */
1196 MD_orig
, /* s: base_is_round stem_is_serif dist */
1199 bci_compute_stem_width
,
1200 CALL
, /* s: new_dist */
1209 WS
, /* sal_pos: base_point_y_pos + new_dist */
1219 unsigned char FPGM(bci_action_anchor
) [] = {
1226 bci_handle_segments
,
1229 bci_handle_segments
,
1240 * bci_action_blue_anchor
1242 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1243 * and to set the edge anchor.
1247 * ... stuff for bci_align_segments ...
1252 * XXX: Instead of `anchor_point', use the median of the first segment in the
1256 unsigned char FPGM(bci_action_blue_anchor
) [] = {
1259 bci_action_blue_anchor
,
1262 /* store anchor point number in `sal_anchor' */
1268 /* store blue position in `sal_pos' */
1283 unsigned char FPGM(bci_action_adjust
) [] = {
1290 bci_handle_segments
,
1293 bci_handle_segments
,
1302 unsigned char FPGM(bci_action_stem
) [] = {
1309 bci_handle_segments
,
1312 bci_handle_segments
,
1325 * Handle the BLUE action to align an edge with a blue zone.
1328 * ... stuff for bci_align_segments ...
1333 unsigned char FPGM(bci_action_blue
) [] = {
1339 /* store blue position in `sal_pos' */
1354 unsigned char FPGM(bci_action_serif
) [] = {
1361 bci_handle_segments
,
1370 unsigned char FPGM(bci_action_serif_anchor
) [] = {
1373 bci_action_serif_anchor
,
1377 bci_handle_segments
,
1386 unsigned char FPGM(bci_action_serif_link1
) [] = {
1389 bci_action_serif_link1
,
1393 bci_handle_segments
,
1402 unsigned char FPGM(bci_action_serif_link2
) [] = {
1405 bci_action_serif_link2
,
1409 bci_handle_segments
,
1424 * in: function_index
1427 unsigned char FPGM(bci_handle_action
) [] = {
1443 * This is the top-level glyph hinting function
1444 * which parses the arguments on the stack and calls subroutines.
1446 * in: num_actions (M)
1455 * uses: bci_handle_action
1456 * bci_action_adjust_bound
1457 * bci_action_stem_bound
1461 * bci_action_blue_anchor
1467 * bci_action_serif_anchor
1468 * bci_action_serif_link1
1469 * bci_action_serif_link2
1472 unsigned char FPGM(bci_hint_glyph
) [] = {
1487 #define COPY_FPGM(func_name) \
1488 memcpy(buf_p, fpgm_ ## func_name, \
1489 sizeof (fpgm_ ## func_name)); \
1490 buf_p += sizeof (fpgm_ ## func_name) \
1493 TA_table_build_fpgm(FT_Byte
** fpgm
,
1503 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
1505 + sizeof (FPGM(bci_compute_stem_width_b
))
1507 + sizeof (FPGM(bci_compute_stem_width_c
))
1508 + sizeof (FPGM(bci_loop
))
1509 + sizeof (FPGM(bci_cvt_rescale
))
1510 + sizeof (FPGM(bci_sal_assign
))
1511 + sizeof (FPGM(bci_loop_sal_assign
))
1512 + sizeof (FPGM(bci_blue_round_a
))
1514 + sizeof (FPGM(bci_blue_round_b
))
1515 + sizeof (FPGM(bci_get_point_extrema
))
1516 + sizeof (FPGM(bci_create_segment_point
))
1517 + sizeof (FPGM(bci_create_segment_points
))
1518 + sizeof (FPGM(bci_handle_segment
))
1519 + sizeof (FPGM(bci_align_segment
))
1520 + sizeof (FPGM(bci_handle_segments
))
1521 + sizeof (FPGM(bci_align_segments
))
1522 + sizeof (FPGM(bci_action_adjust_bound
))
1523 + sizeof (FPGM(bci_action_stem_bound
))
1524 + sizeof (FPGM(bci_action_link
))
1525 + sizeof (FPGM(bci_action_anchor
))
1526 + sizeof (FPGM(bci_action_blue_anchor
))
1527 + sizeof (FPGM(bci_action_adjust
))
1528 + sizeof (FPGM(bci_action_stem
))
1529 + sizeof (FPGM(bci_action_blue
))
1530 + sizeof (FPGM(bci_action_serif
))
1531 + sizeof (FPGM(bci_action_serif_anchor
))
1532 + sizeof (FPGM(bci_action_serif_link1
))
1533 + sizeof (FPGM(bci_action_serif_link2
))
1534 + sizeof (FPGM(bci_handle_action
))
1535 + sizeof (FPGM(bci_hint_glyph
));
1536 /* buffer length must be a multiple of four */
1537 len
= (buf_len
+ 3) & ~3;
1538 buf
= (FT_Byte
*)malloc(len
);
1540 return FT_Err_Out_Of_Memory
;
1542 /* pad end of buffer with zeros */
1543 buf
[len
- 1] = 0x00;
1544 buf
[len
- 2] = 0x00;
1545 buf
[len
- 3] = 0x00;
1547 /* copy font program into buffer and fill in the missing variables */
1550 COPY_FPGM(bci_compute_stem_width_a
);
1551 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1552 COPY_FPGM(bci_compute_stem_width_b
);
1553 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1554 COPY_FPGM(bci_compute_stem_width_c
);
1555 COPY_FPGM(bci_loop
);
1556 COPY_FPGM(bci_cvt_rescale
);
1557 COPY_FPGM(bci_sal_assign
);
1558 COPY_FPGM(bci_loop_sal_assign
);
1559 COPY_FPGM(bci_blue_round_a
);
1560 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
1561 COPY_FPGM(bci_blue_round_b
);
1562 COPY_FPGM(bci_get_point_extrema
);
1563 COPY_FPGM(bci_create_segment_point
);
1564 COPY_FPGM(bci_create_segment_points
);
1565 COPY_FPGM(bci_handle_segment
);
1566 COPY_FPGM(bci_align_segment
);
1567 COPY_FPGM(bci_handle_segments
);
1568 COPY_FPGM(bci_align_segments
);
1569 COPY_FPGM(bci_action_adjust_bound
);
1570 COPY_FPGM(bci_action_stem_bound
);
1571 COPY_FPGM(bci_action_link
);
1572 COPY_FPGM(bci_action_anchor
);
1573 COPY_FPGM(bci_action_blue_anchor
);
1574 COPY_FPGM(bci_action_adjust
);
1575 COPY_FPGM(bci_action_stem
);
1576 COPY_FPGM(bci_action_blue
);
1577 COPY_FPGM(bci_action_serif
);
1578 COPY_FPGM(bci_action_serif_anchor
);
1579 COPY_FPGM(bci_action_serif_link1
);
1580 COPY_FPGM(bci_action_serif_link2
);
1581 COPY_FPGM(bci_handle_action
);
1582 COPY_FPGM(bci_hint_glyph
);
1585 *fpgm_len
= buf_len
;
1592 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
1601 error
= TA_sfnt_add_table_info(sfnt
);
1605 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
1609 /* in case of success, `fpgm_buf' gets linked */
1610 /* and is eventually freed in `TA_font_unload' */
1611 error
= TA_font_add_table(font
,
1612 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1613 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
1624 /* the `prep' instructions */
1626 #define PREP(snippet_name) prep_ ## snippet_name
1628 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1629 /* thus we provide it in the storage area */
1631 unsigned char PREP(store_0x10000
) [] = {
1645 unsigned char PREP(align_top_a
) [] = {
1647 /* optimize the alignment of the top of small letters to the pixel grid */
1653 /* %c, index of alignment blue zone */
1655 unsigned char PREP(align_top_b
) [] = {
1663 FLOOR
, /* fitted = FLOOR(scaled + 40) */
1664 DUP
, /* s: scaled scaled fitted fitted */
1667 IF
, /* s: scaled fitted */
1671 MUL
, /* scaled in 16.16 format */
1673 DIV
, /* (fitted / scaled) in 16.16 format */
1682 unsigned char PREP(loop_cvt_a
) [] = {
1684 /* loop over vertical CVT entries */
1689 /* %c, first vertical index */
1690 /* %c, last vertical index */
1692 unsigned char PREP(loop_cvt_b
) [] = {
1698 /* loop over blue refs */
1703 /* %c, first blue ref index */
1704 /* %c, last blue ref index */
1706 unsigned char PREP(loop_cvt_c
) [] = {
1712 /* loop over blue shoots */
1717 /* %c, first blue shoot index */
1718 /* %c, last blue shoot index */
1720 unsigned char PREP(loop_cvt_d
) [] = {
1729 unsigned char PREP(compute_extra_light_a
) [] = {
1731 /* compute (vertical) `extra_light' flag */
1738 /* %c, index of vertical standard_width */
1740 unsigned char PREP(compute_extra_light_b
) [] = {
1743 GT
, /* standard_width < 40 */
1748 unsigned char PREP(round_blues_a
) [] = {
1750 /* use discrete values for blue zone widths */
1755 /* %c, first blue ref index */
1756 /* %c, last blue ref index */
1758 unsigned char PREP(round_blues_b
) [] = {
1766 /* XXX talatin.c: 1671 */
1767 /* XXX talatin.c: 1708 */
1768 /* XXX talatin.c: 2182 */
1771 #define COPY_PREP(snippet_name) \
1772 memcpy(buf_p, prep_ ## snippet_name, \
1773 sizeof (prep_ ## snippet_name)); \
1774 buf_p += sizeof (prep_ ## snippet_name);
1777 TA_table_build_prep(FT_Byte
** prep
,
1782 TA_LatinBlue blue_adjustment
;
1791 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
1792 blue_adjustment
= NULL
;
1794 for (i
= 0; i
< vaxis
->blue_count
; i
++)
1796 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
1798 blue_adjustment
= &vaxis
->blues
[i
];
1803 buf_len
= sizeof (PREP(store_0x10000
));
1805 if (blue_adjustment
)
1806 buf_len
+= sizeof (PREP(align_top_a
))
1808 + sizeof (PREP(align_top_b
))
1809 + sizeof (PREP(loop_cvt_a
))
1811 + sizeof (PREP(loop_cvt_b
))
1813 + sizeof (PREP(loop_cvt_c
))
1815 + sizeof (PREP(loop_cvt_d
));
1817 buf_len
+= sizeof (PREP(compute_extra_light_a
))
1819 + sizeof (PREP(compute_extra_light_b
));
1821 if (CVT_BLUES_SIZE(font
))
1822 buf_len
+= sizeof (PREP(round_blues_a
))
1824 + sizeof (PREP(round_blues_b
));
1826 /* buffer length must be a multiple of four */
1827 len
= (buf_len
+ 3) & ~3;
1828 buf
= (FT_Byte
*)malloc(len
);
1830 return FT_Err_Out_Of_Memory
;
1832 /* pad end of buffer with zeros */
1833 buf
[len
- 1] = 0x00;
1834 buf
[len
- 2] = 0x00;
1835 buf
[len
- 3] = 0x00;
1837 /* copy cvt program into buffer and fill in the missing variables */
1840 COPY_PREP(store_0x10000
);
1842 if (blue_adjustment
)
1844 COPY_PREP(align_top_a
);
1845 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1846 + blue_adjustment
- vaxis
->blues
);
1847 COPY_PREP(align_top_b
);
1849 COPY_PREP(loop_cvt_a
);
1850 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1851 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
1852 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
1853 COPY_PREP(loop_cvt_b
);
1854 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1855 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1856 + CVT_BLUES_SIZE(font
) - 1);
1857 COPY_PREP(loop_cvt_c
);
1858 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
1859 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1860 + CVT_BLUES_SIZE(font
) - 1);
1861 COPY_PREP(loop_cvt_d
);
1864 COPY_PREP(compute_extra_light_a
);
1865 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
1866 COPY_PREP(compute_extra_light_b
);
1868 if (CVT_BLUES_SIZE(font
))
1870 COPY_PREP(round_blues_a
);
1871 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1872 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1873 + CVT_BLUES_SIZE(font
) - 1);
1874 COPY_PREP(round_blues_b
);
1878 *prep_len
= buf_len
;
1885 TA_sfnt_build_prep_table(SFNT
* sfnt
,
1894 error
= TA_sfnt_add_table_info(sfnt
);
1898 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
1902 /* in case of success, `prep_buf' gets linked */
1903 /* and is eventually freed in `TA_font_unload' */
1904 error
= TA_font_add_table(font
,
1905 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1906 TTAG_prep
, prep_len
, prep_buf
);
1917 /* we store the segments in the storage area; */
1918 /* each segment record consists of the first and last point */
1921 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
1925 TA_GlyphHints hints
= &font
->loader
->hints
;
1926 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1927 TA_Point points
= hints
->points
;
1928 TA_Segment segments
= axis
->segments
;
1930 TA_Segment seg_limit
;
1937 FT_Bool need_words
= 0;
1940 FT_UInt num_storage
;
1941 FT_UInt num_stack_elements
;
1944 seg_limit
= segments
+ axis
->num_segments
;
1945 num_args
= 2 * axis
->num_segments
+ 3;
1947 /* collect all arguments temporarily in an array (in reverse order) */
1948 /* so that we can easily split into chunks of 255 args */
1949 /* as needed by NPUSHB and NPUSHW, respectively */
1950 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1954 arg
= args
+ num_args
- 1;
1956 if (axis
->num_segments
> 0xFF)
1959 *(arg
--) = bci_loop_sal_assign
;
1960 *(arg
--) = axis
->num_segments
* 2;
1961 *(arg
--) = sal_segment_offset
;
1963 for (seg
= segments
; seg
< seg_limit
; seg
++)
1965 FT_UInt first
= seg
->first
- points
;
1966 FT_UInt last
= seg
->last
- points
;
1972 if (first
> 0xFF || last
> 0xFF)
1976 /* with most fonts it is very rare */
1977 /* that any of the pushed arguments is larger than 0xFF, */
1978 /* thus we refrain from further optimizing this case */
1984 for (i
= 0; i
< num_args
; i
+= 255)
1986 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
1990 for (j
= 0; j
< nargs
; j
++)
2000 for (i
= 0; i
< num_args
; i
+= 255)
2002 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
2006 for (j
= 0; j
< nargs
; j
++)
2016 num_storage
= sal_segment_offset
+ axis
->num_segments
* 2;
2017 if (num_storage
> sfnt
->max_storage
)
2018 sfnt
->max_storage
= num_storage
;
2020 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
2021 if (num_stack_elements
> sfnt
->max_stack_elements
)
2022 sfnt
->max_stack_elements
= num_stack_elements
;
2031 TA_hints_record_is_different(Hints_Record
* hints_records
,
2032 FT_UInt num_hints_records
,
2036 Hints_Record last_hints_record
;
2042 /* we only need to compare with the last hints record */
2043 last_hints_record
= hints_records
[num_hints_records
- 1];
2045 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
2048 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
2056 TA_add_hints_record(Hints_Record
** hints_records
,
2057 FT_UInt
* num_hints_records
,
2059 Hints_Record hints_record
)
2061 Hints_Record
* hints_records_new
;
2063 /* at this point, `hints_record.buf' still points into `ins_buf' */
2064 FT_Byte
* end
= hints_record
.buf
;
2067 buf_len
= (FT_UInt
)(end
- start
);
2069 /* now fill the structure completely */
2070 hints_record
.buf_len
= buf_len
;
2071 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
2072 if (!hints_record
.buf
)
2073 return FT_Err_Out_Of_Memory
;
2075 memcpy(hints_record
.buf
, start
, buf_len
);
2077 (*num_hints_records
)++;
2079 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
2080 * sizeof (Hints_Record
));
2081 if (!hints_records_new
)
2083 free(hints_record
.buf
);
2084 (*num_hints_records
)--;
2085 return FT_Err_Out_Of_Memory
;
2088 *hints_records
= hints_records_new
;
2090 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
2097 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
2098 Hints_Record
* hints_record
,
2103 FT_Bool need_words
= 0;
2106 FT_UInt num_arguments
;
2108 FT_UInt num_stack_elements
;
2111 /* check whether any argument is larger than 0xFF */
2112 endp
= hints_record
->buf
+ hints_record
->buf_len
;
2113 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
2117 /* with most fonts it is very rare */
2118 /* that any of the pushed arguments is larger than 0xFF, */
2119 /* thus we refrain from further optimizing this case */
2121 num_arguments
= hints_record
->buf_len
/ 2;
2126 for (i
= 0; i
< num_arguments
; i
+= 255)
2128 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2132 for (j
= 0; j
< num_args
; j
++)
2142 /* we only need the lower bytes */
2145 for (i
= 0; i
< num_arguments
; i
+= 255)
2147 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
2151 for (j
= 0; j
< num_args
; j
++)
2159 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
2160 if (num_stack_elements
> sfnt
->max_stack_elements
)
2161 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
2168 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
2169 Hints_Record
* hints_records
,
2170 FT_UInt num_hints_records
,
2174 Hints_Record
* hints_record
;
2177 hints_record
= hints_records
;
2179 /* this instruction is essential for getting correct CVT values */
2180 /* if horizontal and vertical resolutions differ; */
2181 /* it assures that the projection vector is set to the y axis */
2182 /* so that CVT values are handled as being `vertical' */
2185 for (i
= 0; i
< num_hints_records
- 1; i
++)
2188 if (hints_record
->size
> 0xFF)
2191 BCI(HIGH((hints_record
+ 1)->size
));
2192 BCI(LOW((hints_record
+ 1)->size
));
2197 BCI((hints_record
+ 1)->size
);
2201 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2207 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
2209 for (i
= 0; i
< num_hints_records
- 1; i
++)
2213 BCI(bci_hint_glyph
);
2221 TA_free_hints_records(Hints_Record
* hints_records
,
2222 FT_UInt num_hints_records
)
2227 for (i
= 0; i
< num_hints_records
; i
++)
2228 free(hints_records
[i
].buf
);
2230 free(hints_records
);
2235 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
2236 TA_Segment segments
,
2241 FT_UInt num_segs
= 0;
2244 seg_idx
= edge
->first
- segments
;
2246 /* we store everything as 16bit numbers */
2247 *(bufp
++) = HIGH(seg_idx
);
2248 *(bufp
++) = LOW(seg_idx
);
2250 seg
= edge
->first
->edge_next
;
2251 while (seg
!= edge
->first
)
2253 seg
= seg
->edge_next
;
2257 *(bufp
++) = HIGH(num_segs
);
2258 *(bufp
++) = LOW(num_segs
);
2260 seg
= edge
->first
->edge_next
;
2261 while (seg
!= edge
->first
)
2263 seg_idx
= seg
- segments
;
2264 seg
= seg
->edge_next
;
2266 *(bufp
++) = HIGH(seg_idx
);
2267 *(bufp
++) = LOW(seg_idx
);
2275 TA_hints_recorder(TA_Action action
,
2276 TA_GlyphHints hints
,
2282 TA_AxisHints axis
= &hints
->axis
[dim
];
2283 TA_Point points
= hints
->points
;
2284 TA_Segment segments
= axis
->segments
;
2286 Recorder
* recorder
= (Recorder
*)hints
->user
;
2287 FONT
* font
= recorder
->font
;
2288 FT_Byte
* p
= recorder
->hints_record
.buf
;
2291 if (dim
== TA_DIMENSION_HORZ
)
2294 /* we ignore the BOUND action since the information is handled */
2295 /* in `ta_adjust_bound' and `ta_stem_bound' */
2296 if (action
== ta_bound
)
2300 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2304 case ta_adjust_bound
:
2305 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2306 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2307 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2311 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2312 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2313 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
2318 TA_Edge base_edge
= (TA_Edge
)arg1
;
2319 TA_Edge stem_edge
= (TA_Edge
)arg2
;
2322 *(p
++) = HIGH(base_edge
->first
->first
- points
);
2323 *(p
++) = LOW(base_edge
->first
->first
- points
);
2324 *(p
++) = HIGH(stem_edge
->first
->first
- points
);
2325 *(p
++) = LOW(stem_edge
->first
->first
- points
);
2327 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
2329 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
2331 p
= TA_hints_recorder_handle_segments(p
, segments
, stem_edge
);
2336 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2337 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2340 case ta_blue_anchor
:
2342 TA_Edge edge
= (TA_Edge
)arg1
;
2343 TA_Edge blue
= (TA_Edge
)arg2
;
2346 *(p
++) = HIGH(blue
->first
->first
- points
);
2347 *(p
++) = LOW(blue
->first
->first
- points
);
2349 if (edge
->best_blue_is_shoot
)
2351 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2352 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2356 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2357 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2360 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2365 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2366 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2370 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2371 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
2376 TA_Edge edge
= (TA_Edge
)arg1
;
2379 if (edge
->best_blue_is_shoot
)
2381 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2382 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
2386 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2387 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
2390 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
2395 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2398 case ta_serif_anchor
:
2399 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2402 case ta_serif_link1
:
2403 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2406 case ta_serif_link2
:
2407 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
2410 /* to pacify the compiler */
2415 recorder
->hints_record
.num_actions
++;
2416 recorder
->hints_record
.buf
= p
;
2421 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2425 FT_Face face
= sfnt
->face
;
2432 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2433 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2434 GLYPH
* glyph
= &data
->glyphs
[idx
];
2436 TA_GlyphHints hints
;
2438 FT_UInt num_hints_records
;
2439 Hints_Record
* hints_records
;
2447 return FT_Err_Invalid_Argument
;
2449 /* computing the segments is resolution independent, */
2450 /* thus the pixel size in this call is arbitrary */
2451 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
2455 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2456 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
2460 /* do nothing if we have an empty glyph */
2461 if (!face
->glyph
->outline
.n_contours
)
2464 hints
= &font
->loader
->hints
;
2466 /* we allocate a buffer which is certainly large enough */
2467 /* to hold all of the created bytecode instructions; */
2468 /* later on it gets reallocated to its real size */
2469 ins_len
= hints
->num_points
* 1000;
2470 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2472 return FT_Err_Out_Of_Memory
;
2474 /* initialize array with an invalid bytecode */
2475 /* so that we can easily find the array length at reallocation time */
2476 memset(ins_buf
, INS_A0
, ins_len
);
2478 bufp
= TA_sfnt_build_glyph_segments(sfnt
, font
, ins_buf
);
2480 /* now we loop over a large range of pixel sizes */
2481 /* to find hints records which get pushed onto the bytecode stack */
2482 num_hints_records
= 0;
2483 hints_records
= NULL
;
2486 printf("glyph %ld\n", idx
);
2489 /* we temporarily use `ins_buf' to record the current glyph hints, */
2490 /* leaving two bytes at the beginning so that the number of actions */
2491 /* can be inserted later on */
2492 recorder
.font
= font
;
2493 ta_loader_register_hints_recorder(font
->loader
,
2497 for (size
= 8; size
<= 1000; size
++)
2499 /* rewind buffer pointer for recorder */
2500 recorder
.hints_record
.buf
= bufp
+ 2;
2501 recorder
.hints_record
.num_actions
= 0;
2502 recorder
.hints_record
.size
= size
;
2504 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2508 /* calling `ta_loader_load_glyph' uses the */
2509 /* `TA_hints_recorder' function as a callback, */
2510 /* modifying `hints_record' */
2511 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
2515 /* store the number of actions in `ins_buf' */
2516 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
2517 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
2519 if (TA_hints_record_is_different(hints_records
,
2521 bufp
, recorder
.hints_record
.buf
))
2528 printf(" %d:\n", size
);
2529 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
2530 printf(" %2d", *p
* 256 + *(p
+ 1));
2535 error
= TA_add_hints_record(&hints_records
,
2537 bufp
, recorder
.hints_record
);
2543 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
2545 /* don't emit anything if we only have a single empty record */
2553 /* otherwise, clear the temporarily used part of `ins_buf' */
2554 while (*p
!= INS_A0
)
2557 bufp
= TA_sfnt_emit_hints_records(sfnt
,
2558 hints_records
, num_hints_records
,
2561 /* we are done, so reallocate the instruction array to its real size */
2562 if (*bufp
== INS_A0
)
2564 /* search backwards */
2565 while (*bufp
== INS_A0
)
2571 /* search forwards */
2572 while (*bufp
!= INS_A0
)
2576 ins_len
= bufp
- ins_buf
;
2579 if (ins_len
> sfnt
->max_instructions
)
2580 sfnt
->max_instructions
= ins_len
;
2582 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2583 glyph
->ins_len
= ins_len
;
2585 TA_free_hints_records(hints_records
, num_hints_records
);
2590 TA_free_hints_records(hints_records
, num_hints_records
);
2598 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
2601 FT_Face face
= sfnt
->face
;
2606 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
2608 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
2616 /* end of tabytecode.c */