Don't use trailing comma in bytecode macros.
[ttfautohint.git] / src / tabytecode.c
blobd8ec26647da607b77f0e919f01e87b7ef84e7545
1 /* tabytecode.c */
3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
5 #include "ta.h"
6 #include "tabytecode.h"
9 #ifdef TA_DEBUG
10 int _ta_debug = 1;
11 int _ta_debug_disable_horz_hints;
12 int _ta_debug_disable_vert_hints;
13 int _ta_debug_disable_blue_hints;
14 void* _ta_debug_hints;
15 #endif
18 static FT_Error
19 TA_sfnt_compute_global_hints(SFNT* sfnt,
20 FONT* font)
22 FT_Error error;
23 FT_Face face = sfnt->face;
24 FT_UInt enc;
25 FT_UInt idx;
27 static const FT_Encoding latin_encs[] =
29 FT_ENCODING_UNICODE,
30 FT_ENCODING_APPLE_ROMAN,
31 FT_ENCODING_ADOBE_STANDARD,
32 FT_ENCODING_ADOBE_LATIN_1,
34 FT_ENCODING_NONE /* end of list */
38 error = ta_loader_init(font->loader);
39 if (error)
40 return error;
42 /* try to select a latin charmap */
43 for (enc = 0; latin_encs[enc] != FT_ENCODING_NONE; enc++)
45 error = FT_Select_Charmap(face, latin_encs[enc]);
46 if (!error)
47 break;
50 /* load latin glyph `a' to trigger all initializations */
51 idx = FT_Get_Char_Index(face, 'a');
52 error = ta_loader_load_glyph(font->loader, face, idx, 0);
54 return error;
58 static FT_Error
59 TA_table_build_cvt(FT_Byte** cvt,
60 FT_ULong* cvt_len,
61 SFNT* sfnt,
62 FONT* font)
64 TA_LatinAxis haxis;
65 TA_LatinAxis vaxis;
67 FT_UInt i;
68 FT_UInt buf_len;
69 FT_UInt len;
70 FT_Byte* buf;
71 FT_Byte* buf_p;
73 FT_Error error;
76 error = TA_sfnt_compute_global_hints(sfnt, font);
77 if (error)
78 return error;
80 /* XXX check validity of pointers */
81 haxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[0];
82 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
84 buf_len = 2 * (haxis->width_count + vaxis->width_count
85 + 2 * vaxis->blue_count);
87 /* buffer length must be a multiple of four */
88 len = (buf_len + 3) & ~3;
89 buf = (FT_Byte*)malloc(len);
90 if (!buf)
91 return FT_Err_Out_Of_Memory;
93 /* pad end of buffer with zeros */
94 buf[len - 1] = 0x00;
95 buf[len - 2] = 0x00;
96 buf[len - 3] = 0x00;
98 buf_p = buf;
100 /* XXX emit standard_width also? */
102 for (i = 0; i < haxis->width_count; i++)
104 if (haxis->widths[i].org > 0xFFFF)
105 goto Err;
106 *(buf_p++) = HIGH(haxis->widths[i].org);
107 *(buf_p++) = LOW(haxis->widths[i].org);
110 for (i = 0; i < vaxis->width_count; i++)
112 if (vaxis->widths[i].org > 0xFFFF)
113 goto Err;
114 *(buf_p++) = HIGH(vaxis->widths[i].org);
115 *(buf_p++) = LOW(vaxis->widths[i].org);
118 for (i = 0; i < vaxis->blue_count; i++)
120 if (vaxis->blues[i].ref.org > 0xFFFF)
121 goto Err;
122 *(buf_p++) = HIGH(vaxis->blues[i].ref.org);
123 *(buf_p++) = LOW(vaxis->blues[i].ref.org);
124 if (vaxis->blues[i].shoot.org > 0xFFFF)
125 goto Err;
126 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
127 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
130 #if 0
131 TA_LOG(("--------------------------------------------------\n"));
132 TA_LOG(("glyph %d:\n", idx));
133 ta_glyph_hints_dump_edges(_ta_debug_hints);
134 ta_glyph_hints_dump_segments(_ta_debug_hints);
135 ta_glyph_hints_dump_points(_ta_debug_hints);
136 #endif
138 *cvt = buf;
139 *cvt_len = buf_len;
141 return FT_Err_Ok;
143 Err:
144 free(buf);
145 return TA_Err_Hinter_Overflow;
149 FT_Error
150 TA_sfnt_build_cvt_table(SFNT* sfnt,
151 FONT* font)
153 FT_Error error;
155 FT_Byte* cvt_buf;
156 FT_ULong cvt_len;
159 error = TA_sfnt_add_table_info(sfnt);
160 if (error)
161 return error;
163 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
164 if (error)
165 return error;
167 /* in case of success, `cvt_buf' gets linked */
168 /* and is eventually freed in `TA_font_unload' */
169 error = TA_font_add_table(font,
170 &sfnt->table_infos[sfnt->num_table_infos - 1],
171 TTAG_cvt, cvt_len, cvt_buf);
172 if (error)
174 free(cvt_buf);
175 return error;
180 /* the horizontal stem widths */
181 #define CVT_HORZ_WIDTHS_OFFSET(font) 0
182 #define CVT_HORZ_WIDTHS_SIZE(font) \
183 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
185 /* the vertical stem widths */
186 #define CVT_VERT_WIDTHS_OFFSET(font) \
187 CVT_HORZ_WIDTHS_OFFSET(font) \
188 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
189 #define CVT_VERT_WIDTHS_SIZE(font) \
190 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
192 /* the blue zone values for flat edges */
193 #define CVT_BLUE_REFS_OFFSET(font) \
194 CVT_VERT_WIDTHS_OFFSET(font) \
195 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
196 #define CVT_BLUE_REFS_SIZE(font) \
197 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
199 /* the blue zone values for round edges */
200 #define CVT_BLUE_SHOOTS_OFFSET(font) \
201 CVT_BLUE_REFS_OFFSET(font) \
202 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
203 #define CVT_BLUE_SHOOTS_SIZE(font) \
204 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
207 /* symbolic names for storage area locations */
209 #define sal_counter 0
210 #define sal_limit 1
211 #define sal_scale 2
212 #define sal_0x10000 3
215 /* in the comments below, the top of the stack (`s:') */
216 /* is the rightmost element; the stack is shown */
217 /* after the instruction on the same line has been executed */
220 * compute_stem_width
222 * This is the equivalent to the following code from function
223 * `ta_latin_compute_stem_width':
225 * dist = ABS(width)
227 * if stem_is_serif
228 * && dist < 3*64:
229 * return width
230 * else if base_is_round:
231 * if dist < 80
232 * dist = 64
233 * else:
234 * dist = MIN(56, dist)
236 * delta = ABS(dist - std_width)
238 * if delta < 40:
239 * dist = MIN(48, std_width)
240 * goto End
242 * if dist < 3*64:
243 * delta = dist
244 * dist = FLOOR(dist)
245 * delta = delta - dist
247 * if delta < 10:
248 * dist = dist + delta
249 * else if delta < 32:
250 * dist = dist + 10
251 * else if delta < 54:
252 * dist = dist + 54
253 * else
254 * dist = dist + delta
255 * else
256 * dist = ROUND(dist)
258 * End:
259 * if width < 0:
260 * dist = -dist
261 * return dist
265 * Function 0: compute_stem_width
267 * in: width
268 * stem_is_serif
269 * base_is_round
270 * out: new_width
271 * CVT: is_extra_light XXX
272 * std_width
275 #define compute_stem_width 0
277 unsigned char fpgm_0a[] = {
279 PUSHB_1,
280 compute_stem_width,
281 FDEF,
283 DUP,
284 ABS, /* s: base_is_round stem_is_serif width dist */
286 DUP,
287 PUSHB_1,
288 3*64,
289 LT, /* dist < 3*64 */
291 PUSHB_1,
293 MINDEX, /* s: base_is_round width dist (dist<3*64) stem_is_serif */
295 AND, /* stem_is_serif && dist < 3*64 */
296 IF, /* s: base_is_round width dist */
297 POP,
298 SWAP,
299 POP, /* s: width */
301 ELSE,
302 ROLL, /* s: width dist base_is_round */
303 IF, /* s: width dist */
304 DUP,
305 PUSHB_1,
307 LT, /* dist < 80 */
308 IF, /* s: width dist */
309 POP,
310 PUSHB_1,
311 64, /* dist = 64 */
312 EIF,
314 ELSE,
315 PUSHB_1,
317 MIN, /* dist = min(56, dist) */
318 EIF,
320 DUP, /* s: width dist dist */
321 PUSHB_1,
325 /* %c, index of std_width */
327 unsigned char fpgm_0b[] = {
329 RCVT,
330 SUB,
331 ABS, /* s: width dist delta */
333 PUSHB_1,
335 LT, /* delta < 40 */
336 IF, /* s: width dist */
337 POP,
338 PUSHB_2,
343 /* %c, index of std_width */
345 unsigned char fpgm_0c[] = {
347 RCVT,
348 MIN, /* dist = min(48, std_width) */
350 ELSE,
351 DUP, /* s: width dist dist */
352 PUSHB_1,
353 3*64,
354 LT, /* dist < 3*64 */
356 DUP, /* s: width delta dist */
357 FLOOR, /* dist = FLOOR(dist) */
358 DUP, /* s: width delta dist dist */
359 ROLL,
360 ROLL, /* s: width dist delta dist */
361 SUB, /* delta = delta - dist */
363 DUP, /* s: width dist delta delta */
364 PUSHB_1,
366 LT, /* delta < 10 */
367 IF, /* s: width dist delta */
368 ADD, /* dist = dist + delta */
370 ELSE,
371 DUP,
372 PUSHB_1,
374 LT, /* delta < 32 */
376 POP,
377 PUSHB_1,
379 ADD, /* dist = dist + 10 */
381 ELSE,
382 DUP,
383 PUSHB_1,
385 LT, /* delta < 54 */
387 POP,
388 PUSHB_1,
390 ADD, /* dist = dist + 54 */
392 ELSE,
393 ADD, /* dist = dist + delta */
395 EIF,
396 EIF,
397 EIF,
399 ELSE,
400 PUSHB_1,
402 ADD,
403 FLOOR, /* dist = round(dist) */
405 EIF,
406 EIF,
408 SWAP, /* s: dist width */
409 PUSHB_1,
411 LT, /* width < 0 */
412 NEG, /* dist = -dist */
414 EIF,
415 EIF,
417 ENDF,
423 * loop
425 * Take a range and a function number and apply the function to all
426 * elements of the range. The called function must not change the
427 * stack.
429 * Function 1: loop
431 * in: func_num
432 * end
433 * start
435 * uses: sal_counter (counter initialized with `start')
436 * sal_limit (`end')
439 #define loop 1
441 unsigned char fpgm_1[] = {
443 PUSHB_1,
444 loop,
445 FDEF,
447 ROLL, /* s: func_num start end */
448 PUSHB_1,
449 sal_limit,
450 SWAP,
453 PUSHB_1,
454 sal_counter,
455 SWAP,
458 /* start_loop: */
459 PUSHB_1,
460 sal_counter,
462 PUSHB_1,
463 sal_limit,
465 LTEQ, /* start <= end */
466 IF, /* s: func_num */
467 DUP,
468 CALL,
469 PUSHB_2,
471 sal_counter,
473 ADD, /* start = start + 1 */
474 PUSHB_1,
475 sal_counter,
476 SWAP,
479 PUSHB_1,
481 NEG,
482 JMPR, /* goto start_loop */
483 ELSE,
484 POP,
485 EIF,
487 ENDF,
493 * rescale
495 * All entries in the CVT table get scaled automatically using the
496 * vertical resolution. However, some widths must be scaled with the
497 * horizontal resolution, and others get adjusted later on.
499 * Function 2: rescale
501 * uses: sal_counter (CVT index)
502 * sal_scale (scale in 16.16 format)
505 #define rescale 2
507 unsigned char fpgm_2[] = {
509 PUSHB_1,
510 rescale,
511 FDEF,
513 PUSHB_1,
514 sal_counter,
516 DUP,
517 RCVT,
518 PUSHB_1,
519 sal_scale,
521 MUL, /* CVT * scale * 2^10 */
522 PUSHB_1,
523 sal_0x10000,
525 DIV, /* CVT * scale */
527 SWAP,
528 WCVTP,
530 ENDF,
535 /* we often need 0x10000 which can't be pushed directly onto the stack, */
536 /* thus we provide it in the storage area */
538 unsigned char fpgm_A[] = {
540 PUSHB_1,
541 sal_0x10000,
542 PUSHW_2,
543 0x08, /* 0x800 */
544 0x00,
545 0x08, /* 0x800 */
546 0x00,
547 MUL, /* 0x10000 */
553 static FT_Error
554 TA_table_build_fpgm(FT_Byte** fpgm,
555 FT_ULong* fpgm_len,
556 FONT* font)
558 FT_UInt buf_len;
559 FT_UInt len;
560 FT_Byte* buf;
561 FT_Byte* buf_p;
564 buf_len = sizeof (fpgm_0a)
566 + sizeof (fpgm_0b)
568 + sizeof (fpgm_0c)
569 + sizeof (fpgm_1)
570 + sizeof (fpgm_2)
571 + sizeof (fpgm_A);
572 /* buffer length must be a multiple of four */
573 len = (buf_len + 3) & ~3;
574 buf = (FT_Byte*)malloc(len);
575 if (!buf)
576 return FT_Err_Out_Of_Memory;
578 /* pad end of buffer with zeros */
579 buf[len - 1] = 0x00;
580 buf[len - 2] = 0x00;
581 buf[len - 3] = 0x00;
583 /* copy font program into buffer and fill in the missing variables */
584 buf_p = buf;
586 memcpy(buf_p, fpgm_0a, sizeof (fpgm_0a));
587 buf_p += sizeof (fpgm_0a);
589 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
591 memcpy(buf_p, fpgm_0b, sizeof (fpgm_0b));
592 buf_p += sizeof (fpgm_0b);
594 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
596 memcpy(buf_p, fpgm_0c, sizeof (fpgm_0c));
597 buf_p += sizeof (fpgm_0c);
599 memcpy(buf_p, fpgm_1, sizeof (fpgm_1));
600 buf_p += sizeof (fpgm_1);
602 memcpy(buf_p, fpgm_2, sizeof (fpgm_2));
603 buf_p += sizeof (fpgm_2);
605 memcpy(buf_p, fpgm_A, sizeof (fpgm_A));
607 *fpgm = buf;
608 *fpgm_len = buf_len;
610 return FT_Err_Ok;
614 FT_Error
615 TA_sfnt_build_fpgm_table(SFNT* sfnt,
616 FONT* font)
618 FT_Error error;
620 FT_Byte* fpgm_buf;
621 FT_ULong fpgm_len;
624 error = TA_sfnt_add_table_info(sfnt);
625 if (error)
626 return error;
628 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
629 if (error)
630 return error;
632 /* in case of success, `fpgm_buf' gets linked */
633 /* and is eventually freed in `TA_font_unload' */
634 error = TA_font_add_table(font,
635 &sfnt->table_infos[sfnt->num_table_infos - 1],
636 TTAG_fpgm, fpgm_len, fpgm_buf);
637 if (error)
639 free(fpgm_buf);
640 return error;
645 /* the `prep' instructions */
647 unsigned char prep_a[] = {
649 /* scale horizontal CVT entries */
650 /* if horizontal and vertical resolutions differ */
652 SVTCA_x,
653 MPPEM,
654 SVTCA_y,
655 MPPEM,
656 NEQ, /* horz_ppem != vert_ppem */
658 SVTCA_x,
659 MPPEM,
660 PUSHB_1,
661 sal_0x10000,
663 MUL, /* horz_ppem in 22.10 format */
665 SVTCA_y,
666 MPPEM,
667 DIV, /* (horz_ppem / vert_ppem) in 16.16 format */
669 PUSHB_1,
670 sal_scale,
671 SWAP,
674 /* loop over horizontal CVT entries */
675 PUSHB_4,
679 /* %c, first horizontal index */
680 /* %c, last horizontal index */
682 unsigned char prep_b[] = {
684 rescale,
685 loop,
686 CALL,
687 EIF,
691 unsigned char prep_c[] = {
693 /* optimize the alignment of the top of small letters to the pixel grid */
695 PUSHB_1,
699 /* %c, index of alignment blue zone */
701 unsigned char prep_d[] = {
703 RCVT,
704 DUP,
705 DUP,
706 PUSHB_1,
708 ADD,
709 FLOOR, /* fitted = FLOOR(scaled + 40) */
710 DUP, /* s: scaled scaled fitted fitted */
711 ROLL,
712 NEQ,
713 IF, /* s: scaled fitted */
714 SWAP,
715 PUSHB_1,
716 sal_0x10000,
718 MUL, /* scaled in 16.16 format */
719 SWAP,
720 DIV, /* (scaled / fitted) in 16.16 format */
722 PUSHB_1,
723 sal_scale,
724 SWAP,
727 /* loop over vertical CVT entries */
728 PUSHB_4,
732 /* %c, first vertical index */
733 /* %c, last vertical index */
735 unsigned char prep_e[] = {
737 rescale,
738 loop,
739 CALL,
741 /* loop over blue refs */
742 PUSHB_4,
746 /* %c, first blue ref index */
747 /* %c, last blue ref index */
749 unsigned char prep_f[] = {
751 rescale,
752 loop,
753 CALL,
755 /* loop over blue shoots */
756 PUSHB_4,
760 /* %c, first blue shoot index */
761 /* %c, last blue shoot index */
763 unsigned char prep_g[] = {
765 rescale,
766 loop,
767 CALL,
769 EIF,
774 static FT_Error
775 TA_table_build_prep(FT_Byte** prep,
776 FT_ULong* prep_len,
777 FONT* font)
779 TA_LatinAxis vaxis;
780 TA_LatinBlue blue_adjustment;
781 FT_UInt i;
783 FT_UInt buf_len;
784 FT_UInt len;
785 FT_Byte* buf;
786 FT_Byte* buf_p;
789 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
790 blue_adjustment = NULL;
792 for (i = 0; i < vaxis->blue_count; i++)
794 if (vaxis->blues[i].flags & TA_LATIN_BLUE_ADJUSTMENT)
796 blue_adjustment = &vaxis->blues[i];
797 break;
801 buf_len = sizeof (prep_a)
803 + sizeof (prep_b);
805 if (blue_adjustment)
807 buf_len += sizeof (prep_c)
809 + sizeof (prep_d)
811 + sizeof (prep_e)
813 + sizeof (prep_f)
815 + sizeof (prep_g);
818 /* buffer length must be a multiple of four */
819 len = (buf_len + 3) & ~3;
820 buf = (FT_Byte*)malloc(len);
821 if (!buf)
822 return FT_Err_Out_Of_Memory;
824 /* pad end of buffer with zeros */
825 buf[len - 1] = 0x00;
826 buf[len - 2] = 0x00;
827 buf[len - 3] = 0x00;
829 /* copy cvt program into buffer and fill in the missing variables */
830 buf_p = buf;
832 memcpy(buf_p, prep_a, sizeof (prep_a));
833 buf_p += sizeof (prep_a);
835 *(buf_p++) = (unsigned char)CVT_HORZ_WIDTHS_OFFSET(font);
836 *(buf_p++) = (unsigned char)(CVT_HORZ_WIDTHS_OFFSET(font)
837 + CVT_HORZ_WIDTHS_SIZE(font) - 1);
839 memcpy(buf_p, prep_b, sizeof (prep_b));
841 if (blue_adjustment)
843 buf_p += sizeof (prep_b);
845 memcpy(buf_p, prep_c, sizeof (prep_c));
846 buf_p += sizeof (prep_c);
848 *(buf_p++) = blue_adjustment - vaxis->blues;
850 memcpy(buf_p, prep_d, sizeof (prep_d));
851 buf_p += sizeof (prep_d);
853 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
854 *(buf_p++) = (unsigned char)(CVT_VERT_WIDTHS_OFFSET(font)
855 + CVT_VERT_WIDTHS_SIZE(font) - 1);
857 memcpy(buf_p, prep_e, sizeof (prep_e));
858 buf_p += sizeof (prep_e);
860 *(buf_p++) = (unsigned char)CVT_BLUE_REFS_OFFSET(font);
861 *(buf_p++) = (unsigned char)(CVT_BLUE_REFS_OFFSET(font)
862 + CVT_BLUE_REFS_SIZE(font) - 1);
864 memcpy(buf_p, prep_f, sizeof (prep_f));
865 buf_p += sizeof (prep_f);
867 *(buf_p++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(font);
868 *(buf_p++) = (unsigned char)(CVT_BLUE_SHOOTS_OFFSET(font)
869 + CVT_BLUE_SHOOTS_SIZE(font) - 1);
871 memcpy(buf_p, prep_g, sizeof (prep_g));
874 *prep = buf;
875 *prep_len = buf_len;
877 return FT_Err_Ok;
881 FT_Error
882 TA_sfnt_build_prep_table(SFNT* sfnt,
883 FONT* font)
885 FT_Error error;
887 FT_Byte* prep_buf;
888 FT_ULong prep_len;
891 error = TA_sfnt_add_table_info(sfnt);
892 if (error)
893 return error;
895 error = TA_table_build_prep(&prep_buf, &prep_len, font);
896 if (error)
897 return error;
899 /* in case of success, `prep_buf' gets linked */
900 /* and is eventually freed in `TA_font_unload' */
901 error = TA_font_add_table(font,
902 &sfnt->table_infos[sfnt->num_table_infos - 1],
903 TTAG_prep, prep_len, prep_buf);
904 if (error)
906 free(prep_buf);
907 return error;
911 /* end of tabytecode.c */