Use `Control_Type' to handle different segment directions.
[ttfautohint.git] / lib / tabytecode.c
blob22eb66777001dd05f842bc8b1430880c0df6e5b4
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,
184 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
185 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
186 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
187 * PUSHW_X gets used
190 FT_Byte*
191 TA_build_push(FT_Byte* bufp,
192 FT_UInt* args,
193 FT_UInt num_args,
194 FT_Bool need_words,
195 FT_Bool optimize)
197 FT_UInt* arg = args;
198 FT_UInt i, j, nargs;
201 if (need_words)
203 for (i = 0; i < num_args; i += 255)
205 nargs = (num_args - i > 255) ? 255 : num_args - i;
207 if (optimize && nargs <= 8)
208 BCI(PUSHW_1 - 1 + nargs);
209 else
211 BCI(NPUSHW);
212 BCI(nargs);
214 for (j = 0; j < nargs; j++)
216 BCI(HIGH(*arg));
217 BCI(LOW(*arg));
218 arg++;
222 else
224 for (i = 0; i < num_args; i += 255)
226 nargs = (num_args - i > 255) ? 255 : num_args - i;
228 if (optimize && nargs <= 8)
229 BCI(PUSHB_1 - 1 + nargs);
230 else
232 BCI(NPUSHB);
233 BCI(nargs);
235 for (j = 0; j < nargs; j++)
237 BCI(*arg);
238 arg++;
243 return bufp;
248 * We optimize two common cases, replacing
250 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
252 * with
254 * NPUSHB (A+B[+C]) ... CALL
256 * if possible
259 FT_Byte*
260 TA_optimize_push(FT_Byte* buf,
261 FT_Byte** pos)
263 FT_Byte sizes[3];
264 FT_Byte new_size1;
265 FT_Byte new_size2;
267 FT_UInt sum;
268 FT_UInt i;
269 FT_UInt pos_idx;
271 FT_Byte* p;
272 FT_Byte* bufp;
275 /* XXX improve handling of NPUSHW */
276 if (*(pos[0]) == NPUSHW
277 || *(pos[1]) == NPUSHW
278 || *(pos[2]) == NPUSHW)
279 return buf;
281 /* the point hints records block can be missing */
282 if (pos[0] == pos[1])
284 pos[1] = pos[2];
285 pos[2] = NULL;
288 /* there are at least two NPUSHB instructions */
289 /* (one of them directly at the start) */
290 sizes[0] = *(pos[0] + 1);
291 sizes[1] = *(pos[1] + 1);
292 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
294 sum = sizes[0] + sizes[1] + sizes[2];
296 if (sum > 2 * 0xFF)
297 return buf; /* nothing to do since we need three NPUSHB */
298 else if (!sizes[2] && (sum > 0xFF))
299 return buf; /* nothing to do since we need two NPUSHB */
301 if (sum > 0xFF)
303 /* reduce three NPUSHB to two */
304 new_size1 = 0xFF;
305 new_size2 = sum - 0xFF;
307 else
309 /* reduce two or three NPUSHB to one */
310 new_size1 = sum;
311 new_size2 = 0;
314 /* pack data */
315 p = buf;
316 bufp = buf;
317 pos_idx = 0;
319 if (new_size1 <= 8)
320 BCI(PUSHB_1 - 1 + new_size1);
321 else
323 BCI(NPUSHB);
324 BCI(new_size1);
326 for (i = 0; i < new_size1; i++)
328 if (p == pos[pos_idx])
330 pos_idx++;
331 p += 2; /* skip old NPUSHB */
333 *(bufp++) = *(p++);
336 if (new_size2)
338 if (new_size2 <= 8)
339 BCI(PUSHB_1 - 1 + new_size2);
340 else
342 BCI(NPUSHB);
343 BCI(new_size2);
345 for (i = 0; i < new_size2; i++)
347 if (p == pos[pos_idx])
349 pos_idx++;
350 p += 2;
352 *(bufp++) = *(p++);
356 BCI(CALL);
358 return bufp;
362 /* We add a subglyph for each composite glyph. */
363 /* Since subglyphs must contain at least one point, */
364 /* we have to adjust all point indices accordingly. */
365 /* Using the `pointsums' array of the `GLYPH' structure */
366 /* it is straightforward to do that: */
367 /* Assuming that point with index x is in the interval */
368 /* pointsums[n] <= x < pointsums[n + 1], */
369 /* the new point index is x + n. */
371 static FT_UInt
372 TA_adjust_point_index(Recorder* recorder,
373 FT_UInt idx)
375 FONT* font = recorder->font;
376 GLYPH* glyph = recorder->glyph;
377 FT_UShort i;
380 if (!glyph->num_components || !font->hint_composites)
381 return idx; /* not a composite glyph */
383 for (i = 0; i < glyph->num_pointsums; i++)
384 if (idx < glyph->pointsums[i])
385 break;
387 return idx + i;
391 /* we store the segments in the storage area; */
392 /* each segment record consists of the first and last point */
394 static FT_Byte*
395 TA_sfnt_build_glyph_segments(SFNT* sfnt,
396 Recorder* recorder,
397 FT_Byte* bufp,
398 FT_Bool optimize)
400 FONT* font = recorder->font;
401 TA_GlyphHints hints = &font->loader->hints;
402 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
403 TA_Point points = hints->points;
404 TA_Segment segments = axis->segments;
405 TA_Segment seg;
406 TA_Segment seg_limit;
408 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
409 glyf_Data* data = (glyf_Data*)glyf_table->data;
411 FT_UInt style_id = data->style_ids
412 [font->loader->metrics->style_class->style];
414 FT_Outline outline = font->loader->gloader->base.outline;
416 FT_UInt* args;
417 FT_UInt* arg;
418 FT_UInt num_args;
419 FT_UShort num_segments;
421 FT_Bool need_words = 0;
423 FT_Int n;
424 FT_UInt base;
425 FT_UShort num_packed_segments;
426 FT_UShort num_storage;
427 FT_UShort num_stack_elements;
428 FT_UShort num_twilight_points;
431 seg_limit = segments + axis->num_segments;
432 num_segments = axis->num_segments;
434 /* to pack the data in the bytecode more tightly, */
435 /* we store up to the first nine segments in nibbles if possible, */
436 /* using delta values */
437 base = 0;
438 num_packed_segments = 0;
439 for (seg = segments; seg < seg_limit; seg++)
441 FT_UInt first = seg->first - points;
442 FT_UInt last = seg->last - points;
445 first = TA_adjust_point_index(recorder, first);
446 last = TA_adjust_point_index(recorder, last);
448 if (first - base >= 16)
449 break;
450 if (first > last || last - first >= 16)
451 break;
452 if (num_packed_segments == 9)
453 break;
454 num_packed_segments++;
455 base = last;
458 /* also handle wrap-around segments */
459 num_segments += recorder->num_wrap_around_segments;
461 /* wrap-around segments are pushed with four arguments; */
462 /* a segment stored in nibbles needs only one byte instead of two */
463 num_args = num_packed_segments
464 + 2 * (num_segments - num_packed_segments)
465 + 2 * recorder->num_wrap_around_segments
466 + 3;
468 /* collect all arguments temporarily in an array (in reverse order) */
469 /* so that we can easily split into chunks of 255 args */
470 /* as needed by NPUSHB and NPUSHW, respectively */
471 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
472 if (!args)
473 return NULL;
475 arg = args + num_args - 1;
477 if (num_segments > 0xFF)
478 need_words = 1;
480 /* the number of packed segments is indicated by the function number */
481 if (recorder->glyph->num_components && font->hint_composites)
482 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
483 else
484 *(arg--) = bci_create_segments_0 + num_packed_segments;
486 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
487 *(arg--) = num_segments;
489 base = 0;
490 for (seg = segments; seg < segments + num_packed_segments; seg++)
492 FT_UInt first = seg->first - points;
493 FT_UInt last = seg->last - points;
494 FT_UInt low_nibble;
495 FT_UInt high_nibble;
498 first = TA_adjust_point_index(recorder, first);
499 last = TA_adjust_point_index(recorder, last);
501 low_nibble = first - base;
502 high_nibble = last - first;
504 *(arg--) = 16 * high_nibble + low_nibble;
506 base = last;
509 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
511 FT_UInt first = seg->first - points;
512 FT_UInt last = seg->last - points;
515 *(arg--) = TA_adjust_point_index(recorder, first);
516 *(arg--) = TA_adjust_point_index(recorder, last);
518 /* we push the last and first contour point */
519 /* as a third and fourth argument in wrap-around segments */
520 if (first > last)
522 for (n = 0; n < outline.n_contours; n++)
524 FT_UInt end = (FT_UInt)outline.contours[n];
527 if (first <= end)
529 *(arg--) = TA_adjust_point_index(recorder, end);
530 if (end > 0xFF)
531 need_words = 1;
533 if (n == 0)
534 *(arg--) = TA_adjust_point_index(recorder, 0);
535 else
536 *(arg--) = TA_adjust_point_index(recorder,
537 (FT_UInt)outline.contours[n - 1] + 1);
538 break;
543 if (last > 0xFF)
544 need_words = 1;
547 /* emit the second part of wrap-around segments as separate segments */
548 /* so that edges can easily link to them */
549 for (seg = segments; seg < seg_limit; seg++)
551 FT_UInt first = seg->first - points;
552 FT_UInt last = seg->last - points;
555 if (first > last)
557 for (n = 0; n < outline.n_contours; n++)
559 if (first <= (FT_UInt)outline.contours[n])
561 if (n == 0)
562 *(arg--) = TA_adjust_point_index(recorder, 0);
563 else
564 *(arg--) = TA_adjust_point_index(recorder,
565 (FT_UInt)outline.contours[n - 1] + 1);
566 break;
570 *(arg--) = TA_adjust_point_index(recorder, last);
574 /* with most fonts it is very rare */
575 /* that any of the pushed arguments is larger than 0xFF, */
576 /* thus we refrain from further optimizing this case */
577 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
579 BCI(CALL);
581 num_storage = sal_segment_offset + num_segments * 2;
582 if (num_storage > sfnt->max_storage)
583 sfnt->max_storage = num_storage;
585 num_twilight_points = num_segments * 2;
586 if (num_twilight_points > sfnt->max_twilight_points)
587 sfnt->max_twilight_points = num_twilight_points;
589 /* both this function and `TA_emit_hints_record' */
590 /* push data onto the stack */
591 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
592 + recorder->num_stack_elements + num_args;
593 if (num_stack_elements > sfnt->max_stack_elements)
594 sfnt->max_stack_elements = num_stack_elements;
596 free(args);
598 return bufp;
602 static void
603 build_delta_exception(const Ctrl* ctrl,
604 FT_UInt** delta_args,
605 int* num_delta_args)
607 int offset;
608 int ppem;
609 int x_shift;
610 int y_shift;
613 ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
615 if (ppem < 16)
616 offset = 0;
617 else if (ppem < 32)
618 offset = 1;
619 else
620 offset = 2;
622 ppem -= offset << 4;
625 * Using
627 * delta_shift = 3 ,
629 * the possible shift values in the instructions are indexed as follows:
631 * 0 -1px
632 * 1 -7/8px
633 * ...
634 * 7 -1/8px
635 * 8 1/8px
636 * ...
637 * 14 7/8px
638 * 15 1px
640 * (note that there is no index for a zero shift).
643 if (ctrl->x_shift < 0)
644 x_shift = ctrl->x_shift + 8;
645 else
646 x_shift = ctrl->x_shift + 7;
648 if (ctrl->y_shift < 0)
649 y_shift = ctrl->y_shift + 8;
650 else
651 y_shift = ctrl->y_shift + 7;
653 /* add point index and exception specification to appropriate stack */
654 if (ctrl->x_shift)
656 *(delta_args[offset] + num_delta_args[offset]++) =
657 (ppem << 4) + x_shift;
658 *(delta_args[offset] + num_delta_args[offset]++) =
659 ctrl->point_idx;
662 if (ctrl->y_shift)
664 offset += 3;
665 *(delta_args[offset] + num_delta_args[offset]++) =
666 (ppem << 4) + y_shift;
667 *(delta_args[offset] + num_delta_args[offset]++) =
668 ctrl->point_idx;
673 static FT_Byte*
674 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
675 FONT* font,
676 FT_Long idx,
677 FT_Byte* bufp)
679 FT_Face face = font->loader->face;
681 int num_points;
682 int i;
684 FT_UShort num_stack_elements;
686 /* DELTAP[1-3] stacks for both x and y directions */
687 FT_UInt* delta_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
688 int num_delta_args[6] = {0, 0, 0, 0, 0, 0};
689 FT_UInt* args = NULL;
691 FT_Bool need_words = 0;
692 FT_Bool need_word_counts = 0;
693 FT_Bool allocated = 0;
696 num_points = font->loader->gloader->base.outline.n_points;
698 /* loop over all fitting control instructions */
699 for (;;)
701 const Ctrl* ctrl = TA_control_get_ctrl(font);
704 if (!ctrl)
705 break;
707 /* check type */
708 if (!(ctrl->type == Control_Delta_before_IUP
709 || ctrl->type == Control_Delta_after_IUP))
710 break;
712 /* too large values of font and glyph indices in `ctrl' */
713 /* are handled by later calls of this function */
714 if (face->face_index < ctrl->font_idx
715 || idx < ctrl->glyph_idx)
716 break;
718 if (!allocated)
720 for (i = 0; i < 6; i++)
722 /* see the comment on allocating `ins_buf' in function */
723 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
724 /* we have to increase by 1 for the number of argument pairs */
725 delta_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
726 * sizeof (FT_UInt));
727 if (!delta_args[i])
729 bufp = NULL;
730 goto Done;
734 allocated = 1;
737 /* since we walk sequentially over all glyphs (with points), */
738 /* and the control instruction entries have the same order, */
739 /* we don't need to test for equality of font and glyph indices: */
740 /* at this very point in the code we certainly have a hit */
741 build_delta_exception(ctrl, delta_args, num_delta_args);
743 if (ctrl->point_idx > 255)
744 need_words = 1;
746 TA_control_get_next(font);
749 /* nothing to do if no control instructions */
750 if (!allocated)
751 return bufp;
753 /* add number of argument pairs to the stacks */
754 for (i = 0; i < 6; i++)
756 if (num_delta_args[i])
758 int n = num_delta_args[i] >> 1;
761 if (n > 255)
762 need_word_counts = 1;
764 *(delta_args[i] + num_delta_args[i]) = n;
765 num_delta_args[i]++;
769 /* merge delta stacks into a single one */
770 if (need_words
771 || (!need_words && !need_word_counts))
773 FT_UInt num_args = 0;
776 for (i = 0; i < 6; i++)
778 FT_UInt* args_new;
779 FT_UInt num_args_new;
782 if (!num_delta_args[i])
783 continue;
785 num_args_new = num_args + num_delta_args[i];
786 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
787 if (!args_new)
789 bufp = NULL;
790 goto Done;
793 memcpy(args_new + num_args,
794 delta_args[i],
795 num_delta_args[i] * sizeof (FT_UInt));
797 args = args_new;
798 num_args = num_args_new;
801 num_stack_elements = num_args;
803 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
805 else
807 num_stack_elements = 0;
809 /* stack elements are bytes, but counts need words */
810 for (i = 0; i < 6; i++)
812 int num_delta_arg;
815 if (!num_delta_args[i])
816 continue;
818 num_delta_arg = num_delta_args[i] - 1;
820 bufp = TA_build_push(bufp,
821 delta_args[i],
822 num_delta_arg,
823 need_words,
826 num_stack_elements += num_delta_arg + 1;
828 num_delta_arg >>= 1;
829 BCI(PUSHW_1);
830 BCI(HIGH(num_delta_arg));
831 BCI(LOW(num_delta_arg));
835 /* emit the DELTA opcodes */
836 if (num_delta_args[5])
837 BCI(DELTAP3);
838 if (num_delta_args[4])
839 BCI(DELTAP2);
840 if (num_delta_args[3])
841 BCI(DELTAP1);
843 if (num_delta_args[2] || num_delta_args[1] || num_delta_args[0])
844 BCI(SVTCA_x);
846 if (num_delta_args[2])
847 BCI(DELTAP3);
848 if (num_delta_args[1])
849 BCI(DELTAP2);
850 if (num_delta_args[0])
851 BCI(DELTAP1);
853 Done:
854 for (i = 0; i < 6; i++)
855 free(delta_args[i]);
856 free(args);
858 if (num_stack_elements > sfnt->max_stack_elements)
859 sfnt->max_stack_elements = num_stack_elements;
860 return bufp;
864 static FT_Byte*
865 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
866 Recorder* recorder,
867 FT_Byte* bufp)
869 FONT* font = recorder->font;
870 FT_GlyphSlot glyph = sfnt->face->glyph;
871 FT_Vector* points = glyph->outline.points;
872 FT_Int num_contours = glyph->outline.n_contours;
874 FT_UInt* args;
875 FT_UInt* arg;
876 FT_UInt num_args;
878 FT_Bool need_words = 0;
879 FT_Int p, q;
880 FT_Int start, end;
881 FT_UShort num_storage;
882 FT_UShort num_stack_elements;
885 num_args = 2 * num_contours + 2;
887 /* collect all arguments temporarily in an array (in reverse order) */
888 /* so that we can easily split into chunks of 255 args */
889 /* as needed by NPUSHB and NPUSHW, respectively */
890 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
891 if (!args)
892 return NULL;
894 arg = args + num_args - 1;
896 if (num_args > 0xFF)
897 need_words = 1;
899 if (recorder->glyph->num_components && font->hint_composites)
900 *(arg--) = bci_scale_composite_glyph;
901 else
902 *(arg--) = bci_scale_glyph;
903 *(arg--) = num_contours;
905 start = 0;
906 end = 0;
908 for (p = 0; p < num_contours; p++)
910 FT_Int max = start;
911 FT_Int min = start;
914 end = glyph->outline.contours[p];
916 for (q = start; q <= end; q++)
918 if (points[q].y < points[min].y)
919 min = q;
920 if (points[q].y > points[max].y)
921 max = q;
924 if (min > max)
926 *(arg--) = TA_adjust_point_index(recorder, max);
927 *(arg--) = TA_adjust_point_index(recorder, min);
929 else
931 *(arg--) = TA_adjust_point_index(recorder, min);
932 *(arg--) = TA_adjust_point_index(recorder, max);
935 start = end + 1;
938 if (end > 0xFF)
939 need_words = 1;
941 /* with most fonts it is very rare */
942 /* that any of the pushed arguments is larger than 0xFF, */
943 /* thus we refrain from further optimizing this case */
944 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
946 BCI(CALL);
948 num_storage = sal_segment_offset;
949 if (num_storage > sfnt->max_storage)
950 sfnt->max_storage = num_storage;
952 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
953 if (num_stack_elements > sfnt->max_stack_elements)
954 sfnt->max_stack_elements = num_stack_elements;
956 free(args);
958 return bufp;
962 static FT_Byte*
963 TA_font_build_subglyph_shifter(FONT* font,
964 FT_Byte* bufp)
966 FT_Face face = font->loader->face;
967 FT_GlyphSlot glyph = face->glyph;
969 TA_GlyphLoader gloader = font->loader->gloader;
971 TA_SubGlyph subglyphs = gloader->base.subglyphs;
972 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
973 TA_SubGlyph subglyph;
975 FT_Int curr_contour = 0;
978 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
980 FT_Error error;
982 FT_UShort flags = subglyph->flags;
983 FT_Pos y_offset = subglyph->arg2;
985 FT_Int num_contours;
988 /* load subglyph to get the number of contours */
989 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
990 if (error)
991 return NULL;
992 num_contours = glyph->outline.n_contours;
994 /* nothing to do if there is a point-to-point alignment */
995 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
996 goto End;
998 /* nothing to do if y offset is zero */
999 if (!y_offset)
1000 goto End;
1002 /* nothing to do if there are no contours */
1003 if (!num_contours)
1004 goto End;
1006 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1007 /* ensures that composite subglyphs are represented as simple glyphs */
1009 if (num_contours > 0xFF
1010 || curr_contour > 0xFF)
1012 BCI(PUSHW_2);
1013 BCI(HIGH(curr_contour));
1014 BCI(LOW(curr_contour));
1015 BCI(HIGH(num_contours));
1016 BCI(LOW(num_contours));
1018 else
1020 BCI(PUSHB_2);
1021 BCI(curr_contour);
1022 BCI(num_contours);
1025 /* there are high chances that this value needs PUSHW, */
1026 /* thus we handle it separately */
1027 if (y_offset > 0xFF || y_offset < 0)
1029 BCI(PUSHW_1);
1030 BCI(HIGH(y_offset));
1031 BCI(LOW(y_offset));
1033 else
1035 BCI(PUSHB_1);
1036 BCI(y_offset);
1039 BCI(PUSHB_1);
1040 BCI(bci_shift_subglyph);
1041 BCI(CALL);
1043 End:
1044 curr_contour += num_contours;
1047 return bufp;
1052 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1053 * data in four arrays (which are simple but waste a lot of memory). The
1054 * function below converts them into bytecode.
1056 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1057 * together with the edge they correspond to.
1059 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1060 * loop over the edge or edge pairs, respectively, and each edge or edge
1061 * pair contains an inner loop to emit the correponding points.
1064 static void
1065 TA_build_point_hints(Recorder* recorder,
1066 TA_GlyphHints hints)
1068 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1069 TA_Segment segments = axis->segments;
1070 TA_Edge edges = axis->edges;
1072 FT_Byte* p = recorder->hints_record.buf;
1074 FT_UShort i;
1075 FT_UShort j;
1077 FT_UShort prev_edge;
1078 FT_UShort prev_before_edge;
1079 FT_UShort prev_after_edge;
1081 Node1* before_node;
1082 Node1* after_node;
1083 Node2* on_node;
1084 Node3* between_node;
1087 /* we store everything as 16bit numbers; */
1088 /* the function numbers (`ta_ip_before', etc.) */
1089 /* reflect the order in the TA_Action enumeration */
1091 /* ip_before_points */
1093 i = 0;
1094 for (before_node = LLRB_MIN(ip_before_points,
1095 &recorder->ip_before_points_head);
1096 before_node;
1097 before_node = LLRB_NEXT(ip_before_points,
1098 &recorder->ip_before_points_head,
1099 before_node))
1101 /* count points */
1102 i++;
1105 if (i)
1107 TA_Edge edge;
1110 recorder->hints_record.num_actions++;
1112 edge = edges;
1114 *(p++) = 0;
1115 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1116 *(p++) = HIGH(edge->first - segments);
1117 *(p++) = LOW(edge->first - segments);
1118 *(p++) = HIGH(i);
1119 *(p++) = LOW(i);
1121 for (before_node = LLRB_MIN(ip_before_points,
1122 &recorder->ip_before_points_head);
1123 before_node;
1124 before_node = LLRB_NEXT(ip_before_points,
1125 &recorder->ip_before_points_head,
1126 before_node))
1128 FT_UInt point;
1131 point = TA_adjust_point_index(recorder, before_node->point);
1132 *(p++) = HIGH(point);
1133 *(p++) = LOW(point);
1137 /* ip_after_points */
1139 i = 0;
1140 for (after_node = LLRB_MIN(ip_after_points,
1141 &recorder->ip_after_points_head);
1142 after_node;
1143 after_node = LLRB_NEXT(ip_after_points,
1144 &recorder->ip_after_points_head,
1145 after_node))
1147 /* count points */
1148 i++;
1151 if (i)
1153 TA_Edge edge;
1156 recorder->hints_record.num_actions++;
1158 edge = edges + axis->num_edges - 1;
1160 *(p++) = 0;
1161 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1162 *(p++) = HIGH(edge->first - segments);
1163 *(p++) = LOW(edge->first - segments);
1164 *(p++) = HIGH(i);
1165 *(p++) = LOW(i);
1167 for (after_node = LLRB_MIN(ip_after_points,
1168 &recorder->ip_after_points_head);
1169 after_node;
1170 after_node = LLRB_NEXT(ip_after_points,
1171 &recorder->ip_after_points_head,
1172 after_node))
1174 FT_UInt point;
1177 point = TA_adjust_point_index(recorder, after_node->point);
1178 *(p++) = HIGH(point);
1179 *(p++) = LOW(point);
1183 /* ip_on_point_array */
1185 prev_edge = 0xFFFF;
1186 i = 0;
1187 for (on_node = LLRB_MIN(ip_on_points,
1188 &recorder->ip_on_points_head);
1189 on_node;
1190 on_node = LLRB_NEXT(ip_on_points,
1191 &recorder->ip_on_points_head,
1192 on_node))
1194 /* count edges */
1195 if (on_node->edge != prev_edge)
1197 i++;
1198 prev_edge = on_node->edge;
1202 if (i)
1204 recorder->hints_record.num_actions++;
1206 *(p++) = 0;
1207 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1208 *(p++) = HIGH(i);
1209 *(p++) = LOW(i);
1211 for (on_node = LLRB_MIN(ip_on_points,
1212 &recorder->ip_on_points_head);
1213 on_node;
1214 on_node = LLRB_NEXT(ip_on_points,
1215 &recorder->ip_on_points_head,
1216 on_node))
1218 Node2* edge_node;
1219 TA_Edge edge;
1222 edge = edges + on_node->edge;
1224 *(p++) = HIGH(edge->first - segments);
1225 *(p++) = LOW(edge->first - segments);
1227 /* save current position */
1228 edge_node = on_node;
1229 j = 0;
1230 for (;
1231 on_node;
1232 on_node = LLRB_NEXT(ip_on_points,
1233 &recorder->ip_on_points_head,
1234 on_node))
1236 /* count points on current edge */
1237 if (on_node->edge != edge_node->edge)
1238 break;
1239 j++;
1242 *(p++) = HIGH(j);
1243 *(p++) = LOW(j);
1245 /* restore current position */
1246 on_node = edge_node;
1247 for (;
1248 on_node;
1249 on_node = LLRB_NEXT(ip_on_points,
1250 &recorder->ip_on_points_head,
1251 on_node))
1253 FT_UInt point;
1256 if (on_node->edge != edge_node->edge)
1257 break;
1259 point = TA_adjust_point_index(recorder, on_node->point);
1260 *(p++) = HIGH(point);
1261 *(p++) = LOW(point);
1263 /* keep track of previous node */
1264 edge_node = on_node;
1267 /* reset loop iterator by one element, then continue */
1268 on_node = edge_node;
1272 /* ip_between_point_array */
1274 prev_before_edge = 0xFFFF;
1275 prev_after_edge = 0xFFFF;
1276 i = 0;
1277 for (between_node = LLRB_MIN(ip_between_points,
1278 &recorder->ip_between_points_head);
1279 between_node;
1280 between_node = LLRB_NEXT(ip_between_points,
1281 &recorder->ip_between_points_head,
1282 between_node))
1284 /* count `(before,after)' edge pairs */
1285 if (between_node->before_edge != prev_before_edge
1286 || between_node->after_edge != prev_after_edge)
1288 i++;
1289 prev_before_edge = between_node->before_edge;
1290 prev_after_edge = between_node->after_edge;
1294 if (i)
1296 recorder->hints_record.num_actions++;
1298 *(p++) = 0;
1299 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1300 *(p++) = HIGH(i);
1301 *(p++) = LOW(i);
1303 for (between_node = LLRB_MIN(ip_between_points,
1304 &recorder->ip_between_points_head);
1305 between_node;
1306 between_node = LLRB_NEXT(ip_between_points,
1307 &recorder->ip_between_points_head,
1308 between_node))
1310 Node3* edge_pair_node;
1311 TA_Edge before;
1312 TA_Edge after;
1315 before = edges + between_node->before_edge;
1316 after = edges + between_node->after_edge;
1318 *(p++) = HIGH(after->first - segments);
1319 *(p++) = LOW(after->first - segments);
1320 *(p++) = HIGH(before->first - segments);
1321 *(p++) = LOW(before->first - segments);
1323 /* save current position */
1324 edge_pair_node = between_node;
1325 j = 0;
1326 for (;
1327 between_node;
1328 between_node = LLRB_NEXT(ip_between_points,
1329 &recorder->ip_between_points_head,
1330 between_node))
1332 /* count points associated with current edge pair */
1333 if (between_node->before_edge != edge_pair_node->before_edge
1334 || between_node->after_edge != edge_pair_node->after_edge)
1335 break;
1336 j++;
1339 *(p++) = HIGH(j);
1340 *(p++) = LOW(j);
1342 /* restore current position */
1343 between_node = edge_pair_node;
1344 for (;
1345 between_node;
1346 between_node = LLRB_NEXT(ip_between_points,
1347 &recorder->ip_between_points_head,
1348 between_node))
1350 FT_UInt point;
1353 if (between_node->before_edge != edge_pair_node->before_edge
1354 || between_node->after_edge != edge_pair_node->after_edge)
1355 break;
1357 point = TA_adjust_point_index(recorder, between_node->point);
1358 *(p++) = HIGH(point);
1359 *(p++) = LOW(point);
1361 /* keep track of previous node */
1362 edge_pair_node = between_node;
1365 /* reset loop iterator by one element, then continue */
1366 between_node = edge_pair_node;
1370 recorder->hints_record.buf = p;
1374 static FT_Bool
1375 TA_hints_record_is_different(Hints_Record* hints_records,
1376 FT_UInt num_hints_records,
1377 FT_Byte* start,
1378 FT_Byte* end)
1380 Hints_Record last_hints_record;
1383 if (!hints_records)
1384 return 1;
1386 /* we only need to compare with the last hints record */
1387 last_hints_record = hints_records[num_hints_records - 1];
1389 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1390 return 1;
1392 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1393 return 1;
1395 return 0;
1399 static FT_Error
1400 TA_add_hints_record(Hints_Record** hints_records,
1401 FT_UInt* num_hints_records,
1402 FT_Byte* start,
1403 Hints_Record hints_record)
1405 Hints_Record* hints_records_new;
1406 FT_UInt buf_len;
1407 /* at this point, `hints_record.buf' still points into `ins_buf' */
1408 FT_Byte* end = hints_record.buf;
1411 buf_len = (FT_UInt)(end - start);
1413 /* now fill the structure completely */
1414 hints_record.buf_len = buf_len;
1415 hints_record.buf = (FT_Byte*)malloc(buf_len);
1416 if (!hints_record.buf)
1417 return FT_Err_Out_Of_Memory;
1419 memcpy(hints_record.buf, start, buf_len);
1421 (*num_hints_records)++;
1422 hints_records_new =
1423 (Hints_Record*)realloc(*hints_records, *num_hints_records
1424 * sizeof (Hints_Record));
1425 if (!hints_records_new)
1427 free(hints_record.buf);
1428 (*num_hints_records)--;
1429 return FT_Err_Out_Of_Memory;
1431 else
1432 *hints_records = hints_records_new;
1434 (*hints_records)[*num_hints_records - 1] = hints_record;
1436 return FT_Err_Ok;
1440 static FT_Byte*
1441 TA_emit_hints_record(Recorder* recorder,
1442 Hints_Record* hints_record,
1443 FT_Byte* bufp,
1444 FT_Bool optimize)
1446 FT_Byte* p;
1447 FT_Byte* endp;
1448 FT_Bool need_words = 0;
1450 FT_UInt i, j;
1451 FT_UInt num_arguments;
1452 FT_UInt num_args;
1455 /* check whether any argument is larger than 0xFF */
1456 endp = hints_record->buf + hints_record->buf_len;
1457 for (p = hints_record->buf; p < endp; p += 2)
1458 if (*p)
1460 need_words = 1;
1461 break;
1464 /* with most fonts it is very rare */
1465 /* that any of the pushed arguments is larger than 0xFF, */
1466 /* thus we refrain from further optimizing this case */
1468 num_arguments = hints_record->buf_len / 2;
1469 p = endp - 2;
1471 if (need_words)
1473 for (i = 0; i < num_arguments; i += 255)
1475 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1477 if (optimize && num_args <= 8)
1478 BCI(PUSHW_1 - 1 + num_args);
1479 else
1481 BCI(NPUSHW);
1482 BCI(num_args);
1484 for (j = 0; j < num_args; j++)
1486 BCI(*p);
1487 BCI(*(p + 1));
1488 p -= 2;
1492 else
1494 /* we only need the lower bytes */
1495 p++;
1497 for (i = 0; i < num_arguments; i += 255)
1499 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1501 if (optimize && num_args <= 8)
1502 BCI(PUSHB_1 - 1 + num_args);
1503 else
1505 BCI(NPUSHB);
1506 BCI(num_args);
1508 for (j = 0; j < num_args; j++)
1510 BCI(*p);
1511 p -= 2;
1516 /* collect stack depth data */
1517 if (num_arguments > recorder->num_stack_elements)
1518 recorder->num_stack_elements = num_arguments;
1520 return bufp;
1524 static FT_Byte*
1525 TA_emit_hints_records(Recorder* recorder,
1526 Hints_Record* hints_records,
1527 FT_UInt num_hints_records,
1528 FT_Byte* bufp,
1529 FT_Bool optimize)
1531 FT_UInt i;
1532 Hints_Record* hints_record;
1535 hints_record = hints_records;
1537 /* emit hints records in `if' clauses, */
1538 /* with the ppem size as the condition */
1539 for (i = 0; i < num_hints_records - 1; i++)
1541 BCI(MPPEM);
1542 if (hints_record->size > 0xFF)
1544 BCI(PUSHW_1);
1545 BCI(HIGH((hints_record + 1)->size));
1546 BCI(LOW((hints_record + 1)->size));
1548 else
1550 BCI(PUSHB_1);
1551 BCI((hints_record + 1)->size);
1553 BCI(LT);
1554 BCI(IF);
1555 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1556 BCI(ELSE);
1558 hints_record++;
1561 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1563 for (i = 0; i < num_hints_records - 1; i++)
1564 BCI(EIF);
1566 return bufp;
1570 static void
1571 TA_free_hints_records(Hints_Record* hints_records,
1572 FT_UInt num_hints_records)
1574 FT_UInt i;
1577 for (i = 0; i < num_hints_records; i++)
1578 free(hints_records[i].buf);
1580 free(hints_records);
1584 static FT_Byte*
1585 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1586 TA_AxisHints axis,
1587 TA_Edge edge,
1588 FT_UShort* wraps)
1590 TA_Segment segments = axis->segments;
1591 TA_Segment seg;
1592 FT_UShort seg_idx;
1593 FT_UShort num_segs = 0;
1594 FT_UShort* wrap;
1597 seg_idx = edge->first - segments;
1599 /* we store everything as 16bit numbers */
1600 *(bufp++) = HIGH(seg_idx);
1601 *(bufp++) = LOW(seg_idx);
1603 /* wrap-around segments are stored as two segments */
1604 if (edge->first->first > edge->first->last)
1605 num_segs++;
1607 seg = edge->first->edge_next;
1608 while (seg != edge->first)
1610 num_segs++;
1612 if (seg->first > seg->last)
1613 num_segs++;
1615 seg = seg->edge_next;
1618 *(bufp++) = HIGH(num_segs);
1619 *(bufp++) = LOW(num_segs);
1621 if (edge->first->first > edge->first->last)
1623 /* emit second part of wrap-around segment; */
1624 /* the bytecode positions such segments after `normal' ones */
1625 wrap = wraps;
1626 for (;;)
1628 if (seg_idx == *wrap)
1629 break;
1630 wrap++;
1633 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1634 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1637 seg = edge->first->edge_next;
1638 while (seg != edge->first)
1640 seg_idx = seg - segments;
1642 *(bufp++) = HIGH(seg_idx);
1643 *(bufp++) = LOW(seg_idx);
1645 if (seg->first > seg->last)
1647 wrap = wraps;
1648 for (;;)
1650 if (seg_idx == *wrap)
1651 break;
1652 wrap++;
1655 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1656 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1659 seg = seg->edge_next;
1662 return bufp;
1666 static void
1667 TA_hints_recorder(TA_Action action,
1668 TA_GlyphHints hints,
1669 TA_Dimension dim,
1670 void* arg1,
1671 TA_Edge arg2,
1672 TA_Edge arg3,
1673 TA_Edge lower_bound,
1674 TA_Edge upper_bound)
1676 TA_AxisHints axis = &hints->axis[dim];
1677 TA_Edge edges = axis->edges;
1678 TA_Segment segments = axis->segments;
1679 TA_Point points = hints->points;
1681 Recorder* recorder = (Recorder*)hints->user;
1682 SFNT* sfnt = recorder->sfnt;
1683 FONT* font = recorder->font;
1684 FT_UShort* wraps = recorder->wrap_around_segments;
1685 FT_Byte* p = recorder->hints_record.buf;
1687 FT_UInt style = font->loader->metrics->style_class->style;
1690 if (dim == TA_DIMENSION_HORZ)
1691 return;
1693 /* we collect point hints for later processing */
1694 switch (action)
1696 case ta_ip_before:
1698 Node1* before_node;
1699 TA_Point point = (TA_Point)arg1;
1702 before_node = (Node1*)malloc(sizeof (Node1));
1703 if (!before_node)
1704 return;
1705 before_node->point = point - points;
1707 LLRB_INSERT(ip_before_points,
1708 &recorder->ip_before_points_head,
1709 before_node);
1711 return;
1713 case ta_ip_after:
1715 Node1* after_node;
1716 TA_Point point = (TA_Point)arg1;
1719 after_node = (Node1*)malloc(sizeof (Node1));
1720 if (!after_node)
1721 return;
1722 after_node->point = point - points;
1724 LLRB_INSERT(ip_after_points,
1725 &recorder->ip_after_points_head,
1726 after_node);
1728 return;
1730 case ta_ip_on:
1732 Node2* on_node;
1733 TA_Point point = (TA_Point)arg1;
1734 TA_Edge edge = arg2;
1737 on_node = (Node2*)malloc(sizeof (Node2));
1738 if (!on_node)
1739 return;
1740 on_node->edge = edge - edges;
1741 on_node->point = point - points;
1743 LLRB_INSERT(ip_on_points,
1744 &recorder->ip_on_points_head,
1745 on_node);
1747 return;
1749 case ta_ip_between:
1751 Node3* between_node;
1752 TA_Point point = (TA_Point)arg1;
1753 TA_Edge before = arg2;
1754 TA_Edge after = arg3;
1757 between_node = (Node3*)malloc(sizeof (Node3));
1758 if (!between_node)
1759 return;
1760 between_node->before_edge = before - edges;
1761 between_node->after_edge = after - edges;
1762 between_node->point = point - points;
1764 LLRB_INSERT(ip_between_points,
1765 &recorder->ip_between_points_head,
1766 between_node);
1768 return;
1770 case ta_bound:
1771 /* we ignore the BOUND action since we signal this information */
1772 /* with the proper function number */
1773 return;
1775 default:
1776 break;
1779 /* some enum values correspond to four or eight bytecode functions; */
1780 /* if the value is n, the function numbers are n, ..., n+7, */
1781 /* to be differentiated with flags */
1783 switch (action)
1785 case ta_link:
1787 TA_Edge base_edge = (TA_Edge)arg1;
1788 TA_Edge stem_edge = arg2;
1791 *(p++) = 0;
1792 *(p++) = (FT_Byte)action + ACTION_OFFSET
1793 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1794 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1796 *(p++) = HIGH(base_edge->first - segments);
1797 *(p++) = LOW(base_edge->first - segments);
1798 *(p++) = HIGH(stem_edge->first - segments);
1799 *(p++) = LOW(stem_edge->first - segments);
1801 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1803 break;
1805 case ta_anchor:
1807 TA_Edge edge = (TA_Edge)arg1;
1808 TA_Edge edge2 = arg2;
1811 *(p++) = 0;
1812 *(p++) = (FT_Byte)action + ACTION_OFFSET
1813 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1814 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1816 *(p++) = HIGH(edge->first - segments);
1817 *(p++) = LOW(edge->first - segments);
1818 *(p++) = HIGH(edge2->first - segments);
1819 *(p++) = LOW(edge2->first - segments);
1821 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1823 break;
1825 case ta_adjust:
1827 TA_Edge edge = (TA_Edge)arg1;
1828 TA_Edge edge2 = arg2;
1829 TA_Edge edge_minus_one = lower_bound;
1832 *(p++) = 0;
1833 *(p++) = (FT_Byte)action + ACTION_OFFSET
1834 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1835 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1836 + 4 * (edge_minus_one != NULL);
1838 *(p++) = HIGH(edge->first - segments);
1839 *(p++) = LOW(edge->first - segments);
1840 *(p++) = HIGH(edge2->first - segments);
1841 *(p++) = LOW(edge2->first - segments);
1843 if (edge_minus_one)
1845 *(p++) = HIGH(edge_minus_one->first - segments);
1846 *(p++) = LOW(edge_minus_one->first - segments);
1849 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1851 break;
1853 case ta_blue_anchor:
1855 TA_Edge edge = (TA_Edge)arg1;
1856 TA_Edge blue = arg2;
1859 *(p++) = 0;
1860 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1862 *(p++) = HIGH(blue->first - segments);
1863 *(p++) = LOW(blue->first - segments);
1865 if (edge->best_blue_is_shoot)
1867 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1868 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1870 else
1872 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1873 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1876 *(p++) = HIGH(edge->first - segments);
1877 *(p++) = LOW(edge->first - segments);
1879 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1881 break;
1883 case ta_stem:
1885 TA_Edge edge = (TA_Edge)arg1;
1886 TA_Edge edge2 = arg2;
1887 TA_Edge edge_minus_one = lower_bound;
1890 *(p++) = 0;
1891 *(p++) = (FT_Byte)action + ACTION_OFFSET
1892 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1893 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1894 + 4 * (edge_minus_one != NULL);
1896 *(p++) = HIGH(edge->first - segments);
1897 *(p++) = LOW(edge->first - segments);
1898 *(p++) = HIGH(edge2->first - segments);
1899 *(p++) = LOW(edge2->first - segments);
1901 if (edge_minus_one)
1903 *(p++) = HIGH(edge_minus_one->first - segments);
1904 *(p++) = LOW(edge_minus_one->first - segments);
1907 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1908 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1910 break;
1912 case ta_blue:
1914 TA_Edge edge = (TA_Edge)arg1;
1917 *(p++) = 0;
1918 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1920 if (edge->best_blue_is_shoot)
1922 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1923 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1925 else
1927 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1928 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1931 *(p++) = HIGH(edge->first - segments);
1932 *(p++) = LOW(edge->first - segments);
1934 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1936 break;
1938 case ta_serif:
1940 TA_Edge serif = (TA_Edge)arg1;
1941 TA_Edge base = serif->serif;
1944 *(p++) = 0;
1945 *(p++) = (FT_Byte)action + ACTION_OFFSET
1946 + (lower_bound != NULL)
1947 + 2 * (upper_bound != NULL);
1949 *(p++) = HIGH(serif->first - segments);
1950 *(p++) = LOW(serif->first - segments);
1951 *(p++) = HIGH(base->first - segments);
1952 *(p++) = LOW(base->first - segments);
1954 if (lower_bound)
1956 *(p++) = HIGH(lower_bound->first - segments);
1957 *(p++) = LOW(lower_bound->first - segments);
1959 if (upper_bound)
1961 *(p++) = HIGH(upper_bound->first - segments);
1962 *(p++) = LOW(upper_bound->first - segments);
1965 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1967 break;
1969 case ta_serif_anchor:
1970 case ta_serif_link2:
1972 TA_Edge edge = (TA_Edge)arg1;
1975 *(p++) = 0;
1976 *(p++) = (FT_Byte)action + ACTION_OFFSET
1977 + (lower_bound != NULL)
1978 + 2 * (upper_bound != NULL);
1980 *(p++) = HIGH(edge->first - segments);
1981 *(p++) = LOW(edge->first - segments);
1983 if (lower_bound)
1985 *(p++) = HIGH(lower_bound->first - segments);
1986 *(p++) = LOW(lower_bound->first - segments);
1988 if (upper_bound)
1990 *(p++) = HIGH(upper_bound->first - segments);
1991 *(p++) = LOW(upper_bound->first - segments);
1994 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1996 break;
1998 case ta_serif_link1:
2000 TA_Edge edge = (TA_Edge)arg1;
2001 TA_Edge before = arg2;
2002 TA_Edge after = arg3;
2005 *(p++) = 0;
2006 *(p++) = (FT_Byte)action + ACTION_OFFSET
2007 + (lower_bound != NULL)
2008 + 2 * (upper_bound != NULL);
2010 *(p++) = HIGH(before->first - segments);
2011 *(p++) = LOW(before->first - segments);
2012 *(p++) = HIGH(edge->first - segments);
2013 *(p++) = LOW(edge->first - segments);
2014 *(p++) = HIGH(after->first - segments);
2015 *(p++) = LOW(after->first - segments);
2017 if (lower_bound)
2019 *(p++) = HIGH(lower_bound->first - segments);
2020 *(p++) = LOW(lower_bound->first - segments);
2022 if (upper_bound)
2024 *(p++) = HIGH(upper_bound->first - segments);
2025 *(p++) = LOW(upper_bound->first - segments);
2028 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2030 break;
2032 default:
2033 /* there are more cases in the enumeration */
2034 /* which are handled with flags */
2035 break;
2038 recorder->hints_record.num_actions++;
2039 recorder->hints_record.buf = p;
2043 static FT_Error
2044 TA_init_recorder(Recorder* recorder,
2045 SFNT* sfnt,
2046 FONT* font,
2047 GLYPH* glyph,
2048 TA_GlyphHints hints)
2050 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2051 TA_Point points = hints->points;
2052 TA_Point point_limit = points + hints->num_points;
2053 TA_Point point;
2055 TA_Segment segments = axis->segments;
2056 TA_Segment seg_limit = segments + axis->num_segments;
2057 TA_Segment seg;
2059 FT_UShort num_strong_points = 0;
2060 FT_UShort* wrap_around_segment;
2062 recorder->sfnt = sfnt;
2063 recorder->font = font;
2064 recorder->glyph = glyph;
2065 recorder->num_segments = axis->num_segments;
2067 LLRB_INIT(&recorder->ip_before_points_head);
2068 LLRB_INIT(&recorder->ip_after_points_head);
2069 LLRB_INIT(&recorder->ip_on_points_head);
2070 LLRB_INIT(&recorder->ip_between_points_head);
2072 recorder->num_stack_elements = 0;
2074 /* no need to clean up allocated arrays in case of error; */
2075 /* this is handled later by `TA_free_recorder' */
2077 recorder->num_wrap_around_segments = 0;
2078 for (seg = segments; seg < seg_limit; seg++)
2079 if (seg->first > seg->last)
2080 recorder->num_wrap_around_segments++;
2082 recorder->wrap_around_segments =
2083 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2084 * sizeof (FT_UShort));
2085 if (!recorder->wrap_around_segments)
2086 return FT_Err_Out_Of_Memory;
2088 wrap_around_segment = recorder->wrap_around_segments;
2089 for (seg = segments; seg < seg_limit; seg++)
2090 if (seg->first > seg->last)
2091 *(wrap_around_segment++) = seg - segments;
2093 /* get number of strong points */
2094 for (point = points; point < point_limit; point++)
2096 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2097 /* however, this value isn't known yet */
2098 /* (or rather, it can vary between different pixel sizes) */
2099 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
2100 continue;
2102 num_strong_points++;
2105 recorder->num_strong_points = num_strong_points;
2107 return FT_Err_Ok;
2111 static void
2112 TA_reset_recorder(Recorder* recorder,
2113 FT_Byte* bufp)
2115 recorder->hints_record.buf = bufp;
2116 recorder->hints_record.num_actions = 0;
2120 static void
2121 TA_rewind_recorder(Recorder* recorder,
2122 FT_Byte* bufp,
2123 FT_UInt size)
2125 Node1* before_node;
2126 Node1* after_node;
2127 Node2* on_node;
2128 Node3* between_node;
2130 Node1* next_before_node;
2131 Node1* next_after_node;
2132 Node2* next_on_node;
2133 Node3* next_between_node;
2136 TA_reset_recorder(recorder, bufp);
2138 recorder->hints_record.size = size;
2140 /* deallocate our red-black trees */
2142 for (before_node = LLRB_MIN(ip_before_points,
2143 &recorder->ip_before_points_head);
2144 before_node;
2145 before_node = next_before_node)
2147 next_before_node = LLRB_NEXT(ip_before_points,
2148 &recorder->ip_before_points_head,
2149 before_node);
2150 LLRB_REMOVE(ip_before_points,
2151 &recorder->ip_before_points_head,
2152 before_node);
2153 free(before_node);
2156 for (after_node = LLRB_MIN(ip_after_points,
2157 &recorder->ip_after_points_head);
2158 after_node;
2159 after_node = next_after_node)
2161 next_after_node = LLRB_NEXT(ip_after_points,
2162 &recorder->ip_after_points_head,
2163 after_node);
2164 LLRB_REMOVE(ip_after_points,
2165 &recorder->ip_after_points_head,
2166 after_node);
2167 free(after_node);
2170 for (on_node = LLRB_MIN(ip_on_points,
2171 &recorder->ip_on_points_head);
2172 on_node;
2173 on_node = next_on_node)
2175 next_on_node = LLRB_NEXT(ip_on_points,
2176 &recorder->ip_on_points_head,
2177 on_node);
2178 LLRB_REMOVE(ip_on_points,
2179 &recorder->ip_on_points_head,
2180 on_node);
2181 free(on_node);
2184 for (between_node = LLRB_MIN(ip_between_points,
2185 &recorder->ip_between_points_head);
2186 between_node;
2187 between_node = next_between_node)
2189 next_between_node = LLRB_NEXT(ip_between_points,
2190 &recorder->ip_between_points_head,
2191 between_node);
2192 LLRB_REMOVE(ip_between_points,
2193 &recorder->ip_between_points_head,
2194 between_node);
2195 free(between_node);
2200 static void
2201 TA_free_recorder(Recorder* recorder)
2203 free(recorder->wrap_around_segments);
2205 TA_rewind_recorder(recorder, NULL, 0);
2209 FT_Error
2210 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2211 FONT* font,
2212 FT_Long idx)
2214 FT_Face face = sfnt->face;
2215 FT_Error error;
2217 FT_Byte* ins_buf;
2218 FT_UInt ins_len;
2219 FT_Byte* bufp;
2220 FT_Byte* p;
2222 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2223 glyf_Data* data = (glyf_Data*)glyf_table->data;
2224 /* `idx' is never negative */
2225 GLYPH* glyph = &data->glyphs[idx];
2227 TA_GlyphHints hints;
2229 FT_UInt num_action_hints_records = 0;
2230 FT_UInt num_point_hints_records = 0;
2231 Hints_Record* action_hints_records = NULL;
2232 Hints_Record* point_hints_records = NULL;
2234 Recorder recorder;
2235 FT_UShort num_stack_elements;
2236 FT_Bool optimize = 0;
2238 FT_Int32 load_flags;
2239 FT_UInt size;
2241 FT_Byte* pos[3];
2243 #ifdef TA_DEBUG
2244 int _ta_debug_save;
2245 #endif
2248 /* XXX: right now, we abuse this flag to control */
2249 /* the global behaviour of the auto-hinter */
2250 load_flags = 1 << 29; /* vertical hinting only */
2251 if (!font->adjust_subglyphs)
2253 if (font->hint_composites)
2254 load_flags |= FT_LOAD_NO_SCALE;
2255 else
2256 load_flags |= FT_LOAD_NO_RECURSE;
2259 /* computing the segments is resolution independent, */
2260 /* thus the pixel size in this call is arbitrary -- */
2261 /* however, we avoid unnecessary debugging output */
2262 /* if we use the lowest value of the hinting range */
2263 error = FT_Set_Pixel_Sizes(face,
2264 font->hinting_range_min,
2265 font->hinting_range_min);
2266 if (error)
2267 return error;
2269 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2270 /* to modify `out' directions of points at the user's request */
2271 error = TA_control_point_dir_collect(font, face->face_index, idx);
2272 if (error)
2273 return error;
2275 #ifdef TA_DEBUG
2276 /* temporarily disable some debugging output */
2277 /* to avoid getting the information twice */
2278 _ta_debug_save = _ta_debug;
2279 _ta_debug = 0;
2280 #endif
2282 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2283 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2285 #ifdef TA_DEBUG
2286 _ta_debug = _ta_debug_save;
2287 #endif
2289 if (error)
2290 return error;
2292 /* do nothing if we have an empty glyph */
2293 if (!face->glyph->outline.n_contours)
2294 return FT_Err_Ok;
2296 hints = &font->loader->hints;
2298 /* do nothing if the setup delivered the `none_dflt' style only */
2299 if (!hints->num_points)
2300 return FT_Err_Ok;
2303 * We allocate a buffer which is certainly large enough
2304 * to hold all of the created bytecode instructions;
2305 * later on it gets reallocated to its real size.
2307 * The value `1000' is a very rough guess, not tested well.
2309 * For delta exceptions, we have three DELTA commands,
2310 * covering 3*16 ppem values.
2311 * Since a point index can be larger than 255,
2312 * we assume two bytes everywhere for the necessary PUSH calls.
2313 * This value must be doubled for the other arguments of DELTA.
2314 * Additionally, we have both x and y deltas,
2315 * which need to be handled separately in the bytecode.
2316 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2317 * adding some bytes for the necessary overhead.
2319 ins_len = hints->num_points
2320 * (1000 + ((font->control_data_head != NULL) ? 400 : 0));
2321 ins_buf = (FT_Byte*)malloc(ins_len);
2322 if (!ins_buf)
2323 return FT_Err_Out_Of_Memory;
2325 /* handle composite glyph */
2326 if (font->loader->gloader->base.num_subglyphs)
2328 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2329 if (!bufp)
2331 error = FT_Err_Out_Of_Memory;
2332 goto Err;
2335 goto Done1;
2338 /* only scale the glyph if the `none_dflt' style has been used */
2339 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
2341 /* since `TA_init_recorder' hasn't been called yet, */
2342 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2343 recorder.sfnt = sfnt;
2344 recorder.font = font;
2345 recorder.glyph = glyph;
2347 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2348 if (!bufp)
2350 error = FT_Err_Out_Of_Memory;
2351 goto Err;
2354 goto Done1;
2357 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2358 if (error)
2359 goto Err;
2361 /* loop over a large range of pixel sizes */
2362 /* to find hints records which get pushed onto the bytecode stack */
2364 #ifdef DEBUGGING
2365 if (font->debug)
2367 int num_chars, i;
2368 char buf[256];
2371 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
2373 num_chars = fprintf(stderr, "glyph %ld", idx);
2374 if (*buf)
2375 num_chars += fprintf(stderr, " (%s)", buf);
2376 fprintf(stderr, "\n");
2377 for (i = 0; i < num_chars; i++)
2378 putc('=', stderr);
2379 fprintf(stderr, "\n\n");
2382 #endif
2384 /* we temporarily use `ins_buf' to record the current glyph hints */
2385 ta_loader_register_hints_recorder(font->loader,
2386 TA_hints_recorder,
2387 (void*)&recorder);
2389 for (size = font->hinting_range_min;
2390 size <= font->hinting_range_max;
2391 size++)
2393 #ifdef DEBUGGING
2394 int have_dumps = 0;
2395 #endif
2398 TA_rewind_recorder(&recorder, ins_buf, size);
2400 error = FT_Set_Pixel_Sizes(face, size, size);
2401 if (error)
2402 goto Err;
2404 #ifdef DEBUGGING
2405 if (font->debug)
2407 int num_chars, i;
2410 num_chars = fprintf(stderr, "size %d\n", size);
2411 for (i = 0; i < num_chars - 1; i++)
2412 putc('-', stderr);
2413 fprintf(stderr, "\n\n");
2415 #endif
2417 /* calling `ta_loader_load_glyph' uses the */
2418 /* `TA_hints_recorder' function as a callback, */
2419 /* modifying `hints_record' */
2420 error = ta_loader_load_glyph(font, face, idx, load_flags);
2421 if (error)
2422 goto Err;
2424 if (TA_hints_record_is_different(action_hints_records,
2425 num_action_hints_records,
2426 ins_buf, recorder.hints_record.buf))
2428 #ifdef DEBUGGING
2429 if (font->debug)
2431 have_dumps = 1;
2433 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2434 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2435 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2437 fprintf(stderr, "action hints record:\n");
2438 if (ins_buf == recorder.hints_record.buf)
2439 fprintf(stderr, " (none)");
2440 else
2442 fprintf(stderr, " ");
2443 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2444 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2446 fprintf(stderr, "\n");
2448 #endif
2450 error = TA_add_hints_record(&action_hints_records,
2451 &num_action_hints_records,
2452 ins_buf, recorder.hints_record);
2453 if (error)
2454 goto Err;
2457 /* now handle point records */
2459 TA_reset_recorder(&recorder, ins_buf);
2461 /* use the point hints data collected in `TA_hints_recorder' */
2462 TA_build_point_hints(&recorder, hints);
2464 if (TA_hints_record_is_different(point_hints_records,
2465 num_point_hints_records,
2466 ins_buf, recorder.hints_record.buf))
2468 #ifdef DEBUGGING
2469 if (font->debug)
2471 if (!have_dumps)
2473 int num_chars, i;
2476 num_chars = fprintf(stderr, "size %d\n", size);
2477 for (i = 0; i < num_chars - 1; i++)
2478 putc('-', stderr);
2479 fprintf(stderr, "\n\n");
2481 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2482 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2483 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2486 fprintf(stderr, "point hints record:\n");
2487 if (ins_buf == recorder.hints_record.buf)
2488 fprintf(stderr, " (none)");
2489 else
2491 fprintf(stderr, " ");
2492 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2493 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2495 fprintf(stderr, "\n\n");
2497 #endif
2499 error = TA_add_hints_record(&point_hints_records,
2500 &num_point_hints_records,
2501 ins_buf, recorder.hints_record);
2502 if (error)
2503 goto Err;
2507 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2509 /* since we only have a single empty record we just scale the glyph */
2510 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2511 if (!bufp)
2513 error = FT_Err_Out_Of_Memory;
2514 goto Err;
2517 goto Done;
2520 /* if there is only a single record, */
2521 /* we do a global optimization later on */
2522 if (num_action_hints_records > 1)
2523 optimize = 1;
2525 /* store the hints records and handle stack depth */
2526 pos[0] = ins_buf;
2527 bufp = TA_emit_hints_records(&recorder,
2528 point_hints_records,
2529 num_point_hints_records,
2530 ins_buf,
2531 optimize);
2533 num_stack_elements = recorder.num_stack_elements;
2534 recorder.num_stack_elements = 0;
2536 pos[1] = bufp;
2537 bufp = TA_emit_hints_records(&recorder,
2538 action_hints_records,
2539 num_action_hints_records,
2540 bufp,
2541 optimize);
2543 recorder.num_stack_elements += num_stack_elements;
2545 pos[2] = bufp;
2546 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2547 if (!bufp)
2549 error = FT_Err_Out_Of_Memory;
2550 goto Err;
2553 if (num_action_hints_records == 1)
2554 bufp = TA_optimize_push(ins_buf, pos);
2556 Done:
2557 TA_free_hints_records(action_hints_records, num_action_hints_records);
2558 TA_free_hints_records(point_hints_records, num_point_hints_records);
2559 TA_free_recorder(&recorder);
2561 Done1:
2562 /* handle delta exceptions */
2563 if (font->control_data_head)
2565 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
2566 if (!bufp)
2568 error = FT_Err_Out_Of_Memory;
2569 goto Err;
2573 ins_len = bufp - ins_buf;
2575 if (ins_len > sfnt->max_instructions)
2576 sfnt->max_instructions = ins_len;
2578 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2579 glyph->ins_len = ins_len;
2581 return FT_Err_Ok;
2583 Err:
2584 TA_free_hints_records(action_hints_records, num_action_hints_records);
2585 TA_free_hints_records(point_hints_records, num_point_hints_records);
2586 TA_free_recorder(&recorder);
2587 free(ins_buf);
2589 return error;
2593 /* end of tabytecode.c */