Add wildcard (`*') as possible value for `script' in control instructions.
[ttfautohint.git] / lib / tabytecode.c
blobab04341e8134428cb0bab8444217f0390a7b32fb
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2017 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 = (unsigned int)font->loader->gloader->base.outline.n_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
905 || (!need_before_IUP_words && !need_before_IUP_word_counts))
907 FT_UInt num_args = 0;
910 for (i = 0; i < 6; i++)
912 FT_UInt* args_new;
913 FT_UInt num_args_new;
916 if (!num_delta_before_IUP_args[i])
917 continue;
919 num_args_new = num_args + num_delta_before_IUP_args[i];
920 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
921 if (!args_new)
923 bufp = NULL;
924 goto Done;
927 memcpy(args_new + num_args,
928 delta_before_IUP_args[i],
929 num_delta_before_IUP_args[i] * sizeof (FT_UInt));
931 args = args_new;
932 num_args = num_args_new;
935 num_before_IUP_stack_elements = (FT_UShort)num_args;
937 bufp = TA_build_push(bufp, args, num_args, need_before_IUP_words, 1);
939 else
941 num_before_IUP_stack_elements = 0;
943 /* stack elements are bytes, but counts need words */
944 for (i = 0; i < 6; i++)
946 FT_UInt num_delta_arg;
949 if (!num_delta_before_IUP_args[i])
950 continue;
952 num_delta_arg = num_delta_before_IUP_args[i] - 2;
954 bufp = TA_build_push(bufp,
955 delta_before_IUP_args[i],
956 num_delta_arg,
957 need_before_IUP_words,
960 num_before_IUP_stack_elements += num_delta_arg + 2;
962 num_delta_arg >>= 1;
963 BCI(PUSHW_1);
964 BCI(HIGH(num_delta_arg));
965 BCI(LOW(num_delta_arg));
967 /* the function number */
968 BCI(PUSHB_1);
969 BCI(delta_before_IUP_args[i][num_delta_before_IUP_args[i] - 1]);
973 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
974 if (num_delta_before_IUP_args[5])
975 BCI(LOOPCALL);
976 if (num_delta_before_IUP_args[4])
977 BCI(LOOPCALL);
978 if (num_delta_before_IUP_args[3])
979 BCI(LOOPCALL);
981 if (num_delta_before_IUP_args[2]
982 || num_delta_before_IUP_args[1]
983 || num_delta_before_IUP_args[0])
984 BCI(SVTCA_x);
986 /* emit x DELTA opcodes */
987 if (num_delta_before_IUP_args[2])
988 BCI(LOOPCALL);
989 if (num_delta_before_IUP_args[1])
990 BCI(LOOPCALL);
991 if (num_delta_before_IUP_args[0])
992 BCI(LOOPCALL);
994 if (num_delta_before_IUP_args[2]
995 || num_delta_before_IUP_args[1]
996 || num_delta_before_IUP_args[0])
997 BCI(SVTCA_y);
999 if (num_delta_before_IUP_args[5]
1000 || num_delta_before_IUP_args[4]
1001 || num_delta_before_IUP_args[3])
1002 BCI(IUP_y);
1004 /* merge `after IUP' delta stacks into a single one */
1005 if (need_after_IUP_words
1006 || (!need_after_IUP_words && !need_after_IUP_word_counts))
1008 FT_UInt num_args = 0;
1011 for (i = 0; i < 6; i++)
1013 FT_UInt* args_new;
1014 FT_UInt num_args_new;
1017 if (!num_delta_after_IUP_args[i])
1018 continue;
1020 num_args_new = num_args + num_delta_after_IUP_args[i];
1021 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
1022 if (!args_new)
1024 bufp = NULL;
1025 goto Done;
1028 memcpy(args_new + num_args,
1029 delta_after_IUP_args[i],
1030 num_delta_after_IUP_args[i] * sizeof (FT_UInt));
1032 args = args_new;
1033 num_args = num_args_new;
1036 num_after_IUP_stack_elements = (FT_UShort)num_args;
1038 bufp = TA_build_push(bufp, args, num_args, need_after_IUP_words, 1);
1040 else
1042 num_after_IUP_stack_elements = 0;
1044 /* stack elements are bytes, but counts need words */
1045 for (i = 0; i < 6; i++)
1047 FT_UInt num_delta_arg;
1050 if (!num_delta_after_IUP_args[i])
1051 continue;
1053 num_delta_arg = num_delta_after_IUP_args[i] - 1;
1055 bufp = TA_build_push(bufp,
1056 delta_after_IUP_args[i],
1057 num_delta_arg,
1058 need_after_IUP_words,
1061 num_after_IUP_stack_elements += num_delta_arg + 1;
1063 num_delta_arg >>= 1;
1064 BCI(PUSHW_1);
1065 BCI(HIGH(num_delta_arg));
1066 BCI(LOW(num_delta_arg));
1070 /* emit y DELTA opcodes */
1071 if (num_delta_after_IUP_args[5])
1072 BCI(DELTAP3);
1073 if (num_delta_after_IUP_args[4])
1074 BCI(DELTAP2);
1075 if (num_delta_after_IUP_args[3])
1076 BCI(DELTAP1);
1078 if (num_delta_after_IUP_args[2]
1079 || num_delta_after_IUP_args[1]
1080 || num_delta_after_IUP_args[0])
1081 BCI(SVTCA_x);
1083 /* emit x DELTA opcodes */
1084 if (num_delta_after_IUP_args[2])
1085 BCI(DELTAP3);
1086 if (num_delta_after_IUP_args[1])
1087 BCI(DELTAP2);
1088 if (num_delta_after_IUP_args[0])
1089 BCI(DELTAP1);
1091 /* we need to insert a few extra bytecode instructions */
1092 /* if we have y delta exceptions before IUP */
1093 if (num_delta_before_IUP_args[5]
1094 || num_delta_before_IUP_args[4]
1095 || num_delta_before_IUP_args[3])
1097 FT_Byte* ins_extra_buf_new;
1098 FT_Byte ins_extra_len_new;
1101 ins_extra_len_new = glyph->ins_extra_len
1102 + sizeof (ins_extra_delta_exceptions);
1103 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
1104 ins_extra_len_new);
1105 if (!ins_extra_buf_new)
1107 bufp = NULL;
1108 goto Done;
1111 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1112 /* by activating `ins_extra_delta_exceptions' */
1113 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
1114 ins_extra_delta_exceptions,
1115 sizeof (ins_extra_delta_exceptions));
1117 glyph->ins_extra_buf = ins_extra_buf_new;
1118 glyph->ins_extra_len = ins_extra_len_new;
1120 /* reset `cvtl_do_iup_y' for next glyph */
1121 BCI(PUSHB_2);
1122 BCI(cvtl_do_iup_y);
1123 BCI(100);
1124 BCI(WCVTP);
1127 Done:
1128 for (i = 0; i < 6; i++)
1130 free(delta_before_IUP_args[i]);
1131 free(delta_after_IUP_args[i]);
1133 free(args);
1135 if (num_before_IUP_stack_elements > sfnt->max_stack_elements)
1136 sfnt->max_stack_elements = num_before_IUP_stack_elements;
1137 if (num_after_IUP_stack_elements > sfnt->max_stack_elements)
1138 sfnt->max_stack_elements = num_after_IUP_stack_elements;
1140 return bufp;
1144 static FT_Byte*
1145 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
1146 Recorder* recorder,
1147 FT_Byte* bufp)
1149 FONT* font = recorder->font;
1150 FT_GlyphSlot glyph = sfnt->face->glyph;
1151 FT_Vector* points = glyph->outline.points;
1152 FT_UInt num_contours = (FT_UInt)glyph->outline.n_contours;
1154 FT_UInt* args;
1155 FT_UInt* arg;
1156 FT_UInt num_args;
1158 FT_Bool need_words = 0;
1159 FT_UInt p, q;
1160 FT_UInt start, end;
1161 FT_UShort num_storage;
1162 FT_UShort num_stack_elements;
1165 num_args = 2 * num_contours + 2;
1167 /* collect all arguments temporarily in an array (in reverse order) */
1168 /* so that we can easily split into chunks of 255 args */
1169 /* as needed by NPUSHB and NPUSHW, respectively */
1170 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1171 if (!args)
1172 return NULL;
1174 arg = args + num_args - 1;
1176 if (num_args > 0xFF)
1177 need_words = 1;
1179 if (recorder->glyph->num_components && font->hint_composites)
1180 *(arg--) = bci_scale_composite_glyph;
1181 else
1182 *(arg--) = bci_scale_glyph;
1183 *(arg--) = num_contours;
1185 start = 0;
1186 end = 0;
1188 for (p = 0; p < num_contours; p++)
1190 FT_UInt max = start;
1191 FT_UInt min = start;
1194 end = (FT_UInt)glyph->outline.contours[p];
1196 for (q = start; q <= end; q++)
1198 if (points[q].y < points[min].y)
1199 min = q;
1200 if (points[q].y > points[max].y)
1201 max = q;
1204 if (min > max)
1206 *(arg--) = TA_adjust_point_index(recorder, max);
1207 *(arg--) = TA_adjust_point_index(recorder, min);
1209 else
1211 *(arg--) = TA_adjust_point_index(recorder, min);
1212 *(arg--) = TA_adjust_point_index(recorder, max);
1215 start = end + 1;
1218 if (end > 0xFF)
1219 need_words = 1;
1221 /* with most fonts it is very rare */
1222 /* that any of the pushed arguments is larger than 0xFF, */
1223 /* thus we refrain from further optimizing this case */
1224 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
1226 BCI(CALL);
1228 num_storage = sal_segment_offset;
1229 if (num_storage > sfnt->max_storage)
1230 sfnt->max_storage = num_storage;
1232 num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS + num_args);
1233 if (num_stack_elements > sfnt->max_stack_elements)
1234 sfnt->max_stack_elements = num_stack_elements;
1236 free(args);
1238 return bufp;
1242 static FT_Byte*
1243 TA_font_build_subglyph_shifter(FONT* font,
1244 FT_Byte* bufp)
1246 FT_Face face = font->loader->face;
1247 FT_GlyphSlot glyph = face->glyph;
1249 TA_GlyphLoader gloader = font->loader->gloader;
1251 TA_SubGlyph subglyphs = gloader->current.subglyphs;
1252 TA_SubGlyph subglyph_limit = subglyphs + gloader->current.num_subglyphs;
1253 TA_SubGlyph subglyph;
1255 FT_Int curr_contour = 0;
1258 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
1260 FT_Error error;
1262 FT_UShort flags = subglyph->flags;
1263 FT_Pos y_offset = subglyph->arg2;
1265 FT_Int num_contours;
1268 /* load subglyph to get the number of contours */
1269 error = FT_Load_Glyph(face, (FT_UInt)subglyph->index, FT_LOAD_NO_SCALE);
1270 if (error)
1271 return NULL;
1272 num_contours = glyph->outline.n_contours;
1274 /* nothing to do if there is a point-to-point alignment */
1275 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1276 goto End;
1278 /* nothing to do if y offset is zero */
1279 if (!y_offset)
1280 goto End;
1282 /* nothing to do if there are no contours */
1283 if (!num_contours)
1284 goto End;
1286 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1287 /* ensures that composite subglyphs are represented as simple glyphs */
1289 if (num_contours > 0xFF
1290 || curr_contour > 0xFF)
1292 BCI(PUSHW_2);
1293 BCI(HIGH(curr_contour));
1294 BCI(LOW(curr_contour));
1295 BCI(HIGH(num_contours));
1296 BCI(LOW(num_contours));
1298 else
1300 BCI(PUSHB_2);
1301 BCI(curr_contour);
1302 BCI(num_contours);
1305 /* there are high chances that this value needs PUSHW, */
1306 /* thus we handle it separately */
1307 if (y_offset > 0xFF || y_offset < 0)
1309 BCI(PUSHW_1);
1310 BCI(HIGH(y_offset));
1311 BCI(LOW(y_offset));
1313 else
1315 BCI(PUSHB_1);
1316 BCI(y_offset);
1319 BCI(PUSHB_1);
1320 BCI(bci_shift_subglyph);
1321 BCI(CALL);
1323 End:
1324 curr_contour += num_contours;
1327 return bufp;
1332 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1333 * data in four arrays (which are simple but waste a lot of memory). The
1334 * function below converts them into bytecode.
1336 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1337 * together with the edge they correspond to.
1339 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1340 * loop over the edge or edge pairs, respectively, and each edge or edge
1341 * pair contains an inner loop to emit the correponding points.
1344 static void
1345 TA_build_point_hints(Recorder* recorder,
1346 TA_GlyphHints hints)
1348 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1349 TA_Edge edges = axis->edges;
1351 FT_Byte* p = recorder->hints_record.buf;
1353 FT_UShort i;
1354 FT_UShort j;
1356 FT_UShort prev_edge;
1357 FT_UShort prev_before_edge;
1358 FT_UShort prev_after_edge;
1360 Node1* before_node;
1361 Node1* after_node;
1362 Node2* on_node;
1363 Node3* between_node;
1366 /* we store everything as 16bit numbers; */
1367 /* the function numbers (`ta_ip_before', etc.) */
1368 /* reflect the order in the TA_Action enumeration */
1370 /* ip_before_points */
1372 i = 0;
1373 for (before_node = LLRB_MIN(ip_before_points,
1374 &recorder->ip_before_points_head);
1375 before_node;
1376 before_node = LLRB_NEXT(ip_before_points,
1377 &recorder->ip_before_points_head,
1378 before_node))
1380 /* count points */
1381 i++;
1384 if (i)
1386 TA_Edge edge;
1387 FT_UShort edge_first_idx;
1390 recorder->hints_record.num_actions++;
1392 edge = edges;
1393 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1395 *(p++) = 0;
1396 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1397 *(p++) = HIGH(edge_first_idx);
1398 *(p++) = LOW(edge_first_idx);
1399 *(p++) = HIGH(i);
1400 *(p++) = LOW(i);
1402 for (before_node = LLRB_MIN(ip_before_points,
1403 &recorder->ip_before_points_head);
1404 before_node;
1405 before_node = LLRB_NEXT(ip_before_points,
1406 &recorder->ip_before_points_head,
1407 before_node))
1409 FT_UInt point;
1412 point = TA_adjust_point_index(recorder, before_node->point);
1413 *(p++) = HIGH(point);
1414 *(p++) = LOW(point);
1418 /* ip_after_points */
1420 i = 0;
1421 for (after_node = LLRB_MIN(ip_after_points,
1422 &recorder->ip_after_points_head);
1423 after_node;
1424 after_node = LLRB_NEXT(ip_after_points,
1425 &recorder->ip_after_points_head,
1426 after_node))
1428 /* count points */
1429 i++;
1432 if (i)
1434 TA_Edge edge;
1435 FT_UShort edge_first_idx;
1438 recorder->hints_record.num_actions++;
1440 edge = edges + axis->num_edges - 1;
1441 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1443 *(p++) = 0;
1444 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1445 *(p++) = HIGH(edge_first_idx);
1446 *(p++) = LOW(edge_first_idx);
1447 *(p++) = HIGH(i);
1448 *(p++) = LOW(i);
1450 for (after_node = LLRB_MIN(ip_after_points,
1451 &recorder->ip_after_points_head);
1452 after_node;
1453 after_node = LLRB_NEXT(ip_after_points,
1454 &recorder->ip_after_points_head,
1455 after_node))
1457 FT_UInt point;
1460 point = TA_adjust_point_index(recorder, after_node->point);
1461 *(p++) = HIGH(point);
1462 *(p++) = LOW(point);
1466 /* ip_on_point_array */
1468 prev_edge = 0xFFFF;
1469 i = 0;
1470 for (on_node = LLRB_MIN(ip_on_points,
1471 &recorder->ip_on_points_head);
1472 on_node;
1473 on_node = LLRB_NEXT(ip_on_points,
1474 &recorder->ip_on_points_head,
1475 on_node))
1477 /* count edges */
1478 if (on_node->edge != prev_edge)
1480 i++;
1481 prev_edge = on_node->edge;
1485 if (i)
1487 recorder->hints_record.num_actions++;
1489 *(p++) = 0;
1490 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1491 *(p++) = HIGH(i);
1492 *(p++) = LOW(i);
1494 for (on_node = LLRB_MIN(ip_on_points,
1495 &recorder->ip_on_points_head);
1496 on_node;
1497 on_node = LLRB_NEXT(ip_on_points,
1498 &recorder->ip_on_points_head,
1499 on_node))
1501 Node2* edge_node;
1502 TA_Edge edge;
1503 FT_UShort edge_first_idx;
1506 edge = edges + on_node->edge;
1507 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1509 *(p++) = HIGH(edge_first_idx);
1510 *(p++) = LOW(edge_first_idx);
1512 /* save current position */
1513 edge_node = on_node;
1514 j = 0;
1515 for (;
1516 on_node;
1517 on_node = LLRB_NEXT(ip_on_points,
1518 &recorder->ip_on_points_head,
1519 on_node))
1521 /* count points on current edge */
1522 if (on_node->edge != edge_node->edge)
1523 break;
1524 j++;
1527 *(p++) = HIGH(j);
1528 *(p++) = LOW(j);
1530 /* restore current position */
1531 on_node = edge_node;
1532 for (;
1533 on_node;
1534 on_node = LLRB_NEXT(ip_on_points,
1535 &recorder->ip_on_points_head,
1536 on_node))
1538 FT_UInt point;
1541 if (on_node->edge != edge_node->edge)
1542 break;
1544 point = TA_adjust_point_index(recorder, on_node->point);
1545 *(p++) = HIGH(point);
1546 *(p++) = LOW(point);
1548 /* keep track of previous node */
1549 edge_node = on_node;
1552 /* reset loop iterator by one element, then continue */
1553 on_node = edge_node;
1557 /* ip_between_point_array */
1559 prev_before_edge = 0xFFFF;
1560 prev_after_edge = 0xFFFF;
1561 i = 0;
1562 for (between_node = LLRB_MIN(ip_between_points,
1563 &recorder->ip_between_points_head);
1564 between_node;
1565 between_node = LLRB_NEXT(ip_between_points,
1566 &recorder->ip_between_points_head,
1567 between_node))
1569 /* count `(before,after)' edge pairs */
1570 if (between_node->before_edge != prev_before_edge
1571 || between_node->after_edge != prev_after_edge)
1573 i++;
1574 prev_before_edge = between_node->before_edge;
1575 prev_after_edge = between_node->after_edge;
1579 if (i)
1581 recorder->hints_record.num_actions++;
1583 *(p++) = 0;
1584 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1585 *(p++) = HIGH(i);
1586 *(p++) = LOW(i);
1588 for (between_node = LLRB_MIN(ip_between_points,
1589 &recorder->ip_between_points_head);
1590 between_node;
1591 between_node = LLRB_NEXT(ip_between_points,
1592 &recorder->ip_between_points_head,
1593 between_node))
1595 Node3* edge_pair_node;
1596 TA_Edge before;
1597 TA_Edge after;
1598 FT_UShort before_first_idx;
1599 FT_UShort after_first_idx;
1602 before = edges + between_node->before_edge;
1603 after = edges + between_node->after_edge;
1604 before_first_idx = TA_get_segment_index(before->first, recorder);
1605 after_first_idx = TA_get_segment_index(after->first, recorder);
1607 *(p++) = HIGH(after_first_idx);
1608 *(p++) = LOW(after_first_idx);
1609 *(p++) = HIGH(before_first_idx);
1610 *(p++) = LOW(before_first_idx);
1612 /* save current position */
1613 edge_pair_node = between_node;
1614 j = 0;
1615 for (;
1616 between_node;
1617 between_node = LLRB_NEXT(ip_between_points,
1618 &recorder->ip_between_points_head,
1619 between_node))
1621 /* count points associated with current edge pair */
1622 if (between_node->before_edge != edge_pair_node->before_edge
1623 || between_node->after_edge != edge_pair_node->after_edge)
1624 break;
1625 j++;
1628 *(p++) = HIGH(j);
1629 *(p++) = LOW(j);
1631 /* restore current position */
1632 between_node = edge_pair_node;
1633 for (;
1634 between_node;
1635 between_node = LLRB_NEXT(ip_between_points,
1636 &recorder->ip_between_points_head,
1637 between_node))
1639 FT_UInt point;
1642 if (between_node->before_edge != edge_pair_node->before_edge
1643 || between_node->after_edge != edge_pair_node->after_edge)
1644 break;
1646 point = TA_adjust_point_index(recorder, between_node->point);
1647 *(p++) = HIGH(point);
1648 *(p++) = LOW(point);
1650 /* keep track of previous node */
1651 edge_pair_node = between_node;
1654 /* reset loop iterator by one element, then continue */
1655 between_node = edge_pair_node;
1659 recorder->hints_record.buf = p;
1663 static FT_Bool
1664 TA_hints_record_is_different(Hints_Record* hints_records,
1665 FT_UInt num_hints_records,
1666 FT_Byte* start,
1667 FT_Byte* end)
1669 Hints_Record last_hints_record;
1672 if (!hints_records)
1673 return 1;
1675 /* we only need to compare with the last hints record */
1676 last_hints_record = hints_records[num_hints_records - 1];
1678 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1679 return 1;
1681 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1682 return 1;
1684 return 0;
1688 static FT_Error
1689 TA_add_hints_record(Hints_Record** hints_records,
1690 FT_UInt* num_hints_records,
1691 FT_Byte* start,
1692 Hints_Record hints_record)
1694 Hints_Record* hints_records_new;
1695 FT_UInt buf_len;
1696 /* at this point, `hints_record.buf' still points into `ins_buf' */
1697 FT_Byte* end = hints_record.buf;
1700 buf_len = (FT_UInt)(end - start);
1702 /* now fill the structure completely */
1703 hints_record.buf_len = buf_len;
1704 hints_record.buf = (FT_Byte*)malloc(buf_len);
1705 if (!hints_record.buf)
1706 return FT_Err_Out_Of_Memory;
1708 memcpy(hints_record.buf, start, buf_len);
1710 (*num_hints_records)++;
1711 hints_records_new =
1712 (Hints_Record*)realloc(*hints_records, *num_hints_records
1713 * sizeof (Hints_Record));
1714 if (!hints_records_new)
1716 free(hints_record.buf);
1717 (*num_hints_records)--;
1718 return FT_Err_Out_Of_Memory;
1720 else
1721 *hints_records = hints_records_new;
1723 (*hints_records)[*num_hints_records - 1] = hints_record;
1725 return FT_Err_Ok;
1729 static FT_Byte*
1730 TA_emit_hints_record(Recorder* recorder,
1731 Hints_Record* hints_record,
1732 FT_Byte* bufp,
1733 FT_Bool optimize)
1735 FT_Byte* p;
1736 FT_Byte* endp;
1737 FT_Bool need_words = 0;
1739 FT_UInt i, j;
1740 FT_UInt num_arguments;
1741 FT_UInt num_args;
1744 /* check whether any argument is larger than 0xFF */
1745 endp = hints_record->buf + hints_record->buf_len;
1746 for (p = hints_record->buf; p < endp; p += 2)
1747 if (*p)
1749 need_words = 1;
1750 break;
1753 /* with most fonts it is very rare */
1754 /* that any of the pushed arguments is larger than 0xFF, */
1755 /* thus we refrain from further optimizing this case */
1757 num_arguments = hints_record->buf_len / 2;
1758 p = endp - 2;
1760 if (need_words)
1762 for (i = 0; i < num_arguments; i += 255)
1764 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1766 if (optimize && num_args <= 8)
1767 BCI(PUSHW_1 - 1 + num_args);
1768 else
1770 BCI(NPUSHW);
1771 BCI(num_args);
1773 for (j = 0; j < num_args; j++)
1775 BCI(*p);
1776 BCI(*(p + 1));
1777 p -= 2;
1781 else
1783 /* we only need the lower bytes */
1784 p++;
1786 for (i = 0; i < num_arguments; i += 255)
1788 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1790 if (optimize && num_args <= 8)
1791 BCI(PUSHB_1 - 1 + num_args);
1792 else
1794 BCI(NPUSHB);
1795 BCI(num_args);
1797 for (j = 0; j < num_args; j++)
1799 BCI(*p);
1800 p -= 2;
1805 /* collect stack depth data */
1806 if (num_arguments > recorder->num_stack_elements)
1807 recorder->num_stack_elements = (FT_UShort)num_arguments;
1809 return bufp;
1813 static FT_Byte*
1814 TA_emit_hints_records(Recorder* recorder,
1815 Hints_Record* hints_records,
1816 FT_UInt num_hints_records,
1817 FT_Byte* bufp,
1818 FT_Bool optimize)
1820 FT_UInt i;
1821 Hints_Record* hints_record;
1824 hints_record = hints_records;
1826 /* emit hints records in `if' clauses, */
1827 /* with the ppem size as the condition */
1828 for (i = 0; i < num_hints_records - 1; i++)
1830 BCI(MPPEM);
1831 if (hints_record->size > 0xFF)
1833 BCI(PUSHW_1);
1834 BCI(HIGH((hints_record + 1)->size));
1835 BCI(LOW((hints_record + 1)->size));
1837 else
1839 BCI(PUSHB_1);
1840 BCI((hints_record + 1)->size);
1842 BCI(LT);
1843 BCI(IF);
1844 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1845 BCI(ELSE);
1847 hints_record++;
1850 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1852 for (i = 0; i < num_hints_records - 1; i++)
1853 BCI(EIF);
1855 return bufp;
1859 static void
1860 TA_free_hints_records(Hints_Record* hints_records,
1861 FT_UInt num_hints_records)
1863 FT_UInt i;
1866 for (i = 0; i < num_hints_records; i++)
1867 free(hints_records[i].buf);
1869 free(hints_records);
1873 static FT_Byte*
1874 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1875 Recorder* recorder,
1876 TA_Edge edge,
1877 FT_UShort* wraps)
1879 TA_Segment seg;
1880 FT_UShort seg_idx;
1881 FT_UShort num_segs = 0;
1882 FT_UShort* wrap;
1883 FT_UShort num_segments;
1886 seg_idx = TA_get_segment_index(edge->first, recorder);
1887 num_segments = TA_get_segment_index(NULL, recorder);
1889 /* we store everything as 16bit numbers */
1890 *(bufp++) = HIGH(seg_idx);
1891 *(bufp++) = LOW(seg_idx);
1893 /* wrap-around segments are stored as two segments */
1894 if (edge->first->first > edge->first->last)
1895 num_segs++;
1897 seg = edge->first->edge_next;
1898 while (seg != edge->first)
1900 num_segs++;
1902 if (seg->first > seg->last)
1903 num_segs++;
1905 seg = seg->edge_next;
1908 *(bufp++) = HIGH(num_segs);
1909 *(bufp++) = LOW(num_segs);
1911 if (edge->first->first > edge->first->last)
1913 /* emit second part of wrap-around segment; */
1914 /* the bytecode positions such segments after `normal' ones */
1915 wrap = wraps;
1916 for (;;)
1918 if (seg_idx == *wrap)
1919 break;
1920 wrap++;
1923 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1924 *(bufp++) = LOW(num_segments + (wrap - wraps));
1927 seg = edge->first->edge_next;
1928 while (seg != edge->first)
1930 seg_idx = TA_get_segment_index(seg, recorder);
1932 *(bufp++) = HIGH(seg_idx);
1933 *(bufp++) = LOW(seg_idx);
1935 if (seg->first > seg->last)
1937 wrap = wraps;
1938 for (;;)
1940 if (seg_idx == *wrap)
1941 break;
1942 wrap++;
1945 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1946 *(bufp++) = LOW(num_segments + (wrap - wraps));
1949 seg = seg->edge_next;
1952 return bufp;
1956 static void
1957 TA_hints_recorder(TA_Action action,
1958 TA_GlyphHints hints,
1959 TA_Dimension dim,
1960 void* arg1,
1961 TA_Edge arg2,
1962 TA_Edge arg3,
1963 TA_Edge lower_bound,
1964 TA_Edge upper_bound)
1966 TA_AxisHints axis = &hints->axis[dim];
1967 TA_Edge edges = axis->edges;
1968 TA_Point points = hints->points;
1970 TA_Segment segments = axis->segments;
1971 TA_Segment seg_limit = segments + axis->num_segments;
1972 TA_Segment seg;
1974 Recorder* recorder = (Recorder*)hints->user;
1975 SFNT* sfnt = recorder->sfnt;
1976 FONT* font = recorder->font;
1977 FT_UShort* wraps = recorder->wrap_around_segments;
1978 FT_Byte* p = recorder->hints_record.buf;
1980 TA_StyleClass style_class = font->loader->metrics->style_class;
1981 TA_ScriptClass script_class = ta_script_classes[style_class->script];
1983 FT_UInt style = style_class->style;
1984 FT_Bool top_to_bottom_hinting = script_class->top_to_bottom_hinting;
1987 if (dim == TA_DIMENSION_HORZ)
1988 return;
1990 if (!recorder->segment_map_initialized)
1992 FT_UShort* segment_map = recorder->segment_map;
1993 FT_UShort idx;
1996 idx = 0;
1997 for (seg = segments; seg < seg_limit; seg++)
1999 if (seg->edge)
2000 *segment_map = idx++;
2001 else
2002 *segment_map = 0xFFFF;
2004 segment_map++;
2006 *segment_map = idx;
2008 recorder->segment_map_initialized = 1;
2011 if (!recorder->wrap_around_segments_initialized)
2013 FT_UShort* wrap_around_segment;
2016 wrap_around_segment = recorder->wrap_around_segments;
2017 for (seg = segments; seg < seg_limit; seg++)
2018 if (seg->first > seg->last)
2019 *(wrap_around_segment++) = TA_get_segment_index(seg, recorder);
2021 recorder->wrap_around_segments_initialized = 1;
2024 /* we collect point hints for later processing */
2025 switch (action)
2027 case ta_ip_before:
2029 Node1* before_node;
2030 TA_Point point = (TA_Point)arg1;
2033 before_node = (Node1*)malloc(sizeof (Node1));
2034 if (!before_node)
2035 return;
2036 before_node->point = (FT_UShort)(point - points);
2038 LLRB_INSERT(ip_before_points,
2039 &recorder->ip_before_points_head,
2040 before_node);
2042 return;
2044 case ta_ip_after:
2046 Node1* after_node;
2047 TA_Point point = (TA_Point)arg1;
2050 after_node = (Node1*)malloc(sizeof (Node1));
2051 if (!after_node)
2052 return;
2053 after_node->point = (FT_UShort)(point - points);
2055 LLRB_INSERT(ip_after_points,
2056 &recorder->ip_after_points_head,
2057 after_node);
2059 return;
2061 case ta_ip_on:
2063 Node2* on_node;
2064 TA_Point point = (TA_Point)arg1;
2065 TA_Edge edge = arg2;
2068 on_node = (Node2*)malloc(sizeof (Node2));
2069 if (!on_node)
2070 return;
2071 on_node->edge = (FT_UShort)(edge - edges);
2072 on_node->point = (FT_UShort)(point - points);
2074 LLRB_INSERT(ip_on_points,
2075 &recorder->ip_on_points_head,
2076 on_node);
2078 return;
2080 case ta_ip_between:
2082 Node3* between_node;
2083 TA_Point point = (TA_Point)arg1;
2084 TA_Edge before = arg2;
2085 TA_Edge after = arg3;
2088 between_node = (Node3*)malloc(sizeof (Node3));
2089 if (!between_node)
2090 return;
2091 between_node->before_edge = (FT_UShort)(before - edges);
2092 between_node->after_edge = (FT_UShort)(after - edges);
2093 between_node->point = (FT_UShort)(point - points);
2095 LLRB_INSERT(ip_between_points,
2096 &recorder->ip_between_points_head,
2097 between_node);
2099 return;
2101 case ta_bound:
2102 /* we ignore the BOUND action since we signal this information */
2103 /* with the proper function number */
2104 return;
2106 default:
2107 break;
2110 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2111 /* if the value is n, the function numbers are n, ..., n+11, */
2112 /* to be differentiated with flags */
2114 switch (action)
2116 case ta_link:
2118 TA_Edge base_edge = (TA_Edge)arg1;
2119 TA_Edge stem_edge = arg2;
2120 FT_UShort base_first_idx;
2121 FT_UShort stem_first_idx;
2124 base_first_idx = TA_get_segment_index(base_edge->first, recorder);
2125 stem_first_idx = TA_get_segment_index(stem_edge->first, recorder);
2127 *(p++) = 0;
2128 *(p++) = (FT_Byte)action + ACTION_OFFSET
2129 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
2130 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
2132 *(p++) = HIGH(base_first_idx);
2133 *(p++) = LOW(base_first_idx);
2134 *(p++) = HIGH(stem_first_idx);
2135 *(p++) = LOW(stem_first_idx);
2137 p = TA_hints_recorder_handle_segments(p, recorder, stem_edge, wraps);
2139 break;
2141 case ta_anchor:
2143 TA_Edge edge = (TA_Edge)arg1;
2144 TA_Edge edge2 = arg2;
2145 FT_UShort edge_first_idx;
2146 FT_UShort edge2_first_idx;
2149 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2150 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2152 *(p++) = 0;
2153 *(p++) = (FT_Byte)action + ACTION_OFFSET
2154 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2155 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
2157 *(p++) = HIGH(edge_first_idx);
2158 *(p++) = LOW(edge_first_idx);
2159 *(p++) = HIGH(edge2_first_idx);
2160 *(p++) = LOW(edge2_first_idx);
2162 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2164 break;
2166 case ta_adjust:
2168 TA_Edge edge = (TA_Edge)arg1;
2169 TA_Edge edge2 = arg2;
2170 TA_Edge edge_minus_one = lower_bound;
2171 FT_UShort edge_first_idx;
2172 FT_UShort edge2_first_idx;
2175 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2176 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2178 *(p++) = 0;
2179 *(p++) = (FT_Byte)action + ACTION_OFFSET
2180 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2181 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2182 + 4 * (edge_minus_one != NULL) /* `bound' */
2183 + 4 * (edge_minus_one != NULL
2184 && top_to_bottom_hinting); /* `down' */
2186 *(p++) = HIGH(edge_first_idx);
2187 *(p++) = LOW(edge_first_idx);
2188 *(p++) = HIGH(edge2_first_idx);
2189 *(p++) = LOW(edge2_first_idx);
2191 if (edge_minus_one)
2193 FT_UShort edge_minus_one_first_idx;
2196 edge_minus_one_first_idx = TA_get_segment_index(
2197 edge_minus_one->first, recorder);
2199 *(p++) = HIGH(edge_minus_one_first_idx);
2200 *(p++) = LOW(edge_minus_one_first_idx);
2203 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2205 break;
2207 case ta_blue_anchor:
2209 TA_Edge edge = (TA_Edge)arg1;
2210 TA_Edge blue = arg2;
2211 FT_UShort blue_first_idx;
2212 FT_UShort edge_first_idx;
2215 blue_first_idx = TA_get_segment_index(blue->first, recorder);
2216 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2218 *(p++) = 0;
2219 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2221 *(p++) = HIGH(blue_first_idx);
2222 *(p++) = LOW(blue_first_idx);
2224 if (edge->best_blue_is_shoot)
2226 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2227 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2229 else
2231 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2232 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2235 *(p++) = HIGH(edge_first_idx);
2236 *(p++) = LOW(edge_first_idx);
2238 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2240 break;
2242 case ta_stem:
2244 TA_Edge edge = (TA_Edge)arg1;
2245 TA_Edge edge2 = arg2;
2246 TA_Edge edge_minus_one = lower_bound;
2247 FT_UShort edge_first_idx;
2248 FT_UShort edge2_first_idx;
2251 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2252 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2254 *(p++) = 0;
2255 *(p++) = (FT_Byte)action + ACTION_OFFSET
2256 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2257 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2258 + 4 * (edge_minus_one != NULL) /* `bound' */
2259 + 4 * (edge_minus_one != NULL
2260 && top_to_bottom_hinting); /* `down' */
2262 *(p++) = HIGH(edge_first_idx);
2263 *(p++) = LOW(edge_first_idx);
2264 *(p++) = HIGH(edge2_first_idx);
2265 *(p++) = LOW(edge2_first_idx);
2267 if (edge_minus_one)
2269 FT_UShort edge_minus_one_first_idx;
2272 edge_minus_one_first_idx = TA_get_segment_index(
2273 edge_minus_one->first, recorder);
2275 *(p++) = HIGH(edge_minus_one_first_idx);
2276 *(p++) = LOW(edge_minus_one_first_idx);
2279 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2280 p = TA_hints_recorder_handle_segments(p, recorder, edge2, wraps);
2282 break;
2284 case ta_blue:
2286 TA_Edge edge = (TA_Edge)arg1;
2287 FT_UShort edge_first_idx;
2290 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2292 *(p++) = 0;
2293 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2295 if (edge->best_blue_is_shoot)
2297 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2298 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2300 else
2302 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2303 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2306 *(p++) = HIGH(edge_first_idx);
2307 *(p++) = LOW(edge_first_idx);
2309 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2311 break;
2313 case ta_serif:
2315 TA_Edge serif = (TA_Edge)arg1;
2316 TA_Edge base = serif->serif;
2317 FT_UShort serif_first_idx;
2318 FT_UShort base_first_idx;
2321 serif_first_idx = TA_get_segment_index(serif->first, recorder);
2322 base_first_idx = TA_get_segment_index(base->first, recorder);
2324 *(p++) = 0;
2325 *(p++) = (FT_Byte)action + ACTION_OFFSET
2326 + (lower_bound != NULL)
2327 + 2 * (upper_bound != NULL)
2328 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2329 && top_to_bottom_hinting); /* `down' */
2331 *(p++) = HIGH(serif_first_idx);
2332 *(p++) = LOW(serif_first_idx);
2333 *(p++) = HIGH(base_first_idx);
2334 *(p++) = LOW(base_first_idx);
2336 if (lower_bound)
2338 FT_UShort lower_bound_first_idx;
2341 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2342 recorder);
2344 *(p++) = HIGH(lower_bound_first_idx);
2345 *(p++) = LOW(lower_bound_first_idx);
2347 if (upper_bound)
2349 FT_UShort upper_bound_first_idx;
2352 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2353 recorder);
2355 *(p++) = HIGH(upper_bound_first_idx);
2356 *(p++) = LOW(upper_bound_first_idx);
2359 p = TA_hints_recorder_handle_segments(p, recorder, serif, wraps);
2361 break;
2363 case ta_serif_anchor:
2364 case ta_serif_link2:
2366 TA_Edge edge = (TA_Edge)arg1;
2367 FT_UShort edge_first_idx;
2370 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2372 *(p++) = 0;
2373 *(p++) = (FT_Byte)action + ACTION_OFFSET
2374 + (lower_bound != NULL)
2375 + 2 * (upper_bound != NULL)
2376 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2377 && top_to_bottom_hinting); /* `down' */
2379 *(p++) = HIGH(edge_first_idx);
2380 *(p++) = LOW(edge_first_idx);
2382 if (lower_bound)
2384 FT_UShort lower_bound_first_idx;
2387 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2388 recorder);
2390 *(p++) = HIGH(lower_bound_first_idx);
2391 *(p++) = LOW(lower_bound_first_idx);
2393 if (upper_bound)
2395 FT_UShort upper_bound_first_idx;
2398 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2399 recorder);
2401 *(p++) = HIGH(upper_bound_first_idx);
2402 *(p++) = LOW(upper_bound_first_idx);
2405 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2407 break;
2409 case ta_serif_link1:
2411 TA_Edge edge = (TA_Edge)arg1;
2412 TA_Edge before = arg2;
2413 TA_Edge after = arg3;
2414 FT_UShort before_first_idx;
2415 FT_UShort edge_first_idx;
2416 FT_UShort after_first_idx;
2419 before_first_idx = TA_get_segment_index(before->first, recorder);
2420 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2421 after_first_idx = TA_get_segment_index(after->first, recorder);
2423 *(p++) = 0;
2424 *(p++) = (FT_Byte)action + ACTION_OFFSET
2425 + (lower_bound != NULL)
2426 + 2 * (upper_bound != NULL)
2427 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2428 && top_to_bottom_hinting); /* `down' */
2430 *(p++) = HIGH(before_first_idx);
2431 *(p++) = LOW(before_first_idx);
2432 *(p++) = HIGH(edge_first_idx);
2433 *(p++) = LOW(edge_first_idx);
2434 *(p++) = HIGH(after_first_idx);
2435 *(p++) = LOW(after_first_idx);
2437 if (lower_bound)
2439 FT_UShort lower_bound_first_idx;
2442 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2443 recorder);
2445 *(p++) = HIGH(lower_bound_first_idx);
2446 *(p++) = LOW(lower_bound_first_idx);
2448 if (upper_bound)
2450 FT_UShort upper_bound_first_idx;
2453 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2454 recorder);
2456 *(p++) = HIGH(upper_bound_first_idx);
2457 *(p++) = LOW(upper_bound_first_idx);
2460 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2462 break;
2464 default:
2465 /* there are more cases in the enumeration */
2466 /* which are handled with flags */
2467 break;
2470 recorder->hints_record.num_actions++;
2471 recorder->hints_record.buf = p;
2475 static FT_Error
2476 TA_init_recorder(Recorder* recorder,
2477 SFNT* sfnt,
2478 FONT* font,
2479 GLYPH* glyph,
2480 TA_GlyphHints hints)
2482 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2484 TA_Segment segments = axis->segments;
2485 TA_Segment seg_limit = segments + axis->num_segments;
2486 TA_Segment seg;
2489 recorder->sfnt = sfnt;
2490 recorder->font = font;
2491 recorder->glyph = glyph;
2493 LLRB_INIT(&recorder->ip_before_points_head);
2494 LLRB_INIT(&recorder->ip_after_points_head);
2495 LLRB_INIT(&recorder->ip_on_points_head);
2496 LLRB_INIT(&recorder->ip_between_points_head);
2498 recorder->num_stack_elements = 0;
2500 /* no need to clean up allocated arrays in case of error; */
2501 /* this is handled later by `TA_free_recorder' */
2503 /* we use segment_map[axis->num_segments] */
2504 /* as the total number of mapped segments, so allocate one more element */
2505 recorder->segment_map =
2506 (FT_UShort*)malloc((size_t)(axis->num_segments + 1) * sizeof (FT_UShort));
2507 if (!recorder->segment_map)
2508 return FT_Err_Out_Of_Memory;
2510 /* `segment_map' gets initialized later on, */
2511 /* after the first call of `ta_loader_load_glyph' */
2512 recorder->segment_map_initialized = 0;
2514 recorder->num_wrap_around_segments = 0;
2515 for (seg = segments; seg < seg_limit; seg++)
2516 if (seg->first > seg->last)
2517 recorder->num_wrap_around_segments++;
2519 recorder->wrap_around_segments =
2520 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2521 * sizeof (FT_UShort));
2522 if (!recorder->wrap_around_segments)
2523 return FT_Err_Out_Of_Memory;
2525 /* `wrap_around_segments' gets initialized later on; */
2526 /* it needs function `TA_get_segment_index' which uses data */
2527 /* that hasn't been initialized yet either */
2528 recorder->wrap_around_segments_initialized = 0;
2530 return FT_Err_Ok;
2534 static void
2535 TA_reset_recorder(Recorder* recorder,
2536 FT_Byte* bufp)
2538 recorder->hints_record.buf = bufp;
2539 recorder->hints_record.num_actions = 0;
2543 static void
2544 TA_rewind_recorder(Recorder* recorder,
2545 FT_Byte* bufp,
2546 FT_UInt size)
2548 Node1* before_node;
2549 Node1* after_node;
2550 Node2* on_node;
2551 Node3* between_node;
2553 Node1* next_before_node;
2554 Node1* next_after_node;
2555 Node2* next_on_node;
2556 Node3* next_between_node;
2559 TA_reset_recorder(recorder, bufp);
2561 recorder->hints_record.size = size;
2563 /* deallocate our red-black trees */
2565 for (before_node = LLRB_MIN(ip_before_points,
2566 &recorder->ip_before_points_head);
2567 before_node;
2568 before_node = next_before_node)
2570 next_before_node = LLRB_NEXT(ip_before_points,
2571 &recorder->ip_before_points_head,
2572 before_node);
2573 LLRB_REMOVE(ip_before_points,
2574 &recorder->ip_before_points_head,
2575 before_node);
2576 free(before_node);
2579 for (after_node = LLRB_MIN(ip_after_points,
2580 &recorder->ip_after_points_head);
2581 after_node;
2582 after_node = next_after_node)
2584 next_after_node = LLRB_NEXT(ip_after_points,
2585 &recorder->ip_after_points_head,
2586 after_node);
2587 LLRB_REMOVE(ip_after_points,
2588 &recorder->ip_after_points_head,
2589 after_node);
2590 free(after_node);
2593 for (on_node = LLRB_MIN(ip_on_points,
2594 &recorder->ip_on_points_head);
2595 on_node;
2596 on_node = next_on_node)
2598 next_on_node = LLRB_NEXT(ip_on_points,
2599 &recorder->ip_on_points_head,
2600 on_node);
2601 LLRB_REMOVE(ip_on_points,
2602 &recorder->ip_on_points_head,
2603 on_node);
2604 free(on_node);
2607 for (between_node = LLRB_MIN(ip_between_points,
2608 &recorder->ip_between_points_head);
2609 between_node;
2610 between_node = next_between_node)
2612 next_between_node = LLRB_NEXT(ip_between_points,
2613 &recorder->ip_between_points_head,
2614 between_node);
2615 LLRB_REMOVE(ip_between_points,
2616 &recorder->ip_between_points_head,
2617 between_node);
2618 free(between_node);
2623 static void
2624 TA_free_recorder(Recorder* recorder)
2626 free(recorder->segment_map);
2627 free(recorder->wrap_around_segments);
2629 TA_rewind_recorder(recorder, NULL, 0);
2633 FT_Error
2634 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2635 FONT* font,
2636 FT_Long idx)
2638 FT_Face face = sfnt->face;
2639 FT_Error error;
2641 FT_Byte* ins_buf;
2642 FT_UInt ins_len;
2643 FT_Byte* bufp;
2644 FT_Byte* p;
2646 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2647 glyf_Data* data = (glyf_Data*)glyf_table->data;
2648 /* `idx' is never negative */
2649 GLYPH* glyph = &data->glyphs[idx];
2651 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
2652 FT_UShort* gstyles = globals->glyph_styles;
2653 FT_Bool use_gstyle_data = 1;
2655 TA_GlyphHints hints;
2657 FT_UInt num_action_hints_records = 0;
2658 FT_UInt num_point_hints_records = 0;
2659 Hints_Record* action_hints_records = NULL;
2660 Hints_Record* point_hints_records = NULL;
2662 Recorder recorder;
2663 FT_UShort num_stack_elements;
2664 FT_Bool optimize = 0;
2666 FT_Int32 load_flags;
2667 FT_UInt size;
2669 /* we store only three positions, but it simplifies the algorithm in */
2670 /* `TA_optimize_push' if we have one additional element */
2671 FT_Byte* pos[4];
2673 #ifdef TA_DEBUG
2674 int _ta_debug_save;
2675 #endif
2678 /* XXX: right now, we abuse this flag to control */
2679 /* the global behaviour of the auto-hinter */
2680 load_flags = 1 << 29; /* vertical hinting only */
2681 if (!font->adjust_subglyphs)
2683 if (font->hint_composites)
2684 load_flags |= FT_LOAD_NO_SCALE;
2685 else
2686 load_flags |= FT_LOAD_NO_RECURSE;
2689 /* computing the segments is resolution independent, */
2690 /* thus the pixel size in this call is arbitrary -- */
2691 /* however, we avoid unnecessary debugging output */
2692 /* if we use the lowest value of the hinting range */
2693 error = FT_Set_Pixel_Sizes(face,
2694 font->hinting_range_min,
2695 font->hinting_range_min);
2696 if (error)
2697 return error;
2699 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2700 /* to modify `out' directions of points at the user's request */
2701 /* (which will eventually become single-point segments) */
2702 error = TA_control_segment_dir_collect(font, face->face_index, idx);
2703 if (error)
2704 return error;
2706 #ifdef TA_DEBUG
2707 /* temporarily disable some debugging output */
2708 /* to avoid getting the information twice */
2709 _ta_debug_save = _ta_debug;
2710 _ta_debug = 0;
2711 #endif
2713 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2714 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2716 #ifdef TA_DEBUG
2717 _ta_debug = _ta_debug_save;
2718 #endif
2720 if (error)
2721 return error;
2723 /* do nothing if we have an empty glyph */
2724 if (!(font->loader->gloader->current.num_subglyphs
2725 || face->glyph->outline.n_contours))
2726 return FT_Err_Ok;
2728 hints = &font->loader->hints;
2731 * We allocate a buffer which is certainly large enough
2732 * to hold all of the created bytecode instructions;
2733 * later on it gets reallocated to its real size.
2735 * The value `1000' is a very rough guess, not tested well.
2737 * For delta exceptions, we have three DELTA commands,
2738 * covering 3*16 ppem values.
2739 * Since a point index can be larger than 255,
2740 * we assume two bytes everywhere for the necessary PUSH calls.
2741 * This value must be doubled for the other arguments of DELTA.
2742 * Additionally, we have both x and y deltas,
2743 * which need to be handled separately in the bytecode.
2744 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2745 * adding some bytes for the necessary overhead.
2747 ins_len = (FT_UInt)(hints->num_points
2748 * (1000
2749 + ((font->control_data_head != NULL) ? 400 : 0)));
2750 ins_buf = (FT_Byte*)malloc(ins_len);
2751 if (!ins_buf)
2752 return FT_Err_Out_Of_Memory;
2754 /* handle composite glyph */
2755 if (font->loader->gloader->current.num_subglyphs)
2757 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2758 if (!bufp)
2760 error = FT_Err_Out_Of_Memory;
2761 goto Err;
2764 use_gstyle_data = 0;
2766 goto Done1;
2770 if (font->fallback_scaling)
2772 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
2774 /* the scaling value of `none_dflt' */
2775 /* (this is, hinting without script-specific blue zones) */
2776 /* is always 1, which corresponds to a no-op */
2777 bufp = ins_buf;
2779 else
2781 /* since `TA_init_recorder' hasn't been called yet, */
2782 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2783 recorder.sfnt = sfnt;
2784 recorder.font = font;
2785 recorder.glyph = glyph;
2787 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2788 if (!bufp)
2790 error = FT_Err_Out_Of_Memory;
2791 goto Err;
2795 use_gstyle_data = 0;
2797 goto Done1;
2800 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2801 if (error)
2802 goto Err;
2804 /* loop over a large range of pixel sizes */
2805 /* to find hints records which get pushed onto the bytecode stack */
2807 #ifdef DEBUGGING
2808 if (font->debug)
2810 int num_chars, i;
2811 char buf[256];
2814 (void)FT_Get_Glyph_Name(face, (FT_UInt)idx, buf, 256);
2816 num_chars = fprintf(stderr, "glyph %ld", idx);
2817 if (*buf)
2818 num_chars += fprintf(stderr, " (%s)", buf);
2819 fprintf(stderr, "\n");
2820 for (i = 0; i < num_chars; i++)
2821 putc('=', stderr);
2822 fprintf(stderr, "\n\n");
2825 #endif
2827 /* we temporarily use `ins_buf' to record the current glyph hints */
2828 ta_loader_register_hints_recorder(font->loader,
2829 TA_hints_recorder,
2830 (void*)&recorder);
2833 * It is important that we start the loop with the smallest PPEM value
2834 * used for hinting, since the number of segments that form an edge can
2835 * become smaller for larger PPEM values. For efficiency, we skip
2836 * non-edge one-point segments, and `TA_get_segment_index' would return
2837 * wrong indices otherwise.
2839 for (size = font->hinting_range_min;
2840 size <= font->hinting_range_max;
2841 size++)
2843 #ifdef DEBUGGING
2844 int have_dumps = 0;
2845 #endif
2848 TA_rewind_recorder(&recorder, ins_buf, size);
2850 error = FT_Set_Pixel_Sizes(face, size, size);
2851 if (error)
2852 goto Err;
2854 #ifdef DEBUGGING
2855 if (font->debug)
2857 int num_chars, i;
2860 num_chars = fprintf(stderr, "size %d\n", size);
2861 for (i = 0; i < num_chars - 1; i++)
2862 putc('-', stderr);
2863 fprintf(stderr, "\n\n");
2865 #endif
2867 /* calling `ta_loader_load_glyph' uses the */
2868 /* `TA_hints_recorder' function as a callback, */
2869 /* modifying `hints_record' */
2870 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2871 if (error)
2872 goto Err;
2874 if (TA_hints_record_is_different(action_hints_records,
2875 num_action_hints_records,
2876 ins_buf, recorder.hints_record.buf))
2878 #ifdef DEBUGGING
2879 if (font->debug)
2881 have_dumps = 1;
2883 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2884 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2885 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2887 fprintf(stderr, "action hints record:\n");
2888 if (ins_buf == recorder.hints_record.buf)
2889 fprintf(stderr, " (none)");
2890 else
2892 fprintf(stderr, " ");
2893 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2894 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2896 fprintf(stderr, "\n");
2898 #endif
2900 error = TA_add_hints_record(&action_hints_records,
2901 &num_action_hints_records,
2902 ins_buf, recorder.hints_record);
2903 if (error)
2904 goto Err;
2907 /* now handle point records */
2909 TA_reset_recorder(&recorder, ins_buf);
2911 /* use the point hints data collected in `TA_hints_recorder' */
2912 TA_build_point_hints(&recorder, hints);
2914 if (TA_hints_record_is_different(point_hints_records,
2915 num_point_hints_records,
2916 ins_buf, recorder.hints_record.buf))
2918 #ifdef DEBUGGING
2919 if (font->debug)
2921 if (!have_dumps)
2923 int num_chars, i;
2926 num_chars = fprintf(stderr, "size %d\n", size);
2927 for (i = 0; i < num_chars - 1; i++)
2928 putc('-', stderr);
2929 fprintf(stderr, "\n\n");
2931 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2932 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2933 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2936 fprintf(stderr, "point hints record:\n");
2937 if (ins_buf == recorder.hints_record.buf)
2938 fprintf(stderr, " (none)");
2939 else
2941 fprintf(stderr, " ");
2942 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2943 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2945 fprintf(stderr, "\n\n");
2947 #endif
2949 error = TA_add_hints_record(&point_hints_records,
2950 &num_point_hints_records,
2951 ins_buf, recorder.hints_record);
2952 if (error)
2953 goto Err;
2957 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2959 /* since we only have a single empty record we just scale the glyph */
2960 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2961 if (!bufp)
2963 error = FT_Err_Out_Of_Memory;
2964 goto Err;
2967 use_gstyle_data = 0;
2969 goto Done;
2972 /* if there is only a single record, */
2973 /* we do a global optimization later on */
2974 if (num_action_hints_records > 1)
2975 optimize = 1;
2977 /* store the hints records and handle stack depth */
2978 pos[0] = ins_buf;
2979 bufp = TA_emit_hints_records(&recorder,
2980 point_hints_records,
2981 num_point_hints_records,
2982 ins_buf,
2983 optimize);
2985 num_stack_elements = recorder.num_stack_elements;
2986 recorder.num_stack_elements = 0;
2988 pos[1] = bufp;
2989 bufp = TA_emit_hints_records(&recorder,
2990 action_hints_records,
2991 num_action_hints_records,
2992 bufp,
2993 optimize);
2995 recorder.num_stack_elements += num_stack_elements;
2997 pos[2] = bufp;
2998 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2999 if (!bufp)
3001 error = FT_Err_Out_Of_Memory;
3002 goto Err;
3005 if (num_action_hints_records == 1)
3006 bufp = TA_optimize_push(ins_buf, pos);
3008 Done:
3009 TA_free_hints_records(action_hints_records, num_action_hints_records);
3010 TA_free_hints_records(point_hints_records, num_point_hints_records);
3011 TA_free_recorder(&recorder);
3013 Done1:
3014 /* handle delta exceptions */
3015 if (font->control_data_head)
3017 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
3018 if (!bufp)
3020 error = FT_Err_Out_Of_Memory;
3021 goto Err;
3025 /* we need to insert a few extra bytecode instructions */
3026 /* for non-base glyphs */
3027 if (use_gstyle_data && (gstyles[idx] & TA_NONBASE))
3029 FT_Byte* ins_extra_buf_new;
3030 FT_Byte ins_extra_len_new;
3033 ins_extra_len_new = glyph->ins_extra_len
3034 + sizeof (ins_extra_ignore_std_width);
3035 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
3036 ins_extra_len_new);
3037 if (!ins_extra_buf_new)
3039 bufp = NULL;
3040 goto Done;
3043 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3044 /* by activating `ins_extra_ignore_std_width' */
3045 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
3046 ins_extra_ignore_std_width,
3047 sizeof (ins_extra_ignore_std_width));
3049 glyph->ins_extra_buf = ins_extra_buf_new;
3050 glyph->ins_extra_len = ins_extra_len_new;
3052 /* reset `cvtl_ignore_std_width' for next glyph */
3053 BCI(PUSHB_2);
3054 BCI(cvtl_ignore_std_width);
3055 BCI(0);
3056 BCI(WCVTP);
3059 ins_len = (FT_UInt)(bufp - ins_buf);
3061 if (ins_len > sfnt->max_instructions)
3062 sfnt->max_instructions = (FT_UShort)ins_len;
3064 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
3065 glyph->ins_len = ins_len;
3067 return FT_Err_Ok;
3069 Err:
3070 TA_free_hints_records(action_hints_records, num_action_hints_records);
3071 TA_free_hints_records(point_hints_records, num_point_hints_records);
3072 TA_free_recorder(&recorder);
3073 free(ins_buf);
3075 return error;
3079 /* end of tabytecode.c */