Fix reallocation of bytecode buffer.
[ttfautohint.git] / src / tabytecode.c
blob972d663d03fcda493148d9c61a99b477c058b8a7
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_limit sal_j + 1
263 #define sal_scale sal_limit + 1
264 #define sal_0x10000 sal_scale + 1
265 #define sal_is_extra_light sal_0x10000 + 1
266 #define sal_pos sal_is_extra_light + 1
267 #define sal_anchor sal_pos + 1
268 #define sal_point_min sal_anchor + 1
269 #define sal_point_max sal_point_min + 1
270 #define sal_segment_offset sal_point_max + 1 /* must be last */
273 /* we need the following macro */
274 /* so that `func_name' doesn't get replaced with its #defined value */
275 /* (as defined in `tabytecode.h') */
277 #define FPGM(func_name) fpgm_ ## func_name
280 /* in the comments below, the top of the stack (`s:') */
281 /* is the rightmost element; the stack is shown */
282 /* after the instruction on the same line has been executed */
284 /* point 0 in the twilight zone (zp0) is originally located */
285 /* at the origin; we don't change that */
288 * bci_compute_stem_width
290 * This is the equivalent to the following code from function
291 * `ta_latin_compute_stem_width':
293 * dist = ABS(width)
295 * if (stem_is_serif
296 * && dist < 3*64)
297 * || is_extra_light:
298 * return width
299 * else if base_is_round:
300 * if dist < 80
301 * dist = 64
302 * else if dist < 56:
303 * dist = 56
305 * delta = ABS(dist - std_width)
307 * if delta < 40:
308 * dist = MIN(48, std_width)
309 * goto End
311 * if dist < 3*64:
312 * delta = dist
313 * dist = FLOOR(dist)
314 * delta = delta - dist
316 * if delta < 10:
317 * dist = dist + delta
318 * else if delta < 32:
319 * dist = dist + 10
320 * else if delta < 54:
321 * dist = dist + 54
322 * else
323 * dist = dist + delta
324 * else
325 * dist = ROUND(dist)
327 * End:
328 * if width < 0:
329 * dist = -dist
330 * return dist
333 * in: width
334 * stem_is_serif
335 * base_is_round
336 * out: new_width
337 * sal: sal_is_extra_light
338 * CVT: std_width
341 unsigned char FPGM(bci_compute_stem_width_a) [] = {
343 PUSHB_1,
344 bci_compute_stem_width,
345 FDEF,
347 DUP,
348 ABS, /* s: base_is_round stem_is_serif width dist */
350 DUP,
351 PUSHB_1,
352 3*64,
353 LT, /* dist < 3*64 */
355 PUSHB_1,
357 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
358 AND, /* stem_is_serif && dist < 3*64 */
360 PUSHB_1,
361 sal_is_extra_light,
363 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
365 IF, /* s: base_is_round width dist */
366 POP,
367 SWAP,
368 POP, /* s: width */
370 ELSE,
371 ROLL, /* s: width dist base_is_round */
372 IF, /* s: width dist */
373 DUP,
374 PUSHB_1,
376 LT, /* dist < 80 */
377 IF, /* s: width dist */
378 POP,
379 PUSHB_1,
380 64, /* dist = 64 */
381 EIF,
383 ELSE,
384 DUP,
385 PUSHB_1,
387 LT, /* dist < 56 */
388 IF, /* s: width dist */
389 POP,
390 PUSHB_1,
391 56, /* dist = 56 */
392 EIF,
393 EIF,
395 DUP, /* s: width dist dist */
396 PUSHB_1,
400 /* %c, index of std_width */
402 unsigned char FPGM(bci_compute_stem_width_b) [] = {
404 RCVT,
405 SUB,
406 ABS, /* s: width dist delta */
408 PUSHB_1,
410 LT, /* delta < 40 */
411 IF, /* s: width dist */
412 POP,
413 PUSHB_2,
418 /* %c, index of std_width */
420 unsigned char FPGM(bci_compute_stem_width_c) [] = {
422 RCVT,
423 MIN, /* dist = min(48, std_width) */
425 ELSE,
426 DUP, /* s: width dist dist */
427 PUSHB_1,
428 3*64,
429 LT, /* dist < 3*64 */
431 DUP, /* s: width delta dist */
432 FLOOR, /* dist = FLOOR(dist) */
433 DUP, /* s: width delta dist dist */
434 ROLL,
435 ROLL, /* s: width dist delta dist */
436 SUB, /* delta = delta - dist */
438 DUP, /* s: width dist delta delta */
439 PUSHB_1,
441 LT, /* delta < 10 */
442 IF, /* s: width dist delta */
443 ADD, /* dist = dist + delta */
445 ELSE,
446 DUP,
447 PUSHB_1,
449 LT, /* delta < 32 */
451 POP,
452 PUSHB_1,
454 ADD, /* dist = dist + 10 */
456 ELSE,
457 DUP,
458 PUSHB_1,
460 LT, /* delta < 54 */
462 POP,
463 PUSHB_1,
465 ADD, /* dist = dist + 54 */
467 ELSE,
468 ADD, /* dist = dist + delta */
470 EIF,
471 EIF,
472 EIF,
474 ELSE,
475 PUSHB_1,
477 ADD,
478 FLOOR, /* dist = round(dist) */
480 EIF,
481 EIF,
483 SWAP, /* s: dist width */
484 PUSHB_1,
486 LT, /* width < 0 */
488 NEG, /* dist = -dist */
489 EIF,
490 EIF,
491 EIF,
493 ENDF,
499 * bci_loop
501 * Take a range and a function number and apply the function to all
502 * elements of the range. The called function must not change the
503 * stack.
505 * in: func_num
506 * end
507 * start
509 * uses: sal_i (counter initialized with `start')
510 * sal_limit (`end')
513 unsigned char FPGM(bci_loop) [] = {
515 PUSHB_1,
516 bci_loop,
517 FDEF,
519 ROLL,
520 ROLL, /* s: func_num start end */
521 PUSHB_1,
522 sal_limit,
523 SWAP,
526 PUSHB_1,
527 sal_i,
528 SWAP,
531 /* start_loop: */
532 PUSHB_1,
533 sal_i,
535 PUSHB_1,
536 sal_limit,
538 LTEQ, /* start <= end */
539 IF, /* s: func_num */
540 DUP,
541 CALL,
542 PUSHB_3,
543 sal_i,
545 sal_i,
547 ADD, /* start = start + 1 */
550 PUSHB_1,
552 NEG,
553 JMPR, /* goto start_loop */
554 ELSE,
555 POP,
556 EIF,
558 ENDF,
564 * bci_cvt_rescale
566 * Rescale CVT value by a given factor.
568 * uses: sal_i (CVT index)
569 * sal_scale (scale in 16.16 format)
572 unsigned char FPGM(bci_cvt_rescale) [] = {
574 PUSHB_1,
575 bci_cvt_rescale,
576 FDEF,
578 PUSHB_1,
579 sal_i,
581 DUP,
582 RCVT,
583 PUSHB_1,
584 sal_scale,
586 MUL, /* CVT * scale * 2^10 */
587 PUSHB_1,
588 sal_0x10000,
590 DIV, /* CVT * scale */
592 WCVTP,
594 ENDF,
600 * bci_loop_sal_assign
602 * Apply the WS instruction repeatedly to stack data.
604 * in: counter (N)
605 * offset
606 * data_0
607 * data_1
608 * ...
609 * data_(N-1)
611 * uses: bci_sal_assign
614 unsigned char FPGM(bci_sal_assign) [] = {
616 PUSHB_1,
617 bci_sal_assign,
618 FDEF,
620 DUP,
621 ROLL, /* s: offset offset data */
624 PUSHB_1,
626 ADD, /* s: (offset + 1) */
628 ENDF,
632 unsigned char FPGM(bci_loop_sal_assign) [] = {
634 PUSHB_1,
635 bci_loop_sal_assign,
636 FDEF,
638 /* process the stack, popping off the elements in a loop */
639 PUSHB_1,
640 bci_sal_assign,
641 LOOPCALL,
643 /* clean up stack */
644 POP,
646 ENDF,
652 * bci_blue_round
654 * Round a blue ref value and adjust its corresponding shoot value.
656 * uses: sal_i (CVT index)
660 unsigned char FPGM(bci_blue_round_a) [] = {
662 PUSHB_1,
663 bci_blue_round,
664 FDEF,
666 PUSHB_1,
667 sal_i,
669 DUP,
670 RCVT, /* s: ref_idx ref */
672 DUP,
673 PUSHB_1,
675 ADD,
676 FLOOR,
677 SWAP, /* s: ref_idx round(ref) ref */
679 PUSHB_2,
683 /* %c, blue_count */
685 unsigned char FPGM(bci_blue_round_b) [] = {
688 CINDEX,
689 ADD, /* s: ref_idx round(ref) ref shoot_idx */
690 DUP,
691 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
693 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
694 SWAP,
695 SUB, /* s: ref_idx round(ref) shoot_idx dist */
696 DUP,
697 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
699 DUP,
700 PUSHB_1,
702 LT, /* delta < 32 */
704 POP,
705 PUSHB_1,
706 0, /* delta = 0 */
708 ELSE,
709 PUSHB_1,
711 LT, /* delta < 48 */
713 PUSHB_1,
714 32, /* delta = 32 */
716 ELSE,
717 PUSHB_1,
718 64, /* delta = 64 */
719 EIF,
720 EIF,
722 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
723 PUSHB_1,
725 LT, /* dist < 0 */
727 NEG, /* delta = -delta */
728 EIF,
730 PUSHB_1,
732 CINDEX,
733 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
735 WCVTP,
736 WCVTP,
738 ENDF,
744 * bci_get_point_extrema
746 * An auxiliary function for `bci_create_segment_point'.
748 * in: point-1
749 * out: point
751 * sal: sal_point_min
752 * sal_point_max
755 unsigned char FPGM(bci_get_point_extrema) [] = {
757 PUSHB_1,
758 bci_get_point_extrema,
759 FDEF,
761 PUSHB_1,
763 ADD, /* s: point */
764 DUP,
765 DUP,
767 /* check whether current point is a new minimum */
768 PUSHB_1,
769 sal_point_min,
770 RS, /* s: point point point point_min */
771 MD_orig,
772 /* if distance is negative, we have a new minimum */
773 PUSHB_1,
776 IF, /* s: point point */
777 DUP,
778 PUSHB_1,
779 sal_point_min,
780 SWAP,
782 EIF,
784 /* check whether current point is a new maximum */
785 PUSHB_1,
786 sal_point_max,
787 RS, /* s: point point point_max */
788 MD_orig,
789 /* if distance is positive, we have a new maximum */
790 PUSHB_1,
793 IF, /* s: point point */
794 PUSHB_1,
795 sal_point_max,
796 SWAP,
798 ELSE,
799 POP,
800 EIF, /* s: point */
802 ENDF,
808 * bci_create_segment_point
810 * Construct a point in the twilight zone which represents a segment.
811 * This function is used by `bci_create_segment_points'.
813 * uses: bci_get_point_extrema
815 * sal: sal_i (start of current segment)
816 * sal_j (current twilight point)
817 * sal_point_min
818 * sal_point_max
821 unsigned char FPGM(bci_create_segment_point) [] = {
823 PUSHB_1,
824 bci_create_segment_point,
825 FDEF,
827 PUSHB_1,
828 sal_i,
830 RS, /* s: start_point */
831 DUP,
833 /* increase `sal_i'; with the outer loop, this makes sal_i += 2 */
834 PUSHB_2,
836 sal_i,
838 ADD,
839 DUP,
840 PUSHB_1,
841 sal_i,
842 SWAP,
845 SWAP, /* s: start_point end_point start_point */
847 /* initialize inner loop */
848 DUP,
849 PUSHB_1,
850 sal_point_min,
851 SWAP,
852 WS, /* sal_point_min = start_point */
853 DUP,
854 PUSHB_1,
855 sal_point_max,
856 SWAP,
857 WS, /* sal_point_max = start_point */
859 SUB, /* s: start_point loop_count */
861 PUSHB_2,
864 SZP0, /* set zp0 to normal zone 1 */
865 SZP1, /* set zp1 to normal zone 1 */
867 PUSHB_1,
868 bci_get_point_extrema,
869 LOOPCALL,
870 /* clean up stack */
871 POP,
873 /* the twilight point representing a segment */
874 /* is in the middle between the minimum and maximum */
875 PUSHB_1,
876 sal_point_max,
878 PUSHB_1,
879 sal_point_min,
881 MD_orig,
882 PUSHB_1,
883 32, /* do the division with proper rounding */
884 ADD,
885 PUSHB_1,
886 2*64,
887 DIV, /* s: delta */
889 PUSHB_4,
890 sal_j,
893 sal_point_min,
895 MDAP_noround, /* set rp0 and rp1 tp `sal_point_min' */
896 SZP1, /* set zp1 to twilight zone 0 */
897 SZP2, /* set zp2 to twilight zone 0 */
900 DUP, /* delta point[sal_j] point[sal_j] */
901 ALIGNRP, /* align `point[sal_j]' with `sal_point_min' */
902 SWAP,
903 SHPIX, /* shift `point[sal_j]' by `delta' */
905 PUSHB_3,
906 sal_j,
908 sal_j,
910 ADD, /* twilight_point = twilight_point + 1 */
913 ENDF,
919 * bci_create_segment_points
921 * Construct points in the twilight zone which represent segments. This
922 * function searches the points of a segment with the minimum and maximum
923 * y-values, then takes the median.
925 * in: num_segments
927 * uses: bci_create_segment_point
929 * sal: sal_i (start of current segment)
930 * sal_j (current twilight point)
933 unsigned char FPGM(bci_create_segment_points) [] = {
935 PUSHB_1,
936 bci_create_segment_points,
937 FDEF,
939 DUP,
940 ADD,
941 PUSHB_2,
942 sal_segment_offset,
943 sal_segment_offset,
944 ROLL,
945 ADD, /* s: start_seg_1 end_seg_N */
947 PUSHB_2,
948 sal_j,
952 PUSHB_2,
953 bci_create_segment_point,
954 bci_loop,
955 CALL,
957 /* clean up stack */
958 POP,
960 ENDF,
964 unsigned char FPGM(bci_handle_segment) [] = {
966 PUSHB_1,
967 bci_handle_segment,
968 FDEF,
970 POP, /* XXX segment */
972 ENDF,
978 * bci_align_segment
980 * Align all points in a segment to the value in `sal_pos'.
982 * in: segment_index
984 * sal: sal_pos
987 unsigned char FPGM(bci_align_segment) [] = {
989 PUSHB_1,
990 bci_align_segment,
991 FDEF,
993 PUSHB_6,
996 sal_pos,
1000 SZP0, /* set zp0 to twilight zone 0 */
1001 SZP1, /* set zp1 to twilight zone 0 */
1003 /* we can't directly set rp0 to a stack value */
1004 MDAP_noround, /* reset rp0 (and rp1) to the origin in the twilight zone */
1006 MSIRP_rp0, /* set point 1 and rp0 in the twilight zone to `sal_pos' */
1008 SZP1, /* set zp1 to normal zone 1 */
1010 /* we need the values of `sal_segment_offset + 2*segment_index' */
1011 /* and `sal_segment_offset + 2*segment_index + 1' */
1012 DUP,
1013 ADD,
1014 PUSHB_1,
1015 sal_segment_offset,
1016 ADD,
1017 DUP,
1019 SWAP,
1020 PUSHB_1,
1022 ADD,
1023 RS, /* s: first last */
1025 /* start_loop: */
1026 PUSHB_1,
1028 CINDEX, /* s: first last first */
1029 PUSHB_1,
1031 CINDEX, /* s: first last first last */
1032 LTEQ, /* first <= end */
1033 IF, /* s: first last */
1034 SWAP,
1035 DUP, /* s: last first first */
1036 ALIGNRP, /* align point with index `first' with rp0 */
1038 PUSHB_1,
1040 ADD, /* first = first + 1 */
1041 SWAP, /* s: first last */
1043 PUSHB_1,
1045 NEG,
1046 JMPR, /* goto start_loop */
1047 ELSE,
1048 POP,
1049 POP,
1050 EIF,
1052 ENDF,
1056 unsigned char FPGM(bci_handle_segments) [] = {
1058 PUSHB_1,
1059 bci_handle_segments,
1060 FDEF,
1062 POP, /* XXX first segment */
1064 PUSHB_1,
1065 bci_handle_segment,
1066 LOOPCALL,
1068 ENDF,
1074 * bci_align_segments
1076 * Align segments to the value in `sal_pos'.
1078 * in: first_segment
1079 * loop_counter (N)
1080 * segment_1
1081 * segment_2
1082 * ...
1083 * segment_N
1085 * sal: sal_pos
1087 * uses: handle_segment
1091 unsigned char FPGM(bci_align_segments) [] = {
1093 PUSHB_1,
1094 bci_align_segments,
1095 FDEF,
1097 PUSHB_1,
1098 bci_align_segment,
1099 CALL,
1101 PUSHB_1,
1102 bci_align_segment,
1103 LOOPCALL,
1105 ENDF,
1110 unsigned char FPGM(bci_action_adjust_bound) [] = {
1112 PUSHB_1,
1113 bci_action_adjust_bound,
1114 FDEF,
1116 PUSHB_1,
1117 bci_handle_segments,
1118 CALL,
1119 PUSHB_1,
1120 bci_handle_segments,
1121 CALL,
1122 PUSHB_1,
1123 bci_handle_segments,
1124 CALL,
1126 /* XXX */
1128 ENDF,
1132 unsigned char FPGM(bci_action_stem_bound) [] = {
1134 PUSHB_1,
1135 bci_action_stem_bound,
1136 FDEF,
1138 PUSHB_1,
1139 bci_handle_segments,
1140 CALL,
1141 PUSHB_1,
1142 bci_handle_segments,
1143 CALL,
1144 PUSHB_1,
1145 bci_handle_segments,
1146 CALL,
1148 /* XXX */
1150 ENDF,
1156 * bci_action_link
1158 * Handle the LINK action to link an edge to another one.
1160 * in: base_point
1161 * stem_point
1162 * stem_is_serif
1163 * base_is_round
1164 * ... stuff for bci_align_segments ...
1166 * sal: sal_pos
1168 * XXX: Instead of `base_point', use the median of the first segment in the
1169 * base edge.
1172 unsigned char FPGM(bci_action_link) [] = {
1174 PUSHB_1,
1175 bci_action_link,
1176 FDEF,
1178 PUSHB_5,
1180 sal_pos,
1184 SZP0, /* set zp0 to normal zone 1 */
1185 SZP1, /* set zp1 to twilight zone 0 */
1186 CINDEX, /* s: ... stem_point base_point 1 sal_pos base_point */
1188 /* get distance between base_point and twilight point 0 (at origin) */
1189 PUSHB_1,
1191 MD_cur, /* s: ... stem_point base_point 1 sal_pos base_point_y_pos */
1192 WS, /* sal_pos: base_point_y_pos */
1194 SZP1, /* set zp1 to normal zone 1 */
1196 MD_orig, /* s: base_is_round stem_is_serif dist */
1198 PUSHB_1,
1199 bci_compute_stem_width,
1200 CALL, /* s: new_dist */
1202 PUSHB_1,
1203 sal_pos,
1205 ADD,
1206 PUSHB_1,
1207 sal_pos,
1208 SWAP,
1209 WS, /* sal_pos: base_point_y_pos + new_dist */
1211 PUSHB_1,
1212 bci_align_segments,
1213 CALL,
1215 ENDF,
1219 unsigned char FPGM(bci_action_anchor) [] = {
1221 PUSHB_1,
1222 bci_action_anchor,
1223 FDEF,
1225 PUSHB_1,
1226 bci_handle_segments,
1227 CALL,
1228 PUSHB_1,
1229 bci_handle_segments,
1230 CALL,
1232 /* XXX */
1234 ENDF,
1240 * bci_action_blue_anchor
1242 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1243 * and to set the edge anchor.
1245 * in: anchor_point
1246 * blue_cvt_idx
1247 * ... stuff for bci_align_segments ...
1249 * sal: sal_anchor
1250 * sal_pos
1252 * XXX: Instead of `anchor_point', use the median of the first segment in the
1253 * base edge.
1256 unsigned char FPGM(bci_action_blue_anchor) [] = {
1258 PUSHB_1,
1259 bci_action_blue_anchor,
1260 FDEF,
1262 /* store anchor point number in `sal_anchor' */
1263 PUSHB_1,
1264 sal_anchor,
1265 SWAP,
1268 /* store blue position in `sal_pos' */
1269 RCVT,
1270 PUSHB_1,
1271 sal_pos,
1272 SWAP,
1275 PUSHB_1,
1276 bci_align_segments,
1277 CALL,
1279 ENDF,
1283 unsigned char FPGM(bci_action_adjust) [] = {
1285 PUSHB_1,
1286 bci_action_adjust,
1287 FDEF,
1289 PUSHB_1,
1290 bci_handle_segments,
1291 CALL,
1292 PUSHB_1,
1293 bci_handle_segments,
1294 CALL,
1296 /* XXX */
1298 ENDF,
1302 unsigned char FPGM(bci_action_stem) [] = {
1304 PUSHB_1,
1305 bci_action_stem,
1306 FDEF,
1308 PUSHB_1,
1309 bci_handle_segments,
1310 CALL,
1311 PUSHB_1,
1312 bci_handle_segments,
1313 CALL,
1315 /* XXX */
1317 ENDF,
1323 * bci_action_blue
1325 * Handle the BLUE action to align an edge with a blue zone.
1327 * in: blue_cvt_idx
1328 * ... stuff for bci_align_segments ...
1330 * sal: sal_pos
1333 unsigned char FPGM(bci_action_blue) [] = {
1335 PUSHB_1,
1336 bci_action_blue,
1337 FDEF,
1339 /* store blue position in `sal_pos' */
1340 RCVT,
1341 PUSHB_1,
1342 sal_pos,
1343 SWAP,
1346 PUSHB_1,
1347 bci_align_segments,
1348 CALL,
1350 ENDF,
1354 unsigned char FPGM(bci_action_serif) [] = {
1356 PUSHB_1,
1357 bci_action_serif,
1358 FDEF,
1360 PUSHB_1,
1361 bci_handle_segments,
1362 CALL,
1364 /* XXX */
1366 ENDF,
1370 unsigned char FPGM(bci_action_serif_anchor) [] = {
1372 PUSHB_1,
1373 bci_action_serif_anchor,
1374 FDEF,
1376 PUSHB_1,
1377 bci_handle_segments,
1378 CALL,
1380 /* XXX */
1382 ENDF,
1386 unsigned char FPGM(bci_action_serif_link1) [] = {
1388 PUSHB_1,
1389 bci_action_serif_link1,
1390 FDEF,
1392 PUSHB_1,
1393 bci_handle_segments,
1394 CALL,
1396 /* XXX */
1398 ENDF,
1402 unsigned char FPGM(bci_action_serif_link2) [] = {
1404 PUSHB_1,
1405 bci_action_serif_link2,
1406 FDEF,
1408 PUSHB_1,
1409 bci_handle_segments,
1410 CALL,
1412 /* XXX */
1414 ENDF,
1420 * bci_handle_action
1422 * Execute function.
1424 * in: function_index
1427 unsigned char FPGM(bci_handle_action) [] = {
1429 PUSHB_1,
1430 bci_handle_action,
1431 FDEF,
1433 CALL,
1435 ENDF,
1441 * bci_hint_glyph
1443 * This is the top-level glyph hinting function
1444 * which parses the arguments on the stack and calls subroutines.
1446 * in: num_actions (M)
1447 * action_0_func_idx
1448 * ... data ...
1449 * action_1_func_idx
1450 * ... data ...
1451 * ...
1452 * action_M_func_idx
1453 * ... data ...
1455 * uses: bci_handle_action
1456 * bci_action_adjust_bound
1457 * bci_action_stem_bound
1459 * bci_action_link
1460 * bci_action_anchor
1461 * bci_action_blue_anchor
1462 * bci_action_adjust
1463 * bci_action_stem
1465 * bci_action_blue
1466 * bci_action_serif
1467 * bci_action_serif_anchor
1468 * bci_action_serif_link1
1469 * bci_action_serif_link2
1472 unsigned char FPGM(bci_hint_glyph) [] = {
1474 PUSHB_1,
1475 bci_hint_glyph,
1476 FDEF,
1478 PUSHB_1,
1479 bci_handle_action,
1480 LOOPCALL,
1482 ENDF,
1487 #define COPY_FPGM(func_name) \
1488 memcpy(buf_p, fpgm_ ## func_name, \
1489 sizeof (fpgm_ ## func_name)); \
1490 buf_p += sizeof (fpgm_ ## func_name) \
1492 static FT_Error
1493 TA_table_build_fpgm(FT_Byte** fpgm,
1494 FT_ULong* fpgm_len,
1495 FONT* font)
1497 FT_UInt buf_len;
1498 FT_UInt len;
1499 FT_Byte* buf;
1500 FT_Byte* buf_p;
1503 buf_len = sizeof (FPGM(bci_compute_stem_width_a))
1505 + sizeof (FPGM(bci_compute_stem_width_b))
1507 + sizeof (FPGM(bci_compute_stem_width_c))
1508 + sizeof (FPGM(bci_loop))
1509 + sizeof (FPGM(bci_cvt_rescale))
1510 + sizeof (FPGM(bci_sal_assign))
1511 + sizeof (FPGM(bci_loop_sal_assign))
1512 + sizeof (FPGM(bci_blue_round_a))
1514 + sizeof (FPGM(bci_blue_round_b))
1515 + sizeof (FPGM(bci_get_point_extrema))
1516 + sizeof (FPGM(bci_create_segment_point))
1517 + sizeof (FPGM(bci_create_segment_points))
1518 + sizeof (FPGM(bci_handle_segment))
1519 + sizeof (FPGM(bci_align_segment))
1520 + sizeof (FPGM(bci_handle_segments))
1521 + sizeof (FPGM(bci_align_segments))
1522 + sizeof (FPGM(bci_action_adjust_bound))
1523 + sizeof (FPGM(bci_action_stem_bound))
1524 + sizeof (FPGM(bci_action_link))
1525 + sizeof (FPGM(bci_action_anchor))
1526 + sizeof (FPGM(bci_action_blue_anchor))
1527 + sizeof (FPGM(bci_action_adjust))
1528 + sizeof (FPGM(bci_action_stem))
1529 + sizeof (FPGM(bci_action_blue))
1530 + sizeof (FPGM(bci_action_serif))
1531 + sizeof (FPGM(bci_action_serif_anchor))
1532 + sizeof (FPGM(bci_action_serif_link1))
1533 + sizeof (FPGM(bci_action_serif_link2))
1534 + sizeof (FPGM(bci_handle_action))
1535 + sizeof (FPGM(bci_hint_glyph));
1536 /* buffer length must be a multiple of four */
1537 len = (buf_len + 3) & ~3;
1538 buf = (FT_Byte*)malloc(len);
1539 if (!buf)
1540 return FT_Err_Out_Of_Memory;
1542 /* pad end of buffer with zeros */
1543 buf[len - 1] = 0x00;
1544 buf[len - 2] = 0x00;
1545 buf[len - 3] = 0x00;
1547 /* copy font program into buffer and fill in the missing variables */
1548 buf_p = buf;
1550 COPY_FPGM(bci_compute_stem_width_a);
1551 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1552 COPY_FPGM(bci_compute_stem_width_b);
1553 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1554 COPY_FPGM(bci_compute_stem_width_c);
1555 COPY_FPGM(bci_loop);
1556 COPY_FPGM(bci_cvt_rescale);
1557 COPY_FPGM(bci_sal_assign);
1558 COPY_FPGM(bci_loop_sal_assign);
1559 COPY_FPGM(bci_blue_round_a);
1560 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
1561 COPY_FPGM(bci_blue_round_b);
1562 COPY_FPGM(bci_get_point_extrema);
1563 COPY_FPGM(bci_create_segment_point);
1564 COPY_FPGM(bci_create_segment_points);
1565 COPY_FPGM(bci_handle_segment);
1566 COPY_FPGM(bci_align_segment);
1567 COPY_FPGM(bci_handle_segments);
1568 COPY_FPGM(bci_align_segments);
1569 COPY_FPGM(bci_action_adjust_bound);
1570 COPY_FPGM(bci_action_stem_bound);
1571 COPY_FPGM(bci_action_link);
1572 COPY_FPGM(bci_action_anchor);
1573 COPY_FPGM(bci_action_blue_anchor);
1574 COPY_FPGM(bci_action_adjust);
1575 COPY_FPGM(bci_action_stem);
1576 COPY_FPGM(bci_action_blue);
1577 COPY_FPGM(bci_action_serif);
1578 COPY_FPGM(bci_action_serif_anchor);
1579 COPY_FPGM(bci_action_serif_link1);
1580 COPY_FPGM(bci_action_serif_link2);
1581 COPY_FPGM(bci_handle_action);
1582 COPY_FPGM(bci_hint_glyph);
1584 *fpgm = buf;
1585 *fpgm_len = buf_len;
1587 return FT_Err_Ok;
1591 FT_Error
1592 TA_sfnt_build_fpgm_table(SFNT* sfnt,
1593 FONT* font)
1595 FT_Error error;
1597 FT_Byte* fpgm_buf;
1598 FT_ULong fpgm_len;
1601 error = TA_sfnt_add_table_info(sfnt);
1602 if (error)
1603 return error;
1605 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
1606 if (error)
1607 return error;
1609 /* in case of success, `fpgm_buf' gets linked */
1610 /* and is eventually freed in `TA_font_unload' */
1611 error = TA_font_add_table(font,
1612 &sfnt->table_infos[sfnt->num_table_infos - 1],
1613 TTAG_fpgm, fpgm_len, fpgm_buf);
1614 if (error)
1616 free(fpgm_buf);
1617 return error;
1620 return FT_Err_Ok;
1624 /* the `prep' instructions */
1626 #define PREP(snippet_name) prep_ ## snippet_name
1628 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1629 /* thus we provide it in the storage area */
1631 unsigned char PREP(store_0x10000) [] = {
1633 PUSHB_1,
1634 sal_0x10000,
1635 PUSHW_2,
1636 0x08, /* 0x800 */
1637 0x00,
1638 0x08, /* 0x800 */
1639 0x00,
1640 MUL, /* 0x10000 */
1645 unsigned char PREP(align_top_a) [] = {
1647 /* optimize the alignment of the top of small letters to the pixel grid */
1649 PUSHB_1,
1653 /* %c, index of alignment blue zone */
1655 unsigned char PREP(align_top_b) [] = {
1657 RCVT,
1658 DUP,
1659 DUP,
1660 PUSHB_1,
1662 ADD,
1663 FLOOR, /* fitted = FLOOR(scaled + 40) */
1664 DUP, /* s: scaled scaled fitted fitted */
1665 ROLL,
1666 NEQ,
1667 IF, /* s: scaled fitted */
1668 PUSHB_1,
1669 sal_0x10000,
1671 MUL, /* scaled in 16.16 format */
1672 SWAP,
1673 DIV, /* (fitted / scaled) in 16.16 format */
1675 PUSHB_1,
1676 sal_scale,
1677 SWAP,
1682 unsigned char PREP(loop_cvt_a) [] = {
1684 /* loop over vertical CVT entries */
1685 PUSHB_4,
1689 /* %c, first vertical index */
1690 /* %c, last vertical index */
1692 unsigned char PREP(loop_cvt_b) [] = {
1694 bci_cvt_rescale,
1695 bci_loop,
1696 CALL,
1698 /* loop over blue refs */
1699 PUSHB_4,
1703 /* %c, first blue ref index */
1704 /* %c, last blue ref index */
1706 unsigned char PREP(loop_cvt_c) [] = {
1708 bci_cvt_rescale,
1709 bci_loop,
1710 CALL,
1712 /* loop over blue shoots */
1713 PUSHB_4,
1717 /* %c, first blue shoot index */
1718 /* %c, last blue shoot index */
1720 unsigned char PREP(loop_cvt_d) [] = {
1722 bci_cvt_rescale,
1723 bci_loop,
1724 CALL,
1725 EIF,
1729 unsigned char PREP(compute_extra_light_a) [] = {
1731 /* compute (vertical) `extra_light' flag */
1732 PUSHB_3,
1733 sal_is_extra_light,
1738 /* %c, index of vertical standard_width */
1740 unsigned char PREP(compute_extra_light_b) [] = {
1742 RCVT,
1743 GT, /* standard_width < 40 */
1748 unsigned char PREP(round_blues_a) [] = {
1750 /* use discrete values for blue zone widths */
1751 PUSHB_4,
1755 /* %c, first blue ref index */
1756 /* %c, last blue ref index */
1758 unsigned char PREP(round_blues_b) [] = {
1760 bci_blue_round,
1761 bci_loop,
1762 CALL
1766 /* XXX talatin.c: 1671 */
1767 /* XXX talatin.c: 1708 */
1768 /* XXX talatin.c: 2182 */
1771 #define COPY_PREP(snippet_name) \
1772 memcpy(buf_p, prep_ ## snippet_name, \
1773 sizeof (prep_ ## snippet_name)); \
1774 buf_p += sizeof (prep_ ## snippet_name);
1776 static FT_Error
1777 TA_table_build_prep(FT_Byte** prep,
1778 FT_ULong* prep_len,
1779 FONT* font)
1781 TA_LatinAxis vaxis;
1782 TA_LatinBlue blue_adjustment;
1783 FT_UInt i;
1785 FT_UInt buf_len;
1786 FT_UInt len;
1787 FT_Byte* buf;
1788 FT_Byte* buf_p;
1791 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
1792 blue_adjustment = NULL;
1794 for (i = 0; i < vaxis->blue_count; i++)
1796 if (vaxis->blues[i].flags & TA_LATIN_BLUE_ADJUSTMENT)
1798 blue_adjustment = &vaxis->blues[i];
1799 break;
1803 buf_len = sizeof (PREP(store_0x10000));
1805 if (blue_adjustment)
1806 buf_len += sizeof (PREP(align_top_a))
1808 + sizeof (PREP(align_top_b))
1809 + sizeof (PREP(loop_cvt_a))
1811 + sizeof (PREP(loop_cvt_b))
1813 + sizeof (PREP(loop_cvt_c))
1815 + sizeof (PREP(loop_cvt_d));
1817 buf_len += sizeof (PREP(compute_extra_light_a))
1819 + sizeof (PREP(compute_extra_light_b));
1821 if (CVT_BLUES_SIZE(font))
1822 buf_len += sizeof (PREP(round_blues_a))
1824 + sizeof (PREP(round_blues_b));
1826 /* buffer length must be a multiple of four */
1827 len = (buf_len + 3) & ~3;
1828 buf = (FT_Byte*)malloc(len);
1829 if (!buf)
1830 return FT_Err_Out_Of_Memory;
1832 /* pad end of buffer with zeros */
1833 buf[len - 1] = 0x00;
1834 buf[len - 2] = 0x00;
1835 buf[len - 3] = 0x00;
1837 /* copy cvt program into buffer and fill in the missing variables */
1838 buf_p = buf;
1840 COPY_PREP(store_0x10000);
1842 if (blue_adjustment)
1844 COPY_PREP(align_top_a);
1845 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
1846 + blue_adjustment - vaxis->blues);
1847 COPY_PREP(align_top_b);
1849 COPY_PREP(loop_cvt_a);
1850 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1851 *(buf_p++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font)
1852 + CVT_VERT_WIDTHS_SIZE(font) - 1);
1853 COPY_PREP(loop_cvt_b);
1854 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
1855 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
1856 + CVT_BLUES_SIZE(font) - 1);
1857 COPY_PREP(loop_cvt_c);
1858 *(buf_p++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font);
1859 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
1860 + CVT_BLUES_SIZE(font) - 1);
1861 COPY_PREP(loop_cvt_d);
1864 COPY_PREP(compute_extra_light_a);
1865 *(buf_p++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font);
1866 COPY_PREP(compute_extra_light_b);
1868 if (CVT_BLUES_SIZE(font))
1870 COPY_PREP(round_blues_a);
1871 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
1872 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
1873 + CVT_BLUES_SIZE(font) - 1);
1874 COPY_PREP(round_blues_b);
1877 *prep = buf;
1878 *prep_len = buf_len;
1880 return FT_Err_Ok;
1884 FT_Error
1885 TA_sfnt_build_prep_table(SFNT* sfnt,
1886 FONT* font)
1888 FT_Error error;
1890 FT_Byte* prep_buf;
1891 FT_ULong prep_len;
1894 error = TA_sfnt_add_table_info(sfnt);
1895 if (error)
1896 return error;
1898 error = TA_table_build_prep(&prep_buf, &prep_len, font);
1899 if (error)
1900 return error;
1902 /* in case of success, `prep_buf' gets linked */
1903 /* and is eventually freed in `TA_font_unload' */
1904 error = TA_font_add_table(font,
1905 &sfnt->table_infos[sfnt->num_table_infos - 1],
1906 TTAG_prep, prep_len, prep_buf);
1907 if (error)
1909 free(prep_buf);
1910 return error;
1913 return FT_Err_Ok;
1917 /* we store the segments in the storage area; */
1918 /* each segment record consists of the first and last point */
1920 static FT_Byte*
1921 TA_sfnt_build_glyph_segments(SFNT* sfnt,
1922 FONT* font,
1923 FT_Byte* bufp)
1925 TA_GlyphHints hints = &font->loader->hints;
1926 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1927 TA_Point points = hints->points;
1928 TA_Segment segments = axis->segments;
1929 TA_Segment seg;
1930 TA_Segment seg_limit;
1932 FT_UInt* args;
1933 FT_UInt* arg;
1934 FT_UInt num_args;
1935 FT_UInt nargs;
1937 FT_Bool need_words = 0;
1939 FT_UInt i, j;
1940 FT_UInt num_storage;
1941 FT_UInt num_stack_elements;
1944 seg_limit = segments + axis->num_segments;
1945 num_args = 2 * axis->num_segments + 3;
1947 /* collect all arguments temporarily in an array (in reverse order) */
1948 /* so that we can easily split into chunks of 255 args */
1949 /* as needed by NPUSHB and NPUSHW, respectively */
1950 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1951 if (!args)
1952 return NULL;
1954 arg = args + num_args - 1;
1956 if (axis->num_segments > 0xFF)
1957 need_words = 1;
1959 *(arg--) = bci_loop_sal_assign;
1960 *(arg--) = axis->num_segments * 2;
1961 *(arg--) = sal_segment_offset;
1963 for (seg = segments; seg < seg_limit; seg++)
1965 FT_UInt first = seg->first - points;
1966 FT_UInt last = seg->last - points;
1969 *(arg--) = first;
1970 *(arg--) = last;
1972 if (first > 0xFF || last > 0xFF)
1973 need_words = 1;
1976 /* with most fonts it is very rare */
1977 /* that any of the pushed arguments is larger than 0xFF, */
1978 /* thus we refrain from further optimizing this case */
1980 arg = args;
1982 if (need_words)
1984 for (i = 0; i < num_args; i += 255)
1986 nargs = (num_args - i > 255) ? 255 : num_args - i;
1988 BCI(NPUSHW);
1989 BCI(nargs);
1990 for (j = 0; j < nargs; j++)
1992 BCI(HIGH(*arg));
1993 BCI(LOW(*arg));
1994 arg++;
1998 else
2000 for (i = 0; i < num_args; i += 255)
2002 nargs = (num_args - i > 255) ? 255 : num_args - i;
2004 BCI(NPUSHB);
2005 BCI(nargs);
2006 for (j = 0; j < nargs; j++)
2008 BCI(*arg);
2009 arg++;
2014 BCI(CALL);
2016 num_storage = sal_segment_offset + axis->num_segments * 2;
2017 if (num_storage > sfnt->max_storage)
2018 sfnt->max_storage = num_storage;
2020 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
2021 if (num_stack_elements > sfnt->max_stack_elements)
2022 sfnt->max_stack_elements = num_stack_elements;
2024 free(args);
2026 return bufp;
2030 static FT_Bool
2031 TA_hints_record_is_different(Hints_Record* hints_records,
2032 FT_UInt num_hints_records,
2033 FT_Byte* start,
2034 FT_Byte* end)
2036 Hints_Record last_hints_record;
2039 if (!hints_records)
2040 return 1;
2042 /* we only need to compare with the last hints record */
2043 last_hints_record = hints_records[num_hints_records - 1];
2045 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
2046 return 1;
2048 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
2049 return 1;
2051 return 0;
2055 static FT_Error
2056 TA_add_hints_record(Hints_Record** hints_records,
2057 FT_UInt* num_hints_records,
2058 FT_Byte* start,
2059 Hints_Record hints_record)
2061 Hints_Record* hints_records_new;
2062 FT_UInt buf_len;
2063 /* at this point, `hints_record.buf' still points into `ins_buf' */
2064 FT_Byte* end = hints_record.buf;
2067 buf_len = (FT_UInt)(end - start);
2069 /* now fill the structure completely */
2070 hints_record.buf_len = buf_len;
2071 hints_record.buf = (FT_Byte*)malloc(buf_len);
2072 if (!hints_record.buf)
2073 return FT_Err_Out_Of_Memory;
2075 memcpy(hints_record.buf, start, buf_len);
2077 (*num_hints_records)++;
2078 hints_records_new =
2079 (Hints_Record*)realloc(*hints_records, *num_hints_records
2080 * sizeof (Hints_Record));
2081 if (!hints_records_new)
2083 free(hints_record.buf);
2084 (*num_hints_records)--;
2085 return FT_Err_Out_Of_Memory;
2087 else
2088 *hints_records = hints_records_new;
2090 (*hints_records)[*num_hints_records - 1] = hints_record;
2092 return FT_Err_Ok;
2096 static FT_Byte*
2097 TA_sfnt_emit_hints_record(SFNT* sfnt,
2098 Hints_Record* hints_record,
2099 FT_Byte* bufp)
2101 FT_Byte* p;
2102 FT_Byte* endp;
2103 FT_Bool need_words = 0;
2105 FT_UInt i, j;
2106 FT_UInt num_arguments;
2107 FT_UInt num_args;
2108 FT_UInt num_stack_elements;
2111 /* check whether any argument is larger than 0xFF */
2112 endp = hints_record->buf + hints_record->buf_len;
2113 for (p = hints_record->buf; p < endp; p += 2)
2114 if (*p)
2115 need_words = 1;
2117 /* with most fonts it is very rare */
2118 /* that any of the pushed arguments is larger than 0xFF, */
2119 /* thus we refrain from further optimizing this case */
2121 num_arguments = hints_record->buf_len / 2;
2122 p = endp - 2;
2124 if (need_words)
2126 for (i = 0; i < num_arguments; i += 255)
2128 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2130 BCI(NPUSHW);
2131 BCI(num_args);
2132 for (j = 0; j < num_args; j++)
2134 BCI(*p);
2135 BCI(*(p + 1));
2136 p -= 2;
2140 else
2142 /* we only need the lower bytes */
2143 p++;
2145 for (i = 0; i < num_arguments; i += 255)
2147 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2149 BCI(NPUSHB);
2150 BCI(num_args);
2151 for (j = 0; j < num_args; j++)
2153 BCI(*p);
2154 p -= 2;
2159 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
2160 if (num_stack_elements > sfnt->max_stack_elements)
2161 sfnt->max_stack_elements = sfnt->max_stack_elements;
2163 return bufp;
2167 static FT_Byte*
2168 TA_sfnt_emit_hints_records(SFNT* sfnt,
2169 Hints_Record* hints_records,
2170 FT_UInt num_hints_records,
2171 FT_Byte* bufp)
2173 FT_UInt i;
2174 Hints_Record* hints_record;
2177 hints_record = hints_records;
2179 /* this instruction is essential for getting correct CVT values */
2180 /* if horizontal and vertical resolutions differ; */
2181 /* it assures that the projection vector is set to the y axis */
2182 /* so that CVT values are handled as being `vertical' */
2183 BCI(SVTCA_y);
2185 for (i = 0; i < num_hints_records - 1; i++)
2187 BCI(MPPEM);
2188 if (hints_record->size > 0xFF)
2190 BCI(PUSHW_1);
2191 BCI(HIGH((hints_record + 1)->size));
2192 BCI(LOW((hints_record + 1)->size));
2194 else
2196 BCI(PUSHB_1);
2197 BCI((hints_record + 1)->size);
2199 BCI(LT);
2200 BCI(IF);
2201 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2202 BCI(ELSE);
2204 hints_record++;
2207 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2209 for (i = 0; i < num_hints_records - 1; i++)
2210 BCI(EIF);
2212 BCI(PUSHB_1);
2213 BCI(bci_hint_glyph);
2214 BCI(CALL);
2216 return bufp;
2220 static void
2221 TA_free_hints_records(Hints_Record* hints_records,
2222 FT_UInt num_hints_records)
2224 FT_UInt i;
2227 for (i = 0; i < num_hints_records; i++)
2228 free(hints_records[i].buf);
2230 free(hints_records);
2234 static FT_Byte*
2235 TA_hints_recorder_handle_segments(FT_Byte* bufp,
2236 TA_Segment segments,
2237 TA_Edge edge)
2239 TA_Segment seg;
2240 FT_UInt seg_idx;
2241 FT_UInt num_segs = 0;
2244 seg_idx = edge->first - segments;
2246 /* we store everything as 16bit numbers */
2247 *(bufp++) = HIGH(seg_idx);
2248 *(bufp++) = LOW(seg_idx);
2250 seg = edge->first->edge_next;
2251 while (seg != edge->first)
2253 seg = seg->edge_next;
2254 num_segs++;
2257 *(bufp++) = HIGH(num_segs);
2258 *(bufp++) = LOW(num_segs);
2260 seg = edge->first->edge_next;
2261 while (seg != edge->first)
2263 seg_idx = seg - segments;
2264 seg = seg->edge_next;
2266 *(bufp++) = HIGH(seg_idx);
2267 *(bufp++) = LOW(seg_idx);
2270 return bufp;
2274 static void
2275 TA_hints_recorder(TA_Action action,
2276 TA_GlyphHints hints,
2277 TA_Dimension dim,
2278 void* arg1,
2279 void* arg2,
2280 void* arg3)
2282 TA_AxisHints axis = &hints->axis[dim];
2283 TA_Point points = hints->points;
2284 TA_Segment segments = axis->segments;
2286 Recorder* recorder = (Recorder*)hints->user;
2287 FONT* font = recorder->font;
2288 FT_Byte* p = recorder->hints_record.buf;
2291 if (dim == TA_DIMENSION_HORZ)
2292 return;
2294 /* we ignore the BOUND action since the information is handled */
2295 /* in `ta_adjust_bound' and `ta_stem_bound' */
2296 if (action == ta_bound)
2297 return;
2299 *(p++) = 0;
2300 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2302 switch (action)
2304 case ta_adjust_bound:
2305 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2306 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2307 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2308 break;
2310 case ta_stem_bound:
2311 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2312 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2313 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2314 break;
2316 case ta_link:
2318 TA_Edge base_edge = (TA_Edge)arg1;
2319 TA_Edge stem_edge = (TA_Edge)arg2;
2322 *(p++) = HIGH(base_edge->first->first - points);
2323 *(p++) = LOW(base_edge->first->first - points);
2324 *(p++) = HIGH(stem_edge->first->first - points);
2325 *(p++) = LOW(stem_edge->first->first - points);
2326 *(p++) = 0;
2327 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
2328 *(p++) = 0;
2329 *(p++) = base_edge->flags & TA_EDGE_ROUND;
2331 p = TA_hints_recorder_handle_segments(p, segments, stem_edge);
2333 break;
2335 case ta_anchor:
2336 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2337 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2338 break;
2340 case ta_blue_anchor:
2342 TA_Edge edge = (TA_Edge)arg1;
2343 TA_Edge blue = (TA_Edge)arg2;
2346 *(p++) = HIGH(blue->first->first - points);
2347 *(p++) = LOW(blue->first->first - points);
2349 if (edge->best_blue_is_shoot)
2351 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2352 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2354 else
2356 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2357 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2360 p = TA_hints_recorder_handle_segments(p, segments, edge);
2362 break;
2364 case ta_adjust:
2365 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2366 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2367 break;
2369 case ta_stem:
2370 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2371 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2372 break;
2374 case ta_blue:
2376 TA_Edge edge = (TA_Edge)arg1;
2379 if (edge->best_blue_is_shoot)
2381 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2382 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2384 else
2386 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2387 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2390 p = TA_hints_recorder_handle_segments(p, segments, edge);
2392 break;
2394 case ta_serif:
2395 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2396 break;
2398 case ta_serif_anchor:
2399 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2400 break;
2402 case ta_serif_link1:
2403 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2404 break;
2406 case ta_serif_link2:
2407 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2408 break;
2410 /* to pacify the compiler */
2411 case ta_bound:
2412 break;
2415 recorder->hints_record.num_actions++;
2416 recorder->hints_record.buf = p;
2420 static FT_Error
2421 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2422 FONT* font,
2423 FT_Long idx)
2425 FT_Face face = sfnt->face;
2426 FT_Error error;
2428 FT_Byte* ins_buf;
2429 FT_UInt ins_len;
2430 FT_Byte* bufp;
2432 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2433 glyf_Data* data = (glyf_Data*)glyf_table->data;
2434 GLYPH* glyph = &data->glyphs[idx];
2436 TA_GlyphHints hints;
2438 FT_UInt num_hints_records;
2439 Hints_Record* hints_records;
2441 Recorder recorder;
2443 FT_UInt size;
2446 if (idx < 0)
2447 return FT_Err_Invalid_Argument;
2449 /* computing the segments is resolution independent, */
2450 /* thus the pixel size in this call is arbitrary */
2451 error = FT_Set_Pixel_Sizes(face, 20, 20);
2452 if (error)
2453 return error;
2455 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2456 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
2457 if (error)
2458 return error;
2460 /* do nothing if we have an empty glyph */
2461 if (!face->glyph->outline.n_contours)
2462 return FT_Err_Ok;
2464 hints = &font->loader->hints;
2466 /* we allocate a buffer which is certainly large enough */
2467 /* to hold all of the created bytecode instructions; */
2468 /* later on it gets reallocated to its real size */
2469 ins_len = hints->num_points * 1000;
2470 ins_buf = (FT_Byte*)malloc(ins_len);
2471 if (!ins_buf)
2472 return FT_Err_Out_Of_Memory;
2474 /* initialize array with an invalid bytecode */
2475 /* so that we can easily find the array length at reallocation time */
2476 memset(ins_buf, INS_A0, ins_len);
2478 bufp = TA_sfnt_build_glyph_segments(sfnt, font, ins_buf);
2480 /* now we loop over a large range of pixel sizes */
2481 /* to find hints records which get pushed onto the bytecode stack */
2482 num_hints_records = 0;
2483 hints_records = NULL;
2485 #ifdef DEBUGGING
2486 printf("glyph %ld\n", idx);
2487 #endif
2489 /* we temporarily use `ins_buf' to record the current glyph hints, */
2490 /* leaving two bytes at the beginning so that the number of actions */
2491 /* can be inserted later on */
2492 recorder.font = font;
2493 ta_loader_register_hints_recorder(font->loader,
2494 TA_hints_recorder,
2495 (void *)&recorder);
2497 for (size = 8; size <= 1000; size++)
2499 /* rewind buffer pointer for recorder */
2500 recorder.hints_record.buf = bufp + 2;
2501 recorder.hints_record.num_actions = 0;
2502 recorder.hints_record.size = size;
2504 error = FT_Set_Pixel_Sizes(face, size, size);
2505 if (error)
2506 goto Err;
2508 /* calling `ta_loader_load_glyph' uses the */
2509 /* `TA_hints_recorder' function as a callback, */
2510 /* modifying `hints_record' */
2511 error = ta_loader_load_glyph(font->loader, face, idx, 0);
2512 if (error)
2513 goto Err;
2515 /* store the number of actions in `ins_buf' */
2516 *bufp = HIGH(recorder.hints_record.num_actions);
2517 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
2519 if (TA_hints_record_is_different(hints_records,
2520 num_hints_records,
2521 bufp, recorder.hints_record.buf))
2523 #ifdef DEBUGGING
2525 FT_Byte* p;
2528 printf(" %d:\n", size);
2529 for (p = bufp; p < recorder.hints_record.buf; p += 2)
2530 printf(" %2d", *p * 256 + *(p + 1));
2531 printf("\n");
2533 #endif
2535 error = TA_add_hints_record(&hints_records,
2536 &num_hints_records,
2537 bufp, recorder.hints_record);
2538 if (error)
2539 goto Err;
2543 if (num_hints_records == 1 && !hints_records[0].num_actions)
2545 /* don't emit anything if we only have a single empty record */
2546 ins_len = 0;
2548 else
2550 FT_Byte* p = bufp;
2553 /* otherwise, clear the temporarily used part of `ins_buf' */
2554 while (*p != INS_A0)
2555 *(p++) = INS_A0;
2557 bufp = TA_sfnt_emit_hints_records(sfnt,
2558 hints_records, num_hints_records,
2559 bufp);
2561 /* we are done, so reallocate the instruction array to its real size */
2562 if (*bufp == INS_A0)
2564 /* search backwards */
2565 while (*bufp == INS_A0)
2566 bufp--;
2567 bufp++;
2569 else
2571 /* search forwards */
2572 while (*bufp != INS_A0)
2573 bufp++;
2576 ins_len = bufp - ins_buf;
2579 if (ins_len > sfnt->max_instructions)
2580 sfnt->max_instructions = ins_len;
2582 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2583 glyph->ins_len = ins_len;
2585 TA_free_hints_records(hints_records, num_hints_records);
2587 return FT_Err_Ok;
2589 Err:
2590 TA_free_hints_records(hints_records, num_hints_records);
2591 free(ins_buf);
2593 return error;
2597 FT_Error
2598 TA_sfnt_build_glyf_hints(SFNT* sfnt,
2599 FONT* font)
2601 FT_Face face = sfnt->face;
2602 FT_Long idx;
2603 FT_Error error;
2606 for (idx = 0; idx < face->num_glyphs; idx++)
2608 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
2609 if (error)
2610 return error;
2613 return FT_Err_Ok;
2616 /* end of tabytecode.c */