1 /* tabytecode.c */
2 
3 /*
4  * Copyright (C) 2011-2021 by Werner Lemberg.
5  *
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.
10  *
11  * The file `COPYING' mentioned in the previous paragraph is distributed
12  * with the ttfautohint library.
13  */
14 
15 
16 #include "ta.h"
17 
18 #include <stdbool.h> /* for llrb.h */
19 
20 #include "llrb.h" /* a red-black tree implementation */
21 #include "tahints.h"
22 
23 
24 #define DEBUGGING
25 
26 
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
35 
36 
37 /* node structures for point hints */
38 
39 typedef struct Node1 Node1;
40 struct Node1
41 {
42   LLRB_ENTRY(Node1) entry1;
43   FT_UShort point;
44 };
45 
46 typedef struct Node2 Node2;
47 struct Node2
48 {
49   LLRB_ENTRY(Node2) entry2;
50   FT_UShort edge;
51   FT_UShort point;
52 };
53 
54 typedef struct Node3 Node3;
55 struct Node3
56 {
57   LLRB_ENTRY(Node3) entry3;
58   FT_UShort before_edge;
59   FT_UShort after_edge;
60   FT_UShort point;
61 };
62 
63 
64 /* comparison functions for our red-black trees */
65 
66 static int
node1cmp(Node1 * e1,Node1 * e2)67 node1cmp(Node1* e1,
68          Node1* e2)
69 {
70   /* sort by points */
71   return e1->point - e2->point;
72 }
73 
74 static int
node2cmp(Node2 * e1,Node2 * e2)75 node2cmp(Node2* e1,
76          Node2* e2)
77 {
78   FT_Int delta;
79 
80 
81   /* sort by edges ... */
82   delta = (FT_Int)e1->edge - (FT_Int)e2->edge;
83   if (delta)
84     return delta;
85 
86   /* ... then by points */
87   return (FT_Int)e1->point - (FT_Int)e2->point;
88 }
89 
90 static int
node3cmp(Node3 * e1,Node3 * e2)91 node3cmp(Node3* e1,
92          Node3* e2)
93 {
94   FT_Int delta;
95 
96 
97   /* sort by `before' edges ... */
98   delta = (FT_Int)e1->before_edge - (FT_Int)e2->before_edge;
99   if (delta)
100     return delta;
101 
102   /* ... then by `after' edges ... */
103   delta = (FT_Int)e1->after_edge - (FT_Int)e2->after_edge;
104   if (delta)
105     return delta;
106 
107   /* ... then by points */
108   return (FT_Int)e1->point - (FT_Int)e2->point;
109 }
110 
111 
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;
117 
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);
122 
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)
128 
129 
130 typedef struct Hints_Record_
131 {
132   FT_UInt size;
133   FT_UInt num_actions;
134   FT_Byte* buf;
135   FT_UInt buf_len;
136 } Hints_Record;
137 
138 typedef struct Recorder_
139 {
140   SFNT* sfnt;
141   FONT* font;
142   GLYPH* glyph; /* the current glyph */
143   Hints_Record hints_record;
144 
145   /* some segments can `wrap around' */
146   /* a contour's start point like 24-25-26-0-1-2 */
147   /* (there can be at most one such segment per contour); */
148   /* later on we append additional records */
149   /* to split them into 24-26 and 0-2 */
150   FT_UShort* wrap_around_segments;
151   FT_UShort num_wrap_around_segments;
152   FT_Bool wrap_around_segments_initialized;
153 
154   FT_UShort num_stack_elements; /* the necessary stack depth so far */
155 
156   /* data necessary for strong point interpolation */
157   ip_before_points ip_before_points_head;
158   ip_after_points ip_after_points_head;
159   ip_on_points ip_on_points_head;
160   ip_between_points ip_between_points_head;
161 
162   /* we omit one-point segments not part of an edge, */
163   /* thus we have to adjust indices into the `segments' array */
164   FT_UShort* segment_map;
165   FT_Bool segment_map_initialized;
166 } Recorder;
167 
168 
169 /* this is the bytecode of the `.ttfautohint' glyph */
170 
171 FT_Byte ttfautohint_glyph_bytecode[7] =
172 {
173 
174   /* increment `cvtl_is_subglyph' counter */
175   PUSHB_3,
176     cvtl_is_subglyph,
177     100,
178     cvtl_is_subglyph,
179   RCVT,
180   ADD,
181   WCVTP,
182 
183 };
184 
185 
186 /* if we have y delta exceptions before IUP_y, this code gets inserted */
187 static FT_Byte ins_extra_delta_exceptions[4] =
188 {
189 
190   /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
191   PUSHB_2,
192     cvtl_do_iup_y,
193     0,
194   WCVTP,
195 
196 };
197 
198 
199 /* if we have a non-base glyph, this code gets inserted */
200 static FT_Byte ins_extra_ignore_std_width[4] =
201 {
202 
203   /* tell bci_{smooth,strong}_stem_width to ignore std_width */
204   PUSHB_2,
205     cvtl_ignore_std_width,
206     100,
207   WCVTP,
208 
209 };
210 
211 
212 /*
213  * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
214  * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
215  * only if `optimize' is not set); if `need_words' is set, NPUSHW and
216  * PUSHW_X gets used
217  */
218 
219 FT_Byte*
TA_build_push(FT_Byte * bufp,FT_UInt * args,FT_UInt num_args,FT_Bool need_words,FT_Bool optimize)220 TA_build_push(FT_Byte* bufp,
221               FT_UInt* args,
222               FT_UInt num_args,
223               FT_Bool need_words,
224               FT_Bool optimize)
225 {
226   FT_UInt* arg = args;
227   FT_UInt i, j, nargs;
228 
229 
230   if (need_words)
231   {
232     for (i = 0; i < num_args; i += 255)
233     {
234       nargs = (num_args - i > 255) ? 255 : num_args - i;
235 
236       if (optimize && nargs <= 8)
237         BCI(PUSHW_1 - 1 + nargs);
238       else
239       {
240         BCI(NPUSHW);
241         BCI(nargs);
242       }
243       for (j = 0; j < nargs; j++)
244       {
245         BCI(HIGH(*arg));
246         BCI(LOW(*arg));
247         arg++;
248       }
249     }
250   }
251   else
252   {
253     for (i = 0; i < num_args; i += 255)
254     {
255       nargs = (num_args - i > 255) ? 255 : num_args - i;
256 
257       if (optimize && nargs <= 8)
258         BCI(PUSHB_1 - 1 + nargs);
259       else
260       {
261         BCI(NPUSHB);
262         BCI(nargs);
263       }
264       for (j = 0; j < nargs; j++)
265       {
266         BCI(*arg);
267         arg++;
268       }
269     }
270   }
271 
272   return bufp;
273 }
274 
275 
276 /*
277  * We optimize two common cases, replacing
278  *
279  *   NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
280  *
281  * with
282  *
283  *   NPUSHB (A+B[+C]) ... CALL
284  *
285  * if possible
286  */
287 
288 static FT_Byte*
TA_optimize_push(FT_Byte * buf,FT_Byte ** pos)289 TA_optimize_push(FT_Byte* buf,
290                  FT_Byte** pos)
291 {
292   FT_Byte sizes[3];
293   FT_Byte new_size1;
294   FT_Byte new_size2;
295 
296   FT_UInt sum;
297   FT_UInt i;
298   FT_UInt pos_idx;
299 
300   FT_Byte* p;
301   FT_Byte* bufp;
302 
303 
304   /* XXX improve handling of NPUSHW */
305   if (*(pos[0]) == NPUSHW
306       || *(pos[1]) == NPUSHW
307       || *(pos[2]) == NPUSHW)
308     return buf;
309 
310   /* the point hints records block can be missing */
311   if (pos[0] == pos[1])
312   {
313     pos[1] = pos[2];
314     pos[2] = NULL;
315   }
316 
317   /* only needed for the algorithm loops below */
318   pos[3] = NULL;
319 
320   /* there are at least two NPUSHB instructions */
321   /* (one of them directly at the start) */
322   sizes[0] = *(pos[0] + 1);
323   sizes[1] = *(pos[1] + 1);
324   sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
325 
326   sum = sizes[0] + sizes[1] + sizes[2];
327 
328   if (sum > 2 * 0xFF)
329     return buf; /* nothing to do since we need three NPUSHB */
330   else if (!sizes[2] && (sum > 0xFF))
331     return buf; /* nothing to do since we need two NPUSHB */
332 
333   if (sum > 0xFF)
334   {
335     /* reduce three NPUSHB to two */
336     new_size1 = 0xFF;
337     new_size2 = (FT_Byte)(sum - 0xFF);
338   }
339   else
340   {
341     /* reduce two or three NPUSHB to one */
342     new_size1 = (FT_Byte)sum;
343     new_size2 = 0;
344   }
345 
346   /* pack data */
347   p = buf;
348   bufp = buf;
349   pos_idx = 0;
350 
351   if (new_size1 <= 8)
352     BCI(PUSHB_1 - 1 + new_size1);
353   else
354   {
355     BCI(NPUSHB);
356     BCI(new_size1);
357   }
358   for (i = 0; i < new_size1; i++)
359   {
360     if (p == pos[pos_idx])
361     {
362       pos_idx++;
363       p += 2; /* skip old NPUSHB */
364     }
365     *(bufp++) = *(p++);
366   }
367 
368   if (new_size2)
369   {
370     if (new_size2 <= 8)
371       BCI(PUSHB_1 - 1 + new_size2);
372     else
373     {
374       BCI(NPUSHB);
375       BCI(new_size2);
376     }
377     for (i = 0; i < new_size2; i++)
378     {
379       if (p == pos[pos_idx])
380       {
381         pos_idx++;
382         p += 2;
383       }
384       *(bufp++) = *(p++);
385     }
386   }
387 
388   BCI(CALL);
389 
390   return bufp;
391 }
392 
393 
394 /* We add a subglyph for each composite glyph. */
395 /* Since subglyphs must contain at least one point, */
396 /* we have to adjust all point indices accordingly. */
397 /* Using the `pointsums' array of the `GLYPH' structure */
398 /* it is straightforward to do that: */
399 /* Assuming that point with index x is in the interval */
400 /* pointsums[n] <= x < pointsums[n + 1], */
401 /* the new point index is x + n. */
402 
403 static FT_UInt
TA_adjust_point_index(Recorder * recorder,FT_UInt idx)404 TA_adjust_point_index(Recorder* recorder,
405                       FT_UInt idx)
406 {
407   FONT* font = recorder->font;
408   GLYPH* glyph = recorder->glyph;
409   FT_UShort i;
410 
411 
412   if (!glyph->num_components || !font->hint_composites)
413     return idx; /* not a composite glyph */
414 
415   for (i = 0; i < glyph->num_pointsums; i++)
416     if (idx < glyph->pointsums[i])
417       break;
418 
419   return idx + i;
420 }
421 
422 
423 /* We omit one-point segments not part of an edge, */
424 /* thus we have to adjust indices into the `segments' array. */
425 /* If `segment' is NULL, the number of all segments */
426 /* without non-edge one-point segments is returned. */
427 
428 static FT_UShort
TA_get_segment_index(TA_Segment segment,Recorder * recorder)429 TA_get_segment_index(TA_Segment segment,
430                      Recorder* recorder)
431 {
432   FONT* font = recorder->font;
433   TA_GlyphHints hints = &font->loader->hints;
434   TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
435 
436 
437   return segment ? recorder->segment_map[segment - axis->segments]
438                  : recorder->segment_map[axis->num_segments];
439 }
440 
441 
442 /* we store the segments in the storage area; */
443 /* each segment record consists of the first and last point */
444 
445 static FT_Byte*
TA_sfnt_build_glyph_segments(SFNT * sfnt,Recorder * recorder,FT_Byte * bufp,FT_Bool optimize)446 TA_sfnt_build_glyph_segments(SFNT* sfnt,
447                              Recorder* recorder,
448                              FT_Byte* bufp,
449                              FT_Bool optimize)
450 {
451   FONT* font = recorder->font;
452   TA_GlyphHints hints = &font->loader->hints;
453   TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
454   TA_Point points = hints->points;
455   TA_Segment segments = axis->segments;
456   TA_Segment seg;
457   TA_Segment seg_limit;
458 
459   SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
460   glyf_Data* data = (glyf_Data*)glyf_table->data;
461 
462   FT_UInt style_id = data->style_ids
463                        [font->loader->metrics->style_class->style];
464 
465   FT_Outline outline = font->loader->gloader->base.outline;
466 
467   FT_UInt* args;
468   FT_UInt* arg;
469   FT_UInt num_args;
470   FT_UShort num_segments;
471 
472   FT_Bool need_words = 0;
473 
474   FT_Int n;
475   FT_UInt base;
476   FT_UShort num_packed_segments;
477   FT_UShort num_storage;
478   FT_UShort num_stack_elements;
479   FT_UShort num_twilight_points;
480 
481 
482   seg_limit = segments + axis->num_segments;
483   num_segments = TA_get_segment_index(NULL, recorder);
484 
485   /* to pack the data in the bytecode more tightly, */
486   /* we store up to the first nine segments in nibbles if possible, */
487   /* using delta values */
488   base = 0;
489   num_packed_segments = 0;
490   for (seg = segments; seg < seg_limit; seg++)
491   {
492     FT_UInt first = (FT_UInt)(seg->first - points);
493     FT_UInt last = (FT_UInt)(seg->last - points);
494 
495 
496     if (TA_get_segment_index(seg, recorder) == 0xFFFF)
497       continue;
498 
499     first = TA_adjust_point_index(recorder, first);
500     last = TA_adjust_point_index(recorder, last);
501 
502     if (first - base >= 16)
503       break;
504     if (first > last || last - first >= 16)
505       break;
506     if (num_packed_segments == 9)
507       break;
508     num_packed_segments++;
509     base = last;
510   }
511 
512   /* also handle wrap-around segments */
513   num_segments += recorder->num_wrap_around_segments;
514 
515   /* wrap-around segments are pushed with four arguments; */
516   /* a segment stored in nibbles needs only one byte instead of two */
517   num_args = num_packed_segments
518              + 2 * (num_segments - num_packed_segments)
519              + 2 * recorder->num_wrap_around_segments
520              + 3;
521 
522   /* collect all arguments temporarily in an array (in reverse order) */
523   /* so that we can easily split into chunks of 255 args */
524   /* as needed by NPUSHB and NPUSHW, respectively */
525   args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
526   if (!args)
527     return NULL;
528 
529   arg = args + num_args - 1;
530 
531   if (num_segments > 0xFF)
532     need_words = 1;
533 
534   /* the number of packed segments is indicated by the function number */
535   if (recorder->glyph->num_components && font->hint_composites)
536     *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
537   else
538     *(arg--) = bci_create_segments_0 + num_packed_segments;
539 
540   *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
541   *(arg--) = num_segments;
542 
543   base = 0;
544   n = 0;
545   for (seg = segments; seg < seg_limit; seg++)
546   {
547     FT_UInt first = (FT_UInt)(seg->first - points);
548     FT_UInt last = (FT_UInt)(seg->last - points);
549     FT_UInt low_nibble;
550     FT_UInt high_nibble;
551 
552 
553     if (TA_get_segment_index(seg, recorder) == 0xFFFF)
554       continue;
555     if (n >= num_packed_segments)
556       break;
557 
558     first = TA_adjust_point_index(recorder, first);
559     last = TA_adjust_point_index(recorder, last);
560 
561     low_nibble = first - base;
562     high_nibble = last - first;
563 
564     *(arg--) = 16 * high_nibble + low_nibble;
565 
566     base = last;
567     n++;
568   }
569 
570   for (; seg < seg_limit; seg++)
571   {
572     FT_UInt first = (FT_UInt)(seg->first - points);
573     FT_UInt last = (FT_UInt)(seg->last - points);
574 
575 
576     if (TA_get_segment_index(seg, recorder) == 0xFFFF)
577       continue;
578 
579     *(arg--) = TA_adjust_point_index(recorder, first);
580     *(arg--) = TA_adjust_point_index(recorder, last);
581 
582     /* we push the last and first contour point */
583     /* as a third and fourth argument in wrap-around segments */
584     if (first > last)
585     {
586       for (n = 0; n < outline.n_contours; n++)
587       {
588         FT_UInt end = (FT_UInt)outline.contours[n];
589 
590 
591         if (first <= end)
592         {
593           *(arg--) = TA_adjust_point_index(recorder, end);
594           if (end > 0xFF)
595             need_words = 1;
596 
597           if (n == 0)
598             *(arg--) = TA_adjust_point_index(recorder, 0);
599           else
600             *(arg--) = TA_adjust_point_index(recorder,
601                          (FT_UInt)outline.contours[n - 1] + 1);
602           break;
603         }
604       }
605     }
606 
607     if (last > 0xFF)
608       need_words = 1;
609   }
610 
611   /* emit the second part of wrap-around segments as separate segments */
612   /* so that edges can easily link to them */
613   for (seg = segments; seg < seg_limit; seg++)
614   {
615     FT_UInt first = (FT_UInt)(seg->first - points);
616     FT_UInt last = (FT_UInt)(seg->last - points);
617 
618 
619     if (TA_get_segment_index(seg, recorder) == 0xFFFF)
620       continue;
621 
622     if (first > last)
623     {
624       for (n = 0; n < outline.n_contours; n++)
625       {
626         if (first <= (FT_UInt)outline.contours[n])
627         {
628           if (n == 0)
629             *(arg--) = TA_adjust_point_index(recorder, 0);
630           else
631             *(arg--) = TA_adjust_point_index(recorder,
632                          (FT_UInt)outline.contours[n - 1] + 1);
633           break;
634         }
635       }
636 
637       *(arg--) = TA_adjust_point_index(recorder, last);
638     }
639   }
640 
641   /* with most fonts it is very rare */
642   /* that any of the pushed arguments is larger than 0xFF, */
643   /* thus we refrain from further optimizing this case */
644   bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
645 
646   BCI(CALL);
647 
648   /* see storage area layout description in `tabytecode.h' */
649   num_storage = sal_segment_offset + num_segments * 3;
650   if (num_storage > sfnt->max_storage)
651     sfnt->max_storage = num_storage;
652 
653   num_twilight_points = num_segments * 2;
654   if (num_twilight_points > sfnt->max_twilight_points)
655     sfnt->max_twilight_points = num_twilight_points;
656 
657   /* both this function and `TA_emit_hints_record' */
658   /* push data onto the stack */
659   num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS
660                                    + recorder->num_stack_elements
661                                    + num_args);
662   if (num_stack_elements > sfnt->max_stack_elements)
663     sfnt->max_stack_elements = num_stack_elements;
664 
665   free(args);
666 
667   return bufp;
668 }
669 
670 
671 static void
build_delta_exception(const Ctrl * ctrl,FT_UInt ** delta_args,unsigned int * num_delta_args)672 build_delta_exception(const Ctrl* ctrl,
673                       FT_UInt** delta_args,
674                       unsigned int* num_delta_args)
675 {
676   int offset;
677   int ppem;
678   int x_shift;
679   int y_shift;
680 
681 
682   ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
683 
684   if (ppem < 16)
685     offset = 0;
686   else if (ppem < 32)
687     offset = 1;
688   else
689     offset = 2;
690 
691   ppem -= offset << 4;
692 
693   /*
694    * Using
695    *
696    *   delta_shift = 3   ,
697    *
698    * the possible shift values in the instructions are indexed as follows:
699    *
700    *    0   -1px
701    *    1   -7/8px
702    *   ...
703    *    7   -1/8px
704    *    8    1/8px
705    *   ...
706    *   14    7/8px
707    *   15    1px
708    *
709    * (note that there is no index for a zero shift).
710    */
711 
712   if (ctrl->x_shift < 0)
713     x_shift = ctrl->x_shift + 8;
714   else
715     x_shift = ctrl->x_shift + 7;
716 
717   if (ctrl->y_shift < 0)
718     y_shift = ctrl->y_shift + 8;
719   else
720     y_shift = ctrl->y_shift + 7;
721 
722   /* add point index and exception specification to appropriate stack */
723   if (ctrl->x_shift)
724   {
725     *(delta_args[offset] + num_delta_args[offset]++) =
726       (FT_UInt)((ppem << 4) + x_shift);
727     *(delta_args[offset] + num_delta_args[offset]++) =
728       (FT_UInt)ctrl->point_idx;
729   }
730 
731   if (ctrl->y_shift)
732   {
733     offset += 3;
734     *(delta_args[offset] + num_delta_args[offset]++) =
735       (FT_UInt)((ppem << 4) + y_shift);
736     *(delta_args[offset] + num_delta_args[offset]++) =
737       (FT_UInt)ctrl->point_idx;
738   }
739 }
740 
741 
742 static FT_Byte*
TA_sfnt_build_delta_exceptions(SFNT * sfnt,FONT * font,FT_Long idx,FT_Byte * bufp)743 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
744                                FONT* font,
745                                FT_Long idx,
746                                FT_Byte* bufp)
747 {
748   SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
749   glyf_Data* data = (glyf_Data*)glyf_table->data;
750   GLYPH* glyph = &data->glyphs[idx];
751 
752   FT_Face face = font->loader->face;
753 
754   unsigned int num_points;
755   int i;
756 
757   FT_UShort num_before_IUP_stack_elements = 0;
758   FT_UShort num_after_IUP_stack_elements = 0;
759 
760   /* DELTAP[1-3] stacks for both x and y directions */
761   FT_UInt* delta_before_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
762   FT_UInt* delta_after_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
763   unsigned int num_delta_before_IUP_args[6] = {0, 0, 0, 0, 0, 0};
764   unsigned int num_delta_after_IUP_args[6] = {0, 0, 0, 0, 0, 0};
765   FT_UInt* args = NULL;
766 
767   FT_Bool need_before_IUP_words = 0;
768   FT_Bool need_after_IUP_words = 0;
769   FT_Bool need_before_IUP_word_counts = 0;
770   FT_Bool need_after_IUP_word_counts = 0;
771   FT_Bool allocated_before_IUP = 0;
772   FT_Bool allocated_after_IUP = 0;
773 
774 
775   num_points = glyph->num_points;
776 
777   /* loop over all fitting control instructions */
778   for (;;)
779   {
780     const Ctrl* ctrl = TA_control_get_ctrl(font);
781 
782 
783     if (!ctrl)
784       break;
785 
786     /* check type */
787     if (!(ctrl->type == Control_Delta_before_IUP
788           || ctrl->type == Control_Delta_after_IUP))
789       break;
790 
791     /* too large values of font and glyph indices in `ctrl' */
792     /* are handled by later calls of this function */
793     if (face->face_index < ctrl->font_idx
794         || idx < ctrl->glyph_idx)
795       break;
796 
797     if (ctrl->type == Control_Delta_before_IUP
798         && !allocated_before_IUP)
799     {
800       for (i = 0; i < 6; i++)
801       {
802         /* see the comment on allocating `ins_buf' in function */
803         /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
804         /* we have to increase by 2 to push the number of argument pairs */
805         /* and the function for a LOOPCALL instruction */
806         delta_before_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 2)
807                                                     * sizeof (FT_UInt));
808         if (!delta_before_IUP_args[i])
809         {
810           bufp = NULL;
811           goto Done;
812         }
813       }
814 
815       allocated_before_IUP = 1;
816     }
817 
818     if (ctrl->type == Control_Delta_after_IUP
819         && !allocated_after_IUP)
820     {
821       for (i = 0; i < 6; i++)
822       {
823         /* we have to increase by 1 for the number of argument pairs */
824         /* as needed by the DELTA instructions */
825         delta_after_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
826                                                    * sizeof (FT_UInt));
827         if (!delta_after_IUP_args[i])
828         {
829           bufp = NULL;
830           goto Done;
831         }
832       }
833 
834       allocated_after_IUP = 1;
835     }
836 
837     /* since we walk sequentially over all glyphs (with points), */
838     /* and the control instruction entries have the same order, */
839     /* we don't need to test for equality of font and glyph indices: */
840     /* at this very point in the code we certainly have a hit */
841     if (ctrl->type == Control_Delta_before_IUP)
842     {
843       build_delta_exception(ctrl,
844                             delta_before_IUP_args,
845                             num_delta_before_IUP_args);
846 
847       if (ctrl->point_idx > 255)
848         need_before_IUP_words = 1;
849     }
850     else
851     {
852       build_delta_exception(ctrl,
853                             delta_after_IUP_args,
854                             num_delta_after_IUP_args);
855 
856       if (ctrl->point_idx > 255)
857         need_after_IUP_words = 1;
858     }
859 
860     TA_control_get_next(font);
861   }
862 
863   /* nothing to do if no control instructions */
864   if (!(allocated_before_IUP || allocated_after_IUP))
865     return bufp;
866 
867   /* add number of argument pairs and function number to the stacks */
868   for (i = 0; i < 6; i++)
869   {
870     if (num_delta_before_IUP_args[i])
871     {
872       unsigned int n = num_delta_before_IUP_args[i] >> 1;
873 
874 
875       if (n > 255)
876         need_before_IUP_word_counts = 1;
877 
878       *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) = n;
879       num_delta_before_IUP_args[i]++;
880 
881       *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) =
882         bci_deltap1 + (i % 3);
883       num_delta_before_IUP_args[i]++;
884     }
885   }
886 
887   /* add number of argument pairs to the stacks */
888   for (i = 0; i < 6; i++)
889   {
890     if (num_delta_after_IUP_args[i])
891     {
892       unsigned int n = num_delta_after_IUP_args[i] >> 1;
893 
894 
895       if (n > 255)
896         need_after_IUP_word_counts = 1;
897 
898       *(delta_after_IUP_args[i] + num_delta_after_IUP_args[i]) = n;
899       num_delta_after_IUP_args[i]++;
900     }
901   }
902 
903   /* merge `before IUP' delta stacks into a single one */
904   if (need_before_IUP_words || !need_before_IUP_word_counts)
905   {
906     FT_UInt num_args = 0;
907 
908 
909     for (i = 0; i < 6; i++)
910     {
911       FT_UInt* args_new;
912       FT_UInt num_args_new;
913 
914 
915       if (!num_delta_before_IUP_args[i])
916         continue;
917 
918       num_args_new = num_args + num_delta_before_IUP_args[i];
919       args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
920       if (!args_new)
921       {
922         bufp = NULL;
923         goto Done;
924       }
925 
926       memcpy(args_new + num_args,
927              delta_before_IUP_args[i],
928              num_delta_before_IUP_args[i] * sizeof (FT_UInt));
929 
930       args = args_new;
931       num_args = num_args_new;
932     }
933 
934     num_before_IUP_stack_elements = (FT_UShort)num_args;
935 
936     bufp = TA_build_push(bufp, args, num_args, need_before_IUP_words, 1);
937   }
938   else
939   {
940     num_before_IUP_stack_elements = 0;
941 
942     /* stack elements are bytes, but counts need words */
943     for (i = 0; i < 6; i++)
944     {
945       FT_UInt num_delta_arg;
946 
947 
948       if (!num_delta_before_IUP_args[i])
949         continue;
950 
951       num_delta_arg = num_delta_before_IUP_args[i] - 2;
952 
953       bufp = TA_build_push(bufp,
954                            delta_before_IUP_args[i],
955                            num_delta_arg,
956                            need_before_IUP_words,
957                            1);
958 
959       num_before_IUP_stack_elements += num_delta_arg + 2;
960 
961       num_delta_arg >>= 1;
962       BCI(PUSHW_1);
963       BCI(HIGH(num_delta_arg));
964       BCI(LOW(num_delta_arg));
965 
966       /* the function number */
967       BCI(PUSHB_1);
968       BCI(delta_before_IUP_args[i][num_delta_before_IUP_args[i] - 1]);
969     }
970   }
971 
972   /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
973   if (num_delta_before_IUP_args[5])
974     BCI(LOOPCALL);
975   if (num_delta_before_IUP_args[4])
976     BCI(LOOPCALL);
977   if (num_delta_before_IUP_args[3])
978     BCI(LOOPCALL);
979 
980   if (num_delta_before_IUP_args[2]
981       || num_delta_before_IUP_args[1]
982       || num_delta_before_IUP_args[0])
983     BCI(SVTCA_x);
984 
985   /* emit x DELTA opcodes */
986   if (num_delta_before_IUP_args[2])
987     BCI(LOOPCALL);
988   if (num_delta_before_IUP_args[1])
989     BCI(LOOPCALL);
990   if (num_delta_before_IUP_args[0])
991     BCI(LOOPCALL);
992 
993   if (num_delta_before_IUP_args[2]
994       || num_delta_before_IUP_args[1]
995       || num_delta_before_IUP_args[0])
996     BCI(SVTCA_y);
997 
998   if (num_delta_before_IUP_args[5]
999       || num_delta_before_IUP_args[4]
1000       || num_delta_before_IUP_args[3])
1001     BCI(IUP_y);
1002 
1003   /* merge `after IUP' delta stacks into a single one */
1004   if (need_after_IUP_words || !need_after_IUP_word_counts)
1005   {
1006     FT_UInt num_args = 0;
1007 
1008 
1009     for (i = 0; i < 6; i++)
1010     {
1011       FT_UInt* args_new;
1012       FT_UInt num_args_new;
1013 
1014 
1015       if (!num_delta_after_IUP_args[i])
1016         continue;
1017 
1018       num_args_new = num_args + num_delta_after_IUP_args[i];
1019       args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
1020       if (!args_new)
1021       {
1022         bufp = NULL;
1023         goto Done;
1024       }
1025 
1026       memcpy(args_new + num_args,
1027              delta_after_IUP_args[i],
1028              num_delta_after_IUP_args[i] * sizeof (FT_UInt));
1029 
1030       args = args_new;
1031       num_args = num_args_new;
1032     }
1033 
1034     num_after_IUP_stack_elements = (FT_UShort)num_args;
1035 
1036     bufp = TA_build_push(bufp, args, num_args, need_after_IUP_words, 1);
1037   }
1038   else
1039   {
1040     num_after_IUP_stack_elements = 0;
1041 
1042     /* stack elements are bytes, but counts need words */
1043     for (i = 0; i < 6; i++)
1044     {
1045       FT_UInt num_delta_arg;
1046 
1047 
1048       if (!num_delta_after_IUP_args[i])
1049         continue;
1050 
1051       num_delta_arg = num_delta_after_IUP_args[i] - 1;
1052 
1053       bufp = TA_build_push(bufp,
1054                            delta_after_IUP_args[i],
1055                            num_delta_arg,
1056                            need_after_IUP_words,
1057                            1);
1058 
1059       num_after_IUP_stack_elements += num_delta_arg + 1;
1060 
1061       num_delta_arg >>= 1;
1062       BCI(PUSHW_1);
1063       BCI(HIGH(num_delta_arg));
1064       BCI(LOW(num_delta_arg));
1065     }
1066   }
1067 
1068   /* emit y DELTA opcodes */
1069   if (num_delta_after_IUP_args[5])
1070     BCI(DELTAP3);
1071   if (num_delta_after_IUP_args[4])
1072     BCI(DELTAP2);
1073   if (num_delta_after_IUP_args[3])
1074     BCI(DELTAP1);
1075 
1076   if (num_delta_after_IUP_args[2]
1077       || num_delta_after_IUP_args[1]
1078       || num_delta_after_IUP_args[0])
1079     BCI(SVTCA_x);
1080 
1081   /* emit x DELTA opcodes */
1082   if (num_delta_after_IUP_args[2])
1083     BCI(DELTAP3);
1084   if (num_delta_after_IUP_args[1])
1085     BCI(DELTAP2);
1086   if (num_delta_after_IUP_args[0])
1087     BCI(DELTAP1);
1088 
1089   /* we need to insert a few extra bytecode instructions */
1090   /* if we have y delta exceptions before IUP */
1091   if (num_delta_before_IUP_args[5]
1092       || num_delta_before_IUP_args[4]
1093       || num_delta_before_IUP_args[3])
1094   {
1095     FT_Byte* ins_extra_buf_new;
1096     FT_Byte ins_extra_len_new;
1097 
1098 
1099     ins_extra_len_new = glyph->ins_extra_len
1100                         + sizeof (ins_extra_delta_exceptions);
1101     ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
1102                                           ins_extra_len_new);
1103     if (!ins_extra_buf_new)
1104     {
1105       bufp = NULL;
1106       goto Done;
1107     }
1108 
1109     /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1110     /* by activating `ins_extra_delta_exceptions' */
1111     memcpy(ins_extra_buf_new + glyph->ins_extra_len,
1112            ins_extra_delta_exceptions,
1113            sizeof (ins_extra_delta_exceptions));
1114 
1115     glyph->ins_extra_buf = ins_extra_buf_new;
1116     glyph->ins_extra_len = ins_extra_len_new;
1117 
1118     /* reset `cvtl_do_iup_y' for next glyph */
1119     BCI(PUSHB_2);
1120     BCI(cvtl_do_iup_y);
1121     BCI(100);
1122     BCI(WCVTP);
1123   }
1124 
1125 Done:
1126   for (i = 0; i < 6; i++)
1127   {
1128     free(delta_before_IUP_args[i]);
1129     free(delta_after_IUP_args[i]);
1130   }
1131   free(args);
1132 
1133   if (num_before_IUP_stack_elements > sfnt->max_stack_elements)
1134     sfnt->max_stack_elements = num_before_IUP_stack_elements;
1135   if (num_after_IUP_stack_elements > sfnt->max_stack_elements)
1136     sfnt->max_stack_elements = num_after_IUP_stack_elements;
1137 
1138   return bufp;
1139 }
1140 
1141 
1142 static FT_Byte*
TA_sfnt_build_glyph_scaler(SFNT * sfnt,Recorder * recorder,FT_Byte * bufp)1143 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
1144                            Recorder* recorder,
1145                            FT_Byte* bufp)
1146 {
1147   FONT* font = recorder->font;
1148   FT_GlyphSlot glyph = sfnt->face->glyph;
1149   FT_Vector* points = glyph->outline.points;
1150   FT_UInt num_contours = (FT_UInt)glyph->outline.n_contours;
1151 
1152   FT_UInt* args;
1153   FT_UInt* arg;
1154   FT_UInt num_args;
1155 
1156   FT_Bool need_words = 0;
1157   FT_UInt p, q;
1158   FT_UInt start, end;
1159   FT_UShort num_storage;
1160   FT_UShort num_stack_elements;
1161 
1162 
1163   num_args = 2 * num_contours + 2;
1164 
1165   /* collect all arguments temporarily in an array (in reverse order) */
1166   /* so that we can easily split into chunks of 255 args */
1167   /* as needed by NPUSHB and NPUSHW, respectively */
1168   args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1169   if (!args)
1170     return NULL;
1171 
1172   arg = args + num_args - 1;
1173 
1174   if (num_args > 0xFF)
1175     need_words = 1;
1176 
1177   if (recorder->glyph->num_components && font->hint_composites)
1178     *(arg--) = bci_scale_composite_glyph;
1179   else
1180     *(arg--) = bci_scale_glyph;
1181   *(arg--) = num_contours;
1182 
1183   start = 0;
1184   end = 0;
1185 
1186   for (p = 0; p < num_contours; p++)
1187   {
1188     FT_UInt max = start;
1189     FT_UInt min = start;
1190 
1191 
1192     end = (FT_UInt)glyph->outline.contours[p];
1193 
1194     for (q = start; q <= end; q++)
1195     {
1196       if (points[q].y < points[min].y)
1197         min = q;
1198       if (points[q].y > points[max].y)
1199         max = q;
1200     }
1201 
1202     if (min > max)
1203     {
1204       *(arg--) = TA_adjust_point_index(recorder, max);
1205       *(arg--) = TA_adjust_point_index(recorder, min);
1206     }
1207     else
1208     {
1209       *(arg--) = TA_adjust_point_index(recorder, min);
1210       *(arg--) = TA_adjust_point_index(recorder, max);
1211     }
1212 
1213     start = end + 1;
1214   }
1215 
1216   if (end > 0xFF)
1217     need_words = 1;
1218 
1219   /* with most fonts it is very rare */
1220   /* that any of the pushed arguments is larger than 0xFF, */
1221   /* thus we refrain from further optimizing this case */
1222   bufp = TA_build_push(bufp, args, num_args, need_words, 1);
1223 
1224   BCI(CALL);
1225 
1226   num_storage = sal_segment_offset;
1227   if (num_storage > sfnt->max_storage)
1228     sfnt->max_storage = num_storage;
1229 
1230   num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS + num_args);
1231   if (num_stack_elements > sfnt->max_stack_elements)
1232     sfnt->max_stack_elements = num_stack_elements;
1233 
1234   free(args);
1235 
1236   return bufp;
1237 }
1238 
1239 
1240 static FT_Byte*
TA_font_build_subglyph_shifter(FONT * font,FT_Byte * bufp)1241 TA_font_build_subglyph_shifter(FONT* font,
1242                                FT_Byte* bufp)
1243 {
1244   FT_Face face = font->loader->face;
1245   FT_GlyphSlot glyph = face->glyph;
1246 
1247   TA_GlyphLoader gloader = font->loader->gloader;
1248 
1249   TA_SubGlyph subglyphs = gloader->current.subglyphs;
1250   TA_SubGlyph subglyph_limit = subglyphs + gloader->current.num_subglyphs;
1251   TA_SubGlyph subglyph;
1252 
1253   FT_Int curr_contour = 0;
1254 
1255 
1256   for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
1257   {
1258     FT_Error error;
1259 
1260     FT_UShort flags = subglyph->flags;
1261     FT_Pos y_offset = subglyph->arg2;
1262 
1263     FT_Int num_contours;
1264 
1265 
1266     /* load subglyph to get the number of contours */
1267     error = FT_Load_Glyph(face, (FT_UInt)subglyph->index, FT_LOAD_NO_SCALE);
1268     if (error)
1269       return NULL;
1270     num_contours = glyph->outline.n_contours;
1271 
1272     /* nothing to do if there is a point-to-point alignment */
1273     if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1274       goto End;
1275 
1276     /* nothing to do if y offset is zero */
1277     if (!y_offset)
1278       goto End;
1279 
1280     /* nothing to do if there are no contours */
1281     if (!num_contours)
1282       goto End;
1283 
1284     /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1285     /* ensures that composite subglyphs are represented as simple glyphs */
1286 
1287     if (num_contours > 0xFF
1288         || curr_contour > 0xFF)
1289     {
1290       BCI(PUSHW_2);
1291       BCI(HIGH(curr_contour));
1292       BCI(LOW(curr_contour));
1293       BCI(HIGH(num_contours));
1294       BCI(LOW(num_contours));
1295     }
1296     else
1297     {
1298       BCI(PUSHB_2);
1299       BCI(curr_contour);
1300       BCI(num_contours);
1301     }
1302 
1303     /* there are high chances that this value needs PUSHW, */
1304     /* thus we handle it separately */
1305     if (y_offset > 0xFF || y_offset < 0)
1306     {
1307       BCI(PUSHW_1);
1308       BCI(HIGH(y_offset));
1309       BCI(LOW(y_offset));
1310     }
1311     else
1312     {
1313       BCI(PUSHB_1);
1314       BCI(y_offset);
1315     }
1316 
1317     BCI(PUSHB_1);
1318     BCI(bci_shift_subglyph);
1319     BCI(CALL);
1320 
1321   End:
1322     curr_contour += num_contours;
1323   }
1324 
1325   return bufp;
1326 }
1327 
1328 
1329 /*
1330  * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1331  * data in four arrays (which are simple but waste a lot of memory).  The
1332  * function below converts them into bytecode.
1333  *
1334  * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1335  * together with the edge they correspond to.
1336  *
1337  * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1338  * loop over the edge or edge pairs, respectively, and each edge or edge
1339  * pair contains an inner loop to emit the correponding points.
1340  */
1341 
1342 static void
TA_build_point_hints(Recorder * recorder,TA_GlyphHints hints)1343 TA_build_point_hints(Recorder* recorder,
1344                      TA_GlyphHints hints)
1345 {
1346   TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1347   TA_Edge edges = axis->edges;
1348 
1349   FT_Byte* p = recorder->hints_record.buf;
1350 
1351   FT_UShort i;
1352   FT_UShort j;
1353 
1354   FT_UShort prev_edge;
1355   FT_UShort prev_before_edge;
1356   FT_UShort prev_after_edge;
1357 
1358   Node1* before_node;
1359   Node1* after_node;
1360   Node2* on_node;
1361   Node3* between_node;
1362 
1363 
1364   /* we store everything as 16bit numbers; */
1365   /* the function numbers (`ta_ip_before', etc.) */
1366   /* reflect the order in the TA_Action enumeration */
1367 
1368   /* ip_before_points */
1369 
1370   i = 0;
1371   for (before_node = LLRB_MIN(ip_before_points,
1372                               &recorder->ip_before_points_head);
1373        before_node;
1374        before_node = LLRB_NEXT(ip_before_points,
1375                                &recorder->ip_before_points_head,
1376                                before_node))
1377   {
1378     /* count points */
1379     i++;
1380   }
1381 
1382   if (i)
1383   {
1384     TA_Edge edge;
1385     FT_UShort edge_first_idx;
1386 
1387 
1388     recorder->hints_record.num_actions++;
1389 
1390     edge = edges;
1391     edge_first_idx = TA_get_segment_index(edge->first, recorder);
1392 
1393     *(p++) = 0;
1394     *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1395     *(p++) = HIGH(edge_first_idx);
1396     *(p++) = LOW(edge_first_idx);
1397     *(p++) = HIGH(i);
1398     *(p++) = LOW(i);
1399 
1400     for (before_node = LLRB_MIN(ip_before_points,
1401                                 &recorder->ip_before_points_head);
1402          before_node;
1403          before_node = LLRB_NEXT(ip_before_points,
1404                                  &recorder->ip_before_points_head,
1405                                  before_node))
1406     {
1407       FT_UInt point;
1408 
1409 
1410       point = TA_adjust_point_index(recorder, before_node->point);
1411       *(p++) = HIGH(point);
1412       *(p++) = LOW(point);
1413     }
1414   }
1415 
1416   /* ip_after_points */
1417 
1418   i = 0;
1419   for (after_node = LLRB_MIN(ip_after_points,
1420                              &recorder->ip_after_points_head);
1421        after_node;
1422        after_node = LLRB_NEXT(ip_after_points,
1423                               &recorder->ip_after_points_head,
1424                               after_node))
1425   {
1426     /* count points */
1427     i++;
1428   }
1429 
1430   if (i)
1431   {
1432     TA_Edge edge;
1433     FT_UShort edge_first_idx;
1434 
1435 
1436     recorder->hints_record.num_actions++;
1437 
1438     edge = edges + axis->num_edges - 1;
1439     edge_first_idx = TA_get_segment_index(edge->first, recorder);
1440 
1441     *(p++) = 0;
1442     *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1443     *(p++) = HIGH(edge_first_idx);
1444     *(p++) = LOW(edge_first_idx);
1445     *(p++) = HIGH(i);
1446     *(p++) = LOW(i);
1447 
1448     for (after_node = LLRB_MIN(ip_after_points,
1449                                &recorder->ip_after_points_head);
1450          after_node;
1451          after_node = LLRB_NEXT(ip_after_points,
1452                                 &recorder->ip_after_points_head,
1453                                 after_node))
1454     {
1455       FT_UInt point;
1456 
1457 
1458       point = TA_adjust_point_index(recorder, after_node->point);
1459       *(p++) = HIGH(point);
1460       *(p++) = LOW(point);
1461     }
1462   }
1463 
1464   /* ip_on_point_array */
1465 
1466   prev_edge = 0xFFFF;
1467   i = 0;
1468   for (on_node = LLRB_MIN(ip_on_points,
1469                           &recorder->ip_on_points_head);
1470        on_node;
1471        on_node = LLRB_NEXT(ip_on_points,
1472                            &recorder->ip_on_points_head,
1473                            on_node))
1474   {
1475     /* count edges */
1476     if (on_node->edge != prev_edge)
1477     {
1478       i++;
1479       prev_edge = on_node->edge;
1480     }
1481   }
1482 
1483   if (i)
1484   {
1485     recorder->hints_record.num_actions++;
1486 
1487     *(p++) = 0;
1488     *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1489     *(p++) = HIGH(i);
1490     *(p++) = LOW(i);
1491 
1492     for (on_node = LLRB_MIN(ip_on_points,
1493                             &recorder->ip_on_points_head);
1494          on_node;
1495          on_node = LLRB_NEXT(ip_on_points,
1496                              &recorder->ip_on_points_head,
1497                              on_node))
1498     {
1499       Node2* edge_node;
1500       TA_Edge edge;
1501       FT_UShort edge_first_idx;
1502 
1503 
1504       edge = edges + on_node->edge;
1505       edge_first_idx = TA_get_segment_index(edge->first, recorder);
1506 
1507       *(p++) = HIGH(edge_first_idx);
1508       *(p++) = LOW(edge_first_idx);
1509 
1510       /* save current position */
1511       edge_node = on_node;
1512       j = 0;
1513       for (;
1514            on_node;
1515            on_node = LLRB_NEXT(ip_on_points,
1516                                &recorder->ip_on_points_head,
1517                                on_node))
1518       {
1519         /* count points on current edge */
1520         if (on_node->edge != edge_node->edge)
1521           break;
1522         j++;
1523       }
1524 
1525       *(p++) = HIGH(j);
1526       *(p++) = LOW(j);
1527 
1528       /* restore current position */
1529       on_node = edge_node;
1530       for (;
1531            on_node;
1532            on_node = LLRB_NEXT(ip_on_points,
1533                                &recorder->ip_on_points_head,
1534                                on_node))
1535       {
1536         FT_UInt point;
1537 
1538 
1539         if (on_node->edge != edge_node->edge)
1540           break;
1541 
1542         point = TA_adjust_point_index(recorder, on_node->point);
1543         *(p++) = HIGH(point);
1544         *(p++) = LOW(point);
1545 
1546         /* keep track of previous node */
1547         edge_node = on_node;
1548       }
1549 
1550       /* reset loop iterator by one element, then continue */
1551       on_node = edge_node;
1552     }
1553   }
1554 
1555   /* ip_between_point_array */
1556 
1557   prev_before_edge = 0xFFFF;
1558   prev_after_edge = 0xFFFF;
1559   i = 0;
1560   for (between_node = LLRB_MIN(ip_between_points,
1561                                &recorder->ip_between_points_head);
1562        between_node;
1563        between_node = LLRB_NEXT(ip_between_points,
1564                                 &recorder->ip_between_points_head,
1565                                 between_node))
1566   {
1567     /* count `(before,after)' edge pairs */
1568     if (between_node->before_edge != prev_before_edge
1569         || between_node->after_edge != prev_after_edge)
1570     {
1571       i++;
1572       prev_before_edge = between_node->before_edge;
1573       prev_after_edge = between_node->after_edge;
1574     }
1575   }
1576 
1577   if (i)
1578   {
1579     recorder->hints_record.num_actions++;
1580 
1581     *(p++) = 0;
1582     *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1583     *(p++) = HIGH(i);
1584     *(p++) = LOW(i);
1585 
1586     for (between_node = LLRB_MIN(ip_between_points,
1587                                  &recorder->ip_between_points_head);
1588          between_node;
1589          between_node = LLRB_NEXT(ip_between_points,
1590                                   &recorder->ip_between_points_head,
1591                                   between_node))
1592     {
1593       Node3* edge_pair_node;
1594       TA_Edge before;
1595       TA_Edge after;
1596       FT_UShort before_first_idx;
1597       FT_UShort after_first_idx;
1598 
1599 
1600       before = edges + between_node->before_edge;
1601       after = edges + between_node->after_edge;
1602       before_first_idx = TA_get_segment_index(before->first, recorder);
1603       after_first_idx = TA_get_segment_index(after->first, recorder);
1604 
1605       *(p++) = HIGH(after_first_idx);
1606       *(p++) = LOW(after_first_idx);
1607       *(p++) = HIGH(before_first_idx);
1608       *(p++) = LOW(before_first_idx);
1609 
1610       /* save current position */
1611       edge_pair_node = between_node;
1612       j = 0;
1613       for (;
1614            between_node;
1615            between_node = LLRB_NEXT(ip_between_points,
1616                                     &recorder->ip_between_points_head,
1617                                     between_node))
1618       {
1619         /* count points associated with current edge pair */
1620         if (between_node->before_edge != edge_pair_node->before_edge
1621             || between_node->after_edge != edge_pair_node->after_edge)
1622           break;
1623         j++;
1624       }
1625 
1626       *(p++) = HIGH(j);
1627       *(p++) = LOW(j);
1628 
1629       /* restore current position */
1630       between_node = edge_pair_node;
1631       for (;
1632            between_node;
1633            between_node = LLRB_NEXT(ip_between_points,
1634                                     &recorder->ip_between_points_head,
1635                                     between_node))
1636       {
1637         FT_UInt point;
1638 
1639 
1640         if (between_node->before_edge != edge_pair_node->before_edge
1641             || between_node->after_edge != edge_pair_node->after_edge)
1642           break;
1643 
1644         point = TA_adjust_point_index(recorder, between_node->point);
1645         *(p++) = HIGH(point);
1646         *(p++) = LOW(point);
1647 
1648         /* keep track of previous node */
1649         edge_pair_node = between_node;
1650       }
1651 
1652       /* reset loop iterator by one element, then continue */
1653       between_node = edge_pair_node;
1654     }
1655   }
1656 
1657   recorder->hints_record.buf = p;
1658 }
1659 
1660 
1661 static FT_Bool
TA_hints_record_is_different(Hints_Record * hints_records,FT_UInt num_hints_records,FT_Byte * start,FT_Byte * end)1662 TA_hints_record_is_different(Hints_Record* hints_records,
1663                              FT_UInt num_hints_records,
1664                              FT_Byte* start,
1665                              FT_Byte* end)
1666 {
1667   Hints_Record last_hints_record;
1668 
1669 
1670   if (!hints_records)
1671     return 1;
1672 
1673   /* we only need to compare with the last hints record */
1674   last_hints_record = hints_records[num_hints_records - 1];
1675 
1676   if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1677     return 1;
1678 
1679   if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1680     return 1;
1681 
1682   return 0;
1683 }
1684 
1685 
1686 static FT_Error
TA_add_hints_record(Hints_Record ** hints_records,FT_UInt * num_hints_records,FT_Byte * start,Hints_Record hints_record)1687 TA_add_hints_record(Hints_Record** hints_records,
1688                     FT_UInt* num_hints_records,
1689                     FT_Byte* start,
1690                     Hints_Record hints_record)
1691 {
1692   Hints_Record* hints_records_new;
1693   FT_UInt buf_len;
1694   /* at this point, `hints_record.buf' still points into `ins_buf' */
1695   FT_Byte* end = hints_record.buf;
1696 
1697 
1698   buf_len = (FT_UInt)(end - start);
1699 
1700   /* now fill the structure completely */
1701   hints_record.buf_len = buf_len;
1702   hints_record.buf = (FT_Byte*)malloc(buf_len);
1703   if (!hints_record.buf)
1704     return FT_Err_Out_Of_Memory;
1705 
1706   memcpy(hints_record.buf, start, buf_len);
1707 
1708   (*num_hints_records)++;
1709   hints_records_new =
1710     (Hints_Record*)realloc(*hints_records, *num_hints_records
1711                                            * sizeof (Hints_Record));
1712   if (!hints_records_new)
1713   {
1714     free(hints_record.buf);
1715     (*num_hints_records)--;
1716     return FT_Err_Out_Of_Memory;
1717   }
1718   else
1719     *hints_records = hints_records_new;
1720 
1721   (*hints_records)[*num_hints_records - 1] = hints_record;
1722 
1723   return FT_Err_Ok;
1724 }
1725 
1726 
1727 static FT_Byte*
TA_emit_hints_record(Recorder * recorder,Hints_Record * hints_record,FT_Byte * bufp,FT_Bool optimize)1728 TA_emit_hints_record(Recorder* recorder,
1729                      Hints_Record* hints_record,
1730                      FT_Byte* bufp,
1731                      FT_Bool optimize)
1732 {
1733   FT_Byte* p;
1734   FT_Byte* endp;
1735   FT_Bool need_words = 0;
1736 
1737   FT_UInt i, j;
1738   FT_UInt num_arguments;
1739   FT_UInt num_args;
1740 
1741 
1742   /* check whether any argument is larger than 0xFF */
1743   endp = hints_record->buf + hints_record->buf_len;
1744   for (p = hints_record->buf; p < endp; p += 2)
1745     if (*p)
1746     {
1747       need_words = 1;
1748       break;
1749     }
1750 
1751   /* with most fonts it is very rare */
1752   /* that any of the pushed arguments is larger than 0xFF, */
1753   /* thus we refrain from further optimizing this case */
1754 
1755   num_arguments = hints_record->buf_len / 2;
1756   p = endp - 2;
1757 
1758   if (need_words)
1759   {
1760     for (i = 0; i < num_arguments; i += 255)
1761     {
1762       num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1763 
1764       if (optimize && num_args <= 8)
1765         BCI(PUSHW_1 - 1 + num_args);
1766       else
1767       {
1768         BCI(NPUSHW);
1769         BCI(num_args);
1770       }
1771       for (j = 0; j < num_args; j++)
1772       {
1773         BCI(*p);
1774         BCI(*(p + 1));
1775         p -= 2;
1776       }
1777     }
1778   }
1779   else
1780   {
1781     /* we only need the lower bytes */
1782     p++;
1783 
1784     for (i = 0; i < num_arguments; i += 255)
1785     {
1786       num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1787 
1788       if (optimize && num_args <= 8)
1789         BCI(PUSHB_1 - 1 + num_args);
1790       else
1791       {
1792         BCI(NPUSHB);
1793         BCI(num_args);
1794       }
1795       for (j = 0; j < num_args; j++)
1796       {
1797         BCI(*p);
1798         p -= 2;
1799       }
1800     }
1801   }
1802 
1803   /* collect stack depth data */
1804   if (num_arguments > recorder->num_stack_elements)
1805     recorder->num_stack_elements = (FT_UShort)num_arguments;
1806 
1807   return bufp;
1808 }
1809 
1810 
1811 static FT_Byte*
TA_emit_hints_records(Recorder * recorder,Hints_Record * hints_records,FT_UInt num_hints_records,FT_Byte * bufp,FT_Bool optimize)1812 TA_emit_hints_records(Recorder* recorder,
1813                       Hints_Record* hints_records,
1814                       FT_UInt num_hints_records,
1815                       FT_Byte* bufp,
1816                       FT_Bool optimize)
1817 {
1818   FT_UInt i;
1819   Hints_Record* hints_record;
1820 
1821 
1822   hints_record = hints_records;
1823 
1824   /* emit hints records in `if' clauses, */
1825   /* with the ppem size as the condition */
1826   for (i = 0; i < num_hints_records - 1; i++)
1827   {
1828     BCI(MPPEM);
1829     if (hints_record->size > 0xFF)
1830     {
1831       BCI(PUSHW_1);
1832       BCI(HIGH((hints_record + 1)->size));
1833       BCI(LOW((hints_record + 1)->size));
1834     }
1835     else
1836     {
1837       BCI(PUSHB_1);
1838       BCI((hints_record + 1)->size);
1839     }
1840     BCI(LT);
1841     BCI(IF);
1842     bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1843     BCI(ELSE);
1844 
1845     hints_record++;
1846   }
1847 
1848   bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1849 
1850   for (i = 0; i < num_hints_records - 1; i++)
1851     BCI(EIF);
1852 
1853   return bufp;
1854 }
1855 
1856 
1857 static void
TA_free_hints_records(Hints_Record * hints_records,FT_UInt num_hints_records)1858 TA_free_hints_records(Hints_Record* hints_records,
1859                       FT_UInt num_hints_records)
1860 {
1861   FT_UInt i;
1862 
1863 
1864   for (i = 0; i < num_hints_records; i++)
1865     free(hints_records[i].buf);
1866 
1867   free(hints_records);
1868 }
1869 
1870 
1871 static FT_Byte*
TA_hints_recorder_handle_segments(FT_Byte * bufp,Recorder * recorder,TA_Edge edge,FT_UShort * wraps)1872 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1873                                   Recorder* recorder,
1874                                   TA_Edge edge,
1875                                   FT_UShort* wraps)
1876 {
1877   TA_Segment seg;
1878   FT_UShort seg_idx;
1879   FT_UShort num_segs = 0;
1880   FT_UShort* wrap;
1881   FT_UShort num_segments;
1882 
1883 
1884   seg_idx = TA_get_segment_index(edge->first, recorder);
1885   num_segments = TA_get_segment_index(NULL, recorder);
1886 
1887   /* we store everything as 16bit numbers */
1888   *(bufp++) = HIGH(seg_idx);
1889   *(bufp++) = LOW(seg_idx);
1890 
1891   /* wrap-around segments are stored as two segments */
1892   if (edge->first->first > edge->first->last)
1893     num_segs++;
1894 
1895   seg = edge->first->edge_next;
1896   while (seg != edge->first)
1897   {
1898     num_segs++;
1899 
1900     if (seg->first > seg->last)
1901       num_segs++;
1902 
1903     seg = seg->edge_next;
1904   }
1905 
1906   *(bufp++) = HIGH(num_segs);
1907   *(bufp++) = LOW(num_segs);
1908 
1909   if (edge->first->first > edge->first->last)
1910   {
1911     /* emit second part of wrap-around segment; */
1912     /* the bytecode positions such segments after `normal' ones */
1913     wrap = wraps;
1914     for (;;)
1915     {
1916       if (seg_idx == *wrap)
1917         break;
1918       wrap++;
1919     }
1920 
1921     *(bufp++) = HIGH(num_segments + (wrap - wraps));
1922     *(bufp++) = LOW(num_segments + (wrap - wraps));
1923   }
1924 
1925   seg = edge->first->edge_next;
1926   while (seg != edge->first)
1927   {
1928     seg_idx = TA_get_segment_index(seg, recorder);
1929 
1930     *(bufp++) = HIGH(seg_idx);
1931     *(bufp++) = LOW(seg_idx);
1932 
1933     if (seg->first > seg->last)
1934     {
1935       wrap = wraps;
1936       for (;;)
1937       {
1938         if (seg_idx == *wrap)
1939           break;
1940         wrap++;
1941       }
1942 
1943       *(bufp++) = HIGH(num_segments + (wrap - wraps));
1944       *(bufp++) = LOW(num_segments + (wrap - wraps));
1945     }
1946 
1947     seg = seg->edge_next;
1948   }
1949 
1950   return bufp;
1951 }
1952 
1953 
1954 static void
TA_hints_recorder(TA_Action action,TA_GlyphHints hints,TA_Dimension dim,void * arg1,TA_Edge arg2,TA_Edge arg3,TA_Edge lower_bound,TA_Edge upper_bound)1955 TA_hints_recorder(TA_Action action,
1956                   TA_GlyphHints hints,
1957                   TA_Dimension dim,
1958                   void* arg1,
1959                   TA_Edge arg2,
1960                   TA_Edge arg3,
1961                   TA_Edge lower_bound,
1962                   TA_Edge upper_bound)
1963 {
1964   TA_AxisHints axis = &hints->axis[dim];
1965   TA_Edge edges = axis->edges;
1966   TA_Point points = hints->points;
1967 
1968   TA_Segment segments = axis->segments;
1969   TA_Segment seg_limit = segments + axis->num_segments;
1970   TA_Segment seg;
1971 
1972   Recorder* recorder = (Recorder*)hints->user;
1973   SFNT* sfnt = recorder->sfnt;
1974   FONT* font = recorder->font;
1975   FT_UShort* wraps = recorder->wrap_around_segments;
1976   FT_Byte* p = recorder->hints_record.buf;
1977 
1978   TA_StyleClass style_class = font->loader->metrics->style_class;
1979   TA_ScriptClass script_class = ta_script_classes[style_class->script];
1980 
1981   FT_UInt style = style_class->style;
1982   FT_Bool top_to_bottom_hinting = script_class->top_to_bottom_hinting;
1983 
1984 
1985   if (dim == TA_DIMENSION_HORZ)
1986     return;
1987 
1988   if (!recorder->segment_map_initialized)
1989   {
1990     FT_UShort* segment_map = recorder->segment_map;
1991     FT_UShort idx;
1992 
1993 
1994     idx = 0;
1995     for (seg = segments; seg < seg_limit; seg++)
1996     {
1997       if (seg->edge)
1998         *segment_map = idx++;
1999       else
2000         *segment_map = 0xFFFF;
2001 
2002       segment_map++;
2003     }
2004     *segment_map = idx;
2005 
2006     recorder->segment_map_initialized = 1;
2007   }
2008 
2009   if (!recorder->wrap_around_segments_initialized)
2010   {
2011     FT_UShort* wrap_around_segment;
2012 
2013 
2014     wrap_around_segment = recorder->wrap_around_segments;
2015     for (seg = segments; seg < seg_limit; seg++)
2016       if (seg->first > seg->last)
2017         *(wrap_around_segment++) = TA_get_segment_index(seg, recorder);
2018 
2019     recorder->wrap_around_segments_initialized = 1;
2020   }
2021 
2022   /* we collect point hints for later processing */
2023   switch (action)
2024   {
2025   case ta_ip_before:
2026     {
2027       Node1* before_node;
2028       TA_Point point = (TA_Point)arg1;
2029 
2030 
2031       before_node = (Node1*)malloc(sizeof (Node1));
2032       if (!before_node)
2033         return;
2034       before_node->point = (FT_UShort)(point - points);
2035 
2036       LLRB_INSERT(ip_before_points,
2037                   &recorder->ip_before_points_head,
2038                   before_node);
2039     }
2040     return;
2041 
2042   case ta_ip_after:
2043     {
2044       Node1* after_node;
2045       TA_Point point = (TA_Point)arg1;
2046 
2047 
2048       after_node = (Node1*)malloc(sizeof (Node1));
2049       if (!after_node)
2050         return;
2051       after_node->point = (FT_UShort)(point - points);
2052 
2053       LLRB_INSERT(ip_after_points,
2054                   &recorder->ip_after_points_head,
2055                   after_node);
2056     }
2057     return;
2058 
2059   case ta_ip_on:
2060     {
2061       Node2* on_node;
2062       TA_Point point = (TA_Point)arg1;
2063       TA_Edge edge = arg2;
2064 
2065 
2066       on_node = (Node2*)malloc(sizeof (Node2));
2067       if (!on_node)
2068         return;
2069       on_node->edge = (FT_UShort)(edge - edges);
2070       on_node->point = (FT_UShort)(point - points);
2071 
2072       LLRB_INSERT(ip_on_points,
2073                   &recorder->ip_on_points_head,
2074                   on_node);
2075     }
2076     return;
2077 
2078   case ta_ip_between:
2079     {
2080       Node3* between_node;
2081       TA_Point point = (TA_Point)arg1;
2082       TA_Edge before = arg2;
2083       TA_Edge after = arg3;
2084 
2085 
2086       between_node = (Node3*)malloc(sizeof (Node3));
2087       if (!between_node)
2088         return;
2089       between_node->before_edge = (FT_UShort)(before - edges);
2090       between_node->after_edge = (FT_UShort)(after - edges);
2091       between_node->point = (FT_UShort)(point - points);
2092 
2093       LLRB_INSERT(ip_between_points,
2094                   &recorder->ip_between_points_head,
2095                   between_node);
2096     }
2097     return;
2098 
2099   case ta_bound:
2100     /* we ignore the BOUND action since we signal this information */
2101     /* with the proper function number */
2102     return;
2103 
2104   default:
2105     break;
2106   }
2107 
2108   /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2109   /* if the value is n, the function numbers are n, ..., n+11, */
2110   /* to be differentiated with flags */
2111 
2112   switch (action)
2113   {
2114   case ta_link:
2115     {
2116       TA_Edge base_edge = (TA_Edge)arg1;
2117       TA_Edge stem_edge = arg2;
2118       FT_UShort base_first_idx;
2119       FT_UShort stem_first_idx;
2120 
2121 
2122       base_first_idx = TA_get_segment_index(base_edge->first, recorder);
2123       stem_first_idx = TA_get_segment_index(stem_edge->first, recorder);
2124 
2125       *(p++) = 0;
2126       *(p++) = (FT_Byte)action + ACTION_OFFSET
2127                + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
2128                + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
2129 
2130       *(p++) = HIGH(base_first_idx);
2131       *(p++) = LOW(base_first_idx);
2132       *(p++) = HIGH(stem_first_idx);
2133       *(p++) = LOW(stem_first_idx);
2134 
2135       p = TA_hints_recorder_handle_segments(p, recorder, stem_edge, wraps);
2136     }
2137     break;
2138 
2139   case ta_anchor:
2140     {
2141       TA_Edge edge = (TA_Edge)arg1;
2142       TA_Edge edge2 = arg2;
2143       FT_UShort edge_first_idx;
2144       FT_UShort edge2_first_idx;
2145 
2146 
2147       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2148       edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2149 
2150       *(p++) = 0;
2151       *(p++) = (FT_Byte)action + ACTION_OFFSET
2152                + ((edge2->flags & TA_EDGE_SERIF) != 0)
2153                + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
2154 
2155       *(p++) = HIGH(edge_first_idx);
2156       *(p++) = LOW(edge_first_idx);
2157       *(p++) = HIGH(edge2_first_idx);
2158       *(p++) = LOW(edge2_first_idx);
2159 
2160       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2161     }
2162     break;
2163 
2164   case ta_adjust:
2165     {
2166       TA_Edge edge = (TA_Edge)arg1;
2167       TA_Edge edge2 = arg2;
2168       TA_Edge edge_minus_one = lower_bound;
2169       FT_UShort edge_first_idx;
2170       FT_UShort edge2_first_idx;
2171 
2172 
2173       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2174       edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2175 
2176       *(p++) = 0;
2177       *(p++) = (FT_Byte)action + ACTION_OFFSET
2178                + ((edge2->flags & TA_EDGE_SERIF) != 0)
2179                + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2180                + 4 * (edge_minus_one != NULL) /* `bound' */
2181                + 4 * (edge_minus_one != NULL
2182                       && top_to_bottom_hinting); /* `down' */
2183 
2184       *(p++) = HIGH(edge_first_idx);
2185       *(p++) = LOW(edge_first_idx);
2186       *(p++) = HIGH(edge2_first_idx);
2187       *(p++) = LOW(edge2_first_idx);
2188 
2189       if (edge_minus_one)
2190       {
2191         FT_UShort edge_minus_one_first_idx;
2192 
2193 
2194         edge_minus_one_first_idx = TA_get_segment_index(
2195                                      edge_minus_one->first, recorder);
2196 
2197         *(p++) = HIGH(edge_minus_one_first_idx);
2198         *(p++) = LOW(edge_minus_one_first_idx);
2199       }
2200 
2201       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2202     }
2203     break;
2204 
2205   case ta_blue_anchor:
2206     {
2207       TA_Edge edge = (TA_Edge)arg1;
2208       TA_Edge blue = arg2;
2209       FT_UShort blue_first_idx;
2210       FT_UShort edge_first_idx;
2211 
2212 
2213       blue_first_idx = TA_get_segment_index(blue->first, recorder);
2214       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2215 
2216       *(p++) = 0;
2217       *(p++) = (FT_Byte)action + ACTION_OFFSET;
2218 
2219       *(p++) = HIGH(blue_first_idx);
2220       *(p++) = LOW(blue_first_idx);
2221 
2222       if (edge->best_blue_is_shoot)
2223       {
2224         *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2225         *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2226       }
2227       else
2228       {
2229         *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2230         *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2231       }
2232 
2233       *(p++) = HIGH(edge_first_idx);
2234       *(p++) = LOW(edge_first_idx);
2235 
2236       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2237     }
2238     break;
2239 
2240   case ta_stem:
2241     {
2242       TA_Edge edge = (TA_Edge)arg1;
2243       TA_Edge edge2 = arg2;
2244       TA_Edge edge_minus_one = lower_bound;
2245       FT_UShort edge_first_idx;
2246       FT_UShort edge2_first_idx;
2247 
2248 
2249       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2250       edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2251 
2252       *(p++) = 0;
2253       *(p++) = (FT_Byte)action + ACTION_OFFSET
2254                + ((edge2->flags & TA_EDGE_SERIF) != 0)
2255                + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2256                + 4 * (edge_minus_one != NULL) /* `bound' */
2257                + 4 * (edge_minus_one != NULL
2258                       && top_to_bottom_hinting); /* `down' */
2259 
2260       *(p++) = HIGH(edge_first_idx);
2261       *(p++) = LOW(edge_first_idx);
2262       *(p++) = HIGH(edge2_first_idx);
2263       *(p++) = LOW(edge2_first_idx);
2264 
2265       if (edge_minus_one)
2266       {
2267         FT_UShort edge_minus_one_first_idx;
2268 
2269 
2270         edge_minus_one_first_idx = TA_get_segment_index(
2271                                      edge_minus_one->first, recorder);
2272 
2273         *(p++) = HIGH(edge_minus_one_first_idx);
2274         *(p++) = LOW(edge_minus_one_first_idx);
2275       }
2276 
2277       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2278       p = TA_hints_recorder_handle_segments(p, recorder, edge2, wraps);
2279     }
2280     break;
2281 
2282   case ta_blue:
2283     {
2284       TA_Edge edge = (TA_Edge)arg1;
2285       FT_UShort edge_first_idx;
2286 
2287 
2288       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2289 
2290       *(p++) = 0;
2291       *(p++) = (FT_Byte)action + ACTION_OFFSET;
2292 
2293       if (edge->best_blue_is_shoot)
2294       {
2295         *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2296         *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2297       }
2298       else
2299       {
2300         *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2301         *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2302       }
2303 
2304       *(p++) = HIGH(edge_first_idx);
2305       *(p++) = LOW(edge_first_idx);
2306 
2307       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2308     }
2309     break;
2310 
2311   case ta_serif:
2312     {
2313       TA_Edge serif = (TA_Edge)arg1;
2314       TA_Edge base = serif->serif;
2315       FT_UShort serif_first_idx;
2316       FT_UShort base_first_idx;
2317 
2318 
2319       serif_first_idx = TA_get_segment_index(serif->first, recorder);
2320       base_first_idx = TA_get_segment_index(base->first, recorder);
2321 
2322       *(p++) = 0;
2323       *(p++) = (FT_Byte)action + ACTION_OFFSET
2324                + (lower_bound != NULL)
2325                + 2 * (upper_bound != NULL)
2326                + 3 * ((lower_bound != NULL || upper_bound != NULL)
2327                       && top_to_bottom_hinting); /* `down' */
2328 
2329       *(p++) = HIGH(serif_first_idx);
2330       *(p++) = LOW(serif_first_idx);
2331       *(p++) = HIGH(base_first_idx);
2332       *(p++) = LOW(base_first_idx);
2333 
2334       if (lower_bound)
2335       {
2336         FT_UShort lower_bound_first_idx;
2337 
2338 
2339         lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2340                                                      recorder);
2341 
2342         *(p++) = HIGH(lower_bound_first_idx);
2343         *(p++) = LOW(lower_bound_first_idx);
2344       }
2345       if (upper_bound)
2346       {
2347         FT_UShort upper_bound_first_idx;
2348 
2349 
2350         upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2351                                                      recorder);
2352 
2353         *(p++) = HIGH(upper_bound_first_idx);
2354         *(p++) = LOW(upper_bound_first_idx);
2355       }
2356 
2357       p = TA_hints_recorder_handle_segments(p, recorder, serif, wraps);
2358     }
2359     break;
2360 
2361   case ta_serif_anchor:
2362   case ta_serif_link2:
2363     {
2364       TA_Edge edge = (TA_Edge)arg1;
2365       FT_UShort edge_first_idx;
2366 
2367 
2368       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2369 
2370       *(p++) = 0;
2371       *(p++) = (FT_Byte)action + ACTION_OFFSET
2372                + (lower_bound != NULL)
2373                + 2 * (upper_bound != NULL)
2374                + 3 * ((lower_bound != NULL || upper_bound != NULL)
2375                       && top_to_bottom_hinting); /* `down' */
2376 
2377       *(p++) = HIGH(edge_first_idx);
2378       *(p++) = LOW(edge_first_idx);
2379 
2380       if (lower_bound)
2381       {
2382         FT_UShort lower_bound_first_idx;
2383 
2384 
2385         lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2386                                                      recorder);
2387 
2388         *(p++) = HIGH(lower_bound_first_idx);
2389         *(p++) = LOW(lower_bound_first_idx);
2390       }
2391       if (upper_bound)
2392       {
2393         FT_UShort upper_bound_first_idx;
2394 
2395 
2396         upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2397                                                      recorder);
2398 
2399         *(p++) = HIGH(upper_bound_first_idx);
2400         *(p++) = LOW(upper_bound_first_idx);
2401       }
2402 
2403       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2404     }
2405     break;
2406 
2407   case ta_serif_link1:
2408     {
2409       TA_Edge edge = (TA_Edge)arg1;
2410       TA_Edge before = arg2;
2411       TA_Edge after = arg3;
2412       FT_UShort before_first_idx;
2413       FT_UShort edge_first_idx;
2414       FT_UShort after_first_idx;
2415 
2416 
2417       before_first_idx = TA_get_segment_index(before->first, recorder);
2418       edge_first_idx = TA_get_segment_index(edge->first, recorder);
2419       after_first_idx = TA_get_segment_index(after->first, recorder);
2420 
2421       *(p++) = 0;
2422       *(p++) = (FT_Byte)action + ACTION_OFFSET
2423                + (lower_bound != NULL)
2424                + 2 * (upper_bound != NULL)
2425                + 3 * ((lower_bound != NULL || upper_bound != NULL)
2426                       && top_to_bottom_hinting); /* `down' */
2427 
2428       *(p++) = HIGH(before_first_idx);
2429       *(p++) = LOW(before_first_idx);
2430       *(p++) = HIGH(edge_first_idx);
2431       *(p++) = LOW(edge_first_idx);
2432       *(p++) = HIGH(after_first_idx);
2433       *(p++) = LOW(after_first_idx);
2434 
2435       if (lower_bound)
2436       {
2437         FT_UShort lower_bound_first_idx;
2438 
2439 
2440         lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2441                                                      recorder);
2442 
2443         *(p++) = HIGH(lower_bound_first_idx);
2444         *(p++) = LOW(lower_bound_first_idx);
2445       }
2446       if (upper_bound)
2447       {
2448         FT_UShort upper_bound_first_idx;
2449 
2450 
2451         upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2452                                                      recorder);
2453 
2454         *(p++) = HIGH(upper_bound_first_idx);
2455         *(p++) = LOW(upper_bound_first_idx);
2456       }
2457 
2458       p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2459     }
2460     break;
2461 
2462   default:
2463     /* there are more cases in the enumeration */
2464     /* which are handled with flags */
2465     break;
2466   }
2467 
2468   recorder->hints_record.num_actions++;
2469   recorder->hints_record.buf = p;
2470 }
2471 
2472 
2473 static FT_Error
TA_init_recorder(Recorder * recorder,SFNT * sfnt,FONT * font,GLYPH * glyph,TA_GlyphHints hints)2474 TA_init_recorder(Recorder* recorder,
2475                  SFNT* sfnt,
2476                  FONT* font,
2477                  GLYPH* glyph,
2478                  TA_GlyphHints hints)
2479 {
2480   TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2481 
2482   TA_Segment segments = axis->segments;
2483   TA_Segment seg_limit = segments + axis->num_segments;
2484   TA_Segment seg;
2485 
2486 
2487   recorder->sfnt = sfnt;
2488   recorder->font = font;
2489   recorder->glyph = glyph;
2490 
2491   LLRB_INIT(&recorder->ip_before_points_head);
2492   LLRB_INIT(&recorder->ip_after_points_head);
2493   LLRB_INIT(&recorder->ip_on_points_head);
2494   LLRB_INIT(&recorder->ip_between_points_head);
2495 
2496   recorder->num_stack_elements = 0;
2497 
2498   /* no need to clean up allocated arrays in case of error; */
2499   /* this is handled later by `TA_free_recorder' */
2500 
2501   /* we use segment_map[axis->num_segments] */
2502   /* as the total number of mapped segments, so allocate one more element */
2503   recorder->segment_map =
2504     (FT_UShort*)malloc((size_t)(axis->num_segments + 1) * sizeof (FT_UShort));
2505   if (!recorder->segment_map)
2506     return FT_Err_Out_Of_Memory;
2507 
2508   /* `segment_map' gets initialized later on, */
2509   /* after the first call of `ta_loader_load_glyph' */
2510   recorder->segment_map_initialized = 0;
2511 
2512   recorder->num_wrap_around_segments = 0;
2513   for (seg = segments; seg < seg_limit; seg++)
2514     if (seg->first > seg->last)
2515       recorder->num_wrap_around_segments++;
2516 
2517   recorder->wrap_around_segments =
2518     (FT_UShort*)malloc(recorder->num_wrap_around_segments
2519                        * sizeof (FT_UShort));
2520   if (!recorder->wrap_around_segments)
2521     return FT_Err_Out_Of_Memory;
2522 
2523   /* `wrap_around_segments' gets initialized later on; */
2524   /* it needs function `TA_get_segment_index' which uses data */
2525   /* that hasn't been initialized yet either */
2526   recorder->wrap_around_segments_initialized = 0;
2527 
2528   return FT_Err_Ok;
2529 }
2530 
2531 
2532 static void
TA_reset_recorder(Recorder * recorder,FT_Byte * bufp)2533 TA_reset_recorder(Recorder* recorder,
2534                   FT_Byte* bufp)
2535 {
2536   recorder->hints_record.buf = bufp;
2537   recorder->hints_record.num_actions = 0;
2538 }
2539 
2540 
2541 static void
TA_rewind_recorder(Recorder * recorder,FT_Byte * bufp,FT_UInt size)2542 TA_rewind_recorder(Recorder* recorder,
2543                    FT_Byte* bufp,
2544                    FT_UInt size)
2545 {
2546   Node1* before_node;
2547   Node1* after_node;
2548   Node2* on_node;
2549   Node3* between_node;
2550 
2551   Node1* next_before_node;
2552   Node1* next_after_node;
2553   Node2* next_on_node;
2554   Node3* next_between_node;
2555 
2556 
2557   TA_reset_recorder(recorder, bufp);
2558 
2559   recorder->hints_record.size = size;
2560 
2561   /* deallocate our red-black trees */
2562 
2563   for (before_node = LLRB_MIN(ip_before_points,
2564                               &recorder->ip_before_points_head);
2565        before_node;
2566        before_node = next_before_node)
2567   {
2568     next_before_node = LLRB_NEXT(ip_before_points,
2569                                  &recorder->ip_before_points_head,
2570                                  before_node);
2571     LLRB_REMOVE(ip_before_points,
2572                 &recorder->ip_before_points_head,
2573                 before_node);
2574     free(before_node);
2575   }
2576 
2577   for (after_node = LLRB_MIN(ip_after_points,
2578                              &recorder->ip_after_points_head);
2579        after_node;
2580        after_node = next_after_node)
2581   {
2582     next_after_node = LLRB_NEXT(ip_after_points,
2583                                 &recorder->ip_after_points_head,
2584                                 after_node);
2585     LLRB_REMOVE(ip_after_points,
2586                 &recorder->ip_after_points_head,
2587                 after_node);
2588     free(after_node);
2589   }
2590 
2591   for (on_node = LLRB_MIN(ip_on_points,
2592                           &recorder->ip_on_points_head);
2593        on_node;
2594        on_node = next_on_node)
2595   {
2596     next_on_node = LLRB_NEXT(ip_on_points,
2597                              &recorder->ip_on_points_head,
2598                              on_node);
2599     LLRB_REMOVE(ip_on_points,
2600                 &recorder->ip_on_points_head,
2601                 on_node);
2602     free(on_node);
2603   }
2604 
2605   for (between_node = LLRB_MIN(ip_between_points,
2606                                &recorder->ip_between_points_head);
2607        between_node;
2608        between_node = next_between_node)
2609   {
2610     next_between_node = LLRB_NEXT(ip_between_points,
2611                                   &recorder->ip_between_points_head,
2612                                   between_node);
2613     LLRB_REMOVE(ip_between_points,
2614                 &recorder->ip_between_points_head,
2615                 between_node);
2616     free(between_node);
2617   }
2618 }
2619 
2620 
2621 static void
TA_free_recorder(Recorder * recorder)2622 TA_free_recorder(Recorder* recorder)
2623 {
2624   free(recorder->segment_map);
2625   free(recorder->wrap_around_segments);
2626 
2627   TA_rewind_recorder(recorder, NULL, 0);
2628 }
2629 
2630 
2631 FT_Error
TA_sfnt_build_glyph_instructions(SFNT * sfnt,FONT * font,FT_Long idx)2632 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2633                                  FONT* font,
2634                                  FT_Long idx)
2635 {
2636   FT_Face face = sfnt->face;
2637   FT_Error error;
2638 
2639   FT_Byte* ins_buf;
2640   FT_UInt ins_len;
2641   FT_Byte* bufp;
2642   FT_Byte* p;
2643 
2644   SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2645   glyf_Data* data = (glyf_Data*)glyf_table->data;
2646   /* `idx' is never negative */
2647   GLYPH* glyph = &data->glyphs[idx];
2648 
2649   TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
2650   FT_UShort* gstyles = globals->glyph_styles;
2651   FT_Bool use_gstyle_data = 1;
2652 
2653   TA_GlyphHints hints;
2654 
2655   FT_UInt num_action_hints_records = 0;
2656   FT_UInt num_point_hints_records = 0;
2657   Hints_Record* action_hints_records = NULL;
2658   Hints_Record* point_hints_records = NULL;
2659 
2660   Recorder recorder;
2661   FT_UShort num_stack_elements;
2662   FT_Bool optimize = 0;
2663 
2664   FT_Int32 load_flags;
2665   FT_UInt size;
2666 
2667   /* we store only three positions, but it simplifies the algorithm in */
2668   /* `TA_optimize_push' if we have one additional element */
2669   FT_Byte* pos[4];
2670 
2671 #ifdef TA_DEBUG
2672   int _ta_debug_save;
2673 #endif
2674 
2675 
2676   /* XXX: right now, we abuse this flag to control */
2677   /*      the global behaviour of the auto-hinter */
2678   load_flags = 1 << 29; /* vertical hinting only */
2679   if (!font->adjust_subglyphs)
2680   {
2681     if (font->hint_composites)
2682       load_flags |= FT_LOAD_NO_SCALE;
2683     else
2684       load_flags |= FT_LOAD_NO_RECURSE;
2685   }
2686 
2687   /* computing the segments is resolution independent, */
2688   /* thus the pixel size in this call is arbitrary -- */
2689   /* however, we avoid unnecessary debugging output */
2690   /* if we use the lowest value of the hinting range */
2691   error = FT_Set_Pixel_Sizes(face,
2692                              font->hinting_range_min,
2693                              font->hinting_range_min);
2694   if (error)
2695     return error;
2696 
2697   /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2698   /* to modify `out' directions of points at the user's request */
2699   /* (which will eventually become single-point segments) */
2700   error = TA_control_segment_dir_collect(font, face->face_index, idx);
2701   if (error)
2702     return error;
2703 
2704 #ifdef TA_DEBUG
2705   /* temporarily disable some debugging output */
2706   /* to avoid getting the information twice */
2707   _ta_debug_save = _ta_debug;
2708   _ta_debug = 0;
2709 #endif
2710 
2711   ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2712   error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2713 
2714 #ifdef TA_DEBUG
2715   _ta_debug = _ta_debug_save;
2716 #endif
2717 
2718   if (error)
2719     return error;
2720 
2721   /* do nothing if we have an empty glyph */
2722   if (!(font->loader->gloader->current.num_subglyphs
2723         || face->glyph->outline.n_contours))
2724     return FT_Err_Ok;
2725 
2726   hints = &font->loader->hints;
2727 
2728   /*
2729    * We allocate a buffer which is certainly large enough
2730    * to hold all of the created bytecode instructions;
2731    * later on it gets reallocated to its real size.
2732    *
2733    * The value `1000' is a very rough guess, not tested well.
2734    *
2735    * For delta exceptions, we have three DELTA commands,
2736    * covering 3*16 ppem values.
2737    * Since a point index can be larger than 255,
2738    * we assume two bytes everywhere for the necessary PUSH calls.
2739    * This value must be doubled for the other arguments of DELTA.
2740    * Additionally, we have both x and y deltas,
2741    * which need to be handled separately in the bytecode.
2742    * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2743    * adding some bytes for the necessary overhead.
2744    */
2745   ins_len = (FT_UInt)(hints->num_points
2746                       * (1000
2747                          + ((font->control_data_head != NULL) ? 400 : 0)));
2748   ins_buf = (FT_Byte*)malloc(ins_len);
2749   if (!ins_buf)
2750     return FT_Err_Out_Of_Memory;
2751 
2752   /* handle composite glyph */
2753   if (font->loader->gloader->current.num_subglyphs)
2754   {
2755     bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2756     if (!bufp)
2757     {
2758       error = FT_Err_Out_Of_Memory;
2759       goto Err;
2760     }
2761 
2762     use_gstyle_data = 0;
2763 
2764     goto Done1;
2765   }
2766 
2767 
2768   if (font->fallback_scaling)
2769   {
2770     TA_StyleClass style_class = font->loader->metrics->style_class;
2771 
2772 
2773     if (style_class == &ta_none_dflt_style_class)
2774     {
2775       /* the scaling value of `none_dflt' */
2776       /* (this is, hinting without script-specific blue zones) */
2777       /* is always 1, which corresponds to a no-op */
2778       bufp = ins_buf;
2779 
2780       use_gstyle_data = 0;
2781 
2782       goto Done1;
2783     }
2784     else if (style_class == ta_style_classes[font->fallback_style])
2785     {
2786       /* since `TA_init_recorder' hasn't been called yet, */
2787       /* we manually initialize the `sfnt', `font', and `glyph' fields */
2788       recorder.sfnt = sfnt;
2789       recorder.font = font;
2790       recorder.glyph = glyph;
2791 
2792       bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2793       if (!bufp)
2794       {
2795         error = FT_Err_Out_Of_Memory;
2796         goto Err;
2797       }
2798 
2799       use_gstyle_data = 0;
2800 
2801       goto Done1;
2802     }
2803   }
2804 
2805   error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2806   if (error)
2807     goto Err;
2808 
2809   /* loop over a large range of pixel sizes */
2810   /* to find hints records which get pushed onto the bytecode stack */
2811 
2812 #ifdef DEBUGGING
2813   if (font->debug)
2814   {
2815     int num_chars, i;
2816     char buf[256];
2817 
2818 
2819     (void)FT_Get_Glyph_Name(face, (FT_UInt)idx, buf, 256);
2820 
2821     num_chars = fprintf(stderr, "glyph %ld", idx);
2822     if (*buf)
2823       num_chars += fprintf(stderr, " (%s)", buf);
2824     fprintf(stderr, "\n");
2825     for (i = 0; i < num_chars; i++)
2826       putc('=', stderr);
2827     fprintf(stderr, "\n\n");
2828 
2829   }
2830 #endif
2831 
2832   /* we temporarily use `ins_buf' to record the current glyph hints */
2833   ta_loader_register_hints_recorder(font->loader,
2834                                     TA_hints_recorder,
2835                                     (void*)&recorder);
2836 
2837   /*
2838    * It is important that we start the loop with the smallest PPEM value
2839    * used for hinting, since the number of segments that form an edge can
2840    * become smaller for larger PPEM values.  For efficiency, we skip
2841    * non-edge one-point segments, and `TA_get_segment_index' would return
2842    * wrong indices otherwise.
2843    */
2844   for (size = font->hinting_range_min;
2845        size <= font->hinting_range_max;
2846        size++)
2847   {
2848 #ifdef DEBUGGING
2849     int have_dumps = 0;
2850 #endif
2851 
2852 
2853     TA_rewind_recorder(&recorder, ins_buf, size);
2854 
2855     error = FT_Set_Pixel_Sizes(face, size, size);
2856     if (error)
2857       goto Err;
2858 
2859 #ifdef DEBUGGING
2860     if (font->debug)
2861     {
2862       int num_chars, i;
2863 
2864 
2865       num_chars = fprintf(stderr, "size %d\n", size);
2866       for (i = 0; i < num_chars - 1; i++)
2867         putc('-', stderr);
2868       fprintf(stderr, "\n\n");
2869     }
2870 #endif
2871 
2872     /* calling `ta_loader_load_glyph' uses the */
2873     /* `TA_hints_recorder' function as a callback, */
2874     /* modifying `hints_record' */
2875     error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2876     if (error)
2877       goto Err;
2878 
2879     if (TA_hints_record_is_different(action_hints_records,
2880                                      num_action_hints_records,
2881                                      ins_buf, recorder.hints_record.buf))
2882     {
2883 #ifdef DEBUGGING
2884       if (font->debug)
2885       {
2886         have_dumps = 1;
2887 
2888         ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2889         ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2890         ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2891 
2892         fprintf(stderr, "action hints record:\n");
2893         if (ins_buf == recorder.hints_record.buf)
2894           fprintf(stderr, "  (none)");
2895         else
2896         {
2897           fprintf(stderr, "  ");
2898           for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2899             fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2900         }
2901         fprintf(stderr, "\n");
2902       }
2903 #endif
2904 
2905       error = TA_add_hints_record(&action_hints_records,
2906                                   &num_action_hints_records,
2907                                   ins_buf, recorder.hints_record);
2908       if (error)
2909         goto Err;
2910     }
2911 
2912     /* now handle point records */
2913 
2914     TA_reset_recorder(&recorder, ins_buf);
2915 
2916     /* use the point hints data collected in `TA_hints_recorder' */
2917     TA_build_point_hints(&recorder, hints);
2918 
2919     if (TA_hints_record_is_different(point_hints_records,
2920                                      num_point_hints_records,
2921                                      ins_buf, recorder.hints_record.buf))
2922     {
2923 #ifdef DEBUGGING
2924       if (font->debug)
2925       {
2926         if (!have_dumps)
2927         {
2928           int num_chars, i;
2929 
2930 
2931           num_chars = fprintf(stderr, "size %d\n", size);
2932           for (i = 0; i < num_chars - 1; i++)
2933             putc('-', stderr);
2934           fprintf(stderr, "\n\n");
2935 
2936           ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2937           ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2938           ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2939         }
2940 
2941         fprintf(stderr, "point hints record:\n");
2942         if (ins_buf == recorder.hints_record.buf)
2943           fprintf(stderr, "  (none)");
2944         else
2945         {
2946           fprintf(stderr, "  ");
2947           for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2948             fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2949         }
2950         fprintf(stderr, "\n\n");
2951       }
2952 #endif
2953 
2954       error = TA_add_hints_record(&point_hints_records,
2955                                   &num_point_hints_records,
2956                                   ins_buf, recorder.hints_record);
2957       if (error)
2958         goto Err;
2959     }
2960   }
2961 
2962   if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2963   {
2964     /* since we only have a single empty record we just scale the glyph */
2965     bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2966     if (!bufp)
2967     {
2968       error = FT_Err_Out_Of_Memory;
2969       goto Err;
2970     }
2971 
2972     use_gstyle_data = 0;
2973 
2974     goto Done;
2975   }
2976 
2977   /* if there is only a single record, */
2978   /* we do a global optimization later on */
2979   if (num_action_hints_records > 1)
2980     optimize = 1;
2981 
2982   /* store the hints records and handle stack depth */
2983   pos[0] = ins_buf;
2984   bufp = TA_emit_hints_records(&recorder,
2985                                point_hints_records,
2986                                num_point_hints_records,
2987                                ins_buf,
2988                                optimize);
2989 
2990   num_stack_elements = recorder.num_stack_elements;
2991   recorder.num_stack_elements = 0;
2992 
2993   pos[1] = bufp;
2994   bufp = TA_emit_hints_records(&recorder,
2995                                action_hints_records,
2996                                num_action_hints_records,
2997                                bufp,
2998                                optimize);
2999 
3000   recorder.num_stack_elements += num_stack_elements;
3001 
3002   pos[2] = bufp;
3003   bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
3004   if (!bufp)
3005   {
3006     error = FT_Err_Out_Of_Memory;
3007     goto Err;
3008   }
3009 
3010   if (num_action_hints_records == 1)
3011     bufp = TA_optimize_push(ins_buf, pos);
3012 
3013 Done:
3014   TA_free_hints_records(action_hints_records, num_action_hints_records);
3015   TA_free_hints_records(point_hints_records, num_point_hints_records);
3016   TA_free_recorder(&recorder);
3017 
3018 Done1:
3019   /* handle delta exceptions */
3020   if (font->control_data_head)
3021   {
3022     bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
3023     if (!bufp)
3024     {
3025       error = FT_Err_Out_Of_Memory;
3026       goto Err;
3027     }
3028   }
3029 
3030   /* we need to insert a few extra bytecode instructions */
3031   /* for non-base glyphs */
3032   if (use_gstyle_data && (gstyles[idx] & TA_NONBASE))
3033   {
3034     FT_Byte* ins_extra_buf_new;
3035     FT_Byte ins_extra_len_new;
3036 
3037 
3038     ins_extra_len_new = glyph->ins_extra_len
3039                         + sizeof (ins_extra_ignore_std_width);
3040     ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
3041                                           ins_extra_len_new);
3042     if (!ins_extra_buf_new)
3043     {
3044       bufp = NULL;
3045       goto Done;
3046     }
3047 
3048     /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3049     /* by activating `ins_extra_ignore_std_width' */
3050     memcpy(ins_extra_buf_new + glyph->ins_extra_len,
3051            ins_extra_ignore_std_width,
3052            sizeof (ins_extra_ignore_std_width));
3053 
3054     glyph->ins_extra_buf = ins_extra_buf_new;
3055     glyph->ins_extra_len = ins_extra_len_new;
3056 
3057     /* reset `cvtl_ignore_std_width' for next glyph */
3058     BCI(PUSHB_2);
3059     BCI(cvtl_ignore_std_width);
3060     BCI(0);
3061     BCI(WCVTP);
3062   }
3063 
3064   ins_len = (FT_UInt)(bufp - ins_buf);
3065 
3066   if (ins_len > sfnt->max_instructions)
3067     sfnt->max_instructions = (FT_UShort)ins_len;
3068 
3069   glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
3070   glyph->ins_len = ins_len;
3071 
3072   return FT_Err_Ok;
3073 
3074 Err:
3075   TA_free_hints_records(action_hints_records, num_action_hints_records);
3076   TA_free_hints_records(point_hints_records, num_point_hints_records);
3077   TA_free_recorder(&recorder);
3078   free(ins_buf);
3079 
3080   return error;
3081 }
3082 
3083 
3084 /* end of tabytecode.c */
3085