Add some comments.
[ttfautohint.git] / src / tabytecode.c
blobf74836fd9b2fa992756f0e16dbd760a1066d036d
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;
66 TA_LatinBlue blue;
68 FT_UInt i;
69 FT_UInt buf_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);
86 buf = (FT_Byte*)malloc(buf_len);
87 if (!buf)
88 return FT_Err_Out_Of_Memory;
90 buf_p = buf;
92 /* XXX emit standard_width also? */
94 for (i = 0; i < haxis->width_count; i++)
96 if (haxis->widths[i].org > 0xFFFF)
97 goto Err;
98 *(buf_p++) = HIGH(haxis->widths[i].org);
99 *(buf_p++) = LOW(haxis->widths[i].org);
102 for (i = 0; i < vaxis->width_count; i++)
104 if (vaxis->widths[i].org > 0xFFFF)
105 goto Err;
106 *(buf_p++) = HIGH(vaxis->widths[i].org);
107 *(buf_p++) = LOW(vaxis->widths[i].org);
110 for (i = 0; i < vaxis->blue_count; i++)
112 if (vaxis->blues[i].ref.org > 0xFFFF)
113 goto Err;
114 *(buf_p++) = HIGH(vaxis->blues[i].ref.org);
115 *(buf_p++) = LOW(vaxis->blues[i].ref.org);
116 if (vaxis->blues[i].shoot.org > 0xFFFF)
117 goto Err;
118 *(buf_p++) = HIGH(vaxis->blues[i].shoot.org);
119 *(buf_p++) = LOW(vaxis->blues[i].shoot.org);
122 #if 0
123 TA_LOG(("--------------------------------------------------\n"));
124 TA_LOG(("glyph %d:\n", idx));
125 ta_glyph_hints_dump_edges(_ta_debug_hints);
126 ta_glyph_hints_dump_segments(_ta_debug_hints);
127 ta_glyph_hints_dump_points(_ta_debug_hints);
128 #endif
130 *cvt = buf;
131 *cvt_len = buf_len;
133 return FT_Err_Ok;
135 Err:
136 free(buf);
137 return TA_Err_Hinter_Overflow;
141 FT_Error
142 TA_sfnt_build_cvt_table(SFNT* sfnt,
143 FONT* font)
145 FT_Error error;
147 FT_Byte* cvt_buf;
148 FT_ULong cvt_len;
151 error = TA_sfnt_add_table_info(sfnt);
152 if (error)
153 return error;
155 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
156 if (error)
157 return error;
159 /* in case of success, `cvt_buf' gets linked */
160 /* and is eventually freed in `TA_font_unload' */
161 error = TA_font_add_table(font,
162 &sfnt->table_infos[sfnt->num_table_infos - 1],
163 TTAG_cvt, cvt_len, cvt_buf);
164 if (error)
166 free(cvt_buf);
167 return error;
172 /* the horizontal stem widths */
173 #define CVT_HORZ_WIDTHS_OFFSET(font) 0
174 #define CVT_HORZ_WIDTHS_SIZE(font) \
175 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
177 /* the vertical stem widths */
178 #define CVT_VERT_WIDTHS_OFFSET(font) \
179 CVT_HORZ_WIDTHS_OFFSET(font) \
180 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[0].width_count
181 #define CVT_VERT_WIDTHS_SIZE(font) \
182 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
184 /* the blue zone values for flat edges */
185 #define CVT_BLUE_REFS_OFFSET(font) \
186 CVT_VERT_WIDTHS_OFFSET(font) \
187 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].width_count
188 #define CVT_BLUE_REFS_SIZE(font) \
189 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
191 /* the blue zone values for round edges */
192 #define CVT_BLUE_SHOOTS_OFFSET(font) \
193 CVT_BLUE_REFS_OFFSET(font) \
194 + ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
195 #define CVT_BLUE_SHOOTS_SIZE(font) \
196 ((TA_LatinMetrics)font->loader->hints.metrics)->axis[1].blue_count
199 /* symbolic names for storage area locations */
201 #define sal_counter 0,
202 #define sal_limit 1,
203 #define sal_scale 2,
204 #define sal_0x10000 3,
207 /* in the comments below, the top of the stack (`s:') */
208 /* is the rightmost element; the stack is shown */
209 /* after the instruction on the same line has been executed */
212 * compute_stem_width
214 * This is the equivalent to the following code from function
215 * `ta_latin_compute_stem_width':
217 * dist = ABS(width)
219 * if stem_is_serif
220 * && dist < 3*64:
221 * return width
222 * else if base_is_round:
223 * if dist < 80
224 * dist = 64
225 * else:
226 * dist = MIN(56, dist)
228 * delta = ABS(dist - std_width)
230 * if delta < 40:
231 * dist = MIN(48, std_width)
232 * goto End
234 * if dist < 3*64:
235 * delta = dist
236 * dist = FLOOR(dist)
237 * delta = delta - dist
239 * if delta < 10:
240 * dist = dist + delta
241 * else if delta < 32:
242 * dist = dist + 10
243 * else if delta < 54:
244 * dist = dist + 54
245 * else
246 * dist = dist + delta
247 * else
248 * dist = ROUND(dist)
250 * End:
251 * if width < 0:
252 * dist = -dist
253 * return dist
257 * Function 0: compute_stem_width
259 * in: width
260 * stem_is_serif
261 * base_is_round
262 * out: new_width
263 * CVT: is_extra_light XXX
264 * std_width
267 #define compute_stem_width 0,
269 unsigned char fpgm_0a[] = {
271 PUSHB_1
272 compute_stem_width
273 FDEF
276 ABS /* s: base_is_round stem_is_serif width dist */
279 PUSHB_1
280 3*64,
281 LT /* dist < 3*64 */
283 PUSHB_1
285 MINDEX /* s: base_is_round width dist (dist<3*64) stem_is_serif */
287 AND /* stem_is_serif && dist < 3*64 */
288 IF /* s: base_is_round width dist */
290 SWAP
291 POP /* s: width */
293 ELSE
294 ROLL /* s: width dist base_is_round */
295 IF /* s: width dist */
297 PUSHB_1
299 LT /* dist < 80 */
300 IF /* s: width dist */
302 PUSHB_1
303 64, /* dist = 64 */
306 ELSE
307 PUSHB_1
309 MIN /* dist = min(56, dist) */
312 DUP /* s: width dist dist */
313 PUSHB_1
317 /* %c, index of std_width */
319 unsigned char fpgm_0b[] = {
321 RCVT
323 ABS /* s: width dist delta */
325 PUSHB_1
327 LT /* delta < 40 */
328 IF /* s: width dist */
330 PUSHB_2
335 /* %c, index of std_width */
337 unsigned char fpgm_0c[] = {
339 RCVT
340 MIN /* dist = min(48, std_width) */
342 ELSE
343 DUP /* s: width dist dist */
344 PUSHB_1
345 3*64,
346 LT /* dist < 3*64 */
348 DUP /* s: width delta dist */
349 FLOOR /* dist = FLOOR(dist) */
350 DUP /* s: width delta dist dist */
351 ROLL
352 ROLL /* s: width dist delta dist */
353 SUB /* delta = delta - dist */
355 DUP /* s: width dist delta delta */
356 PUSHB_1
358 LT /* delta < 10 */
359 IF /* s: width dist delta */
360 ADD /* dist = dist + delta */
362 ELSE
364 PUSHB_1
366 LT /* delta < 32 */
369 PUSHB_1
371 ADD /* dist = dist + 10 */
373 ELSE
375 PUSHB_1
377 LT /* delta < 54 */
380 PUSHB_1
382 ADD /* dist = dist + 54 */
384 ELSE
385 ADD /* dist = dist + delta */
391 ELSE
392 PUSHB_1
395 FLOOR /* dist = round(dist) */
400 SWAP /* s: dist width */
401 PUSHB_1
403 LT /* width < 0 */
404 NEG /* dist = -dist */
409 ENDF
415 * loop
417 * Take a range and a function number and apply the function to all
418 * elements of the range. The called function must not change the
419 * stack.
421 * Function 1: loop
423 * in: func_num
424 * end
425 * start
427 * uses: sal_counter (counter initialized with `start')
428 * sal_limit (`end')
431 #define loop 1,
433 unsigned char fpgm_1[] = {
435 PUSHB_1
436 loop
437 FDEF
439 ROLL /* s: func_num start end */
440 PUSHB_1
441 sal_limit
442 SWAP
445 PUSHB_1
446 sal_counter
447 SWAP
450 /* start_loop: */
451 PUSHB_1
452 sal_counter
454 PUSHB_1
455 sal_limit
457 LTEQ /* start <= end */
458 IF /* s: func_num */
460 CALL
461 PUSHB_2
463 sal_counter
465 ADD /* start = start + 1 */
466 PUSHB_1
467 sal_counter
468 SWAP
471 PUSHB_1
474 JMPR /* goto start_loop */
475 ELSE
479 ENDF
485 * rescale_horizontally
487 * All entries in the CVT table get scaled automatically using the
488 * vertical resolution. However, some widths must be scaled with the
489 * horizontal resolution.
491 * Function 2: rescale_horizontally
493 * uses: sal_counter (CVT index)
494 * sal_scale (scale in 16.16 format)
497 #define rescale_horizontally 2,
499 unsigned char fpgm_2[] = {
501 PUSHB_1
502 rescale_horizontally
503 FDEF
505 PUSHB_1
506 sal_counter
509 RCVT
510 PUSHB_1
511 sal_scale
513 MUL /* CVT * scale * 2^10 */
514 PUSHB_1
515 sal_0x10000
517 DIV /* CVT * scale */
519 SWAP
520 WCVTP
522 ENDF
527 /* we often need 0x10000 which can't be pushed directly onto the stack, */
528 /* thus we provide it in the storage area */
530 unsigned char fpgm_A[] = {
532 PUSHB_1
533 sal_0x10000
534 PUSHW_2
535 0x08, /* 0x800 */
536 0x00,
537 0x08, /* 0x800 */
538 0x00,
539 MUL /* 0x10000 */
545 static FT_Error
546 TA_table_build_fpgm(FT_Byte** fpgm,
547 FT_ULong* fpgm_len,
548 FONT* font)
550 FT_UInt buf_len;
551 FT_Byte* buf;
552 FT_Byte* buf_p;
555 buf_len = sizeof (fpgm_0a)
557 + sizeof (fpgm_0b)
559 + sizeof (fpgm_0c)
560 + sizeof (fpgm_1)
561 + sizeof (fpgm_2)
562 + sizeof (fpgm_A);
563 buf = (FT_Byte*)malloc(buf_len);
564 if (!buf)
565 return FT_Err_Out_Of_Memory;
567 /* copy font program into buffer and fill in the missing variables */
568 buf_p = buf;
569 memcpy(buf_p, fpgm_0a, sizeof (fpgm_0a));
570 buf_p += sizeof (fpgm_0a);
571 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
572 memcpy(buf_p, fpgm_0b, sizeof (fpgm_0b));
573 buf_p += sizeof (fpgm_0b);
574 *(buf_p++) = (unsigned char)CVT_VERT_WIDTHS_OFFSET(font);
575 memcpy(buf_p, fpgm_0c, sizeof (fpgm_0c));
576 buf_p += sizeof (fpgm_0c);
577 memcpy(buf_p, fpgm_1, sizeof (fpgm_1));
578 buf_p += sizeof (fpgm_1);
579 memcpy(buf_p, fpgm_2, sizeof (fpgm_2));
580 buf_p += sizeof (fpgm_2);
581 memcpy(buf_p, fpgm_A, sizeof (fpgm_A));
583 *fpgm = buf;
584 *fpgm_len = buf_len;
586 return FT_Err_Ok;
590 FT_Error
591 TA_sfnt_build_fpgm_table(SFNT* sfnt,
592 FONT* font)
594 FT_Error error;
596 FT_Byte* fpgm_buf;
597 FT_ULong fpgm_len;
600 error = TA_sfnt_add_table_info(sfnt);
601 if (error)
602 return error;
604 error = TA_table_build_fpgm(&fpgm_buf, &fpgm_len, font);
605 if (error)
606 return error;
608 /* in case of success, `fpgm_buf' gets linked */
609 /* and is eventually freed in `TA_font_unload' */
610 error = TA_font_add_table(font,
611 &sfnt->table_infos[sfnt->num_table_infos - 1],
612 TTAG_fpgm, fpgm_len, fpgm_buf);
613 if (error)
615 free(fpgm_buf);
616 return error;
621 /* the `prep' instructions */
623 unsigned char prep_a[] = {
625 /* scale horizontal CVT entries */
626 /* if horizontal and vertical resolutions differ */
628 SVTCA_x
629 MPPEM
630 SVTCA_y
631 MPPEM
632 NEQ /* horz_ppem != vert_ppem */
634 SVTCA_x
635 MPPEM
636 PUSHB_1
637 sal_0x10000
639 MUL /* horz_ppem in 22.10 format */
641 SVTCA_y
642 MPPEM
643 DIV /* (horz_ppem / vert_ppem) in 16.16 format */
645 PUSHB_1
646 sal_scale
647 SWAP
650 /* loop over horizontal CVT entries */
651 PUSHB_4
655 /* %c, first horizontal index */
656 /* %c, last horizontal index */
658 unsigned char prep_b[] = {
660 rescale_horizontally
661 loop
662 CALL
668 static FT_Error
669 TA_table_build_prep(FT_Byte** prep,
670 FT_ULong* prep_len,
671 FONT* font)
673 FT_UInt buf_len;
674 FT_Byte* buf;
675 FT_Byte* buf_p;
678 buf_len = sizeof (prep_a)
680 + sizeof (prep_b);
681 buf = (FT_Byte*)malloc(buf_len);
682 if (!buf)
683 return FT_Err_Out_Of_Memory;
685 /* copy cvt program into buffer and fill in the missing variables */
686 buf_p = buf;
687 memcpy(buf_p, prep_a, sizeof (prep_a));
688 buf_p += sizeof (prep_a);
689 *(buf_p++) = (unsigned char)CVT_HORZ_WIDTHS_OFFSET(font);
690 *(buf_p++) = (unsigned char)(CVT_HORZ_WIDTHS_OFFSET(font)
691 + CVT_HORZ_WIDTHS_SIZE(font) - 1);
692 memcpy(buf_p, prep_b, sizeof (prep_b));
694 *prep = buf;
695 *prep_len = buf_len;
697 return FT_Err_Ok;
701 FT_Error
702 TA_sfnt_build_prep_table(SFNT* sfnt,
703 FONT* font)
705 FT_Error error;
707 FT_Byte* prep_buf;
708 FT_ULong prep_len;
711 error = TA_sfnt_add_table_info(sfnt);
712 if (error)
713 return error;
715 error = TA_table_build_prep(&prep_buf, &prep_len, font);
716 if (error)
717 return error;
719 /* in case of success, `prep_buf' gets linked */
720 /* and is eventually freed in `TA_font_unload' */
721 error = TA_font_add_table(font,
722 &sfnt->table_infos[sfnt->num_table_infos - 1],
723 TTAG_prep, prep_len, prep_buf);
724 if (error)
726 free(prep_buf);
727 return error;
731 /* end of tabytecode.c */