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