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 /* structures for hinting sets */
26 typedef struct Edge2Blue_
{
27 FT_UInt first_segment
;
32 FT_UInt num_remaining_segments
;
33 FT_UInt
* remaining_segments
;
36 typedef struct Edge2Link_
{
37 FT_UInt first_segment
;
39 FT_UInt num_remaining_segments
;
40 FT_UInt
* remaining_segments
;
43 typedef struct Hinting_Set_
{
46 FT_UInt num_edges2blues
;
47 Edge2Blue
* edges2blues
;
49 FT_UInt num_edges2links
;
50 Edge2Link
* edges2links
;
58 TA_sfnt_compute_global_hints(SFNT
* sfnt
,
62 FT_Face face
= sfnt
->face
;
66 static const FT_Encoding latin_encs
[] =
69 FT_ENCODING_APPLE_ROMAN
,
70 FT_ENCODING_ADOBE_STANDARD
,
71 FT_ENCODING_ADOBE_LATIN_1
,
73 FT_ENCODING_NONE
/* end of list */
77 error
= ta_loader_init(font
->loader
);
81 /* try to select a latin charmap */
82 for (enc
= 0; latin_encs
[enc
] != FT_ENCODING_NONE
; enc
++)
84 error
= FT_Select_Charmap(face
, latin_encs
[enc
]);
89 /* load latin glyph `a' to trigger all initializations */
90 idx
= FT_Get_Char_Index(face
, 'a');
91 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
98 TA_table_build_cvt(FT_Byte
** cvt
,
115 error
= TA_sfnt_compute_global_hints(sfnt
, font
);
119 /* XXX check validity of pointers */
120 haxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[0];
121 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
126 + 2 * vaxis
->blue_count
);
128 /* buffer length must be a multiple of four */
129 len
= (buf_len
+ 3) & ~3;
130 buf
= (FT_Byte
*)malloc(len
);
132 return FT_Err_Out_Of_Memory
;
134 /* pad end of buffer with zeros */
141 if (haxis
->width_count
> 0)
143 *(buf_p
++) = HIGH(haxis
->widths
[0].org
);
144 *(buf_p
++) = LOW(haxis
->widths
[0].org
);
151 if (vaxis
->width_count
> 0)
153 *(buf_p
++) = HIGH(vaxis
->widths
[0].org
);
154 *(buf_p
++) = LOW(vaxis
->widths
[0].org
);
162 for (i
= 0; i
< haxis
->width_count
; i
++)
164 if (haxis
->widths
[i
].org
> 0xFFFF)
166 *(buf_p
++) = HIGH(haxis
->widths
[i
].org
);
167 *(buf_p
++) = LOW(haxis
->widths
[i
].org
);
170 for (i
= 0; i
< vaxis
->width_count
; i
++)
172 if (vaxis
->widths
[i
].org
> 0xFFFF)
174 *(buf_p
++) = HIGH(vaxis
->widths
[i
].org
);
175 *(buf_p
++) = LOW(vaxis
->widths
[i
].org
);
178 for (i
= 0; i
< vaxis
->blue_count
; i
++)
180 if (vaxis
->blues
[i
].ref
.org
> 0xFFFF)
182 *(buf_p
++) = HIGH(vaxis
->blues
[i
].ref
.org
);
183 *(buf_p
++) = LOW(vaxis
->blues
[i
].ref
.org
);
186 for (i
= 0; i
< vaxis
->blue_count
; i
++)
188 if (vaxis
->blues
[i
].shoot
.org
> 0xFFFF)
190 *(buf_p
++) = HIGH(vaxis
->blues
[i
].shoot
.org
);
191 *(buf_p
++) = LOW(vaxis
->blues
[i
].shoot
.org
);
195 TA_LOG(("--------------------------------------------------\n"));
196 TA_LOG(("glyph %d:\n", idx
));
197 ta_glyph_hints_dump_edges(_ta_debug_hints
);
198 ta_glyph_hints_dump_segments(_ta_debug_hints
);
199 ta_glyph_hints_dump_points(_ta_debug_hints
);
209 return TA_Err_Hinter_Overflow
;
214 TA_sfnt_build_cvt_table(SFNT
* sfnt
,
223 error
= TA_sfnt_add_table_info(sfnt
);
227 error
= TA_table_build_cvt(&cvt_buf
, &cvt_len
, sfnt
, font
);
231 /* in case of success, `cvt_buf' gets linked */
232 /* and is eventually freed in `TA_font_unload' */
233 error
= TA_font_add_table(font
,
234 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
235 TTAG_cvt
, cvt_len
, cvt_buf
);
246 /* the horizontal and vertical standard widths */
247 #define CVT_HORZ_STANDARD_WIDTH_OFFSET(font) 0
248 #define CVT_VERT_STANDARD_WIDTH_OFFSET(font) \
249 CVT_HORZ_STANDARD_WIDTH_OFFSET(font) + 1
251 /* the horizontal stem widths */
252 #define CVT_HORZ_WIDTHS_OFFSET(font) \
253 CVT_VERT_STANDARD_WIDTH_OFFSET(font) + 1
254 #define CVT_HORZ_WIDTHS_SIZE(font) \
255 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
257 /* the vertical stem widths */
258 #define CVT_VERT_WIDTHS_OFFSET(font) \
259 CVT_HORZ_WIDTHS_OFFSET(font) + CVT_HORZ_WIDTHS_SIZE(font)
260 #define CVT_VERT_WIDTHS_SIZE(font) \
261 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
263 /* the number of blue zones */
264 #define CVT_BLUES_SIZE(font) \
265 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
267 /* the blue zone values for flat and round edges */
268 #define CVT_BLUE_REFS_OFFSET(font) \
269 CVT_VERT_WIDTHS_OFFSET(font) + CVT_VERT_WIDTHS_SIZE(font)
270 #define CVT_BLUE_SHOOTS_OFFSET(font) \
271 CVT_BLUE_REFS_OFFSET(font) + CVT_BLUES_SIZE(font)
274 /* symbolic names for storage area locations */
276 #define sal_counter 0
277 #define sal_limit sal_counter + 1
278 #define sal_scale sal_limit + 1
279 #define sal_0x10000 sal_scale + 1
280 #define sal_is_extra_light sal_0x10000 + 1
281 #define sal_segment_offset sal_is_extra_light + 1 /* must be last */
284 /* we need the following macro */
285 /* so that `func_name' doesn't get replaced with its #defined value */
286 /* (as defined in `tabytecode.h') */
288 #define FPGM(func_name) fpgm_ ## func_name
291 /* in the comments below, the top of the stack (`s:') */
292 /* is the rightmost element; the stack is shown */
293 /* after the instruction on the same line has been executed */
296 * bci_compute_stem_width
298 * This is the equivalent to the following code from function
299 * `ta_latin_compute_stem_width':
307 * else if base_is_round:
311 * dist = MIN(56, dist)
313 * delta = ABS(dist - std_width)
316 * dist = MIN(48, std_width)
322 * delta = delta - dist
325 * dist = dist + delta
326 * else if delta < 32:
328 * else if delta < 54:
331 * dist = dist + delta
345 * sal: is_extra_light
349 unsigned char FPGM(bci_compute_stem_width_a
) [] = {
352 bci_compute_stem_width
,
356 ABS
, /* s: base_is_round stem_is_serif width dist */
361 LT
, /* dist < 3*64 */
365 MINDEX
, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
366 AND
, /* stem_is_serif && dist < 3*64 */
371 OR
, /* (stem_is_serif && dist < 3*64) || is_extra_light */
373 IF
, /* s: base_is_round width dist */
379 ROLL
, /* s: width dist base_is_round */
380 IF
, /* s: width dist */
385 IF
, /* s: width dist */
394 MIN
, /* dist = min(56, dist) */
397 DUP
, /* s: width dist dist */
402 /* %c, index of std_width */
404 unsigned char FPGM(bci_compute_stem_width_b
) [] = {
408 ABS
, /* s: width dist delta */
413 IF
, /* s: width dist */
420 /* %c, index of std_width */
422 unsigned char FPGM(bci_compute_stem_width_c
) [] = {
425 MIN
, /* dist = min(48, std_width) */
428 DUP
, /* s: width dist dist */
431 LT
, /* dist < 3*64 */
433 DUP
, /* s: width delta dist */
434 FLOOR
, /* dist = FLOOR(dist) */
435 DUP
, /* s: width delta dist dist */
437 ROLL
, /* s: width dist delta dist */
438 SUB
, /* delta = delta - dist */
440 DUP
, /* s: width dist delta delta */
444 IF
, /* s: width dist delta */
445 ADD
, /* dist = dist + delta */
456 ADD
, /* dist = dist + 10 */
467 ADD
, /* dist = dist + 54 */
470 ADD
, /* dist = dist + delta */
480 FLOOR
, /* dist = round(dist) */
485 SWAP
, /* s: dist width */
490 NEG
, /* dist = -dist */
503 * Take a range and a function number and apply the function to all
504 * elements of the range. The called function must not change the
511 * uses: sal_counter (counter initialized with `start')
515 unsigned char FPGM(bci_loop
) [] = {
522 ROLL
, /* s: func_num start end */
540 LTEQ
, /* start <= end */
541 IF
, /* s: func_num */
548 ADD
, /* start = start + 1 */
557 JMPR
, /* goto start_loop */
570 * Rescale CVT value by a given factor.
572 * uses: sal_counter (CVT index)
573 * sal_scale (scale in 16.16 format)
576 unsigned char FPGM(bci_cvt_rescale
) [] = {
590 MUL
, /* CVT * scale * 2^10 */
594 DIV
, /* CVT * scale */
604 * bci_loop_sal_assign
606 * Apply the WS instruction repeatedly to stack data.
615 * uses: bci_sal_assign
618 unsigned char FPGM(bci_sal_assign
) [] = {
625 ROLL
, /* s: offset offset data */
630 ADD
, /* s: (offset + 1) */
636 unsigned char FPGM(bci_loop_sal_assign
) [] = {
642 /* process the stack, popping off the elements in a loop */
658 * Round a blue ref value and adjust its corresponding shoot value.
660 * uses: sal_counter (CVT index)
664 unsigned char FPGM(bci_blue_round_a
) [] = {
674 RCVT
, /* s: ref_idx ref */
681 SWAP
, /* s: ref_idx round(ref) ref */
689 unsigned char FPGM(bci_blue_round_b
) [] = {
693 ADD
, /* s: ref_idx round(ref) ref shoot_idx */
695 RCVT
, /* s: ref_idx round(ref) ref shoot_idx shoot */
697 ROLL
, /* s: ref_idx round(ref) shoot_idx shoot ref */
699 SUB
, /* s: ref_idx round(ref) shoot_idx dist */
701 ABS
, /* s: ref_idx round(ref) shoot_idx dist delta */
726 SWAP
, /* s: ref_idx round(ref) shoot_idx delta dist */
731 NEG
, /* delta = -delta */
737 ADD
, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
750 * This is the top-level glyph hinting function
751 * which parses the arguments on the stack and calls subroutines.
753 * in: num_edges2blues (M)
754 * edge2blue_0.first_segment
757 * .num_remaining_segments (N)
758 * .remaining_segments_0
766 * num_edges2links (P)
767 * edge2link_0.first_segment
768 * .num_remaining_segments (Q)
769 * .remaining_segments_0
777 * uses: bci_edge2blue
781 unsigned char FPGM(bci_remaining_edges
) [] = {
787 POP
, /* XXX remaining segment */
793 unsigned char FPGM(bci_edge2blue
) [] = {
799 POP
, /* XXX first_segment */
800 POP
, /* XXX is_serif */
801 POP
, /* XXX is_round */
810 unsigned char FPGM(bci_edge2link
) [] = {
816 POP
, /* XXX first_segment */
825 unsigned char FPGM(bci_hint_glyph
) [] = {
844 #define COPY_FPGM(func_name) \
845 memcpy(buf_p, fpgm_ ## func_name, \
846 sizeof (fpgm_ ## func_name)); \
847 buf_p += sizeof (fpgm_ ## func_name) \
850 TA_table_build_fpgm(FT_Byte
** fpgm
,
860 buf_len
= sizeof (FPGM(bci_compute_stem_width_a
))
862 + sizeof (FPGM(bci_compute_stem_width_b
))
864 + sizeof (FPGM(bci_compute_stem_width_c
))
865 + sizeof (FPGM(bci_loop
))
866 + sizeof (FPGM(bci_cvt_rescale
))
867 + sizeof (FPGM(bci_sal_assign
))
868 + sizeof (FPGM(bci_loop_sal_assign
))
869 + sizeof (FPGM(bci_blue_round_a
))
871 + sizeof (FPGM(bci_blue_round_b
))
872 + sizeof (FPGM(bci_remaining_edges
))
873 + sizeof (FPGM(bci_edge2blue
))
874 + sizeof (FPGM(bci_edge2link
))
875 + sizeof (FPGM(bci_hint_glyph
));
876 /* buffer length must be a multiple of four */
877 len
= (buf_len
+ 3) & ~3;
878 buf
= (FT_Byte
*)malloc(len
);
880 return FT_Err_Out_Of_Memory
;
882 /* pad end of buffer with zeros */
887 /* copy font program into buffer and fill in the missing variables */
890 COPY_FPGM(bci_compute_stem_width_a
);
891 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
892 COPY_FPGM(bci_compute_stem_width_b
);
893 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
894 COPY_FPGM(bci_compute_stem_width_c
);
896 COPY_FPGM(bci_cvt_rescale
);
897 COPY_FPGM(bci_sal_assign
);
898 COPY_FPGM(bci_loop_sal_assign
);
899 COPY_FPGM(bci_blue_round_a
);
900 *(buf_p
++) = (unsigned char)CVT_BLUES_SIZE(font
);
901 COPY_FPGM(bci_blue_round_b
);
902 COPY_FPGM(bci_remaining_edges
);
903 COPY_FPGM(bci_edge2blue
);
904 COPY_FPGM(bci_edge2link
);
905 COPY_FPGM(bci_hint_glyph
);
915 TA_sfnt_build_fpgm_table(SFNT
* sfnt
,
924 error
= TA_sfnt_add_table_info(sfnt
);
928 error
= TA_table_build_fpgm(&fpgm_buf
, &fpgm_len
, font
);
932 /* in case of success, `fpgm_buf' gets linked */
933 /* and is eventually freed in `TA_font_unload' */
934 error
= TA_font_add_table(font
,
935 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
936 TTAG_fpgm
, fpgm_len
, fpgm_buf
);
947 /* the `prep' instructions */
949 #define PREP(snippet_name) prep_ ## snippet_name
951 /* we often need 0x10000 which can't be pushed directly onto the stack, */
952 /* thus we provide it in the storage area */
954 unsigned char PREP(store_0x10000
) [] = {
968 unsigned char PREP(align_top_a
) [] = {
970 /* optimize the alignment of the top of small letters to the pixel grid */
976 /* %c, index of alignment blue zone */
978 unsigned char PREP(align_top_b
) [] = {
986 FLOOR
, /* fitted = FLOOR(scaled + 40) */
987 DUP
, /* s: scaled scaled fitted fitted */
990 IF
, /* s: scaled fitted */
994 MUL
, /* scaled in 16.16 format */
996 DIV
, /* (fitted / scaled) in 16.16 format */
1005 unsigned char PREP(loop_cvt_a
) [] = {
1007 /* loop over vertical CVT entries */
1012 /* %c, first vertical index */
1013 /* %c, last vertical index */
1015 unsigned char PREP(loop_cvt_b
) [] = {
1021 /* loop over blue refs */
1026 /* %c, first blue ref index */
1027 /* %c, last blue ref index */
1029 unsigned char PREP(loop_cvt_c
) [] = {
1035 /* loop over blue shoots */
1040 /* %c, first blue shoot index */
1041 /* %c, last blue shoot index */
1043 unsigned char PREP(loop_cvt_d
) [] = {
1052 unsigned char PREP(compute_extra_light_a
) [] = {
1054 /* compute (vertical) `extra_light' flag */
1061 /* %c, index of vertical standard_width */
1063 unsigned char PREP(compute_extra_light_b
) [] = {
1066 GT
, /* standard_width < 40 */
1071 unsigned char PREP(round_blues_a
) [] = {
1073 /* use discrete values for blue zone widths */
1078 /* %c, first blue ref index */
1079 /* %c, last blue ref index */
1081 unsigned char PREP(round_blues_b
) [] = {
1090 /* XXX talatin.c: 1671 */
1091 /* XXX talatin.c: 1708 */
1092 /* XXX talatin.c: 2182 */
1095 #define COPY_PREP(snippet_name) \
1096 memcpy(buf_p, prep_ ## snippet_name, \
1097 sizeof (prep_ ## snippet_name)); \
1098 buf_p += sizeof (prep_ ## snippet_name);
1101 TA_table_build_prep(FT_Byte
** prep
,
1106 TA_LatinBlue blue_adjustment
;
1115 vaxis
= &((TA_LatinMetrics
)font
->loader
->hints
.metrics
)->axis
[1];
1116 blue_adjustment
= NULL
;
1118 for (i
= 0; i
< vaxis
->blue_count
; i
++)
1120 if (vaxis
->blues
[i
].flags
& TA_LATIN_BLUE_ADJUSTMENT
)
1122 blue_adjustment
= &vaxis
->blues
[i
];
1127 buf_len
= sizeof (PREP(store_0x10000
));
1129 if (blue_adjustment
)
1130 buf_len
+= sizeof (PREP(align_top_a
))
1132 + sizeof (PREP(align_top_b
))
1133 + sizeof (PREP(loop_cvt_a
))
1135 + sizeof (PREP(loop_cvt_b
))
1137 + sizeof (PREP(loop_cvt_c
))
1139 + sizeof (PREP(loop_cvt_d
));
1141 buf_len
+= sizeof (PREP(compute_extra_light_a
))
1143 + sizeof (PREP(compute_extra_light_b
));
1145 if (CVT_BLUES_SIZE(font
))
1146 buf_len
+= sizeof (PREP(round_blues_a
))
1148 + sizeof (PREP(round_blues_b
));
1150 /* buffer length must be a multiple of four */
1151 len
= (buf_len
+ 3) & ~3;
1152 buf
= (FT_Byte
*)malloc(len
);
1154 return FT_Err_Out_Of_Memory
;
1156 /* pad end of buffer with zeros */
1157 buf
[len
- 1] = 0x00;
1158 buf
[len
- 2] = 0x00;
1159 buf
[len
- 3] = 0x00;
1161 /* copy cvt program into buffer and fill in the missing variables */
1164 COPY_PREP(store_0x10000
);
1166 if (blue_adjustment
)
1168 COPY_PREP(align_top_a
);
1169 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1170 + blue_adjustment
- vaxis
->blues
);
1171 COPY_PREP(align_top_b
);
1173 COPY_PREP(loop_cvt_a
);
1174 *(buf_p
++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font
);
1175 *(buf_p
++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font
)
1176 + CVT_VERT_WIDTHS_SIZE(font
) - 1);
1177 COPY_PREP(loop_cvt_b
);
1178 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1179 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1180 + CVT_BLUES_SIZE(font
) - 1);
1181 COPY_PREP(loop_cvt_c
);
1182 *(buf_p
++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font
);
1183 *(buf_p
++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font
)
1184 + CVT_BLUES_SIZE(font
) - 1);
1185 COPY_PREP(loop_cvt_d
);
1188 COPY_PREP(compute_extra_light_a
);
1189 *(buf_p
++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font
);
1190 COPY_PREP(compute_extra_light_b
);
1192 if (CVT_BLUES_SIZE(font
))
1194 COPY_PREP(round_blues_a
);
1195 *(buf_p
++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font
);
1196 *(buf_p
++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font
)
1197 + CVT_BLUES_SIZE(font
) - 1);
1198 COPY_PREP(round_blues_b
);
1202 *prep_len
= buf_len
;
1209 TA_sfnt_build_prep_table(SFNT
* sfnt
,
1218 error
= TA_sfnt_add_table_info(sfnt
);
1222 error
= TA_table_build_prep(&prep_buf
, &prep_len
, font
);
1226 /* in case of success, `prep_buf' gets linked */
1227 /* and is eventually freed in `TA_font_unload' */
1228 error
= TA_font_add_table(font
,
1229 &sfnt
->table_infos
[sfnt
->num_table_infos
- 1],
1230 TTAG_prep
, prep_len
, prep_buf
);
1241 /* we store the segments in the storage area; */
1242 /* each segment record consists of the first and last point */
1245 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
1249 TA_GlyphHints hints
= &font
->loader
->hints
;
1250 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1251 TA_Point points
= hints
->points
;
1252 TA_Segment segments
= axis
->segments
;
1254 TA_Segment seg_limit
;
1261 FT_Bool need_words
= 0;
1264 FT_UInt num_storage
;
1265 FT_UInt num_stack_elements
;
1268 seg_limit
= segments
+ axis
->num_segments
;
1269 num_args
= 2 * axis
->num_segments
+ 3;
1271 /* collect all arguments temporarily in an array (in reverse order) */
1272 /* so that we can easily split into chunks of 255 args */
1273 /* as needed by NPUSHB and NPUSHW, respectively */
1274 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1278 arg
= args
+ num_args
- 1;
1280 if (axis
->num_segments
> 0xFF)
1283 *(arg
--) = bci_loop_sal_assign
;
1284 *(arg
--) = axis
->num_segments
* 2;
1285 *(arg
--) = sal_segment_offset
;
1287 for (seg
= segments
; seg
< seg_limit
; seg
++)
1289 FT_UInt first
= seg
->first
- points
;
1290 FT_UInt last
= seg
->last
- points
;
1296 if (first
> 0xFF || last
> 0xFF)
1300 /* with most fonts it is very rare */
1301 /* that any of the pushed arguments is larger than 0xFF, */
1302 /* thus we refrain from further optimizing this case */
1308 for (i
= 0; i
< num_args
; i
+= 255)
1310 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
1314 for (j
= 0; j
< nargs
; j
++)
1324 for (i
= 0; i
< num_args
; i
+= 255)
1326 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
1330 for (j
= 0; j
< nargs
; j
++)
1340 num_storage
= sal_segment_offset
+ axis
->num_segments
;
1341 if (num_storage
> sfnt
->max_storage
)
1342 sfnt
->max_storage
= num_storage
;
1344 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
1345 if (num_stack_elements
> sfnt
->max_stack_elements
)
1346 sfnt
->max_stack_elements
= num_stack_elements
;
1355 TA_font_clear_edge_DONE_flag(FONT
* font
)
1357 TA_GlyphHints hints
= &font
->loader
->hints
;
1358 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1359 TA_Edge edges
= axis
->edges
;
1360 TA_Edge edge_limit
= edges
+ axis
->num_edges
;
1364 for (edge
= edges
; edge
< edge_limit
; edge
++)
1365 edge
->flags
&= ~TA_EDGE_DONE
;
1370 TA_construct_hinting_set(FONT
* font
,
1372 Hinting_Set
* hinting_set
)
1374 TA_GlyphHints hints
= &font
->loader
->hints
;
1375 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1376 TA_Segment segments
= axis
->segments
;
1377 TA_Edge edges
= axis
->edges
;
1378 TA_Edge limit
= edges
+ axis
->num_edges
;
1381 Edge2Blue
* edge2blue
;
1382 Edge2Link
* edge2link
;
1385 hinting_set
->size
= size
;
1386 hinting_set
->need_words
= 0;
1387 hinting_set
->num_args
= 0;
1389 hinting_set
->num_edges2blues
= 0;
1390 hinting_set
->edges2blues
= NULL
;
1391 hinting_set
->num_edges2links
= 0;
1392 hinting_set
->edges2links
= NULL
;
1394 for (edge
= edges
; edge
< limit
; edge
++)
1396 if (edge
->blue_edge
)
1397 hinting_set
->num_edges2blues
++;
1399 hinting_set
->num_edges2links
++;
1402 if (hinting_set
->num_edges2blues
> 0xFF
1403 || hinting_set
->num_edges2links
> 0xFF)
1404 hinting_set
->need_words
= 1;
1406 /* we push num_edges2blues and num_edges2links */
1407 hinting_set
->num_args
+= 2;
1409 if (hinting_set
->num_edges2blues
)
1411 hinting_set
->edges2blues
=
1412 (Edge2Blue
*)calloc(1, hinting_set
->num_edges2blues
1413 * sizeof (Edge2Blue
));
1414 if (!hinting_set
->edges2blues
)
1415 return FT_Err_Out_Of_Memory
;
1418 if (hinting_set
->num_edges2links
)
1420 hinting_set
->edges2links
=
1421 (Edge2Link
*)calloc(1, hinting_set
->num_edges2links
1422 * sizeof (Edge2Link
));
1423 if (!hinting_set
->edges2links
)
1424 return FT_Err_Out_Of_Memory
;
1427 edge2blue
= hinting_set
->edges2blues
;
1428 edge2link
= hinting_set
->edges2links
;
1430 for (edge
= edges
; edge
< limit
; edge
++)
1433 FT_UInt
* remaining_segment
;
1436 if (edge
->blue_edge
)
1438 edge2blue
->first_segment
= edge
->first
- segments
;
1439 edge2blue
->is_serif
= edge
->flags
& TA_EDGE_SERIF
;
1440 edge2blue
->is_round
= edge
->flags
& TA_EDGE_ROUND
;
1442 seg
= edge
->first
->edge_next
;
1443 while (seg
!= edge
->first
)
1445 edge2blue
->num_remaining_segments
++;
1446 seg
= seg
->edge_next
;
1449 if (edge2blue
->first_segment
> 0xFF
1450 || edge2blue
->num_remaining_segments
> 0xFF)
1451 hinting_set
->need_words
= 1;
1453 if (edge2blue
->num_remaining_segments
)
1455 edge2blue
->remaining_segments
=
1456 (FT_UInt
*)calloc(1, edge2blue
->num_remaining_segments
1457 * sizeof (FT_UInt
));
1458 if (!edge2blue
->remaining_segments
)
1459 return FT_Err_Out_Of_Memory
;
1462 seg
= edge
->first
->edge_next
;
1463 remaining_segment
= edge2blue
->remaining_segments
;
1464 while (seg
!= edge
->first
)
1466 *remaining_segment
= seg
- segments
;
1467 seg
= seg
->edge_next
;
1469 if (*remaining_segment
> 0xFF)
1470 hinting_set
->need_words
= 1;
1472 remaining_segment
++;
1475 /* we push the number of remaining segments, is_serif, is_round, */
1476 /* the first segment, and the remaining segments */
1477 hinting_set
->num_args
+= edge2blue
->num_remaining_segments
+ 4;
1483 edge2link
->first_segment
= edge
->first
- segments
;
1485 seg
= edge
->first
->edge_next
;
1486 while (seg
!= edge
->first
)
1488 edge2link
->num_remaining_segments
++;
1489 seg
= seg
->edge_next
;
1492 if (edge2link
->first_segment
> 0xFF
1493 || edge2link
->num_remaining_segments
> 0xFF)
1494 hinting_set
->need_words
= 1;
1496 if (edge2link
->num_remaining_segments
)
1498 edge2link
->remaining_segments
=
1499 (FT_UInt
*)calloc(1, edge2link
->num_remaining_segments
1500 * sizeof (FT_UInt
));
1501 if (!edge2link
->remaining_segments
)
1502 return FT_Err_Out_Of_Memory
;
1505 seg
= edge
->first
->edge_next
;
1506 remaining_segment
= edge2link
->remaining_segments
;
1507 while (seg
!= edge
->first
)
1509 *remaining_segment
= seg
- segments
;
1510 seg
= seg
->edge_next
;
1512 if (*remaining_segment
> 0xFF)
1513 hinting_set
->need_words
= 1;
1515 remaining_segment
++;
1518 /* we push the number of remaining segments, */
1519 /* the first segment, and the remaining segments */
1520 hinting_set
->num_args
+= edge2link
->num_remaining_segments
+ 2;
1531 TA_hinting_set_is_different(Hinting_Set
* hinting_sets
,
1532 FT_UInt num_hinting_sets
,
1533 Hinting_Set hinting_set
)
1535 Hinting_Set last_hinting_set
;
1537 Edge2Blue
* edge2blue
;
1538 Edge2Blue
* last_edge2blue
;
1539 Edge2Link
* edge2link
;
1540 Edge2Link
* last_edge2link
;
1548 /* we only need to compare with the last hinting set */
1549 last_hinting_set
= hinting_sets
[num_hinting_sets
- 1];
1551 if (hinting_set
.num_edges2blues
1552 != last_hinting_set
.num_edges2blues
)
1555 edge2blue
= hinting_set
.edges2blues
;
1556 last_edge2blue
= last_hinting_set
.edges2blues
;
1559 i
< hinting_set
.num_edges2blues
;
1560 i
++, edge2blue
++, last_edge2blue
++)
1562 if (edge2blue
->num_remaining_segments
1563 != last_edge2blue
->num_remaining_segments
)
1566 if (edge2blue
->remaining_segments
)
1568 if (memcmp(edge2blue
->remaining_segments
,
1569 last_edge2blue
->remaining_segments
,
1570 sizeof (FT_UInt
) * edge2blue
->num_remaining_segments
))
1575 if (hinting_set
.num_edges2links
1576 != last_hinting_set
.num_edges2links
)
1579 edge2link
= hinting_set
.edges2links
;
1580 last_edge2link
= last_hinting_set
.edges2links
;
1583 i
< hinting_set
.num_edges2links
;
1584 i
++, edge2link
++, last_edge2link
++)
1586 if (edge2link
->num_remaining_segments
1587 != last_edge2link
->num_remaining_segments
)
1590 if (edge2link
->remaining_segments
)
1592 if (memcmp(edge2link
->remaining_segments
,
1593 last_edge2link
->remaining_segments
,
1594 sizeof (FT_UInt
) * edge2link
->num_remaining_segments
))
1604 TA_add_hinting_set(Hinting_Set
** hinting_sets
,
1605 FT_UInt
* num_hinting_sets
,
1606 Hinting_Set hinting_set
)
1608 Hinting_Set
* hinting_sets_new
;
1611 (*num_hinting_sets
)++;
1613 (Hinting_Set
*)realloc(*hinting_sets
, *num_hinting_sets
1614 * sizeof (Hinting_Set
));
1615 if (!hinting_sets_new
)
1617 (*num_hinting_sets
)--;
1618 return FT_Err_Out_Of_Memory
;
1621 *hinting_sets
= hinting_sets_new
;
1623 (*hinting_sets
)[*num_hinting_sets
- 1] = hinting_set
;
1630 TA_sfnt_emit_hinting_set(SFNT
* sfnt
,
1631 Hinting_Set
* hinting_set
,
1637 Edge2Blue
* edge2blue
;
1638 Edge2Blue
* edge2blue_limit
;
1639 Edge2Link
* edge2link
;
1640 Edge2Link
* edge2link_limit
;
1647 FT_UInt num_stack_elements
;
1650 /* collect all arguments temporarily in an array (in reverse order) */
1651 /* so that we can easily split into chunks of 255 args */
1652 /* as needed by NPUSHB and NPUSHW, respectively */
1653 args
= (FT_UInt
*)malloc(hinting_set
->num_args
* sizeof (FT_UInt
));
1657 arg
= args
+ hinting_set
->num_args
- 1;
1659 *(arg
--) = hinting_set
->num_edges2blues
;
1661 edge2blue_limit
= hinting_set
->edges2blues
1662 + hinting_set
->num_edges2blues
;
1663 for (edge2blue
= hinting_set
->edges2blues
;
1664 edge2blue
< edge2blue_limit
;
1667 *(arg
--) = edge2blue
->first_segment
;
1668 *(arg
--) = edge2blue
->is_serif
;
1669 *(arg
--) = edge2blue
->is_round
;
1670 *(arg
--) = edge2blue
->num_remaining_segments
;
1672 seg_limit
= edge2blue
->remaining_segments
1673 + edge2blue
->num_remaining_segments
;
1674 for (seg
= edge2blue
->remaining_segments
; seg
< seg_limit
; seg
++)
1678 *(arg
--) = hinting_set
->num_edges2links
;
1680 edge2link_limit
= hinting_set
->edges2links
1681 + hinting_set
->num_edges2links
;
1682 for (edge2link
= hinting_set
->edges2links
;
1683 edge2link
< edge2link_limit
;
1686 *(arg
--) = edge2link
->first_segment
;
1687 *(arg
--) = edge2link
->num_remaining_segments
;
1689 seg_limit
= edge2link
->remaining_segments
1690 + edge2link
->num_remaining_segments
;
1691 for (seg
= edge2link
->remaining_segments
; seg
< seg_limit
; seg
++)
1695 /* with most fonts it is very rare */
1696 /* that any of the pushed arguments is larger than 0xFF, */
1697 /* thus we refrain from further optimizing this case */
1701 if (hinting_set
->need_words
)
1703 for (i
= 0; i
< hinting_set
->num_args
; i
+= 255)
1705 num_args
= (hinting_set
->num_args
- i
> 255)
1707 : hinting_set
->num_args
- i
;
1711 for (j
= 0; j
< num_args
; j
++)
1721 for (i
= 0; i
< hinting_set
->num_args
; i
+= 255)
1723 num_args
= (hinting_set
->num_args
- i
> 255)
1725 : hinting_set
->num_args
- i
;
1729 for (j
= 0; j
< num_args
; j
++)
1739 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ hinting_set
->num_args
;
1740 if (num_stack_elements
> sfnt
->max_stack_elements
)
1741 sfnt
->max_stack_elements
= sfnt
->max_stack_elements
;
1748 TA_sfnt_emit_hinting_sets(SFNT
* sfnt
,
1749 Hinting_Set
* hinting_sets
,
1750 FT_UInt num_hinting_sets
,
1754 Hinting_Set
* hinting_set
;
1757 hinting_set
= hinting_sets
;
1759 /* this instruction is essential for getting correct CVT values */
1760 /* if horizontal and vertical resolutions differ; */
1761 /* it assures that the projection vector is set to the y axis */
1762 /* so that CVT values are handled as being `vertical' */
1765 for (i
= 0; i
< num_hinting_sets
- 1; i
++)
1768 if (hinting_set
->size
> 0xFF)
1771 BCI(HIGH((hinting_set
+ 1)->size
));
1772 BCI(LOW((hinting_set
+ 1)->size
));
1777 BCI((hinting_set
+ 1)->size
);
1781 bufp
= TA_sfnt_emit_hinting_set(sfnt
, hinting_set
, bufp
);
1789 bufp
= TA_sfnt_emit_hinting_set(sfnt
, hinting_set
, bufp
);
1793 for (i
= 0; i
< num_hinting_sets
- 1; i
++)
1797 BCI(bci_hint_glyph
);
1805 TA_free_hinting_set(Hinting_Set hinting_set
)
1810 for (i
= 0; i
< hinting_set
.num_edges2blues
; i
++)
1811 free(hinting_set
.edges2blues
[i
].remaining_segments
);
1812 free(hinting_set
.edges2blues
);
1814 for (i
= 0; i
< hinting_set
.num_edges2links
; i
++)
1815 free(hinting_set
.edges2links
[i
].remaining_segments
);
1816 free(hinting_set
.edges2links
);
1821 TA_free_hinting_sets(Hinting_Set
* hinting_sets
,
1822 FT_UInt num_hinting_sets
)
1827 for (i
= 0; i
< num_hinting_sets
; i
++)
1828 TA_free_hinting_set(hinting_sets
[i
]);
1835 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1839 FT_Face face
= sfnt
->face
;
1846 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1847 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1848 GLYPH
* glyph
= &data
->glyphs
[idx
];
1850 TA_GlyphHints hints
;
1852 FT_UInt num_hinting_sets
;
1853 Hinting_Set
* hinting_sets
;
1859 return FT_Err_Invalid_Argument
;
1861 /* computing the segments is resolution independent, */
1862 /* thus the pixel size in this call is arbitrary */
1863 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1867 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, 0);
1871 /* do nothing if we have an empty glyph */
1872 if (!face
->glyph
->outline
.n_contours
)
1875 hints
= &font
->loader
->hints
;
1877 /* we allocate a buffer which is certainly large enough */
1878 /* to hold all of the created bytecode instructions; */
1879 /* later on it gets reallocated to its real size */
1880 ins_len
= hints
->num_points
* 1000;
1881 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1883 return FT_Err_Out_Of_Memory
;
1885 /* initialize array with an invalid bytecode */
1886 /* so that we can easily find the array length at reallocation time */
1887 memset(ins_buf
, INS_A0
, ins_len
);
1889 bufp
= TA_sfnt_build_glyph_segments(sfnt
, font
, ins_buf
);
1891 /* now we loop over a large range of pixel sizes */
1892 /* to find hinting sets which get pushed onto the bytecode stack */
1893 num_hinting_sets
= 0;
1894 hinting_sets
= NULL
;
1897 printf("glyph %ld\n", idx
);
1900 for (size
= 8; size
<= 1000; size
++)
1902 Hinting_Set hinting_set
;
1905 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1909 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
1913 TA_font_clear_edge_DONE_flag(font
);
1915 error
= TA_construct_hinting_set(font
, size
, &hinting_set
);
1919 if (TA_hinting_set_is_different(hinting_sets
,
1924 if (num_hinting_sets
> 0)
1925 printf(" additional hinting set for size %d\n", size
);
1928 error
= TA_add_hinting_set(&hinting_sets
,
1933 TA_free_hinting_set(hinting_set
);
1938 TA_free_hinting_set(hinting_set
);
1941 bufp
= TA_sfnt_emit_hinting_sets(sfnt
,
1942 hinting_sets
, num_hinting_sets
, bufp
);
1944 return FT_Err_Out_Of_Memory
;
1946 /* we are done, so reallocate the instruction array to its real size */
1947 bufp
= (FT_Byte
*)memchr((char*)ins_buf
, INS_A0
, ins_len
);
1948 ins_len
= bufp
- ins_buf
;
1950 if (ins_len
> sfnt
->max_instructions
)
1951 sfnt
->max_instructions
= ins_len
;
1953 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
1954 glyph
->ins_len
= ins_len
;
1956 TA_free_hinting_sets(hinting_sets
, num_hinting_sets
);
1961 TA_free_hinting_sets(hinting_sets
, num_hinting_sets
);
1969 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
1972 FT_Face face
= sfnt
->face
;
1977 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
1979 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
1987 /* end of tabytecode.c */