Comments, formatting.
[ttfautohint.git] / src / tabytecode.c
blob8b7563fc01354e4cf91da850a0b8b3fbe8571b32
1 /* tabytecode.c */
3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
5 #include "ta.h"
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
16 #ifdef TA_DEBUG
17 int _ta_debug = 1;
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;
22 #endif
25 /* structures for hinting sets */
26 typedef struct Edge2Blue_ {
27 FT_UInt first_segment;
29 FT_Bool is_serif;
30 FT_Bool is_round;
32 FT_UInt num_remaining_segments;
33 FT_UInt* remaining_segments;
34 } Edge2Blue;
36 typedef struct Edge2Link_ {
37 FT_UInt first_segment;
39 FT_UInt num_remaining_segments;
40 FT_UInt* remaining_segments;
41 } Edge2Link;
43 typedef struct Hinting_Set_ {
44 FT_UInt size;
46 FT_UInt num_edges2blues;
47 Edge2Blue* edges2blues;
49 FT_UInt num_edges2links;
50 Edge2Link* edges2links;
52 FT_Bool need_words;
53 FT_UInt num_args;
54 } Hinting_Set;
57 static FT_Error
58 TA_sfnt_compute_global_hints(SFNT* sfnt,
59 FONT* font)
61 FT_Error error;
62 FT_Face face = sfnt->face;
63 FT_UInt enc;
64 FT_UInt idx;
66 static const FT_Encoding latin_encs[] =
68 FT_ENCODING_UNICODE,
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);
78 if (error)
79 return error;
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]);
85 if (!error)
86 break;
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);
93 return error;
97 static FT_Error
98 TA_table_build_cvt(FT_Byte** cvt,
99 FT_ULong* cvt_len,
100 SFNT* sfnt,
101 FONT* font)
103 TA_LatinAxis haxis;
104 TA_LatinAxis vaxis;
106 FT_UInt i;
107 FT_UInt buf_len;
108 FT_UInt len;
109 FT_Byte* buf;
110 FT_Byte* buf_p;
112 FT_Error error;
115 error = TA_sfnt_compute_global_hints(sfnt, font);
116 if (error)
117 return error;
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];
123 buf_len = 2 * (2
124 + haxis->width_count
125 + vaxis->width_count
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);
131 if (!buf)
132 return FT_Err_Out_Of_Memory;
134 /* pad end of buffer with zeros */
135 buf[len - 1] = 0x00;
136 buf[len - 2] = 0x00;
137 buf[len - 3] = 0x00;
139 buf_p = buf;
141 if (haxis->width_count > 0)
143 *(buf_p++) = HIGH(haxis->widths[0].org);
144 *(buf_p++) = LOW(haxis->widths[0].org);
146 else
148 *(buf_p++) = 0;
149 *(buf_p++) = 50;
151 if (vaxis->width_count > 0)
153 *(buf_p++) = HIGH(vaxis->widths[0].org);
154 *(buf_p++) = LOW(vaxis->widths[0].org);
156 else
158 *(buf_p++) = 0;
159 *(buf_p++) = 50;
162 for (i = 0; i < haxis->width_count; i++)
164 if (haxis->widths[i].org > 0xFFFF)
165 goto Err;
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)
173 goto Err;
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)
181 goto Err;
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)
189 goto Err;
190 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
191 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
194 #if 0
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);
200 #endif
202 *cvt = buf;
203 *cvt_len = buf_len;
205 return FT_Err_Ok;
207 Err:
208 free(buf);
209 return TA_Err_Hinter_Overflow;
213 FT_Error
214 TA_sfnt_build_cvt_table(SFNT* sfnt,
215 FONT* font)
217 FT_Error error;
219 FT_Byte* cvt_buf;
220 FT_ULong cvt_len;
223 error = TA_sfnt_add_table_info(sfnt);
224 if (error)
225 return error;
227 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
228 if (error)
229 return error;
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);
236 if (error)
238 free(cvt_buf);
239 return error;
242 return FT_Err_Ok;
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':
301 * dist = ABS(width)
303 * if (stem_is_serif
304 * && dist < 3*64)
305 * || is_extra_light:
306 * return width
307 * else if base_is_round:
308 * if dist < 80
309 * dist = 64
310 * else:
311 * dist = MIN(56, dist)
313 * delta = ABS(dist - std_width)
315 * if delta < 40:
316 * dist = MIN(48, std_width)
317 * goto End
319 * if dist < 3*64:
320 * delta = dist
321 * dist = FLOOR(dist)
322 * delta = delta - dist
324 * if delta < 10:
325 * dist = dist + delta
326 * else if delta < 32:
327 * dist = dist + 10
328 * else if delta < 54:
329 * dist = dist + 54
330 * else
331 * dist = dist + delta
332 * else
333 * dist = ROUND(dist)
335 * End:
336 * if width < 0:
337 * dist = -dist
338 * return dist
341 * in: width
342 * stem_is_serif
343 * base_is_round
344 * out: new_width
345 * sal: is_extra_light
346 * CVT: std_width
349 unsigned char FPGM(bci_compute_stem_width_a) [] = {
351 PUSHB_1,
352 bci_compute_stem_width,
353 FDEF,
355 DUP,
356 ABS, /* s: base_is_round stem_is_serif width dist */
358 DUP,
359 PUSHB_1,
360 3*64,
361 LT, /* dist < 3*64 */
363 PUSHB_1,
365 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
366 AND, /* stem_is_serif && dist < 3*64 */
368 PUSHB_1,
369 sal_is_extra_light,
371 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
373 IF, /* s: base_is_round width dist */
374 POP,
375 SWAP,
376 POP, /* s: width */
378 ELSE,
379 ROLL, /* s: width dist base_is_round */
380 IF, /* s: width dist */
381 DUP,
382 PUSHB_1,
384 LT, /* dist < 80 */
385 IF, /* s: width dist */
386 POP,
387 PUSHB_1,
388 64, /* dist = 64 */
389 EIF,
391 ELSE,
392 PUSHB_1,
394 MIN, /* dist = min(56, dist) */
395 EIF,
397 DUP, /* s: width dist dist */
398 PUSHB_1,
402 /* %c, index of std_width */
404 unsigned char FPGM(bci_compute_stem_width_b) [] = {
406 RCVT,
407 SUB,
408 ABS, /* s: width dist delta */
410 PUSHB_1,
412 LT, /* delta < 40 */
413 IF, /* s: width dist */
414 POP,
415 PUSHB_2,
420 /* %c, index of std_width */
422 unsigned char FPGM(bci_compute_stem_width_c) [] = {
424 RCVT,
425 MIN, /* dist = min(48, std_width) */
427 ELSE,
428 DUP, /* s: width dist dist */
429 PUSHB_1,
430 3*64,
431 LT, /* dist < 3*64 */
433 DUP, /* s: width delta dist */
434 FLOOR, /* dist = FLOOR(dist) */
435 DUP, /* s: width delta dist dist */
436 ROLL,
437 ROLL, /* s: width dist delta dist */
438 SUB, /* delta = delta - dist */
440 DUP, /* s: width dist delta delta */
441 PUSHB_1,
443 LT, /* delta < 10 */
444 IF, /* s: width dist delta */
445 ADD, /* dist = dist + delta */
447 ELSE,
448 DUP,
449 PUSHB_1,
451 LT, /* delta < 32 */
453 POP,
454 PUSHB_1,
456 ADD, /* dist = dist + 10 */
458 ELSE,
459 DUP,
460 PUSHB_1,
462 LT, /* delta < 54 */
464 POP,
465 PUSHB_1,
467 ADD, /* dist = dist + 54 */
469 ELSE,
470 ADD, /* dist = dist + delta */
472 EIF,
473 EIF,
474 EIF,
476 ELSE,
477 PUSHB_1,
479 ADD,
480 FLOOR, /* dist = round(dist) */
482 EIF,
483 EIF,
485 SWAP, /* s: dist width */
486 PUSHB_1,
488 LT, /* width < 0 */
490 NEG, /* dist = -dist */
491 EIF,
492 EIF,
493 EIF,
495 ENDF,
501 * bci_loop
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
505 * stack.
507 * in: func_num
508 * end
509 * start
511 * uses: sal_counter (counter initialized with `start')
512 * sal_limit (`end')
515 unsigned char FPGM(bci_loop) [] = {
517 PUSHB_1,
518 bci_loop,
519 FDEF,
521 ROLL,
522 ROLL, /* s: func_num start end */
523 PUSHB_1,
524 sal_limit,
525 SWAP,
528 PUSHB_1,
529 sal_counter,
530 SWAP,
533 /* start_loop: */
534 PUSHB_1,
535 sal_counter,
537 PUSHB_1,
538 sal_limit,
540 LTEQ, /* start <= end */
541 IF, /* s: func_num */
542 DUP,
543 CALL,
544 PUSHB_2,
546 sal_counter,
548 ADD, /* start = start + 1 */
549 PUSHB_1,
550 sal_counter,
551 SWAP,
554 PUSHB_1,
556 NEG,
557 JMPR, /* goto start_loop */
558 ELSE,
559 POP,
560 EIF,
562 ENDF,
568 * bci_cvt_rescale
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) [] = {
578 PUSHB_1,
579 bci_cvt_rescale,
580 FDEF,
582 PUSHB_1,
583 sal_counter,
585 DUP,
586 RCVT,
587 PUSHB_1,
588 sal_scale,
590 MUL, /* CVT * scale * 2^10 */
591 PUSHB_1,
592 sal_0x10000,
594 DIV, /* CVT * scale */
596 WCVTP,
598 ENDF,
604 * bci_loop_sal_assign
606 * Apply the WS instruction repeatedly to stack data.
608 * in: counter (N)
609 * offset
610 * data_0
611 * data_1
612 * ...
613 * data_(N-1)
615 * uses: bci_sal_assign
618 unsigned char FPGM(bci_sal_assign) [] = {
620 PUSHB_1,
621 bci_sal_assign,
622 FDEF,
624 DUP,
625 ROLL, /* s: offset offset data */
628 PUSHB_1,
630 ADD, /* s: (offset + 1) */
632 ENDF,
636 unsigned char FPGM(bci_loop_sal_assign) [] = {
638 PUSHB_1,
639 bci_loop_sal_assign,
640 FDEF,
642 /* process the stack, popping off the elements in a loop */
643 PUSHB_1,
644 bci_sal_assign,
645 LOOPCALL,
647 /* clean up stack */
648 POP,
650 ENDF,
656 * bci_blue_round
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) [] = {
666 PUSHB_1,
667 bci_blue_round,
668 FDEF,
670 PUSHB_1,
671 sal_counter,
673 DUP,
674 RCVT, /* s: ref_idx ref */
676 DUP,
677 PUSHB_1,
679 ADD,
680 FLOOR,
681 SWAP, /* s: ref_idx round(ref) ref */
683 PUSHB_2,
687 /* %c, blue_count */
689 unsigned char FPGM(bci_blue_round_b) [] = {
692 CINDEX,
693 ADD, /* s: ref_idx round(ref) ref shoot_idx */
694 DUP,
695 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
697 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
698 SWAP,
699 SUB, /* s: ref_idx round(ref) shoot_idx dist */
700 DUP,
701 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
703 DUP,
704 PUSHB_1,
706 LT, /* delta < 32 */
708 POP,
709 PUSHB_1,
710 0, /* delta = 0 */
712 ELSE,
713 PUSHB_1,
715 LT, /* delta < 48 */
717 PUSHB_1,
718 32, /* delta = 32 */
720 ELSE,
721 PUSHB_1,
722 64, /* delta = 64 */
723 EIF,
724 EIF,
726 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
727 PUSHB_1,
729 LT, /* dist < 0 */
731 NEG, /* delta = -delta */
732 EIF,
734 PUSHB_1,
736 CINDEX,
737 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
739 WCVTP,
740 WCVTP,
742 ENDF,
748 * bci_hint_glyph
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
755 * .is_serif
756 * .is_round
757 * .num_remaining_segments (N)
758 * .remaining_segments_0
759 * _1
760 * ...
761 * _(N-1)
762 * _1
763 * ...
764 * _(M-1)
766 * num_edges2links (P)
767 * edge2link_0.first_segment
768 * .num_remaining_segments (Q)
769 * .remaining_segments_0
770 * _1
771 * ...
772 * _(Q-1)
773 * _1
774 * ...
775 * _(P-1)
777 * uses: bci_edge2blue
778 * bci_edge2link
781 unsigned char FPGM(bci_remaining_edges) [] = {
783 PUSHB_1,
784 bci_remaining_edges,
785 FDEF,
787 POP, /* XXX remaining segment */
789 ENDF,
793 unsigned char FPGM(bci_edge2blue) [] = {
795 PUSHB_1,
796 bci_edge2blue,
797 FDEF,
799 POP, /* XXX first_segment */
800 POP, /* XXX is_serif */
801 POP, /* XXX is_round */
802 PUSHB_1,
803 bci_remaining_edges,
804 LOOPCALL,
806 ENDF,
810 unsigned char FPGM(bci_edge2link) [] = {
812 PUSHB_1,
813 bci_edge2link,
814 FDEF,
816 POP, /* XXX first_segment */
817 PUSHB_1,
818 bci_remaining_edges,
819 LOOPCALL,
821 ENDF,
825 unsigned char FPGM(bci_hint_glyph) [] = {
827 PUSHB_1,
828 bci_hint_glyph,
829 FDEF,
831 PUSHB_1,
832 bci_edge2blue,
833 LOOPCALL,
835 PUSHB_1,
836 bci_edge2link,
837 LOOPCALL,
839 ENDF,
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) \
849 static FT_Error
850 TA_table_build_fpgm(FT_Byte** fpgm,
851 FT_ULong* fpgm_len,
852 FONT* font)
854 FT_UInt buf_len;
855 FT_UInt len;
856 FT_Byte* buf;
857 FT_Byte* buf_p;
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);
879 if (!buf)
880 return FT_Err_Out_Of_Memory;
882 /* pad end of buffer with zeros */
883 buf[len - 1] = 0x00;
884 buf[len - 2] = 0x00;
885 buf[len - 3] = 0x00;
887 /* copy font program into buffer and fill in the missing variables */
888 buf_p = buf;
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);
895 COPY_FPGM(bci_loop);
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);
907 *fpgm = buf;
908 *fpgm_len = buf_len;
910 return FT_Err_Ok;
914 FT_Error
915 TA_sfnt_build_fpgm_table(SFNT* sfnt,
916 FONT* font)
918 FT_Error error;
920 FT_Byte* fpgm_buf;
921 FT_ULong fpgm_len;
924 error = TA_sfnt_add_table_info(sfnt);
925 if (error)
926 return error;
928 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
929 if (error)
930 return error;
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);
937 if (error)
939 free(fpgm_buf);
940 return error;
943 return FT_Err_Ok;
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) [] = {
956 PUSHB_1,
957 sal_0x10000,
958 PUSHW_2,
959 0x08, /* 0x800 */
960 0x00,
961 0x08, /* 0x800 */
962 0x00,
963 MUL, /* 0x10000 */
968 unsigned char PREP(align_top_a) [] = {
970 /* optimize the alignment of the top of small letters to the pixel grid */
972 PUSHB_1,
976 /* %c, index of alignment blue zone */
978 unsigned char PREP(align_top_b) [] = {
980 RCVT,
981 DUP,
982 DUP,
983 PUSHB_1,
985 ADD,
986 FLOOR, /* fitted = FLOOR(scaled + 40) */
987 DUP, /* s: scaled scaled fitted fitted */
988 ROLL,
989 NEQ,
990 IF, /* s: scaled fitted */
991 PUSHB_1,
992 sal_0x10000,
994 MUL, /* scaled in 16.16 format */
995 SWAP,
996 DIV, /* (fitted / scaled) in 16.16 format */
998 PUSHB_1,
999 sal_scale,
1000 SWAP,
1005 unsigned char PREP(loop_cvt_a) [] = {
1007 /* loop over vertical CVT entries */
1008 PUSHB_4,
1012 /* %c, first vertical index */
1013 /* %c, last vertical index */
1015 unsigned char PREP(loop_cvt_b) [] = {
1017 bci_cvt_rescale,
1018 bci_loop,
1019 CALL,
1021 /* loop over blue refs */
1022 PUSHB_4,
1026 /* %c, first blue ref index */
1027 /* %c, last blue ref index */
1029 unsigned char PREP(loop_cvt_c) [] = {
1031 bci_cvt_rescale,
1032 bci_loop,
1033 CALL,
1035 /* loop over blue shoots */
1036 PUSHB_4,
1040 /* %c, first blue shoot index */
1041 /* %c, last blue shoot index */
1043 unsigned char PREP(loop_cvt_d) [] = {
1045 bci_cvt_rescale,
1046 bci_loop,
1047 CALL,
1048 EIF,
1052 unsigned char PREP(compute_extra_light_a) [] = {
1054 /* compute (vertical) `extra_light' flag */
1055 PUSHB_3,
1056 sal_is_extra_light,
1061 /* %c, index of vertical standard_width */
1063 unsigned char PREP(compute_extra_light_b) [] = {
1065 RCVT,
1066 GT, /* standard_width < 40 */
1071 unsigned char PREP(round_blues_a) [] = {
1073 /* use discrete values for blue zone widths */
1074 PUSHB_4,
1078 /* %c, first blue ref index */
1079 /* %c, last blue ref index */
1081 unsigned char PREP(round_blues_b) [] = {
1083 bci_blue_round,
1084 bci_loop,
1085 CALL
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);
1100 static FT_Error
1101 TA_table_build_prep(FT_Byte** prep,
1102 FT_ULong* prep_len,
1103 FONT* font)
1105 TA_LatinAxis vaxis;
1106 TA_LatinBlue blue_adjustment;
1107 FT_UInt i;
1109 FT_UInt buf_len;
1110 FT_UInt len;
1111 FT_Byte* buf;
1112 FT_Byte* buf_p;
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];
1123 break;
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);
1153 if (!buf)
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 */
1162 buf_p = buf;
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);
1201 *prep = buf;
1202 *prep_len = buf_len;
1204 return FT_Err_Ok;
1208 FT_Error
1209 TA_sfnt_build_prep_table(SFNT* sfnt,
1210 FONT* font)
1212 FT_Error error;
1214 FT_Byte* prep_buf;
1215 FT_ULong prep_len;
1218 error = TA_sfnt_add_table_info(sfnt);
1219 if (error)
1220 return error;
1222 error = TA_table_build_prep(&prep_buf, &prep_len, font);
1223 if (error)
1224 return error;
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);
1231 if (error)
1233 free(prep_buf);
1234 return error;
1237 return FT_Err_Ok;
1241 /* we store the segments in the storage area; */
1242 /* each segment record consists of the first and last point */
1244 static FT_Byte*
1245 TA_sfnt_build_glyph_segments(SFNT* sfnt,
1246 FONT* font,
1247 FT_Byte* bufp)
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;
1253 TA_Segment seg;
1254 TA_Segment seg_limit;
1256 FT_UInt* args;
1257 FT_UInt* arg;
1258 FT_UInt num_args;
1259 FT_UInt nargs;
1261 FT_Bool need_words = 0;
1263 FT_UInt i, j;
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));
1275 if (!args)
1276 return NULL;
1278 arg = args + num_args - 1;
1280 if (axis->num_segments > 0xFF)
1281 need_words = 1;
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;
1293 *(arg--) = first;
1294 *(arg--) = last;
1296 if (first > 0xFF || last > 0xFF)
1297 need_words = 1;
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 */
1304 arg = args;
1306 if (need_words)
1308 for (i = 0; i < num_args; i += 255)
1310 nargs = (num_args - i > 255) ? 255 : num_args - i;
1312 BCI(NPUSHW);
1313 BCI(nargs);
1314 for (j = 0; j < nargs; j++)
1316 BCI(HIGH(*arg));
1317 BCI(LOW(*arg));
1318 arg++;
1322 else
1324 for (i = 0; i < num_args; i += 255)
1326 nargs = (num_args - i > 255) ? 255 : num_args - i;
1328 BCI(NPUSHB);
1329 BCI(nargs);
1330 for (j = 0; j < nargs; j++)
1332 BCI(*arg);
1333 arg++;
1338 BCI(CALL);
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;
1348 free(args);
1350 return bufp;
1354 static void
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;
1361 TA_Edge edge;
1364 for (edge = edges; edge < edge_limit; edge++)
1365 edge->flags &= ~TA_EDGE_DONE;
1369 static FT_Error
1370 TA_construct_hinting_set(FONT* font,
1371 FT_UInt size,
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;
1379 TA_Edge edge;
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++;
1398 else
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++)
1432 TA_Segment seg;
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;
1479 edge2blue++;
1481 else
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;
1522 edge2link++;
1526 return FT_Err_Ok;
1530 static FT_Bool
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;
1542 FT_UInt i;
1545 if (!hinting_sets)
1546 return 1;
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)
1553 return 1;
1555 edge2blue = hinting_set.edges2blues;
1556 last_edge2blue = last_hinting_set.edges2blues;
1558 for (i = 0;
1559 i < hinting_set.num_edges2blues;
1560 i++, edge2blue++, last_edge2blue++)
1562 if (edge2blue->num_remaining_segments
1563 != last_edge2blue->num_remaining_segments)
1564 return 1;
1566 if (edge2blue->remaining_segments)
1568 if (memcmp(edge2blue->remaining_segments,
1569 last_edge2blue->remaining_segments,
1570 sizeof (FT_UInt) * edge2blue->num_remaining_segments))
1571 return 1;
1575 if (hinting_set.num_edges2links
1576 != last_hinting_set.num_edges2links)
1577 return 1;
1579 edge2link = hinting_set.edges2links;
1580 last_edge2link = last_hinting_set.edges2links;
1582 for (i = 0;
1583 i < hinting_set.num_edges2links;
1584 i++, edge2link++, last_edge2link++)
1586 if (edge2link->num_remaining_segments
1587 != last_edge2link->num_remaining_segments)
1588 return 1;
1590 if (edge2link->remaining_segments)
1592 if (memcmp(edge2link->remaining_segments,
1593 last_edge2link->remaining_segments,
1594 sizeof (FT_UInt) * edge2link->num_remaining_segments))
1595 return 1;
1599 return 0;
1603 static FT_Error
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)++;
1612 hinting_sets_new =
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;
1620 else
1621 *hinting_sets = hinting_sets_new;
1623 (*hinting_sets)[*num_hinting_sets - 1] = hinting_set;
1625 return FT_Err_Ok;
1629 static FT_Byte*
1630 TA_sfnt_emit_hinting_set(SFNT* sfnt,
1631 Hinting_Set* hinting_set,
1632 FT_Byte* bufp)
1634 FT_UInt* args;
1635 FT_UInt* arg;
1637 Edge2Blue* edge2blue;
1638 Edge2Blue* edge2blue_limit;
1639 Edge2Link* edge2link;
1640 Edge2Link* edge2link_limit;
1642 FT_UInt* seg;
1643 FT_UInt* seg_limit;
1645 FT_UInt i, j;
1646 FT_UInt num_args;
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));
1654 if (!args)
1655 return NULL;
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;
1665 edge2blue++)
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++)
1675 *(arg--) = *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;
1684 edge2link++)
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++)
1692 *(arg--) = *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 */
1699 arg = args;
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)
1706 ? 255
1707 : hinting_set->num_args - i;
1709 BCI(NPUSHW);
1710 BCI(num_args);
1711 for (j = 0; j < num_args; j++)
1713 BCI(HIGH(*arg));
1714 BCI(LOW(*arg));
1715 arg++;
1719 else
1721 for (i = 0; i < hinting_set->num_args; i += 255)
1723 num_args = (hinting_set->num_args - i > 255)
1724 ? 255
1725 : hinting_set->num_args - i;
1727 BCI(NPUSHB);
1728 BCI(num_args);
1729 for (j = 0; j < num_args; j++)
1731 BCI(*arg);
1732 arg++;
1737 free(args);
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;
1743 return bufp;
1747 static FT_Byte*
1748 TA_sfnt_emit_hinting_sets(SFNT* sfnt,
1749 Hinting_Set* hinting_sets,
1750 FT_UInt num_hinting_sets,
1751 FT_Byte* bufp)
1753 FT_UInt i;
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' */
1763 BCI(SVTCA_y);
1765 for (i = 0; i < num_hinting_sets - 1; i++)
1767 BCI(MPPEM);
1768 if (hinting_set->size > 0xFF)
1770 BCI(PUSHW_1);
1771 BCI(HIGH((hinting_set + 1)->size));
1772 BCI(LOW((hinting_set + 1)->size));
1774 else
1776 BCI(PUSHB_1);
1777 BCI((hinting_set + 1)->size);
1779 BCI(LT);
1780 BCI(IF);
1781 bufp = TA_sfnt_emit_hinting_set(sfnt, hinting_set, bufp);
1782 if (!bufp)
1783 return NULL;
1784 BCI(ELSE);
1786 hinting_set++;
1789 bufp = TA_sfnt_emit_hinting_set(sfnt, hinting_set, bufp);
1790 if (!bufp)
1791 return NULL;
1793 for (i = 0; i < num_hinting_sets - 1; i++)
1794 BCI(EIF);
1796 BCI(PUSHB_1);
1797 BCI(bci_hint_glyph);
1798 BCI(CALL);
1800 return bufp;
1804 static void
1805 TA_free_hinting_set(Hinting_Set hinting_set)
1807 FT_UInt i;
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);
1820 static void
1821 TA_free_hinting_sets(Hinting_Set* hinting_sets,
1822 FT_UInt num_hinting_sets)
1824 FT_UInt i;
1827 for (i = 0; i < num_hinting_sets; i++)
1828 TA_free_hinting_set(hinting_sets[i]);
1830 free(hinting_sets);
1834 static FT_Error
1835 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1836 FONT* font,
1837 FT_Long idx)
1839 FT_Face face = sfnt->face;
1840 FT_Error error;
1842 FT_Byte* ins_buf;
1843 FT_UInt ins_len;
1844 FT_Byte* bufp;
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;
1855 FT_UInt size;
1858 if (idx < 0)
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);
1864 if (error)
1865 return error;
1867 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
1868 if (error)
1869 return error;
1871 /* do nothing if we have an empty glyph */
1872 if (!face->glyph->outline.n_contours)
1873 return FT_Err_Ok;
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);
1882 if (!ins_buf)
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;
1896 #if 0
1897 printf("glyph %ld\n", idx);
1898 #endif
1900 for (size = 8; size <= 1000; size++)
1902 Hinting_Set hinting_set;
1905 error = FT_Set_Pixel_Sizes(face, size, size);
1906 if (error)
1907 goto Err;
1909 error = ta_loader_load_glyph(font->loader, face, idx, 0);
1910 if (error)
1911 goto Err;
1913 TA_font_clear_edge_DONE_flag(font);
1915 error = TA_construct_hinting_set(font, size, &hinting_set);
1916 if (error)
1917 goto Err;
1919 if (TA_hinting_set_is_different(hinting_sets,
1920 num_hinting_sets,
1921 hinting_set))
1923 #if 0
1924 if (num_hinting_sets > 0)
1925 printf(" additional hinting set for size %d\n", size);
1926 #endif
1928 error = TA_add_hinting_set(&hinting_sets,
1929 &num_hinting_sets,
1930 hinting_set);
1931 if (error)
1933 TA_free_hinting_set(hinting_set);
1934 goto Err;
1937 else
1938 TA_free_hinting_set(hinting_set);
1941 bufp = TA_sfnt_emit_hinting_sets(sfnt,
1942 hinting_sets, num_hinting_sets, bufp);
1943 if (!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);
1958 return FT_Err_Ok;
1960 Err:
1961 TA_free_hinting_sets(hinting_sets, num_hinting_sets);
1962 free(ins_buf);
1964 return error;
1968 FT_Error
1969 TA_sfnt_build_glyf_hints(SFNT* sfnt,
1970 FONT* font)
1972 FT_Face face = sfnt->face;
1973 FT_Long idx;
1974 FT_Error error;
1977 for (idx = 0; idx < face->num_glyphs; idx++)
1979 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
1980 if (error)
1981 return error;
1984 return FT_Err_Ok;
1987 /* end of tabytecode.c */