Fix OTS warning about `maxp.maxSizeOfInstructions`.
[ttfautohint.git] / lib / tabytecode.c
blobe8460f27ea747ec177ab0b98917e76bcc8fed455
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2022 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
18 #include <stdbool.h> /* for llrb.h */
20 #include "llrb.h" /* a red-black tree implementation */
21 #include "tahints.h"
24 #define DEBUGGING
27 #ifdef TA_DEBUG
28 int _ta_debug = 0;
29 int _ta_debug_global = 0;
30 int _ta_debug_disable_horz_hints;
31 int _ta_debug_disable_vert_hints;
32 int _ta_debug_disable_blue_hints;
33 void* _ta_debug_hints;
34 #endif
37 /* node structures for point hints */
39 typedef struct Node1 Node1;
40 struct Node1
42 LLRB_ENTRY(Node1) entry1;
43 FT_UShort point;
46 typedef struct Node2 Node2;
47 struct Node2
49 LLRB_ENTRY(Node2) entry2;
50 FT_UShort edge;
51 FT_UShort point;
54 typedef struct Node3 Node3;
55 struct Node3
57 LLRB_ENTRY(Node3) entry3;
58 FT_UShort before_edge;
59 FT_UShort after_edge;
60 FT_UShort point;
64 /* comparison functions for our red-black trees */
66 static int
67 node1cmp(Node1* e1,
68 Node1* e2)
70 /* sort by points */
71 return e1->point - e2->point;
74 static int
75 node2cmp(Node2* e1,
76 Node2* e2)
78 FT_Int delta;
81 /* sort by edges ... */
82 delta = (FT_Int)e1->edge - (FT_Int)e2->edge;
83 if (delta)
84 return delta;
86 /* ... then by points */
87 return (FT_Int)e1->point - (FT_Int)e2->point;
90 static int
91 node3cmp(Node3* e1,
92 Node3* e2)
94 FT_Int delta;
97 /* sort by `before' edges ... */
98 delta = (FT_Int)e1->before_edge - (FT_Int)e2->before_edge;
99 if (delta)
100 return delta;
102 /* ... then by `after' edges ... */
103 delta = (FT_Int)e1->after_edge - (FT_Int)e2->after_edge;
104 if (delta)
105 return delta;
107 /* ... then by points */
108 return (FT_Int)e1->point - (FT_Int)e2->point;
112 /* the red-black tree function bodies */
113 typedef struct ip_before_points ip_before_points;
114 typedef struct ip_after_points ip_after_points;
115 typedef struct ip_on_points ip_on_points;
116 typedef struct ip_between_points ip_between_points;
118 LLRB_HEAD(ip_before_points, Node1);
119 LLRB_HEAD(ip_after_points, Node1);
120 LLRB_HEAD(ip_on_points, Node2);
121 LLRB_HEAD(ip_between_points, Node3);
123 /* no trailing semicolon in the next four lines */
124 LLRB_GENERATE_STATIC(ip_before_points, Node1, entry1, node1cmp)
125 LLRB_GENERATE_STATIC(ip_after_points, Node1, entry1, node1cmp)
126 LLRB_GENERATE_STATIC(ip_on_points, Node2, entry2, node2cmp)
127 LLRB_GENERATE_STATIC(ip_between_points, Node3, entry3, node3cmp)
130 typedef struct Hints_Record_
132 FT_UInt size;
133 FT_UInt num_actions;
134 FT_Byte* buf;
135 FT_UInt buf_len;
136 } Hints_Record;
138 typedef struct Recorder_
140 SFNT* sfnt;
141 FONT* font;
142 GLYPH* glyph; /* the current glyph */
143 Hints_Record hints_record;
145 /* some segments can `wrap around' */
146 /* a contour's start point like 24-25-26-0-1-2 */
147 /* (there can be at most one such segment per contour); */
148 /* later on we append additional records */
149 /* to split them into 24-26 and 0-2 */
150 FT_UShort* wrap_around_segments;
151 FT_UShort num_wrap_around_segments;
152 FT_Bool wrap_around_segments_initialized;
154 FT_UShort num_stack_elements; /* the necessary stack depth so far */
156 /* data necessary for strong point interpolation */
157 ip_before_points ip_before_points_head;
158 ip_after_points ip_after_points_head;
159 ip_on_points ip_on_points_head;
160 ip_between_points ip_between_points_head;
162 /* we omit one-point segments not part of an edge, */
163 /* thus we have to adjust indices into the `segments' array */
164 FT_UShort* segment_map;
165 FT_Bool segment_map_initialized;
166 } Recorder;
169 /* this is the bytecode of the `.ttfautohint' glyph */
171 FT_Byte ttfautohint_glyph_bytecode[7] =
174 /* increment `cvtl_is_subglyph' counter */
175 PUSHB_3,
176 cvtl_is_subglyph,
177 100,
178 cvtl_is_subglyph,
179 RCVT,
180 ADD,
181 WCVTP,
186 /* if we have y delta exceptions before IUP_y, this code gets inserted */
187 static FT_Byte ins_extra_delta_exceptions[4] =
190 /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
191 PUSHB_2,
192 cvtl_do_iup_y,
194 WCVTP,
199 /* if we have a non-base glyph, this code gets inserted */
200 static FT_Byte ins_extra_ignore_std_width[4] =
203 /* tell bci_{smooth,strong}_stem_width to ignore std_width */
204 PUSHB_2,
205 cvtl_ignore_std_width,
206 100,
207 WCVTP,
213 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
214 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
215 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
216 * PUSHW_X gets used
219 FT_Byte*
220 TA_build_push(FT_Byte* bufp,
221 FT_UInt* args,
222 FT_UInt num_args,
223 FT_Bool need_words,
224 FT_Bool optimize)
226 FT_UInt* arg = args;
227 FT_UInt i, j, nargs;
230 if (need_words)
232 for (i = 0; i < num_args; i += 255)
234 nargs = (num_args - i > 255) ? 255 : num_args - i;
236 if (optimize && nargs <= 8)
237 BCI(PUSHW_1 - 1 + nargs);
238 else
240 BCI(NPUSHW);
241 BCI(nargs);
243 for (j = 0; j < nargs; j++)
245 BCI(HIGH(*arg));
246 BCI(LOW(*arg));
247 arg++;
251 else
253 for (i = 0; i < num_args; i += 255)
255 nargs = (num_args - i > 255) ? 255 : num_args - i;
257 if (optimize && nargs <= 8)
258 BCI(PUSHB_1 - 1 + nargs);
259 else
261 BCI(NPUSHB);
262 BCI(nargs);
264 for (j = 0; j < nargs; j++)
266 BCI(*arg);
267 arg++;
272 return bufp;
277 * We optimize two common cases, replacing
279 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
281 * with
283 * NPUSHB (A+B[+C]) ... CALL
285 * if possible
288 static FT_Byte*
289 TA_optimize_push(FT_Byte* buf,
290 FT_Byte** pos)
292 FT_Byte sizes[3];
293 FT_Byte new_size1;
294 FT_Byte new_size2;
296 FT_UInt sum;
297 FT_UInt i;
298 FT_UInt pos_idx;
300 FT_Byte* p;
301 FT_Byte* bufp;
304 /* XXX improve handling of NPUSHW */
305 if (*(pos[0]) == NPUSHW
306 || *(pos[1]) == NPUSHW
307 || *(pos[2]) == NPUSHW)
308 return buf;
310 /* the point hints records block can be missing */
311 if (pos[0] == pos[1])
313 pos[1] = pos[2];
314 pos[2] = NULL;
317 /* only needed for the algorithm loops below */
318 pos[3] = NULL;
320 /* there are at least two NPUSHB instructions */
321 /* (one of them directly at the start) */
322 sizes[0] = *(pos[0] + 1);
323 sizes[1] = *(pos[1] + 1);
324 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
326 sum = sizes[0] + sizes[1] + sizes[2];
328 if (sum > 2 * 0xFF)
329 return buf; /* nothing to do since we need three NPUSHB */
330 else if (!sizes[2] && (sum > 0xFF))
331 return buf; /* nothing to do since we need two NPUSHB */
333 if (sum > 0xFF)
335 /* reduce three NPUSHB to two */
336 new_size1 = 0xFF;
337 new_size2 = (FT_Byte)(sum - 0xFF);
339 else
341 /* reduce two or three NPUSHB to one */
342 new_size1 = (FT_Byte)sum;
343 new_size2 = 0;
346 /* pack data */
347 p = buf;
348 bufp = buf;
349 pos_idx = 0;
351 if (new_size1 <= 8)
352 BCI(PUSHB_1 - 1 + new_size1);
353 else
355 BCI(NPUSHB);
356 BCI(new_size1);
358 for (i = 0; i < new_size1; i++)
360 if (p == pos[pos_idx])
362 pos_idx++;
363 p += 2; /* skip old NPUSHB */
365 *(bufp++) = *(p++);
368 if (new_size2)
370 if (new_size2 <= 8)
371 BCI(PUSHB_1 - 1 + new_size2);
372 else
374 BCI(NPUSHB);
375 BCI(new_size2);
377 for (i = 0; i < new_size2; i++)
379 if (p == pos[pos_idx])
381 pos_idx++;
382 p += 2;
384 *(bufp++) = *(p++);
388 BCI(CALL);
390 return bufp;
394 /* We add a subglyph for each composite glyph. */
395 /* Since subglyphs must contain at least one point, */
396 /* we have to adjust all point indices accordingly. */
397 /* Using the `pointsums' array of the `GLYPH' structure */
398 /* it is straightforward to do that: */
399 /* Assuming that point with index x is in the interval */
400 /* pointsums[n] <= x < pointsums[n + 1], */
401 /* the new point index is x + n. */
403 static FT_UInt
404 TA_adjust_point_index(Recorder* recorder,
405 FT_UInt idx)
407 FONT* font = recorder->font;
408 GLYPH* glyph = recorder->glyph;
409 FT_UShort i;
412 if (!glyph->num_components || !font->hint_composites)
413 return idx; /* not a composite glyph */
415 for (i = 0; i < glyph->num_pointsums; i++)
416 if (idx < glyph->pointsums[i])
417 break;
419 return idx + i;
423 /* We omit one-point segments not part of an edge, */
424 /* thus we have to adjust indices into the `segments' array. */
425 /* If `segment' is NULL, the number of all segments */
426 /* without non-edge one-point segments is returned. */
428 static FT_UShort
429 TA_get_segment_index(TA_Segment segment,
430 Recorder* recorder)
432 FONT* font = recorder->font;
433 TA_GlyphHints hints = &font->loader->hints;
434 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
437 return segment ? recorder->segment_map[segment - axis->segments]
438 : recorder->segment_map[axis->num_segments];
442 /* we store the segments in the storage area; */
443 /* each segment record consists of the first and last point */
445 static FT_Byte*
446 TA_sfnt_build_glyph_segments(SFNT* sfnt,
447 Recorder* recorder,
448 FT_Byte* bufp,
449 FT_Bool optimize)
451 FONT* font = recorder->font;
452 TA_GlyphHints hints = &font->loader->hints;
453 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
454 TA_Point points = hints->points;
455 TA_Segment segments = axis->segments;
456 TA_Segment seg;
457 TA_Segment seg_limit;
459 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
460 glyf_Data* data = (glyf_Data*)glyf_table->data;
462 FT_UInt style_id = data->style_ids
463 [font->loader->metrics->style_class->style];
465 FT_Outline outline = font->loader->gloader->base.outline;
467 FT_UInt* args;
468 FT_UInt* arg;
469 FT_UInt num_args;
470 FT_UShort num_segments;
472 FT_Bool need_words = 0;
474 FT_Int n;
475 FT_UInt base;
476 FT_UShort num_packed_segments;
477 FT_UShort num_storage;
478 FT_UShort num_stack_elements;
479 FT_UShort num_twilight_points;
482 seg_limit = segments + axis->num_segments;
483 num_segments = TA_get_segment_index(NULL, recorder);
485 /* to pack the data in the bytecode more tightly, */
486 /* we store up to the first nine segments in nibbles if possible, */
487 /* using delta values */
488 base = 0;
489 num_packed_segments = 0;
490 for (seg = segments; seg < seg_limit; seg++)
492 FT_UInt first = (FT_UInt)(seg->first - points);
493 FT_UInt last = (FT_UInt)(seg->last - points);
496 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
497 continue;
499 first = TA_adjust_point_index(recorder, first);
500 last = TA_adjust_point_index(recorder, last);
502 if (first - base >= 16)
503 break;
504 if (first > last || last - first >= 16)
505 break;
506 if (num_packed_segments == 9)
507 break;
508 num_packed_segments++;
509 base = last;
512 /* also handle wrap-around segments */
513 num_segments += recorder->num_wrap_around_segments;
515 /* wrap-around segments are pushed with four arguments; */
516 /* a segment stored in nibbles needs only one byte instead of two */
517 num_args = num_packed_segments
518 + 2 * (num_segments - num_packed_segments)
519 + 2 * recorder->num_wrap_around_segments
520 + 3;
522 /* collect all arguments temporarily in an array (in reverse order) */
523 /* so that we can easily split into chunks of 255 args */
524 /* as needed by NPUSHB and NPUSHW, respectively */
525 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
526 if (!args)
527 return NULL;
529 arg = args + num_args - 1;
531 if (num_segments > 0xFF)
532 need_words = 1;
534 /* the number of packed segments is indicated by the function number */
535 if (recorder->glyph->num_components && font->hint_composites)
536 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
537 else
538 *(arg--) = bci_create_segments_0 + num_packed_segments;
540 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
541 *(arg--) = num_segments;
543 base = 0;
544 n = 0;
545 for (seg = segments; seg < seg_limit; seg++)
547 FT_UInt first = (FT_UInt)(seg->first - points);
548 FT_UInt last = (FT_UInt)(seg->last - points);
549 FT_UInt low_nibble;
550 FT_UInt high_nibble;
553 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
554 continue;
555 if (n >= num_packed_segments)
556 break;
558 first = TA_adjust_point_index(recorder, first);
559 last = TA_adjust_point_index(recorder, last);
561 low_nibble = first - base;
562 high_nibble = last - first;
564 *(arg--) = 16 * high_nibble + low_nibble;
566 base = last;
567 n++;
570 for (; seg < seg_limit; seg++)
572 FT_UInt first = (FT_UInt)(seg->first - points);
573 FT_UInt last = (FT_UInt)(seg->last - points);
576 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
577 continue;
579 *(arg--) = TA_adjust_point_index(recorder, first);
580 *(arg--) = TA_adjust_point_index(recorder, last);
582 /* we push the last and first contour point */
583 /* as a third and fourth argument in wrap-around segments */
584 if (first > last)
586 for (n = 0; n < outline.n_contours; n++)
588 FT_UInt end = (FT_UInt)outline.contours[n];
591 if (first <= end)
593 *(arg--) = TA_adjust_point_index(recorder, end);
594 if (end > 0xFF)
595 need_words = 1;
597 if (n == 0)
598 *(arg--) = TA_adjust_point_index(recorder, 0);
599 else
600 *(arg--) = TA_adjust_point_index(recorder,
601 (FT_UInt)outline.contours[n - 1] + 1);
602 break;
607 if (last > 0xFF)
608 need_words = 1;
611 /* emit the second part of wrap-around segments as separate segments */
612 /* so that edges can easily link to them */
613 for (seg = segments; seg < seg_limit; seg++)
615 FT_UInt first = (FT_UInt)(seg->first - points);
616 FT_UInt last = (FT_UInt)(seg->last - points);
619 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
620 continue;
622 if (first > last)
624 for (n = 0; n < outline.n_contours; n++)
626 if (first <= (FT_UInt)outline.contours[n])
628 if (n == 0)
629 *(arg--) = TA_adjust_point_index(recorder, 0);
630 else
631 *(arg--) = TA_adjust_point_index(recorder,
632 (FT_UInt)outline.contours[n - 1] + 1);
633 break;
637 *(arg--) = TA_adjust_point_index(recorder, last);
641 /* with most fonts it is very rare */
642 /* that any of the pushed arguments is larger than 0xFF, */
643 /* thus we refrain from further optimizing this case */
644 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
646 BCI(CALL);
648 /* see storage area layout description in `tabytecode.h' */
649 num_storage = sal_segment_offset + num_segments * 3;
650 if (num_storage > sfnt->max_storage)
651 sfnt->max_storage = num_storage;
653 num_twilight_points = num_segments * 2;
654 if (num_twilight_points > sfnt->max_twilight_points)
655 sfnt->max_twilight_points = num_twilight_points;
657 /* both this function and `TA_emit_hints_record' */
658 /* push data onto the stack */
659 num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS
660 + recorder->num_stack_elements
661 + num_args);
662 if (num_stack_elements > sfnt->max_stack_elements)
663 sfnt->max_stack_elements = num_stack_elements;
665 free(args);
667 return bufp;
671 static void
672 build_delta_exception(const Ctrl* ctrl,
673 FT_UInt** delta_args,
674 unsigned int* num_delta_args)
676 int offset;
677 int ppem;
678 int x_shift;
679 int y_shift;
682 ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
684 if (ppem < 16)
685 offset = 0;
686 else if (ppem < 32)
687 offset = 1;
688 else
689 offset = 2;
691 ppem -= offset << 4;
694 * Using
696 * delta_shift = 3 ,
698 * the possible shift values in the instructions are indexed as follows:
700 * 0 -1px
701 * 1 -7/8px
702 * ...
703 * 7 -1/8px
704 * 8 1/8px
705 * ...
706 * 14 7/8px
707 * 15 1px
709 * (note that there is no index for a zero shift).
712 if (ctrl->x_shift < 0)
713 x_shift = ctrl->x_shift + 8;
714 else
715 x_shift = ctrl->x_shift + 7;
717 if (ctrl->y_shift < 0)
718 y_shift = ctrl->y_shift + 8;
719 else
720 y_shift = ctrl->y_shift + 7;
722 /* add point index and exception specification to appropriate stack */
723 if (ctrl->x_shift)
725 *(delta_args[offset] + num_delta_args[offset]++) =
726 (FT_UInt)((ppem << 4) + x_shift);
727 *(delta_args[offset] + num_delta_args[offset]++) =
728 (FT_UInt)ctrl->point_idx;
731 if (ctrl->y_shift)
733 offset += 3;
734 *(delta_args[offset] + num_delta_args[offset]++) =
735 (FT_UInt)((ppem << 4) + y_shift);
736 *(delta_args[offset] + num_delta_args[offset]++) =
737 (FT_UInt)ctrl->point_idx;
742 static FT_Byte*
743 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
744 FONT* font,
745 FT_Long idx,
746 FT_Byte* bufp)
748 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
749 glyf_Data* data = (glyf_Data*)glyf_table->data;
750 GLYPH* glyph = &data->glyphs[idx];
752 FT_Face face = font->loader->face;
754 unsigned int num_points;
755 int i;
757 FT_UShort num_before_IUP_stack_elements = 0;
758 FT_UShort num_after_IUP_stack_elements = 0;
760 /* DELTAP[1-3] stacks for both x and y directions */
761 FT_UInt* delta_before_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
762 FT_UInt* delta_after_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
763 unsigned int num_delta_before_IUP_args[6] = {0, 0, 0, 0, 0, 0};
764 unsigned int num_delta_after_IUP_args[6] = {0, 0, 0, 0, 0, 0};
765 FT_UInt* args = NULL;
767 FT_Bool need_before_IUP_words = 0;
768 FT_Bool need_after_IUP_words = 0;
769 FT_Bool need_before_IUP_word_counts = 0;
770 FT_Bool need_after_IUP_word_counts = 0;
771 FT_Bool allocated_before_IUP = 0;
772 FT_Bool allocated_after_IUP = 0;
775 num_points = glyph->num_points;
777 /* loop over all fitting control instructions */
778 for (;;)
780 const Ctrl* ctrl = TA_control_get_ctrl(font);
783 if (!ctrl)
784 break;
786 /* check type */
787 if (!(ctrl->type == Control_Delta_before_IUP
788 || ctrl->type == Control_Delta_after_IUP))
789 break;
791 /* too large values of font and glyph indices in `ctrl' */
792 /* are handled by later calls of this function */
793 if (face->face_index < ctrl->font_idx
794 || idx < ctrl->glyph_idx)
795 break;
797 if (ctrl->type == Control_Delta_before_IUP
798 && !allocated_before_IUP)
800 for (i = 0; i < 6; i++)
802 /* see the comment on allocating `ins_buf' in function */
803 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
804 /* we have to increase by 2 to push the number of argument pairs */
805 /* and the function for a LOOPCALL instruction */
806 delta_before_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 2)
807 * sizeof (FT_UInt));
808 if (!delta_before_IUP_args[i])
810 bufp = NULL;
811 goto Done;
815 allocated_before_IUP = 1;
818 if (ctrl->type == Control_Delta_after_IUP
819 && !allocated_after_IUP)
821 for (i = 0; i < 6; i++)
823 /* we have to increase by 1 for the number of argument pairs */
824 /* as needed by the DELTA instructions */
825 delta_after_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
826 * sizeof (FT_UInt));
827 if (!delta_after_IUP_args[i])
829 bufp = NULL;
830 goto Done;
834 allocated_after_IUP = 1;
837 /* since we walk sequentially over all glyphs (with points), */
838 /* and the control instruction entries have the same order, */
839 /* we don't need to test for equality of font and glyph indices: */
840 /* at this very point in the code we certainly have a hit */
841 if (ctrl->type == Control_Delta_before_IUP)
843 build_delta_exception(ctrl,
844 delta_before_IUP_args,
845 num_delta_before_IUP_args);
847 if (ctrl->point_idx > 255)
848 need_before_IUP_words = 1;
850 else
852 build_delta_exception(ctrl,
853 delta_after_IUP_args,
854 num_delta_after_IUP_args);
856 if (ctrl->point_idx > 255)
857 need_after_IUP_words = 1;
860 TA_control_get_next(font);
863 /* nothing to do if no control instructions */
864 if (!(allocated_before_IUP || allocated_after_IUP))
865 return bufp;
867 /* add number of argument pairs and function number to the stacks */
868 for (i = 0; i < 6; i++)
870 if (num_delta_before_IUP_args[i])
872 unsigned int n = num_delta_before_IUP_args[i] >> 1;
875 if (n > 255)
876 need_before_IUP_word_counts = 1;
878 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) = n;
879 num_delta_before_IUP_args[i]++;
881 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) =
882 bci_deltap1 + (i % 3);
883 num_delta_before_IUP_args[i]++;
887 /* add number of argument pairs to the stacks */
888 for (i = 0; i < 6; i++)
890 if (num_delta_after_IUP_args[i])
892 unsigned int n = num_delta_after_IUP_args[i] >> 1;
895 if (n > 255)
896 need_after_IUP_word_counts = 1;
898 *(delta_after_IUP_args[i] + num_delta_after_IUP_args[i]) = n;
899 num_delta_after_IUP_args[i]++;
903 /* merge `before IUP' delta stacks into a single one */
904 if (need_before_IUP_words || !need_before_IUP_word_counts)
906 FT_UInt num_args = 0;
909 for (i = 0; i < 6; i++)
911 FT_UInt* args_new;
912 FT_UInt num_args_new;
915 if (!num_delta_before_IUP_args[i])
916 continue;
918 num_args_new = num_args + num_delta_before_IUP_args[i];
919 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
920 if (!args_new)
922 bufp = NULL;
923 goto Done;
926 memcpy(args_new + num_args,
927 delta_before_IUP_args[i],
928 num_delta_before_IUP_args[i] * sizeof (FT_UInt));
930 args = args_new;
931 num_args = num_args_new;
934 num_before_IUP_stack_elements = (FT_UShort)num_args;
936 bufp = TA_build_push(bufp, args, num_args, need_before_IUP_words, 1);
938 else
940 num_before_IUP_stack_elements = 0;
942 /* stack elements are bytes, but counts need words */
943 for (i = 0; i < 6; i++)
945 FT_UInt num_delta_arg;
948 if (!num_delta_before_IUP_args[i])
949 continue;
951 num_delta_arg = num_delta_before_IUP_args[i] - 2;
953 bufp = TA_build_push(bufp,
954 delta_before_IUP_args[i],
955 num_delta_arg,
956 need_before_IUP_words,
959 num_before_IUP_stack_elements += num_delta_arg + 2;
961 num_delta_arg >>= 1;
962 BCI(PUSHW_1);
963 BCI(HIGH(num_delta_arg));
964 BCI(LOW(num_delta_arg));
966 /* the function number */
967 BCI(PUSHB_1);
968 BCI(delta_before_IUP_args[i][num_delta_before_IUP_args[i] - 1]);
972 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
973 if (num_delta_before_IUP_args[5])
974 BCI(LOOPCALL);
975 if (num_delta_before_IUP_args[4])
976 BCI(LOOPCALL);
977 if (num_delta_before_IUP_args[3])
978 BCI(LOOPCALL);
980 if (num_delta_before_IUP_args[2]
981 || num_delta_before_IUP_args[1]
982 || num_delta_before_IUP_args[0])
983 BCI(SVTCA_x);
985 /* emit x DELTA opcodes */
986 if (num_delta_before_IUP_args[2])
987 BCI(LOOPCALL);
988 if (num_delta_before_IUP_args[1])
989 BCI(LOOPCALL);
990 if (num_delta_before_IUP_args[0])
991 BCI(LOOPCALL);
993 if (num_delta_before_IUP_args[2]
994 || num_delta_before_IUP_args[1]
995 || num_delta_before_IUP_args[0])
996 BCI(SVTCA_y);
998 if (num_delta_before_IUP_args[5]
999 || num_delta_before_IUP_args[4]
1000 || num_delta_before_IUP_args[3])
1001 BCI(IUP_y);
1003 /* merge `after IUP' delta stacks into a single one */
1004 if (need_after_IUP_words || !need_after_IUP_word_counts)
1006 FT_UInt num_args = 0;
1009 for (i = 0; i < 6; i++)
1011 FT_UInt* args_new;
1012 FT_UInt num_args_new;
1015 if (!num_delta_after_IUP_args[i])
1016 continue;
1018 num_args_new = num_args + num_delta_after_IUP_args[i];
1019 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
1020 if (!args_new)
1022 bufp = NULL;
1023 goto Done;
1026 memcpy(args_new + num_args,
1027 delta_after_IUP_args[i],
1028 num_delta_after_IUP_args[i] * sizeof (FT_UInt));
1030 args = args_new;
1031 num_args = num_args_new;
1034 num_after_IUP_stack_elements = (FT_UShort)num_args;
1036 bufp = TA_build_push(bufp, args, num_args, need_after_IUP_words, 1);
1038 else
1040 num_after_IUP_stack_elements = 0;
1042 /* stack elements are bytes, but counts need words */
1043 for (i = 0; i < 6; i++)
1045 FT_UInt num_delta_arg;
1048 if (!num_delta_after_IUP_args[i])
1049 continue;
1051 num_delta_arg = num_delta_after_IUP_args[i] - 1;
1053 bufp = TA_build_push(bufp,
1054 delta_after_IUP_args[i],
1055 num_delta_arg,
1056 need_after_IUP_words,
1059 num_after_IUP_stack_elements += num_delta_arg + 1;
1061 num_delta_arg >>= 1;
1062 BCI(PUSHW_1);
1063 BCI(HIGH(num_delta_arg));
1064 BCI(LOW(num_delta_arg));
1068 /* emit y DELTA opcodes */
1069 if (num_delta_after_IUP_args[5])
1070 BCI(DELTAP3);
1071 if (num_delta_after_IUP_args[4])
1072 BCI(DELTAP2);
1073 if (num_delta_after_IUP_args[3])
1074 BCI(DELTAP1);
1076 if (num_delta_after_IUP_args[2]
1077 || num_delta_after_IUP_args[1]
1078 || num_delta_after_IUP_args[0])
1079 BCI(SVTCA_x);
1081 /* emit x DELTA opcodes */
1082 if (num_delta_after_IUP_args[2])
1083 BCI(DELTAP3);
1084 if (num_delta_after_IUP_args[1])
1085 BCI(DELTAP2);
1086 if (num_delta_after_IUP_args[0])
1087 BCI(DELTAP1);
1089 /* we need to insert a few extra bytecode instructions */
1090 /* if we have y delta exceptions before IUP */
1091 if (num_delta_before_IUP_args[5]
1092 || num_delta_before_IUP_args[4]
1093 || num_delta_before_IUP_args[3])
1095 FT_Byte* ins_extra_buf_new;
1096 FT_Byte ins_extra_len_new;
1099 ins_extra_len_new = glyph->ins_extra_len
1100 + sizeof (ins_extra_delta_exceptions);
1101 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
1102 ins_extra_len_new);
1103 if (!ins_extra_buf_new)
1105 bufp = NULL;
1106 goto Done;
1109 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1110 /* by activating `ins_extra_delta_exceptions' */
1111 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
1112 ins_extra_delta_exceptions,
1113 sizeof (ins_extra_delta_exceptions));
1115 glyph->ins_extra_buf = ins_extra_buf_new;
1116 glyph->ins_extra_len = ins_extra_len_new;
1118 /* reset `cvtl_do_iup_y' for next glyph */
1119 BCI(PUSHB_2);
1120 BCI(cvtl_do_iup_y);
1121 BCI(100);
1122 BCI(WCVTP);
1125 Done:
1126 for (i = 0; i < 6; i++)
1128 free(delta_before_IUP_args[i]);
1129 free(delta_after_IUP_args[i]);
1131 free(args);
1133 if (num_before_IUP_stack_elements > sfnt->max_stack_elements)
1134 sfnt->max_stack_elements = num_before_IUP_stack_elements;
1135 if (num_after_IUP_stack_elements > sfnt->max_stack_elements)
1136 sfnt->max_stack_elements = num_after_IUP_stack_elements;
1138 return bufp;
1142 static FT_Byte*
1143 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
1144 Recorder* recorder,
1145 FT_Byte* bufp)
1147 FONT* font = recorder->font;
1148 FT_GlyphSlot glyph = sfnt->face->glyph;
1149 FT_Vector* points = glyph->outline.points;
1150 FT_UInt num_contours = (FT_UInt)glyph->outline.n_contours;
1152 FT_UInt* args;
1153 FT_UInt* arg;
1154 FT_UInt num_args;
1156 FT_Bool need_words = 0;
1157 FT_UInt p, q;
1158 FT_UInt start, end;
1159 FT_UShort num_storage;
1160 FT_UShort num_stack_elements;
1163 num_args = 2 * num_contours + 2;
1165 /* collect all arguments temporarily in an array (in reverse order) */
1166 /* so that we can easily split into chunks of 255 args */
1167 /* as needed by NPUSHB and NPUSHW, respectively */
1168 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1169 if (!args)
1170 return NULL;
1172 arg = args + num_args - 1;
1174 if (num_args > 0xFF)
1175 need_words = 1;
1177 if (recorder->glyph->num_components && font->hint_composites)
1178 *(arg--) = bci_scale_composite_glyph;
1179 else
1180 *(arg--) = bci_scale_glyph;
1181 *(arg--) = num_contours;
1183 start = 0;
1184 end = 0;
1186 for (p = 0; p < num_contours; p++)
1188 FT_UInt max = start;
1189 FT_UInt min = start;
1192 end = (FT_UInt)glyph->outline.contours[p];
1194 for (q = start; q <= end; q++)
1196 if (points[q].y < points[min].y)
1197 min = q;
1198 if (points[q].y > points[max].y)
1199 max = q;
1202 if (min > max)
1204 *(arg--) = TA_adjust_point_index(recorder, max);
1205 *(arg--) = TA_adjust_point_index(recorder, min);
1207 else
1209 *(arg--) = TA_adjust_point_index(recorder, min);
1210 *(arg--) = TA_adjust_point_index(recorder, max);
1213 start = end + 1;
1216 if (end > 0xFF)
1217 need_words = 1;
1219 /* with most fonts it is very rare */
1220 /* that any of the pushed arguments is larger than 0xFF, */
1221 /* thus we refrain from further optimizing this case */
1222 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
1224 BCI(CALL);
1226 num_storage = sal_segment_offset;
1227 if (num_storage > sfnt->max_storage)
1228 sfnt->max_storage = num_storage;
1230 num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS + num_args);
1231 if (num_stack_elements > sfnt->max_stack_elements)
1232 sfnt->max_stack_elements = num_stack_elements;
1234 free(args);
1236 return bufp;
1240 static FT_Byte*
1241 TA_font_build_subglyph_shifter(FONT* font,
1242 FT_Byte* bufp)
1244 FT_Face face = font->loader->face;
1245 FT_GlyphSlot glyph = face->glyph;
1247 TA_GlyphLoader gloader = font->loader->gloader;
1249 TA_SubGlyph subglyphs = gloader->current.subglyphs;
1250 TA_SubGlyph subglyph_limit = subglyphs + gloader->current.num_subglyphs;
1251 TA_SubGlyph subglyph;
1253 FT_Int curr_contour = 0;
1256 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
1258 FT_Error error;
1260 FT_UShort flags = subglyph->flags;
1261 FT_Pos y_offset = subglyph->arg2;
1263 FT_Int num_contours;
1266 /* load subglyph to get the number of contours */
1267 error = FT_Load_Glyph(face, (FT_UInt)subglyph->index, FT_LOAD_NO_SCALE);
1268 if (error)
1269 return NULL;
1270 num_contours = glyph->outline.n_contours;
1272 /* nothing to do if there is a point-to-point alignment */
1273 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1274 goto End;
1276 /* nothing to do if y offset is zero */
1277 if (!y_offset)
1278 goto End;
1280 /* nothing to do if there are no contours */
1281 if (!num_contours)
1282 goto End;
1284 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1285 /* ensures that composite subglyphs are represented as simple glyphs */
1287 if (num_contours > 0xFF
1288 || curr_contour > 0xFF)
1290 BCI(PUSHW_2);
1291 BCI(HIGH(curr_contour));
1292 BCI(LOW(curr_contour));
1293 BCI(HIGH(num_contours));
1294 BCI(LOW(num_contours));
1296 else
1298 BCI(PUSHB_2);
1299 BCI(curr_contour);
1300 BCI(num_contours);
1303 /* there are high chances that this value needs PUSHW, */
1304 /* thus we handle it separately */
1305 if (y_offset > 0xFF || y_offset < 0)
1307 BCI(PUSHW_1);
1308 BCI(HIGH(y_offset));
1309 BCI(LOW(y_offset));
1311 else
1313 BCI(PUSHB_1);
1314 BCI(y_offset);
1317 BCI(PUSHB_1);
1318 BCI(bci_shift_subglyph);
1319 BCI(CALL);
1321 End:
1322 curr_contour += num_contours;
1325 return bufp;
1330 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1331 * data in four arrays (which are simple but waste a lot of memory). The
1332 * function below converts them into bytecode.
1334 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1335 * together with the edge they correspond to.
1337 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1338 * loop over the edge or edge pairs, respectively, and each edge or edge
1339 * pair contains an inner loop to emit the correponding points.
1342 static void
1343 TA_build_point_hints(Recorder* recorder,
1344 TA_GlyphHints hints)
1346 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1347 TA_Edge edges = axis->edges;
1349 FT_Byte* p = recorder->hints_record.buf;
1351 FT_UShort i;
1352 FT_UShort j;
1354 FT_UShort prev_edge;
1355 FT_UShort prev_before_edge;
1356 FT_UShort prev_after_edge;
1358 Node1* before_node;
1359 Node1* after_node;
1360 Node2* on_node;
1361 Node3* between_node;
1364 /* we store everything as 16bit numbers; */
1365 /* the function numbers (`ta_ip_before', etc.) */
1366 /* reflect the order in the TA_Action enumeration */
1368 /* ip_before_points */
1370 i = 0;
1371 for (before_node = LLRB_MIN(ip_before_points,
1372 &recorder->ip_before_points_head);
1373 before_node;
1374 before_node = LLRB_NEXT(ip_before_points,
1375 &recorder->ip_before_points_head,
1376 before_node))
1378 /* count points */
1379 i++;
1382 if (i)
1384 TA_Edge edge;
1385 FT_UShort edge_first_idx;
1388 recorder->hints_record.num_actions++;
1390 edge = edges;
1391 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1393 *(p++) = 0;
1394 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1395 *(p++) = HIGH(edge_first_idx);
1396 *(p++) = LOW(edge_first_idx);
1397 *(p++) = HIGH(i);
1398 *(p++) = LOW(i);
1400 for (before_node = LLRB_MIN(ip_before_points,
1401 &recorder->ip_before_points_head);
1402 before_node;
1403 before_node = LLRB_NEXT(ip_before_points,
1404 &recorder->ip_before_points_head,
1405 before_node))
1407 FT_UInt point;
1410 point = TA_adjust_point_index(recorder, before_node->point);
1411 *(p++) = HIGH(point);
1412 *(p++) = LOW(point);
1416 /* ip_after_points */
1418 i = 0;
1419 for (after_node = LLRB_MIN(ip_after_points,
1420 &recorder->ip_after_points_head);
1421 after_node;
1422 after_node = LLRB_NEXT(ip_after_points,
1423 &recorder->ip_after_points_head,
1424 after_node))
1426 /* count points */
1427 i++;
1430 if (i)
1432 TA_Edge edge;
1433 FT_UShort edge_first_idx;
1436 recorder->hints_record.num_actions++;
1438 edge = edges + axis->num_edges - 1;
1439 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1441 *(p++) = 0;
1442 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1443 *(p++) = HIGH(edge_first_idx);
1444 *(p++) = LOW(edge_first_idx);
1445 *(p++) = HIGH(i);
1446 *(p++) = LOW(i);
1448 for (after_node = LLRB_MIN(ip_after_points,
1449 &recorder->ip_after_points_head);
1450 after_node;
1451 after_node = LLRB_NEXT(ip_after_points,
1452 &recorder->ip_after_points_head,
1453 after_node))
1455 FT_UInt point;
1458 point = TA_adjust_point_index(recorder, after_node->point);
1459 *(p++) = HIGH(point);
1460 *(p++) = LOW(point);
1464 /* ip_on_point_array */
1466 prev_edge = 0xFFFF;
1467 i = 0;
1468 for (on_node = LLRB_MIN(ip_on_points,
1469 &recorder->ip_on_points_head);
1470 on_node;
1471 on_node = LLRB_NEXT(ip_on_points,
1472 &recorder->ip_on_points_head,
1473 on_node))
1475 /* count edges */
1476 if (on_node->edge != prev_edge)
1478 i++;
1479 prev_edge = on_node->edge;
1483 if (i)
1485 recorder->hints_record.num_actions++;
1487 *(p++) = 0;
1488 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1489 *(p++) = HIGH(i);
1490 *(p++) = LOW(i);
1492 for (on_node = LLRB_MIN(ip_on_points,
1493 &recorder->ip_on_points_head);
1494 on_node;
1495 on_node = LLRB_NEXT(ip_on_points,
1496 &recorder->ip_on_points_head,
1497 on_node))
1499 Node2* edge_node;
1500 TA_Edge edge;
1501 FT_UShort edge_first_idx;
1504 edge = edges + on_node->edge;
1505 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1507 *(p++) = HIGH(edge_first_idx);
1508 *(p++) = LOW(edge_first_idx);
1510 /* save current position */
1511 edge_node = on_node;
1512 j = 0;
1513 for (;
1514 on_node;
1515 on_node = LLRB_NEXT(ip_on_points,
1516 &recorder->ip_on_points_head,
1517 on_node))
1519 /* count points on current edge */
1520 if (on_node->edge != edge_node->edge)
1521 break;
1522 j++;
1525 *(p++) = HIGH(j);
1526 *(p++) = LOW(j);
1528 /* restore current position */
1529 on_node = edge_node;
1530 for (;
1531 on_node;
1532 on_node = LLRB_NEXT(ip_on_points,
1533 &recorder->ip_on_points_head,
1534 on_node))
1536 FT_UInt point;
1539 if (on_node->edge != edge_node->edge)
1540 break;
1542 point = TA_adjust_point_index(recorder, on_node->point);
1543 *(p++) = HIGH(point);
1544 *(p++) = LOW(point);
1546 /* keep track of previous node */
1547 edge_node = on_node;
1550 /* reset loop iterator by one element, then continue */
1551 on_node = edge_node;
1555 /* ip_between_point_array */
1557 prev_before_edge = 0xFFFF;
1558 prev_after_edge = 0xFFFF;
1559 i = 0;
1560 for (between_node = LLRB_MIN(ip_between_points,
1561 &recorder->ip_between_points_head);
1562 between_node;
1563 between_node = LLRB_NEXT(ip_between_points,
1564 &recorder->ip_between_points_head,
1565 between_node))
1567 /* count `(before,after)' edge pairs */
1568 if (between_node->before_edge != prev_before_edge
1569 || between_node->after_edge != prev_after_edge)
1571 i++;
1572 prev_before_edge = between_node->before_edge;
1573 prev_after_edge = between_node->after_edge;
1577 if (i)
1579 recorder->hints_record.num_actions++;
1581 *(p++) = 0;
1582 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1583 *(p++) = HIGH(i);
1584 *(p++) = LOW(i);
1586 for (between_node = LLRB_MIN(ip_between_points,
1587 &recorder->ip_between_points_head);
1588 between_node;
1589 between_node = LLRB_NEXT(ip_between_points,
1590 &recorder->ip_between_points_head,
1591 between_node))
1593 Node3* edge_pair_node;
1594 TA_Edge before;
1595 TA_Edge after;
1596 FT_UShort before_first_idx;
1597 FT_UShort after_first_idx;
1600 before = edges + between_node->before_edge;
1601 after = edges + between_node->after_edge;
1602 before_first_idx = TA_get_segment_index(before->first, recorder);
1603 after_first_idx = TA_get_segment_index(after->first, recorder);
1605 *(p++) = HIGH(after_first_idx);
1606 *(p++) = LOW(after_first_idx);
1607 *(p++) = HIGH(before_first_idx);
1608 *(p++) = LOW(before_first_idx);
1610 /* save current position */
1611 edge_pair_node = between_node;
1612 j = 0;
1613 for (;
1614 between_node;
1615 between_node = LLRB_NEXT(ip_between_points,
1616 &recorder->ip_between_points_head,
1617 between_node))
1619 /* count points associated with current edge pair */
1620 if (between_node->before_edge != edge_pair_node->before_edge
1621 || between_node->after_edge != edge_pair_node->after_edge)
1622 break;
1623 j++;
1626 *(p++) = HIGH(j);
1627 *(p++) = LOW(j);
1629 /* restore current position */
1630 between_node = edge_pair_node;
1631 for (;
1632 between_node;
1633 between_node = LLRB_NEXT(ip_between_points,
1634 &recorder->ip_between_points_head,
1635 between_node))
1637 FT_UInt point;
1640 if (between_node->before_edge != edge_pair_node->before_edge
1641 || between_node->after_edge != edge_pair_node->after_edge)
1642 break;
1644 point = TA_adjust_point_index(recorder, between_node->point);
1645 *(p++) = HIGH(point);
1646 *(p++) = LOW(point);
1648 /* keep track of previous node */
1649 edge_pair_node = between_node;
1652 /* reset loop iterator by one element, then continue */
1653 between_node = edge_pair_node;
1657 recorder->hints_record.buf = p;
1661 static FT_Bool
1662 TA_hints_record_is_different(Hints_Record* hints_records,
1663 FT_UInt num_hints_records,
1664 FT_Byte* start,
1665 FT_Byte* end)
1667 Hints_Record last_hints_record;
1670 if (!hints_records)
1671 return 1;
1673 /* we only need to compare with the last hints record */
1674 last_hints_record = hints_records[num_hints_records - 1];
1676 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1677 return 1;
1679 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1680 return 1;
1682 return 0;
1686 static FT_Error
1687 TA_add_hints_record(Hints_Record** hints_records,
1688 FT_UInt* num_hints_records,
1689 FT_Byte* start,
1690 Hints_Record hints_record)
1692 Hints_Record* hints_records_new;
1693 FT_UInt buf_len;
1694 /* at this point, `hints_record.buf' still points into `ins_buf' */
1695 FT_Byte* end = hints_record.buf;
1698 buf_len = (FT_UInt)(end - start);
1700 /* now fill the structure completely */
1701 hints_record.buf_len = buf_len;
1702 hints_record.buf = (FT_Byte*)malloc(buf_len);
1703 if (!hints_record.buf)
1704 return FT_Err_Out_Of_Memory;
1706 memcpy(hints_record.buf, start, buf_len);
1708 (*num_hints_records)++;
1709 hints_records_new =
1710 (Hints_Record*)realloc(*hints_records, *num_hints_records
1711 * sizeof (Hints_Record));
1712 if (!hints_records_new)
1714 free(hints_record.buf);
1715 (*num_hints_records)--;
1716 return FT_Err_Out_Of_Memory;
1718 else
1719 *hints_records = hints_records_new;
1721 (*hints_records)[*num_hints_records - 1] = hints_record;
1723 return FT_Err_Ok;
1727 static FT_Byte*
1728 TA_emit_hints_record(Recorder* recorder,
1729 Hints_Record* hints_record,
1730 FT_Byte* bufp,
1731 FT_Bool optimize)
1733 FT_Byte* p;
1734 FT_Byte* endp;
1735 FT_Bool need_words = 0;
1737 FT_UInt i, j;
1738 FT_UInt num_arguments;
1739 FT_UInt num_args;
1742 /* check whether any argument is larger than 0xFF */
1743 endp = hints_record->buf + hints_record->buf_len;
1744 for (p = hints_record->buf; p < endp; p += 2)
1745 if (*p)
1747 need_words = 1;
1748 break;
1751 /* with most fonts it is very rare */
1752 /* that any of the pushed arguments is larger than 0xFF, */
1753 /* thus we refrain from further optimizing this case */
1755 num_arguments = hints_record->buf_len / 2;
1756 p = endp - 2;
1758 if (need_words)
1760 for (i = 0; i < num_arguments; i += 255)
1762 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1764 if (optimize && num_args <= 8)
1765 BCI(PUSHW_1 - 1 + num_args);
1766 else
1768 BCI(NPUSHW);
1769 BCI(num_args);
1771 for (j = 0; j < num_args; j++)
1773 BCI(*p);
1774 BCI(*(p + 1));
1775 p -= 2;
1779 else
1781 /* we only need the lower bytes */
1782 p++;
1784 for (i = 0; i < num_arguments; i += 255)
1786 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1788 if (optimize && num_args <= 8)
1789 BCI(PUSHB_1 - 1 + num_args);
1790 else
1792 BCI(NPUSHB);
1793 BCI(num_args);
1795 for (j = 0; j < num_args; j++)
1797 BCI(*p);
1798 p -= 2;
1803 /* collect stack depth data */
1804 if (num_arguments > recorder->num_stack_elements)
1805 recorder->num_stack_elements = (FT_UShort)num_arguments;
1807 return bufp;
1811 static FT_Byte*
1812 TA_emit_hints_records(Recorder* recorder,
1813 Hints_Record* hints_records,
1814 FT_UInt num_hints_records,
1815 FT_Byte* bufp,
1816 FT_Bool optimize)
1818 FT_UInt i;
1819 Hints_Record* hints_record;
1822 hints_record = hints_records;
1824 /* emit hints records in `if' clauses, */
1825 /* with the ppem size as the condition */
1826 for (i = 0; i < num_hints_records - 1; i++)
1828 BCI(MPPEM);
1829 if (hints_record->size > 0xFF)
1831 BCI(PUSHW_1);
1832 BCI(HIGH((hints_record + 1)->size));
1833 BCI(LOW((hints_record + 1)->size));
1835 else
1837 BCI(PUSHB_1);
1838 BCI((hints_record + 1)->size);
1840 BCI(LT);
1841 BCI(IF);
1842 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1843 BCI(ELSE);
1845 hints_record++;
1848 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1850 for (i = 0; i < num_hints_records - 1; i++)
1851 BCI(EIF);
1853 return bufp;
1857 static void
1858 TA_free_hints_records(Hints_Record* hints_records,
1859 FT_UInt num_hints_records)
1861 FT_UInt i;
1864 for (i = 0; i < num_hints_records; i++)
1865 free(hints_records[i].buf);
1867 free(hints_records);
1871 static FT_Byte*
1872 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1873 Recorder* recorder,
1874 TA_Edge edge,
1875 FT_UShort* wraps)
1877 TA_Segment seg;
1878 FT_UShort seg_idx;
1879 FT_UShort num_segs = 0;
1880 FT_UShort* wrap;
1881 FT_UShort num_segments;
1884 seg_idx = TA_get_segment_index(edge->first, recorder);
1885 num_segments = TA_get_segment_index(NULL, recorder);
1887 /* we store everything as 16bit numbers */
1888 *(bufp++) = HIGH(seg_idx);
1889 *(bufp++) = LOW(seg_idx);
1891 /* wrap-around segments are stored as two segments */
1892 if (edge->first->first > edge->first->last)
1893 num_segs++;
1895 seg = edge->first->edge_next;
1896 while (seg != edge->first)
1898 num_segs++;
1900 if (seg->first > seg->last)
1901 num_segs++;
1903 seg = seg->edge_next;
1906 *(bufp++) = HIGH(num_segs);
1907 *(bufp++) = LOW(num_segs);
1909 if (edge->first->first > edge->first->last)
1911 /* emit second part of wrap-around segment; */
1912 /* the bytecode positions such segments after `normal' ones */
1913 wrap = wraps;
1914 for (;;)
1916 if (seg_idx == *wrap)
1917 break;
1918 wrap++;
1921 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1922 *(bufp++) = LOW(num_segments + (wrap - wraps));
1925 seg = edge->first->edge_next;
1926 while (seg != edge->first)
1928 seg_idx = TA_get_segment_index(seg, recorder);
1930 *(bufp++) = HIGH(seg_idx);
1931 *(bufp++) = LOW(seg_idx);
1933 if (seg->first > seg->last)
1935 wrap = wraps;
1936 for (;;)
1938 if (seg_idx == *wrap)
1939 break;
1940 wrap++;
1943 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1944 *(bufp++) = LOW(num_segments + (wrap - wraps));
1947 seg = seg->edge_next;
1950 return bufp;
1954 static void
1955 TA_hints_recorder(TA_Action action,
1956 TA_GlyphHints hints,
1957 TA_Dimension dim,
1958 void* arg1,
1959 TA_Edge arg2,
1960 TA_Edge arg3,
1961 TA_Edge lower_bound,
1962 TA_Edge upper_bound)
1964 TA_AxisHints axis = &hints->axis[dim];
1965 TA_Edge edges = axis->edges;
1966 TA_Point points = hints->points;
1968 TA_Segment segments = axis->segments;
1969 TA_Segment seg_limit = segments + axis->num_segments;
1970 TA_Segment seg;
1972 Recorder* recorder = (Recorder*)hints->user;
1973 SFNT* sfnt = recorder->sfnt;
1974 FONT* font = recorder->font;
1975 FT_UShort* wraps = recorder->wrap_around_segments;
1976 FT_Byte* p = recorder->hints_record.buf;
1978 TA_StyleClass style_class = font->loader->metrics->style_class;
1979 TA_ScriptClass script_class = ta_script_classes[style_class->script];
1981 FT_UInt style = style_class->style;
1982 FT_Bool top_to_bottom_hinting = script_class->top_to_bottom_hinting;
1985 if (dim == TA_DIMENSION_HORZ)
1986 return;
1988 if (!recorder->segment_map_initialized)
1990 FT_UShort* segment_map = recorder->segment_map;
1991 FT_UShort idx;
1994 idx = 0;
1995 for (seg = segments; seg < seg_limit; seg++)
1997 if (seg->edge)
1998 *segment_map = idx++;
1999 else
2000 *segment_map = 0xFFFF;
2002 segment_map++;
2004 *segment_map = idx;
2006 recorder->segment_map_initialized = 1;
2009 if (!recorder->wrap_around_segments_initialized)
2011 FT_UShort* wrap_around_segment;
2014 wrap_around_segment = recorder->wrap_around_segments;
2015 for (seg = segments; seg < seg_limit; seg++)
2016 if (seg->first > seg->last)
2017 *(wrap_around_segment++) = TA_get_segment_index(seg, recorder);
2019 recorder->wrap_around_segments_initialized = 1;
2022 /* we collect point hints for later processing */
2023 switch (action)
2025 case ta_ip_before:
2027 Node1* before_node;
2028 TA_Point point = (TA_Point)arg1;
2031 before_node = (Node1*)malloc(sizeof (Node1));
2032 if (!before_node)
2033 return;
2034 before_node->point = (FT_UShort)(point - points);
2036 LLRB_INSERT(ip_before_points,
2037 &recorder->ip_before_points_head,
2038 before_node);
2040 return;
2042 case ta_ip_after:
2044 Node1* after_node;
2045 TA_Point point = (TA_Point)arg1;
2048 after_node = (Node1*)malloc(sizeof (Node1));
2049 if (!after_node)
2050 return;
2051 after_node->point = (FT_UShort)(point - points);
2053 LLRB_INSERT(ip_after_points,
2054 &recorder->ip_after_points_head,
2055 after_node);
2057 return;
2059 case ta_ip_on:
2061 Node2* on_node;
2062 TA_Point point = (TA_Point)arg1;
2063 TA_Edge edge = arg2;
2066 on_node = (Node2*)malloc(sizeof (Node2));
2067 if (!on_node)
2068 return;
2069 on_node->edge = (FT_UShort)(edge - edges);
2070 on_node->point = (FT_UShort)(point - points);
2072 LLRB_INSERT(ip_on_points,
2073 &recorder->ip_on_points_head,
2074 on_node);
2076 return;
2078 case ta_ip_between:
2080 Node3* between_node;
2081 TA_Point point = (TA_Point)arg1;
2082 TA_Edge before = arg2;
2083 TA_Edge after = arg3;
2086 between_node = (Node3*)malloc(sizeof (Node3));
2087 if (!between_node)
2088 return;
2089 between_node->before_edge = (FT_UShort)(before - edges);
2090 between_node->after_edge = (FT_UShort)(after - edges);
2091 between_node->point = (FT_UShort)(point - points);
2093 LLRB_INSERT(ip_between_points,
2094 &recorder->ip_between_points_head,
2095 between_node);
2097 return;
2099 case ta_bound:
2100 /* we ignore the BOUND action since we signal this information */
2101 /* with the proper function number */
2102 return;
2104 default:
2105 break;
2108 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2109 /* if the value is n, the function numbers are n, ..., n+11, */
2110 /* to be differentiated with flags */
2112 switch (action)
2114 case ta_link:
2116 TA_Edge base_edge = (TA_Edge)arg1;
2117 TA_Edge stem_edge = arg2;
2118 FT_UShort base_first_idx;
2119 FT_UShort stem_first_idx;
2122 base_first_idx = TA_get_segment_index(base_edge->first, recorder);
2123 stem_first_idx = TA_get_segment_index(stem_edge->first, recorder);
2125 *(p++) = 0;
2126 *(p++) = (FT_Byte)action + ACTION_OFFSET
2127 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
2128 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
2130 *(p++) = HIGH(base_first_idx);
2131 *(p++) = LOW(base_first_idx);
2132 *(p++) = HIGH(stem_first_idx);
2133 *(p++) = LOW(stem_first_idx);
2135 p = TA_hints_recorder_handle_segments(p, recorder, stem_edge, wraps);
2137 break;
2139 case ta_anchor:
2141 TA_Edge edge = (TA_Edge)arg1;
2142 TA_Edge edge2 = arg2;
2143 FT_UShort edge_first_idx;
2144 FT_UShort edge2_first_idx;
2147 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2148 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2150 *(p++) = 0;
2151 *(p++) = (FT_Byte)action + ACTION_OFFSET
2152 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2153 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
2155 *(p++) = HIGH(edge_first_idx);
2156 *(p++) = LOW(edge_first_idx);
2157 *(p++) = HIGH(edge2_first_idx);
2158 *(p++) = LOW(edge2_first_idx);
2160 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2162 break;
2164 case ta_adjust:
2166 TA_Edge edge = (TA_Edge)arg1;
2167 TA_Edge edge2 = arg2;
2168 TA_Edge edge_minus_one = lower_bound;
2169 FT_UShort edge_first_idx;
2170 FT_UShort edge2_first_idx;
2173 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2174 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2176 *(p++) = 0;
2177 *(p++) = (FT_Byte)action + ACTION_OFFSET
2178 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2179 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2180 + 4 * (edge_minus_one != NULL) /* `bound' */
2181 + 4 * (edge_minus_one != NULL
2182 && top_to_bottom_hinting); /* `down' */
2184 *(p++) = HIGH(edge_first_idx);
2185 *(p++) = LOW(edge_first_idx);
2186 *(p++) = HIGH(edge2_first_idx);
2187 *(p++) = LOW(edge2_first_idx);
2189 if (edge_minus_one)
2191 FT_UShort edge_minus_one_first_idx;
2194 edge_minus_one_first_idx = TA_get_segment_index(
2195 edge_minus_one->first, recorder);
2197 *(p++) = HIGH(edge_minus_one_first_idx);
2198 *(p++) = LOW(edge_minus_one_first_idx);
2201 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2203 break;
2205 case ta_blue_anchor:
2207 TA_Edge edge = (TA_Edge)arg1;
2208 TA_Edge blue = arg2;
2209 FT_UShort blue_first_idx;
2210 FT_UShort edge_first_idx;
2213 blue_first_idx = TA_get_segment_index(blue->first, recorder);
2214 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2216 *(p++) = 0;
2217 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2219 *(p++) = HIGH(blue_first_idx);
2220 *(p++) = LOW(blue_first_idx);
2222 if (edge->best_blue_is_shoot)
2224 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2225 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2227 else
2229 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2230 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2233 *(p++) = HIGH(edge_first_idx);
2234 *(p++) = LOW(edge_first_idx);
2236 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2238 break;
2240 case ta_stem:
2242 TA_Edge edge = (TA_Edge)arg1;
2243 TA_Edge edge2 = arg2;
2244 TA_Edge edge_minus_one = lower_bound;
2245 FT_UShort edge_first_idx;
2246 FT_UShort edge2_first_idx;
2249 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2250 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2252 *(p++) = 0;
2253 *(p++) = (FT_Byte)action + ACTION_OFFSET
2254 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2255 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2256 + 4 * (edge_minus_one != NULL) /* `bound' */
2257 + 4 * (edge_minus_one != NULL
2258 && top_to_bottom_hinting); /* `down' */
2260 *(p++) = HIGH(edge_first_idx);
2261 *(p++) = LOW(edge_first_idx);
2262 *(p++) = HIGH(edge2_first_idx);
2263 *(p++) = LOW(edge2_first_idx);
2265 if (edge_minus_one)
2267 FT_UShort edge_minus_one_first_idx;
2270 edge_minus_one_first_idx = TA_get_segment_index(
2271 edge_minus_one->first, recorder);
2273 *(p++) = HIGH(edge_minus_one_first_idx);
2274 *(p++) = LOW(edge_minus_one_first_idx);
2277 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2278 p = TA_hints_recorder_handle_segments(p, recorder, edge2, wraps);
2280 break;
2282 case ta_blue:
2284 TA_Edge edge = (TA_Edge)arg1;
2285 FT_UShort edge_first_idx;
2288 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2290 *(p++) = 0;
2291 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2293 if (edge->best_blue_is_shoot)
2295 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2296 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2298 else
2300 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2301 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2304 *(p++) = HIGH(edge_first_idx);
2305 *(p++) = LOW(edge_first_idx);
2307 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2309 break;
2311 case ta_serif:
2313 TA_Edge serif = (TA_Edge)arg1;
2314 TA_Edge base = serif->serif;
2315 FT_UShort serif_first_idx;
2316 FT_UShort base_first_idx;
2319 serif_first_idx = TA_get_segment_index(serif->first, recorder);
2320 base_first_idx = TA_get_segment_index(base->first, recorder);
2322 *(p++) = 0;
2323 *(p++) = (FT_Byte)action + ACTION_OFFSET
2324 + (lower_bound != NULL)
2325 + 2 * (upper_bound != NULL)
2326 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2327 && top_to_bottom_hinting); /* `down' */
2329 *(p++) = HIGH(serif_first_idx);
2330 *(p++) = LOW(serif_first_idx);
2331 *(p++) = HIGH(base_first_idx);
2332 *(p++) = LOW(base_first_idx);
2334 if (lower_bound)
2336 FT_UShort lower_bound_first_idx;
2339 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2340 recorder);
2342 *(p++) = HIGH(lower_bound_first_idx);
2343 *(p++) = LOW(lower_bound_first_idx);
2345 if (upper_bound)
2347 FT_UShort upper_bound_first_idx;
2350 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2351 recorder);
2353 *(p++) = HIGH(upper_bound_first_idx);
2354 *(p++) = LOW(upper_bound_first_idx);
2357 p = TA_hints_recorder_handle_segments(p, recorder, serif, wraps);
2359 break;
2361 case ta_serif_anchor:
2362 case ta_serif_link2:
2364 TA_Edge edge = (TA_Edge)arg1;
2365 FT_UShort edge_first_idx;
2368 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2370 *(p++) = 0;
2371 *(p++) = (FT_Byte)action + ACTION_OFFSET
2372 + (lower_bound != NULL)
2373 + 2 * (upper_bound != NULL)
2374 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2375 && top_to_bottom_hinting); /* `down' */
2377 *(p++) = HIGH(edge_first_idx);
2378 *(p++) = LOW(edge_first_idx);
2380 if (lower_bound)
2382 FT_UShort lower_bound_first_idx;
2385 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2386 recorder);
2388 *(p++) = HIGH(lower_bound_first_idx);
2389 *(p++) = LOW(lower_bound_first_idx);
2391 if (upper_bound)
2393 FT_UShort upper_bound_first_idx;
2396 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2397 recorder);
2399 *(p++) = HIGH(upper_bound_first_idx);
2400 *(p++) = LOW(upper_bound_first_idx);
2403 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2405 break;
2407 case ta_serif_link1:
2409 TA_Edge edge = (TA_Edge)arg1;
2410 TA_Edge before = arg2;
2411 TA_Edge after = arg3;
2412 FT_UShort before_first_idx;
2413 FT_UShort edge_first_idx;
2414 FT_UShort after_first_idx;
2417 before_first_idx = TA_get_segment_index(before->first, recorder);
2418 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2419 after_first_idx = TA_get_segment_index(after->first, recorder);
2421 *(p++) = 0;
2422 *(p++) = (FT_Byte)action + ACTION_OFFSET
2423 + (lower_bound != NULL)
2424 + 2 * (upper_bound != NULL)
2425 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2426 && top_to_bottom_hinting); /* `down' */
2428 *(p++) = HIGH(before_first_idx);
2429 *(p++) = LOW(before_first_idx);
2430 *(p++) = HIGH(edge_first_idx);
2431 *(p++) = LOW(edge_first_idx);
2432 *(p++) = HIGH(after_first_idx);
2433 *(p++) = LOW(after_first_idx);
2435 if (lower_bound)
2437 FT_UShort lower_bound_first_idx;
2440 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2441 recorder);
2443 *(p++) = HIGH(lower_bound_first_idx);
2444 *(p++) = LOW(lower_bound_first_idx);
2446 if (upper_bound)
2448 FT_UShort upper_bound_first_idx;
2451 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2452 recorder);
2454 *(p++) = HIGH(upper_bound_first_idx);
2455 *(p++) = LOW(upper_bound_first_idx);
2458 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2460 break;
2462 default:
2463 /* there are more cases in the enumeration */
2464 /* which are handled with flags */
2465 break;
2468 recorder->hints_record.num_actions++;
2469 recorder->hints_record.buf = p;
2473 static FT_Error
2474 TA_init_recorder(Recorder* recorder,
2475 SFNT* sfnt,
2476 FONT* font,
2477 GLYPH* glyph,
2478 TA_GlyphHints hints)
2480 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2482 TA_Segment segments = axis->segments;
2483 TA_Segment seg_limit = segments + axis->num_segments;
2484 TA_Segment seg;
2487 recorder->sfnt = sfnt;
2488 recorder->font = font;
2489 recorder->glyph = glyph;
2491 LLRB_INIT(&recorder->ip_before_points_head);
2492 LLRB_INIT(&recorder->ip_after_points_head);
2493 LLRB_INIT(&recorder->ip_on_points_head);
2494 LLRB_INIT(&recorder->ip_between_points_head);
2496 recorder->num_stack_elements = 0;
2498 /* no need to clean up allocated arrays in case of error; */
2499 /* this is handled later by `TA_free_recorder' */
2501 /* we use segment_map[axis->num_segments] */
2502 /* as the total number of mapped segments, so allocate one more element */
2503 recorder->segment_map =
2504 (FT_UShort*)malloc((size_t)(axis->num_segments + 1) * sizeof (FT_UShort));
2505 if (!recorder->segment_map)
2506 return FT_Err_Out_Of_Memory;
2508 /* `segment_map' gets initialized later on, */
2509 /* after the first call of `ta_loader_load_glyph' */
2510 recorder->segment_map_initialized = 0;
2512 recorder->num_wrap_around_segments = 0;
2513 for (seg = segments; seg < seg_limit; seg++)
2514 if (seg->first > seg->last)
2515 recorder->num_wrap_around_segments++;
2517 recorder->wrap_around_segments =
2518 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2519 * sizeof (FT_UShort));
2520 if (!recorder->wrap_around_segments)
2521 return FT_Err_Out_Of_Memory;
2523 /* `wrap_around_segments' gets initialized later on; */
2524 /* it needs function `TA_get_segment_index' which uses data */
2525 /* that hasn't been initialized yet either */
2526 recorder->wrap_around_segments_initialized = 0;
2528 return FT_Err_Ok;
2532 static void
2533 TA_reset_recorder(Recorder* recorder,
2534 FT_Byte* bufp)
2536 recorder->hints_record.buf = bufp;
2537 recorder->hints_record.num_actions = 0;
2541 static void
2542 TA_rewind_recorder(Recorder* recorder,
2543 FT_Byte* bufp,
2544 FT_UInt size)
2546 Node1* before_node;
2547 Node1* after_node;
2548 Node2* on_node;
2549 Node3* between_node;
2551 Node1* next_before_node;
2552 Node1* next_after_node;
2553 Node2* next_on_node;
2554 Node3* next_between_node;
2557 TA_reset_recorder(recorder, bufp);
2559 recorder->hints_record.size = size;
2561 /* deallocate our red-black trees */
2563 for (before_node = LLRB_MIN(ip_before_points,
2564 &recorder->ip_before_points_head);
2565 before_node;
2566 before_node = next_before_node)
2568 next_before_node = LLRB_NEXT(ip_before_points,
2569 &recorder->ip_before_points_head,
2570 before_node);
2571 LLRB_REMOVE(ip_before_points,
2572 &recorder->ip_before_points_head,
2573 before_node);
2574 free(before_node);
2577 for (after_node = LLRB_MIN(ip_after_points,
2578 &recorder->ip_after_points_head);
2579 after_node;
2580 after_node = next_after_node)
2582 next_after_node = LLRB_NEXT(ip_after_points,
2583 &recorder->ip_after_points_head,
2584 after_node);
2585 LLRB_REMOVE(ip_after_points,
2586 &recorder->ip_after_points_head,
2587 after_node);
2588 free(after_node);
2591 for (on_node = LLRB_MIN(ip_on_points,
2592 &recorder->ip_on_points_head);
2593 on_node;
2594 on_node = next_on_node)
2596 next_on_node = LLRB_NEXT(ip_on_points,
2597 &recorder->ip_on_points_head,
2598 on_node);
2599 LLRB_REMOVE(ip_on_points,
2600 &recorder->ip_on_points_head,
2601 on_node);
2602 free(on_node);
2605 for (between_node = LLRB_MIN(ip_between_points,
2606 &recorder->ip_between_points_head);
2607 between_node;
2608 between_node = next_between_node)
2610 next_between_node = LLRB_NEXT(ip_between_points,
2611 &recorder->ip_between_points_head,
2612 between_node);
2613 LLRB_REMOVE(ip_between_points,
2614 &recorder->ip_between_points_head,
2615 between_node);
2616 free(between_node);
2621 static void
2622 TA_free_recorder(Recorder* recorder)
2624 free(recorder->segment_map);
2625 free(recorder->wrap_around_segments);
2627 TA_rewind_recorder(recorder, NULL, 0);
2631 FT_Error
2632 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2633 FONT* font,
2634 FT_Long idx)
2636 FT_Face face = sfnt->face;
2637 FT_Error error;
2639 FT_Byte* ins_buf;
2640 FT_UInt ins_len;
2641 FT_Byte* bufp;
2642 FT_Byte* p;
2644 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2645 glyf_Data* data = (glyf_Data*)glyf_table->data;
2646 /* `idx' is never negative */
2647 GLYPH* glyph = &data->glyphs[idx];
2649 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
2650 FT_UShort* gstyles = globals->glyph_styles;
2651 FT_Bool use_gstyle_data = 1;
2653 TA_GlyphHints hints;
2655 FT_UInt num_action_hints_records = 0;
2656 FT_UInt num_point_hints_records = 0;
2657 Hints_Record* action_hints_records = NULL;
2658 Hints_Record* point_hints_records = NULL;
2660 Recorder recorder;
2661 FT_UShort num_stack_elements;
2662 FT_Bool optimize = 0;
2664 FT_Int32 load_flags;
2665 FT_UInt size;
2667 /* we store only three positions, but it simplifies the algorithm in */
2668 /* `TA_optimize_push' if we have one additional element */
2669 FT_Byte* pos[4];
2671 #ifdef TA_DEBUG
2672 int _ta_debug_save;
2673 #endif
2676 /* XXX: right now, we abuse this flag to control */
2677 /* the global behaviour of the auto-hinter */
2678 load_flags = 1 << 29; /* vertical hinting only */
2679 if (!font->adjust_subglyphs)
2681 if (font->hint_composites)
2682 load_flags |= FT_LOAD_NO_SCALE;
2683 else
2684 load_flags |= FT_LOAD_NO_RECURSE;
2687 /* computing the segments is resolution independent, */
2688 /* thus the pixel size in this call is arbitrary -- */
2689 /* however, we avoid unnecessary debugging output */
2690 /* if we use the lowest value of the hinting range */
2691 error = FT_Set_Pixel_Sizes(face,
2692 font->hinting_range_min,
2693 font->hinting_range_min);
2694 if (error)
2695 return error;
2697 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2698 /* to modify `out' directions of points at the user's request */
2699 /* (which will eventually become single-point segments) */
2700 error = TA_control_segment_dir_collect(font, face->face_index, idx);
2701 if (error)
2702 return error;
2704 #ifdef TA_DEBUG
2705 /* temporarily disable some debugging output */
2706 /* to avoid getting the information twice */
2707 _ta_debug_save = _ta_debug;
2708 _ta_debug = 0;
2709 #endif
2711 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2712 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2714 #ifdef TA_DEBUG
2715 _ta_debug = _ta_debug_save;
2716 #endif
2718 if (error)
2719 return error;
2721 /* do nothing if we have an empty glyph */
2722 if (!(font->loader->gloader->current.num_subglyphs
2723 || face->glyph->outline.n_contours))
2724 return FT_Err_Ok;
2726 hints = &font->loader->hints;
2729 * We allocate a buffer which is certainly large enough
2730 * to hold all of the created bytecode instructions;
2731 * later on it gets reallocated to its real size.
2733 * The value `1000' is a very rough guess, not tested well.
2735 * For delta exceptions, we have three DELTA commands,
2736 * covering 3*16 ppem values.
2737 * Since a point index can be larger than 255,
2738 * we assume two bytes everywhere for the necessary PUSH calls.
2739 * This value must be doubled for the other arguments of DELTA.
2740 * Additionally, we have both x and y deltas,
2741 * which need to be handled separately in the bytecode.
2742 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2743 * adding some bytes for the necessary overhead.
2745 ins_len = (FT_UInt)(hints->num_points
2746 * (1000
2747 + ((font->control_data_head != NULL) ? 400 : 0)));
2748 ins_buf = (FT_Byte*)malloc(ins_len);
2749 if (!ins_buf)
2750 return FT_Err_Out_Of_Memory;
2752 /* handle composite glyph */
2753 if (font->loader->gloader->current.num_subglyphs)
2755 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2756 if (!bufp)
2758 error = FT_Err_Out_Of_Memory;
2759 goto Err;
2762 use_gstyle_data = 0;
2764 goto Done1;
2768 if (font->fallback_scaling)
2770 TA_StyleClass style_class = font->loader->metrics->style_class;
2773 if (style_class == &ta_none_dflt_style_class)
2775 /* the scaling value of `none_dflt' */
2776 /* (this is, hinting without script-specific blue zones) */
2777 /* is always 1, which corresponds to a no-op */
2778 bufp = ins_buf;
2780 use_gstyle_data = 0;
2782 goto Done1;
2784 else if (style_class == ta_style_classes[font->fallback_style])
2786 /* since `TA_init_recorder' hasn't been called yet, */
2787 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2788 recorder.sfnt = sfnt;
2789 recorder.font = font;
2790 recorder.glyph = glyph;
2792 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2793 if (!bufp)
2795 error = FT_Err_Out_Of_Memory;
2796 goto Err;
2799 use_gstyle_data = 0;
2801 goto Done1;
2805 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2806 if (error)
2807 goto Err;
2809 /* loop over a large range of pixel sizes */
2810 /* to find hints records which get pushed onto the bytecode stack */
2812 #ifdef DEBUGGING
2813 if (font->debug)
2815 int num_chars, i;
2816 char buf[256];
2819 (void)FT_Get_Glyph_Name(face, (FT_UInt)idx, buf, 256);
2821 num_chars = fprintf(stderr, "glyph %ld", idx);
2822 if (*buf)
2823 num_chars += fprintf(stderr, " (%s)", buf);
2824 fprintf(stderr, "\n");
2825 for (i = 0; i < num_chars; i++)
2826 putc('=', stderr);
2827 fprintf(stderr, "\n\n");
2830 #endif
2832 /* we temporarily use `ins_buf' to record the current glyph hints */
2833 ta_loader_register_hints_recorder(font->loader,
2834 TA_hints_recorder,
2835 (void*)&recorder);
2838 * It is important that we start the loop with the smallest PPEM value
2839 * used for hinting, since the number of segments that form an edge can
2840 * become smaller for larger PPEM values. For efficiency, we skip
2841 * non-edge one-point segments, and `TA_get_segment_index' would return
2842 * wrong indices otherwise.
2844 for (size = font->hinting_range_min;
2845 size <= font->hinting_range_max;
2846 size++)
2848 #ifdef DEBUGGING
2849 int have_dumps = 0;
2850 #endif
2853 TA_rewind_recorder(&recorder, ins_buf, size);
2855 error = FT_Set_Pixel_Sizes(face, size, size);
2856 if (error)
2857 goto Err;
2859 #ifdef DEBUGGING
2860 if (font->debug)
2862 int num_chars, i;
2865 num_chars = fprintf(stderr, "size %d\n", size);
2866 for (i = 0; i < num_chars - 1; i++)
2867 putc('-', stderr);
2868 fprintf(stderr, "\n\n");
2870 #endif
2872 /* calling `ta_loader_load_glyph' uses the */
2873 /* `TA_hints_recorder' function as a callback, */
2874 /* modifying `hints_record' */
2875 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2876 if (error)
2877 goto Err;
2879 if (TA_hints_record_is_different(action_hints_records,
2880 num_action_hints_records,
2881 ins_buf, recorder.hints_record.buf))
2883 #ifdef DEBUGGING
2884 if (font->debug)
2886 have_dumps = 1;
2888 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2889 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2890 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2892 fprintf(stderr, "action hints record:\n");
2893 if (ins_buf == recorder.hints_record.buf)
2894 fprintf(stderr, " (none)");
2895 else
2897 fprintf(stderr, " ");
2898 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2899 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2901 fprintf(stderr, "\n");
2903 #endif
2905 error = TA_add_hints_record(&action_hints_records,
2906 &num_action_hints_records,
2907 ins_buf, recorder.hints_record);
2908 if (error)
2909 goto Err;
2912 /* now handle point records */
2914 TA_reset_recorder(&recorder, ins_buf);
2916 /* use the point hints data collected in `TA_hints_recorder' */
2917 TA_build_point_hints(&recorder, hints);
2919 if (TA_hints_record_is_different(point_hints_records,
2920 num_point_hints_records,
2921 ins_buf, recorder.hints_record.buf))
2923 #ifdef DEBUGGING
2924 if (font->debug)
2926 if (!have_dumps)
2928 int num_chars, i;
2931 num_chars = fprintf(stderr, "size %d\n", size);
2932 for (i = 0; i < num_chars - 1; i++)
2933 putc('-', stderr);
2934 fprintf(stderr, "\n\n");
2936 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2937 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2938 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2941 fprintf(stderr, "point hints record:\n");
2942 if (ins_buf == recorder.hints_record.buf)
2943 fprintf(stderr, " (none)");
2944 else
2946 fprintf(stderr, " ");
2947 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2948 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2950 fprintf(stderr, "\n\n");
2952 #endif
2954 error = TA_add_hints_record(&point_hints_records,
2955 &num_point_hints_records,
2956 ins_buf, recorder.hints_record);
2957 if (error)
2958 goto Err;
2962 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2964 /* since we only have a single empty record we just scale the glyph */
2965 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2966 if (!bufp)
2968 error = FT_Err_Out_Of_Memory;
2969 goto Err;
2972 use_gstyle_data = 0;
2974 goto Done;
2977 /* if there is only a single record, */
2978 /* we do a global optimization later on */
2979 if (num_action_hints_records > 1)
2980 optimize = 1;
2982 /* store the hints records and handle stack depth */
2983 pos[0] = ins_buf;
2984 bufp = TA_emit_hints_records(&recorder,
2985 point_hints_records,
2986 num_point_hints_records,
2987 ins_buf,
2988 optimize);
2990 num_stack_elements = recorder.num_stack_elements;
2991 recorder.num_stack_elements = 0;
2993 pos[1] = bufp;
2994 bufp = TA_emit_hints_records(&recorder,
2995 action_hints_records,
2996 num_action_hints_records,
2997 bufp,
2998 optimize);
3000 recorder.num_stack_elements += num_stack_elements;
3002 pos[2] = bufp;
3003 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
3004 if (!bufp)
3006 error = FT_Err_Out_Of_Memory;
3007 goto Err;
3010 if (num_action_hints_records == 1)
3011 bufp = TA_optimize_push(ins_buf, pos);
3013 Done:
3014 TA_free_hints_records(action_hints_records, num_action_hints_records);
3015 TA_free_hints_records(point_hints_records, num_point_hints_records);
3016 TA_free_recorder(&recorder);
3018 Done1:
3019 /* handle delta exceptions */
3020 if (font->control_data_head)
3022 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
3023 if (!bufp)
3025 error = FT_Err_Out_Of_Memory;
3026 goto Err;
3030 /* we need to insert a few extra bytecode instructions */
3031 /* for non-base glyphs */
3032 if (use_gstyle_data && (gstyles[idx] & TA_NONBASE))
3034 FT_Byte* ins_extra_buf_new;
3035 FT_Byte ins_extra_len_new;
3038 ins_extra_len_new = glyph->ins_extra_len
3039 + sizeof (ins_extra_ignore_std_width);
3040 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
3041 ins_extra_len_new);
3042 if (!ins_extra_buf_new)
3044 bufp = NULL;
3045 goto Done;
3048 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3049 /* by activating `ins_extra_ignore_std_width' */
3050 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
3051 ins_extra_ignore_std_width,
3052 sizeof (ins_extra_ignore_std_width));
3054 glyph->ins_extra_buf = ins_extra_buf_new;
3055 glyph->ins_extra_len = ins_extra_len_new;
3057 /* reset `cvtl_ignore_std_width' for next glyph */
3058 BCI(PUSHB_2);
3059 BCI(cvtl_ignore_std_width);
3060 BCI(0);
3061 BCI(WCVTP);
3064 ins_len = (FT_UInt)(bufp - ins_buf);
3066 if ((ins_len + glyph->ins_extra_len) > sfnt->max_instructions)
3067 sfnt->max_instructions = (FT_UShort)(ins_len + glyph->ins_extra_len);
3069 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
3070 glyph->ins_len = ins_len;
3072 return FT_Err_Ok;
3074 Err:
3075 TA_free_hints_records(action_hints_records, num_action_hints_records);
3076 TA_free_hints_records(point_hints_records, num_point_hints_records);
3077 TA_free_recorder(&recorder);
3078 free(ins_buf);
3080 return error;
3084 /* end of tabytecode.c */