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 amount */
13 #define ADDITIONAL_STACK_ELEMENTS 20
18 int _ta_debug_disable_horz_hints
;
19 int _ta_debug_disable_vert_hints
;
20 int _ta_debug_disable_blue_hints
;
21 void* _ta_debug_hints
;
25 typedef struct Hints_Record_
{
32 typedef struct Recorder_
{
34 Hints_Record hints_record
;
39 TA_sfnt_compute_global_hints(SFNT
* sfnt
,
43 FT_Face face
= sfnt
->face
;
47 static const FT_Encoding latin_encs
[] =
50 FT_ENCODING_APPLE_ROMAN
,
51 FT_ENCODING_ADOBE_STANDARD
,
52 FT_ENCODING_ADOBE_LATIN_1
,
54 FT_ENCODING_NONE
/* end of list */
58 error
= ta_loader_init(font
->loader
);
62 /* try to select a latin charmap */
63 for (enc
= 0; latin_encs
[enc
] != FT_ENCODING_NONE
; enc
++)
65 error
= FT_Select_Charmap(face
, latin_encs
[enc
]);
70 /* load latin glyph `a' to trigger all initializations */
71 idx
= FT_Get_Char_Index(face
, 'a');
72 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
79 TA_table_build_cvt(FT_Byte
** cvt
,
96 error
= TA_sfnt_compute_global_hints(sfnt
, font
);
100 /* XXX check validity of pointers */
101 haxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[0];
102 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
107 + 2 * vaxis
->blue_count
);
109 /* buffer length must be a multiple of four */
110 len
= (buf_len
+ 3) & ~3;
111 buf
= (FT_Byte
*)malloc(len
);
113 return FT_Err_Out_Of_Memory
;
115 /* pad end of buffer with zeros */
122 if (haxis
->width_count
> 0)
124 *(buf_p
++) = HIGH(haxis
->widths
[0].org
);
125 *(buf_p
++) = LOW(haxis
->widths
[0].org
);
132 if (vaxis
->width_count
> 0)
134 *(buf_p
++) = HIGH(vaxis
->widths
[0].org
);
135 *(buf_p
++) = LOW(vaxis
->widths
[0].org
);
143 for (i
= 0; i
< haxis
->width_count
; i
++)
145 if (haxis
->widths
[i
].org
> 0xFFFF)
147 *(buf_p
++) = HIGH(haxis
->widths
[i
].org
);
148 *(buf_p
++) = LOW(haxis
->widths
[i
].org
);
151 for (i
= 0; i
< vaxis
->width_count
; i
++)
153 if (vaxis
->widths
[i
].org
> 0xFFFF)
155 *(buf_p
++) = HIGH(vaxis
->widths
[i
].org
);
156 *(buf_p
++) = LOW(vaxis
->widths
[i
].org
);
159 for (i
= 0; i
< vaxis
->blue_count
; i
++)
161 if (vaxis
->blues
[i
].ref
.org
> 0xFFFF)
163 *(buf_p
++) = HIGH(vaxis
->blues
[i
].ref
.org
);
164 *(buf_p
++) = LOW(vaxis
->blues
[i
].ref
.org
);
167 for (i
= 0; i
< vaxis
->blue_count
; i
++)
169 if (vaxis
->blues
[i
].shoot
.org
> 0xFFFF)
171 *(buf_p
++) = HIGH(vaxis
->blues
[i
].shoot
.org
);
172 *(buf_p
++) = LOW(vaxis
->blues
[i
].shoot
.org
);
176 TA_LOG(("--------------------------------------------------\n"));
177 TA_LOG(("glyph %d:\n", idx
));
178 ta_glyph_hints_dump_edges(_ta_debug_hints
);
179 ta_glyph_hints_dump_segments(_ta_debug_hints
);
180 ta_glyph_hints_dump_points(_ta_debug_hints
);
190 return TA_Err_Hinter_Overflow
;
195 TA_sfnt_build_cvt_table(SFNT
* sfnt
,
204 error
= TA_sfnt_add_table_info(sfnt
);
208 error
= TA_table_build_cvt(&cvt_buf
, &cvt_len
, sfnt
, font
);
212 /* in case of success, `cvt_buf' gets linked */
213 /* and is eventually freed in `TA_font_unload' */
214 error
= TA_font_add_table(font
,
215 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
216 TTAG_cvt
, cvt_len
, cvt_buf
);
227 /* the horizontal and vertical standard widths */
228 #define CVT_HORZ_STANDARD_WIDTH_OFFSET(font) 0
229 #define CVT_VERT_STANDARD_WIDTH_OFFSET(font) \
230 CVT_HORZ_STANDARD_WIDTH_OFFSET(font) + 1
232 /* the horizontal stem widths */
233 #define CVT_HORZ_WIDTHS_OFFSET(font) \
234 CVT_VERT_STANDARD_WIDTH_OFFSET(font) + 1
235 #define CVT_HORZ_WIDTHS_SIZE(font) \
236 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
238 /* the vertical stem widths */
239 #define CVT_VERT_WIDTHS_OFFSET(font) \
240 CVT_HORZ_WIDTHS_OFFSET(font) + CVT_HORZ_WIDTHS_SIZE(font)
241 #define CVT_VERT_WIDTHS_SIZE(font) \
242 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
244 /* the number of blue zones */
245 #define CVT_BLUES_SIZE(font) \
246 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
248 /* the blue zone values for flat and round edges */
249 #define CVT_BLUE_REFS_OFFSET(font) \
250 CVT_VERT_WIDTHS_OFFSET(font) + CVT_VERT_WIDTHS_SIZE(font)
251 #define CVT_BLUE_SHOOTS_OFFSET(font) \
252 CVT_BLUE_REFS_OFFSET(font) + CVT_BLUES_SIZE(font)
255 /* symbolic names for storage area locations */
257 #define sal_counter 0
258 #define sal_limit sal_counter + 1
259 #define sal_scale sal_limit + 1
260 #define sal_0x10000 sal_scale + 1
261 #define sal_is_extra_light sal_0x10000 + 1
262 #define sal_segment_offset sal_is_extra_light + 1 /* must be last */
265 /* we need the following macro */
266 /* so that `func_name' doesn't get replaced with its #defined value */
267 /* (as defined in `tabytecode.h') */
269 #define FPGM(func_name) fpgm_ ## func_name
272 /* in the comments below, the top of the stack (`s:') */
273 /* is the rightmost element; the stack is shown */
274 /* after the instruction on the same line has been executed */
277 * bci_compute_stem_width
279 * This is the equivalent to the following code from function
280 * `ta_latin_compute_stem_width':
288 * else if base_is_round:
292 * dist = MIN(56, dist)
294 * delta = ABS(dist - std_width)
297 * dist = MIN(48, std_width)
303 * delta = delta - dist
306 * dist = dist + delta
307 * else if delta < 32:
309 * else if delta < 54:
312 * dist = dist + delta
326 * sal: is_extra_light
330 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
333 bci_compute_stem_width
,
337 ABS
, /* s: base_is_round stem_is_serif width dist */
342 LT
, /* dist < 3*64 */
346 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
347 AND
, /* stem_is_serif && dist < 3*64 */
352 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
354 IF
, /* s: base_is_round width dist */
360 ROLL
, /* s: width dist base_is_round */
361 IF
, /* s: width dist */
366 IF
, /* s: width dist */
375 MIN
, /* dist = min(56, dist) */
378 DUP
, /* s: width dist dist */
383 /* %c, index of std_width */
385 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
389 ABS
, /* s: width dist delta */
394 IF
, /* s: width dist */
401 /* %c, index of std_width */
403 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
406 MIN
, /* dist = min(48, std_width) */
409 DUP
, /* s: width dist dist */
412 LT
, /* dist < 3*64 */
414 DUP
, /* s: width delta dist */
415 FLOOR
, /* dist = FLOOR(dist) */
416 DUP
, /* s: width delta dist dist */
418 ROLL
, /* s: width dist delta dist */
419 SUB
, /* delta = delta - dist */
421 DUP
, /* s: width dist delta delta */
425 IF
, /* s: width dist delta */
426 ADD
, /* dist = dist + delta */
437 ADD
, /* dist = dist + 10 */
448 ADD
, /* dist = dist + 54 */
451 ADD
, /* dist = dist + delta */
461 FLOOR
, /* dist = round(dist) */
466 SWAP
, /* s: dist width */
471 NEG
, /* dist = -dist */
484 * Take a range and a function number and apply the function to all
485 * elements of the range. The called function must not change the
492 * uses: sal_counter (counter initialized with `start')
496 unsigned char FPGM(bci_loop
) [] = {
503 ROLL
, /* s: func_num start end */
521 LTEQ
, /* start <= end */
522 IF
, /* s: func_num */
529 ADD
, /* start = start + 1 */
538 JMPR
, /* goto start_loop */
551 * Rescale CVT value by a given factor.
553 * uses: sal_counter (CVT index)
554 * sal_scale (scale in 16.16 format)
557 unsigned char FPGM(bci_cvt_rescale
) [] = {
571 MUL
, /* CVT * scale * 2^10 */
575 DIV
, /* CVT * scale */
585 * bci_loop_sal_assign
587 * Apply the WS instruction repeatedly to stack data.
596 * uses: bci_sal_assign
599 unsigned char FPGM(bci_sal_assign
) [] = {
606 ROLL
, /* s: offset offset data */
611 ADD
, /* s: (offset + 1) */
617 unsigned char FPGM(bci_loop_sal_assign
) [] = {
623 /* process the stack, popping off the elements in a loop */
639 * Round a blue ref value and adjust its corresponding shoot value.
641 * uses: sal_counter (CVT index)
645 unsigned char FPGM(bci_blue_round_a
) [] = {
655 RCVT
, /* s: ref_idx ref */
662 SWAP
, /* s: ref_idx round(ref) ref */
670 unsigned char FPGM(bci_blue_round_b
) [] = {
674 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
676 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
678 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
680 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
682 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
707 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
712 NEG
, /* delta = -delta */
718 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
731 * This is the top-level glyph hinting function
732 * which parses the arguments on the stack and calls subroutines.
734 * in: num_actions (M)
743 * uses: bci_handle_action
744 * bci_action_adjust_bound
745 * bci_action_stem_bound
754 * bci_action_serif_anchor
755 * bci_action_serif_link1
756 * bci_action_serif_link2
758 * All of the above action handlers use `bci_handle_segments' up to three
762 unsigned char FPGM(bci_handle_remaining_segment
) [] = {
765 bci_handle_remaining_segment
,
768 POP
, /* XXX remaining segment */
774 unsigned char FPGM(bci_handle_segments
) [] = {
780 POP
, /* XXX first segment */
781 POP
, /* XXX is_serif */
782 POP
, /* XXX is_round */
785 bci_handle_remaining_segment
,
792 unsigned char FPGM(bci_action_adjust_bound
) [] = {
795 bci_action_adjust_bound
,
814 unsigned char FPGM(bci_action_stem_bound
) [] = {
817 bci_action_stem_bound
,
836 unsigned char FPGM(bci_action_link
) [] = {
855 unsigned char FPGM(bci_action_anchor
) [] = {
874 unsigned char FPGM(bci_action_adjust
) [] = {
893 unsigned char FPGM(bci_action_stem
) [] = {
912 unsigned char FPGM(bci_action_blue
) [] = {
930 unsigned char FPGM(bci_action_serif
) [] = {
946 unsigned char FPGM(bci_action_serif_anchor
) [] = {
949 bci_action_serif_anchor
,
962 unsigned char FPGM(bci_action_link1
) [] = {
978 unsigned char FPGM(bci_action_link2
) [] = {
994 unsigned char FPGM(bci_handle_action
) [] = {
1006 unsigned char FPGM(bci_hint_glyph
) [] = {
1021 #define COPY_FPGM(func_name) \
1022 memcpy(buf_p, fpgm_ ## func_name, \
1023 sizeof (fpgm_ ## func_name)); \
1024 buf_p += sizeof (fpgm_ ## func_name) \
1027 TA_table_build_fpgm(FT_Byte
** fpgm
,
1037 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
1039 + sizeof (FPGM(bci_compute_stem_width_b
))
1041 + sizeof (FPGM(bci_compute_stem_width_c
))
1042 + sizeof (FPGM(bci_loop
))
1043 + sizeof (FPGM(bci_cvt_rescale
))
1044 + sizeof (FPGM(bci_sal_assign
))
1045 + sizeof (FPGM(bci_loop_sal_assign
))
1046 + sizeof (FPGM(bci_blue_round_a
))
1048 + sizeof (FPGM(bci_blue_round_b
))
1049 + sizeof (FPGM(bci_handle_remaining_segment
))
1050 + sizeof (FPGM(bci_handle_segments
))
1051 + sizeof (FPGM(bci_action_adjust_bound
))
1052 + sizeof (FPGM(bci_action_stem_bound
))
1053 + sizeof (FPGM(bci_action_link
))
1054 + sizeof (FPGM(bci_action_anchor
))
1055 + sizeof (FPGM(bci_action_adjust
))
1056 + sizeof (FPGM(bci_action_stem
))
1057 + sizeof (FPGM(bci_action_blue
))
1058 + sizeof (FPGM(bci_action_serif
))
1059 + sizeof (FPGM(bci_action_anchor
))
1060 + sizeof (FPGM(bci_action_link1
))
1061 + sizeof (FPGM(bci_action_link2
))
1062 + sizeof (FPGM(bci_handle_action
))
1063 + sizeof (FPGM(bci_hint_glyph
));
1064 /* buffer length must be a multiple of four */
1065 len
= (buf_len
+ 3) & ~3;
1066 buf
= (FT_Byte
*)malloc(len
);
1068 return FT_Err_Out_Of_Memory
;
1070 /* pad end of buffer with zeros */
1071 buf
[len
- 1] = 0x00;
1072 buf
[len
- 2] = 0x00;
1073 buf
[len
- 3] = 0x00;
1075 /* copy font program into buffer and fill in the missing variables */
1078 COPY_FPGM(bci_compute_stem_width_a
);
1079 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1080 COPY_FPGM(bci_compute_stem_width_b
);
1081 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1082 COPY_FPGM(bci_compute_stem_width_c
);
1083 COPY_FPGM(bci_loop
);
1084 COPY_FPGM(bci_cvt_rescale
);
1085 COPY_FPGM(bci_sal_assign
);
1086 COPY_FPGM(bci_loop_sal_assign
);
1087 COPY_FPGM(bci_blue_round_a
);
1088 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
1089 COPY_FPGM(bci_blue_round_b
);
1090 COPY_FPGM(bci_handle_remaining_segment
);
1091 COPY_FPGM(bci_handle_segments
);
1092 COPY_FPGM(bci_action_adjust_bound
);
1093 COPY_FPGM(bci_action_stem_bound
);
1094 COPY_FPGM(bci_action_link
);
1095 COPY_FPGM(bci_action_anchor
);
1096 COPY_FPGM(bci_action_adjust
);
1097 COPY_FPGM(bci_action_stem
);
1098 COPY_FPGM(bci_action_blue
);
1099 COPY_FPGM(bci_action_serif
);
1100 COPY_FPGM(bci_action_anchor
);
1101 COPY_FPGM(bci_action_link1
);
1102 COPY_FPGM(bci_action_link2
);
1103 COPY_FPGM(bci_handle_action
);
1104 COPY_FPGM(bci_hint_glyph
);
1107 *fpgm_len
= buf_len
;
1114 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
1123 error
= TA_sfnt_add_table_info(sfnt
);
1127 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
1131 /* in case of success, `fpgm_buf' gets linked */
1132 /* and is eventually freed in `TA_font_unload' */
1133 error
= TA_font_add_table(font
,
1134 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1135 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
1146 /* the `prep' instructions */
1148 #define PREP(snippet_name) prep_ ## snippet_name
1150 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1151 /* thus we provide it in the storage area */
1153 unsigned char PREP(store_0x10000
) [] = {
1167 unsigned char PREP(align_top_a
) [] = {
1169 /* optimize the alignment of the top of small letters to the pixel grid */
1175 /* %c, index of alignment blue zone */
1177 unsigned char PREP(align_top_b
) [] = {
1185 FLOOR
, /* fitted = FLOOR(scaled + 40) */
1186 DUP
, /* s: scaled scaled fitted fitted */
1189 IF
, /* s: scaled fitted */
1193 MUL
, /* scaled in 16.16 format */
1195 DIV
, /* (fitted / scaled) in 16.16 format */
1204 unsigned char PREP(loop_cvt_a
) [] = {
1206 /* loop over vertical CVT entries */
1211 /* %c, first vertical index */
1212 /* %c, last vertical index */
1214 unsigned char PREP(loop_cvt_b
) [] = {
1220 /* loop over blue refs */
1225 /* %c, first blue ref index */
1226 /* %c, last blue ref index */
1228 unsigned char PREP(loop_cvt_c
) [] = {
1234 /* loop over blue shoots */
1239 /* %c, first blue shoot index */
1240 /* %c, last blue shoot index */
1242 unsigned char PREP(loop_cvt_d
) [] = {
1251 unsigned char PREP(compute_extra_light_a
) [] = {
1253 /* compute (vertical) `extra_light' flag */
1260 /* %c, index of vertical standard_width */
1262 unsigned char PREP(compute_extra_light_b
) [] = {
1265 GT
, /* standard_width < 40 */
1270 unsigned char PREP(round_blues_a
) [] = {
1272 /* use discrete values for blue zone widths */
1277 /* %c, first blue ref index */
1278 /* %c, last blue ref index */
1280 unsigned char PREP(round_blues_b
) [] = {
1289 /* XXX talatin.c: 1671 */
1290 /* XXX talatin.c: 1708 */
1291 /* XXX talatin.c: 2182 */
1294 #define COPY_PREP(snippet_name) \
1295 memcpy(buf_p, prep_ ## snippet_name, \
1296 sizeof (prep_ ## snippet_name)); \
1297 buf_p += sizeof (prep_ ## snippet_name);
1300 TA_table_build_prep(FT_Byte
** prep
,
1305 TA_LatinBlue blue_adjustment
;
1314 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
1315 blue_adjustment
= NULL
;
1317 for (i
= 0; i
< vaxis
->blue_count
; i
++)
1319 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
1321 blue_adjustment
= &vaxis
->blues
[i
];
1326 buf_len
= sizeof (PREP(store_0x10000
));
1328 if (blue_adjustment
)
1329 buf_len
+= sizeof (PREP(align_top_a
))
1331 + sizeof (PREP(align_top_b
))
1332 + sizeof (PREP(loop_cvt_a
))
1334 + sizeof (PREP(loop_cvt_b
))
1336 + sizeof (PREP(loop_cvt_c
))
1338 + sizeof (PREP(loop_cvt_d
));
1340 buf_len
+= sizeof (PREP(compute_extra_light_a
))
1342 + sizeof (PREP(compute_extra_light_b
));
1344 if (CVT_BLUES_SIZE(font
))
1345 buf_len
+= sizeof (PREP(round_blues_a
))
1347 + sizeof (PREP(round_blues_b
));
1349 /* buffer length must be a multiple of four */
1350 len
= (buf_len
+ 3) & ~3;
1351 buf
= (FT_Byte
*)malloc(len
);
1353 return FT_Err_Out_Of_Memory
;
1355 /* pad end of buffer with zeros */
1356 buf
[len
- 1] = 0x00;
1357 buf
[len
- 2] = 0x00;
1358 buf
[len
- 3] = 0x00;
1360 /* copy cvt program into buffer and fill in the missing variables */
1363 COPY_PREP(store_0x10000
);
1365 if (blue_adjustment
)
1367 COPY_PREP(align_top_a
);
1368 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1369 + blue_adjustment
- vaxis
->blues
);
1370 COPY_PREP(align_top_b
);
1372 COPY_PREP(loop_cvt_a
);
1373 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1374 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
1375 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
1376 COPY_PREP(loop_cvt_b
);
1377 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1378 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1379 + CVT_BLUES_SIZE(font
) - 1);
1380 COPY_PREP(loop_cvt_c
);
1381 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
1382 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1383 + CVT_BLUES_SIZE(font
) - 1);
1384 COPY_PREP(loop_cvt_d
);
1387 COPY_PREP(compute_extra_light_a
);
1388 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
1389 COPY_PREP(compute_extra_light_b
);
1391 if (CVT_BLUES_SIZE(font
))
1393 COPY_PREP(round_blues_a
);
1394 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1395 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1396 + CVT_BLUES_SIZE(font
) - 1);
1397 COPY_PREP(round_blues_b
);
1401 *prep_len
= buf_len
;
1408 TA_sfnt_build_prep_table(SFNT
* sfnt
,
1417 error
= TA_sfnt_add_table_info(sfnt
);
1421 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
1425 /* in case of success, `prep_buf' gets linked */
1426 /* and is eventually freed in `TA_font_unload' */
1427 error
= TA_font_add_table(font
,
1428 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1429 TTAG_prep
, prep_len
, prep_buf
);
1440 /* we store the segments in the storage area; */
1441 /* each segment record consists of the first and last point */
1444 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
1448 TA_GlyphHints hints
= &font
->loader
->hints
;
1449 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1450 TA_Point points
= hints
->points
;
1451 TA_Segment segments
= axis
->segments
;
1453 TA_Segment seg_limit
;
1460 FT_Bool need_words
= 0;
1463 FT_UInt num_storage
;
1464 FT_UInt num_stack_elements
;
1467 seg_limit
= segments
+ axis
->num_segments
;
1468 num_args
= 2 * axis
->num_segments
+ 3;
1470 /* collect all arguments temporarily in an array (in reverse order) */
1471 /* so that we can easily split into chunks of 255 args */
1472 /* as needed by NPUSHB and NPUSHW, respectively */
1473 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1477 arg
= args
+ num_args
- 1;
1479 if (axis
->num_segments
> 0xFF)
1482 *(arg
--) = bci_loop_sal_assign
;
1483 *(arg
--) = axis
->num_segments
* 2;
1484 *(arg
--) = sal_segment_offset
;
1486 for (seg
= segments
; seg
< seg_limit
; seg
++)
1488 FT_UInt first
= seg
->first
- points
;
1489 FT_UInt last
= seg
->last
- points
;
1495 if (first
> 0xFF || last
> 0xFF)
1499 /* with most fonts it is very rare */
1500 /* that any of the pushed arguments is larger than 0xFF, */
1501 /* thus we refrain from further optimizing this case */
1507 for (i
= 0; i
< num_args
; i
+= 255)
1509 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
1513 for (j
= 0; j
< nargs
; j
++)
1523 for (i
= 0; i
< num_args
; i
+= 255)
1525 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
1529 for (j
= 0; j
< nargs
; j
++)
1539 num_storage
= sal_segment_offset
+ axis
->num_segments
;
1540 if (num_storage
> sfnt
->max_storage
)
1541 sfnt
->max_storage
= num_storage
;
1543 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
1544 if (num_stack_elements
> sfnt
->max_stack_elements
)
1545 sfnt
->max_stack_elements
= num_stack_elements
;
1554 TA_hints_record_is_different(Hints_Record
* hints_records
,
1555 FT_UInt num_hints_records
,
1559 Hints_Record last_hints_record
;
1565 /* we only need to compare with the last hints record */
1566 last_hints_record
= hints_records
[num_hints_records
- 1];
1568 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1571 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1579 TA_add_hints_record(Hints_Record
** hints_records
,
1580 FT_UInt
* num_hints_records
,
1582 Hints_Record hints_record
)
1584 Hints_Record
* hints_records_new
;
1586 /* at this point, `hints_record.buf' still points into `ins_buf' */
1587 FT_Byte
* end
= hints_record
.buf
;
1590 buf_len
= (FT_UInt
)(end
- start
);
1592 /* now fill the structure completely */
1593 hints_record
.buf_len
= buf_len
;
1594 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1595 if (!hints_record
.buf
)
1596 return FT_Err_Out_Of_Memory
;
1598 memcpy(hints_record
.buf
, start
, buf_len
);
1600 (*num_hints_records
)++;
1602 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1603 * sizeof (Hints_Record
));
1604 if (!hints_records_new
)
1606 free(hints_record
.buf
);
1607 (*num_hints_records
)--;
1608 return FT_Err_Out_Of_Memory
;
1611 *hints_records
= hints_records_new
;
1613 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1620 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
1621 Hints_Record
* hints_record
,
1626 FT_Bool need_words
= 0;
1629 FT_UInt num_arguments
;
1631 FT_UInt num_stack_elements
;
1634 /* check whether any argument is larger than 0xFF */
1635 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1636 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1640 /* with most fonts it is very rare */
1641 /* that any of the pushed arguments is larger than 0xFF, */
1642 /* thus we refrain from further optimizing this case */
1644 num_arguments
= hints_record
->buf_len
/ 2;
1649 for (i
= 0; i
< num_arguments
; i
+= 255)
1651 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1655 for (j
= 0; j
< num_args
; j
++)
1665 /* we only need the lower bytes */
1668 for (i
= 0; i
< num_arguments
; i
+= 255)
1670 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1674 for (j
= 0; j
< num_args
; j
++)
1682 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
1683 if (num_stack_elements
> sfnt
->max_stack_elements
)
1684 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
1691 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
1692 Hints_Record
* hints_records
,
1693 FT_UInt num_hints_records
,
1697 Hints_Record
* hints_record
;
1700 hints_record
= hints_records
;
1702 /* this instruction is essential for getting correct CVT values */
1703 /* if horizontal and vertical resolutions differ; */
1704 /* it assures that the projection vector is set to the y axis */
1705 /* so that CVT values are handled as being `vertical' */
1708 for (i
= 0; i
< num_hints_records
- 1; i
++)
1711 if (hints_record
->size
> 0xFF)
1714 BCI(HIGH((hints_record
+ 1)->size
));
1715 BCI(LOW((hints_record
+ 1)->size
));
1720 BCI((hints_record
+ 1)->size
);
1724 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
1730 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
1732 for (i
= 0; i
< num_hints_records
- 1; i
++)
1736 BCI(bci_hint_glyph
);
1744 TA_free_hints_records(Hints_Record
* hints_records
,
1745 FT_UInt num_hints_records
)
1750 for (i
= 0; i
< num_hints_records
; i
++)
1751 free(hints_records
[i
].buf
);
1753 free(hints_records
);
1758 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1759 TA_Segment segments
,
1764 FT_UInt num_segs
= 0;
1767 seg_idx
= edge
->first
- segments
;
1769 /* we store everything as 16bit numbers */
1770 *(bufp
++) = HIGH(seg_idx
);
1771 *(bufp
++) = LOW(seg_idx
);
1773 *(bufp
++) = edge
->flags
& TA_EDGE_SERIF
;
1775 *(bufp
++) = edge
->flags
& TA_EDGE_ROUND
;
1777 seg
= edge
->first
->edge_next
;
1778 while (seg
!= edge
->first
)
1780 seg
= seg
->edge_next
;
1784 *(bufp
++) = HIGH(num_segs
);
1785 *(bufp
++) = LOW(num_segs
);
1787 seg
= edge
->first
->edge_next
;
1788 while (seg
!= edge
->first
)
1790 seg_idx
= seg
- segments
;
1791 seg
= seg
->edge_next
;
1793 *(bufp
++) = HIGH(seg_idx
);
1794 *(bufp
++) = LOW(seg_idx
);
1802 TA_hints_recorder(TA_Action action
,
1803 TA_GlyphHints hints
,
1809 TA_AxisHints axis
= &hints
->axis
[dim
];
1810 TA_Segment segments
= axis
->segments
;
1812 Recorder
* recorder
= (Recorder
*)hints
->user
;
1813 FONT
* font
= recorder
->font
;
1814 FT_Byte
* p
= recorder
->hints_record
.buf
;
1817 if (dim
== TA_DIMENSION_HORZ
)
1820 /* we ignore the BOUND action since the information is handled */
1821 /* in `ta_adjust_bound' and `ta_stem_bound' */
1822 if (action
== ta_bound
)
1826 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1830 case ta_adjust_bound
:
1831 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1832 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1833 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
1837 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1838 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1839 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg3
);
1843 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1844 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1848 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1849 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1853 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1854 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1858 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1859 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg2
);
1864 TA_Edge edge
= (TA_Edge
)arg1
;
1867 if (edge
->best_blue_is_shoot
)
1869 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1870 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1874 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1875 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1878 p
= TA_hints_recorder_handle_segments(p
, segments
, edge
);
1883 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1886 case ta_serif_anchor
:
1887 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1890 case ta_serif_link1
:
1891 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1894 case ta_serif_link2
:
1895 p
= TA_hints_recorder_handle_segments(p
, segments
, (TA_Edge
)arg1
);
1898 /* to pacify the compiler */
1903 recorder
->hints_record
.num_actions
++;
1904 recorder
->hints_record
.buf
= p
;
1909 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1913 FT_Face face
= sfnt
->face
;
1920 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1921 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1922 GLYPH
* glyph
= &data
->glyphs
[idx
];
1924 TA_GlyphHints hints
;
1926 FT_UInt num_hints_records
;
1927 Hints_Record
* hints_records
;
1935 return FT_Err_Invalid_Argument
;
1937 /* computing the segments is resolution independent, */
1938 /* thus the pixel size in this call is arbitrary */
1939 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1943 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1944 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
1948 /* do nothing if we have an empty glyph */
1949 if (!face
->glyph
->outline
.n_contours
)
1952 hints
= &font
->loader
->hints
;
1954 /* we allocate a buffer which is certainly large enough */
1955 /* to hold all of the created bytecode instructions; */
1956 /* later on it gets reallocated to its real size */
1957 ins_len
= hints
->num_points
* 1000;
1958 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1960 return FT_Err_Out_Of_Memory
;
1962 /* initialize array with an invalid bytecode */
1963 /* so that we can easily find the array length at reallocation time */
1964 memset(ins_buf
, INS_A0
, ins_len
);
1966 bufp
= TA_sfnt_build_glyph_segments(sfnt
, font
, ins_buf
);
1968 /* now we loop over a large range of pixel sizes */
1969 /* to find hints records which get pushed onto the bytecode stack */
1970 num_hints_records
= 0;
1971 hints_records
= NULL
;
1974 printf("glyph %ld\n", idx
);
1977 /* we temporarily use `ins_buf' to record the current glyph hints, */
1978 /* leaving two bytes at the beginning so that the number of actions */
1979 /* can be inserted later on */
1980 recorder
.font
= font
;
1981 ta_loader_register_hints_recorder(font
->loader
,
1985 for (size
= 8; size
<= 1000; size
++)
1987 /* rewind buffer pointer for recorder */
1988 recorder
.hints_record
.buf
= bufp
+ 2;
1989 recorder
.hints_record
.num_actions
= 0;
1990 recorder
.hints_record
.size
= size
;
1992 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1996 /* calling `ta_loader_load_glyph' uses the */
1997 /* `TA_hints_recorder' function as a callback, */
1998 /* modifying `hints_record' */
1999 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
2003 /* store the number of actions in `ins_buf' */
2004 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
2005 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
2007 if (TA_hints_record_is_different(hints_records
,
2009 bufp
, recorder
.hints_record
.buf
))
2012 if (num_hints_records
> 0)
2017 printf(" %d:\n", size
);
2018 for (p
= bufp
; p
< hints_record
.buf
; p
+= 2)
2019 printf(" %2d", *p
* 256 + *(p
+ 1));
2024 error
= TA_add_hints_record(&hints_records
,
2026 bufp
, recorder
.hints_record
);
2032 /* clear `ins_buf' if we only have a single empty record */
2033 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
2034 memset(ins_buf
, INS_A0
, (bufp
+ 2) - ins_buf
);
2036 bufp
= TA_sfnt_emit_hints_records(sfnt
,
2037 hints_records
, num_hints_records
,
2040 /* we are done, so reallocate the instruction array to its real size */
2041 /* (memrchr is a GNU glibc extension, so we do it manually) */
2042 bufp
= ins_buf
+ ins_len
;
2043 while (*(--bufp
) == INS_A0
)
2045 ins_len
= bufp
- ins_buf
+ 1;
2047 if (ins_len
> sfnt
->max_instructions
)
2048 sfnt
->max_instructions
= ins_len
;
2050 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2051 glyph
->ins_len
= ins_len
;
2053 TA_free_hints_records(hints_records
, num_hints_records
);
2058 TA_free_hints_records(hints_records
, num_hints_records
);
2066 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
2069 FT_Face face
= sfnt
->face
;
2074 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
2076 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
2084 /* end of tabytecode.c */