Completely remove `sal_pos'.
[ttfautohint.git] / src / tabytecode.c
blob85fba4a590883e6109472774dd7f1d70b2b170d6
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_limit sal_k + 1
264 #define sal_num_segments sal_limit + 1
265 #define sal_scale sal_num_segments + 1
266 #define sal_0x10000 sal_scale + 1
267 #define sal_is_extra_light sal_0x10000 + 1
268 #define sal_anchor sal_is_extra_light + 1
269 #define sal_point_min sal_anchor + 1
270 #define sal_point_max sal_point_min + 1
271 #define sal_segment_offset sal_point_max + 1 /* must be last */
274 /* we need the following macro */
275 /* so that `func_name' doesn't get replaced with its #defined value */
276 /* (as defined in `tabytecode.h') */
278 #define FPGM(func_name) fpgm_ ## func_name
281 /* in the comments below, the top of the stack (`s:') */
282 /* is the rightmost element; the stack is shown */
283 /* after the instruction on the same line has been executed */
285 /* we use two sets of points in the twilight zone (zp0): */
286 /* one set to hold the unhinted segment positions, */
287 /* and another one to track the positions as changed by the hinting -- */
288 /* this is necessary since all points in zp0 */
289 /* have (0,0) as the original coordinates, */
290 /* making e.g. `MD_cur' return useless results */
294 * bci_compute_stem_width
296 * This is the equivalent to the following code from function
297 * `ta_latin_compute_stem_width':
299 * dist = ABS(width)
301 * if (stem_is_serif
302 * && dist < 3*64)
303 * || is_extra_light:
304 * return width
305 * else if base_is_round:
306 * if dist < 80
307 * dist = 64
308 * else if dist < 56:
309 * dist = 56
311 * delta = ABS(dist - std_width)
313 * if delta < 40:
314 * dist = MIN(48, std_width)
315 * goto End
317 * if dist < 3*64:
318 * delta = dist
319 * dist = FLOOR(dist)
320 * delta = delta - dist
322 * if delta < 10:
323 * dist = dist + delta
324 * else if delta < 32:
325 * dist = dist + 10
326 * else if delta < 54:
327 * dist = dist + 54
328 * else
329 * dist = dist + delta
330 * else
331 * dist = ROUND(dist)
333 * End:
334 * if width < 0:
335 * dist = -dist
336 * return dist
339 * in: width
340 * stem_is_serif
341 * base_is_round
342 * out: new_width
343 * sal: sal_is_extra_light
344 * CVT: std_width
347 unsigned char FPGM(bci_compute_stem_width_a) [] = {
349 PUSHB_1,
350 bci_compute_stem_width,
351 FDEF,
353 DUP,
354 ABS, /* s: base_is_round stem_is_serif width dist */
356 DUP,
357 PUSHB_1,
358 3*64,
359 LT, /* dist < 3*64 */
361 PUSHB_1,
363 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
364 AND, /* stem_is_serif && dist < 3*64 */
366 PUSHB_1,
367 sal_is_extra_light,
369 OR, /* (stem_is_serif && dist < 3*64) || is_extra_light */
371 IF, /* s: base_is_round width dist */
372 POP,
373 SWAP,
374 POP, /* s: width */
376 ELSE,
377 ROLL, /* s: width dist base_is_round */
378 IF, /* s: width dist */
379 DUP,
380 PUSHB_1,
382 LT, /* dist < 80 */
383 IF, /* s: width dist */
384 POP,
385 PUSHB_1,
386 64, /* dist = 64 */
387 EIF,
389 ELSE,
390 DUP,
391 PUSHB_1,
393 LT, /* dist < 56 */
394 IF, /* s: width dist */
395 POP,
396 PUSHB_1,
397 56, /* dist = 56 */
398 EIF,
399 EIF,
401 DUP, /* s: width dist dist */
402 PUSHB_1,
406 /* %c, index of std_width */
408 unsigned char FPGM(bci_compute_stem_width_b) [] = {
410 RCVT,
411 SUB,
412 ABS, /* s: width dist delta */
414 PUSHB_1,
416 LT, /* delta < 40 */
417 IF, /* s: width dist */
418 POP,
419 PUSHB_2,
424 /* %c, index of std_width */
426 unsigned char FPGM(bci_compute_stem_width_c) [] = {
428 RCVT,
429 MIN, /* dist = min(48, std_width) */
431 ELSE,
432 DUP, /* s: width dist dist */
433 PUSHB_1,
434 3*64,
435 LT, /* dist < 3*64 */
437 DUP, /* s: width delta dist */
438 FLOOR, /* dist = FLOOR(dist) */
439 DUP, /* s: width delta dist dist */
440 ROLL,
441 ROLL, /* s: width dist delta dist */
442 SUB, /* delta = delta - dist */
444 DUP, /* s: width dist delta delta */
445 PUSHB_1,
447 LT, /* delta < 10 */
448 IF, /* s: width dist delta */
449 ADD, /* dist = dist + delta */
451 ELSE,
452 DUP,
453 PUSHB_1,
455 LT, /* delta < 32 */
457 POP,
458 PUSHB_1,
460 ADD, /* dist = dist + 10 */
462 ELSE,
463 DUP,
464 PUSHB_1,
466 LT, /* delta < 54 */
468 POP,
469 PUSHB_1,
471 ADD, /* dist = dist + 54 */
473 ELSE,
474 ADD, /* dist = dist + delta */
476 EIF,
477 EIF,
478 EIF,
480 ELSE,
481 PUSHB_1,
483 ADD,
484 FLOOR, /* dist = round(dist) */
486 EIF,
487 EIF,
489 SWAP, /* s: dist width */
490 PUSHB_1,
492 LT, /* width < 0 */
494 NEG, /* dist = -dist */
495 EIF,
496 EIF,
497 EIF,
499 ENDF,
505 * bci_loop
507 * Take a range and a function number and apply the function to all
508 * elements of the range. The called function must not change the
509 * stack.
511 * in: func_num
512 * end
513 * start
515 * uses: sal_i (counter initialized with `start')
516 * sal_limit (`end')
519 unsigned char FPGM(bci_loop) [] = {
521 PUSHB_1,
522 bci_loop,
523 FDEF,
525 ROLL,
526 ROLL, /* s: func_num start end */
527 PUSHB_1,
528 sal_limit,
529 SWAP,
532 PUSHB_1,
533 sal_i,
534 SWAP,
537 /* start_loop: */
538 PUSHB_1,
539 sal_i,
541 PUSHB_1,
542 sal_limit,
544 LTEQ, /* start <= end */
545 IF, /* s: func_num */
546 DUP,
547 CALL,
548 PUSHB_3,
549 sal_i,
551 sal_i,
553 ADD, /* start = start + 1 */
556 PUSHB_1,
558 NEG,
559 JMPR, /* goto start_loop */
560 ELSE,
561 POP,
562 EIF,
564 ENDF,
570 * bci_cvt_rescale
572 * Rescale CVT value by a given factor.
574 * uses: sal_i (CVT index)
575 * sal_scale (scale in 16.16 format)
578 unsigned char FPGM(bci_cvt_rescale) [] = {
580 PUSHB_1,
581 bci_cvt_rescale,
582 FDEF,
584 PUSHB_1,
585 sal_i,
587 DUP,
588 RCVT,
589 PUSHB_1,
590 sal_scale,
592 MUL, /* CVT * scale * 2^10 */
593 PUSHB_1,
594 sal_0x10000,
596 DIV, /* CVT * scale */
598 WCVTP,
600 ENDF,
606 * bci_sal_assign
608 * Auxiliary function for `bci_set_up_segments'.
610 * in: offset
611 * data
613 * out: offset+1
616 unsigned char FPGM(bci_sal_assign) [] = {
618 PUSHB_1,
619 bci_sal_assign,
620 FDEF,
622 DUP,
623 ROLL, /* s: offset offset data */
626 PUSHB_1,
628 ADD, /* s: (offset + 1) */
630 ENDF,
636 * bci_set_up_segments
638 * Set up segments by defining the point ranges which defines them
639 * and computing twilight points to represent them.
641 * in: num_segments (N)
642 * offset
643 * segment_start_0
644 * segment_end_0
645 * segment_start_1
646 * segment_end_1
647 * ...
648 * segment_start_(N-1)
649 * segment_end_(N-1)
651 * sal: sal_num_segments
653 * uses: bci_sal_assign
656 unsigned char FPGM(bci_set_up_segments) [] = {
658 PUSHB_1,
659 bci_set_up_segments,
660 FDEF,
662 DUP,
663 PUSHB_1,
664 sal_num_segments,
665 SWAP,
668 /* we have 2*num_segments arguments */
669 DUP,
670 ADD,
672 /* process the stack, popping off the elements in a loop */
673 PUSHB_1,
674 bci_sal_assign,
675 LOOPCALL,
677 /* clean up stack */
678 POP,
680 PUSHB_1,
681 bci_create_segment_points,
682 CALL,
684 ENDF,
690 * bci_blue_round
692 * Round a blue ref value and adjust its corresponding shoot value.
694 * uses: sal_i (CVT index)
698 unsigned char FPGM(bci_blue_round_a) [] = {
700 PUSHB_1,
701 bci_blue_round,
702 FDEF,
704 PUSHB_1,
705 sal_i,
707 DUP,
708 RCVT, /* s: ref_idx ref */
710 DUP,
711 PUSHB_1,
713 ADD,
714 FLOOR,
715 SWAP, /* s: ref_idx round(ref) ref */
717 PUSHB_2,
721 /* %c, blue_count */
723 unsigned char FPGM(bci_blue_round_b) [] = {
726 CINDEX,
727 ADD, /* s: ref_idx round(ref) ref shoot_idx */
728 DUP,
729 RCVT, /* s: ref_idx round(ref) ref shoot_idx shoot */
731 ROLL, /* s: ref_idx round(ref) shoot_idx shoot ref */
732 SWAP,
733 SUB, /* s: ref_idx round(ref) shoot_idx dist */
734 DUP,
735 ABS, /* s: ref_idx round(ref) shoot_idx dist delta */
737 DUP,
738 PUSHB_1,
740 LT, /* delta < 32 */
742 POP,
743 PUSHB_1,
744 0, /* delta = 0 */
746 ELSE,
747 PUSHB_1,
749 LT, /* delta < 48 */
751 PUSHB_1,
752 32, /* delta = 32 */
754 ELSE,
755 PUSHB_1,
756 64, /* delta = 64 */
757 EIF,
758 EIF,
760 SWAP, /* s: ref_idx round(ref) shoot_idx delta dist */
761 PUSHB_1,
763 LT, /* dist < 0 */
765 NEG, /* delta = -delta */
766 EIF,
768 PUSHB_1,
770 CINDEX,
771 ADD, /* s: ref_idx round(ref) shoot_idx (round(ref) + delta) */
773 WCVTP,
774 WCVTP,
776 ENDF,
782 * bci_get_point_extrema
784 * An auxiliary function for `bci_create_segment_point'.
786 * in: point-1
787 * out: point
789 * sal: sal_point_min
790 * sal_point_max
793 unsigned char FPGM(bci_get_point_extrema) [] = {
795 PUSHB_1,
796 bci_get_point_extrema,
797 FDEF,
799 PUSHB_1,
801 ADD, /* s: point */
802 DUP,
803 DUP,
805 /* check whether `point' is a new minimum */
806 PUSHB_1,
807 sal_point_min,
808 RS, /* s: point point point point_min */
809 MD_orig,
810 /* if distance is negative, we have a new minimum */
811 PUSHB_1,
814 IF, /* s: point point */
815 DUP,
816 PUSHB_1,
817 sal_point_min,
818 SWAP,
820 EIF,
822 /* check whether `point' is a new maximum */
823 PUSHB_1,
824 sal_point_max,
825 RS, /* s: point point point_max */
826 MD_orig,
827 /* if distance is positive, we have a new maximum */
828 PUSHB_1,
831 IF, /* s: point */
832 DUP,
833 PUSHB_1,
834 sal_point_max,
835 SWAP,
837 EIF, /* s: point */
839 ENDF,
845 * bci_create_segment_point
847 * Construct two points in the twilight zone to represent a segment:
848 * an original one (which stays unmodified) and a hinted one,
849 * initialized with the original value.
851 * This function is used by `bci_create_segment_points'.
853 * uses: bci_get_point_extrema
855 * sal: sal_i (start of current segment)
856 * sal_j (current original twilight point)
857 * sal_k (current hinted twilight point)
858 * sal_point_min
859 * sal_point_max
862 unsigned char FPGM(bci_create_segment_point) [] = {
864 PUSHB_1,
865 bci_create_segment_point,
866 FDEF,
868 PUSHB_1,
869 sal_i,
871 RS, /* s: start_point */
872 DUP,
874 /* increase `sal_i'; together with the outer loop, this makes sal_i += 2 */
875 PUSHB_2,
877 sal_i,
879 ADD,
880 DUP,
881 PUSHB_1,
882 sal_i,
883 SWAP,
886 SWAP, /* s: start_point end_point start_point */
888 /* initialize inner loop */
889 DUP,
890 PUSHB_1,
891 sal_point_min,
892 SWAP,
893 WS, /* sal_point_min = start_point */
894 DUP,
895 PUSHB_1,
896 sal_point_max,
897 SWAP,
898 WS, /* sal_point_max = start_point */
900 SUB, /* s: start_point loop_count */
902 PUSHB_2,
905 SZP0, /* set zp0 to normal zone 1 */
906 SZP1, /* set zp1 to normal zone 1 */
908 /* all our measurements are taken along the y axis */
909 SVTCA_y,
911 PUSHB_1,
912 bci_get_point_extrema,
913 LOOPCALL,
914 /* clean up stack */
915 POP,
917 /* the twilight point representing a segment */
918 /* is in the middle between the minimum and maximum */
919 PUSHB_1,
920 sal_point_max,
922 PUSHB_1,
923 sal_point_min,
925 MD_orig,
926 PUSHB_1,
927 2*64,
928 DIV, /* s: delta */
930 PUSHB_4,
931 sal_j,
934 sal_point_min,
936 MDAP_noround, /* set rp0 and rp1 to `sal_point_min' */
937 SZP1, /* set zp1 to twilight zone 0 */
938 SZP2, /* set zp2 to twilight zone 0 */
941 DUP, /* s: delta point[sal_j] point[sal_j] */
942 ALIGNRP, /* align `point[sal_j]' with `sal_point_min' */
943 PUSHB_1,
945 CINDEX, /* s: delta point[sal_j] delta */
946 SHPIX, /* shift `point[sal_j]' by `delta' */
948 PUSHB_1,
949 sal_k,
951 DUP, /* s: delta point[sal_k] point[sal_k] */
952 ALIGNRP, /* align `point[sal_k]' with `sal_point_min' */
953 SWAP,
954 SHPIX, /* shift `point[sal_k]' by `delta' */
956 PUSHB_6,
957 sal_k,
959 sal_k,
960 sal_j,
962 sal_j,
964 ADD, /* original_twilight_point = original_twilight_point + 1 */
967 ADD, /* hinted_twilight_point = hinted_twilight_point + 1 */
970 ENDF,
976 * bci_create_segment_points
978 * Construct two sets of points in the twilight zone to represent segments.
979 * This function searches the points of a segment with the minimum and
980 * maximum y-values, then takes the median.
982 * uses: bci_create_segment_point
984 * sal: sal_i (start of current segment)
985 * sal_j (current original twilight point)
986 * sal_k (current hinted twilight point)
987 * sal_num_segments
990 unsigned char FPGM(bci_create_segment_points) [] = {
992 PUSHB_1,
993 bci_create_segment_points,
994 FDEF,
996 PUSHB_7,
997 sal_segment_offset,
998 sal_segment_offset,
999 sal_num_segments,
1001 sal_k,
1003 sal_j,
1004 sal_num_segments,
1006 WS, /* sal_j = num_segments (offset for original points) */
1007 WS, /* sal_k = 0 (offset for hinted points) */
1010 DUP,
1011 ADD,
1012 ADD,
1013 PUSHB_1,
1015 SUB, /* s: sal_segment_offset (sal_segment_offset + 2*num_segments - 1) */
1017 PUSHB_2,
1018 bci_create_segment_point,
1019 bci_loop,
1020 CALL,
1022 ENDF,
1026 unsigned char FPGM(bci_handle_segment) [] = {
1028 PUSHB_1,
1029 bci_handle_segment,
1030 FDEF,
1032 POP, /* XXX segment */
1034 ENDF,
1040 * bci_align_segment
1042 * Align all points in a segment to the twilight point in rp0.
1043 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1045 * in: segment_index
1048 unsigned char FPGM(bci_align_segment) [] = {
1050 PUSHB_1,
1051 bci_align_segment,
1052 FDEF,
1054 /* we need the values of `sal_segment_offset + 2*segment_index' */
1055 /* and `sal_segment_offset + 2*segment_index + 1' */
1056 DUP,
1057 ADD,
1058 PUSHB_1,
1059 sal_segment_offset,
1060 ADD,
1061 DUP,
1063 SWAP,
1064 PUSHB_1,
1066 ADD,
1067 RS, /* s: first last */
1069 /* start_loop: */
1070 PUSHB_1,
1072 CINDEX, /* s: first last first */
1073 PUSHB_1,
1075 CINDEX, /* s: first last first last */
1076 LTEQ, /* first <= end */
1077 IF, /* s: first last */
1078 SWAP,
1079 DUP, /* s: last first first */
1080 ALIGNRP, /* align point with index `first' with rp0 */
1082 PUSHB_1,
1084 ADD, /* first = first + 1 */
1085 SWAP, /* s: first last */
1087 PUSHB_1,
1089 NEG,
1090 JMPR, /* goto start_loop */
1091 ELSE,
1092 POP,
1093 POP,
1094 EIF,
1096 ENDF,
1100 unsigned char FPGM(bci_handle_segments) [] = {
1102 PUSHB_1,
1103 bci_handle_segments,
1104 FDEF,
1106 POP, /* XXX first segment */
1108 PUSHB_1,
1109 bci_handle_segment,
1110 LOOPCALL,
1112 ENDF,
1118 * bci_align_segments
1120 * Align segments to the twilight point in rp0.
1121 * zp0 and zp1 must be set to 0 (twilight) and 1 (normal), respectively.
1123 * in: first_segment
1124 * loop_counter (N)
1125 * segment_1
1126 * segment_2
1127 * ...
1128 * segment_N
1130 * uses: handle_segment
1134 unsigned char FPGM(bci_align_segments) [] = {
1136 PUSHB_1,
1137 bci_align_segments,
1138 FDEF,
1140 PUSHB_1,
1141 bci_align_segment,
1142 CALL,
1144 PUSHB_1,
1145 bci_align_segment,
1146 LOOPCALL,
1148 ENDF,
1153 unsigned char FPGM(bci_action_adjust_bound) [] = {
1155 PUSHB_1,
1156 bci_action_adjust_bound,
1157 FDEF,
1159 PUSHB_1,
1160 bci_handle_segments,
1161 CALL,
1162 PUSHB_1,
1163 bci_handle_segments,
1164 CALL,
1165 PUSHB_1,
1166 bci_handle_segments,
1167 CALL,
1169 /* XXX */
1171 ENDF,
1175 unsigned char FPGM(bci_action_stem_bound) [] = {
1177 PUSHB_1,
1178 bci_action_stem_bound,
1179 FDEF,
1181 PUSHB_1,
1182 bci_handle_segments,
1183 CALL,
1184 PUSHB_1,
1185 bci_handle_segments,
1186 CALL,
1187 PUSHB_1,
1188 bci_handle_segments,
1189 CALL,
1191 /* XXX */
1193 ENDF,
1199 * bci_action_link
1201 * Handle the LINK action to link an edge to another one.
1203 * in: stem_is_serif
1204 * base_is_round
1205 * base_point (in twilight zone)
1206 * stem_point (in twilight zone)
1207 * ... stuff for bci_align_segments ...
1210 unsigned char FPGM(bci_action_link) [] = {
1212 PUSHB_1,
1213 bci_action_link,
1214 FDEF,
1216 PUSHB_1,
1218 SZPS, /* set zp0, zp1, and zp2 to twilight zone 0 */
1220 PUSHB_1,
1222 CINDEX,
1223 PUSHB_1,
1224 sal_num_segments,
1226 ADD,
1227 PUSHB_1,
1229 MINDEX,
1230 DUP,
1231 MDAP_noround, /* set rp0 and rp1 to `base_point' (for ALIGNRP below) */
1232 PUSHB_1,
1233 sal_num_segments,
1235 ADD, /* s: stem is_round is_serif stem_orig base_orig */
1237 MD_cur, /* s: stem is_round is_serif dist_orig */
1239 PUSHB_1,
1240 bci_compute_stem_width,
1241 CALL, /* s: stem new_dist */
1243 SWAP,
1244 DUP,
1245 ALIGNRP, /* align `stem_point' with `base_point' */
1246 DUP,
1247 MDAP_noround, /* set rp0 and rp1 to `stem_point' */
1248 SWAP,
1249 SHPIX, /* stem_point = base_point + new_dist */
1251 PUSHB_2,
1252 bci_align_segments,
1254 SZP1, /* set zp1 to normal zone 1 */
1255 CALL,
1257 ENDF,
1261 unsigned char FPGM(bci_action_anchor) [] = {
1263 PUSHB_1,
1264 bci_action_anchor,
1265 FDEF,
1267 PUSHB_1,
1268 bci_handle_segments,
1269 CALL,
1270 PUSHB_1,
1271 bci_handle_segments,
1272 CALL,
1274 /* XXX */
1276 ENDF,
1282 * bci_action_blue_anchor
1284 * Handle the BLUE_ANCHOR action to align an edge with a blue zone
1285 * and to set the edge anchor.
1287 * in: anchor_point (in twilight zone)
1288 * blue_cvt_idx
1289 * edge_point (in twilight zone)
1290 * ... stuff for bci_align_segments ...
1292 * sal: sal_anchor
1295 unsigned char FPGM(bci_action_blue_anchor) [] = {
1297 PUSHB_1,
1298 bci_action_blue_anchor,
1299 FDEF,
1301 /* store anchor point number in `sal_anchor' */
1302 PUSHB_1,
1303 sal_anchor,
1304 SWAP,
1307 PUSHB_1,
1309 SZP0, /* set zp0 to twilight zone 0 */
1311 /* move `edge_point' to `blue_cvt_idx' position */
1312 MIAP_noround, /* this also sets rp0 */
1314 PUSHB_2,
1315 bci_align_segments,
1317 SZP1, /* set zp1 to normal zone 1 */
1318 CALL,
1320 ENDF,
1324 unsigned char FPGM(bci_action_adjust) [] = {
1326 PUSHB_1,
1327 bci_action_adjust,
1328 FDEF,
1330 PUSHB_1,
1331 bci_handle_segments,
1332 CALL,
1333 PUSHB_1,
1334 bci_handle_segments,
1335 CALL,
1337 /* XXX */
1339 ENDF,
1343 unsigned char FPGM(bci_action_stem) [] = {
1345 PUSHB_1,
1346 bci_action_stem,
1347 FDEF,
1349 PUSHB_1,
1350 bci_handle_segments,
1351 CALL,
1352 PUSHB_1,
1353 bci_handle_segments,
1354 CALL,
1356 /* XXX */
1358 ENDF,
1364 * bci_action_blue
1366 * Handle the BLUE action to align an edge with a blue zone.
1368 * in: blue_cvt_idx
1369 * edge_point (in twilight zone)
1370 * ... stuff for bci_align_segments ...
1373 unsigned char FPGM(bci_action_blue) [] = {
1375 PUSHB_1,
1376 bci_action_blue,
1377 FDEF,
1379 PUSHB_1,
1381 SZP0, /* set zp0 to twilight zone 0 */
1383 /* move `edge_point' to `blue_cvt_idx' position */
1384 MIAP_noround, /* this also sets rp0 */
1386 PUSHB_2,
1387 bci_align_segments,
1389 SZP1, /* set zp1 to normal zone 1 */
1390 CALL,
1392 ENDF,
1396 unsigned char FPGM(bci_action_serif) [] = {
1398 PUSHB_1,
1399 bci_action_serif,
1400 FDEF,
1402 PUSHB_1,
1403 bci_handle_segments,
1404 CALL,
1406 /* XXX */
1408 ENDF,
1412 unsigned char FPGM(bci_action_serif_anchor) [] = {
1414 PUSHB_1,
1415 bci_action_serif_anchor,
1416 FDEF,
1418 PUSHB_1,
1419 bci_handle_segments,
1420 CALL,
1422 /* XXX */
1424 ENDF,
1428 unsigned char FPGM(bci_action_serif_link1) [] = {
1430 PUSHB_1,
1431 bci_action_serif_link1,
1432 FDEF,
1434 PUSHB_1,
1435 bci_handle_segments,
1436 CALL,
1438 /* XXX */
1440 ENDF,
1444 unsigned char FPGM(bci_action_serif_link2) [] = {
1446 PUSHB_1,
1447 bci_action_serif_link2,
1448 FDEF,
1450 PUSHB_1,
1451 bci_handle_segments,
1452 CALL,
1454 /* XXX */
1456 ENDF,
1462 * bci_handle_action
1464 * Execute function.
1466 * in: function_index
1469 unsigned char FPGM(bci_handle_action) [] = {
1471 PUSHB_1,
1472 bci_handle_action,
1473 FDEF,
1475 CALL,
1477 ENDF,
1483 * bci_hint_glyph
1485 * This is the top-level glyph hinting function
1486 * which parses the arguments on the stack and calls subroutines.
1488 * in: num_actions (M)
1489 * action_0_func_idx
1490 * ... data ...
1491 * action_1_func_idx
1492 * ... data ...
1493 * ...
1494 * action_M_func_idx
1495 * ... data ...
1497 * uses: bci_handle_action
1498 * bci_action_adjust_bound
1499 * bci_action_stem_bound
1501 * bci_action_link
1502 * bci_action_anchor
1503 * bci_action_blue_anchor
1504 * bci_action_adjust
1505 * bci_action_stem
1507 * bci_action_blue
1508 * bci_action_serif
1509 * bci_action_serif_anchor
1510 * bci_action_serif_link1
1511 * bci_action_serif_link2
1514 unsigned char FPGM(bci_hint_glyph) [] = {
1516 PUSHB_1,
1517 bci_hint_glyph,
1518 FDEF,
1520 PUSHB_1,
1521 bci_handle_action,
1522 LOOPCALL,
1524 ENDF,
1529 #define COPY_FPGM(func_name) \
1530 memcpy(buf_p, fpgm_ ## func_name, \
1531 sizeof (fpgm_ ## func_name)); \
1532 buf_p += sizeof (fpgm_ ## func_name) \
1534 static FT_Error
1535 TA_table_build_fpgm(FT_Byte** fpgm,
1536 FT_ULong* fpgm_len,
1537 FONT* font)
1539 FT_UInt buf_len;
1540 FT_UInt len;
1541 FT_Byte* buf;
1542 FT_Byte* buf_p;
1545 buf_len = sizeof (FPGM(bci_compute_stem_width_a))
1547 + sizeof (FPGM(bci_compute_stem_width_b))
1549 + sizeof (FPGM(bci_compute_stem_width_c))
1550 + sizeof (FPGM(bci_loop))
1551 + sizeof (FPGM(bci_cvt_rescale))
1552 + sizeof (FPGM(bci_sal_assign))
1553 + sizeof (FPGM(bci_set_up_segments))
1554 + sizeof (FPGM(bci_blue_round_a))
1556 + sizeof (FPGM(bci_blue_round_b))
1557 + sizeof (FPGM(bci_get_point_extrema))
1558 + sizeof (FPGM(bci_create_segment_point))
1559 + sizeof (FPGM(bci_create_segment_points))
1560 + sizeof (FPGM(bci_handle_segment))
1561 + sizeof (FPGM(bci_align_segment))
1562 + sizeof (FPGM(bci_handle_segments))
1563 + sizeof (FPGM(bci_align_segments))
1564 + sizeof (FPGM(bci_action_adjust_bound))
1565 + sizeof (FPGM(bci_action_stem_bound))
1566 + sizeof (FPGM(bci_action_link))
1567 + sizeof (FPGM(bci_action_anchor))
1568 + sizeof (FPGM(bci_action_blue_anchor))
1569 + sizeof (FPGM(bci_action_adjust))
1570 + sizeof (FPGM(bci_action_stem))
1571 + sizeof (FPGM(bci_action_blue))
1572 + sizeof (FPGM(bci_action_serif))
1573 + sizeof (FPGM(bci_action_serif_anchor))
1574 + sizeof (FPGM(bci_action_serif_link1))
1575 + sizeof (FPGM(bci_action_serif_link2))
1576 + sizeof (FPGM(bci_handle_action))
1577 + sizeof (FPGM(bci_hint_glyph));
1578 /* buffer length must be a multiple of four */
1579 len = (buf_len + 3) & ~3;
1580 buf = (FT_Byte*)malloc(len);
1581 if (!buf)
1582 return FT_Err_Out_Of_Memory;
1584 /* pad end of buffer with zeros */
1585 buf[len - 1] = 0x00;
1586 buf[len - 2] = 0x00;
1587 buf[len - 3] = 0x00;
1589 /* copy font program into buffer and fill in the missing variables */
1590 buf_p = buf;
1592 COPY_FPGM(bci_compute_stem_width_a);
1593 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1594 COPY_FPGM(bci_compute_stem_width_b);
1595 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1596 COPY_FPGM(bci_compute_stem_width_c);
1597 COPY_FPGM(bci_loop);
1598 COPY_FPGM(bci_cvt_rescale);
1599 COPY_FPGM(bci_sal_assign);
1600 COPY_FPGM(bci_set_up_segments);
1601 COPY_FPGM(bci_blue_round_a);
1602 *(buf_p++) = (unsigned char)CVT_BLUES_SIZE(font);
1603 COPY_FPGM(bci_blue_round_b);
1604 COPY_FPGM(bci_get_point_extrema);
1605 COPY_FPGM(bci_create_segment_point);
1606 COPY_FPGM(bci_create_segment_points);
1607 COPY_FPGM(bci_handle_segment);
1608 COPY_FPGM(bci_align_segment);
1609 COPY_FPGM(bci_handle_segments);
1610 COPY_FPGM(bci_align_segments);
1611 COPY_FPGM(bci_action_adjust_bound);
1612 COPY_FPGM(bci_action_stem_bound);
1613 COPY_FPGM(bci_action_link);
1614 COPY_FPGM(bci_action_anchor);
1615 COPY_FPGM(bci_action_blue_anchor);
1616 COPY_FPGM(bci_action_adjust);
1617 COPY_FPGM(bci_action_stem);
1618 COPY_FPGM(bci_action_blue);
1619 COPY_FPGM(bci_action_serif);
1620 COPY_FPGM(bci_action_serif_anchor);
1621 COPY_FPGM(bci_action_serif_link1);
1622 COPY_FPGM(bci_action_serif_link2);
1623 COPY_FPGM(bci_handle_action);
1624 COPY_FPGM(bci_hint_glyph);
1626 *fpgm = buf;
1627 *fpgm_len = buf_len;
1629 return FT_Err_Ok;
1633 FT_Error
1634 TA_sfnt_build_fpgm_table(SFNT* sfnt,
1635 FONT* font)
1637 FT_Error error;
1639 FT_Byte* fpgm_buf;
1640 FT_ULong fpgm_len;
1643 error = TA_sfnt_add_table_info(sfnt);
1644 if (error)
1645 return error;
1647 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
1648 if (error)
1649 return error;
1651 /* in case of success, `fpgm_buf' gets linked */
1652 /* and is eventually freed in `TA_font_unload' */
1653 error = TA_font_add_table(font,
1654 &sfnt->table_infos[sfnt->num_table_infos - 1],
1655 TTAG_fpgm, fpgm_len, fpgm_buf);
1656 if (error)
1658 free(fpgm_buf);
1659 return error;
1662 return FT_Err_Ok;
1666 /* the `prep' instructions */
1668 #define PREP(snippet_name) prep_ ## snippet_name
1670 /* we often need 0x10000 which can't be pushed directly onto the stack, */
1671 /* thus we provide it in the storage area */
1673 unsigned char PREP(store_0x10000) [] = {
1675 PUSHB_1,
1676 sal_0x10000,
1677 PUSHW_2,
1678 0x08, /* 0x800 */
1679 0x00,
1680 0x08, /* 0x800 */
1681 0x00,
1682 MUL, /* 0x10000 */
1687 unsigned char PREP(align_top_a) [] = {
1689 /* optimize the alignment of the top of small letters to the pixel grid */
1691 PUSHB_1,
1695 /* %c, index of alignment blue zone */
1697 unsigned char PREP(align_top_b) [] = {
1699 RCVT,
1700 DUP,
1701 DUP,
1702 PUSHB_1,
1704 ADD,
1705 FLOOR, /* fitted = FLOOR(scaled + 40) */
1706 DUP, /* s: scaled scaled fitted fitted */
1707 ROLL,
1708 NEQ,
1709 IF, /* s: scaled fitted */
1710 PUSHB_1,
1711 sal_0x10000,
1713 MUL, /* scaled in 16.16 format */
1714 SWAP,
1715 DIV, /* (fitted / scaled) in 16.16 format */
1717 PUSHB_1,
1718 sal_scale,
1719 SWAP,
1724 unsigned char PREP(loop_cvt_a) [] = {
1726 /* loop over vertical CVT entries */
1727 PUSHB_4,
1731 /* %c, first vertical index */
1732 /* %c, last vertical index */
1734 unsigned char PREP(loop_cvt_b) [] = {
1736 bci_cvt_rescale,
1737 bci_loop,
1738 CALL,
1740 /* loop over blue refs */
1741 PUSHB_4,
1745 /* %c, first blue ref index */
1746 /* %c, last blue ref index */
1748 unsigned char PREP(loop_cvt_c) [] = {
1750 bci_cvt_rescale,
1751 bci_loop,
1752 CALL,
1754 /* loop over blue shoots */
1755 PUSHB_4,
1759 /* %c, first blue shoot index */
1760 /* %c, last blue shoot index */
1762 unsigned char PREP(loop_cvt_d) [] = {
1764 bci_cvt_rescale,
1765 bci_loop,
1766 CALL,
1767 EIF,
1771 unsigned char PREP(compute_extra_light_a) [] = {
1773 /* compute (vertical) `extra_light' flag */
1774 PUSHB_3,
1775 sal_is_extra_light,
1780 /* %c, index of vertical standard_width */
1782 unsigned char PREP(compute_extra_light_b) [] = {
1784 RCVT,
1785 GT, /* standard_width < 40 */
1790 unsigned char PREP(round_blues_a) [] = {
1792 /* use discrete values for blue zone widths */
1793 PUSHB_4,
1797 /* %c, first blue ref index */
1798 /* %c, last blue ref index */
1800 unsigned char PREP(round_blues_b) [] = {
1802 bci_blue_round,
1803 bci_loop,
1804 CALL
1808 /* XXX talatin.c: 1671 */
1809 /* XXX talatin.c: 1708 */
1810 /* XXX talatin.c: 2182 */
1813 #define COPY_PREP(snippet_name) \
1814 memcpy(buf_p, prep_ ## snippet_name, \
1815 sizeof (prep_ ## snippet_name)); \
1816 buf_p += sizeof (prep_ ## snippet_name);
1818 static FT_Error
1819 TA_table_build_prep(FT_Byte** prep,
1820 FT_ULong* prep_len,
1821 FONT* font)
1823 TA_LatinAxis vaxis;
1824 TA_LatinBlue blue_adjustment;
1825 FT_UInt i;
1827 FT_UInt buf_len;
1828 FT_UInt len;
1829 FT_Byte* buf;
1830 FT_Byte* buf_p;
1833 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
1834 blue_adjustment = NULL;
1836 for (i = 0; i < vaxis->blue_count; i++)
1838 if (vaxis->blues[i].flags & TA_LATIN_BLUE_ADJUSTMENT)
1840 blue_adjustment = &vaxis->blues[i];
1841 break;
1845 buf_len = sizeof (PREP(store_0x10000));
1847 if (blue_adjustment)
1848 buf_len += sizeof (PREP(align_top_a))
1850 + sizeof (PREP(align_top_b))
1851 + sizeof (PREP(loop_cvt_a))
1853 + sizeof (PREP(loop_cvt_b))
1855 + sizeof (PREP(loop_cvt_c))
1857 + sizeof (PREP(loop_cvt_d));
1859 buf_len += sizeof (PREP(compute_extra_light_a))
1861 + sizeof (PREP(compute_extra_light_b));
1863 if (CVT_BLUES_SIZE(font))
1864 buf_len += sizeof (PREP(round_blues_a))
1866 + sizeof (PREP(round_blues_b));
1868 /* buffer length must be a multiple of four */
1869 len = (buf_len + 3) & ~3;
1870 buf = (FT_Byte*)malloc(len);
1871 if (!buf)
1872 return FT_Err_Out_Of_Memory;
1874 /* pad end of buffer with zeros */
1875 buf[len - 1] = 0x00;
1876 buf[len - 2] = 0x00;
1877 buf[len - 3] = 0x00;
1879 /* copy cvt program into buffer and fill in the missing variables */
1880 buf_p = buf;
1882 COPY_PREP(store_0x10000);
1884 if (blue_adjustment)
1886 COPY_PREP(align_top_a);
1887 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
1888 + blue_adjustment - vaxis->blues);
1889 COPY_PREP(align_top_b);
1891 COPY_PREP(loop_cvt_a);
1892 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
1893 *(buf_p++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font)
1894 + CVT_VERT_WIDTHS_SIZE(font) - 1);
1895 COPY_PREP(loop_cvt_b);
1896 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
1897 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
1898 + CVT_BLUES_SIZE(font) - 1);
1899 COPY_PREP(loop_cvt_c);
1900 *(buf_p++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font);
1901 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
1902 + CVT_BLUES_SIZE(font) - 1);
1903 COPY_PREP(loop_cvt_d);
1906 COPY_PREP(compute_extra_light_a);
1907 *(buf_p++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(font);
1908 COPY_PREP(compute_extra_light_b);
1910 if (CVT_BLUES_SIZE(font))
1912 COPY_PREP(round_blues_a);
1913 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
1914 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
1915 + CVT_BLUES_SIZE(font) - 1);
1916 COPY_PREP(round_blues_b);
1919 *prep = buf;
1920 *prep_len = buf_len;
1922 return FT_Err_Ok;
1926 FT_Error
1927 TA_sfnt_build_prep_table(SFNT* sfnt,
1928 FONT* font)
1930 FT_Error error;
1932 FT_Byte* prep_buf;
1933 FT_ULong prep_len;
1936 error = TA_sfnt_add_table_info(sfnt);
1937 if (error)
1938 return error;
1940 error = TA_table_build_prep(&prep_buf, &prep_len, font);
1941 if (error)
1942 return error;
1944 /* in case of success, `prep_buf' gets linked */
1945 /* and is eventually freed in `TA_font_unload' */
1946 error = TA_font_add_table(font,
1947 &sfnt->table_infos[sfnt->num_table_infos - 1],
1948 TTAG_prep, prep_len, prep_buf);
1949 if (error)
1951 free(prep_buf);
1952 return error;
1955 return FT_Err_Ok;
1959 /* we store the segments in the storage area; */
1960 /* each segment record consists of the first and last point */
1962 static FT_Byte*
1963 TA_sfnt_build_glyph_segments(SFNT* sfnt,
1964 FONT* font,
1965 FT_Byte* bufp)
1967 TA_GlyphHints hints = &font->loader->hints;
1968 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1969 TA_Point points = hints->points;
1970 TA_Segment segments = axis->segments;
1971 TA_Segment seg;
1972 TA_Segment seg_limit;
1974 FT_UInt* args;
1975 FT_UInt* arg;
1976 FT_UInt num_args;
1977 FT_UInt nargs;
1979 FT_Bool need_words = 0;
1981 FT_UInt i, j;
1982 FT_UInt num_storage;
1983 FT_UInt num_stack_elements;
1984 FT_UInt num_twilight_points;
1987 seg_limit = segments + axis->num_segments;
1988 num_args = 2 * axis->num_segments + 3;
1990 /* collect all arguments temporarily in an array (in reverse order) */
1991 /* so that we can easily split into chunks of 255 args */
1992 /* as needed by NPUSHB and NPUSHW, respectively */
1993 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1994 if (!args)
1995 return NULL;
1997 arg = args + num_args - 1;
1999 if (axis->num_segments > 0xFF)
2000 need_words = 1;
2002 *(arg--) = bci_set_up_segments;
2003 *(arg--) = axis->num_segments;
2004 *(arg--) = sal_segment_offset;
2006 for (seg = segments; seg < seg_limit; seg++)
2008 FT_UInt first = seg->first - points;
2009 FT_UInt last = seg->last - points;
2012 *(arg--) = first;
2013 *(arg--) = last;
2015 if (first > 0xFF || last > 0xFF)
2016 need_words = 1;
2019 /* with most fonts it is very rare */
2020 /* that any of the pushed arguments is larger than 0xFF, */
2021 /* thus we refrain from further optimizing this case */
2023 arg = args;
2025 if (need_words)
2027 for (i = 0; i < num_args; i += 255)
2029 nargs = (num_args - i > 255) ? 255 : num_args - i;
2031 BCI(NPUSHW);
2032 BCI(nargs);
2033 for (j = 0; j < nargs; j++)
2035 BCI(HIGH(*arg));
2036 BCI(LOW(*arg));
2037 arg++;
2041 else
2043 for (i = 0; i < num_args; i += 255)
2045 nargs = (num_args - i > 255) ? 255 : num_args - i;
2047 BCI(NPUSHB);
2048 BCI(nargs);
2049 for (j = 0; j < nargs; j++)
2051 BCI(*arg);
2052 arg++;
2057 BCI(CALL);
2059 num_storage = sal_segment_offset + axis->num_segments * 2;
2060 if (num_storage > sfnt->max_storage)
2061 sfnt->max_storage = num_storage;
2063 num_twilight_points = axis->num_segments * 2;
2064 if (num_twilight_points > sfnt->max_twilight_points)
2065 sfnt->max_twilight_points = num_twilight_points;
2067 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
2068 if (num_stack_elements > sfnt->max_stack_elements)
2069 sfnt->max_stack_elements = num_stack_elements;
2071 free(args);
2073 return bufp;
2077 static FT_Bool
2078 TA_hints_record_is_different(Hints_Record* hints_records,
2079 FT_UInt num_hints_records,
2080 FT_Byte* start,
2081 FT_Byte* end)
2083 Hints_Record last_hints_record;
2086 if (!hints_records)
2087 return 1;
2089 /* we only need to compare with the last hints record */
2090 last_hints_record = hints_records[num_hints_records - 1];
2092 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
2093 return 1;
2095 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
2096 return 1;
2098 return 0;
2102 static FT_Error
2103 TA_add_hints_record(Hints_Record** hints_records,
2104 FT_UInt* num_hints_records,
2105 FT_Byte* start,
2106 Hints_Record hints_record)
2108 Hints_Record* hints_records_new;
2109 FT_UInt buf_len;
2110 /* at this point, `hints_record.buf' still points into `ins_buf' */
2111 FT_Byte* end = hints_record.buf;
2114 buf_len = (FT_UInt)(end - start);
2116 /* now fill the structure completely */
2117 hints_record.buf_len = buf_len;
2118 hints_record.buf = (FT_Byte*)malloc(buf_len);
2119 if (!hints_record.buf)
2120 return FT_Err_Out_Of_Memory;
2122 memcpy(hints_record.buf, start, buf_len);
2124 (*num_hints_records)++;
2125 hints_records_new =
2126 (Hints_Record*)realloc(*hints_records, *num_hints_records
2127 * sizeof (Hints_Record));
2128 if (!hints_records_new)
2130 free(hints_record.buf);
2131 (*num_hints_records)--;
2132 return FT_Err_Out_Of_Memory;
2134 else
2135 *hints_records = hints_records_new;
2137 (*hints_records)[*num_hints_records - 1] = hints_record;
2139 return FT_Err_Ok;
2143 static FT_Byte*
2144 TA_sfnt_emit_hints_record(SFNT* sfnt,
2145 Hints_Record* hints_record,
2146 FT_Byte* bufp)
2148 FT_Byte* p;
2149 FT_Byte* endp;
2150 FT_Bool need_words = 0;
2152 FT_UInt i, j;
2153 FT_UInt num_arguments;
2154 FT_UInt num_args;
2155 FT_UInt num_stack_elements;
2158 /* check whether any argument is larger than 0xFF */
2159 endp = hints_record->buf + hints_record->buf_len;
2160 for (p = hints_record->buf; p < endp; p += 2)
2161 if (*p)
2162 need_words = 1;
2164 /* with most fonts it is very rare */
2165 /* that any of the pushed arguments is larger than 0xFF, */
2166 /* thus we refrain from further optimizing this case */
2168 num_arguments = hints_record->buf_len / 2;
2169 p = endp - 2;
2171 if (need_words)
2173 for (i = 0; i < num_arguments; i += 255)
2175 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2177 BCI(NPUSHW);
2178 BCI(num_args);
2179 for (j = 0; j < num_args; j++)
2181 BCI(*p);
2182 BCI(*(p + 1));
2183 p -= 2;
2187 else
2189 /* we only need the lower bytes */
2190 p++;
2192 for (i = 0; i < num_arguments; i += 255)
2194 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
2196 BCI(NPUSHB);
2197 BCI(num_args);
2198 for (j = 0; j < num_args; j++)
2200 BCI(*p);
2201 p -= 2;
2206 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
2207 if (num_stack_elements > sfnt->max_stack_elements)
2208 sfnt->max_stack_elements = sfnt->max_stack_elements;
2210 return bufp;
2214 static FT_Byte*
2215 TA_sfnt_emit_hints_records(SFNT* sfnt,
2216 Hints_Record* hints_records,
2217 FT_UInt num_hints_records,
2218 FT_Byte* bufp)
2220 FT_UInt i;
2221 Hints_Record* hints_record;
2224 hints_record = hints_records;
2226 for (i = 0; i < num_hints_records - 1; i++)
2228 BCI(MPPEM);
2229 if (hints_record->size > 0xFF)
2231 BCI(PUSHW_1);
2232 BCI(HIGH((hints_record + 1)->size));
2233 BCI(LOW((hints_record + 1)->size));
2235 else
2237 BCI(PUSHB_1);
2238 BCI((hints_record + 1)->size);
2240 BCI(LT);
2241 BCI(IF);
2242 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2243 BCI(ELSE);
2245 hints_record++;
2248 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
2250 for (i = 0; i < num_hints_records - 1; i++)
2251 BCI(EIF);
2253 BCI(PUSHB_1);
2254 BCI(bci_hint_glyph);
2255 BCI(CALL);
2257 return bufp;
2261 static void
2262 TA_free_hints_records(Hints_Record* hints_records,
2263 FT_UInt num_hints_records)
2265 FT_UInt i;
2268 for (i = 0; i < num_hints_records; i++)
2269 free(hints_records[i].buf);
2271 free(hints_records);
2275 static FT_Byte*
2276 TA_hints_recorder_handle_segments(FT_Byte* bufp,
2277 TA_Segment segments,
2278 TA_Edge edge)
2280 TA_Segment seg;
2281 FT_UInt seg_idx;
2282 FT_UInt num_segs = 0;
2285 seg_idx = edge->first - segments;
2287 /* we store everything as 16bit numbers */
2288 *(bufp++) = HIGH(seg_idx);
2289 *(bufp++) = LOW(seg_idx);
2291 seg = edge->first->edge_next;
2292 while (seg != edge->first)
2294 seg = seg->edge_next;
2295 num_segs++;
2298 *(bufp++) = HIGH(num_segs);
2299 *(bufp++) = LOW(num_segs);
2301 seg = edge->first->edge_next;
2302 while (seg != edge->first)
2304 seg_idx = seg - segments;
2305 seg = seg->edge_next;
2307 *(bufp++) = HIGH(seg_idx);
2308 *(bufp++) = LOW(seg_idx);
2311 return bufp;
2315 static void
2316 TA_hints_recorder(TA_Action action,
2317 TA_GlyphHints hints,
2318 TA_Dimension dim,
2319 void* arg1,
2320 void* arg2,
2321 void* arg3)
2323 TA_AxisHints axis = &hints->axis[dim];
2324 TA_Segment segments = axis->segments;
2326 Recorder* recorder = (Recorder*)hints->user;
2327 FONT* font = recorder->font;
2328 FT_Byte* p = recorder->hints_record.buf;
2331 if (dim == TA_DIMENSION_HORZ)
2332 return;
2334 /* we ignore the BOUND action since the information is handled */
2335 /* in `ta_adjust_bound' and `ta_stem_bound' */
2336 if (action == ta_bound)
2337 return;
2339 *(p++) = 0;
2340 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2342 switch (action)
2344 case ta_adjust_bound:
2345 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2346 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2347 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2348 break;
2350 case ta_stem_bound:
2351 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2352 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2353 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg3);
2354 break;
2356 case ta_link:
2358 TA_Edge base_edge = (TA_Edge)arg1;
2359 TA_Edge stem_edge = (TA_Edge)arg2;
2362 *(p++) = 0;
2363 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
2364 *(p++) = 0;
2365 *(p++) = base_edge->flags & TA_EDGE_ROUND;
2366 *(p++) = HIGH(base_edge->first - segments);
2367 *(p++) = LOW(base_edge->first - segments);
2368 *(p++) = HIGH(stem_edge->first - segments);
2369 *(p++) = LOW(stem_edge->first - segments);
2371 p = TA_hints_recorder_handle_segments(p, segments, stem_edge);
2373 break;
2375 case ta_anchor:
2376 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2377 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2378 break;
2380 case ta_blue_anchor:
2382 TA_Edge edge = (TA_Edge)arg1;
2383 TA_Edge blue = (TA_Edge)arg2;
2386 *(p++) = HIGH(blue->first - segments);
2387 *(p++) = LOW(blue->first - segments);
2389 if (edge->best_blue_is_shoot)
2391 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2392 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2394 else
2396 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2397 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2400 *(p++) = HIGH(edge->first - segments);
2401 *(p++) = LOW(edge->first - segments);
2403 p = TA_hints_recorder_handle_segments(p, segments, edge);
2405 break;
2407 case ta_adjust:
2408 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2409 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2410 break;
2412 case ta_stem:
2413 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2414 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg2);
2415 break;
2417 case ta_blue:
2419 TA_Edge edge = (TA_Edge)arg1;
2422 if (edge->best_blue_is_shoot)
2424 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2425 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
2427 else
2429 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2430 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
2433 *(p++) = HIGH(edge->first - segments);
2434 *(p++) = LOW(edge->first - segments);
2436 p = TA_hints_recorder_handle_segments(p, segments, edge);
2438 break;
2440 case ta_serif:
2441 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2442 break;
2444 case ta_serif_anchor:
2445 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2446 break;
2448 case ta_serif_link1:
2449 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2450 break;
2452 case ta_serif_link2:
2453 p = TA_hints_recorder_handle_segments(p, segments, (TA_Edge)arg1);
2454 break;
2456 /* to pacify the compiler */
2457 case ta_bound:
2458 break;
2461 recorder->hints_record.num_actions++;
2462 recorder->hints_record.buf = p;
2466 static FT_Error
2467 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2468 FONT* font,
2469 FT_Long idx)
2471 FT_Face face = sfnt->face;
2472 FT_Error error;
2474 FT_Byte* ins_buf;
2475 FT_UInt ins_len;
2476 FT_Byte* bufp;
2478 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2479 glyf_Data* data = (glyf_Data*)glyf_table->data;
2480 GLYPH* glyph = &data->glyphs[idx];
2482 TA_GlyphHints hints;
2484 FT_UInt num_hints_records;
2485 Hints_Record* hints_records;
2487 Recorder recorder;
2489 FT_UInt size;
2492 if (idx < 0)
2493 return FT_Err_Invalid_Argument;
2495 /* computing the segments is resolution independent, */
2496 /* thus the pixel size in this call is arbitrary */
2497 error = FT_Set_Pixel_Sizes(face, 20, 20);
2498 if (error)
2499 return error;
2501 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2502 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
2503 if (error)
2504 return error;
2506 /* do nothing if we have an empty glyph */
2507 if (!face->glyph->outline.n_contours)
2508 return FT_Err_Ok;
2510 hints = &font->loader->hints;
2512 /* we allocate a buffer which is certainly large enough */
2513 /* to hold all of the created bytecode instructions; */
2514 /* later on it gets reallocated to its real size */
2515 ins_len = hints->num_points * 1000;
2516 ins_buf = (FT_Byte*)malloc(ins_len);
2517 if (!ins_buf)
2518 return FT_Err_Out_Of_Memory;
2520 /* initialize array with an invalid bytecode */
2521 /* so that we can easily find the array length at reallocation time */
2522 memset(ins_buf, INS_A0, ins_len);
2524 bufp = TA_sfnt_build_glyph_segments(sfnt, font, ins_buf);
2526 /* now we loop over a large range of pixel sizes */
2527 /* to find hints records which get pushed onto the bytecode stack */
2528 num_hints_records = 0;
2529 hints_records = NULL;
2531 #ifdef DEBUGGING
2532 printf("glyph %ld\n", idx);
2533 #endif
2535 /* we temporarily use `ins_buf' to record the current glyph hints, */
2536 /* leaving two bytes at the beginning so that the number of actions */
2537 /* can be inserted later on */
2538 recorder.font = font;
2539 ta_loader_register_hints_recorder(font->loader,
2540 TA_hints_recorder,
2541 (void *)&recorder);
2543 for (size = 8; size <= 1000; size++)
2545 /* rewind buffer pointer for recorder */
2546 recorder.hints_record.buf = bufp + 2;
2547 recorder.hints_record.num_actions = 0;
2548 recorder.hints_record.size = size;
2550 error = FT_Set_Pixel_Sizes(face, size, size);
2551 if (error)
2552 goto Err;
2554 /* calling `ta_loader_load_glyph' uses the */
2555 /* `TA_hints_recorder' function as a callback, */
2556 /* modifying `hints_record' */
2557 error = ta_loader_load_glyph(font->loader, face, idx, 0);
2558 if (error)
2559 goto Err;
2561 /* store the number of actions in `ins_buf' */
2562 *bufp = HIGH(recorder.hints_record.num_actions);
2563 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
2565 if (TA_hints_record_is_different(hints_records,
2566 num_hints_records,
2567 bufp, recorder.hints_record.buf))
2569 #ifdef DEBUGGING
2571 FT_Byte* p;
2574 printf(" %d:\n", size);
2575 for (p = bufp; p < recorder.hints_record.buf; p += 2)
2576 printf(" %2d", *p * 256 + *(p + 1));
2577 printf("\n");
2579 #endif
2581 error = TA_add_hints_record(&hints_records,
2582 &num_hints_records,
2583 bufp, recorder.hints_record);
2584 if (error)
2585 goto Err;
2589 if (num_hints_records == 1 && !hints_records[0].num_actions)
2591 /* don't emit anything if we only have a single empty record */
2592 ins_len = 0;
2594 else
2596 FT_Byte* p = bufp;
2599 /* otherwise, clear the temporarily used part of `ins_buf' */
2600 while (*p != INS_A0)
2601 *(p++) = INS_A0;
2603 bufp = TA_sfnt_emit_hints_records(sfnt,
2604 hints_records, num_hints_records,
2605 bufp);
2607 /* we are done, so reallocate the instruction array to its real size */
2608 if (*bufp == INS_A0)
2610 /* search backwards */
2611 while (*bufp == INS_A0)
2612 bufp--;
2613 bufp++;
2615 else
2617 /* search forwards */
2618 while (*bufp != INS_A0)
2619 bufp++;
2622 ins_len = bufp - ins_buf;
2625 if (ins_len > sfnt->max_instructions)
2626 sfnt->max_instructions = ins_len;
2628 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2629 glyph->ins_len = ins_len;
2631 TA_free_hints_records(hints_records, num_hints_records);
2633 return FT_Err_Ok;
2635 Err:
2636 TA_free_hints_records(hints_records, num_hints_records);
2637 free(ins_buf);
2639 return error;
2643 FT_Error
2644 TA_sfnt_build_glyf_hints(SFNT* sfnt,
2645 FONT* font)
2647 FT_Face face = sfnt->face;
2648 FT_Long idx;
2649 FT_Error error;
2652 for (idx = 0; idx < face->num_glyphs; idx++)
2654 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
2655 if (error)
2656 return error;
2659 return FT_Err_Ok;
2662 /* end of tabytecode.c */