Add support for a small buffer of extra bytecode instruction.
[ttfautohint.git] / lib / tabytecode.c
blob1cae95cbfb541c4704d534dd483858d04a3fd783
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2014 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;
153 FT_UShort num_stack_elements; /* the necessary stack depth so far */
155 /* data necessary for strong point interpolation */
156 ip_before_points ip_before_points_head;
157 ip_after_points ip_after_points_head;
158 ip_on_points ip_on_points_head;
159 ip_between_points ip_between_points_head;
161 FT_UShort num_strong_points;
162 FT_UShort num_segments;
163 } Recorder;
166 /* this is the bytecode of the `.ttfautohint' glyph */
168 FT_Byte ttfautohint_glyph_bytecode[7] =
171 /* increment `cvtl_is_subglyph' counter */
172 PUSHB_3,
173 cvtl_is_subglyph,
174 100,
175 cvtl_is_subglyph,
176 RCVT,
177 ADD,
178 WCVTP,
183 /* if we have delta exceptions before IUP, this code gets inserted */
185 FT_Byte ins_extra_buf[4] =
197 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
198 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
199 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
200 * PUSHW_X gets used
203 FT_Byte*
204 TA_build_push(FT_Byte* bufp,
205 FT_UInt* args,
206 FT_UInt num_args,
207 FT_Bool need_words,
208 FT_Bool optimize)
210 FT_UInt* arg = args;
211 FT_UInt i, j, nargs;
214 if (need_words)
216 for (i = 0; i < num_args; i += 255)
218 nargs = (num_args - i > 255) ? 255 : num_args - i;
220 if (optimize && nargs <= 8)
221 BCI(PUSHW_1 - 1 + nargs);
222 else
224 BCI(NPUSHW);
225 BCI(nargs);
227 for (j = 0; j < nargs; j++)
229 BCI(HIGH(*arg));
230 BCI(LOW(*arg));
231 arg++;
235 else
237 for (i = 0; i < num_args; i += 255)
239 nargs = (num_args - i > 255) ? 255 : num_args - i;
241 if (optimize && nargs <= 8)
242 BCI(PUSHB_1 - 1 + nargs);
243 else
245 BCI(NPUSHB);
246 BCI(nargs);
248 for (j = 0; j < nargs; j++)
250 BCI(*arg);
251 arg++;
256 return bufp;
261 * We optimize two common cases, replacing
263 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
265 * with
267 * NPUSHB (A+B[+C]) ... CALL
269 * if possible
272 FT_Byte*
273 TA_optimize_push(FT_Byte* buf,
274 FT_Byte** pos)
276 FT_Byte sizes[3];
277 FT_Byte new_size1;
278 FT_Byte new_size2;
280 FT_UInt sum;
281 FT_UInt i;
282 FT_UInt pos_idx;
284 FT_Byte* p;
285 FT_Byte* bufp;
288 /* XXX improve handling of NPUSHW */
289 if (*(pos[0]) == NPUSHW
290 || *(pos[1]) == NPUSHW
291 || *(pos[2]) == NPUSHW)
292 return buf;
294 /* the point hints records block can be missing */
295 if (pos[0] == pos[1])
297 pos[1] = pos[2];
298 pos[2] = NULL;
301 /* there are at least two NPUSHB instructions */
302 /* (one of them directly at the start) */
303 sizes[0] = *(pos[0] + 1);
304 sizes[1] = *(pos[1] + 1);
305 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
307 sum = sizes[0] + sizes[1] + sizes[2];
309 if (sum > 2 * 0xFF)
310 return buf; /* nothing to do since we need three NPUSHB */
311 else if (!sizes[2] && (sum > 0xFF))
312 return buf; /* nothing to do since we need two NPUSHB */
314 if (sum > 0xFF)
316 /* reduce three NPUSHB to two */
317 new_size1 = 0xFF;
318 new_size2 = sum - 0xFF;
320 else
322 /* reduce two or three NPUSHB to one */
323 new_size1 = sum;
324 new_size2 = 0;
327 /* pack data */
328 p = buf;
329 bufp = buf;
330 pos_idx = 0;
332 if (new_size1 <= 8)
333 BCI(PUSHB_1 - 1 + new_size1);
334 else
336 BCI(NPUSHB);
337 BCI(new_size1);
339 for (i = 0; i < new_size1; i++)
341 if (p == pos[pos_idx])
343 pos_idx++;
344 p += 2; /* skip old NPUSHB */
346 *(bufp++) = *(p++);
349 if (new_size2)
351 if (new_size2 <= 8)
352 BCI(PUSHB_1 - 1 + new_size2);
353 else
355 BCI(NPUSHB);
356 BCI(new_size2);
358 for (i = 0; i < new_size2; i++)
360 if (p == pos[pos_idx])
362 pos_idx++;
363 p += 2;
365 *(bufp++) = *(p++);
369 BCI(CALL);
371 return bufp;
375 /* We add a subglyph for each composite glyph. */
376 /* Since subglyphs must contain at least one point, */
377 /* we have to adjust all point indices accordingly. */
378 /* Using the `pointsums' array of the `GLYPH' structure */
379 /* it is straightforward to do that: */
380 /* Assuming that point with index x is in the interval */
381 /* pointsums[n] <= x < pointsums[n + 1], */
382 /* the new point index is x + n. */
384 static FT_UInt
385 TA_adjust_point_index(Recorder* recorder,
386 FT_UInt idx)
388 FONT* font = recorder->font;
389 GLYPH* glyph = recorder->glyph;
390 FT_UShort i;
393 if (!glyph->num_components || !font->hint_composites)
394 return idx; /* not a composite glyph */
396 for (i = 0; i < glyph->num_pointsums; i++)
397 if (idx < glyph->pointsums[i])
398 break;
400 return idx + i;
404 /* we store the segments in the storage area; */
405 /* each segment record consists of the first and last point */
407 static FT_Byte*
408 TA_sfnt_build_glyph_segments(SFNT* sfnt,
409 Recorder* recorder,
410 FT_Byte* bufp,
411 FT_Bool optimize)
413 FONT* font = recorder->font;
414 TA_GlyphHints hints = &font->loader->hints;
415 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
416 TA_Point points = hints->points;
417 TA_Segment segments = axis->segments;
418 TA_Segment seg;
419 TA_Segment seg_limit;
421 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
422 glyf_Data* data = (glyf_Data*)glyf_table->data;
424 FT_UInt style_id = data->style_ids
425 [font->loader->metrics->style_class->style];
427 FT_Outline outline = font->loader->gloader->base.outline;
429 FT_UInt* args;
430 FT_UInt* arg;
431 FT_UInt num_args;
432 FT_UShort num_segments;
434 FT_Bool need_words = 0;
436 FT_Int n;
437 FT_UInt base;
438 FT_UShort num_packed_segments;
439 FT_UShort num_storage;
440 FT_UShort num_stack_elements;
441 FT_UShort num_twilight_points;
444 seg_limit = segments + axis->num_segments;
445 num_segments = axis->num_segments;
447 /* to pack the data in the bytecode more tightly, */
448 /* we store up to the first nine segments in nibbles if possible, */
449 /* using delta values */
450 base = 0;
451 num_packed_segments = 0;
452 for (seg = segments; seg < seg_limit; seg++)
454 FT_UInt first = seg->first - points;
455 FT_UInt last = seg->last - points;
458 first = TA_adjust_point_index(recorder, first);
459 last = TA_adjust_point_index(recorder, last);
461 if (first - base >= 16)
462 break;
463 if (first > last || last - first >= 16)
464 break;
465 if (num_packed_segments == 9)
466 break;
467 num_packed_segments++;
468 base = last;
471 /* also handle wrap-around segments */
472 num_segments += recorder->num_wrap_around_segments;
474 /* wrap-around segments are pushed with four arguments; */
475 /* a segment stored in nibbles needs only one byte instead of two */
476 num_args = num_packed_segments
477 + 2 * (num_segments - num_packed_segments)
478 + 2 * recorder->num_wrap_around_segments
479 + 3;
481 /* collect all arguments temporarily in an array (in reverse order) */
482 /* so that we can easily split into chunks of 255 args */
483 /* as needed by NPUSHB and NPUSHW, respectively */
484 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
485 if (!args)
486 return NULL;
488 arg = args + num_args - 1;
490 if (num_segments > 0xFF)
491 need_words = 1;
493 /* the number of packed segments is indicated by the function number */
494 if (recorder->glyph->num_components && font->hint_composites)
495 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
496 else
497 *(arg--) = bci_create_segments_0 + num_packed_segments;
499 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
500 *(arg--) = num_segments;
502 base = 0;
503 for (seg = segments; seg < segments + num_packed_segments; seg++)
505 FT_UInt first = seg->first - points;
506 FT_UInt last = seg->last - points;
507 FT_UInt low_nibble;
508 FT_UInt high_nibble;
511 first = TA_adjust_point_index(recorder, first);
512 last = TA_adjust_point_index(recorder, last);
514 low_nibble = first - base;
515 high_nibble = last - first;
517 *(arg--) = 16 * high_nibble + low_nibble;
519 base = last;
522 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
524 FT_UInt first = seg->first - points;
525 FT_UInt last = seg->last - points;
528 *(arg--) = TA_adjust_point_index(recorder, first);
529 *(arg--) = TA_adjust_point_index(recorder, last);
531 /* we push the last and first contour point */
532 /* as a third and fourth argument in wrap-around segments */
533 if (first > last)
535 for (n = 0; n < outline.n_contours; n++)
537 FT_UInt end = (FT_UInt)outline.contours[n];
540 if (first <= end)
542 *(arg--) = TA_adjust_point_index(recorder, end);
543 if (end > 0xFF)
544 need_words = 1;
546 if (n == 0)
547 *(arg--) = TA_adjust_point_index(recorder, 0);
548 else
549 *(arg--) = TA_adjust_point_index(recorder,
550 (FT_UInt)outline.contours[n - 1] + 1);
551 break;
556 if (last > 0xFF)
557 need_words = 1;
560 /* emit the second part of wrap-around segments as separate segments */
561 /* so that edges can easily link to them */
562 for (seg = segments; seg < seg_limit; seg++)
564 FT_UInt first = seg->first - points;
565 FT_UInt last = seg->last - points;
568 if (first > last)
570 for (n = 0; n < outline.n_contours; n++)
572 if (first <= (FT_UInt)outline.contours[n])
574 if (n == 0)
575 *(arg--) = TA_adjust_point_index(recorder, 0);
576 else
577 *(arg--) = TA_adjust_point_index(recorder,
578 (FT_UInt)outline.contours[n - 1] + 1);
579 break;
583 *(arg--) = TA_adjust_point_index(recorder, last);
587 /* with most fonts it is very rare */
588 /* that any of the pushed arguments is larger than 0xFF, */
589 /* thus we refrain from further optimizing this case */
590 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
592 BCI(CALL);
594 num_storage = sal_segment_offset + num_segments * 2;
595 if (num_storage > sfnt->max_storage)
596 sfnt->max_storage = num_storage;
598 num_twilight_points = num_segments * 2;
599 if (num_twilight_points > sfnt->max_twilight_points)
600 sfnt->max_twilight_points = num_twilight_points;
602 /* both this function and `TA_emit_hints_record' */
603 /* push data onto the stack */
604 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
605 + recorder->num_stack_elements + num_args;
606 if (num_stack_elements > sfnt->max_stack_elements)
607 sfnt->max_stack_elements = num_stack_elements;
609 free(args);
611 return bufp;
615 static void
616 build_delta_exception(const Ctrl* ctrl,
617 FT_UInt** delta_args,
618 int* num_delta_args)
620 int offset;
621 int ppem;
622 int x_shift;
623 int y_shift;
626 ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
628 if (ppem < 16)
629 offset = 0;
630 else if (ppem < 32)
631 offset = 1;
632 else
633 offset = 2;
635 ppem -= offset << 4;
638 * Using
640 * delta_shift = 3 ,
642 * the possible shift values in the instructions are indexed as follows:
644 * 0 -1px
645 * 1 -7/8px
646 * ...
647 * 7 -1/8px
648 * 8 1/8px
649 * ...
650 * 14 7/8px
651 * 15 1px
653 * (note that there is no index for a zero shift).
656 if (ctrl->x_shift < 0)
657 x_shift = ctrl->x_shift + 8;
658 else
659 x_shift = ctrl->x_shift + 7;
661 if (ctrl->y_shift < 0)
662 y_shift = ctrl->y_shift + 8;
663 else
664 y_shift = ctrl->y_shift + 7;
666 /* add point index and exception specification to appropriate stack */
667 if (ctrl->x_shift)
669 *(delta_args[offset] + num_delta_args[offset]++) =
670 (ppem << 4) + x_shift;
671 *(delta_args[offset] + num_delta_args[offset]++) =
672 ctrl->point_idx;
675 if (ctrl->y_shift)
677 offset += 3;
678 *(delta_args[offset] + num_delta_args[offset]++) =
679 (ppem << 4) + y_shift;
680 *(delta_args[offset] + num_delta_args[offset]++) =
681 ctrl->point_idx;
686 static FT_Byte*
687 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
688 FONT* font,
689 FT_Long idx,
690 FT_Byte* bufp)
692 FT_Face face = font->loader->face;
694 int num_points;
695 int i;
697 FT_UShort num_stack_elements;
699 /* DELTAP[1-3] stacks for both x and y directions */
700 FT_UInt* delta_after_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
701 int num_delta_after_IUP_args[6] = {0, 0, 0, 0, 0, 0};
702 FT_UInt* args = NULL;
704 FT_Bool need_words = 0;
705 FT_Bool need_word_counts = 0;
706 FT_Bool allocated = 0;
709 num_points = font->loader->gloader->base.outline.n_points;
711 /* loop over all fitting control instructions */
712 for (;;)
714 const Ctrl* ctrl = TA_control_get_ctrl(font);
717 if (!ctrl)
718 break;
720 /* check type */
721 if (!(ctrl->type == Control_Delta_before_IUP
722 || ctrl->type == Control_Delta_after_IUP))
723 break;
725 /* too large values of font and glyph indices in `ctrl' */
726 /* are handled by later calls of this function */
727 if (face->face_index < ctrl->font_idx
728 || idx < ctrl->glyph_idx)
729 break;
731 if (!allocated)
733 for (i = 0; i < 6; i++)
735 /* see the comment on allocating `ins_buf' in function */
736 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
737 /* we have to increase by 1 for the number of argument pairs */
738 delta_after_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
739 * sizeof (FT_UInt));
740 if (!delta_after_IUP_args[i])
742 bufp = NULL;
743 goto Done;
747 allocated = 1;
750 /* since we walk sequentially over all glyphs (with points), */
751 /* and the control instruction entries have the same order, */
752 /* we don't need to test for equality of font and glyph indices: */
753 /* at this very point in the code we certainly have a hit */
754 build_delta_exception(ctrl,
755 delta_after_IUP_args,
756 num_delta_after_IUP_args);
758 if (ctrl->point_idx > 255)
759 need_words = 1;
761 TA_control_get_next(font);
764 /* nothing to do if no control instructions */
765 if (!allocated)
766 return bufp;
768 /* add number of argument pairs to the stacks */
769 for (i = 0; i < 6; i++)
771 if (num_delta_after_IUP_args[i])
773 int n = num_delta_after_IUP_args[i] >> 1;
776 if (n > 255)
777 need_word_counts = 1;
779 *(delta_after_IUP_args[i] + num_delta_after_IUP_args[i]) = n;
780 num_delta_after_IUP_args[i]++;
784 /* merge delta stacks into a single one */
785 if (need_words
786 || (!need_words && !need_word_counts))
788 FT_UInt num_args = 0;
791 for (i = 0; i < 6; i++)
793 FT_UInt* args_new;
794 FT_UInt num_args_new;
797 if (!num_delta_after_IUP_args[i])
798 continue;
800 num_args_new = num_args + num_delta_after_IUP_args[i];
801 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
802 if (!args_new)
804 bufp = NULL;
805 goto Done;
808 memcpy(args_new + num_args,
809 delta_after_IUP_args[i],
810 num_delta_after_IUP_args[i] * sizeof (FT_UInt));
812 args = args_new;
813 num_args = num_args_new;
816 num_stack_elements = num_args;
818 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
820 else
822 num_stack_elements = 0;
824 /* stack elements are bytes, but counts need words */
825 for (i = 0; i < 6; i++)
827 int num_delta_arg;
830 if (!num_delta_after_IUP_args[i])
831 continue;
833 num_delta_arg = num_delta_after_IUP_args[i] - 1;
835 bufp = TA_build_push(bufp,
836 delta_after_IUP_args[i],
837 num_delta_arg,
838 need_words,
841 num_stack_elements += num_delta_arg + 1;
843 num_delta_arg >>= 1;
844 BCI(PUSHW_1);
845 BCI(HIGH(num_delta_arg));
846 BCI(LOW(num_delta_arg));
850 /* emit the DELTA opcodes */
851 if (num_delta_after_IUP_args[5])
852 BCI(DELTAP3);
853 if (num_delta_after_IUP_args[4])
854 BCI(DELTAP2);
855 if (num_delta_after_IUP_args[3])
856 BCI(DELTAP1);
858 if (num_delta_after_IUP_args[2]
859 || num_delta_after_IUP_args[1]
860 || num_delta_after_IUP_args[0])
861 BCI(SVTCA_x);
863 if (num_delta_after_IUP_args[2])
864 BCI(DELTAP3);
865 if (num_delta_after_IUP_args[1])
866 BCI(DELTAP2);
867 if (num_delta_after_IUP_args[0])
868 BCI(DELTAP1);
870 Done:
871 for (i = 0; i < 6; i++)
872 free(delta_after_IUP_args[i]);
873 free(args);
875 if (num_stack_elements > sfnt->max_stack_elements)
876 sfnt->max_stack_elements = num_stack_elements;
877 return bufp;
881 static FT_Byte*
882 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
883 Recorder* recorder,
884 FT_Byte* bufp)
886 FONT* font = recorder->font;
887 FT_GlyphSlot glyph = sfnt->face->glyph;
888 FT_Vector* points = glyph->outline.points;
889 FT_Int num_contours = glyph->outline.n_contours;
891 FT_UInt* args;
892 FT_UInt* arg;
893 FT_UInt num_args;
895 FT_Bool need_words = 0;
896 FT_Int p, q;
897 FT_Int start, end;
898 FT_UShort num_storage;
899 FT_UShort num_stack_elements;
902 num_args = 2 * num_contours + 2;
904 /* collect all arguments temporarily in an array (in reverse order) */
905 /* so that we can easily split into chunks of 255 args */
906 /* as needed by NPUSHB and NPUSHW, respectively */
907 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
908 if (!args)
909 return NULL;
911 arg = args + num_args - 1;
913 if (num_args > 0xFF)
914 need_words = 1;
916 if (recorder->glyph->num_components && font->hint_composites)
917 *(arg--) = bci_scale_composite_glyph;
918 else
919 *(arg--) = bci_scale_glyph;
920 *(arg--) = num_contours;
922 start = 0;
923 end = 0;
925 for (p = 0; p < num_contours; p++)
927 FT_Int max = start;
928 FT_Int min = start;
931 end = glyph->outline.contours[p];
933 for (q = start; q <= end; q++)
935 if (points[q].y < points[min].y)
936 min = q;
937 if (points[q].y > points[max].y)
938 max = q;
941 if (min > max)
943 *(arg--) = TA_adjust_point_index(recorder, max);
944 *(arg--) = TA_adjust_point_index(recorder, min);
946 else
948 *(arg--) = TA_adjust_point_index(recorder, min);
949 *(arg--) = TA_adjust_point_index(recorder, max);
952 start = end + 1;
955 if (end > 0xFF)
956 need_words = 1;
958 /* with most fonts it is very rare */
959 /* that any of the pushed arguments is larger than 0xFF, */
960 /* thus we refrain from further optimizing this case */
961 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
963 BCI(CALL);
965 num_storage = sal_segment_offset;
966 if (num_storage > sfnt->max_storage)
967 sfnt->max_storage = num_storage;
969 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
970 if (num_stack_elements > sfnt->max_stack_elements)
971 sfnt->max_stack_elements = num_stack_elements;
973 free(args);
975 return bufp;
979 static FT_Byte*
980 TA_font_build_subglyph_shifter(FONT* font,
981 FT_Byte* bufp)
983 FT_Face face = font->loader->face;
984 FT_GlyphSlot glyph = face->glyph;
986 TA_GlyphLoader gloader = font->loader->gloader;
988 TA_SubGlyph subglyphs = gloader->base.subglyphs;
989 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
990 TA_SubGlyph subglyph;
992 FT_Int curr_contour = 0;
995 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
997 FT_Error error;
999 FT_UShort flags = subglyph->flags;
1000 FT_Pos y_offset = subglyph->arg2;
1002 FT_Int num_contours;
1005 /* load subglyph to get the number of contours */
1006 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
1007 if (error)
1008 return NULL;
1009 num_contours = glyph->outline.n_contours;
1011 /* nothing to do if there is a point-to-point alignment */
1012 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1013 goto End;
1015 /* nothing to do if y offset is zero */
1016 if (!y_offset)
1017 goto End;
1019 /* nothing to do if there are no contours */
1020 if (!num_contours)
1021 goto End;
1023 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1024 /* ensures that composite subglyphs are represented as simple glyphs */
1026 if (num_contours > 0xFF
1027 || curr_contour > 0xFF)
1029 BCI(PUSHW_2);
1030 BCI(HIGH(curr_contour));
1031 BCI(LOW(curr_contour));
1032 BCI(HIGH(num_contours));
1033 BCI(LOW(num_contours));
1035 else
1037 BCI(PUSHB_2);
1038 BCI(curr_contour);
1039 BCI(num_contours);
1042 /* there are high chances that this value needs PUSHW, */
1043 /* thus we handle it separately */
1044 if (y_offset > 0xFF || y_offset < 0)
1046 BCI(PUSHW_1);
1047 BCI(HIGH(y_offset));
1048 BCI(LOW(y_offset));
1050 else
1052 BCI(PUSHB_1);
1053 BCI(y_offset);
1056 BCI(PUSHB_1);
1057 BCI(bci_shift_subglyph);
1058 BCI(CALL);
1060 End:
1061 curr_contour += num_contours;
1064 return bufp;
1069 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1070 * data in four arrays (which are simple but waste a lot of memory). The
1071 * function below converts them into bytecode.
1073 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1074 * together with the edge they correspond to.
1076 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1077 * loop over the edge or edge pairs, respectively, and each edge or edge
1078 * pair contains an inner loop to emit the correponding points.
1081 static void
1082 TA_build_point_hints(Recorder* recorder,
1083 TA_GlyphHints hints)
1085 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1086 TA_Segment segments = axis->segments;
1087 TA_Edge edges = axis->edges;
1089 FT_Byte* p = recorder->hints_record.buf;
1091 FT_UShort i;
1092 FT_UShort j;
1094 FT_UShort prev_edge;
1095 FT_UShort prev_before_edge;
1096 FT_UShort prev_after_edge;
1098 Node1* before_node;
1099 Node1* after_node;
1100 Node2* on_node;
1101 Node3* between_node;
1104 /* we store everything as 16bit numbers; */
1105 /* the function numbers (`ta_ip_before', etc.) */
1106 /* reflect the order in the TA_Action enumeration */
1108 /* ip_before_points */
1110 i = 0;
1111 for (before_node = LLRB_MIN(ip_before_points,
1112 &recorder->ip_before_points_head);
1113 before_node;
1114 before_node = LLRB_NEXT(ip_before_points,
1115 &recorder->ip_before_points_head,
1116 before_node))
1118 /* count points */
1119 i++;
1122 if (i)
1124 TA_Edge edge;
1127 recorder->hints_record.num_actions++;
1129 edge = edges;
1131 *(p++) = 0;
1132 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1133 *(p++) = HIGH(edge->first - segments);
1134 *(p++) = LOW(edge->first - segments);
1135 *(p++) = HIGH(i);
1136 *(p++) = LOW(i);
1138 for (before_node = LLRB_MIN(ip_before_points,
1139 &recorder->ip_before_points_head);
1140 before_node;
1141 before_node = LLRB_NEXT(ip_before_points,
1142 &recorder->ip_before_points_head,
1143 before_node))
1145 FT_UInt point;
1148 point = TA_adjust_point_index(recorder, before_node->point);
1149 *(p++) = HIGH(point);
1150 *(p++) = LOW(point);
1154 /* ip_after_points */
1156 i = 0;
1157 for (after_node = LLRB_MIN(ip_after_points,
1158 &recorder->ip_after_points_head);
1159 after_node;
1160 after_node = LLRB_NEXT(ip_after_points,
1161 &recorder->ip_after_points_head,
1162 after_node))
1164 /* count points */
1165 i++;
1168 if (i)
1170 TA_Edge edge;
1173 recorder->hints_record.num_actions++;
1175 edge = edges + axis->num_edges - 1;
1177 *(p++) = 0;
1178 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1179 *(p++) = HIGH(edge->first - segments);
1180 *(p++) = LOW(edge->first - segments);
1181 *(p++) = HIGH(i);
1182 *(p++) = LOW(i);
1184 for (after_node = LLRB_MIN(ip_after_points,
1185 &recorder->ip_after_points_head);
1186 after_node;
1187 after_node = LLRB_NEXT(ip_after_points,
1188 &recorder->ip_after_points_head,
1189 after_node))
1191 FT_UInt point;
1194 point = TA_adjust_point_index(recorder, after_node->point);
1195 *(p++) = HIGH(point);
1196 *(p++) = LOW(point);
1200 /* ip_on_point_array */
1202 prev_edge = 0xFFFF;
1203 i = 0;
1204 for (on_node = LLRB_MIN(ip_on_points,
1205 &recorder->ip_on_points_head);
1206 on_node;
1207 on_node = LLRB_NEXT(ip_on_points,
1208 &recorder->ip_on_points_head,
1209 on_node))
1211 /* count edges */
1212 if (on_node->edge != prev_edge)
1214 i++;
1215 prev_edge = on_node->edge;
1219 if (i)
1221 recorder->hints_record.num_actions++;
1223 *(p++) = 0;
1224 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1225 *(p++) = HIGH(i);
1226 *(p++) = LOW(i);
1228 for (on_node = LLRB_MIN(ip_on_points,
1229 &recorder->ip_on_points_head);
1230 on_node;
1231 on_node = LLRB_NEXT(ip_on_points,
1232 &recorder->ip_on_points_head,
1233 on_node))
1235 Node2* edge_node;
1236 TA_Edge edge;
1239 edge = edges + on_node->edge;
1241 *(p++) = HIGH(edge->first - segments);
1242 *(p++) = LOW(edge->first - segments);
1244 /* save current position */
1245 edge_node = on_node;
1246 j = 0;
1247 for (;
1248 on_node;
1249 on_node = LLRB_NEXT(ip_on_points,
1250 &recorder->ip_on_points_head,
1251 on_node))
1253 /* count points on current edge */
1254 if (on_node->edge != edge_node->edge)
1255 break;
1256 j++;
1259 *(p++) = HIGH(j);
1260 *(p++) = LOW(j);
1262 /* restore current position */
1263 on_node = edge_node;
1264 for (;
1265 on_node;
1266 on_node = LLRB_NEXT(ip_on_points,
1267 &recorder->ip_on_points_head,
1268 on_node))
1270 FT_UInt point;
1273 if (on_node->edge != edge_node->edge)
1274 break;
1276 point = TA_adjust_point_index(recorder, on_node->point);
1277 *(p++) = HIGH(point);
1278 *(p++) = LOW(point);
1280 /* keep track of previous node */
1281 edge_node = on_node;
1284 /* reset loop iterator by one element, then continue */
1285 on_node = edge_node;
1289 /* ip_between_point_array */
1291 prev_before_edge = 0xFFFF;
1292 prev_after_edge = 0xFFFF;
1293 i = 0;
1294 for (between_node = LLRB_MIN(ip_between_points,
1295 &recorder->ip_between_points_head);
1296 between_node;
1297 between_node = LLRB_NEXT(ip_between_points,
1298 &recorder->ip_between_points_head,
1299 between_node))
1301 /* count `(before,after)' edge pairs */
1302 if (between_node->before_edge != prev_before_edge
1303 || between_node->after_edge != prev_after_edge)
1305 i++;
1306 prev_before_edge = between_node->before_edge;
1307 prev_after_edge = between_node->after_edge;
1311 if (i)
1313 recorder->hints_record.num_actions++;
1315 *(p++) = 0;
1316 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1317 *(p++) = HIGH(i);
1318 *(p++) = LOW(i);
1320 for (between_node = LLRB_MIN(ip_between_points,
1321 &recorder->ip_between_points_head);
1322 between_node;
1323 between_node = LLRB_NEXT(ip_between_points,
1324 &recorder->ip_between_points_head,
1325 between_node))
1327 Node3* edge_pair_node;
1328 TA_Edge before;
1329 TA_Edge after;
1332 before = edges + between_node->before_edge;
1333 after = edges + between_node->after_edge;
1335 *(p++) = HIGH(after->first - segments);
1336 *(p++) = LOW(after->first - segments);
1337 *(p++) = HIGH(before->first - segments);
1338 *(p++) = LOW(before->first - segments);
1340 /* save current position */
1341 edge_pair_node = between_node;
1342 j = 0;
1343 for (;
1344 between_node;
1345 between_node = LLRB_NEXT(ip_between_points,
1346 &recorder->ip_between_points_head,
1347 between_node))
1349 /* count points associated with current edge pair */
1350 if (between_node->before_edge != edge_pair_node->before_edge
1351 || between_node->after_edge != edge_pair_node->after_edge)
1352 break;
1353 j++;
1356 *(p++) = HIGH(j);
1357 *(p++) = LOW(j);
1359 /* restore current position */
1360 between_node = edge_pair_node;
1361 for (;
1362 between_node;
1363 between_node = LLRB_NEXT(ip_between_points,
1364 &recorder->ip_between_points_head,
1365 between_node))
1367 FT_UInt point;
1370 if (between_node->before_edge != edge_pair_node->before_edge
1371 || between_node->after_edge != edge_pair_node->after_edge)
1372 break;
1374 point = TA_adjust_point_index(recorder, between_node->point);
1375 *(p++) = HIGH(point);
1376 *(p++) = LOW(point);
1378 /* keep track of previous node */
1379 edge_pair_node = between_node;
1382 /* reset loop iterator by one element, then continue */
1383 between_node = edge_pair_node;
1387 recorder->hints_record.buf = p;
1391 static FT_Bool
1392 TA_hints_record_is_different(Hints_Record* hints_records,
1393 FT_UInt num_hints_records,
1394 FT_Byte* start,
1395 FT_Byte* end)
1397 Hints_Record last_hints_record;
1400 if (!hints_records)
1401 return 1;
1403 /* we only need to compare with the last hints record */
1404 last_hints_record = hints_records[num_hints_records - 1];
1406 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1407 return 1;
1409 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1410 return 1;
1412 return 0;
1416 static FT_Error
1417 TA_add_hints_record(Hints_Record** hints_records,
1418 FT_UInt* num_hints_records,
1419 FT_Byte* start,
1420 Hints_Record hints_record)
1422 Hints_Record* hints_records_new;
1423 FT_UInt buf_len;
1424 /* at this point, `hints_record.buf' still points into `ins_buf' */
1425 FT_Byte* end = hints_record.buf;
1428 buf_len = (FT_UInt)(end - start);
1430 /* now fill the structure completely */
1431 hints_record.buf_len = buf_len;
1432 hints_record.buf = (FT_Byte*)malloc(buf_len);
1433 if (!hints_record.buf)
1434 return FT_Err_Out_Of_Memory;
1436 memcpy(hints_record.buf, start, buf_len);
1438 (*num_hints_records)++;
1439 hints_records_new =
1440 (Hints_Record*)realloc(*hints_records, *num_hints_records
1441 * sizeof (Hints_Record));
1442 if (!hints_records_new)
1444 free(hints_record.buf);
1445 (*num_hints_records)--;
1446 return FT_Err_Out_Of_Memory;
1448 else
1449 *hints_records = hints_records_new;
1451 (*hints_records)[*num_hints_records - 1] = hints_record;
1453 return FT_Err_Ok;
1457 static FT_Byte*
1458 TA_emit_hints_record(Recorder* recorder,
1459 Hints_Record* hints_record,
1460 FT_Byte* bufp,
1461 FT_Bool optimize)
1463 FT_Byte* p;
1464 FT_Byte* endp;
1465 FT_Bool need_words = 0;
1467 FT_UInt i, j;
1468 FT_UInt num_arguments;
1469 FT_UInt num_args;
1472 /* check whether any argument is larger than 0xFF */
1473 endp = hints_record->buf + hints_record->buf_len;
1474 for (p = hints_record->buf; p < endp; p += 2)
1475 if (*p)
1477 need_words = 1;
1478 break;
1481 /* with most fonts it is very rare */
1482 /* that any of the pushed arguments is larger than 0xFF, */
1483 /* thus we refrain from further optimizing this case */
1485 num_arguments = hints_record->buf_len / 2;
1486 p = endp - 2;
1488 if (need_words)
1490 for (i = 0; i < num_arguments; i += 255)
1492 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1494 if (optimize && num_args <= 8)
1495 BCI(PUSHW_1 - 1 + num_args);
1496 else
1498 BCI(NPUSHW);
1499 BCI(num_args);
1501 for (j = 0; j < num_args; j++)
1503 BCI(*p);
1504 BCI(*(p + 1));
1505 p -= 2;
1509 else
1511 /* we only need the lower bytes */
1512 p++;
1514 for (i = 0; i < num_arguments; i += 255)
1516 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1518 if (optimize && num_args <= 8)
1519 BCI(PUSHB_1 - 1 + num_args);
1520 else
1522 BCI(NPUSHB);
1523 BCI(num_args);
1525 for (j = 0; j < num_args; j++)
1527 BCI(*p);
1528 p -= 2;
1533 /* collect stack depth data */
1534 if (num_arguments > recorder->num_stack_elements)
1535 recorder->num_stack_elements = num_arguments;
1537 return bufp;
1541 static FT_Byte*
1542 TA_emit_hints_records(Recorder* recorder,
1543 Hints_Record* hints_records,
1544 FT_UInt num_hints_records,
1545 FT_Byte* bufp,
1546 FT_Bool optimize)
1548 FT_UInt i;
1549 Hints_Record* hints_record;
1552 hints_record = hints_records;
1554 /* emit hints records in `if' clauses, */
1555 /* with the ppem size as the condition */
1556 for (i = 0; i < num_hints_records - 1; i++)
1558 BCI(MPPEM);
1559 if (hints_record->size > 0xFF)
1561 BCI(PUSHW_1);
1562 BCI(HIGH((hints_record + 1)->size));
1563 BCI(LOW((hints_record + 1)->size));
1565 else
1567 BCI(PUSHB_1);
1568 BCI((hints_record + 1)->size);
1570 BCI(LT);
1571 BCI(IF);
1572 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1573 BCI(ELSE);
1575 hints_record++;
1578 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1580 for (i = 0; i < num_hints_records - 1; i++)
1581 BCI(EIF);
1583 return bufp;
1587 static void
1588 TA_free_hints_records(Hints_Record* hints_records,
1589 FT_UInt num_hints_records)
1591 FT_UInt i;
1594 for (i = 0; i < num_hints_records; i++)
1595 free(hints_records[i].buf);
1597 free(hints_records);
1601 static FT_Byte*
1602 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1603 TA_AxisHints axis,
1604 TA_Edge edge,
1605 FT_UShort* wraps)
1607 TA_Segment segments = axis->segments;
1608 TA_Segment seg;
1609 FT_UShort seg_idx;
1610 FT_UShort num_segs = 0;
1611 FT_UShort* wrap;
1614 seg_idx = edge->first - segments;
1616 /* we store everything as 16bit numbers */
1617 *(bufp++) = HIGH(seg_idx);
1618 *(bufp++) = LOW(seg_idx);
1620 /* wrap-around segments are stored as two segments */
1621 if (edge->first->first > edge->first->last)
1622 num_segs++;
1624 seg = edge->first->edge_next;
1625 while (seg != edge->first)
1627 num_segs++;
1629 if (seg->first > seg->last)
1630 num_segs++;
1632 seg = seg->edge_next;
1635 *(bufp++) = HIGH(num_segs);
1636 *(bufp++) = LOW(num_segs);
1638 if (edge->first->first > edge->first->last)
1640 /* emit second part of wrap-around segment; */
1641 /* the bytecode positions such segments after `normal' ones */
1642 wrap = wraps;
1643 for (;;)
1645 if (seg_idx == *wrap)
1646 break;
1647 wrap++;
1650 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1651 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1654 seg = edge->first->edge_next;
1655 while (seg != edge->first)
1657 seg_idx = seg - segments;
1659 *(bufp++) = HIGH(seg_idx);
1660 *(bufp++) = LOW(seg_idx);
1662 if (seg->first > seg->last)
1664 wrap = wraps;
1665 for (;;)
1667 if (seg_idx == *wrap)
1668 break;
1669 wrap++;
1672 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1673 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1676 seg = seg->edge_next;
1679 return bufp;
1683 static void
1684 TA_hints_recorder(TA_Action action,
1685 TA_GlyphHints hints,
1686 TA_Dimension dim,
1687 void* arg1,
1688 TA_Edge arg2,
1689 TA_Edge arg3,
1690 TA_Edge lower_bound,
1691 TA_Edge upper_bound)
1693 TA_AxisHints axis = &hints->axis[dim];
1694 TA_Edge edges = axis->edges;
1695 TA_Segment segments = axis->segments;
1696 TA_Point points = hints->points;
1698 Recorder* recorder = (Recorder*)hints->user;
1699 SFNT* sfnt = recorder->sfnt;
1700 FONT* font = recorder->font;
1701 FT_UShort* wraps = recorder->wrap_around_segments;
1702 FT_Byte* p = recorder->hints_record.buf;
1704 FT_UInt style = font->loader->metrics->style_class->style;
1707 if (dim == TA_DIMENSION_HORZ)
1708 return;
1710 /* we collect point hints for later processing */
1711 switch (action)
1713 case ta_ip_before:
1715 Node1* before_node;
1716 TA_Point point = (TA_Point)arg1;
1719 before_node = (Node1*)malloc(sizeof (Node1));
1720 if (!before_node)
1721 return;
1722 before_node->point = point - points;
1724 LLRB_INSERT(ip_before_points,
1725 &recorder->ip_before_points_head,
1726 before_node);
1728 return;
1730 case ta_ip_after:
1732 Node1* after_node;
1733 TA_Point point = (TA_Point)arg1;
1736 after_node = (Node1*)malloc(sizeof (Node1));
1737 if (!after_node)
1738 return;
1739 after_node->point = point - points;
1741 LLRB_INSERT(ip_after_points,
1742 &recorder->ip_after_points_head,
1743 after_node);
1745 return;
1747 case ta_ip_on:
1749 Node2* on_node;
1750 TA_Point point = (TA_Point)arg1;
1751 TA_Edge edge = arg2;
1754 on_node = (Node2*)malloc(sizeof (Node2));
1755 if (!on_node)
1756 return;
1757 on_node->edge = edge - edges;
1758 on_node->point = point - points;
1760 LLRB_INSERT(ip_on_points,
1761 &recorder->ip_on_points_head,
1762 on_node);
1764 return;
1766 case ta_ip_between:
1768 Node3* between_node;
1769 TA_Point point = (TA_Point)arg1;
1770 TA_Edge before = arg2;
1771 TA_Edge after = arg3;
1774 between_node = (Node3*)malloc(sizeof (Node3));
1775 if (!between_node)
1776 return;
1777 between_node->before_edge = before - edges;
1778 between_node->after_edge = after - edges;
1779 between_node->point = point - points;
1781 LLRB_INSERT(ip_between_points,
1782 &recorder->ip_between_points_head,
1783 between_node);
1785 return;
1787 case ta_bound:
1788 /* we ignore the BOUND action since we signal this information */
1789 /* with the proper function number */
1790 return;
1792 default:
1793 break;
1796 /* some enum values correspond to four or eight bytecode functions; */
1797 /* if the value is n, the function numbers are n, ..., n+7, */
1798 /* to be differentiated with flags */
1800 switch (action)
1802 case ta_link:
1804 TA_Edge base_edge = (TA_Edge)arg1;
1805 TA_Edge stem_edge = arg2;
1808 *(p++) = 0;
1809 *(p++) = (FT_Byte)action + ACTION_OFFSET
1810 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1811 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1813 *(p++) = HIGH(base_edge->first - segments);
1814 *(p++) = LOW(base_edge->first - segments);
1815 *(p++) = HIGH(stem_edge->first - segments);
1816 *(p++) = LOW(stem_edge->first - segments);
1818 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1820 break;
1822 case ta_anchor:
1824 TA_Edge edge = (TA_Edge)arg1;
1825 TA_Edge edge2 = arg2;
1828 *(p++) = 0;
1829 *(p++) = (FT_Byte)action + ACTION_OFFSET
1830 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1831 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1833 *(p++) = HIGH(edge->first - segments);
1834 *(p++) = LOW(edge->first - segments);
1835 *(p++) = HIGH(edge2->first - segments);
1836 *(p++) = LOW(edge2->first - segments);
1838 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1840 break;
1842 case ta_adjust:
1844 TA_Edge edge = (TA_Edge)arg1;
1845 TA_Edge edge2 = arg2;
1846 TA_Edge edge_minus_one = lower_bound;
1849 *(p++) = 0;
1850 *(p++) = (FT_Byte)action + ACTION_OFFSET
1851 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1852 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1853 + 4 * (edge_minus_one != NULL);
1855 *(p++) = HIGH(edge->first - segments);
1856 *(p++) = LOW(edge->first - segments);
1857 *(p++) = HIGH(edge2->first - segments);
1858 *(p++) = LOW(edge2->first - segments);
1860 if (edge_minus_one)
1862 *(p++) = HIGH(edge_minus_one->first - segments);
1863 *(p++) = LOW(edge_minus_one->first - segments);
1866 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1868 break;
1870 case ta_blue_anchor:
1872 TA_Edge edge = (TA_Edge)arg1;
1873 TA_Edge blue = arg2;
1876 *(p++) = 0;
1877 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1879 *(p++) = HIGH(blue->first - segments);
1880 *(p++) = LOW(blue->first - segments);
1882 if (edge->best_blue_is_shoot)
1884 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1885 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1887 else
1889 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1890 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1893 *(p++) = HIGH(edge->first - segments);
1894 *(p++) = LOW(edge->first - segments);
1896 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1898 break;
1900 case ta_stem:
1902 TA_Edge edge = (TA_Edge)arg1;
1903 TA_Edge edge2 = arg2;
1904 TA_Edge edge_minus_one = lower_bound;
1907 *(p++) = 0;
1908 *(p++) = (FT_Byte)action + ACTION_OFFSET
1909 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1910 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1911 + 4 * (edge_minus_one != NULL);
1913 *(p++) = HIGH(edge->first - segments);
1914 *(p++) = LOW(edge->first - segments);
1915 *(p++) = HIGH(edge2->first - segments);
1916 *(p++) = LOW(edge2->first - segments);
1918 if (edge_minus_one)
1920 *(p++) = HIGH(edge_minus_one->first - segments);
1921 *(p++) = LOW(edge_minus_one->first - segments);
1924 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1925 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1927 break;
1929 case ta_blue:
1931 TA_Edge edge = (TA_Edge)arg1;
1934 *(p++) = 0;
1935 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1937 if (edge->best_blue_is_shoot)
1939 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1940 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1942 else
1944 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1945 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1948 *(p++) = HIGH(edge->first - segments);
1949 *(p++) = LOW(edge->first - segments);
1951 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1953 break;
1955 case ta_serif:
1957 TA_Edge serif = (TA_Edge)arg1;
1958 TA_Edge base = serif->serif;
1961 *(p++) = 0;
1962 *(p++) = (FT_Byte)action + ACTION_OFFSET
1963 + (lower_bound != NULL)
1964 + 2 * (upper_bound != NULL);
1966 *(p++) = HIGH(serif->first - segments);
1967 *(p++) = LOW(serif->first - segments);
1968 *(p++) = HIGH(base->first - segments);
1969 *(p++) = LOW(base->first - segments);
1971 if (lower_bound)
1973 *(p++) = HIGH(lower_bound->first - segments);
1974 *(p++) = LOW(lower_bound->first - segments);
1976 if (upper_bound)
1978 *(p++) = HIGH(upper_bound->first - segments);
1979 *(p++) = LOW(upper_bound->first - segments);
1982 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1984 break;
1986 case ta_serif_anchor:
1987 case ta_serif_link2:
1989 TA_Edge edge = (TA_Edge)arg1;
1992 *(p++) = 0;
1993 *(p++) = (FT_Byte)action + ACTION_OFFSET
1994 + (lower_bound != NULL)
1995 + 2 * (upper_bound != NULL);
1997 *(p++) = HIGH(edge->first - segments);
1998 *(p++) = LOW(edge->first - segments);
2000 if (lower_bound)
2002 *(p++) = HIGH(lower_bound->first - segments);
2003 *(p++) = LOW(lower_bound->first - segments);
2005 if (upper_bound)
2007 *(p++) = HIGH(upper_bound->first - segments);
2008 *(p++) = LOW(upper_bound->first - segments);
2011 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2013 break;
2015 case ta_serif_link1:
2017 TA_Edge edge = (TA_Edge)arg1;
2018 TA_Edge before = arg2;
2019 TA_Edge after = arg3;
2022 *(p++) = 0;
2023 *(p++) = (FT_Byte)action + ACTION_OFFSET
2024 + (lower_bound != NULL)
2025 + 2 * (upper_bound != NULL);
2027 *(p++) = HIGH(before->first - segments);
2028 *(p++) = LOW(before->first - segments);
2029 *(p++) = HIGH(edge->first - segments);
2030 *(p++) = LOW(edge->first - segments);
2031 *(p++) = HIGH(after->first - segments);
2032 *(p++) = LOW(after->first - segments);
2034 if (lower_bound)
2036 *(p++) = HIGH(lower_bound->first - segments);
2037 *(p++) = LOW(lower_bound->first - segments);
2039 if (upper_bound)
2041 *(p++) = HIGH(upper_bound->first - segments);
2042 *(p++) = LOW(upper_bound->first - segments);
2045 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2047 break;
2049 default:
2050 /* there are more cases in the enumeration */
2051 /* which are handled with flags */
2052 break;
2055 recorder->hints_record.num_actions++;
2056 recorder->hints_record.buf = p;
2060 static FT_Error
2061 TA_init_recorder(Recorder* recorder,
2062 SFNT* sfnt,
2063 FONT* font,
2064 GLYPH* glyph,
2065 TA_GlyphHints hints)
2067 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2068 TA_Point points = hints->points;
2069 TA_Point point_limit = points + hints->num_points;
2070 TA_Point point;
2072 TA_Segment segments = axis->segments;
2073 TA_Segment seg_limit = segments + axis->num_segments;
2074 TA_Segment seg;
2076 FT_UShort num_strong_points = 0;
2077 FT_UShort* wrap_around_segment;
2079 recorder->sfnt = sfnt;
2080 recorder->font = font;
2081 recorder->glyph = glyph;
2082 recorder->num_segments = axis->num_segments;
2084 LLRB_INIT(&recorder->ip_before_points_head);
2085 LLRB_INIT(&recorder->ip_after_points_head);
2086 LLRB_INIT(&recorder->ip_on_points_head);
2087 LLRB_INIT(&recorder->ip_between_points_head);
2089 recorder->num_stack_elements = 0;
2091 /* no need to clean up allocated arrays in case of error; */
2092 /* this is handled later by `TA_free_recorder' */
2094 recorder->num_wrap_around_segments = 0;
2095 for (seg = segments; seg < seg_limit; seg++)
2096 if (seg->first > seg->last)
2097 recorder->num_wrap_around_segments++;
2099 recorder->wrap_around_segments =
2100 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2101 * sizeof (FT_UShort));
2102 if (!recorder->wrap_around_segments)
2103 return FT_Err_Out_Of_Memory;
2105 wrap_around_segment = recorder->wrap_around_segments;
2106 for (seg = segments; seg < seg_limit; seg++)
2107 if (seg->first > seg->last)
2108 *(wrap_around_segment++) = seg - segments;
2110 /* get number of strong points */
2111 for (point = points; point < point_limit; point++)
2113 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2114 /* however, this value isn't known yet */
2115 /* (or rather, it can vary between different pixel sizes) */
2116 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
2117 continue;
2119 num_strong_points++;
2122 recorder->num_strong_points = num_strong_points;
2124 return FT_Err_Ok;
2128 static void
2129 TA_reset_recorder(Recorder* recorder,
2130 FT_Byte* bufp)
2132 recorder->hints_record.buf = bufp;
2133 recorder->hints_record.num_actions = 0;
2137 static void
2138 TA_rewind_recorder(Recorder* recorder,
2139 FT_Byte* bufp,
2140 FT_UInt size)
2142 Node1* before_node;
2143 Node1* after_node;
2144 Node2* on_node;
2145 Node3* between_node;
2147 Node1* next_before_node;
2148 Node1* next_after_node;
2149 Node2* next_on_node;
2150 Node3* next_between_node;
2153 TA_reset_recorder(recorder, bufp);
2155 recorder->hints_record.size = size;
2157 /* deallocate our red-black trees */
2159 for (before_node = LLRB_MIN(ip_before_points,
2160 &recorder->ip_before_points_head);
2161 before_node;
2162 before_node = next_before_node)
2164 next_before_node = LLRB_NEXT(ip_before_points,
2165 &recorder->ip_before_points_head,
2166 before_node);
2167 LLRB_REMOVE(ip_before_points,
2168 &recorder->ip_before_points_head,
2169 before_node);
2170 free(before_node);
2173 for (after_node = LLRB_MIN(ip_after_points,
2174 &recorder->ip_after_points_head);
2175 after_node;
2176 after_node = next_after_node)
2178 next_after_node = LLRB_NEXT(ip_after_points,
2179 &recorder->ip_after_points_head,
2180 after_node);
2181 LLRB_REMOVE(ip_after_points,
2182 &recorder->ip_after_points_head,
2183 after_node);
2184 free(after_node);
2187 for (on_node = LLRB_MIN(ip_on_points,
2188 &recorder->ip_on_points_head);
2189 on_node;
2190 on_node = next_on_node)
2192 next_on_node = LLRB_NEXT(ip_on_points,
2193 &recorder->ip_on_points_head,
2194 on_node);
2195 LLRB_REMOVE(ip_on_points,
2196 &recorder->ip_on_points_head,
2197 on_node);
2198 free(on_node);
2201 for (between_node = LLRB_MIN(ip_between_points,
2202 &recorder->ip_between_points_head);
2203 between_node;
2204 between_node = next_between_node)
2206 next_between_node = LLRB_NEXT(ip_between_points,
2207 &recorder->ip_between_points_head,
2208 between_node);
2209 LLRB_REMOVE(ip_between_points,
2210 &recorder->ip_between_points_head,
2211 between_node);
2212 free(between_node);
2217 static void
2218 TA_free_recorder(Recorder* recorder)
2220 free(recorder->wrap_around_segments);
2222 TA_rewind_recorder(recorder, NULL, 0);
2226 FT_Error
2227 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2228 FONT* font,
2229 FT_Long idx)
2231 FT_Face face = sfnt->face;
2232 FT_Error error;
2234 FT_Byte* ins_buf;
2235 FT_UInt ins_len;
2236 FT_Byte* bufp;
2237 FT_Byte* p;
2239 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2240 glyf_Data* data = (glyf_Data*)glyf_table->data;
2241 /* `idx' is never negative */
2242 GLYPH* glyph = &data->glyphs[idx];
2244 TA_GlyphHints hints;
2246 FT_UInt num_action_hints_records = 0;
2247 FT_UInt num_point_hints_records = 0;
2248 Hints_Record* action_hints_records = NULL;
2249 Hints_Record* point_hints_records = NULL;
2251 Recorder recorder;
2252 FT_UShort num_stack_elements;
2253 FT_Bool optimize = 0;
2255 FT_Int32 load_flags;
2256 FT_UInt size;
2258 FT_Byte* pos[3];
2260 #ifdef TA_DEBUG
2261 int _ta_debug_save;
2262 #endif
2265 /* XXX: right now, we abuse this flag to control */
2266 /* the global behaviour of the auto-hinter */
2267 load_flags = 1 << 29; /* vertical hinting only */
2268 if (!font->adjust_subglyphs)
2270 if (font->hint_composites)
2271 load_flags |= FT_LOAD_NO_SCALE;
2272 else
2273 load_flags |= FT_LOAD_NO_RECURSE;
2276 /* computing the segments is resolution independent, */
2277 /* thus the pixel size in this call is arbitrary -- */
2278 /* however, we avoid unnecessary debugging output */
2279 /* if we use the lowest value of the hinting range */
2280 error = FT_Set_Pixel_Sizes(face,
2281 font->hinting_range_min,
2282 font->hinting_range_min);
2283 if (error)
2284 return error;
2286 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2287 /* to modify `out' directions of points at the user's request */
2288 /* (which will eventually become single-point segments) */
2289 error = TA_control_segment_dir_collect(font, face->face_index, idx);
2290 if (error)
2291 return error;
2293 #ifdef TA_DEBUG
2294 /* temporarily disable some debugging output */
2295 /* to avoid getting the information twice */
2296 _ta_debug_save = _ta_debug;
2297 _ta_debug = 0;
2298 #endif
2300 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2301 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2303 #ifdef TA_DEBUG
2304 _ta_debug = _ta_debug_save;
2305 #endif
2307 if (error)
2308 return error;
2310 /* do nothing if we have an empty glyph */
2311 if (!face->glyph->outline.n_contours)
2312 return FT_Err_Ok;
2314 hints = &font->loader->hints;
2316 /* do nothing if the setup delivered the `none_dflt' style only */
2317 if (!hints->num_points)
2318 return FT_Err_Ok;
2321 * We allocate a buffer which is certainly large enough
2322 * to hold all of the created bytecode instructions;
2323 * later on it gets reallocated to its real size.
2325 * The value `1000' is a very rough guess, not tested well.
2327 * For delta exceptions, we have three DELTA commands,
2328 * covering 3*16 ppem values.
2329 * Since a point index can be larger than 255,
2330 * we assume two bytes everywhere for the necessary PUSH calls.
2331 * This value must be doubled for the other arguments of DELTA.
2332 * Additionally, we have both x and y deltas,
2333 * which need to be handled separately in the bytecode.
2334 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2335 * adding some bytes for the necessary overhead.
2337 ins_len = hints->num_points
2338 * (1000 + ((font->control_data_head != NULL) ? 400 : 0));
2339 ins_buf = (FT_Byte*)malloc(ins_len);
2340 if (!ins_buf)
2341 return FT_Err_Out_Of_Memory;
2343 /* handle composite glyph */
2344 if (font->loader->gloader->base.num_subglyphs)
2346 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2347 if (!bufp)
2349 error = FT_Err_Out_Of_Memory;
2350 goto Err;
2353 goto Done1;
2356 /* only scale the glyph if the `none_dflt' style has been used */
2357 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
2359 /* since `TA_init_recorder' hasn't been called yet, */
2360 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2361 recorder.sfnt = sfnt;
2362 recorder.font = font;
2363 recorder.glyph = glyph;
2365 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2366 if (!bufp)
2368 error = FT_Err_Out_Of_Memory;
2369 goto Err;
2372 goto Done1;
2375 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2376 if (error)
2377 goto Err;
2379 /* loop over a large range of pixel sizes */
2380 /* to find hints records which get pushed onto the bytecode stack */
2382 #ifdef DEBUGGING
2383 if (font->debug)
2385 int num_chars, i;
2386 char buf[256];
2389 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
2391 num_chars = fprintf(stderr, "glyph %ld", idx);
2392 if (*buf)
2393 num_chars += fprintf(stderr, " (%s)", buf);
2394 fprintf(stderr, "\n");
2395 for (i = 0; i < num_chars; i++)
2396 putc('=', stderr);
2397 fprintf(stderr, "\n\n");
2400 #endif
2402 /* we temporarily use `ins_buf' to record the current glyph hints */
2403 ta_loader_register_hints_recorder(font->loader,
2404 TA_hints_recorder,
2405 (void*)&recorder);
2407 for (size = font->hinting_range_min;
2408 size <= font->hinting_range_max;
2409 size++)
2411 #ifdef DEBUGGING
2412 int have_dumps = 0;
2413 #endif
2416 TA_rewind_recorder(&recorder, ins_buf, size);
2418 error = FT_Set_Pixel_Sizes(face, size, size);
2419 if (error)
2420 goto Err;
2422 #ifdef DEBUGGING
2423 if (font->debug)
2425 int num_chars, i;
2428 num_chars = fprintf(stderr, "size %d\n", size);
2429 for (i = 0; i < num_chars - 1; i++)
2430 putc('-', stderr);
2431 fprintf(stderr, "\n\n");
2433 #endif
2435 /* calling `ta_loader_load_glyph' uses the */
2436 /* `TA_hints_recorder' function as a callback, */
2437 /* modifying `hints_record' */
2438 error = ta_loader_load_glyph(font, face, idx, load_flags);
2439 if (error)
2440 goto Err;
2442 if (TA_hints_record_is_different(action_hints_records,
2443 num_action_hints_records,
2444 ins_buf, recorder.hints_record.buf))
2446 #ifdef DEBUGGING
2447 if (font->debug)
2449 have_dumps = 1;
2451 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2452 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2453 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2455 fprintf(stderr, "action hints record:\n");
2456 if (ins_buf == recorder.hints_record.buf)
2457 fprintf(stderr, " (none)");
2458 else
2460 fprintf(stderr, " ");
2461 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2462 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2464 fprintf(stderr, "\n");
2466 #endif
2468 error = TA_add_hints_record(&action_hints_records,
2469 &num_action_hints_records,
2470 ins_buf, recorder.hints_record);
2471 if (error)
2472 goto Err;
2475 /* now handle point records */
2477 TA_reset_recorder(&recorder, ins_buf);
2479 /* use the point hints data collected in `TA_hints_recorder' */
2480 TA_build_point_hints(&recorder, hints);
2482 if (TA_hints_record_is_different(point_hints_records,
2483 num_point_hints_records,
2484 ins_buf, recorder.hints_record.buf))
2486 #ifdef DEBUGGING
2487 if (font->debug)
2489 if (!have_dumps)
2491 int num_chars, i;
2494 num_chars = fprintf(stderr, "size %d\n", size);
2495 for (i = 0; i < num_chars - 1; i++)
2496 putc('-', stderr);
2497 fprintf(stderr, "\n\n");
2499 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2500 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2501 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2504 fprintf(stderr, "point hints record:\n");
2505 if (ins_buf == recorder.hints_record.buf)
2506 fprintf(stderr, " (none)");
2507 else
2509 fprintf(stderr, " ");
2510 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2511 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2513 fprintf(stderr, "\n\n");
2515 #endif
2517 error = TA_add_hints_record(&point_hints_records,
2518 &num_point_hints_records,
2519 ins_buf, recorder.hints_record);
2520 if (error)
2521 goto Err;
2525 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2527 /* since we only have a single empty record we just scale the glyph */
2528 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2529 if (!bufp)
2531 error = FT_Err_Out_Of_Memory;
2532 goto Err;
2535 goto Done;
2538 /* if there is only a single record, */
2539 /* we do a global optimization later on */
2540 if (num_action_hints_records > 1)
2541 optimize = 1;
2543 /* store the hints records and handle stack depth */
2544 pos[0] = ins_buf;
2545 bufp = TA_emit_hints_records(&recorder,
2546 point_hints_records,
2547 num_point_hints_records,
2548 ins_buf,
2549 optimize);
2551 num_stack_elements = recorder.num_stack_elements;
2552 recorder.num_stack_elements = 0;
2554 pos[1] = bufp;
2555 bufp = TA_emit_hints_records(&recorder,
2556 action_hints_records,
2557 num_action_hints_records,
2558 bufp,
2559 optimize);
2561 recorder.num_stack_elements += num_stack_elements;
2563 pos[2] = bufp;
2564 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2565 if (!bufp)
2567 error = FT_Err_Out_Of_Memory;
2568 goto Err;
2571 if (num_action_hints_records == 1)
2572 bufp = TA_optimize_push(ins_buf, pos);
2574 Done:
2575 TA_free_hints_records(action_hints_records, num_action_hints_records);
2576 TA_free_hints_records(point_hints_records, num_point_hints_records);
2577 TA_free_recorder(&recorder);
2579 Done1:
2580 /* handle delta exceptions */
2581 if (font->control_data_head)
2583 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
2584 if (!bufp)
2586 error = FT_Err_Out_Of_Memory;
2587 goto Err;
2591 ins_len = bufp - ins_buf;
2593 if (ins_len > sfnt->max_instructions)
2594 sfnt->max_instructions = ins_len;
2596 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2597 glyph->ins_len = ins_len;
2599 return FT_Err_Ok;
2601 Err:
2602 TA_free_hints_records(action_hints_records, num_action_hints_records);
2603 TA_free_hints_records(point_hints_records, num_point_hints_records);
2604 TA_free_recorder(&recorder);
2605 free(ins_buf);
2607 return error;
2611 /* end of tabytecode.c */