Add bytecode for ANCHOR action.
[ttfautohint.git] / src / tabytecode.c
blob4b1e601ab24bda7eecefc831fa8880a07e71f197
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 this amount */
13 #define ADDITIONAL_STACK_ELEMENTS 20
16 /* #define DEBUGGING */
19 #ifdef TA_DEBUG
20 int _ta_debug = 1;
21 int _ta_debug_disable_horz_hints;
22 int _ta_debug_disable_vert_hints;
23 int _ta_debug_disable_blue_hints;
24 void* _ta_debug_hints;
25 #endif
28 typedef struct Hints_Record_ {
29 FT_UInt size;
30 FT_UInt num_actions;
31 FT_Byte* buf;
32 FT_UInt buf_len;
33 } Hints_Record;
35 typedef struct Recorder_ {
36 FONT* font;
37 Hints_Record hints_record;
38 } Recorder;
41 static FT_Error
42 TA_sfnt_compute_global_hints(SFNT* sfnt,
43 FONT* font)
45 FT_Error error;
46 FT_Face face = sfnt->face;
47 FT_UInt enc;
48 FT_UInt idx;
50 static const FT_Encoding latin_encs[] =
52 FT_ENCODING_UNICODE,
53 FT_ENCODING_APPLE_ROMAN,
54 FT_ENCODING_ADOBE_STANDARD,
55 FT_ENCODING_ADOBE_LATIN_1,
57 FT_ENCODING_NONE /* end of list */
61 error = ta_loader_init(font->loader);
62 if (error)
63 return error;
65 /* try to select a latin charmap */
66 for (enc = 0; latin_encs[enc] != FT_ENCODING_NONE; enc++)
68 error = FT_Select_Charmap(face, latin_encs[enc]);
69 if (!error)
70 break;
73 /* load latin glyph `a' to trigger all initializations */
74 idx = FT_Get_Char_Index(face, 'a');
75 error = ta_loader_load_glyph(font->loader, face, idx, 0);
77 return error;
81 static FT_Error
82 TA_table_build_cvt(FT_Byte** cvt,
83 FT_ULong* cvt_len,
84 SFNT* sfnt,
85 FONT* font)
87 TA_LatinAxis haxis;
88 TA_LatinAxis vaxis;
90 FT_UInt i;
91 FT_UInt buf_len;
92 FT_UInt len;
93 FT_Byte* buf;
94 FT_Byte* buf_p;
96 FT_Error error;
99 error = TA_sfnt_compute_global_hints(sfnt, font);
100 if (error)
101 return error;
103 /* XXX check validity of pointers */
104 haxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[0];
105 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
107 buf_len = 2 * (2
108 + haxis->width_count
109 + vaxis->width_count
110 + 2 * vaxis->blue_count);
112 /* buffer length must be a multiple of four */
113 len = (buf_len + 3) & ~3;
114 buf = (FT_Byte*)malloc(len);
115 if (!buf)
116 return FT_Err_Out_Of_Memory;
118 /* pad end of buffer with zeros */
119 buf[len - 1] = 0x00;
120 buf[len - 2] = 0x00;
121 buf[len - 3] = 0x00;
123 buf_p = buf;
125 if (haxis->width_count > 0)
127 *(buf_p++) = HIGH(haxis->widths[0].org);
128 *(buf_p++) = LOW(haxis->widths[0].org);
130 else
132 *(buf_p++) = 0;
133 *(buf_p++) = 50;
135 if (vaxis->width_count > 0)
137 *(buf_p++) = HIGH(vaxis->widths[0].org);
138 *(buf_p++) = LOW(vaxis->widths[0].org);
140 else
142 *(buf_p++) = 0;
143 *(buf_p++) = 50;
146 for (i = 0; i < haxis->width_count; i++)
148 if (haxis->widths[i].org > 0xFFFF)
149 goto Err;
150 *(buf_p++) = HIGH(haxis->widths[i].org);
151 *(buf_p++) = LOW(haxis->widths[i].org);
154 for (i = 0; i < vaxis->width_count; i++)
156 if (vaxis->widths[i].org > 0xFFFF)
157 goto Err;
158 *(buf_p++) = HIGH(vaxis->widths[i].org);
159 *(buf_p++) = LOW(vaxis->widths[i].org);
162 for (i = 0; i < vaxis->blue_count; i++)
164 if (vaxis->blues[i].ref.org > 0xFFFF)
165 goto Err;
166 *(buf_p++) = HIGH(vaxis->blues[i].ref.org);
167 *(buf_p++) = LOW(vaxis->blues[i].ref.org);
170 for (i = 0; i < vaxis->blue_count; i++)
172 if (vaxis->blues[i].shoot.org > 0xFFFF)
173 goto Err;
174 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
175 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
178 #if 0
179 TA_LOG(("--------------------------------------------------\n"));
180 TA_LOG(("glyph %d:\n", idx));
181 ta_glyph_hints_dump_edges(_ta_debug_hints);
182 ta_glyph_hints_dump_segments(_ta_debug_hints);
183 ta_glyph_hints_dump_points(_ta_debug_hints);
184 #endif
186 *cvt = buf;
187 *cvt_len = buf_len;
189 return FT_Err_Ok;
191 Err:
192 free(buf);
193 return TA_Err_Hinter_Overflow;
197 FT_Error
198 TA_sfnt_build_cvt_table(SFNT* sfnt,
199 FONT* font)
201 FT_Error error;
203 FT_Byte* cvt_buf;
204 FT_ULong cvt_len;
207 error = TA_sfnt_add_table_info(sfnt);
208 if (error)
209 return error;
211 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
212 if (error)
213 return error;
215 /* in case of success, `cvt_buf' gets linked */
216 /* and is eventually freed in `TA_font_unload' */
217 error = TA_font_add_table(font,
218 &sfnt->table_infos[sfnt->num_table_infos - 1],
219 TTAG_cvt, cvt_len, cvt_buf);
220 if (error)
222 free(cvt_buf);
223 return error;
226 return FT_Err_Ok;
230 /* the horizontal and vertical standard widths */
231 #define CVT_HORZ_STANDARD_WIDTH_OFFSET(font) 0
232 #define CVT_VERT_STANDARD_WIDTH_OFFSET(font) \
233 CVT_HORZ_STANDARD_WIDTH_OFFSET(font) + 1
235 /* the horizontal stem widths */
236 #define CVT_HORZ_WIDTHS_OFFSET(font) \
237 CVT_VERT_STANDARD_WIDTH_OFFSET(font) + 1
238 #define CVT_HORZ_WIDTHS_SIZE(font) \
239 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
241 /* the vertical stem widths */
242 #define CVT_VERT_WIDTHS_OFFSET(font) \
243 CVT_HORZ_WIDTHS_OFFSET(font) + CVT_HORZ_WIDTHS_SIZE(font)
244 #define CVT_VERT_WIDTHS_SIZE(font) \
245 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
247 /* the number of blue zones */
248 #define CVT_BLUES_SIZE(font) \
249 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
251 /* the blue zone values for flat and round edges */
252 #define CVT_BLUE_REFS_OFFSET(font) \
253 CVT_VERT_WIDTHS_OFFSET(font) + CVT_VERT_WIDTHS_SIZE(font)
254 #define CVT_BLUE_SHOOTS_OFFSET(font) \
255 CVT_BLUE_REFS_OFFSET(font) + CVT_BLUES_SIZE(font)
258 /* symbolic names for storage area locations */
260 #define sal_i 0
261 #define sal_j sal_i + 1
262 #define sal_k sal_j + 1
263 #define sal_temp1 sal_k + 1
264 #define sal_temp2 sal_temp1 + 1
265 #define sal_temp3 sal_temp2 + 1
266 #define sal_temp4 sal_temp3 + 1
267 #define sal_limit sal_temp4 + 1
268 #define sal_num_segments sal_limit + 1
269 #define sal_scale sal_num_segments + 1
270 #define sal_0x10000 sal_scale + 1
271 #define sal_is_extra_light sal_0x10000 + 1
272 #define sal_anchor sal_is_extra_light + 1
273 #define sal_point_min sal_anchor + 1
274 #define sal_point_max sal_point_min + 1
275 #define sal_segment_offset sal_point_max + 1 /* must be last */
278 /* we need the following macro */
279 /* so that `func_name' doesn't get replaced with its #defined value */
280 /* (as defined in `tabytecode.h') */
282 #define FPGM(func_name) fpgm_ ## func_name
285 /* in the comments below, the top of the stack (`s:') */
286 /* is the rightmost element; the stack is shown */
287 /* after the instruction on the same line has been executed */
289 /* we use two sets of points in the twilight zone (zp0): */
290 /* one set to hold the unhinted segment positions, */
291 /* and another one to track the positions as changed by the hinting -- */
292 /* this is necessary since all points in zp0 */
293 /* have (0,0) as the original coordinates, */
294 /* making e.g. `MD_orig' return useless results */
298 * bci_compute_stem_width
300 * This is the equivalent to the following code from function
301 * `ta_latin_compute_stem_width':
303 * dist = ABS(width)
305 * if (stem_is_serif
306 * && dist < 3*64)
307 * || is_extra_light:
308 * return width
309 * else if base_is_round:
310 * if dist < 80
311 * dist = 64
312 * else if dist < 56:
313 * dist = 56
315 * delta = ABS(dist - std_width)
317 * if delta < 40:
318 * dist = MIN(48, std_width)
319 * goto End
321 * if dist < 3*64:
322 * delta = dist
323 * dist = FLOOR(dist)
324 * delta = delta - dist
326 * if delta < 10:
327 * dist = dist + delta
328 * else if delta < 32:
329 * dist = dist + 10
330 * else if delta < 54:
331 * dist = dist + 54
332 * else
333 * dist = dist + delta
334 * else
335 * dist = ROUND(dist)
337 * End:
338 * if width < 0:
339 * dist = -dist
340 * return dist
343 * in: width
344 * stem_is_serif
345 * base_is_round
346 * out: new_width
347 * sal: sal_is_extra_light
348 * CVT: std_width
351 unsigned char FPGM(bci_compute_stem_width_a) [] = {
353 PUSHB_1,
354 bci_compute_stem_width,
355 FDEF,
357 DUP,
358 ABS, /* s: base_is_round stem_is_serif width dist */
360 DUP,
361 PUSHB_1,
362 3*64,
363 LT, /* dist < 3*64 */
365 PUSHB_1,
367 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
368 AND, /* stem_is_serif && dist < 3*64 */
370 PUSHB_1,
371 sal_is_extra_light,
373 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
375 IF, /* s: base_is_round width dist */
376 POP,
377 SWAP,
378 POP, /* s: width */
380 ELSE,
381 ROLL, /* s: width dist base_is_round */
382 IF, /* s: width dist */
383 DUP,
384 PUSHB_1,
386 LT, /* dist < 80 */
387 IF, /* s: width dist */
388 POP,
389 PUSHB_1,
390 64, /* dist = 64 */
391 EIF,
393 ELSE,
394 DUP,
395 PUSHB_1,
397 LT, /* dist < 56 */
398 IF, /* s: width dist */
399 POP,
400 PUSHB_1,
401 56, /* dist = 56 */
402 EIF,
403 EIF,
405 DUP, /* s: width dist dist */
406 PUSHB_1,
410 /* %c, index of std_width */
412 unsigned char FPGM(bci_compute_stem_width_b) [] = {
414 RCVT,
415 SUB,
416 ABS, /* s: width dist delta */
418 PUSHB_1,
420 LT, /* delta < 40 */
421 IF, /* s: width dist */
422 POP,
423 PUSHB_2,
428 /* %c, index of std_width */
430 unsigned char FPGM(bci_compute_stem_width_c) [] = {
432 RCVT,
433 MIN, /* dist = min(48, std_width) */
435 ELSE,
436 DUP, /* s: width dist dist */
437 PUSHB_1,
438 3*64,
439 LT, /* dist < 3*64 */
441 DUP, /* s: width delta dist */
442 FLOOR, /* dist = FLOOR(dist) */
443 DUP, /* s: width delta dist dist */
444 ROLL,
445 ROLL, /* s: width dist delta dist */
446 SUB, /* delta = delta - dist */
448 DUP, /* s: width dist delta delta */
449 PUSHB_1,
451 LT, /* delta < 10 */
452 IF, /* s: width dist delta */
453 ADD, /* dist = dist + delta */
455 ELSE,
456 DUP,
457 PUSHB_1,
459 LT, /* delta < 32 */
461 POP,
462 PUSHB_1,
464 ADD, /* dist = dist + 10 */
466 ELSE,
467 DUP,
468 PUSHB_1,
470 LT, /* delta < 54 */
472 POP,
473 PUSHB_1,
475 ADD, /* dist = dist + 54 */
477 ELSE,
478 ADD, /* dist = dist + delta */
480 EIF,
481 EIF,
482 EIF,
484 ELSE,
485 PUSHB_1,
487 ADD,
488 FLOOR, /* dist = round(dist) */
490 EIF,
491 EIF,
493 SWAP, /* s: dist width */
494 PUSHB_1,
496 LT, /* width < 0 */
498 NEG, /* dist = -dist */
499 EIF,
500 EIF,
501 EIF,
503 ENDF,
509 * bci_loop
511 * Take a range and a function number and apply the function to all
512 * elements of the range. The called function must not change the
513 * stack.
515 * in: func_num
516 * end
517 * start
519 * uses: sal_i (counter initialized with `start')
520 * sal_limit (`end')
523 unsigned char FPGM(bci_loop) [] = {
525 PUSHB_1,
526 bci_loop,
527 FDEF,
529 ROLL,
530 ROLL, /* s: func_num start end */
531 PUSHB_1,
532 sal_limit,
533 SWAP,
536 PUSHB_1,
537 sal_i,
538 SWAP,
541 /* start_loop: */
542 PUSHB_1,
543 sal_i,
545 PUSHB_1,
546 sal_limit,
548 LTEQ, /* start <= end */
549 IF, /* s: func_num */
550 DUP,
551 CALL,
552 PUSHB_3,
553 sal_i,
555 sal_i,
557 ADD, /* start = start + 1 */
560 PUSHB_1,
562 NEG,
563 JMPR, /* goto start_loop */
564 ELSE,
565 POP,
566 EIF,
568 ENDF,
574 * bci_cvt_rescale
576 * Rescale CVT value by a given factor.
578 * uses: sal_i (CVT index)
579 * sal_scale (scale in 16.16 format)
582 unsigned char FPGM(bci_cvt_rescale) [] = {
584 PUSHB_1,
585 bci_cvt_rescale,
586 FDEF,
588 PUSHB_1,
589 sal_i,
591 DUP,
592 RCVT,
593 PUSHB_1,
594 sal_scale,
596 MUL, /* CVT * scale * 2^10 */
597 PUSHB_1,
598 sal_0x10000,
600 DIV, /* CVT * scale */
602 WCVTP,
604 ENDF,
610 * bci_sal_assign
612 * Auxiliary function for `bci_set_up_segments'.
614 * in: offset
615 * data
617 * out: offset+1
620 unsigned char FPGM(bci_sal_assign) [] = {
622 PUSHB_1,
623 bci_sal_assign,
624 FDEF,
626 DUP,
627 ROLL, /* s: offset offset data */
630 PUSHB_1,
632 ADD, /* s: (offset + 1) */
634 ENDF,
640 * bci_set_up_segments
642 * Set up segments by defining the point ranges which defines them
643 * and computing twilight points to represent them.
645 * in: num_segments (N)
646 * offset
647 * segment_start_0
648 * segment_end_0
649 * segment_start_1
650 * segment_end_1
651 * ...
652 * segment_start_(N-1)
653 * segment_end_(N-1)
655 * sal: sal_num_segments
657 * uses: bci_sal_assign
660 unsigned char FPGM(bci_set_up_segments) [] = {
662 PUSHB_1,
663 bci_set_up_segments,
664 FDEF,
666 DUP,
667 PUSHB_1,
668 sal_num_segments,
669 SWAP,
672 /* we have 2*num_segments arguments */
673 DUP,
674 ADD,
676 /* process the stack, popping off the elements in a loop */
677 PUSHB_1,
678 bci_sal_assign,
679 LOOPCALL,
681 /* clean up stack */
682 POP,
684 PUSHB_1,
685 bci_create_segment_points,
686 CALL,
688 ENDF,
694 * bci_blue_round
696 * Round a blue ref value and adjust its corresponding shoot value.
698 * uses: sal_i (CVT index)
702 unsigned char FPGM(bci_blue_round_a) [] = {
704 PUSHB_1,
705 bci_blue_round,
706 FDEF,
708 PUSHB_1,
709 sal_i,
711 DUP,
712 RCVT, /* s: ref_idx ref */
714 DUP,
715 PUSHB_1,
717 ADD,
718 FLOOR,
719 SWAP, /* s: ref_idx round(ref) ref */
721 PUSHB_2,
725 /* %c, blue_count */
727 unsigned char FPGM(bci_blue_round_b) [] = {
730 CINDEX,
731 ADD, /* s: ref_idx round(ref) ref shoot_idx */
732 DUP,
733 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
735 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
736 SWAP,
737 SUB, /* s: ref_idx round(ref) shoot_idx dist */
738 DUP,
739 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
741 DUP,
742 PUSHB_1,
744 LT, /* delta < 32 */
746 POP,
747 PUSHB_1,
748 0, /* delta = 0 */
750 ELSE,
751 PUSHB_1,
753 LT, /* delta < 48 */
755 PUSHB_1,
756 32, /* delta = 32 */
758 ELSE,
759 PUSHB_1,
760 64, /* delta = 64 */
761 EIF,
762 EIF,
764 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
765 PUSHB_1,
767 LT, /* dist < 0 */
769 NEG, /* delta = -delta */
770 EIF,
772 PUSHB_1,
774 CINDEX,
775 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
777 WCVTP,
778 WCVTP,
780 ENDF,
786 * bci_get_point_extrema
788 * An auxiliary function for `bci_create_segment_point'.
790 * in: point-1
791 * out: point
793 * sal: sal_point_min
794 * sal_point_max
797 unsigned char FPGM(bci_get_point_extrema) [] = {
799 PUSHB_1,
800 bci_get_point_extrema,
801 FDEF,
803 PUSHB_1,
805 ADD, /* s: point */
806 DUP,
807 DUP,
809 /* check whether `point' is a new minimum */
810 PUSHB_1,
811 sal_point_min,
812 RS, /* s: point point point point_min */
813 MD_orig,
814 /* if distance is negative, we have a new minimum */
815 PUSHB_1,
818 IF, /* s: point point */
819 DUP,
820 PUSHB_1,
821 sal_point_min,
822 SWAP,
824 EIF,
826 /* check whether `point' is a new maximum */
827 PUSHB_1,
828 sal_point_max,
829 RS, /* s: point point point_max */
830 MD_orig,
831 /* if distance is positive, we have a new maximum */
832 PUSHB_1,
835 IF, /* s: point */
836 DUP,
837 PUSHB_1,
838 sal_point_max,
839 SWAP,
841 EIF, /* s: point */
843 ENDF,
849 * bci_create_segment_point
851 * Construct two points in the twilight zone to represent a segment:
852 * an original one (which stays unmodified) and a hinted one,
853 * initialized with the original value.
855 * This function is used by `bci_create_segment_points'.
857 * uses: bci_get_point_extrema
859 * sal: sal_i (start of current segment)
860 * sal_j (current original twilight point)
861 * sal_k (current hinted twilight point)
862 * sal_point_min
863 * sal_point_max
866 unsigned char FPGM(bci_create_segment_point) [] = {
868 PUSHB_1,
869 bci_create_segment_point,
870 FDEF,
872 PUSHB_1,
873 sal_i,
875 RS, /* s: start_point */
876 DUP,
878 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
879 PUSHB_2,
881 sal_i,
883 ADD,
884 DUP,
885 PUSHB_1,
886 sal_i,
887 SWAP,
890 SWAP, /* s: start_point end_point start_point */
892 /* initialize inner loop */
893 DUP,
894 PUSHB_1,
895 sal_point_min,
896 SWAP,
897 WS, /* sal_point_min = start_point */
898 DUP,
899 PUSHB_1,
900 sal_point_max,
901 SWAP,
902 WS, /* sal_point_max = start_point */
904 SUB, /* s: start_point loop_count */
906 PUSHB_2,
909 SZP0, /* set zp0 to normal zone 1 */
910 SZP1, /* set zp1 to normal zone 1 */
912 /* all our measurements are taken along the y axis */
913 SVTCA_y,
915 PUSHB_1,
916 bci_get_point_extrema,
917 LOOPCALL,
918 /* clean up stack */
919 POP,
921 /* the twilight point representing a segment */
922 /* is in the middle between the minimum and maximum */
923 PUSHB_1,
924 sal_point_max,
926 PUSHB_1,
927 sal_point_min,
929 MD_orig,
930 PUSHB_1,
931 2*64,
932 DIV, /* s: delta */
934 PUSHB_4,
935 sal_j,
938 sal_point_min,
940 MDAP_noround, /* set rp0 and rp1 to `sal_point_min' */
941 SZP1, /* set zp1 to twilight zone 0 */
942 SZP2, /* set zp2 to twilight zone 0 */
945 DUP, /* s: delta point[sal_j] point[sal_j] */
946 ALIGNRP, /* align `point[sal_j]' with `sal_point_min' */
947 PUSHB_1,
949 CINDEX, /* s: delta point[sal_j] delta */
950 SHPIX, /* shift `point[sal_j]' by `delta' */
952 PUSHB_1,
953 sal_k,
955 DUP, /* s: delta point[sal_k] point[sal_k] */
956 ALIGNRP, /* align `point[sal_k]' with `sal_point_min' */
957 SWAP,
958 SHPIX, /* shift `point[sal_k]' by `delta' */
960 PUSHB_6,
961 sal_k,
963 sal_k,
964 sal_j,
966 sal_j,
968 ADD, /* original_twilight_point = original_twilight_point + 1 */
971 ADD, /* hinted_twilight_point = hinted_twilight_point + 1 */
974 ENDF,
980 * bci_create_segment_points
982 * Construct two sets of points in the twilight zone to represent segments.
983 * This function searches the points of a segment with the minimum and
984 * maximum y-values, then takes the median.
986 * uses: bci_create_segment_point
988 * sal: sal_i (start of current segment)
989 * sal_j (current original twilight point)
990 * sal_k (current hinted twilight point)
991 * sal_num_segments
994 unsigned char FPGM(bci_create_segment_points) [] = {
996 PUSHB_1,
997 bci_create_segment_points,
998 FDEF,
1000 PUSHB_7,
1001 sal_segment_offset,
1002 sal_segment_offset,
1003 sal_num_segments,
1005 sal_k,
1007 sal_j,
1008 sal_num_segments,
1010 WS, /* sal_j = num_segments (offset for original points) */
1011 WS, /* sal_k = 0 (offset for hinted points) */
1014 DUP,
1015 ADD,
1016 ADD,
1017 PUSHB_1,
1019 SUB, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1021 PUSHB_2,
1022 bci_create_segment_point,
1023 bci_loop,
1024 CALL,
1026 ENDF,
1030 unsigned char FPGM(bci_handle_segment) [] = {
1032 PUSHB_1,
1033 bci_handle_segment,
1034 FDEF,
1036 POP, /* XXX segment */
1038 ENDF,
1044 * bci_align_segment
1046 * Align all points in a segment to the twilight point in rp0.
1047 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1049 * in: segment_index
1052 unsigned char FPGM(bci_align_segment) [] = {
1054 PUSHB_1,
1055 bci_align_segment,
1056 FDEF,
1058 /* we need the values of `sal_segment_offset + 2*segment_index' */
1059 /* and `sal_segment_offset + 2*segment_index + 1' */
1060 DUP,
1061 ADD,
1062 PUSHB_1,
1063 sal_segment_offset,
1064 ADD,
1065 DUP,
1067 SWAP,
1068 PUSHB_1,
1070 ADD,
1071 RS, /* s: first last */
1073 /* start_loop: */
1074 PUSHB_1,
1076 CINDEX, /* s: first last first */
1077 PUSHB_1,
1079 CINDEX, /* s: first last first last */
1080 LTEQ, /* first <= end */
1081 IF, /* s: first last */
1082 SWAP,
1083 DUP, /* s: last first first */
1084 ALIGNRP, /* align point with index `first' with rp0 */
1086 PUSHB_1,
1088 ADD, /* first = first + 1 */
1089 SWAP, /* s: first last */
1091 PUSHB_1,
1093 NEG,
1094 JMPR, /* goto start_loop */
1095 ELSE,
1096 POP,
1097 POP,
1098 EIF,
1100 ENDF,
1104 unsigned char FPGM(bci_handle_segments) [] = {
1106 PUSHB_1,
1107 bci_handle_segments,
1108 FDEF,
1110 POP, /* XXX first segment */
1112 PUSHB_1,
1113 bci_handle_segment,
1114 LOOPCALL,
1116 ENDF,
1122 * bci_align_segments
1124 * Align segments to the twilight point in rp0.
1125 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1127 * in: first_segment
1128 * loop_counter (N)
1129 * segment_1
1130 * segment_2
1131 * ...
1132 * segment_N
1134 * uses: handle_segment
1138 unsigned char FPGM(bci_align_segments) [] = {
1140 PUSHB_1,
1141 bci_align_segments,
1142 FDEF,
1144 PUSHB_1,
1145 bci_align_segment,
1146 CALL,
1148 PUSHB_1,
1149 bci_align_segment,
1150 LOOPCALL,
1152 ENDF,
1157 unsigned char FPGM(bci_action_adjust_bound) [] = {
1159 PUSHB_1,
1160 bci_action_adjust_bound,
1161 FDEF,
1163 PUSHB_1,
1164 bci_handle_segments,
1165 CALL,
1166 PUSHB_1,
1167 bci_handle_segments,
1168 CALL,
1169 PUSHB_1,
1170 bci_handle_segments,
1171 CALL,
1173 /* XXX */
1175 ENDF,
1179 unsigned char FPGM(bci_action_stem_bound) [] = {
1181 PUSHB_1,
1182 bci_action_stem_bound,
1183 FDEF,
1185 PUSHB_1,
1186 bci_handle_segments,
1187 CALL,
1188 PUSHB_1,
1189 bci_handle_segments,
1190 CALL,
1191 PUSHB_1,
1192 bci_handle_segments,
1193 CALL,
1195 /* XXX */
1197 ENDF,
1203 * bci_action_link
1205 * Handle the LINK action to link an edge to another one.
1207 * in: stem_is_serif
1208 * base_is_round
1209 * base_point (in twilight zone)
1210 * stem_point (in twilight zone)
1211 * ... stuff for bci_align_segments ...
1214 unsigned char FPGM(bci_action_link) [] = {
1216 PUSHB_1,
1217 bci_action_link,
1218 FDEF,
1220 PUSHB_1,
1222 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1224 PUSHB_1,
1226 CINDEX,
1227 PUSHB_1,
1228 sal_num_segments,
1230 ADD,
1231 PUSHB_1,
1233 MINDEX,
1234 DUP,
1235 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1236 PUSHB_1,
1237 sal_num_segments,
1239 ADD, /* s: stem is_round is_serif stem_orig base_orig */
1241 MD_cur, /* s: stem is_round is_serif dist_orig */
1243 PUSHB_1,
1244 bci_compute_stem_width,
1245 CALL, /* s: stem new_dist */
1247 SWAP,
1248 DUP,
1249 ALIGNRP, /* align `stem_point' with `base_point' */
1250 DUP,
1251 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
1252 SWAP,
1253 SHPIX, /* stem_point = base_point + new_dist */
1255 PUSHB_2,
1256 bci_align_segments,
1258 SZP1, /* set zp1 to normal zone 1 */
1259 CALL,
1261 ENDF,
1267 * bci_action_anchor
1269 * Handle the ANCHOR action to align two edges
1270 * and to set the edge anchor.
1272 * The code after computing `cur_len' to shift `edge' and `edge2'
1273 * is equivalent to the snippet below (part of `ta_latin_hint_edges'):
1275 * if cur_len < 96:
1276 * if cur_len < = 64:
1277 * u_off = 32
1278 * d_off = 32
1279 * else:
1280 * u_off = 38
1281 * d_off = 26
1283 * org_center = edge_orig + org_len / 2
1284 * cur_pos1 = ROUND(org_center)
1286 * error1 = ABS(org_center - (cur_pos1 - u_off))
1287 * error2 = ABS(org_center - (cur_pos1 + d_off))
1288 * if (error1 < error2):
1289 * cur_pos1 = cur_pos1 - u_off
1290 * else:
1291 * cur_pos1 = cur_pos1 + d_off
1293 * edge = cur_pos1 - cur_len / 2
1294 * edge2 = edge + cur_len
1296 * else:
1297 * edge = ROUND(edge_orig)
1299 * in: edge2_is_serif
1300 * edge_is_round
1301 * edge_point (in twilight zone)
1302 * edge2_point (in twilight zone)
1303 * ... stuff for bci_align_segments...
1306 #define sal_u_off sal_temp1
1307 #define sal_d_off sal_temp2
1308 #define sal_org_len sal_temp3
1310 unsigned char FPGM(bci_action_anchor) [] = {
1312 PUSHB_1,
1313 bci_action_anchor,
1314 FDEF,
1316 /* store anchor point number in `sal_anchor' */
1317 PUSHB_2,
1318 sal_anchor,
1320 CINDEX,
1321 WS, /* sal_anchor = edge_point */
1323 PUSHB_1,
1325 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1327 PUSHB_1,
1329 CINDEX,
1330 PUSHB_1,
1331 sal_num_segments,
1333 ADD,
1334 PUSHB_1,
1336 CINDEX,
1337 DUP,
1338 MDAP_noround, /* set rp0 and rp1 to `edge_point' (for ALIGNRP below) */
1339 PUSHB_1,
1340 sal_num_segments,
1342 ADD, /* s: edge2 edge is_round is_serif stem_orig edge_orig */
1344 MD_cur, /* s: edge2 edge is_round is_serif org_len */
1345 DUP,
1346 PUSHB_1,
1347 sal_org_len,
1348 SWAP,
1351 PUSHB_1,
1352 bci_compute_stem_width,
1353 CALL, /* s: edge2 edge cur_len */
1355 DUP,
1356 PUSHB_1,
1358 LT, /* cur_len < 96 */
1360 DUP,
1361 PUSHB_1,
1363 LTEQ, /* cur_len <= 64 */
1365 PUSHB_4,
1366 sal_u_off,
1368 sal_d_off,
1370 ELSE,
1371 PUSHB_4,
1372 sal_u_off,
1374 sal_d_off,
1376 EIF,
1380 SWAP, /* s: edge2 cur_len edge */
1381 DUP,
1382 PUSHB_1,
1383 sal_num_segments,
1385 ADD, /* s: edge2 cur_len edge edge_orig */
1387 GC_cur,
1388 PUSHB_1,
1389 sal_org_len,
1391 PUSHB_1,
1392 2*64,
1393 DIV,
1394 ADD, /* s: edge2 cur_len edge org_center */
1396 DUP,
1397 PUSHB_1,
1399 ADD,
1400 FLOOR, /* s: edge2 cur_len edge org_center cur_pos1 */
1402 DUP,
1403 ROLL,
1404 ROLL,
1405 SUB, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) */
1407 DUP,
1408 PUSHB_1,
1409 sal_u_off,
1411 ADD,
1412 ABS, /* s: edge2 cur_len edge cur_pos1 (org_center - cur_pos1) error1 */
1414 SWAP,
1415 PUSHB_1,
1416 sal_d_off,
1418 SUB,
1419 ABS, /* s: edge2 cur_len edge cur_pos1 error1 error2 */
1421 LT, /* error1 < error2 */
1423 PUSHB_1,
1424 sal_u_off,
1426 SUB, /* cur_pos1 = cur_pos1 - u_off */
1427 ELSE,
1428 PUSHB_1,
1429 sal_d_off,
1431 ADD, /* cur_pos1 = cur_pos1 + d_off */
1432 EIF, /* s: edge2 cur_len edge cur_pos1 */
1434 PUSHB_1,
1436 CINDEX,
1437 PUSHB_1,
1438 2*64,
1439 DIV,
1440 SUB, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) */
1442 PUSHB_1,
1444 CINDEX, /* s: edge2 cur_len edge (cur_pos1 - cur_len/2) edge */
1445 GC_cur,
1446 SUB,
1447 SHPIX, /* edge = cur_pos1 - cur_len/2 */
1449 SWAP, /* s: cur_len edge2 */
1450 DUP,
1451 ALIGNRP, /* align `edge2' with rp0 (still `edge') */
1452 SWAP,
1453 SHPIX, /* edge2 = edge1 + cur_len */
1455 ELSE,
1456 POP, /* s: edge2 edge */
1457 DUP,
1458 PUSHB_1,
1459 sal_num_segments,
1461 ADD, /* s: edge2 edge edge_orig */
1463 MDAP_noround, /* set rp0 and rp1 to `edge_orig' */
1464 DUP,
1465 ALIGNRP, /* align `edge' with `edge_orig' */
1466 MDAP_round, /* round `edge' */
1468 /* clean up stack */
1469 POP,
1470 EIF,
1472 PUSHB_2,
1473 bci_align_segments,
1475 SZP1, /* set zp1 to normal zone 1 */
1476 CALL,
1478 ENDF,
1484 * bci_action_blue_anchor
1486 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1487 * and to set the edge anchor.
1489 * in: anchor_point (in twilight zone)
1490 * blue_cvt_idx
1491 * edge_point (in twilight zone)
1492 * ... stuff for bci_align_segments ...
1494 * sal: sal_anchor
1497 unsigned char FPGM(bci_action_blue_anchor) [] = {
1499 PUSHB_1,
1500 bci_action_blue_anchor,
1501 FDEF,
1503 /* store anchor point number in `sal_anchor' */
1504 PUSHB_1,
1505 sal_anchor,
1506 SWAP,
1509 PUSHB_1,
1511 SZP0, /* set zp0 to twilight zone 0 */
1513 /* move `edge_point' to `blue_cvt_idx' position */
1514 MIAP_noround, /* this also sets rp0 */
1516 PUSHB_2,
1517 bci_align_segments,
1519 SZP1, /* set zp1 to normal zone 1 */
1520 CALL,
1522 ENDF,
1526 unsigned char FPGM(bci_action_adjust) [] = {
1528 PUSHB_1,
1529 bci_action_adjust,
1530 FDEF,
1532 PUSHB_1,
1533 bci_handle_segments,
1534 CALL,
1535 PUSHB_1,
1536 bci_handle_segments,
1537 CALL,
1539 /* XXX */
1541 ENDF,
1545 unsigned char FPGM(bci_action_stem) [] = {
1547 PUSHB_1,
1548 bci_action_stem,
1549 FDEF,
1551 PUSHB_1,
1552 bci_handle_segments,
1553 CALL,
1554 PUSHB_1,
1555 bci_handle_segments,
1556 CALL,
1558 /* XXX */
1560 ENDF,
1566 * bci_action_blue
1568 * Handle the BLUE action to align an edge with a blue zone.
1570 * in: blue_cvt_idx
1571 * edge_point (in twilight zone)
1572 * ... stuff for bci_align_segments ...
1575 unsigned char FPGM(bci_action_blue) [] = {
1577 PUSHB_1,
1578 bci_action_blue,
1579 FDEF,
1581 PUSHB_1,
1583 SZP0, /* set zp0 to twilight zone 0 */
1585 /* move `edge_point' to `blue_cvt_idx' position */
1586 MIAP_noround, /* this also sets rp0 */
1588 PUSHB_2,
1589 bci_align_segments,
1591 SZP1, /* set zp1 to normal zone 1 */
1592 CALL,
1594 ENDF,
1598 unsigned char FPGM(bci_action_serif) [] = {
1600 PUSHB_1,
1601 bci_action_serif,
1602 FDEF,
1604 PUSHB_1,
1605 bci_handle_segments,
1606 CALL,
1608 /* XXX */
1610 ENDF,
1614 unsigned char FPGM(bci_action_serif_anchor) [] = {
1616 PUSHB_1,
1617 bci_action_serif_anchor,
1618 FDEF,
1620 PUSHB_1,
1621 bci_handle_segments,
1622 CALL,
1624 /* XXX */
1626 ENDF,
1630 unsigned char FPGM(bci_action_serif_link1) [] = {
1632 PUSHB_1,
1633 bci_action_serif_link1,
1634 FDEF,
1636 PUSHB_1,
1637 bci_handle_segments,
1638 CALL,
1640 /* XXX */
1642 ENDF,
1646 unsigned char FPGM(bci_action_serif_link2) [] = {
1648 PUSHB_1,
1649 bci_action_serif_link2,
1650 FDEF,
1652 PUSHB_1,
1653 bci_handle_segments,
1654 CALL,
1656 /* XXX */
1658 ENDF,
1664 * bci_handle_action
1666 * Execute function.
1668 * in: function_index
1671 unsigned char FPGM(bci_handle_action) [] = {
1673 PUSHB_1,
1674 bci_handle_action,
1675 FDEF,
1677 CALL,
1679 ENDF,
1685 * bci_hint_glyph
1687 * This is the top-level glyph hinting function
1688 * which parses the arguments on the stack and calls subroutines.
1690 * in: num_actions (M)
1691 * action_0_func_idx
1692 * ... data ...
1693 * action_1_func_idx
1694 * ... data ...
1695 * ...
1696 * action_M_func_idx
1697 * ... data ...
1699 * uses: bci_handle_action
1700 * bci_action_adjust_bound
1701 * bci_action_stem_bound
1703 * bci_action_link
1704 * bci_action_anchor
1705 * bci_action_blue_anchor
1706 * bci_action_adjust
1707 * bci_action_stem
1709 * bci_action_blue
1710 * bci_action_serif
1711 * bci_action_serif_anchor
1712 * bci_action_serif_link1
1713 * bci_action_serif_link2
1716 unsigned char FPGM(bci_hint_glyph) [] = {
1718 PUSHB_1,
1719 bci_hint_glyph,
1720 FDEF,
1722 PUSHB_1,
1723 bci_handle_action,
1724 LOOPCALL,
1726 ENDF,
1731 #define COPY_FPGM(func_name) \
1732 memcpy(buf_p, fpgm_ ## func_name, \
1733 sizeof (fpgm_ ## func_name)); \
1734 buf_p += sizeof (fpgm_ ## func_name) \
1736 static FT_Error
1737 TA_table_build_fpgm(FT_Byte** fpgm,
1738 FT_ULong* fpgm_len,
1739 FONT* font)
1741 FT_UInt buf_len;
1742 FT_UInt len;
1743 FT_Byte* buf;
1744 FT_Byte* buf_p;
1747 buf_len = sizeof (FPGM(bci_compute_stem_width_a))
1749 + sizeof (FPGM(bci_compute_stem_width_b))
1751 + sizeof (FPGM(bci_compute_stem_width_c))
1752 + sizeof (FPGM(bci_loop))
1753 + sizeof (FPGM(bci_cvt_rescale))
1754 + sizeof (FPGM(bci_sal_assign))
1755 + sizeof (FPGM(bci_set_up_segments))
1756 + sizeof (FPGM(bci_blue_round_a))
1758 + sizeof (FPGM(bci_blue_round_b))
1759 + sizeof (FPGM(bci_get_point_extrema))
1760 + sizeof (FPGM(bci_create_segment_point))
1761 + sizeof (FPGM(bci_create_segment_points))
1762 + sizeof (FPGM(bci_handle_segment))
1763 + sizeof (FPGM(bci_align_segment))
1764 + sizeof (FPGM(bci_handle_segments))
1765 + sizeof (FPGM(bci_align_segments))
1766 + sizeof (FPGM(bci_action_adjust_bound))
1767 + sizeof (FPGM(bci_action_stem_bound))
1768 + sizeof (FPGM(bci_action_link))
1769 + sizeof (FPGM(bci_action_anchor))
1770 + sizeof (FPGM(bci_action_blue_anchor))
1771 + sizeof (FPGM(bci_action_adjust))
1772 + sizeof (FPGM(bci_action_stem))
1773 + sizeof (FPGM(bci_action_blue))
1774 + sizeof (FPGM(bci_action_serif))
1775 + sizeof (FPGM(bci_action_serif_anchor))
1776 + sizeof (FPGM(bci_action_serif_link1))
1777 + sizeof (FPGM(bci_action_serif_link2))
1778 + sizeof (FPGM(bci_handle_action))
1779 + sizeof (FPGM(bci_hint_glyph));
1780 /* buffer length must be a multiple of four */
1781 len = (buf_len + 3) & ~3;
1782 buf = (FT_Byte*)malloc(len);
1783 if (!buf)
1784 return FT_Err_Out_Of_Memory;
1786 /* pad end of buffer with zeros */
1787 buf[len - 1] = 0x00;
1788 buf[len - 2] = 0x00;
1789 buf[len - 3] = 0x00;
1791 /* copy font program into buffer and fill in the missing variables */
1792 buf_p = buf;
1794 COPY_FPGM(bci_compute_stem_width_a);
1795 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1796 COPY_FPGM(bci_compute_stem_width_b);
1797 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1798 COPY_FPGM(bci_compute_stem_width_c);
1799 COPY_FPGM(bci_loop);
1800 COPY_FPGM(bci_cvt_rescale);
1801 COPY_FPGM(bci_sal_assign);
1802 COPY_FPGM(bci_set_up_segments);
1803 COPY_FPGM(bci_blue_round_a);
1804 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
1805 COPY_FPGM(bci_blue_round_b);
1806 COPY_FPGM(bci_get_point_extrema);
1807 COPY_FPGM(bci_create_segment_point);
1808 COPY_FPGM(bci_create_segment_points);
1809 COPY_FPGM(bci_handle_segment);
1810 COPY_FPGM(bci_align_segment);
1811 COPY_FPGM(bci_handle_segments);
1812 COPY_FPGM(bci_align_segments);
1813 COPY_FPGM(bci_action_adjust_bound);
1814 COPY_FPGM(bci_action_stem_bound);
1815 COPY_FPGM(bci_action_link);
1816 COPY_FPGM(bci_action_anchor);
1817 COPY_FPGM(bci_action_blue_anchor);
1818 COPY_FPGM(bci_action_adjust);
1819 COPY_FPGM(bci_action_stem);
1820 COPY_FPGM(bci_action_blue);
1821 COPY_FPGM(bci_action_serif);
1822 COPY_FPGM(bci_action_serif_anchor);
1823 COPY_FPGM(bci_action_serif_link1);
1824 COPY_FPGM(bci_action_serif_link2);
1825 COPY_FPGM(bci_handle_action);
1826 COPY_FPGM(bci_hint_glyph);
1828 *fpgm = buf;
1829 *fpgm_len = buf_len;
1831 return FT_Err_Ok;
1835 FT_Error
1836 TA_sfnt_build_fpgm_table(SFNT* sfnt,
1837 FONT* font)
1839 FT_Error error;
1841 FT_Byte* fpgm_buf;
1842 FT_ULong fpgm_len;
1845 error = TA_sfnt_add_table_info(sfnt);
1846 if (error)
1847 return error;
1849 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
1850 if (error)
1851 return error;
1853 /* in case of success, `fpgm_buf' gets linked */
1854 /* and is eventually freed in `TA_font_unload' */
1855 error = TA_font_add_table(font,
1856 &sfnt->table_infos[sfnt->num_table_infos - 1],
1857 TTAG_fpgm, fpgm_len, fpgm_buf);
1858 if (error)
1860 free(fpgm_buf);
1861 return error;
1864 return FT_Err_Ok;
1868 /* the `prep' instructions */
1870 #define PREP(snippet_name) prep_ ## snippet_name
1872 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1873 /* thus we provide it in the storage area */
1875 unsigned char PREP(store_0x10000) [] = {
1877 PUSHB_1,
1878 sal_0x10000,
1879 PUSHW_2,
1880 0x08, /* 0x800 */
1881 0x00,
1882 0x08, /* 0x800 */
1883 0x00,
1884 MUL, /* 0x10000 */
1889 unsigned char PREP(align_top_a) [] = {
1891 /* optimize the alignment of the top of small letters to the pixel grid */
1893 PUSHB_1,
1897 /* %c, index of alignment blue zone */
1899 unsigned char PREP(align_top_b) [] = {
1901 RCVT,
1902 DUP,
1903 DUP,
1904 PUSHB_1,
1906 ADD,
1907 FLOOR, /* fitted = FLOOR(scaled + 40) */
1908 DUP, /* s: scaled scaled fitted fitted */
1909 ROLL,
1910 NEQ,
1911 IF, /* s: scaled fitted */
1912 PUSHB_1,
1913 sal_0x10000,
1915 MUL, /* scaled in 16.16 format */
1916 SWAP,
1917 DIV, /* (fitted / scaled) in 16.16 format */
1919 PUSHB_1,
1920 sal_scale,
1921 SWAP,
1926 unsigned char PREP(loop_cvt_a) [] = {
1928 /* loop over vertical CVT entries */
1929 PUSHB_4,
1933 /* %c, first vertical index */
1934 /* %c, last vertical index */
1936 unsigned char PREP(loop_cvt_b) [] = {
1938 bci_cvt_rescale,
1939 bci_loop,
1940 CALL,
1942 /* loop over blue refs */
1943 PUSHB_4,
1947 /* %c, first blue ref index */
1948 /* %c, last blue ref index */
1950 unsigned char PREP(loop_cvt_c) [] = {
1952 bci_cvt_rescale,
1953 bci_loop,
1954 CALL,
1956 /* loop over blue shoots */
1957 PUSHB_4,
1961 /* %c, first blue shoot index */
1962 /* %c, last blue shoot index */
1964 unsigned char PREP(loop_cvt_d) [] = {
1966 bci_cvt_rescale,
1967 bci_loop,
1968 CALL,
1969 EIF,
1973 unsigned char PREP(compute_extra_light_a) [] = {
1975 /* compute (vertical) `extra_light' flag */
1976 PUSHB_3,
1977 sal_is_extra_light,
1982 /* %c, index of vertical standard_width */
1984 unsigned char PREP(compute_extra_light_b) [] = {
1986 RCVT,
1987 GT, /* standard_width < 40 */
1992 unsigned char PREP(round_blues_a) [] = {
1994 /* use discrete values for blue zone widths */
1995 PUSHB_4,
1999 /* %c, first blue ref index */
2000 /* %c, last blue ref index */
2002 unsigned char PREP(round_blues_b) [] = {
2004 bci_blue_round,
2005 bci_loop,
2006 CALL
2010 /* XXX talatin.c: 1671 */
2011 /* XXX talatin.c: 1708 */
2012 /* XXX talatin.c: 2182 */
2015 #define COPY_PREP(snippet_name) \
2016 memcpy(buf_p, prep_ ## snippet_name, \
2017 sizeof (prep_ ## snippet_name)); \
2018 buf_p += sizeof (prep_ ## snippet_name);
2020 static FT_Error
2021 TA_table_build_prep(FT_Byte** prep,
2022 FT_ULong* prep_len,
2023 FONT* font)
2025 TA_LatinAxis vaxis;
2026 TA_LatinBlue blue_adjustment;
2027 FT_UInt i;
2029 FT_UInt buf_len;
2030 FT_UInt len;
2031 FT_Byte* buf;
2032 FT_Byte* buf_p;
2035 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
2036 blue_adjustment = NULL;
2038 for (i = 0; i < vaxis->blue_count; i++)
2040 if (vaxis->blues[i].flags & TA_LATIN_BLUE_ADJUSTMENT)
2042 blue_adjustment = &vaxis->blues[i];
2043 break;
2047 buf_len = sizeof (PREP(store_0x10000));
2049 if (blue_adjustment)
2050 buf_len += sizeof (PREP(align_top_a))
2052 + sizeof (PREP(align_top_b))
2053 + sizeof (PREP(loop_cvt_a))
2055 + sizeof (PREP(loop_cvt_b))
2057 + sizeof (PREP(loop_cvt_c))
2059 + sizeof (PREP(loop_cvt_d));
2061 buf_len += sizeof (PREP(compute_extra_light_a))
2063 + sizeof (PREP(compute_extra_light_b));
2065 if (CVT_BLUES_SIZE(font))
2066 buf_len += sizeof (PREP(round_blues_a))
2068 + sizeof (PREP(round_blues_b));
2070 /* buffer length must be a multiple of four */
2071 len = (buf_len + 3) & ~3;
2072 buf = (FT_Byte*)malloc(len);
2073 if (!buf)
2074 return FT_Err_Out_Of_Memory;
2076 /* pad end of buffer with zeros */
2077 buf[len - 1] = 0x00;
2078 buf[len - 2] = 0x00;
2079 buf[len - 3] = 0x00;
2081 /* copy cvt program into buffer and fill in the missing variables */
2082 buf_p = buf;
2084 COPY_PREP(store_0x10000);
2086 if (blue_adjustment)
2088 COPY_PREP(align_top_a);
2089 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
2090 + blue_adjustment - vaxis->blues);
2091 COPY_PREP(align_top_b);
2093 COPY_PREP(loop_cvt_a);
2094 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
2095 *(buf_p++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font)
2096 + CVT_VERT_WIDTHS_SIZE(font) - 1);
2097 COPY_PREP(loop_cvt_b);
2098 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
2099 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
2100 + CVT_BLUES_SIZE(font) - 1);
2101 COPY_PREP(loop_cvt_c);
2102 *(buf_p++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font);
2103 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
2104 + CVT_BLUES_SIZE(font) - 1);
2105 COPY_PREP(loop_cvt_d);
2108 COPY_PREP(compute_extra_light_a);
2109 *(buf_p++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font);
2110 COPY_PREP(compute_extra_light_b);
2112 if (CVT_BLUES_SIZE(font))
2114 COPY_PREP(round_blues_a);
2115 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
2116 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
2117 + CVT_BLUES_SIZE(font) - 1);
2118 COPY_PREP(round_blues_b);
2121 *prep = buf;
2122 *prep_len = buf_len;
2124 return FT_Err_Ok;
2128 FT_Error
2129 TA_sfnt_build_prep_table(SFNT* sfnt,
2130 FONT* font)
2132 FT_Error error;
2134 FT_Byte* prep_buf;
2135 FT_ULong prep_len;
2138 error = TA_sfnt_add_table_info(sfnt);
2139 if (error)
2140 return error;
2142 error = TA_table_build_prep(&prep_buf, &prep_len, font);
2143 if (error)
2144 return error;
2146 /* in case of success, `prep_buf' gets linked */
2147 /* and is eventually freed in `TA_font_unload' */
2148 error = TA_font_add_table(font,
2149 &sfnt->table_infos[sfnt->num_table_infos - 1],
2150 TTAG_prep, prep_len, prep_buf);
2151 if (error)
2153 free(prep_buf);
2154 return error;
2157 return FT_Err_Ok;
2161 /* we store the segments in the storage area; */
2162 /* each segment record consists of the first and last point */
2164 static FT_Byte*
2165 TA_sfnt_build_glyph_segments(SFNT* sfnt,
2166 FONT* font,
2167 FT_Byte* bufp)
2169 TA_GlyphHints hints = &font->loader->hints;
2170 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2171 TA_Point points = hints->points;
2172 TA_Segment segments = axis->segments;
2173 TA_Segment seg;
2174 TA_Segment seg_limit;
2176 FT_UInt* args;
2177 FT_UInt* arg;
2178 FT_UInt num_args;
2179 FT_UInt nargs;
2181 FT_Bool need_words = 0;
2183 FT_UInt i, j;
2184 FT_UInt num_storage;
2185 FT_UInt num_stack_elements;
2186 FT_UInt num_twilight_points;
2189 seg_limit = segments + axis->num_segments;
2190 num_args = 2 * axis->num_segments + 3;
2192 /* collect all arguments temporarily in an array (in reverse order) */
2193 /* so that we can easily split into chunks of 255 args */
2194 /* as needed by NPUSHB and NPUSHW, respectively */
2195 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
2196 if (!args)
2197 return NULL;
2199 arg = args + num_args - 1;
2201 if (axis->num_segments > 0xFF)
2202 need_words = 1;
2204 *(arg--) = bci_set_up_segments;
2205 *(arg--) = axis->num_segments;
2206 *(arg--) = sal_segment_offset;
2208 for (seg = segments; seg < seg_limit; seg++)
2210 FT_UInt first = seg->first - points;
2211 FT_UInt last = seg->last - points;
2214 *(arg--) = first;
2215 *(arg--) = last;
2217 if (first > 0xFF || last > 0xFF)
2218 need_words = 1;
2221 /* with most fonts it is very rare */
2222 /* that any of the pushed arguments is larger than 0xFF, */
2223 /* thus we refrain from further optimizing this case */
2225 arg = args;
2227 if (need_words)
2229 for (i = 0; i < num_args; i += 255)
2231 nargs = (num_args - i > 255) ? 255 : num_args - i;
2233 BCI(NPUSHW);
2234 BCI(nargs);
2235 for (j = 0; j < nargs; j++)
2237 BCI(HIGH(*arg));
2238 BCI(LOW(*arg));
2239 arg++;
2243 else
2245 for (i = 0; i < num_args; i += 255)
2247 nargs = (num_args - i > 255) ? 255 : num_args - i;
2249 BCI(NPUSHB);
2250 BCI(nargs);
2251 for (j = 0; j < nargs; j++)
2253 BCI(*arg);
2254 arg++;
2259 BCI(CALL);
2261 num_storage = sal_segment_offset + axis->num_segments * 2;
2262 if (num_storage > sfnt->max_storage)
2263 sfnt->max_storage = num_storage;
2265 num_twilight_points = axis->num_segments * 2;
2266 if (num_twilight_points > sfnt->max_twilight_points)
2267 sfnt->max_twilight_points = num_twilight_points;
2269 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
2270 if (num_stack_elements > sfnt->max_stack_elements)
2271 sfnt->max_stack_elements = num_stack_elements;
2273 free(args);
2275 return bufp;
2279 static FT_Bool
2280 TA_hints_record_is_different(Hints_Record* hints_records,
2281 FT_UInt num_hints_records,
2282 FT_Byte* start,
2283 FT_Byte* end)
2285 Hints_Record last_hints_record;
2288 if (!hints_records)
2289 return 1;
2291 /* we only need to compare with the last hints record */
2292 last_hints_record = hints_records[num_hints_records - 1];
2294 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
2295 return 1;
2297 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
2298 return 1;
2300 return 0;
2304 static FT_Error
2305 TA_add_hints_record(Hints_Record** hints_records,
2306 FT_UInt* num_hints_records,
2307 FT_Byte* start,
2308 Hints_Record hints_record)
2310 Hints_Record* hints_records_new;
2311 FT_UInt buf_len;
2312 /* at this point, `hints_record.buf' still points into `ins_buf' */
2313 FT_Byte* end = hints_record.buf;
2316 buf_len = (FT_UInt)(end - start);
2318 /* now fill the structure completely */
2319 hints_record.buf_len = buf_len;
2320 hints_record.buf = (FT_Byte*)malloc(buf_len);
2321 if (!hints_record.buf)
2322 return FT_Err_Out_Of_Memory;
2324 memcpy(hints_record.buf, start, buf_len);
2326 (*num_hints_records)++;
2327 hints_records_new =
2328 (Hints_Record*)realloc(*hints_records, *num_hints_records
2329 * sizeof (Hints_Record));
2330 if (!hints_records_new)
2332 free(hints_record.buf);
2333 (*num_hints_records)--;
2334 return FT_Err_Out_Of_Memory;
2336 else
2337 *hints_records = hints_records_new;
2339 (*hints_records)[*num_hints_records - 1] = hints_record;
2341 return FT_Err_Ok;
2345 static FT_Byte*
2346 TA_sfnt_emit_hints_record(SFNT* sfnt,
2347 Hints_Record* hints_record,
2348 FT_Byte* bufp)
2350 FT_Byte* p;
2351 FT_Byte* endp;
2352 FT_Bool need_words = 0;
2354 FT_UInt i, j;
2355 FT_UInt num_arguments;
2356 FT_UInt num_args;
2357 FT_UInt num_stack_elements;
2360 /* check whether any argument is larger than 0xFF */
2361 endp = hints_record->buf + hints_record->buf_len;
2362 for (p = hints_record->buf; p < endp; p += 2)
2363 if (*p)
2364 need_words = 1;
2366 /* with most fonts it is very rare */
2367 /* that any of the pushed arguments is larger than 0xFF, */
2368 /* thus we refrain from further optimizing this case */
2370 num_arguments = hints_record->buf_len / 2;
2371 p = endp - 2;
2373 if (need_words)
2375 for (i = 0; i < num_arguments; i += 255)
2377 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2379 BCI(NPUSHW);
2380 BCI(num_args);
2381 for (j = 0; j < num_args; j++)
2383 BCI(*p);
2384 BCI(*(p + 1));
2385 p -= 2;
2389 else
2391 /* we only need the lower bytes */
2392 p++;
2394 for (i = 0; i < num_arguments; i += 255)
2396 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2398 BCI(NPUSHB);
2399 BCI(num_args);
2400 for (j = 0; j < num_args; j++)
2402 BCI(*p);
2403 p -= 2;
2408 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
2409 if (num_stack_elements > sfnt->max_stack_elements)
2410 sfnt->max_stack_elements = sfnt->max_stack_elements;
2412 return bufp;
2416 static FT_Byte*
2417 TA_sfnt_emit_hints_records(SFNT* sfnt,
2418 Hints_Record* hints_records,
2419 FT_UInt num_hints_records,
2420 FT_Byte* bufp)
2422 FT_UInt i;
2423 Hints_Record* hints_record;
2426 hints_record = hints_records;
2428 for (i = 0; i < num_hints_records - 1; i++)
2430 BCI(MPPEM);
2431 if (hints_record->size > 0xFF)
2433 BCI(PUSHW_1);
2434 BCI(HIGH((hints_record + 1)->size));
2435 BCI(LOW((hints_record + 1)->size));
2437 else
2439 BCI(PUSHB_1);
2440 BCI((hints_record + 1)->size);
2442 BCI(LT);
2443 BCI(IF);
2444 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2445 BCI(ELSE);
2447 hints_record++;
2450 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2452 for (i = 0; i < num_hints_records - 1; i++)
2453 BCI(EIF);
2455 BCI(PUSHB_1);
2456 BCI(bci_hint_glyph);
2457 BCI(CALL);
2459 return bufp;
2463 static void
2464 TA_free_hints_records(Hints_Record* hints_records,
2465 FT_UInt num_hints_records)
2467 FT_UInt i;
2470 for (i = 0; i < num_hints_records; i++)
2471 free(hints_records[i].buf);
2473 free(hints_records);
2477 static FT_Byte*
2478 TA_hints_recorder_handle_segments(FT_Byte* bufp,
2479 TA_Segment segments,
2480 TA_Edge edge)
2482 TA_Segment seg;
2483 FT_UInt seg_idx;
2484 FT_UInt num_segs = 0;
2487 seg_idx = edge->first - segments;
2489 /* we store everything as 16bit numbers */
2490 *(bufp++) = HIGH(seg_idx);
2491 *(bufp++) = LOW(seg_idx);
2493 seg = edge->first->edge_next;
2494 while (seg != edge->first)
2496 seg = seg->edge_next;
2497 num_segs++;
2500 *(bufp++) = HIGH(num_segs);
2501 *(bufp++) = LOW(num_segs);
2503 seg = edge->first->edge_next;
2504 while (seg != edge->first)
2506 seg_idx = seg - segments;
2507 seg = seg->edge_next;
2509 *(bufp++) = HIGH(seg_idx);
2510 *(bufp++) = LOW(seg_idx);
2513 return bufp;
2517 static void
2518 TA_hints_recorder(TA_Action action,
2519 TA_GlyphHints hints,
2520 TA_Dimension dim,
2521 void* arg1,
2522 void* arg2,
2523 void* arg3)
2525 TA_AxisHints axis = &hints->axis[dim];
2526 TA_Segment segments = axis->segments;
2528 Recorder* recorder = (Recorder*)hints->user;
2529 FONT* font = recorder->font;
2530 FT_Byte* p = recorder->hints_record.buf;
2533 if (dim == TA_DIMENSION_HORZ)
2534 return;
2536 /* we ignore the BOUND action since the information is handled */
2537 /* in `ta_adjust_bound' and `ta_stem_bound' */
2538 if (action == ta_bound)
2539 return;
2541 *(p++) = 0;
2542 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2544 switch (action)
2546 case ta_adjust_bound:
2547 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2548 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2549 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2550 break;
2552 case ta_stem_bound:
2553 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2554 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2555 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2556 break;
2558 case ta_link:
2560 TA_Edge base_edge = (TA_Edge)arg1;
2561 TA_Edge stem_edge = (TA_Edge)arg2;
2564 *(p++) = 0;
2565 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
2566 *(p++) = 0;
2567 *(p++) = base_edge->flags & TA_EDGE_ROUND;
2568 *(p++) = HIGH(base_edge->first - segments);
2569 *(p++) = LOW(base_edge->first - segments);
2570 *(p++) = HIGH(stem_edge->first - segments);
2571 *(p++) = LOW(stem_edge->first - segments);
2573 p = TA_hints_recorder_handle_segments(p, segments, stem_edge);
2575 break;
2577 case ta_anchor:
2579 TA_Edge edge = (TA_Edge)arg1;
2580 TA_Edge edge2 = (TA_Edge)arg2;
2583 *(p++) = 0;
2584 *(p++) = edge2->flags & TA_EDGE_SERIF;
2585 *(p++) = 0;
2586 *(p++) = edge->flags & TA_EDGE_ROUND;
2587 *(p++) = HIGH(edge->first - segments);
2588 *(p++) = LOW(edge->first - segments);
2589 *(p++) = HIGH(edge2->first - segments);
2590 *(p++) = LOW(edge2->first - segments);
2592 p = TA_hints_recorder_handle_segments(p, segments, edge);
2594 break;
2596 case ta_blue_anchor:
2598 TA_Edge edge = (TA_Edge)arg1;
2599 TA_Edge blue = (TA_Edge)arg2;
2602 *(p++) = HIGH(blue->first - segments);
2603 *(p++) = LOW(blue->first - segments);
2605 if (edge->best_blue_is_shoot)
2607 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2608 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2610 else
2612 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2613 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2616 *(p++) = HIGH(edge->first - segments);
2617 *(p++) = LOW(edge->first - segments);
2619 p = TA_hints_recorder_handle_segments(p, segments, edge);
2621 break;
2623 case ta_adjust:
2624 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2625 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2626 break;
2628 case ta_stem:
2629 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2630 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2631 break;
2633 case ta_blue:
2635 TA_Edge edge = (TA_Edge)arg1;
2638 if (edge->best_blue_is_shoot)
2640 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2641 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2643 else
2645 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2646 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2649 *(p++) = HIGH(edge->first - segments);
2650 *(p++) = LOW(edge->first - segments);
2652 p = TA_hints_recorder_handle_segments(p, segments, edge);
2654 break;
2656 case ta_serif:
2657 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2658 break;
2660 case ta_serif_anchor:
2661 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2662 break;
2664 case ta_serif_link1:
2665 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2666 break;
2668 case ta_serif_link2:
2669 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2670 break;
2672 /* to pacify the compiler */
2673 case ta_bound:
2674 break;
2677 recorder->hints_record.num_actions++;
2678 recorder->hints_record.buf = p;
2682 static FT_Error
2683 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2684 FONT* font,
2685 FT_Long idx)
2687 FT_Face face = sfnt->face;
2688 FT_Error error;
2690 FT_Byte* ins_buf;
2691 FT_UInt ins_len;
2692 FT_Byte* bufp;
2694 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2695 glyf_Data* data = (glyf_Data*)glyf_table->data;
2696 GLYPH* glyph = &data->glyphs[idx];
2698 TA_GlyphHints hints;
2700 FT_UInt num_hints_records;
2701 Hints_Record* hints_records;
2703 Recorder recorder;
2705 FT_UInt size;
2708 if (idx < 0)
2709 return FT_Err_Invalid_Argument;
2711 /* computing the segments is resolution independent, */
2712 /* thus the pixel size in this call is arbitrary */
2713 error = FT_Set_Pixel_Sizes(face, 20, 20);
2714 if (error)
2715 return error;
2717 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2718 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
2719 if (error)
2720 return error;
2722 /* do nothing if we have an empty glyph */
2723 if (!face->glyph->outline.n_contours)
2724 return FT_Err_Ok;
2726 hints = &font->loader->hints;
2728 /* we allocate a buffer which is certainly large enough */
2729 /* to hold all of the created bytecode instructions; */
2730 /* later on it gets reallocated to its real size */
2731 ins_len = hints->num_points * 1000;
2732 ins_buf = (FT_Byte*)malloc(ins_len);
2733 if (!ins_buf)
2734 return FT_Err_Out_Of_Memory;
2736 /* initialize array with an invalid bytecode */
2737 /* so that we can easily find the array length at reallocation time */
2738 memset(ins_buf, INS_A0, ins_len);
2740 bufp = TA_sfnt_build_glyph_segments(sfnt, font, ins_buf);
2742 /* now we loop over a large range of pixel sizes */
2743 /* to find hints records which get pushed onto the bytecode stack */
2744 num_hints_records = 0;
2745 hints_records = NULL;
2747 #ifdef DEBUGGING
2748 printf("glyph %ld\n", idx);
2749 #endif
2751 /* we temporarily use `ins_buf' to record the current glyph hints, */
2752 /* leaving two bytes at the beginning so that the number of actions */
2753 /* can be inserted later on */
2754 recorder.font = font;
2755 ta_loader_register_hints_recorder(font->loader,
2756 TA_hints_recorder,
2757 (void *)&recorder);
2759 for (size = 8; size <= 1000; size++)
2761 /* rewind buffer pointer for recorder */
2762 recorder.hints_record.buf = bufp + 2;
2763 recorder.hints_record.num_actions = 0;
2764 recorder.hints_record.size = size;
2766 error = FT_Set_Pixel_Sizes(face, size, size);
2767 if (error)
2768 goto Err;
2770 /* calling `ta_loader_load_glyph' uses the */
2771 /* `TA_hints_recorder' function as a callback, */
2772 /* modifying `hints_record' */
2773 error = ta_loader_load_glyph(font->loader, face, idx, 0);
2774 if (error)
2775 goto Err;
2777 /* store the number of actions in `ins_buf' */
2778 *bufp = HIGH(recorder.hints_record.num_actions);
2779 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
2781 if (TA_hints_record_is_different(hints_records,
2782 num_hints_records,
2783 bufp, recorder.hints_record.buf))
2785 #ifdef DEBUGGING
2787 FT_Byte* p;
2790 printf(" %d:\n", size);
2791 for (p = bufp; p < recorder.hints_record.buf; p += 2)
2792 printf(" %2d", *p * 256 + *(p + 1));
2793 printf("\n");
2795 #endif
2797 error = TA_add_hints_record(&hints_records,
2798 &num_hints_records,
2799 bufp, recorder.hints_record);
2800 if (error)
2801 goto Err;
2805 if (num_hints_records == 1 && !hints_records[0].num_actions)
2807 /* don't emit anything if we only have a single empty record */
2808 ins_len = 0;
2810 else
2812 FT_Byte* p = bufp;
2815 /* otherwise, clear the temporarily used part of `ins_buf' */
2816 while (*p != INS_A0)
2817 *(p++) = INS_A0;
2819 bufp = TA_sfnt_emit_hints_records(sfnt,
2820 hints_records, num_hints_records,
2821 bufp);
2823 /* we are done, so reallocate the instruction array to its real size */
2824 if (*bufp == INS_A0)
2826 /* search backwards */
2827 while (*bufp == INS_A0)
2828 bufp--;
2829 bufp++;
2831 else
2833 /* search forwards */
2834 while (*bufp != INS_A0)
2835 bufp++;
2838 ins_len = bufp - ins_buf;
2841 if (ins_len > sfnt->max_instructions)
2842 sfnt->max_instructions = ins_len;
2844 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2845 glyph->ins_len = ins_len;
2847 TA_free_hints_records(hints_records, num_hints_records);
2849 return FT_Err_Ok;
2851 Err:
2852 TA_free_hints_records(hints_records, num_hints_records);
2853 free(ins_buf);
2855 return error;
2859 FT_Error
2860 TA_sfnt_build_glyf_hints(SFNT* sfnt,
2861 FONT* font)
2863 FT_Face face = sfnt->face;
2864 FT_Long idx;
2865 FT_Error error;
2868 for (idx = 0; idx < face->num_glyphs; idx++)
2870 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
2871 if (error)
2872 return error;
2875 return FT_Err_Ok;
2878 /* end of tabytecode.c */