Synchronize with FreeType [4/4].
[ttfautohint.git] / lib / tabytecode.c
blob5193174e62e17cd6727efdadb6764ecb3c6a73ca
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2015 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 y delta exceptions before IUP_y, this code gets inserted */
185 FT_Byte ins_extra_buf[4] =
188 /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
189 PUSHB_2,
190 cvtl_do_iup_y,
192 WCVTP,
198 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
199 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
200 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
201 * PUSHW_X gets used
204 FT_Byte*
205 TA_build_push(FT_Byte* bufp,
206 FT_UInt* args,
207 FT_UInt num_args,
208 FT_Bool need_words,
209 FT_Bool optimize)
211 FT_UInt* arg = args;
212 FT_UInt i, j, nargs;
215 if (need_words)
217 for (i = 0; i < num_args; i += 255)
219 nargs = (num_args - i > 255) ? 255 : num_args - i;
221 if (optimize && nargs <= 8)
222 BCI(PUSHW_1 - 1 + nargs);
223 else
225 BCI(NPUSHW);
226 BCI(nargs);
228 for (j = 0; j < nargs; j++)
230 BCI(HIGH(*arg));
231 BCI(LOW(*arg));
232 arg++;
236 else
238 for (i = 0; i < num_args; i += 255)
240 nargs = (num_args - i > 255) ? 255 : num_args - i;
242 if (optimize && nargs <= 8)
243 BCI(PUSHB_1 - 1 + nargs);
244 else
246 BCI(NPUSHB);
247 BCI(nargs);
249 for (j = 0; j < nargs; j++)
251 BCI(*arg);
252 arg++;
257 return bufp;
262 * We optimize two common cases, replacing
264 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
266 * with
268 * NPUSHB (A+B[+C]) ... CALL
270 * if possible
273 FT_Byte*
274 TA_optimize_push(FT_Byte* buf,
275 FT_Byte** pos)
277 FT_Byte sizes[3];
278 FT_Byte new_size1;
279 FT_Byte new_size2;
281 FT_UInt sum;
282 FT_UInt i;
283 FT_UInt pos_idx;
285 FT_Byte* p;
286 FT_Byte* bufp;
289 /* XXX improve handling of NPUSHW */
290 if (*(pos[0]) == NPUSHW
291 || *(pos[1]) == NPUSHW
292 || *(pos[2]) == NPUSHW)
293 return buf;
295 /* the point hints records block can be missing */
296 if (pos[0] == pos[1])
298 pos[1] = pos[2];
299 pos[2] = NULL;
302 /* there are at least two NPUSHB instructions */
303 /* (one of them directly at the start) */
304 sizes[0] = *(pos[0] + 1);
305 sizes[1] = *(pos[1] + 1);
306 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
308 sum = sizes[0] + sizes[1] + sizes[2];
310 if (sum > 2 * 0xFF)
311 return buf; /* nothing to do since we need three NPUSHB */
312 else if (!sizes[2] && (sum > 0xFF))
313 return buf; /* nothing to do since we need two NPUSHB */
315 if (sum > 0xFF)
317 /* reduce three NPUSHB to two */
318 new_size1 = 0xFF;
319 new_size2 = sum - 0xFF;
321 else
323 /* reduce two or three NPUSHB to one */
324 new_size1 = sum;
325 new_size2 = 0;
328 /* pack data */
329 p = buf;
330 bufp = buf;
331 pos_idx = 0;
333 if (new_size1 <= 8)
334 BCI(PUSHB_1 - 1 + new_size1);
335 else
337 BCI(NPUSHB);
338 BCI(new_size1);
340 for (i = 0; i < new_size1; i++)
342 if (p == pos[pos_idx])
344 pos_idx++;
345 p += 2; /* skip old NPUSHB */
347 *(bufp++) = *(p++);
350 if (new_size2)
352 if (new_size2 <= 8)
353 BCI(PUSHB_1 - 1 + new_size2);
354 else
356 BCI(NPUSHB);
357 BCI(new_size2);
359 for (i = 0; i < new_size2; i++)
361 if (p == pos[pos_idx])
363 pos_idx++;
364 p += 2;
366 *(bufp++) = *(p++);
370 BCI(CALL);
372 return bufp;
376 /* We add a subglyph for each composite glyph. */
377 /* Since subglyphs must contain at least one point, */
378 /* we have to adjust all point indices accordingly. */
379 /* Using the `pointsums' array of the `GLYPH' structure */
380 /* it is straightforward to do that: */
381 /* Assuming that point with index x is in the interval */
382 /* pointsums[n] <= x < pointsums[n + 1], */
383 /* the new point index is x + n. */
385 static FT_UInt
386 TA_adjust_point_index(Recorder* recorder,
387 FT_UInt idx)
389 FONT* font = recorder->font;
390 GLYPH* glyph = recorder->glyph;
391 FT_UShort i;
394 if (!glyph->num_components || !font->hint_composites)
395 return idx; /* not a composite glyph */
397 for (i = 0; i < glyph->num_pointsums; i++)
398 if (idx < glyph->pointsums[i])
399 break;
401 return idx + i;
405 /* we store the segments in the storage area; */
406 /* each segment record consists of the first and last point */
408 static FT_Byte*
409 TA_sfnt_build_glyph_segments(SFNT* sfnt,
410 Recorder* recorder,
411 FT_Byte* bufp,
412 FT_Bool optimize)
414 FONT* font = recorder->font;
415 TA_GlyphHints hints = &font->loader->hints;
416 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
417 TA_Point points = hints->points;
418 TA_Segment segments = axis->segments;
419 TA_Segment seg;
420 TA_Segment seg_limit;
422 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
423 glyf_Data* data = (glyf_Data*)glyf_table->data;
425 FT_UInt style_id = data->style_ids
426 [font->loader->metrics->style_class->style];
428 FT_Outline outline = font->loader->gloader->base.outline;
430 FT_UInt* args;
431 FT_UInt* arg;
432 FT_UInt num_args;
433 FT_UShort num_segments;
435 FT_Bool need_words = 0;
437 FT_Int n;
438 FT_UInt base;
439 FT_UShort num_packed_segments;
440 FT_UShort num_storage;
441 FT_UShort num_stack_elements;
442 FT_UShort num_twilight_points;
445 seg_limit = segments + axis->num_segments;
446 num_segments = axis->num_segments;
448 /* to pack the data in the bytecode more tightly, */
449 /* we store up to the first nine segments in nibbles if possible, */
450 /* using delta values */
451 base = 0;
452 num_packed_segments = 0;
453 for (seg = segments; seg < seg_limit; seg++)
455 FT_UInt first = seg->first - points;
456 FT_UInt last = seg->last - points;
459 first = TA_adjust_point_index(recorder, first);
460 last = TA_adjust_point_index(recorder, last);
462 if (first - base >= 16)
463 break;
464 if (first > last || last - first >= 16)
465 break;
466 if (num_packed_segments == 9)
467 break;
468 num_packed_segments++;
469 base = last;
472 /* also handle wrap-around segments */
473 num_segments += recorder->num_wrap_around_segments;
475 /* wrap-around segments are pushed with four arguments; */
476 /* a segment stored in nibbles needs only one byte instead of two */
477 num_args = num_packed_segments
478 + 2 * (num_segments - num_packed_segments)
479 + 2 * recorder->num_wrap_around_segments
480 + 3;
482 /* collect all arguments temporarily in an array (in reverse order) */
483 /* so that we can easily split into chunks of 255 args */
484 /* as needed by NPUSHB and NPUSHW, respectively */
485 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
486 if (!args)
487 return NULL;
489 arg = args + num_args - 1;
491 if (num_segments > 0xFF)
492 need_words = 1;
494 /* the number of packed segments is indicated by the function number */
495 if (recorder->glyph->num_components && font->hint_composites)
496 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
497 else
498 *(arg--) = bci_create_segments_0 + num_packed_segments;
500 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
501 *(arg--) = num_segments;
503 base = 0;
504 for (seg = segments; seg < segments + num_packed_segments; seg++)
506 FT_UInt first = seg->first - points;
507 FT_UInt last = seg->last - points;
508 FT_UInt low_nibble;
509 FT_UInt high_nibble;
512 first = TA_adjust_point_index(recorder, first);
513 last = TA_adjust_point_index(recorder, last);
515 low_nibble = first - base;
516 high_nibble = last - first;
518 *(arg--) = 16 * high_nibble + low_nibble;
520 base = last;
523 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
525 FT_UInt first = seg->first - points;
526 FT_UInt last = seg->last - points;
529 *(arg--) = TA_adjust_point_index(recorder, first);
530 *(arg--) = TA_adjust_point_index(recorder, last);
532 /* we push the last and first contour point */
533 /* as a third and fourth argument in wrap-around segments */
534 if (first > last)
536 for (n = 0; n < outline.n_contours; n++)
538 FT_UInt end = (FT_UInt)outline.contours[n];
541 if (first <= end)
543 *(arg--) = TA_adjust_point_index(recorder, end);
544 if (end > 0xFF)
545 need_words = 1;
547 if (n == 0)
548 *(arg--) = TA_adjust_point_index(recorder, 0);
549 else
550 *(arg--) = TA_adjust_point_index(recorder,
551 (FT_UInt)outline.contours[n - 1] + 1);
552 break;
557 if (last > 0xFF)
558 need_words = 1;
561 /* emit the second part of wrap-around segments as separate segments */
562 /* so that edges can easily link to them */
563 for (seg = segments; seg < seg_limit; seg++)
565 FT_UInt first = seg->first - points;
566 FT_UInt last = seg->last - points;
569 if (first > last)
571 for (n = 0; n < outline.n_contours; n++)
573 if (first <= (FT_UInt)outline.contours[n])
575 if (n == 0)
576 *(arg--) = TA_adjust_point_index(recorder, 0);
577 else
578 *(arg--) = TA_adjust_point_index(recorder,
579 (FT_UInt)outline.contours[n - 1] + 1);
580 break;
584 *(arg--) = TA_adjust_point_index(recorder, last);
588 /* with most fonts it is very rare */
589 /* that any of the pushed arguments is larger than 0xFF, */
590 /* thus we refrain from further optimizing this case */
591 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
593 BCI(CALL);
595 num_storage = sal_segment_offset + num_segments * 2;
596 if (num_storage > sfnt->max_storage)
597 sfnt->max_storage = num_storage;
599 num_twilight_points = num_segments * 2;
600 if (num_twilight_points > sfnt->max_twilight_points)
601 sfnt->max_twilight_points = num_twilight_points;
603 /* both this function and `TA_emit_hints_record' */
604 /* push data onto the stack */
605 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
606 + recorder->num_stack_elements + num_args;
607 if (num_stack_elements > sfnt->max_stack_elements)
608 sfnt->max_stack_elements = num_stack_elements;
610 free(args);
612 return bufp;
616 static void
617 build_delta_exception(const Ctrl* ctrl,
618 FT_UInt** delta_args,
619 int* num_delta_args)
621 int offset;
622 int ppem;
623 int x_shift;
624 int y_shift;
627 ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
629 if (ppem < 16)
630 offset = 0;
631 else if (ppem < 32)
632 offset = 1;
633 else
634 offset = 2;
636 ppem -= offset << 4;
639 * Using
641 * delta_shift = 3 ,
643 * the possible shift values in the instructions are indexed as follows:
645 * 0 -1px
646 * 1 -7/8px
647 * ...
648 * 7 -1/8px
649 * 8 1/8px
650 * ...
651 * 14 7/8px
652 * 15 1px
654 * (note that there is no index for a zero shift).
657 if (ctrl->x_shift < 0)
658 x_shift = ctrl->x_shift + 8;
659 else
660 x_shift = ctrl->x_shift + 7;
662 if (ctrl->y_shift < 0)
663 y_shift = ctrl->y_shift + 8;
664 else
665 y_shift = ctrl->y_shift + 7;
667 /* add point index and exception specification to appropriate stack */
668 if (ctrl->x_shift)
670 *(delta_args[offset] + num_delta_args[offset]++) =
671 (ppem << 4) + x_shift;
672 *(delta_args[offset] + num_delta_args[offset]++) =
673 ctrl->point_idx;
676 if (ctrl->y_shift)
678 offset += 3;
679 *(delta_args[offset] + num_delta_args[offset]++) =
680 (ppem << 4) + y_shift;
681 *(delta_args[offset] + num_delta_args[offset]++) =
682 ctrl->point_idx;
687 static FT_Byte*
688 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
689 FONT* font,
690 FT_Long idx,
691 FT_Byte* bufp)
693 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
694 glyf_Data* data = (glyf_Data*)glyf_table->data;
695 GLYPH* glyph = &data->glyphs[idx];
697 FT_Face face = font->loader->face;
699 int num_points;
700 int i;
702 FT_UShort num_before_IUP_stack_elements;
703 FT_UShort num_after_IUP_stack_elements;
705 /* DELTAP[1-3] stacks for both x and y directions */
706 FT_UInt* delta_before_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
707 FT_UInt* delta_after_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
708 int num_delta_before_IUP_args[6] = {0, 0, 0, 0, 0, 0};
709 int num_delta_after_IUP_args[6] = {0, 0, 0, 0, 0, 0};
710 FT_UInt* args = NULL;
712 FT_Bool need_before_IUP_words = 0;
713 FT_Bool need_after_IUP_words = 0;
714 FT_Bool need_before_IUP_word_counts = 0;
715 FT_Bool need_after_IUP_word_counts = 0;
716 FT_Bool allocated_before_IUP = 0;
717 FT_Bool allocated_after_IUP = 0;
720 num_points = font->loader->gloader->base.outline.n_points;
722 /* loop over all fitting control instructions */
723 for (;;)
725 const Ctrl* ctrl = TA_control_get_ctrl(font);
728 if (!ctrl)
729 break;
731 /* check type */
732 if (!(ctrl->type == Control_Delta_before_IUP
733 || ctrl->type == Control_Delta_after_IUP))
734 break;
736 /* too large values of font and glyph indices in `ctrl' */
737 /* are handled by later calls of this function */
738 if (face->face_index < ctrl->font_idx
739 || idx < ctrl->glyph_idx)
740 break;
742 if (ctrl->type == Control_Delta_before_IUP
743 && !allocated_before_IUP)
745 for (i = 0; i < 6; i++)
747 /* see the comment on allocating `ins_buf' in function */
748 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
749 /* we have to increase by 2 to push the number of argument pairs */
750 /* and the function for a LOOPCALL instruction */
751 delta_before_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 2)
752 * sizeof (FT_UInt));
753 if (!delta_before_IUP_args[i])
755 bufp = NULL;
756 goto Done;
760 allocated_before_IUP = 1;
763 if (ctrl->type == Control_Delta_after_IUP
764 && !allocated_after_IUP)
766 for (i = 0; i < 6; i++)
768 /* we have to increase by 1 for the number of argument pairs */
769 /* as needed by the DELTA instructions */
770 delta_after_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
771 * sizeof (FT_UInt));
772 if (!delta_after_IUP_args[i])
774 bufp = NULL;
775 goto Done;
779 allocated_after_IUP = 1;
782 /* since we walk sequentially over all glyphs (with points), */
783 /* and the control instruction entries have the same order, */
784 /* we don't need to test for equality of font and glyph indices: */
785 /* at this very point in the code we certainly have a hit */
786 if (ctrl->type == Control_Delta_before_IUP)
788 build_delta_exception(ctrl,
789 delta_before_IUP_args,
790 num_delta_before_IUP_args);
792 if (ctrl->point_idx > 255)
793 need_before_IUP_words = 1;
795 else
797 build_delta_exception(ctrl,
798 delta_after_IUP_args,
799 num_delta_after_IUP_args);
801 if (ctrl->point_idx > 255)
802 need_after_IUP_words = 1;
805 TA_control_get_next(font);
808 /* nothing to do if no control instructions */
809 if (!(allocated_before_IUP || allocated_after_IUP))
810 return bufp;
812 /* add number of argument pairs and function number to the stacks */
813 for (i = 0; i < 6; i++)
815 if (num_delta_before_IUP_args[i])
817 int n = num_delta_before_IUP_args[i] >> 1;
820 if (n > 255)
821 need_before_IUP_word_counts = 1;
823 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) = n;
824 num_delta_before_IUP_args[i]++;
826 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) =
827 bci_deltap1 + (i % 3);
828 num_delta_before_IUP_args[i]++;
832 /* add number of argument pairs to the stacks */
833 for (i = 0; i < 6; i++)
835 if (num_delta_after_IUP_args[i])
837 int n = num_delta_after_IUP_args[i] >> 1;
840 if (n > 255)
841 need_after_IUP_word_counts = 1;
843 *(delta_after_IUP_args[i] + num_delta_after_IUP_args[i]) = n;
844 num_delta_after_IUP_args[i]++;
848 /* merge `before IUP' delta stacks into a single one */
849 if (need_before_IUP_words
850 || (!need_before_IUP_words && !need_before_IUP_word_counts))
852 FT_UInt num_args = 0;
855 for (i = 0; i < 6; i++)
857 FT_UInt* args_new;
858 FT_UInt num_args_new;
861 if (!num_delta_before_IUP_args[i])
862 continue;
864 num_args_new = num_args + num_delta_before_IUP_args[i];
865 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
866 if (!args_new)
868 bufp = NULL;
869 goto Done;
872 memcpy(args_new + num_args,
873 delta_before_IUP_args[i],
874 num_delta_before_IUP_args[i] * sizeof (FT_UInt));
876 args = args_new;
877 num_args = num_args_new;
880 num_before_IUP_stack_elements = num_args;
882 bufp = TA_build_push(bufp, args, num_args, need_before_IUP_words, 1);
884 else
886 num_before_IUP_stack_elements = 0;
888 /* stack elements are bytes, but counts need words */
889 for (i = 0; i < 6; i++)
891 int num_delta_arg;
894 if (!num_delta_before_IUP_args[i])
895 continue;
897 num_delta_arg = num_delta_before_IUP_args[i] - 2;
899 bufp = TA_build_push(bufp,
900 delta_before_IUP_args[i],
901 num_delta_arg,
902 need_before_IUP_words,
905 num_before_IUP_stack_elements += num_delta_arg + 2;
907 num_delta_arg >>= 1;
908 BCI(PUSHW_1);
909 BCI(HIGH(num_delta_arg));
910 BCI(LOW(num_delta_arg));
912 /* the function number */
913 BCI(PUSHB_1);
914 BCI(delta_before_IUP_args[i][num_delta_before_IUP_args[i] - 1]);
918 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
919 if (num_delta_before_IUP_args[5])
920 BCI(LOOPCALL);
921 if (num_delta_before_IUP_args[4])
922 BCI(LOOPCALL);
923 if (num_delta_before_IUP_args[3])
924 BCI(LOOPCALL);
926 if (num_delta_before_IUP_args[2]
927 || num_delta_before_IUP_args[1]
928 || num_delta_before_IUP_args[0])
929 BCI(SVTCA_x);
931 /* emit x DELTA opcodes */
932 if (num_delta_before_IUP_args[2])
933 BCI(LOOPCALL);
934 if (num_delta_before_IUP_args[1])
935 BCI(LOOPCALL);
936 if (num_delta_before_IUP_args[0])
937 BCI(LOOPCALL);
939 if (num_delta_before_IUP_args[2]
940 || num_delta_before_IUP_args[1]
941 || num_delta_before_IUP_args[0])
942 BCI(SVTCA_y);
944 if (num_delta_before_IUP_args[5]
945 || num_delta_before_IUP_args[4]
946 || num_delta_before_IUP_args[3])
947 BCI(IUP_y);
949 /* merge `after IUP' delta stacks into a single one */
950 if (need_after_IUP_words
951 || (!need_after_IUP_words && !need_after_IUP_word_counts))
953 FT_UInt num_args = 0;
956 for (i = 0; i < 6; i++)
958 FT_UInt* args_new;
959 FT_UInt num_args_new;
962 if (!num_delta_after_IUP_args[i])
963 continue;
965 num_args_new = num_args + num_delta_after_IUP_args[i];
966 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
967 if (!args_new)
969 bufp = NULL;
970 goto Done;
973 memcpy(args_new + num_args,
974 delta_after_IUP_args[i],
975 num_delta_after_IUP_args[i] * sizeof (FT_UInt));
977 args = args_new;
978 num_args = num_args_new;
981 num_after_IUP_stack_elements = num_args;
983 bufp = TA_build_push(bufp, args, num_args, need_after_IUP_words, 1);
985 else
987 num_after_IUP_stack_elements = 0;
989 /* stack elements are bytes, but counts need words */
990 for (i = 0; i < 6; i++)
992 int num_delta_arg;
995 if (!num_delta_after_IUP_args[i])
996 continue;
998 num_delta_arg = num_delta_after_IUP_args[i] - 1;
1000 bufp = TA_build_push(bufp,
1001 delta_after_IUP_args[i],
1002 num_delta_arg,
1003 need_after_IUP_words,
1006 num_after_IUP_stack_elements += num_delta_arg + 1;
1008 num_delta_arg >>= 1;
1009 BCI(PUSHW_1);
1010 BCI(HIGH(num_delta_arg));
1011 BCI(LOW(num_delta_arg));
1015 /* emit y DELTA opcodes */
1016 if (num_delta_after_IUP_args[5])
1017 BCI(DELTAP3);
1018 if (num_delta_after_IUP_args[4])
1019 BCI(DELTAP2);
1020 if (num_delta_after_IUP_args[3])
1021 BCI(DELTAP1);
1023 if (num_delta_after_IUP_args[2]
1024 || num_delta_after_IUP_args[1]
1025 || num_delta_after_IUP_args[0])
1026 BCI(SVTCA_x);
1028 /* emit x DELTA opcodes */
1029 if (num_delta_after_IUP_args[2])
1030 BCI(DELTAP3);
1031 if (num_delta_after_IUP_args[1])
1032 BCI(DELTAP2);
1033 if (num_delta_after_IUP_args[0])
1034 BCI(DELTAP1);
1036 /* we need to insert a few extra bytecode instructions */
1037 /* if we have y delta exceptions before IUP */
1038 if (num_delta_before_IUP_args[5]
1039 || num_delta_before_IUP_args[4]
1040 || num_delta_before_IUP_args[3])
1042 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1043 /* by activating `ins_extra_buf' */
1044 glyph->ins_extra_len = sizeof (ins_extra_buf) / sizeof (FT_Byte);
1046 /* reset `cvtl_do_iup_y' for next glyph */
1047 BCI(PUSHB_2);
1048 BCI(cvtl_do_iup_y);
1049 BCI(100);
1050 BCI(WCVTP);
1053 Done:
1054 for (i = 0; i < 6; i++)
1056 free(delta_before_IUP_args[i]);
1057 free(delta_after_IUP_args[i]);
1059 free(args);
1061 if (num_before_IUP_stack_elements > sfnt->max_stack_elements)
1062 sfnt->max_stack_elements = num_before_IUP_stack_elements;
1063 if (num_after_IUP_stack_elements > sfnt->max_stack_elements)
1064 sfnt->max_stack_elements = num_after_IUP_stack_elements;
1066 return bufp;
1070 static FT_Byte*
1071 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
1072 Recorder* recorder,
1073 FT_Byte* bufp)
1075 FONT* font = recorder->font;
1076 FT_GlyphSlot glyph = sfnt->face->glyph;
1077 FT_Vector* points = glyph->outline.points;
1078 FT_Int num_contours = glyph->outline.n_contours;
1080 FT_UInt* args;
1081 FT_UInt* arg;
1082 FT_UInt num_args;
1084 FT_Bool need_words = 0;
1085 FT_Int p, q;
1086 FT_Int start, end;
1087 FT_UShort num_storage;
1088 FT_UShort num_stack_elements;
1091 num_args = 2 * num_contours + 2;
1093 /* collect all arguments temporarily in an array (in reverse order) */
1094 /* so that we can easily split into chunks of 255 args */
1095 /* as needed by NPUSHB and NPUSHW, respectively */
1096 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1097 if (!args)
1098 return NULL;
1100 arg = args + num_args - 1;
1102 if (num_args > 0xFF)
1103 need_words = 1;
1105 if (recorder->glyph->num_components && font->hint_composites)
1106 *(arg--) = bci_scale_composite_glyph;
1107 else
1108 *(arg--) = bci_scale_glyph;
1109 *(arg--) = num_contours;
1111 start = 0;
1112 end = 0;
1114 for (p = 0; p < num_contours; p++)
1116 FT_Int max = start;
1117 FT_Int min = start;
1120 end = glyph->outline.contours[p];
1122 for (q = start; q <= end; q++)
1124 if (points[q].y < points[min].y)
1125 min = q;
1126 if (points[q].y > points[max].y)
1127 max = q;
1130 if (min > max)
1132 *(arg--) = TA_adjust_point_index(recorder, max);
1133 *(arg--) = TA_adjust_point_index(recorder, min);
1135 else
1137 *(arg--) = TA_adjust_point_index(recorder, min);
1138 *(arg--) = TA_adjust_point_index(recorder, max);
1141 start = end + 1;
1144 if (end > 0xFF)
1145 need_words = 1;
1147 /* with most fonts it is very rare */
1148 /* that any of the pushed arguments is larger than 0xFF, */
1149 /* thus we refrain from further optimizing this case */
1150 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
1152 BCI(CALL);
1154 num_storage = sal_segment_offset;
1155 if (num_storage > sfnt->max_storage)
1156 sfnt->max_storage = num_storage;
1158 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
1159 if (num_stack_elements > sfnt->max_stack_elements)
1160 sfnt->max_stack_elements = num_stack_elements;
1162 free(args);
1164 return bufp;
1168 static FT_Byte*
1169 TA_font_build_subglyph_shifter(FONT* font,
1170 FT_Byte* bufp)
1172 FT_Face face = font->loader->face;
1173 FT_GlyphSlot glyph = face->glyph;
1175 TA_GlyphLoader gloader = font->loader->gloader;
1177 TA_SubGlyph subglyphs = gloader->base.subglyphs;
1178 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
1179 TA_SubGlyph subglyph;
1181 FT_Int curr_contour = 0;
1184 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
1186 FT_Error error;
1188 FT_UShort flags = subglyph->flags;
1189 FT_Pos y_offset = subglyph->arg2;
1191 FT_Int num_contours;
1194 /* load subglyph to get the number of contours */
1195 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
1196 if (error)
1197 return NULL;
1198 num_contours = glyph->outline.n_contours;
1200 /* nothing to do if there is a point-to-point alignment */
1201 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1202 goto End;
1204 /* nothing to do if y offset is zero */
1205 if (!y_offset)
1206 goto End;
1208 /* nothing to do if there are no contours */
1209 if (!num_contours)
1210 goto End;
1212 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1213 /* ensures that composite subglyphs are represented as simple glyphs */
1215 if (num_contours > 0xFF
1216 || curr_contour > 0xFF)
1218 BCI(PUSHW_2);
1219 BCI(HIGH(curr_contour));
1220 BCI(LOW(curr_contour));
1221 BCI(HIGH(num_contours));
1222 BCI(LOW(num_contours));
1224 else
1226 BCI(PUSHB_2);
1227 BCI(curr_contour);
1228 BCI(num_contours);
1231 /* there are high chances that this value needs PUSHW, */
1232 /* thus we handle it separately */
1233 if (y_offset > 0xFF || y_offset < 0)
1235 BCI(PUSHW_1);
1236 BCI(HIGH(y_offset));
1237 BCI(LOW(y_offset));
1239 else
1241 BCI(PUSHB_1);
1242 BCI(y_offset);
1245 BCI(PUSHB_1);
1246 BCI(bci_shift_subglyph);
1247 BCI(CALL);
1249 End:
1250 curr_contour += num_contours;
1253 return bufp;
1258 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1259 * data in four arrays (which are simple but waste a lot of memory). The
1260 * function below converts them into bytecode.
1262 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1263 * together with the edge they correspond to.
1265 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1266 * loop over the edge or edge pairs, respectively, and each edge or edge
1267 * pair contains an inner loop to emit the correponding points.
1270 static void
1271 TA_build_point_hints(Recorder* recorder,
1272 TA_GlyphHints hints)
1274 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1275 TA_Segment segments = axis->segments;
1276 TA_Edge edges = axis->edges;
1278 FT_Byte* p = recorder->hints_record.buf;
1280 FT_UShort i;
1281 FT_UShort j;
1283 FT_UShort prev_edge;
1284 FT_UShort prev_before_edge;
1285 FT_UShort prev_after_edge;
1287 Node1* before_node;
1288 Node1* after_node;
1289 Node2* on_node;
1290 Node3* between_node;
1293 /* we store everything as 16bit numbers; */
1294 /* the function numbers (`ta_ip_before', etc.) */
1295 /* reflect the order in the TA_Action enumeration */
1297 /* ip_before_points */
1299 i = 0;
1300 for (before_node = LLRB_MIN(ip_before_points,
1301 &recorder->ip_before_points_head);
1302 before_node;
1303 before_node = LLRB_NEXT(ip_before_points,
1304 &recorder->ip_before_points_head,
1305 before_node))
1307 /* count points */
1308 i++;
1311 if (i)
1313 TA_Edge edge;
1316 recorder->hints_record.num_actions++;
1318 edge = edges;
1320 *(p++) = 0;
1321 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1322 *(p++) = HIGH(edge->first - segments);
1323 *(p++) = LOW(edge->first - segments);
1324 *(p++) = HIGH(i);
1325 *(p++) = LOW(i);
1327 for (before_node = LLRB_MIN(ip_before_points,
1328 &recorder->ip_before_points_head);
1329 before_node;
1330 before_node = LLRB_NEXT(ip_before_points,
1331 &recorder->ip_before_points_head,
1332 before_node))
1334 FT_UInt point;
1337 point = TA_adjust_point_index(recorder, before_node->point);
1338 *(p++) = HIGH(point);
1339 *(p++) = LOW(point);
1343 /* ip_after_points */
1345 i = 0;
1346 for (after_node = LLRB_MIN(ip_after_points,
1347 &recorder->ip_after_points_head);
1348 after_node;
1349 after_node = LLRB_NEXT(ip_after_points,
1350 &recorder->ip_after_points_head,
1351 after_node))
1353 /* count points */
1354 i++;
1357 if (i)
1359 TA_Edge edge;
1362 recorder->hints_record.num_actions++;
1364 edge = edges + axis->num_edges - 1;
1366 *(p++) = 0;
1367 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1368 *(p++) = HIGH(edge->first - segments);
1369 *(p++) = LOW(edge->first - segments);
1370 *(p++) = HIGH(i);
1371 *(p++) = LOW(i);
1373 for (after_node = LLRB_MIN(ip_after_points,
1374 &recorder->ip_after_points_head);
1375 after_node;
1376 after_node = LLRB_NEXT(ip_after_points,
1377 &recorder->ip_after_points_head,
1378 after_node))
1380 FT_UInt point;
1383 point = TA_adjust_point_index(recorder, after_node->point);
1384 *(p++) = HIGH(point);
1385 *(p++) = LOW(point);
1389 /* ip_on_point_array */
1391 prev_edge = 0xFFFF;
1392 i = 0;
1393 for (on_node = LLRB_MIN(ip_on_points,
1394 &recorder->ip_on_points_head);
1395 on_node;
1396 on_node = LLRB_NEXT(ip_on_points,
1397 &recorder->ip_on_points_head,
1398 on_node))
1400 /* count edges */
1401 if (on_node->edge != prev_edge)
1403 i++;
1404 prev_edge = on_node->edge;
1408 if (i)
1410 recorder->hints_record.num_actions++;
1412 *(p++) = 0;
1413 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1414 *(p++) = HIGH(i);
1415 *(p++) = LOW(i);
1417 for (on_node = LLRB_MIN(ip_on_points,
1418 &recorder->ip_on_points_head);
1419 on_node;
1420 on_node = LLRB_NEXT(ip_on_points,
1421 &recorder->ip_on_points_head,
1422 on_node))
1424 Node2* edge_node;
1425 TA_Edge edge;
1428 edge = edges + on_node->edge;
1430 *(p++) = HIGH(edge->first - segments);
1431 *(p++) = LOW(edge->first - segments);
1433 /* save current position */
1434 edge_node = on_node;
1435 j = 0;
1436 for (;
1437 on_node;
1438 on_node = LLRB_NEXT(ip_on_points,
1439 &recorder->ip_on_points_head,
1440 on_node))
1442 /* count points on current edge */
1443 if (on_node->edge != edge_node->edge)
1444 break;
1445 j++;
1448 *(p++) = HIGH(j);
1449 *(p++) = LOW(j);
1451 /* restore current position */
1452 on_node = edge_node;
1453 for (;
1454 on_node;
1455 on_node = LLRB_NEXT(ip_on_points,
1456 &recorder->ip_on_points_head,
1457 on_node))
1459 FT_UInt point;
1462 if (on_node->edge != edge_node->edge)
1463 break;
1465 point = TA_adjust_point_index(recorder, on_node->point);
1466 *(p++) = HIGH(point);
1467 *(p++) = LOW(point);
1469 /* keep track of previous node */
1470 edge_node = on_node;
1473 /* reset loop iterator by one element, then continue */
1474 on_node = edge_node;
1478 /* ip_between_point_array */
1480 prev_before_edge = 0xFFFF;
1481 prev_after_edge = 0xFFFF;
1482 i = 0;
1483 for (between_node = LLRB_MIN(ip_between_points,
1484 &recorder->ip_between_points_head);
1485 between_node;
1486 between_node = LLRB_NEXT(ip_between_points,
1487 &recorder->ip_between_points_head,
1488 between_node))
1490 /* count `(before,after)' edge pairs */
1491 if (between_node->before_edge != prev_before_edge
1492 || between_node->after_edge != prev_after_edge)
1494 i++;
1495 prev_before_edge = between_node->before_edge;
1496 prev_after_edge = between_node->after_edge;
1500 if (i)
1502 recorder->hints_record.num_actions++;
1504 *(p++) = 0;
1505 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1506 *(p++) = HIGH(i);
1507 *(p++) = LOW(i);
1509 for (between_node = LLRB_MIN(ip_between_points,
1510 &recorder->ip_between_points_head);
1511 between_node;
1512 between_node = LLRB_NEXT(ip_between_points,
1513 &recorder->ip_between_points_head,
1514 between_node))
1516 Node3* edge_pair_node;
1517 TA_Edge before;
1518 TA_Edge after;
1521 before = edges + between_node->before_edge;
1522 after = edges + between_node->after_edge;
1524 *(p++) = HIGH(after->first - segments);
1525 *(p++) = LOW(after->first - segments);
1526 *(p++) = HIGH(before->first - segments);
1527 *(p++) = LOW(before->first - segments);
1529 /* save current position */
1530 edge_pair_node = between_node;
1531 j = 0;
1532 for (;
1533 between_node;
1534 between_node = LLRB_NEXT(ip_between_points,
1535 &recorder->ip_between_points_head,
1536 between_node))
1538 /* count points associated with current edge pair */
1539 if (between_node->before_edge != edge_pair_node->before_edge
1540 || between_node->after_edge != edge_pair_node->after_edge)
1541 break;
1542 j++;
1545 *(p++) = HIGH(j);
1546 *(p++) = LOW(j);
1548 /* restore current position */
1549 between_node = edge_pair_node;
1550 for (;
1551 between_node;
1552 between_node = LLRB_NEXT(ip_between_points,
1553 &recorder->ip_between_points_head,
1554 between_node))
1556 FT_UInt point;
1559 if (between_node->before_edge != edge_pair_node->before_edge
1560 || between_node->after_edge != edge_pair_node->after_edge)
1561 break;
1563 point = TA_adjust_point_index(recorder, between_node->point);
1564 *(p++) = HIGH(point);
1565 *(p++) = LOW(point);
1567 /* keep track of previous node */
1568 edge_pair_node = between_node;
1571 /* reset loop iterator by one element, then continue */
1572 between_node = edge_pair_node;
1576 recorder->hints_record.buf = p;
1580 static FT_Bool
1581 TA_hints_record_is_different(Hints_Record* hints_records,
1582 FT_UInt num_hints_records,
1583 FT_Byte* start,
1584 FT_Byte* end)
1586 Hints_Record last_hints_record;
1589 if (!hints_records)
1590 return 1;
1592 /* we only need to compare with the last hints record */
1593 last_hints_record = hints_records[num_hints_records - 1];
1595 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1596 return 1;
1598 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1599 return 1;
1601 return 0;
1605 static FT_Error
1606 TA_add_hints_record(Hints_Record** hints_records,
1607 FT_UInt* num_hints_records,
1608 FT_Byte* start,
1609 Hints_Record hints_record)
1611 Hints_Record* hints_records_new;
1612 FT_UInt buf_len;
1613 /* at this point, `hints_record.buf' still points into `ins_buf' */
1614 FT_Byte* end = hints_record.buf;
1617 buf_len = (FT_UInt)(end - start);
1619 /* now fill the structure completely */
1620 hints_record.buf_len = buf_len;
1621 hints_record.buf = (FT_Byte*)malloc(buf_len);
1622 if (!hints_record.buf)
1623 return FT_Err_Out_Of_Memory;
1625 memcpy(hints_record.buf, start, buf_len);
1627 (*num_hints_records)++;
1628 hints_records_new =
1629 (Hints_Record*)realloc(*hints_records, *num_hints_records
1630 * sizeof (Hints_Record));
1631 if (!hints_records_new)
1633 free(hints_record.buf);
1634 (*num_hints_records)--;
1635 return FT_Err_Out_Of_Memory;
1637 else
1638 *hints_records = hints_records_new;
1640 (*hints_records)[*num_hints_records - 1] = hints_record;
1642 return FT_Err_Ok;
1646 static FT_Byte*
1647 TA_emit_hints_record(Recorder* recorder,
1648 Hints_Record* hints_record,
1649 FT_Byte* bufp,
1650 FT_Bool optimize)
1652 FT_Byte* p;
1653 FT_Byte* endp;
1654 FT_Bool need_words = 0;
1656 FT_UInt i, j;
1657 FT_UInt num_arguments;
1658 FT_UInt num_args;
1661 /* check whether any argument is larger than 0xFF */
1662 endp = hints_record->buf + hints_record->buf_len;
1663 for (p = hints_record->buf; p < endp; p += 2)
1664 if (*p)
1666 need_words = 1;
1667 break;
1670 /* with most fonts it is very rare */
1671 /* that any of the pushed arguments is larger than 0xFF, */
1672 /* thus we refrain from further optimizing this case */
1674 num_arguments = hints_record->buf_len / 2;
1675 p = endp - 2;
1677 if (need_words)
1679 for (i = 0; i < num_arguments; i += 255)
1681 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1683 if (optimize && num_args <= 8)
1684 BCI(PUSHW_1 - 1 + num_args);
1685 else
1687 BCI(NPUSHW);
1688 BCI(num_args);
1690 for (j = 0; j < num_args; j++)
1692 BCI(*p);
1693 BCI(*(p + 1));
1694 p -= 2;
1698 else
1700 /* we only need the lower bytes */
1701 p++;
1703 for (i = 0; i < num_arguments; i += 255)
1705 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1707 if (optimize && num_args <= 8)
1708 BCI(PUSHB_1 - 1 + num_args);
1709 else
1711 BCI(NPUSHB);
1712 BCI(num_args);
1714 for (j = 0; j < num_args; j++)
1716 BCI(*p);
1717 p -= 2;
1722 /* collect stack depth data */
1723 if (num_arguments > recorder->num_stack_elements)
1724 recorder->num_stack_elements = num_arguments;
1726 return bufp;
1730 static FT_Byte*
1731 TA_emit_hints_records(Recorder* recorder,
1732 Hints_Record* hints_records,
1733 FT_UInt num_hints_records,
1734 FT_Byte* bufp,
1735 FT_Bool optimize)
1737 FT_UInt i;
1738 Hints_Record* hints_record;
1741 hints_record = hints_records;
1743 /* emit hints records in `if' clauses, */
1744 /* with the ppem size as the condition */
1745 for (i = 0; i < num_hints_records - 1; i++)
1747 BCI(MPPEM);
1748 if (hints_record->size > 0xFF)
1750 BCI(PUSHW_1);
1751 BCI(HIGH((hints_record + 1)->size));
1752 BCI(LOW((hints_record + 1)->size));
1754 else
1756 BCI(PUSHB_1);
1757 BCI((hints_record + 1)->size);
1759 BCI(LT);
1760 BCI(IF);
1761 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1762 BCI(ELSE);
1764 hints_record++;
1767 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1769 for (i = 0; i < num_hints_records - 1; i++)
1770 BCI(EIF);
1772 return bufp;
1776 static void
1777 TA_free_hints_records(Hints_Record* hints_records,
1778 FT_UInt num_hints_records)
1780 FT_UInt i;
1783 for (i = 0; i < num_hints_records; i++)
1784 free(hints_records[i].buf);
1786 free(hints_records);
1790 static FT_Byte*
1791 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1792 TA_AxisHints axis,
1793 TA_Edge edge,
1794 FT_UShort* wraps)
1796 TA_Segment segments = axis->segments;
1797 TA_Segment seg;
1798 FT_UShort seg_idx;
1799 FT_UShort num_segs = 0;
1800 FT_UShort* wrap;
1803 seg_idx = edge->first - segments;
1805 /* we store everything as 16bit numbers */
1806 *(bufp++) = HIGH(seg_idx);
1807 *(bufp++) = LOW(seg_idx);
1809 /* wrap-around segments are stored as two segments */
1810 if (edge->first->first > edge->first->last)
1811 num_segs++;
1813 seg = edge->first->edge_next;
1814 while (seg != edge->first)
1816 num_segs++;
1818 if (seg->first > seg->last)
1819 num_segs++;
1821 seg = seg->edge_next;
1824 *(bufp++) = HIGH(num_segs);
1825 *(bufp++) = LOW(num_segs);
1827 if (edge->first->first > edge->first->last)
1829 /* emit second part of wrap-around segment; */
1830 /* the bytecode positions such segments after `normal' ones */
1831 wrap = wraps;
1832 for (;;)
1834 if (seg_idx == *wrap)
1835 break;
1836 wrap++;
1839 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1840 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1843 seg = edge->first->edge_next;
1844 while (seg != edge->first)
1846 seg_idx = seg - segments;
1848 *(bufp++) = HIGH(seg_idx);
1849 *(bufp++) = LOW(seg_idx);
1851 if (seg->first > seg->last)
1853 wrap = wraps;
1854 for (;;)
1856 if (seg_idx == *wrap)
1857 break;
1858 wrap++;
1861 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1862 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1865 seg = seg->edge_next;
1868 return bufp;
1872 static void
1873 TA_hints_recorder(TA_Action action,
1874 TA_GlyphHints hints,
1875 TA_Dimension dim,
1876 void* arg1,
1877 TA_Edge arg2,
1878 TA_Edge arg3,
1879 TA_Edge lower_bound,
1880 TA_Edge upper_bound)
1882 TA_AxisHints axis = &hints->axis[dim];
1883 TA_Edge edges = axis->edges;
1884 TA_Segment segments = axis->segments;
1885 TA_Point points = hints->points;
1887 Recorder* recorder = (Recorder*)hints->user;
1888 SFNT* sfnt = recorder->sfnt;
1889 FONT* font = recorder->font;
1890 FT_UShort* wraps = recorder->wrap_around_segments;
1891 FT_Byte* p = recorder->hints_record.buf;
1893 FT_UInt style = font->loader->metrics->style_class->style;
1896 if (dim == TA_DIMENSION_HORZ)
1897 return;
1899 /* we collect point hints for later processing */
1900 switch (action)
1902 case ta_ip_before:
1904 Node1* before_node;
1905 TA_Point point = (TA_Point)arg1;
1908 before_node = (Node1*)malloc(sizeof (Node1));
1909 if (!before_node)
1910 return;
1911 before_node->point = point - points;
1913 LLRB_INSERT(ip_before_points,
1914 &recorder->ip_before_points_head,
1915 before_node);
1917 return;
1919 case ta_ip_after:
1921 Node1* after_node;
1922 TA_Point point = (TA_Point)arg1;
1925 after_node = (Node1*)malloc(sizeof (Node1));
1926 if (!after_node)
1927 return;
1928 after_node->point = point - points;
1930 LLRB_INSERT(ip_after_points,
1931 &recorder->ip_after_points_head,
1932 after_node);
1934 return;
1936 case ta_ip_on:
1938 Node2* on_node;
1939 TA_Point point = (TA_Point)arg1;
1940 TA_Edge edge = arg2;
1943 on_node = (Node2*)malloc(sizeof (Node2));
1944 if (!on_node)
1945 return;
1946 on_node->edge = edge - edges;
1947 on_node->point = point - points;
1949 LLRB_INSERT(ip_on_points,
1950 &recorder->ip_on_points_head,
1951 on_node);
1953 return;
1955 case ta_ip_between:
1957 Node3* between_node;
1958 TA_Point point = (TA_Point)arg1;
1959 TA_Edge before = arg2;
1960 TA_Edge after = arg3;
1963 between_node = (Node3*)malloc(sizeof (Node3));
1964 if (!between_node)
1965 return;
1966 between_node->before_edge = before - edges;
1967 between_node->after_edge = after - edges;
1968 between_node->point = point - points;
1970 LLRB_INSERT(ip_between_points,
1971 &recorder->ip_between_points_head,
1972 between_node);
1974 return;
1976 case ta_bound:
1977 /* we ignore the BOUND action since we signal this information */
1978 /* with the proper function number */
1979 return;
1981 default:
1982 break;
1985 /* some enum values correspond to four or eight bytecode functions; */
1986 /* if the value is n, the function numbers are n, ..., n+7, */
1987 /* to be differentiated with flags */
1989 switch (action)
1991 case ta_link:
1993 TA_Edge base_edge = (TA_Edge)arg1;
1994 TA_Edge stem_edge = arg2;
1997 *(p++) = 0;
1998 *(p++) = (FT_Byte)action + ACTION_OFFSET
1999 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
2000 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
2002 *(p++) = HIGH(base_edge->first - segments);
2003 *(p++) = LOW(base_edge->first - segments);
2004 *(p++) = HIGH(stem_edge->first - segments);
2005 *(p++) = LOW(stem_edge->first - segments);
2007 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
2009 break;
2011 case ta_anchor:
2013 TA_Edge edge = (TA_Edge)arg1;
2014 TA_Edge edge2 = arg2;
2017 *(p++) = 0;
2018 *(p++) = (FT_Byte)action + ACTION_OFFSET
2019 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2020 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
2022 *(p++) = HIGH(edge->first - segments);
2023 *(p++) = LOW(edge->first - segments);
2024 *(p++) = HIGH(edge2->first - segments);
2025 *(p++) = LOW(edge2->first - segments);
2027 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2029 break;
2031 case ta_adjust:
2033 TA_Edge edge = (TA_Edge)arg1;
2034 TA_Edge edge2 = arg2;
2035 TA_Edge edge_minus_one = lower_bound;
2038 *(p++) = 0;
2039 *(p++) = (FT_Byte)action + ACTION_OFFSET
2040 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2041 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2042 + 4 * (edge_minus_one != NULL);
2044 *(p++) = HIGH(edge->first - segments);
2045 *(p++) = LOW(edge->first - segments);
2046 *(p++) = HIGH(edge2->first - segments);
2047 *(p++) = LOW(edge2->first - segments);
2049 if (edge_minus_one)
2051 *(p++) = HIGH(edge_minus_one->first - segments);
2052 *(p++) = LOW(edge_minus_one->first - segments);
2055 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2057 break;
2059 case ta_blue_anchor:
2061 TA_Edge edge = (TA_Edge)arg1;
2062 TA_Edge blue = arg2;
2065 *(p++) = 0;
2066 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2068 *(p++) = HIGH(blue->first - segments);
2069 *(p++) = LOW(blue->first - segments);
2071 if (edge->best_blue_is_shoot)
2073 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2074 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2076 else
2078 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2079 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2082 *(p++) = HIGH(edge->first - segments);
2083 *(p++) = LOW(edge->first - segments);
2085 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2087 break;
2089 case ta_stem:
2091 TA_Edge edge = (TA_Edge)arg1;
2092 TA_Edge edge2 = arg2;
2093 TA_Edge edge_minus_one = lower_bound;
2096 *(p++) = 0;
2097 *(p++) = (FT_Byte)action + ACTION_OFFSET
2098 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2099 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2100 + 4 * (edge_minus_one != NULL);
2102 *(p++) = HIGH(edge->first - segments);
2103 *(p++) = LOW(edge->first - segments);
2104 *(p++) = HIGH(edge2->first - segments);
2105 *(p++) = LOW(edge2->first - segments);
2107 if (edge_minus_one)
2109 *(p++) = HIGH(edge_minus_one->first - segments);
2110 *(p++) = LOW(edge_minus_one->first - segments);
2113 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2114 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
2116 break;
2118 case ta_blue:
2120 TA_Edge edge = (TA_Edge)arg1;
2123 *(p++) = 0;
2124 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2126 if (edge->best_blue_is_shoot)
2128 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2129 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2131 else
2133 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2134 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2137 *(p++) = HIGH(edge->first - segments);
2138 *(p++) = LOW(edge->first - segments);
2140 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2142 break;
2144 case ta_serif:
2146 TA_Edge serif = (TA_Edge)arg1;
2147 TA_Edge base = serif->serif;
2150 *(p++) = 0;
2151 *(p++) = (FT_Byte)action + ACTION_OFFSET
2152 + (lower_bound != NULL)
2153 + 2 * (upper_bound != NULL);
2155 *(p++) = HIGH(serif->first - segments);
2156 *(p++) = LOW(serif->first - segments);
2157 *(p++) = HIGH(base->first - segments);
2158 *(p++) = LOW(base->first - segments);
2160 if (lower_bound)
2162 *(p++) = HIGH(lower_bound->first - segments);
2163 *(p++) = LOW(lower_bound->first - segments);
2165 if (upper_bound)
2167 *(p++) = HIGH(upper_bound->first - segments);
2168 *(p++) = LOW(upper_bound->first - segments);
2171 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
2173 break;
2175 case ta_serif_anchor:
2176 case ta_serif_link2:
2178 TA_Edge edge = (TA_Edge)arg1;
2181 *(p++) = 0;
2182 *(p++) = (FT_Byte)action + ACTION_OFFSET
2183 + (lower_bound != NULL)
2184 + 2 * (upper_bound != NULL);
2186 *(p++) = HIGH(edge->first - segments);
2187 *(p++) = LOW(edge->first - segments);
2189 if (lower_bound)
2191 *(p++) = HIGH(lower_bound->first - segments);
2192 *(p++) = LOW(lower_bound->first - segments);
2194 if (upper_bound)
2196 *(p++) = HIGH(upper_bound->first - segments);
2197 *(p++) = LOW(upper_bound->first - segments);
2200 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2202 break;
2204 case ta_serif_link1:
2206 TA_Edge edge = (TA_Edge)arg1;
2207 TA_Edge before = arg2;
2208 TA_Edge after = arg3;
2211 *(p++) = 0;
2212 *(p++) = (FT_Byte)action + ACTION_OFFSET
2213 + (lower_bound != NULL)
2214 + 2 * (upper_bound != NULL);
2216 *(p++) = HIGH(before->first - segments);
2217 *(p++) = LOW(before->first - segments);
2218 *(p++) = HIGH(edge->first - segments);
2219 *(p++) = LOW(edge->first - segments);
2220 *(p++) = HIGH(after->first - segments);
2221 *(p++) = LOW(after->first - segments);
2223 if (lower_bound)
2225 *(p++) = HIGH(lower_bound->first - segments);
2226 *(p++) = LOW(lower_bound->first - segments);
2228 if (upper_bound)
2230 *(p++) = HIGH(upper_bound->first - segments);
2231 *(p++) = LOW(upper_bound->first - segments);
2234 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
2236 break;
2238 default:
2239 /* there are more cases in the enumeration */
2240 /* which are handled with flags */
2241 break;
2244 recorder->hints_record.num_actions++;
2245 recorder->hints_record.buf = p;
2249 static FT_Error
2250 TA_init_recorder(Recorder* recorder,
2251 SFNT* sfnt,
2252 FONT* font,
2253 GLYPH* glyph,
2254 TA_GlyphHints hints)
2256 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2257 TA_Point points = hints->points;
2258 TA_Point point_limit = points + hints->num_points;
2259 TA_Point point;
2261 TA_Segment segments = axis->segments;
2262 TA_Segment seg_limit = segments + axis->num_segments;
2263 TA_Segment seg;
2265 FT_UShort num_strong_points = 0;
2266 FT_UShort* wrap_around_segment;
2268 recorder->sfnt = sfnt;
2269 recorder->font = font;
2270 recorder->glyph = glyph;
2271 recorder->num_segments = axis->num_segments;
2273 LLRB_INIT(&recorder->ip_before_points_head);
2274 LLRB_INIT(&recorder->ip_after_points_head);
2275 LLRB_INIT(&recorder->ip_on_points_head);
2276 LLRB_INIT(&recorder->ip_between_points_head);
2278 recorder->num_stack_elements = 0;
2280 /* no need to clean up allocated arrays in case of error; */
2281 /* this is handled later by `TA_free_recorder' */
2283 recorder->num_wrap_around_segments = 0;
2284 for (seg = segments; seg < seg_limit; seg++)
2285 if (seg->first > seg->last)
2286 recorder->num_wrap_around_segments++;
2288 recorder->wrap_around_segments =
2289 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2290 * sizeof (FT_UShort));
2291 if (!recorder->wrap_around_segments)
2292 return FT_Err_Out_Of_Memory;
2294 wrap_around_segment = recorder->wrap_around_segments;
2295 for (seg = segments; seg < seg_limit; seg++)
2296 if (seg->first > seg->last)
2297 *(wrap_around_segment++) = seg - segments;
2299 /* get number of strong points */
2300 for (point = points; point < point_limit; point++)
2302 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2303 /* however, this value isn't known yet */
2304 /* (or rather, it can vary between different pixel sizes) */
2305 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
2306 continue;
2308 num_strong_points++;
2311 recorder->num_strong_points = num_strong_points;
2313 return FT_Err_Ok;
2317 static void
2318 TA_reset_recorder(Recorder* recorder,
2319 FT_Byte* bufp)
2321 recorder->hints_record.buf = bufp;
2322 recorder->hints_record.num_actions = 0;
2326 static void
2327 TA_rewind_recorder(Recorder* recorder,
2328 FT_Byte* bufp,
2329 FT_UInt size)
2331 Node1* before_node;
2332 Node1* after_node;
2333 Node2* on_node;
2334 Node3* between_node;
2336 Node1* next_before_node;
2337 Node1* next_after_node;
2338 Node2* next_on_node;
2339 Node3* next_between_node;
2342 TA_reset_recorder(recorder, bufp);
2344 recorder->hints_record.size = size;
2346 /* deallocate our red-black trees */
2348 for (before_node = LLRB_MIN(ip_before_points,
2349 &recorder->ip_before_points_head);
2350 before_node;
2351 before_node = next_before_node)
2353 next_before_node = LLRB_NEXT(ip_before_points,
2354 &recorder->ip_before_points_head,
2355 before_node);
2356 LLRB_REMOVE(ip_before_points,
2357 &recorder->ip_before_points_head,
2358 before_node);
2359 free(before_node);
2362 for (after_node = LLRB_MIN(ip_after_points,
2363 &recorder->ip_after_points_head);
2364 after_node;
2365 after_node = next_after_node)
2367 next_after_node = LLRB_NEXT(ip_after_points,
2368 &recorder->ip_after_points_head,
2369 after_node);
2370 LLRB_REMOVE(ip_after_points,
2371 &recorder->ip_after_points_head,
2372 after_node);
2373 free(after_node);
2376 for (on_node = LLRB_MIN(ip_on_points,
2377 &recorder->ip_on_points_head);
2378 on_node;
2379 on_node = next_on_node)
2381 next_on_node = LLRB_NEXT(ip_on_points,
2382 &recorder->ip_on_points_head,
2383 on_node);
2384 LLRB_REMOVE(ip_on_points,
2385 &recorder->ip_on_points_head,
2386 on_node);
2387 free(on_node);
2390 for (between_node = LLRB_MIN(ip_between_points,
2391 &recorder->ip_between_points_head);
2392 between_node;
2393 between_node = next_between_node)
2395 next_between_node = LLRB_NEXT(ip_between_points,
2396 &recorder->ip_between_points_head,
2397 between_node);
2398 LLRB_REMOVE(ip_between_points,
2399 &recorder->ip_between_points_head,
2400 between_node);
2401 free(between_node);
2406 static void
2407 TA_free_recorder(Recorder* recorder)
2409 free(recorder->wrap_around_segments);
2411 TA_rewind_recorder(recorder, NULL, 0);
2415 FT_Error
2416 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2417 FONT* font,
2418 FT_Long idx)
2420 FT_Face face = sfnt->face;
2421 FT_Error error;
2423 FT_Byte* ins_buf;
2424 FT_UInt ins_len;
2425 FT_Byte* bufp;
2426 FT_Byte* p;
2428 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2429 glyf_Data* data = (glyf_Data*)glyf_table->data;
2430 /* `idx' is never negative */
2431 GLYPH* glyph = &data->glyphs[idx];
2433 TA_GlyphHints hints;
2435 FT_UInt num_action_hints_records = 0;
2436 FT_UInt num_point_hints_records = 0;
2437 Hints_Record* action_hints_records = NULL;
2438 Hints_Record* point_hints_records = NULL;
2440 Recorder recorder;
2441 FT_UShort num_stack_elements;
2442 FT_Bool optimize = 0;
2444 FT_Int32 load_flags;
2445 FT_UInt size;
2447 FT_Byte* pos[3];
2449 #ifdef TA_DEBUG
2450 int _ta_debug_save;
2451 #endif
2454 /* XXX: right now, we abuse this flag to control */
2455 /* the global behaviour of the auto-hinter */
2456 load_flags = 1 << 29; /* vertical hinting only */
2457 if (!font->adjust_subglyphs)
2459 if (font->hint_composites)
2460 load_flags |= FT_LOAD_NO_SCALE;
2461 else
2462 load_flags |= FT_LOAD_NO_RECURSE;
2465 /* computing the segments is resolution independent, */
2466 /* thus the pixel size in this call is arbitrary -- */
2467 /* however, we avoid unnecessary debugging output */
2468 /* if we use the lowest value of the hinting range */
2469 error = FT_Set_Pixel_Sizes(face,
2470 font->hinting_range_min,
2471 font->hinting_range_min);
2472 if (error)
2473 return error;
2475 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2476 /* to modify `out' directions of points at the user's request */
2477 /* (which will eventually become single-point segments) */
2478 error = TA_control_segment_dir_collect(font, face->face_index, idx);
2479 if (error)
2480 return error;
2482 #ifdef TA_DEBUG
2483 /* temporarily disable some debugging output */
2484 /* to avoid getting the information twice */
2485 _ta_debug_save = _ta_debug;
2486 _ta_debug = 0;
2487 #endif
2489 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2490 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2492 #ifdef TA_DEBUG
2493 _ta_debug = _ta_debug_save;
2494 #endif
2496 if (error)
2497 return error;
2499 /* do nothing if we have an empty glyph */
2500 if (!face->glyph->outline.n_contours)
2501 return FT_Err_Ok;
2503 hints = &font->loader->hints;
2505 /* do nothing if the setup delivered the `none_dflt' style only */
2506 if (!hints->num_points)
2507 return FT_Err_Ok;
2510 * We allocate a buffer which is certainly large enough
2511 * to hold all of the created bytecode instructions;
2512 * later on it gets reallocated to its real size.
2514 * The value `1000' is a very rough guess, not tested well.
2516 * For delta exceptions, we have three DELTA commands,
2517 * covering 3*16 ppem values.
2518 * Since a point index can be larger than 255,
2519 * we assume two bytes everywhere for the necessary PUSH calls.
2520 * This value must be doubled for the other arguments of DELTA.
2521 * Additionally, we have both x and y deltas,
2522 * which need to be handled separately in the bytecode.
2523 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2524 * adding some bytes for the necessary overhead.
2526 ins_len = hints->num_points
2527 * (1000 + ((font->control_data_head != NULL) ? 400 : 0));
2528 ins_buf = (FT_Byte*)malloc(ins_len);
2529 if (!ins_buf)
2530 return FT_Err_Out_Of_Memory;
2532 /* handle composite glyph */
2533 if (font->loader->gloader->base.num_subglyphs)
2535 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2536 if (!bufp)
2538 error = FT_Err_Out_Of_Memory;
2539 goto Err;
2542 goto Done1;
2545 /* only scale the glyph if the `none_dflt' style has been used */
2546 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
2548 /* since `TA_init_recorder' hasn't been called yet, */
2549 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2550 recorder.sfnt = sfnt;
2551 recorder.font = font;
2552 recorder.glyph = glyph;
2554 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2555 if (!bufp)
2557 error = FT_Err_Out_Of_Memory;
2558 goto Err;
2561 goto Done1;
2564 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2565 if (error)
2566 goto Err;
2568 /* loop over a large range of pixel sizes */
2569 /* to find hints records which get pushed onto the bytecode stack */
2571 #ifdef DEBUGGING
2572 if (font->debug)
2574 int num_chars, i;
2575 char buf[256];
2578 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
2580 num_chars = fprintf(stderr, "glyph %ld", idx);
2581 if (*buf)
2582 num_chars += fprintf(stderr, " (%s)", buf);
2583 fprintf(stderr, "\n");
2584 for (i = 0; i < num_chars; i++)
2585 putc('=', stderr);
2586 fprintf(stderr, "\n\n");
2589 #endif
2591 /* we temporarily use `ins_buf' to record the current glyph hints */
2592 ta_loader_register_hints_recorder(font->loader,
2593 TA_hints_recorder,
2594 (void*)&recorder);
2596 for (size = font->hinting_range_min;
2597 size <= font->hinting_range_max;
2598 size++)
2600 #ifdef DEBUGGING
2601 int have_dumps = 0;
2602 #endif
2605 TA_rewind_recorder(&recorder, ins_buf, size);
2607 error = FT_Set_Pixel_Sizes(face, size, size);
2608 if (error)
2609 goto Err;
2611 #ifdef DEBUGGING
2612 if (font->debug)
2614 int num_chars, i;
2617 num_chars = fprintf(stderr, "size %d\n", size);
2618 for (i = 0; i < num_chars - 1; i++)
2619 putc('-', stderr);
2620 fprintf(stderr, "\n\n");
2622 #endif
2624 /* calling `ta_loader_load_glyph' uses the */
2625 /* `TA_hints_recorder' function as a callback, */
2626 /* modifying `hints_record' */
2627 error = ta_loader_load_glyph(font, face, idx, load_flags);
2628 if (error)
2629 goto Err;
2631 if (TA_hints_record_is_different(action_hints_records,
2632 num_action_hints_records,
2633 ins_buf, recorder.hints_record.buf))
2635 #ifdef DEBUGGING
2636 if (font->debug)
2638 have_dumps = 1;
2640 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2641 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2642 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2644 fprintf(stderr, "action hints record:\n");
2645 if (ins_buf == recorder.hints_record.buf)
2646 fprintf(stderr, " (none)");
2647 else
2649 fprintf(stderr, " ");
2650 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2651 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2653 fprintf(stderr, "\n");
2655 #endif
2657 error = TA_add_hints_record(&action_hints_records,
2658 &num_action_hints_records,
2659 ins_buf, recorder.hints_record);
2660 if (error)
2661 goto Err;
2664 /* now handle point records */
2666 TA_reset_recorder(&recorder, ins_buf);
2668 /* use the point hints data collected in `TA_hints_recorder' */
2669 TA_build_point_hints(&recorder, hints);
2671 if (TA_hints_record_is_different(point_hints_records,
2672 num_point_hints_records,
2673 ins_buf, recorder.hints_record.buf))
2675 #ifdef DEBUGGING
2676 if (font->debug)
2678 if (!have_dumps)
2680 int num_chars, i;
2683 num_chars = fprintf(stderr, "size %d\n", size);
2684 for (i = 0; i < num_chars - 1; i++)
2685 putc('-', stderr);
2686 fprintf(stderr, "\n\n");
2688 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2689 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2690 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2693 fprintf(stderr, "point hints record:\n");
2694 if (ins_buf == recorder.hints_record.buf)
2695 fprintf(stderr, " (none)");
2696 else
2698 fprintf(stderr, " ");
2699 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2700 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2702 fprintf(stderr, "\n\n");
2704 #endif
2706 error = TA_add_hints_record(&point_hints_records,
2707 &num_point_hints_records,
2708 ins_buf, recorder.hints_record);
2709 if (error)
2710 goto Err;
2714 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2716 /* since we only have a single empty record we just scale the glyph */
2717 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2718 if (!bufp)
2720 error = FT_Err_Out_Of_Memory;
2721 goto Err;
2724 goto Done;
2727 /* if there is only a single record, */
2728 /* we do a global optimization later on */
2729 if (num_action_hints_records > 1)
2730 optimize = 1;
2732 /* store the hints records and handle stack depth */
2733 pos[0] = ins_buf;
2734 bufp = TA_emit_hints_records(&recorder,
2735 point_hints_records,
2736 num_point_hints_records,
2737 ins_buf,
2738 optimize);
2740 num_stack_elements = recorder.num_stack_elements;
2741 recorder.num_stack_elements = 0;
2743 pos[1] = bufp;
2744 bufp = TA_emit_hints_records(&recorder,
2745 action_hints_records,
2746 num_action_hints_records,
2747 bufp,
2748 optimize);
2750 recorder.num_stack_elements += num_stack_elements;
2752 pos[2] = bufp;
2753 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2754 if (!bufp)
2756 error = FT_Err_Out_Of_Memory;
2757 goto Err;
2760 if (num_action_hints_records == 1)
2761 bufp = TA_optimize_push(ins_buf, pos);
2763 Done:
2764 TA_free_hints_records(action_hints_records, num_action_hints_records);
2765 TA_free_hints_records(point_hints_records, num_point_hints_records);
2766 TA_free_recorder(&recorder);
2768 Done1:
2769 /* handle delta exceptions */
2770 if (font->control_data_head)
2772 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
2773 if (!bufp)
2775 error = FT_Err_Out_Of_Memory;
2776 goto Err;
2780 ins_len = bufp - ins_buf;
2782 if (ins_len > sfnt->max_instructions)
2783 sfnt->max_instructions = ins_len;
2785 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2786 glyph->ins_len = ins_len;
2788 return FT_Err_Ok;
2790 Err:
2791 TA_free_hints_records(action_hints_records, num_action_hints_records);
2792 TA_free_hints_records(point_hints_records, num_point_hints_records);
2793 TA_free_recorder(&recorder);
2794 free(ins_buf);
2796 return error;
2800 /* end of tabytecode.c */