Add framework to handle hinting sets.
[ttfautohint.git] / src / tabytecode.c
blob9381db435ecf23214f47d94a21243cbf2f086f1c
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)
13 #ifdef TA_DEBUG
14 int _ta_debug = 1;
15 int _ta_debug_disable_horz_hints;
16 int _ta_debug_disable_vert_hints;
17 int _ta_debug_disable_blue_hints;
18 void* _ta_debug_hints;
19 #endif
22 /* structures for hinting sets */
23 typedef struct Edge2Blue_ {
24 FT_UInt first_segment;
26 FT_Bool is_serif;
27 FT_Bool is_round;
29 FT_UInt num_remaining_segments;
30 FT_UInt* remaining_segments;
31 } Edge2Blue;
33 typedef struct Edge2Link_ {
34 FT_UInt first_segment;
36 FT_UInt num_remaining_segments;
37 FT_UInt* remaining_segments;
38 } Edge2Link;
40 typedef struct Hinting_Set_ {
41 FT_UInt size;
43 FT_UInt num_edges2blues;
44 Edge2Blue* edges2blues;
46 FT_UInt num_edges2links;
47 Edge2Link* edges2links;
48 } Hinting_Set;
51 static FT_Error
52 TA_sfnt_compute_global_hints(SFNT* sfnt,
53 FONT* font)
55 FT_Error error;
56 FT_Face face = sfnt->face;
57 FT_UInt enc;
58 FT_UInt idx;
60 static const FT_Encoding latin_encs[] =
62 FT_ENCODING_UNICODE,
63 FT_ENCODING_APPLE_ROMAN,
64 FT_ENCODING_ADOBE_STANDARD,
65 FT_ENCODING_ADOBE_LATIN_1,
67 FT_ENCODING_NONE /* end of list */
71 error = ta_loader_init(font->loader);
72 if (error)
73 return error;
75 /* try to select a latin charmap */
76 for (enc = 0; latin_encs[enc] != FT_ENCODING_NONE; enc++)
78 error = FT_Select_Charmap(face, latin_encs[enc]);
79 if (!error)
80 break;
83 /* load latin glyph `a' to trigger all initializations */
84 idx = FT_Get_Char_Index(face, 'a');
85 error = ta_loader_load_glyph(font->loader, face, idx, 0);
87 return error;
91 static FT_Error
92 TA_table_build_cvt(FT_Byte** cvt,
93 FT_ULong* cvt_len,
94 SFNT* sfnt,
95 FONT* font)
97 TA_LatinAxis haxis;
98 TA_LatinAxis vaxis;
100 FT_UInt i;
101 FT_UInt buf_len;
102 FT_UInt len;
103 FT_Byte* buf;
104 FT_Byte* buf_p;
106 FT_Error error;
109 error = TA_sfnt_compute_global_hints(sfnt, font);
110 if (error)
111 return error;
113 /* XXX check validity of pointers */
114 haxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[0];
115 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
117 buf_len = 2 * (haxis->width_count + vaxis->width_count
118 + 2 * vaxis->blue_count);
120 /* buffer length must be a multiple of four */
121 len = (buf_len + 3) & ~3;
122 buf = (FT_Byte*)malloc(len);
123 if (!buf)
124 return FT_Err_Out_Of_Memory;
126 /* pad end of buffer with zeros */
127 buf[len - 1] = 0x00;
128 buf[len - 2] = 0x00;
129 buf[len - 3] = 0x00;
131 buf_p = buf;
133 /* XXX emit standard_width also? */
135 for (i = 0; i < haxis->width_count; i++)
137 if (haxis->widths[i].org > 0xFFFF)
138 goto Err;
139 *(buf_p++) = HIGH(haxis->widths[i].org);
140 *(buf_p++) = LOW(haxis->widths[i].org);
143 for (i = 0; i < vaxis->width_count; i++)
145 if (vaxis->widths[i].org > 0xFFFF)
146 goto Err;
147 *(buf_p++) = HIGH(vaxis->widths[i].org);
148 *(buf_p++) = LOW(vaxis->widths[i].org);
151 for (i = 0; i < vaxis->blue_count; i++)
153 if (vaxis->blues[i].ref.org > 0xFFFF)
154 goto Err;
155 *(buf_p++) = HIGH(vaxis->blues[i].ref.org);
156 *(buf_p++) = LOW(vaxis->blues[i].ref.org);
159 for (i = 0; i < vaxis->blue_count; i++)
161 if (vaxis->blues[i].shoot.org > 0xFFFF)
162 goto Err;
163 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
164 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
167 #if 0
168 TA_LOG(("--------------------------------------------------\n"));
169 TA_LOG(("glyph %d:\n", idx));
170 ta_glyph_hints_dump_edges(_ta_debug_hints);
171 ta_glyph_hints_dump_segments(_ta_debug_hints);
172 ta_glyph_hints_dump_points(_ta_debug_hints);
173 #endif
175 *cvt = buf;
176 *cvt_len = buf_len;
178 return FT_Err_Ok;
180 Err:
181 free(buf);
182 return TA_Err_Hinter_Overflow;
186 FT_Error
187 TA_sfnt_build_cvt_table(SFNT* sfnt,
188 FONT* font)
190 FT_Error error;
192 FT_Byte* cvt_buf;
193 FT_ULong cvt_len;
196 error = TA_sfnt_add_table_info(sfnt);
197 if (error)
198 return error;
200 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
201 if (error)
202 return error;
204 /* in case of success, `cvt_buf' gets linked */
205 /* and is eventually freed in `TA_font_unload' */
206 error = TA_font_add_table(font,
207 &sfnt->table_infos[sfnt->num_table_infos - 1],
208 TTAG_cvt, cvt_len, cvt_buf);
209 if (error)
211 free(cvt_buf);
212 return error;
215 return FT_Err_Ok;
219 /* the horizontal stem widths */
220 #define CVT_HORZ_WIDTHS_OFFSET(font) 0
221 #define CVT_HORZ_WIDTHS_SIZE(font) \
222 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
224 /* the vertical stem widths */
225 #define CVT_VERT_WIDTHS_OFFSET(font) \
226 CVT_HORZ_WIDTHS_OFFSET(font) \
227 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
228 #define CVT_VERT_WIDTHS_SIZE(font) \
229 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
231 /* the blue zone values for flat edges */
232 #define CVT_BLUE_REFS_OFFSET(font) \
233 CVT_VERT_WIDTHS_OFFSET(font) \
234 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
235 #define CVT_BLUE_REFS_SIZE(font) \
236 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
238 /* the blue zone values for round edges */
239 #define CVT_BLUE_SHOOTS_OFFSET(font) \
240 CVT_BLUE_REFS_OFFSET(font) \
241 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
242 #define CVT_BLUE_SHOOTS_SIZE(font) \
243 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
246 /* symbolic names for storage area locations */
248 #define sal_counter 0
249 #define sal_limit 1
250 #define sal_scale 2
251 #define sal_0x10000 3
252 #define sal_segment_offset 4
255 /* in the comments below, the top of the stack (`s:') */
256 /* is the rightmost element; the stack is shown */
257 /* after the instruction on the same line has been executed */
260 * compute_stem_width
262 * This is the equivalent to the following code from function
263 * `ta_latin_compute_stem_width':
265 * dist = ABS(width)
267 * if stem_is_serif
268 * && dist < 3*64:
269 * return width
270 * else if base_is_round:
271 * if dist < 80
272 * dist = 64
273 * else:
274 * dist = MIN(56, dist)
276 * delta = ABS(dist - std_width)
278 * if delta < 40:
279 * dist = MIN(48, std_width)
280 * goto End
282 * if dist < 3*64:
283 * delta = dist
284 * dist = FLOOR(dist)
285 * delta = delta - dist
287 * if delta < 10:
288 * dist = dist + delta
289 * else if delta < 32:
290 * dist = dist + 10
291 * else if delta < 54:
292 * dist = dist + 54
293 * else
294 * dist = dist + delta
295 * else
296 * dist = ROUND(dist)
298 * End:
299 * if width < 0:
300 * dist = -dist
301 * return dist
305 * Function 0: compute_stem_width
307 * in: width
308 * stem_is_serif
309 * base_is_round
310 * out: new_width
311 * CVT: is_extra_light XXX
312 * std_width
315 #define compute_stem_width 0
317 unsigned char fpgm_0a[] = {
319 PUSHB_1,
320 compute_stem_width,
321 FDEF,
323 DUP,
324 ABS, /* s: base_is_round stem_is_serif width dist */
326 DUP,
327 PUSHB_1,
328 3*64,
329 LT, /* dist < 3*64 */
331 PUSHB_1,
333 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
335 AND, /* stem_is_serif && dist < 3*64 */
336 IF, /* s: base_is_round width dist */
337 POP,
338 SWAP,
339 POP, /* s: width */
341 ELSE,
342 ROLL, /* s: width dist base_is_round */
343 IF, /* s: width dist */
344 DUP,
345 PUSHB_1,
347 LT, /* dist < 80 */
348 IF, /* s: width dist */
349 POP,
350 PUSHB_1,
351 64, /* dist = 64 */
352 EIF,
354 ELSE,
355 PUSHB_1,
357 MIN, /* dist = min(56, dist) */
358 EIF,
360 DUP, /* s: width dist dist */
361 PUSHB_1,
365 /* %c, index of std_width */
367 unsigned char fpgm_0b[] = {
369 RCVT,
370 SUB,
371 ABS, /* s: width dist delta */
373 PUSHB_1,
375 LT, /* delta < 40 */
376 IF, /* s: width dist */
377 POP,
378 PUSHB_2,
383 /* %c, index of std_width */
385 unsigned char fpgm_0c[] = {
387 RCVT,
388 MIN, /* dist = min(48, std_width) */
390 ELSE,
391 DUP, /* s: width dist dist */
392 PUSHB_1,
393 3*64,
394 LT, /* dist < 3*64 */
396 DUP, /* s: width delta dist */
397 FLOOR, /* dist = FLOOR(dist) */
398 DUP, /* s: width delta dist dist */
399 ROLL,
400 ROLL, /* s: width dist delta dist */
401 SUB, /* delta = delta - dist */
403 DUP, /* s: width dist delta delta */
404 PUSHB_1,
406 LT, /* delta < 10 */
407 IF, /* s: width dist delta */
408 ADD, /* dist = dist + delta */
410 ELSE,
411 DUP,
412 PUSHB_1,
414 LT, /* delta < 32 */
416 POP,
417 PUSHB_1,
419 ADD, /* dist = dist + 10 */
421 ELSE,
422 DUP,
423 PUSHB_1,
425 LT, /* delta < 54 */
427 POP,
428 PUSHB_1,
430 ADD, /* dist = dist + 54 */
432 ELSE,
433 ADD, /* dist = dist + delta */
435 EIF,
436 EIF,
437 EIF,
439 ELSE,
440 PUSHB_1,
442 ADD,
443 FLOOR, /* dist = round(dist) */
445 EIF,
446 EIF,
448 SWAP, /* s: dist width */
449 PUSHB_1,
451 LT, /* width < 0 */
452 NEG, /* dist = -dist */
454 EIF,
455 EIF,
457 ENDF,
463 * loop
465 * Take a range and a function number and apply the function to all
466 * elements of the range. The called function must not change the
467 * stack.
469 * Function 1: loop
471 * in: func_num
472 * end
473 * start
475 * uses: sal_counter (counter initialized with `start')
476 * sal_limit (`end')
479 #define loop 1
481 unsigned char fpgm_1[] = {
483 PUSHB_1,
484 loop,
485 FDEF,
487 ROLL,
488 ROLL, /* s: func_num start end */
489 PUSHB_1,
490 sal_limit,
491 SWAP,
494 PUSHB_1,
495 sal_counter,
496 SWAP,
499 /* start_loop: */
500 PUSHB_1,
501 sal_counter,
503 PUSHB_1,
504 sal_limit,
506 LTEQ, /* start <= end */
507 IF, /* s: func_num */
508 DUP,
509 CALL,
510 PUSHB_2,
512 sal_counter,
514 ADD, /* start = start + 1 */
515 PUSHB_1,
516 sal_counter,
517 SWAP,
520 PUSHB_1,
522 NEG,
523 JMPR, /* goto start_loop */
524 ELSE,
525 POP,
526 EIF,
528 ENDF,
534 * rescale
536 * All entries in the CVT table get scaled automatically using the
537 * vertical resolution. However, some widths must be scaled with the
538 * horizontal resolution, and others get adjusted later on.
540 * Function 2: rescale
542 * uses: sal_counter (CVT index)
543 * sal_scale (scale in 16.16 format)
546 #define rescale 2
548 unsigned char fpgm_2[] = {
550 PUSHB_1,
551 rescale,
552 FDEF,
554 PUSHB_1,
555 sal_counter,
557 DUP,
558 RCVT,
559 PUSHB_1,
560 sal_scale,
562 MUL, /* CVT * scale * 2^10 */
563 PUSHB_1,
564 sal_0x10000,
566 DIV, /* CVT * scale */
568 WCVTP,
570 ENDF,
576 * sal_loop_assign
578 * Apply the WS instruction repeatedly to stack data.
580 * Function 3: sal_loop_assign
582 * in: counter (N)
583 * offset
584 * data_N-1
585 * data_N-2
586 * ...
587 * data_0
589 * uses: sal_assign
592 #define sal_assign 3
594 unsigned char fpgm_3[] = {
596 PUSHB_1,
597 sal_assign,
598 FDEF,
600 DUP,
601 ROLL, /* s: offset offset data */
604 PUSHB_1,
606 SUB, /* s: (offset - 1) */
608 ENDF,
612 #define sal_loop_assign 4
614 unsigned char fpgm_4[] = {
616 PUSHB_1,
617 sal_loop_assign,
618 FDEF,
620 DUP, /* s: offset counter counter */
621 ROLL,
622 ADD,
623 PUSHB_1,
625 SUB,
626 SWAP, /* s: (offset + counter - 1) counter */
628 /* process the stack, popping off the elements in a loop */
629 PUSHB_1,
630 sal_assign,
631 LOOPCALL,
632 POP,
634 ENDF,
639 static FT_Error
640 TA_table_build_fpgm(FT_Byte** fpgm,
641 FT_ULong* fpgm_len,
642 FONT* font)
644 FT_UInt buf_len;
645 FT_UInt len;
646 FT_Byte* buf;
647 FT_Byte* buf_p;
650 buf_len = sizeof (fpgm_0a)
652 + sizeof (fpgm_0b)
654 + sizeof (fpgm_0c)
655 + sizeof (fpgm_1)
656 + sizeof (fpgm_2)
657 + sizeof (fpgm_3)
658 + sizeof (fpgm_4);
659 /* buffer length must be a multiple of four */
660 len = (buf_len + 3) & ~3;
661 buf = (FT_Byte*)malloc(len);
662 if (!buf)
663 return FT_Err_Out_Of_Memory;
665 /* pad end of buffer with zeros */
666 buf[len - 1] = 0x00;
667 buf[len - 2] = 0x00;
668 buf[len - 3] = 0x00;
670 /* copy font program into buffer and fill in the missing variables */
671 buf_p = buf;
673 memcpy(buf_p, fpgm_0a, sizeof (fpgm_0a));
674 buf_p += sizeof (fpgm_0a);
676 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
678 memcpy(buf_p, fpgm_0b, sizeof (fpgm_0b));
679 buf_p += sizeof (fpgm_0b);
681 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
683 memcpy(buf_p, fpgm_0c, sizeof (fpgm_0c));
684 buf_p += sizeof (fpgm_0c);
686 memcpy(buf_p, fpgm_1, sizeof (fpgm_1));
687 buf_p += sizeof (fpgm_1);
689 memcpy(buf_p, fpgm_2, sizeof (fpgm_2));
690 buf_p += sizeof (fpgm_2);
692 memcpy(buf_p, fpgm_3, sizeof (fpgm_3));
693 buf_p += sizeof (fpgm_3);
695 memcpy(buf_p, fpgm_4, sizeof (fpgm_4));
697 *fpgm = buf;
698 *fpgm_len = buf_len;
700 return FT_Err_Ok;
704 FT_Error
705 TA_sfnt_build_fpgm_table(SFNT* sfnt,
706 FONT* font)
708 FT_Error error;
710 FT_Byte* fpgm_buf;
711 FT_ULong fpgm_len;
714 error = TA_sfnt_add_table_info(sfnt);
715 if (error)
716 return error;
718 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
719 if (error)
720 return error;
722 /* in case of success, `fpgm_buf' gets linked */
723 /* and is eventually freed in `TA_font_unload' */
724 error = TA_font_add_table(font,
725 &sfnt->table_infos[sfnt->num_table_infos - 1],
726 TTAG_fpgm, fpgm_len, fpgm_buf);
727 if (error)
729 free(fpgm_buf);
730 return error;
733 return FT_Err_Ok;
737 /* the `prep' instructions */
739 /* we often need 0x10000 which can't be pushed directly onto the stack, */
740 /* thus we provide it in the storage area */
742 unsigned char prep_A[] = {
744 PUSHB_1,
745 sal_0x10000,
746 PUSHW_2,
747 0x08, /* 0x800 */
748 0x00,
749 0x08, /* 0x800 */
750 0x00,
751 MUL, /* 0x10000 */
757 unsigned char prep_a[] = {
759 /* scale horizontal CVT entries */
760 /* if horizontal and vertical resolutions differ */
762 SVTCA_x,
763 MPPEM,
764 SVTCA_y,
765 MPPEM,
766 NEQ, /* horz_ppem != vert_ppem */
768 SVTCA_x,
769 MPPEM,
770 PUSHB_1,
771 sal_0x10000,
773 MUL, /* horz_ppem in 22.10 format */
775 SVTCA_y,
776 MPPEM,
777 DIV, /* (horz_ppem / vert_ppem) in 16.16 format */
779 PUSHB_1,
780 sal_scale,
781 SWAP,
784 /* loop over horizontal CVT entries */
785 PUSHB_4,
789 /* %c, first horizontal index */
790 /* %c, last horizontal index */
792 unsigned char prep_b[] = {
794 rescale,
795 loop,
796 CALL,
797 EIF,
801 unsigned char prep_c[] = {
803 /* optimize the alignment of the top of small letters to the pixel grid */
805 PUSHB_1,
809 /* %c, index of alignment blue zone */
811 unsigned char prep_d[] = {
813 RCVT,
814 DUP,
815 DUP,
816 PUSHB_1,
818 ADD,
819 FLOOR, /* fitted = FLOOR(scaled + 40) */
820 DUP, /* s: scaled scaled fitted fitted */
821 ROLL,
822 NEQ,
823 IF, /* s: scaled fitted */
824 PUSHB_1,
825 sal_0x10000,
827 MUL, /* scaled in 16.16 format */
828 SWAP,
829 DIV, /* (fitted / scaled) in 16.16 format */
831 PUSHB_1,
832 sal_scale,
833 SWAP,
836 /* loop over vertical CVT entries */
837 PUSHB_4,
841 /* %c, first vertical index */
842 /* %c, last vertical index */
844 unsigned char prep_e[] = {
846 rescale,
847 loop,
848 CALL,
850 /* loop over blue refs */
851 PUSHB_4,
855 /* %c, first blue ref index */
856 /* %c, last blue ref index */
858 unsigned char prep_f[] = {
860 rescale,
861 loop,
862 CALL,
864 /* loop over blue shoots */
865 PUSHB_4,
869 /* %c, first blue shoot index */
870 /* %c, last blue shoot index */
872 unsigned char prep_g[] = {
874 rescale,
875 loop,
876 CALL,
878 EIF,
883 static FT_Error
884 TA_table_build_prep(FT_Byte** prep,
885 FT_ULong* prep_len,
886 FONT* font)
888 TA_LatinAxis vaxis;
889 TA_LatinBlue blue_adjustment;
890 FT_UInt i;
892 FT_UInt buf_len;
893 FT_UInt len;
894 FT_Byte* buf;
895 FT_Byte* buf_p;
898 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
899 blue_adjustment = NULL;
901 for (i = 0; i < vaxis->blue_count; i++)
903 if (vaxis->blues[i].flags & TA_LATIN_BLUE_ADJUSTMENT)
905 blue_adjustment = &vaxis->blues[i];
906 break;
910 buf_len = sizeof (prep_A)
911 + sizeof (prep_a)
913 + sizeof (prep_b);
915 if (blue_adjustment)
917 buf_len += sizeof (prep_c)
919 + sizeof (prep_d)
921 + sizeof (prep_e)
923 + sizeof (prep_f)
925 + sizeof (prep_g);
928 /* buffer length must be a multiple of four */
929 len = (buf_len + 3) & ~3;
930 buf = (FT_Byte*)malloc(len);
931 if (!buf)
932 return FT_Err_Out_Of_Memory;
934 /* pad end of buffer with zeros */
935 buf[len - 1] = 0x00;
936 buf[len - 2] = 0x00;
937 buf[len - 3] = 0x00;
939 /* copy cvt program into buffer and fill in the missing variables */
940 buf_p = buf;
942 memcpy(buf_p, prep_A, sizeof (prep_A));
943 buf_p += sizeof (prep_A);
945 memcpy(buf_p, prep_a, sizeof (prep_a));
946 buf_p += sizeof (prep_a);
948 *(buf_p++) = (unsigned char)CVT_HORZ_WIDTHS_OFFSET(font);
949 *(buf_p++) = (unsigned char)(CVT_HORZ_WIDTHS_OFFSET(font)
950 + CVT_HORZ_WIDTHS_SIZE(font) - 1);
952 memcpy(buf_p, prep_b, sizeof (prep_b));
954 if (blue_adjustment)
956 buf_p += sizeof (prep_b);
958 memcpy(buf_p, prep_c, sizeof (prep_c));
959 buf_p += sizeof (prep_c);
961 *(buf_p++) = blue_adjustment - vaxis->blues
962 + CVT_BLUE_SHOOTS_OFFSET(font);
964 memcpy(buf_p, prep_d, sizeof (prep_d));
965 buf_p += sizeof (prep_d);
967 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
968 *(buf_p++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font)
969 + CVT_VERT_WIDTHS_SIZE(font) - 1);
971 memcpy(buf_p, prep_e, sizeof (prep_e));
972 buf_p += sizeof (prep_e);
974 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
975 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
976 + CVT_BLUE_REFS_SIZE(font) - 1);
978 memcpy(buf_p, prep_f, sizeof (prep_f));
979 buf_p += sizeof (prep_f);
981 *(buf_p++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font);
982 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
983 + CVT_BLUE_SHOOTS_SIZE(font) - 1);
985 memcpy(buf_p, prep_g, sizeof (prep_g));
988 /* XXX handle extra_light */
990 *prep = buf;
991 *prep_len = buf_len;
993 return FT_Err_Ok;
997 FT_Error
998 TA_sfnt_build_prep_table(SFNT* sfnt,
999 FONT* font)
1001 FT_Error error;
1003 FT_Byte* prep_buf;
1004 FT_ULong prep_len;
1007 error = TA_sfnt_add_table_info(sfnt);
1008 if (error)
1009 return error;
1011 error = TA_table_build_prep(&prep_buf, &prep_len, font);
1012 if (error)
1013 return error;
1015 /* in case of success, `prep_buf' gets linked */
1016 /* and is eventually freed in `TA_font_unload' */
1017 error = TA_font_add_table(font,
1018 &sfnt->table_infos[sfnt->num_table_infos - 1],
1019 TTAG_prep, prep_len, prep_buf);
1020 if (error)
1022 free(prep_buf);
1023 return error;
1026 return FT_Err_Ok;
1030 /* we store the segments in the storage area; */
1031 /* each segment record consists of the first and last point */
1033 static void
1034 TA_font_build_glyph_segments(FONT* font,
1035 FT_Byte* bufp)
1037 TA_GlyphHints hints = &font->loader->hints;
1038 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1039 TA_Point points = hints->points;
1040 TA_Segment segments = axis->segments;
1041 TA_Segment seg;
1043 FT_UInt delta;
1044 FT_UInt count;
1045 FT_UInt limit;
1046 FT_UInt loop_limit;
1047 FT_UInt i;
1050 limit = axis->num_segments * 2 + 2;
1051 seg = segments;
1053 /* NPUSHB and NPUSHW can't handle more than 256 stack elements */
1055 if (hints->num_points > 0xFF)
1057 count = 0;
1059 if (limit - count > 256)
1061 delta = 256;
1062 loop_limit = 128;
1064 if (axis->num_segments == 127)
1065 loop_limit = 127;
1067 else
1069 delta = limit - count;
1070 loop_limit = (delta - 2) / 2;
1073 while (count < limit)
1075 BCI(NPUSHW);
1076 BCI(delta);
1078 for (i = 0; i < loop_limit; i++, seg++)
1080 BCI(HIGH(seg->first - points));
1081 BCI(LOW(seg->first - points));
1082 BCI(HIGH(seg->last - points));
1083 BCI(LOW(seg->last - points));
1086 count += delta;
1088 if (limit - count > 256)
1090 delta = 256;
1091 loop_limit = 128;
1093 if (axis->num_segments == 127)
1094 loop_limit = 127;
1096 else
1098 delta = limit - count;
1099 loop_limit = (delta - 2) / 2;
1103 BCI(HIGH(sal_segment_offset));
1104 BCI(LOW(sal_segment_offset));
1105 BCI(HIGH(axis->num_segments * 2));
1106 BCI(LOW(axis->num_segments * 2));
1108 else
1110 count = 0;
1112 if (limit - count > 256)
1114 delta = 256;
1115 loop_limit = 128;
1117 if (axis->num_segments == 127)
1118 loop_limit = 127;
1120 else
1122 delta = limit - count;
1123 loop_limit = (delta - 2) / 2;
1126 while (count < limit)
1128 BCI(NPUSHB);
1129 BCI(delta);
1131 for (i = 0; i < loop_limit; i++, seg++)
1133 BCI(seg->first - points);
1134 BCI(seg->last - points);
1137 count += delta;
1139 if (limit - count > 256)
1141 delta = 256;
1142 loop_limit = 128;
1144 if (axis->num_segments == 127)
1145 loop_limit = 127;
1147 else
1149 delta = limit - count;
1150 loop_limit = (delta - 2) / 2;
1154 BCI(sal_segment_offset);
1155 BCI(axis->num_segments * 2);
1158 BCI(PUSHB_1);
1159 BCI(sal_loop_assign);
1160 BCI(CALL);
1164 static void
1165 TA_font_clear_edge_DONE_flag(FONT* font)
1167 TA_GlyphHints hints = &font->loader->hints;
1168 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1169 TA_Edge edges = axis->edges;
1170 TA_Edge edge_limit = edges + axis->num_edges;
1171 TA_Edge edge;
1174 for (edge = edges; edge < edge_limit; edge++)
1175 edge->flags &= ~TA_EDGE_DONE;
1179 static FT_Error
1180 TA_construct_hinting_set(FONT* font,
1181 FT_UInt size,
1182 Hinting_Set* hinting_set)
1184 hinting_set->size = size;
1186 /* XXX use real values */
1187 hinting_set->num_edges2blues = 0;
1188 hinting_set->edges2blues = NULL;
1189 hinting_set->num_edges2links = 0;
1190 hinting_set->edges2links = NULL;
1192 return FT_Err_Ok;
1196 static FT_Bool
1197 TA_hinting_set_is_different(Hinting_Set* hinting_sets,
1198 FT_UInt num_hinting_sets,
1199 Hinting_Set hinting_set)
1201 Hinting_Set last_hinting_set;
1203 Edge2Blue* edge2blue;
1204 Edge2Blue* last_edge2blue;
1205 Edge2Link* edge2link;
1206 Edge2Link* last_edge2link;
1208 FT_UInt i;
1211 if (!hinting_sets)
1212 return 1;
1214 /* we only need to compare with the last hinting set */
1215 last_hinting_set = hinting_sets[num_hinting_sets - 1];
1217 if (hinting_set.num_edges2blues
1218 != last_hinting_set.num_edges2blues)
1219 return 1;
1221 edge2blue = hinting_set.edges2blues;
1222 last_edge2blue = last_hinting_set.edges2blues;
1224 for (i = 0;
1225 i < hinting_set.num_edges2blues;
1226 i++, edge2blue++, last_edge2blue++)
1228 if (edge2blue->num_remaining_segments
1229 != last_edge2blue->num_remaining_segments)
1230 return 1;
1232 if (edge2blue->remaining_segments)
1234 if (memcmp(edge2blue->remaining_segments,
1235 last_edge2blue->remaining_segments,
1236 sizeof (FT_UInt) * edge2blue->num_remaining_segments))
1237 return 1;
1241 if (hinting_set.num_edges2links
1242 != last_hinting_set.num_edges2links)
1243 return 1;
1245 edge2link = hinting_set.edges2links;
1246 last_edge2link = last_hinting_set.edges2links;
1248 for (i = 0;
1249 i < hinting_set.num_edges2links;
1250 i++, edge2link++, last_edge2link++)
1252 if (edge2link->num_remaining_segments
1253 != last_edge2link->num_remaining_segments)
1254 return 1;
1256 if (edge2link->remaining_segments)
1258 if (memcmp(edge2link->remaining_segments,
1259 last_edge2link->remaining_segments,
1260 sizeof (FT_UInt) * edge2link->num_remaining_segments))
1261 return 1;
1265 return 0;
1269 static FT_Error
1270 TA_add_hinting_set(Hinting_Set** hinting_sets,
1271 FT_UInt* num_hinting_sets,
1272 Hinting_Set hinting_set)
1274 Hinting_Set* hinting_sets_new;
1277 (*num_hinting_sets)++;
1278 hinting_sets_new =
1279 (Hinting_Set*)realloc(*hinting_sets, *num_hinting_sets
1280 * sizeof (Hinting_Set));
1281 if (!hinting_sets_new)
1283 (*num_hinting_sets)--;
1284 return FT_Err_Out_Of_Memory;
1286 else
1287 *hinting_sets = hinting_sets_new;
1289 *hinting_sets[*num_hinting_sets - 1] = hinting_set;
1291 return FT_Err_Ok;
1295 static void
1296 TA_free_hinting_set(Hinting_Set hinting_set)
1298 FT_UInt i;
1301 for (i = 0; i < hinting_set.num_edges2blues; i++)
1302 free(hinting_set.edges2blues[i].remaining_segments);
1303 free(hinting_set.edges2blues);
1305 for (i = 0; i < hinting_set.num_edges2links; i++)
1306 free(hinting_set.edges2links[i].remaining_segments);
1307 free(hinting_set.edges2links);
1311 static void
1312 TA_free_hinting_sets(Hinting_Set* hinting_sets,
1313 FT_UInt num_hinting_sets)
1315 FT_UInt i;
1318 for (i = 0; i < num_hinting_sets; i++)
1319 TA_free_hinting_set(hinting_sets[i]);
1321 free(hinting_sets);
1325 static FT_Error
1326 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1327 FONT* font,
1328 FT_Long idx)
1330 FT_Face face = sfnt->face;
1331 FT_Error error;
1333 FT_Byte* ins_buf;
1334 FT_UInt ins_len;
1335 FT_Byte* p;
1337 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1338 glyf_Data* data = (glyf_Data*)glyf_table->data;
1339 GLYPH* glyph = &data->glyphs[idx];
1341 TA_GlyphHints hints;
1343 FT_UInt num_hinting_sets;
1344 Hinting_Set* hinting_sets;
1346 FT_UInt size;
1349 if (idx < 0)
1350 return FT_Err_Invalid_Argument;
1352 /* computing the segments is resolution independent, */
1353 /* thus the pixel size in this call is arbitrary */
1354 error = FT_Set_Pixel_Sizes(face, 20, 20);
1355 if (error)
1356 return error;
1358 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, 0);
1359 if (error)
1360 return error;
1362 /* do nothing if we have an empty glyph */
1363 if (!face->glyph->outline.n_contours)
1364 return FT_Err_Ok;
1366 hints = &font->loader->hints;
1368 /* we allocate a buffer which is certainly large enough */
1369 /* to hold all of the created bytecode instructions; */
1370 /* later on it gets reallocated to its real size */
1371 ins_len = hints->num_points * 1000;
1372 ins_buf = (FT_Byte*)malloc(ins_len);
1373 if (!ins_buf)
1374 return FT_Err_Out_Of_Memory;
1376 /* initialize array with an invalid bytecode */
1377 /* so that we can easily find the array length at reallocation time */
1378 memset(ins_buf, INS_A0, ins_len);
1380 TA_font_build_glyph_segments(font, ins_buf);
1382 /* now we loop over a large range of pixel sizes */
1383 /* to find hinting sets which get pushed onto the bytecode stack */
1384 num_hinting_sets = 0;
1385 hinting_sets = NULL;
1387 for (size = 8; size <= 10; size++)
1389 Hinting_Set hinting_set;
1392 error = FT_Set_Pixel_Sizes(face, size, size);
1393 if (error)
1394 goto Err;
1396 error = ta_loader_load_glyph(font->loader, face, idx, 0);
1397 if (error)
1398 goto Err;
1400 TA_font_clear_edge_DONE_flag(font);
1402 error = TA_construct_hinting_set(font, size, &hinting_set);
1403 if (error)
1404 goto Err;
1406 if (TA_hinting_set_is_different(hinting_sets,
1407 num_hinting_sets,
1408 hinting_set))
1410 error = TA_add_hinting_set(&hinting_sets,
1411 &num_hinting_sets,
1412 hinting_set);
1413 if (error)
1415 TA_free_hinting_set(hinting_set);
1416 goto Err;
1419 else
1420 TA_free_hinting_set(hinting_set);
1423 /* push hinting sets */
1424 /* XXX: emit hinting instructions */
1426 /* we are done, so reallocate the instruction array to its real size */
1427 p = (FT_Byte*)memchr((char*)ins_buf, INS_A0, ins_len);
1428 ins_len = p - ins_buf;
1430 if (ins_len > sfnt->max_instructions)
1431 sfnt->max_instructions = ins_len;
1433 glyph->ins_buf = realloc(ins_buf, ins_len);
1434 glyph->ins_len = ins_len;
1436 TA_free_hinting_sets(hinting_sets, num_hinting_sets);
1438 return FT_Err_Ok;
1440 Err:
1441 TA_free_hinting_sets(hinting_sets, num_hinting_sets);
1442 free(ins_buf);
1444 return error;
1448 FT_Error
1449 TA_sfnt_build_glyf_hints(SFNT* sfnt,
1450 FONT* font)
1452 FT_Face face = sfnt->face;
1453 FT_Long idx;
1454 FT_Error error;
1457 for (idx = 0; idx < face->num_glyphs; idx++)
1459 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
1460 if (error)
1461 return error;
1464 /* XXX provide real values or better estimates */
1465 sfnt->max_storage = 1000;
1466 sfnt->max_stack_elements = 1000;
1468 return FT_Err_Ok;
1471 /* end of tabytecode.c */