Pass blue zone index to BLUE action.
[ttfautohint.git] / src / tabytecode.c
blob613966f833bd594b7075b1a29eecf9937d1e1d4a
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 typedef struct Hints_Record_ {
26 FT_UInt size;
27 FT_UInt num_actions;
28 FT_Byte* buf;
29 FT_UInt buf_len;
30 } Hints_Record;
32 typedef struct Recorder_ {
33 FONT* font;
34 Hints_Record hints_record;
35 } Recorder;
38 static FT_Error
39 TA_sfnt_compute_global_hints(SFNT* sfnt,
40 FONT* font)
42 FT_Error error;
43 FT_Face face = sfnt->face;
44 FT_UInt enc;
45 FT_UInt idx;
47 static const FT_Encoding latin_encs[] =
49 FT_ENCODING_UNICODE,
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);
59 if (error)
60 return error;
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]);
66 if (!error)
67 break;
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);
74 return error;
78 static FT_Error
79 TA_table_build_cvt(FT_Byte** cvt,
80 FT_ULong* cvt_len,
81 SFNT* sfnt,
82 FONT* font)
84 TA_LatinAxis haxis;
85 TA_LatinAxis vaxis;
87 FT_UInt i;
88 FT_UInt buf_len;
89 FT_UInt len;
90 FT_Byte* buf;
91 FT_Byte* buf_p;
93 FT_Error error;
96 error = TA_sfnt_compute_global_hints(sfnt, font);
97 if (error)
98 return error;
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];
104 buf_len = 2 * (2
105 + haxis->width_count
106 + vaxis->width_count
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);
112 if (!buf)
113 return FT_Err_Out_Of_Memory;
115 /* pad end of buffer with zeros */
116 buf[len - 1] = 0x00;
117 buf[len - 2] = 0x00;
118 buf[len - 3] = 0x00;
120 buf_p = buf;
122 if (haxis->width_count > 0)
124 *(buf_p++) = HIGH(haxis->widths[0].org);
125 *(buf_p++) = LOW(haxis->widths[0].org);
127 else
129 *(buf_p++) = 0;
130 *(buf_p++) = 50;
132 if (vaxis->width_count > 0)
134 *(buf_p++) = HIGH(vaxis->widths[0].org);
135 *(buf_p++) = LOW(vaxis->widths[0].org);
137 else
139 *(buf_p++) = 0;
140 *(buf_p++) = 50;
143 for (i = 0; i < haxis->width_count; i++)
145 if (haxis->widths[i].org > 0xFFFF)
146 goto Err;
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)
154 goto Err;
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)
162 goto Err;
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)
170 goto Err;
171 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
172 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
175 #if 0
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);
181 #endif
183 *cvt = buf;
184 *cvt_len = buf_len;
186 return FT_Err_Ok;
188 Err:
189 free(buf);
190 return TA_Err_Hinter_Overflow;
194 FT_Error
195 TA_sfnt_build_cvt_table(SFNT* sfnt,
196 FONT* font)
198 FT_Error error;
200 FT_Byte* cvt_buf;
201 FT_ULong cvt_len;
204 error = TA_sfnt_add_table_info(sfnt);
205 if (error)
206 return error;
208 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
209 if (error)
210 return error;
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);
217 if (error)
219 free(cvt_buf);
220 return error;
223 return FT_Err_Ok;
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':
282 * dist = ABS(width)
284 * if (stem_is_serif
285 * && dist < 3*64)
286 * || is_extra_light:
287 * return width
288 * else if base_is_round:
289 * if dist < 80
290 * dist = 64
291 * else:
292 * dist = MIN(56, dist)
294 * delta = ABS(dist - std_width)
296 * if delta < 40:
297 * dist = MIN(48, std_width)
298 * goto End
300 * if dist < 3*64:
301 * delta = dist
302 * dist = FLOOR(dist)
303 * delta = delta - dist
305 * if delta < 10:
306 * dist = dist + delta
307 * else if delta < 32:
308 * dist = dist + 10
309 * else if delta < 54:
310 * dist = dist + 54
311 * else
312 * dist = dist + delta
313 * else
314 * dist = ROUND(dist)
316 * End:
317 * if width < 0:
318 * dist = -dist
319 * return dist
322 * in: width
323 * stem_is_serif
324 * base_is_round
325 * out: new_width
326 * sal: is_extra_light
327 * CVT: std_width
330 unsigned char FPGM(bci_compute_stem_width_a) [] = {
332 PUSHB_1,
333 bci_compute_stem_width,
334 FDEF,
336 DUP,
337 ABS, /* s: base_is_round stem_is_serif width dist */
339 DUP,
340 PUSHB_1,
341 3*64,
342 LT, /* dist < 3*64 */
344 PUSHB_1,
346 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
347 AND, /* stem_is_serif && dist < 3*64 */
349 PUSHB_1,
350 sal_is_extra_light,
352 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
354 IF, /* s: base_is_round width dist */
355 POP,
356 SWAP,
357 POP, /* s: width */
359 ELSE,
360 ROLL, /* s: width dist base_is_round */
361 IF, /* s: width dist */
362 DUP,
363 PUSHB_1,
365 LT, /* dist < 80 */
366 IF, /* s: width dist */
367 POP,
368 PUSHB_1,
369 64, /* dist = 64 */
370 EIF,
372 ELSE,
373 PUSHB_1,
375 MIN, /* dist = min(56, dist) */
376 EIF,
378 DUP, /* s: width dist dist */
379 PUSHB_1,
383 /* %c, index of std_width */
385 unsigned char FPGM(bci_compute_stem_width_b) [] = {
387 RCVT,
388 SUB,
389 ABS, /* s: width dist delta */
391 PUSHB_1,
393 LT, /* delta < 40 */
394 IF, /* s: width dist */
395 POP,
396 PUSHB_2,
401 /* %c, index of std_width */
403 unsigned char FPGM(bci_compute_stem_width_c) [] = {
405 RCVT,
406 MIN, /* dist = min(48, std_width) */
408 ELSE,
409 DUP, /* s: width dist dist */
410 PUSHB_1,
411 3*64,
412 LT, /* dist < 3*64 */
414 DUP, /* s: width delta dist */
415 FLOOR, /* dist = FLOOR(dist) */
416 DUP, /* s: width delta dist dist */
417 ROLL,
418 ROLL, /* s: width dist delta dist */
419 SUB, /* delta = delta - dist */
421 DUP, /* s: width dist delta delta */
422 PUSHB_1,
424 LT, /* delta < 10 */
425 IF, /* s: width dist delta */
426 ADD, /* dist = dist + delta */
428 ELSE,
429 DUP,
430 PUSHB_1,
432 LT, /* delta < 32 */
434 POP,
435 PUSHB_1,
437 ADD, /* dist = dist + 10 */
439 ELSE,
440 DUP,
441 PUSHB_1,
443 LT, /* delta < 54 */
445 POP,
446 PUSHB_1,
448 ADD, /* dist = dist + 54 */
450 ELSE,
451 ADD, /* dist = dist + delta */
453 EIF,
454 EIF,
455 EIF,
457 ELSE,
458 PUSHB_1,
460 ADD,
461 FLOOR, /* dist = round(dist) */
463 EIF,
464 EIF,
466 SWAP, /* s: dist width */
467 PUSHB_1,
469 LT, /* width < 0 */
471 NEG, /* dist = -dist */
472 EIF,
473 EIF,
474 EIF,
476 ENDF,
482 * bci_loop
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
486 * stack.
488 * in: func_num
489 * end
490 * start
492 * uses: sal_counter (counter initialized with `start')
493 * sal_limit (`end')
496 unsigned char FPGM(bci_loop) [] = {
498 PUSHB_1,
499 bci_loop,
500 FDEF,
502 ROLL,
503 ROLL, /* s: func_num start end */
504 PUSHB_1,
505 sal_limit,
506 SWAP,
509 PUSHB_1,
510 sal_counter,
511 SWAP,
514 /* start_loop: */
515 PUSHB_1,
516 sal_counter,
518 PUSHB_1,
519 sal_limit,
521 LTEQ, /* start <= end */
522 IF, /* s: func_num */
523 DUP,
524 CALL,
525 PUSHB_2,
527 sal_counter,
529 ADD, /* start = start + 1 */
530 PUSHB_1,
531 sal_counter,
532 SWAP,
535 PUSHB_1,
537 NEG,
538 JMPR, /* goto start_loop */
539 ELSE,
540 POP,
541 EIF,
543 ENDF,
549 * bci_cvt_rescale
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) [] = {
559 PUSHB_1,
560 bci_cvt_rescale,
561 FDEF,
563 PUSHB_1,
564 sal_counter,
566 DUP,
567 RCVT,
568 PUSHB_1,
569 sal_scale,
571 MUL, /* CVT * scale * 2^10 */
572 PUSHB_1,
573 sal_0x10000,
575 DIV, /* CVT * scale */
577 WCVTP,
579 ENDF,
585 * bci_loop_sal_assign
587 * Apply the WS instruction repeatedly to stack data.
589 * in: counter (N)
590 * offset
591 * data_0
592 * data_1
593 * ...
594 * data_(N-1)
596 * uses: bci_sal_assign
599 unsigned char FPGM(bci_sal_assign) [] = {
601 PUSHB_1,
602 bci_sal_assign,
603 FDEF,
605 DUP,
606 ROLL, /* s: offset offset data */
609 PUSHB_1,
611 ADD, /* s: (offset + 1) */
613 ENDF,
617 unsigned char FPGM(bci_loop_sal_assign) [] = {
619 PUSHB_1,
620 bci_loop_sal_assign,
621 FDEF,
623 /* process the stack, popping off the elements in a loop */
624 PUSHB_1,
625 bci_sal_assign,
626 LOOPCALL,
628 /* clean up stack */
629 POP,
631 ENDF,
637 * bci_blue_round
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) [] = {
647 PUSHB_1,
648 bci_blue_round,
649 FDEF,
651 PUSHB_1,
652 sal_counter,
654 DUP,
655 RCVT, /* s: ref_idx ref */
657 DUP,
658 PUSHB_1,
660 ADD,
661 FLOOR,
662 SWAP, /* s: ref_idx round(ref) ref */
664 PUSHB_2,
668 /* %c, blue_count */
670 unsigned char FPGM(bci_blue_round_b) [] = {
673 CINDEX,
674 ADD, /* s: ref_idx round(ref) ref shoot_idx */
675 DUP,
676 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
678 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
679 SWAP,
680 SUB, /* s: ref_idx round(ref) shoot_idx dist */
681 DUP,
682 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
684 DUP,
685 PUSHB_1,
687 LT, /* delta < 32 */
689 POP,
690 PUSHB_1,
691 0, /* delta = 0 */
693 ELSE,
694 PUSHB_1,
696 LT, /* delta < 48 */
698 PUSHB_1,
699 32, /* delta = 32 */
701 ELSE,
702 PUSHB_1,
703 64, /* delta = 64 */
704 EIF,
705 EIF,
707 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
708 PUSHB_1,
710 LT, /* dist < 0 */
712 NEG, /* delta = -delta */
713 EIF,
715 PUSHB_1,
717 CINDEX,
718 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
720 WCVTP,
721 WCVTP,
723 ENDF,
729 * bci_hint_glyph
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)
735 * action_0_func_idx
736 * ... data ...
737 * action_1_func_idx
738 * ... data ...
739 * ...
740 * action_M_func_idx
741 * ... data ...
743 * uses: bci_handle_action
744 * bci_action_adjust_bound
745 * bci_action_stem_bound
747 * bci_action_link
748 * bci_action_anchor
749 * bci_action_adjust
750 * bci_action_stem
752 * bci_action_blue
753 * bci_action_serif
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
759 * times.
762 unsigned char FPGM(bci_handle_remaining_segment) [] = {
764 PUSHB_1,
765 bci_handle_remaining_segment,
766 FDEF,
768 POP, /* XXX remaining segment */
770 ENDF,
774 unsigned char FPGM(bci_handle_segments) [] = {
776 PUSHB_1,
777 bci_handle_segments,
778 FDEF,
780 POP, /* XXX first segment */
781 POP, /* XXX is_serif */
782 POP, /* XXX is_round */
784 PUSHB_1,
785 bci_handle_remaining_segment,
786 LOOPCALL,
788 ENDF,
792 unsigned char FPGM(bci_action_adjust_bound) [] = {
794 PUSHB_1,
795 bci_action_adjust_bound,
796 FDEF,
798 PUSHB_1,
799 bci_handle_segments,
800 CALL,
801 PUSHB_1,
802 bci_handle_segments,
803 CALL,
804 PUSHB_1,
805 bci_handle_segments,
806 CALL,
808 /* XXX */
810 ENDF,
814 unsigned char FPGM(bci_action_stem_bound) [] = {
816 PUSHB_1,
817 bci_action_stem_bound,
818 FDEF,
820 PUSHB_1,
821 bci_handle_segments,
822 CALL,
823 PUSHB_1,
824 bci_handle_segments,
825 CALL,
826 PUSHB_1,
827 bci_handle_segments,
828 CALL,
830 /* XXX */
832 ENDF,
836 unsigned char FPGM(bci_action_link) [] = {
838 PUSHB_1,
839 bci_action_link,
840 FDEF,
842 PUSHB_1,
843 bci_handle_segments,
844 CALL,
845 PUSHB_1,
846 bci_handle_segments,
847 CALL,
849 /* XXX */
851 ENDF,
855 unsigned char FPGM(bci_action_anchor) [] = {
857 PUSHB_1,
858 bci_action_anchor,
859 FDEF,
861 PUSHB_1,
862 bci_handle_segments,
863 CALL,
864 PUSHB_1,
865 bci_handle_segments,
866 CALL,
868 /* XXX */
870 ENDF,
874 unsigned char FPGM(bci_action_adjust) [] = {
876 PUSHB_1,
877 bci_action_adjust,
878 FDEF,
880 PUSHB_1,
881 bci_handle_segments,
882 CALL,
883 PUSHB_1,
884 bci_handle_segments,
885 CALL,
887 /* XXX */
889 ENDF,
893 unsigned char FPGM(bci_action_stem) [] = {
895 PUSHB_1,
896 bci_action_stem,
897 FDEF,
899 PUSHB_1,
900 bci_handle_segments,
901 CALL,
902 PUSHB_1,
903 bci_handle_segments,
904 CALL,
906 /* XXX */
908 ENDF,
912 unsigned char FPGM(bci_action_blue) [] = {
914 PUSHB_1,
915 bci_action_blue,
916 FDEF,
918 POP, /* XXX blue */
920 PUSHB_1,
921 bci_handle_segments,
922 CALL,
924 /* XXX */
926 ENDF,
930 unsigned char FPGM(bci_action_serif) [] = {
932 PUSHB_1,
933 bci_action_serif,
934 FDEF,
936 PUSHB_1,
937 bci_handle_segments,
938 CALL,
940 /* XXX */
942 ENDF,
946 unsigned char FPGM(bci_action_serif_anchor) [] = {
948 PUSHB_1,
949 bci_action_serif_anchor,
950 FDEF,
952 PUSHB_1,
953 bci_handle_segments,
954 CALL,
956 /* XXX */
958 ENDF,
962 unsigned char FPGM(bci_action_link1) [] = {
964 PUSHB_1,
965 bci_action_link1,
966 FDEF,
968 PUSHB_1,
969 bci_handle_segments,
970 CALL,
972 /* XXX */
974 ENDF,
978 unsigned char FPGM(bci_action_link2) [] = {
980 PUSHB_1,
981 bci_action_link2,
982 FDEF,
984 PUSHB_1,
985 bci_handle_segments,
986 CALL,
988 /* XXX */
990 ENDF,
994 unsigned char FPGM(bci_handle_action) [] = {
996 PUSHB_1,
997 bci_handle_action,
998 FDEF,
1000 CALL,
1002 ENDF,
1006 unsigned char FPGM(bci_hint_glyph) [] = {
1008 PUSHB_1,
1009 bci_hint_glyph,
1010 FDEF,
1012 PUSHB_1,
1013 bci_handle_action,
1014 LOOPCALL,
1016 ENDF,
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) \
1026 static FT_Error
1027 TA_table_build_fpgm(FT_Byte** fpgm,
1028 FT_ULong* fpgm_len,
1029 FONT* font)
1031 FT_UInt buf_len;
1032 FT_UInt len;
1033 FT_Byte* buf;
1034 FT_Byte* buf_p;
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);
1067 if (!buf)
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 */
1076 buf_p = buf;
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);
1106 *fpgm = buf;
1107 *fpgm_len = buf_len;
1109 return FT_Err_Ok;
1113 FT_Error
1114 TA_sfnt_build_fpgm_table(SFNT* sfnt,
1115 FONT* font)
1117 FT_Error error;
1119 FT_Byte* fpgm_buf;
1120 FT_ULong fpgm_len;
1123 error = TA_sfnt_add_table_info(sfnt);
1124 if (error)
1125 return error;
1127 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
1128 if (error)
1129 return error;
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);
1136 if (error)
1138 free(fpgm_buf);
1139 return error;
1142 return FT_Err_Ok;
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) [] = {
1155 PUSHB_1,
1156 sal_0x10000,
1157 PUSHW_2,
1158 0x08, /* 0x800 */
1159 0x00,
1160 0x08, /* 0x800 */
1161 0x00,
1162 MUL, /* 0x10000 */
1167 unsigned char PREP(align_top_a) [] = {
1169 /* optimize the alignment of the top of small letters to the pixel grid */
1171 PUSHB_1,
1175 /* %c, index of alignment blue zone */
1177 unsigned char PREP(align_top_b) [] = {
1179 RCVT,
1180 DUP,
1181 DUP,
1182 PUSHB_1,
1184 ADD,
1185 FLOOR, /* fitted = FLOOR(scaled + 40) */
1186 DUP, /* s: scaled scaled fitted fitted */
1187 ROLL,
1188 NEQ,
1189 IF, /* s: scaled fitted */
1190 PUSHB_1,
1191 sal_0x10000,
1193 MUL, /* scaled in 16.16 format */
1194 SWAP,
1195 DIV, /* (fitted / scaled) in 16.16 format */
1197 PUSHB_1,
1198 sal_scale,
1199 SWAP,
1204 unsigned char PREP(loop_cvt_a) [] = {
1206 /* loop over vertical CVT entries */
1207 PUSHB_4,
1211 /* %c, first vertical index */
1212 /* %c, last vertical index */
1214 unsigned char PREP(loop_cvt_b) [] = {
1216 bci_cvt_rescale,
1217 bci_loop,
1218 CALL,
1220 /* loop over blue refs */
1221 PUSHB_4,
1225 /* %c, first blue ref index */
1226 /* %c, last blue ref index */
1228 unsigned char PREP(loop_cvt_c) [] = {
1230 bci_cvt_rescale,
1231 bci_loop,
1232 CALL,
1234 /* loop over blue shoots */
1235 PUSHB_4,
1239 /* %c, first blue shoot index */
1240 /* %c, last blue shoot index */
1242 unsigned char PREP(loop_cvt_d) [] = {
1244 bci_cvt_rescale,
1245 bci_loop,
1246 CALL,
1247 EIF,
1251 unsigned char PREP(compute_extra_light_a) [] = {
1253 /* compute (vertical) `extra_light' flag */
1254 PUSHB_3,
1255 sal_is_extra_light,
1260 /* %c, index of vertical standard_width */
1262 unsigned char PREP(compute_extra_light_b) [] = {
1264 RCVT,
1265 GT, /* standard_width < 40 */
1270 unsigned char PREP(round_blues_a) [] = {
1272 /* use discrete values for blue zone widths */
1273 PUSHB_4,
1277 /* %c, first blue ref index */
1278 /* %c, last blue ref index */
1280 unsigned char PREP(round_blues_b) [] = {
1282 bci_blue_round,
1283 bci_loop,
1284 CALL
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);
1299 static FT_Error
1300 TA_table_build_prep(FT_Byte** prep,
1301 FT_ULong* prep_len,
1302 FONT* font)
1304 TA_LatinAxis vaxis;
1305 TA_LatinBlue blue_adjustment;
1306 FT_UInt i;
1308 FT_UInt buf_len;
1309 FT_UInt len;
1310 FT_Byte* buf;
1311 FT_Byte* buf_p;
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];
1322 break;
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);
1352 if (!buf)
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 */
1361 buf_p = buf;
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);
1400 *prep = buf;
1401 *prep_len = buf_len;
1403 return FT_Err_Ok;
1407 FT_Error
1408 TA_sfnt_build_prep_table(SFNT* sfnt,
1409 FONT* font)
1411 FT_Error error;
1413 FT_Byte* prep_buf;
1414 FT_ULong prep_len;
1417 error = TA_sfnt_add_table_info(sfnt);
1418 if (error)
1419 return error;
1421 error = TA_table_build_prep(&prep_buf, &prep_len, font);
1422 if (error)
1423 return error;
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);
1430 if (error)
1432 free(prep_buf);
1433 return error;
1436 return FT_Err_Ok;
1440 /* we store the segments in the storage area; */
1441 /* each segment record consists of the first and last point */
1443 static FT_Byte*
1444 TA_sfnt_build_glyph_segments(SFNT* sfnt,
1445 FONT* font,
1446 FT_Byte* bufp)
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;
1452 TA_Segment seg;
1453 TA_Segment seg_limit;
1455 FT_UInt* args;
1456 FT_UInt* arg;
1457 FT_UInt num_args;
1458 FT_UInt nargs;
1460 FT_Bool need_words = 0;
1462 FT_UInt i, j;
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));
1474 if (!args)
1475 return NULL;
1477 arg = args + num_args - 1;
1479 if (axis->num_segments > 0xFF)
1480 need_words = 1;
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;
1492 *(arg--) = first;
1493 *(arg--) = last;
1495 if (first > 0xFF || last > 0xFF)
1496 need_words = 1;
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 */
1503 arg = args;
1505 if (need_words)
1507 for (i = 0; i < num_args; i += 255)
1509 nargs = (num_args - i > 255) ? 255 : num_args - i;
1511 BCI(NPUSHW);
1512 BCI(nargs);
1513 for (j = 0; j < nargs; j++)
1515 BCI(HIGH(*arg));
1516 BCI(LOW(*arg));
1517 arg++;
1521 else
1523 for (i = 0; i < num_args; i += 255)
1525 nargs = (num_args - i > 255) ? 255 : num_args - i;
1527 BCI(NPUSHB);
1528 BCI(nargs);
1529 for (j = 0; j < nargs; j++)
1531 BCI(*arg);
1532 arg++;
1537 BCI(CALL);
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;
1547 free(args);
1549 return bufp;
1553 static FT_Bool
1554 TA_hints_record_is_different(Hints_Record* hints_records,
1555 FT_UInt num_hints_records,
1556 FT_Byte* start,
1557 FT_Byte* end)
1559 Hints_Record last_hints_record;
1562 if (!hints_records)
1563 return 1;
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)
1569 return 1;
1571 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1572 return 1;
1574 return 0;
1578 static FT_Error
1579 TA_add_hints_record(Hints_Record** hints_records,
1580 FT_UInt* num_hints_records,
1581 FT_Byte* start,
1582 Hints_Record hints_record)
1584 Hints_Record* hints_records_new;
1585 FT_UInt buf_len;
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)++;
1601 hints_records_new =
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;
1610 else
1611 *hints_records = hints_records_new;
1613 (*hints_records)[*num_hints_records - 1] = hints_record;
1615 return FT_Err_Ok;
1619 static FT_Byte*
1620 TA_sfnt_emit_hints_record(SFNT* sfnt,
1621 Hints_Record* hints_record,
1622 FT_Byte* bufp)
1624 FT_Byte* p;
1625 FT_Byte* endp;
1626 FT_Bool need_words = 0;
1628 FT_UInt i, j;
1629 FT_UInt num_arguments;
1630 FT_UInt num_args;
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)
1637 if (*p)
1638 need_words = 1;
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;
1645 p = endp - 2;
1647 if (need_words)
1649 for (i = 0; i < num_arguments; i += 255)
1651 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1653 BCI(NPUSHW);
1654 BCI(num_args);
1655 for (j = 0; j < num_args; j++)
1657 BCI(*p);
1658 BCI(*(p + 1));
1659 p -= 2;
1663 else
1665 /* we only need the lower bytes */
1666 p++;
1668 for (i = 0; i < num_arguments; i += 255)
1670 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1672 BCI(NPUSHB);
1673 BCI(num_args);
1674 for (j = 0; j < num_args; j++)
1676 BCI(*p);
1677 p -= 2;
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;
1686 return bufp;
1690 static FT_Byte*
1691 TA_sfnt_emit_hints_records(SFNT* sfnt,
1692 Hints_Record* hints_records,
1693 FT_UInt num_hints_records,
1694 FT_Byte* bufp)
1696 FT_UInt i;
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' */
1706 BCI(SVTCA_y);
1708 for (i = 0; i < num_hints_records - 1; i++)
1710 BCI(MPPEM);
1711 if (hints_record->size > 0xFF)
1713 BCI(PUSHW_1);
1714 BCI(HIGH((hints_record + 1)->size));
1715 BCI(LOW((hints_record + 1)->size));
1717 else
1719 BCI(PUSHB_1);
1720 BCI((hints_record + 1)->size);
1722 BCI(LT);
1723 BCI(IF);
1724 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
1725 BCI(ELSE);
1727 hints_record++;
1730 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
1732 for (i = 0; i < num_hints_records - 1; i++)
1733 BCI(EIF);
1735 BCI(PUSHB_1);
1736 BCI(bci_hint_glyph);
1737 BCI(CALL);
1739 return bufp;
1743 static void
1744 TA_free_hints_records(Hints_Record* hints_records,
1745 FT_UInt num_hints_records)
1747 FT_UInt i;
1750 for (i = 0; i < num_hints_records; i++)
1751 free(hints_records[i].buf);
1753 free(hints_records);
1757 static FT_Byte*
1758 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1759 TA_Segment segments,
1760 TA_Edge edge)
1762 TA_Segment seg;
1763 FT_UInt seg_idx;
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);
1772 *(bufp++) = 0;
1773 *(bufp++) = edge->flags & TA_EDGE_SERIF;
1774 *(bufp++) = 0;
1775 *(bufp++) = edge->flags & TA_EDGE_ROUND;
1777 seg = edge->first->edge_next;
1778 while (seg != edge->first)
1780 seg = seg->edge_next;
1781 num_segs++;
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);
1797 return bufp;
1801 static void
1802 TA_hints_recorder(TA_Action action,
1803 TA_GlyphHints hints,
1804 TA_Dimension dim,
1805 void* arg1,
1806 void* arg2,
1807 void* arg3)
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)
1818 return;
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)
1823 return;
1825 *(p++) = 0;
1826 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1828 switch (action)
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);
1834 break;
1836 case ta_stem_bound:
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);
1840 break;
1842 case ta_link:
1843 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1844 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
1845 break;
1847 case ta_anchor:
1848 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1849 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
1850 break;
1852 case ta_adjust:
1853 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1854 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
1855 break;
1857 case ta_stem:
1858 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1859 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
1860 break;
1862 case ta_blue:
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);
1872 else
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);
1879 break;
1882 case ta_serif:
1883 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1884 break;
1886 case ta_serif_anchor:
1887 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1888 break;
1890 case ta_serif_link1:
1891 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1892 break;
1894 case ta_serif_link2:
1895 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
1896 break;
1898 /* to pacify the compiler */
1899 case ta_bound:
1900 break;
1903 recorder->hints_record.num_actions++;
1904 recorder->hints_record.buf = p;
1908 static FT_Error
1909 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1910 FONT* font,
1911 FT_Long idx)
1913 FT_Face face = sfnt->face;
1914 FT_Error error;
1916 FT_Byte* ins_buf;
1917 FT_UInt ins_len;
1918 FT_Byte* bufp;
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;
1929 Recorder recorder;
1931 FT_UInt size;
1934 if (idx < 0)
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);
1940 if (error)
1941 return error;
1943 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1944 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
1945 if (error)
1946 return error;
1948 /* do nothing if we have an empty glyph */
1949 if (!face->glyph->outline.n_contours)
1950 return FT_Err_Ok;
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);
1959 if (!ins_buf)
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;
1973 #ifdef DEBUGGING
1974 printf("glyph %ld\n", idx);
1975 #endif
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,
1982 TA_hints_recorder,
1983 (void *)&recorder);
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);
1993 if (error)
1994 goto Err;
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);
2000 if (error)
2001 goto Err;
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,
2008 num_hints_records,
2009 bufp, recorder.hints_record.buf))
2011 #ifdef DEBUGGING
2012 if (num_hints_records > 0)
2014 FT_Byte* p;
2017 printf(" %d:\n", size);
2018 for (p = bufp; p < hints_record.buf; p += 2)
2019 printf(" %2d", *p * 256 + *(p + 1));
2020 printf("\n");
2022 #endif
2024 error = TA_add_hints_record(&hints_records,
2025 &num_hints_records,
2026 bufp, recorder.hints_record);
2027 if (error)
2028 goto Err;
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);
2035 else
2036 bufp = TA_sfnt_emit_hints_records(sfnt,
2037 hints_records, num_hints_records,
2038 bufp);
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);
2055 return FT_Err_Ok;
2057 Err:
2058 TA_free_hints_records(hints_records, num_hints_records);
2059 free(ins_buf);
2061 return error;
2065 FT_Error
2066 TA_sfnt_build_glyf_hints(SFNT* sfnt,
2067 FONT* font)
2069 FT_Face face = sfnt->face;
2070 FT_Long idx;
2071 FT_Error error;
2074 for (idx = 0; idx < face->num_glyphs; idx++)
2076 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
2077 if (error)
2078 return error;
2081 return FT_Err_Ok;
2084 /* end of tabytecode.c */