autotroll.m4: Clean up Qt path stuff.
[ttfautohint.git] / lib / tabytecode.c
blob2320f5343233fecd58b5d5bf4363cf28e057d4cd
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2017 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
18 #include <stdbool.h> /* for llrb.h */
20 #include "llrb.h" /* a red-black tree implementation */
21 #include "tahints.h"
24 #define DEBUGGING
27 #ifdef TA_DEBUG
28 int _ta_debug = 0;
29 int _ta_debug_global = 0;
30 int _ta_debug_disable_horz_hints;
31 int _ta_debug_disable_vert_hints;
32 int _ta_debug_disable_blue_hints;
33 void* _ta_debug_hints;
34 #endif
37 /* node structures for point hints */
39 typedef struct Node1 Node1;
40 struct Node1
42 LLRB_ENTRY(Node1) entry1;
43 FT_UShort point;
46 typedef struct Node2 Node2;
47 struct Node2
49 LLRB_ENTRY(Node2) entry2;
50 FT_UShort edge;
51 FT_UShort point;
54 typedef struct Node3 Node3;
55 struct Node3
57 LLRB_ENTRY(Node3) entry3;
58 FT_UShort before_edge;
59 FT_UShort after_edge;
60 FT_UShort point;
64 /* comparison functions for our red-black trees */
66 static int
67 node1cmp(Node1* e1,
68 Node1* e2)
70 /* sort by points */
71 return e1->point - e2->point;
74 static int
75 node2cmp(Node2* e1,
76 Node2* e2)
78 FT_Int delta;
81 /* sort by edges ... */
82 delta = (FT_Int)e1->edge - (FT_Int)e2->edge;
83 if (delta)
84 return delta;
86 /* ... then by points */
87 return (FT_Int)e1->point - (FT_Int)e2->point;
90 static int
91 node3cmp(Node3* e1,
92 Node3* e2)
94 FT_Int delta;
97 /* sort by `before' edges ... */
98 delta = (FT_Int)e1->before_edge - (FT_Int)e2->before_edge;
99 if (delta)
100 return delta;
102 /* ... then by `after' edges ... */
103 delta = (FT_Int)e1->after_edge - (FT_Int)e2->after_edge;
104 if (delta)
105 return delta;
107 /* ... then by points */
108 return (FT_Int)e1->point - (FT_Int)e2->point;
112 /* the red-black tree function bodies */
113 typedef struct ip_before_points ip_before_points;
114 typedef struct ip_after_points ip_after_points;
115 typedef struct ip_on_points ip_on_points;
116 typedef struct ip_between_points ip_between_points;
118 LLRB_HEAD(ip_before_points, Node1);
119 LLRB_HEAD(ip_after_points, Node1);
120 LLRB_HEAD(ip_on_points, Node2);
121 LLRB_HEAD(ip_between_points, Node3);
123 /* no trailing semicolon in the next four lines */
124 LLRB_GENERATE_STATIC(ip_before_points, Node1, entry1, node1cmp)
125 LLRB_GENERATE_STATIC(ip_after_points, Node1, entry1, node1cmp)
126 LLRB_GENERATE_STATIC(ip_on_points, Node2, entry2, node2cmp)
127 LLRB_GENERATE_STATIC(ip_between_points, Node3, entry3, node3cmp)
130 typedef struct Hints_Record_
132 FT_UInt size;
133 FT_UInt num_actions;
134 FT_Byte* buf;
135 FT_UInt buf_len;
136 } Hints_Record;
138 typedef struct Recorder_
140 SFNT* sfnt;
141 FONT* font;
142 GLYPH* glyph; /* the current glyph */
143 Hints_Record hints_record;
145 /* some segments can `wrap around' */
146 /* a contour's start point like 24-25-26-0-1-2 */
147 /* (there can be at most one such segment per contour); */
148 /* later on we append additional records */
149 /* to split them into 24-26 and 0-2 */
150 FT_UShort* wrap_around_segments;
151 FT_UShort num_wrap_around_segments;
152 FT_Bool wrap_around_segments_initialized;
154 FT_UShort num_stack_elements; /* the necessary stack depth so far */
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;
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;
169 /* this is the bytecode of the `.ttfautohint' glyph */
171 FT_Byte ttfautohint_glyph_bytecode[7] =
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,
186 /* if we have y delta exceptions before IUP_y, this code gets inserted */
187 static FT_Byte ins_extra_delta_exceptions[4] =
190 /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
191 PUSHB_2,
192 cvtl_do_iup_y,
194 WCVTP,
199 /* if we have a non-base glyph, this code gets inserted */
200 static FT_Byte ins_extra_ignore_std_width[4] =
203 /* tell bci_{smooth,strong}_stem_width to ignore std_width */
204 PUSHB_2,
205 cvtl_ignore_std_width,
206 100,
207 WCVTP,
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
219 FT_Byte*
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)
226 FT_UInt* arg = args;
227 FT_UInt i, j, nargs;
230 if (need_words)
232 for (i = 0; i < num_args; i += 255)
234 nargs = (num_args - i > 255) ? 255 : num_args - i;
236 if (optimize && nargs <= 8)
237 BCI(PUSHW_1 - 1 + nargs);
238 else
240 BCI(NPUSHW);
241 BCI(nargs);
243 for (j = 0; j < nargs; j++)
245 BCI(HIGH(*arg));
246 BCI(LOW(*arg));
247 arg++;
251 else
253 for (i = 0; i < num_args; i += 255)
255 nargs = (num_args - i > 255) ? 255 : num_args - i;
257 if (optimize && nargs <= 8)
258 BCI(PUSHB_1 - 1 + nargs);
259 else
261 BCI(NPUSHB);
262 BCI(nargs);
264 for (j = 0; j < nargs; j++)
266 BCI(*arg);
267 arg++;
272 return bufp;
277 * We optimize two common cases, replacing
279 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
281 * with
283 * NPUSHB (A+B[+C]) ... CALL
285 * if possible
288 static FT_Byte*
289 TA_optimize_push(FT_Byte* buf,
290 FT_Byte** pos)
292 FT_Byte sizes[3];
293 FT_Byte new_size1;
294 FT_Byte new_size2;
296 FT_UInt sum;
297 FT_UInt i;
298 FT_UInt pos_idx;
300 FT_Byte* p;
301 FT_Byte* bufp;
304 /* XXX improve handling of NPUSHW */
305 if (*(pos[0]) == NPUSHW
306 || *(pos[1]) == NPUSHW
307 || *(pos[2]) == NPUSHW)
308 return buf;
310 /* the point hints records block can be missing */
311 if (pos[0] == pos[1])
313 pos[1] = pos[2];
314 pos[2] = NULL;
317 /* only needed for the algorithm loops below */
318 pos[3] = NULL;
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;
326 sum = sizes[0] + sizes[1] + sizes[2];
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 */
333 if (sum > 0xFF)
335 /* reduce three NPUSHB to two */
336 new_size1 = 0xFF;
337 new_size2 = (FT_Byte)(sum - 0xFF);
339 else
341 /* reduce two or three NPUSHB to one */
342 new_size1 = (FT_Byte)sum;
343 new_size2 = 0;
346 /* pack data */
347 p = buf;
348 bufp = buf;
349 pos_idx = 0;
351 if (new_size1 <= 8)
352 BCI(PUSHB_1 - 1 + new_size1);
353 else
355 BCI(NPUSHB);
356 BCI(new_size1);
358 for (i = 0; i < new_size1; i++)
360 if (p == pos[pos_idx])
362 pos_idx++;
363 p += 2; /* skip old NPUSHB */
365 *(bufp++) = *(p++);
368 if (new_size2)
370 if (new_size2 <= 8)
371 BCI(PUSHB_1 - 1 + new_size2);
372 else
374 BCI(NPUSHB);
375 BCI(new_size2);
377 for (i = 0; i < new_size2; i++)
379 if (p == pos[pos_idx])
381 pos_idx++;
382 p += 2;
384 *(bufp++) = *(p++);
388 BCI(CALL);
390 return bufp;
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. */
403 static FT_UInt
404 TA_adjust_point_index(Recorder* recorder,
405 FT_UInt idx)
407 FONT* font = recorder->font;
408 GLYPH* glyph = recorder->glyph;
409 FT_UShort i;
412 if (!glyph->num_components || !font->hint_composites)
413 return idx; /* not a composite glyph */
415 for (i = 0; i < glyph->num_pointsums; i++)
416 if (idx < glyph->pointsums[i])
417 break;
419 return idx + i;
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. */
428 static FT_UShort
429 TA_get_segment_index(TA_Segment segment,
430 Recorder* recorder)
432 FONT* font = recorder->font;
433 TA_GlyphHints hints = &font->loader->hints;
434 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
437 return segment ? recorder->segment_map[segment - axis->segments]
438 : recorder->segment_map[axis->num_segments];
442 /* we store the segments in the storage area; */
443 /* each segment record consists of the first and last point */
445 static FT_Byte*
446 TA_sfnt_build_glyph_segments(SFNT* sfnt,
447 Recorder* recorder,
448 FT_Byte* bufp,
449 FT_Bool optimize)
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;
459 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
460 glyf_Data* data = (glyf_Data*)glyf_table->data;
462 FT_UInt style_id = data->style_ids
463 [font->loader->metrics->style_class->style];
465 FT_Outline outline = font->loader->gloader->base.outline;
467 FT_UInt* args;
468 FT_UInt* arg;
469 FT_UInt num_args;
470 FT_UShort num_segments;
472 FT_Bool need_words = 0;
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;
482 seg_limit = segments + axis->num_segments;
483 num_segments = TA_get_segment_index(NULL, recorder);
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++)
492 FT_UInt first = (FT_UInt)(seg->first - points);
493 FT_UInt last = (FT_UInt)(seg->last - points);
496 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
497 continue;
499 first = TA_adjust_point_index(recorder, first);
500 last = TA_adjust_point_index(recorder, last);
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;
512 /* also handle wrap-around segments */
513 num_segments += recorder->num_wrap_around_segments;
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;
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;
529 arg = args + num_args - 1;
531 if (num_segments > 0xFF)
532 need_words = 1;
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;
540 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
541 *(arg--) = num_segments;
543 base = 0;
544 n = 0;
545 for (seg = segments; seg < seg_limit; seg++)
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;
553 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
554 continue;
555 if (n >= num_packed_segments)
556 break;
558 first = TA_adjust_point_index(recorder, first);
559 last = TA_adjust_point_index(recorder, last);
561 low_nibble = first - base;
562 high_nibble = last - first;
564 *(arg--) = 16 * high_nibble + low_nibble;
566 base = last;
567 n++;
570 for (; seg < seg_limit; seg++)
572 FT_UInt first = (FT_UInt)(seg->first - points);
573 FT_UInt last = (FT_UInt)(seg->last - points);
576 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
577 continue;
579 *(arg--) = TA_adjust_point_index(recorder, first);
580 *(arg--) = TA_adjust_point_index(recorder, last);
582 /* we push the last and first contour point */
583 /* as a third and fourth argument in wrap-around segments */
584 if (first > last)
586 for (n = 0; n < outline.n_contours; n++)
588 FT_UInt end = (FT_UInt)outline.contours[n];
591 if (first <= end)
593 *(arg--) = TA_adjust_point_index(recorder, end);
594 if (end > 0xFF)
595 need_words = 1;
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;
607 if (last > 0xFF)
608 need_words = 1;
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++)
615 FT_UInt first = (FT_UInt)(seg->first - points);
616 FT_UInt last = (FT_UInt)(seg->last - points);
619 if (TA_get_segment_index(seg, recorder) == 0xFFFF)
620 continue;
622 if (first > last)
624 for (n = 0; n < outline.n_contours; n++)
626 if (first <= (FT_UInt)outline.contours[n])
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;
637 *(arg--) = TA_adjust_point_index(recorder, last);
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);
646 BCI(CALL);
648 num_storage = sal_segment_offset + num_segments * 2;
649 if (num_storage > sfnt->max_storage)
650 sfnt->max_storage = num_storage;
652 num_twilight_points = num_segments * 2;
653 if (num_twilight_points > sfnt->max_twilight_points)
654 sfnt->max_twilight_points = num_twilight_points;
656 /* both this function and `TA_emit_hints_record' */
657 /* push data onto the stack */
658 num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS
659 + recorder->num_stack_elements
660 + num_args);
661 if (num_stack_elements > sfnt->max_stack_elements)
662 sfnt->max_stack_elements = num_stack_elements;
664 free(args);
666 return bufp;
670 static void
671 build_delta_exception(const Ctrl* ctrl,
672 FT_UInt** delta_args,
673 unsigned int* num_delta_args)
675 int offset;
676 int ppem;
677 int x_shift;
678 int y_shift;
681 ppem = ctrl->ppem - CONTROL_DELTA_PPEM_MIN;
683 if (ppem < 16)
684 offset = 0;
685 else if (ppem < 32)
686 offset = 1;
687 else
688 offset = 2;
690 ppem -= offset << 4;
693 * Using
695 * delta_shift = 3 ,
697 * the possible shift values in the instructions are indexed as follows:
699 * 0 -1px
700 * 1 -7/8px
701 * ...
702 * 7 -1/8px
703 * 8 1/8px
704 * ...
705 * 14 7/8px
706 * 15 1px
708 * (note that there is no index for a zero shift).
711 if (ctrl->x_shift < 0)
712 x_shift = ctrl->x_shift + 8;
713 else
714 x_shift = ctrl->x_shift + 7;
716 if (ctrl->y_shift < 0)
717 y_shift = ctrl->y_shift + 8;
718 else
719 y_shift = ctrl->y_shift + 7;
721 /* add point index and exception specification to appropriate stack */
722 if (ctrl->x_shift)
724 *(delta_args[offset] + num_delta_args[offset]++) =
725 (FT_UInt)((ppem << 4) + x_shift);
726 *(delta_args[offset] + num_delta_args[offset]++) =
727 (FT_UInt)ctrl->point_idx;
730 if (ctrl->y_shift)
732 offset += 3;
733 *(delta_args[offset] + num_delta_args[offset]++) =
734 (FT_UInt)((ppem << 4) + y_shift);
735 *(delta_args[offset] + num_delta_args[offset]++) =
736 (FT_UInt)ctrl->point_idx;
741 static FT_Byte*
742 TA_sfnt_build_delta_exceptions(SFNT* sfnt,
743 FONT* font,
744 FT_Long idx,
745 FT_Byte* bufp)
747 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
748 glyf_Data* data = (glyf_Data*)glyf_table->data;
749 GLYPH* glyph = &data->glyphs[idx];
751 FT_Face face = font->loader->face;
753 unsigned int num_points;
754 int i;
756 FT_UShort num_before_IUP_stack_elements = 0;
757 FT_UShort num_after_IUP_stack_elements = 0;
759 /* DELTAP[1-3] stacks for both x and y directions */
760 FT_UInt* delta_before_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
761 FT_UInt* delta_after_IUP_args[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
762 unsigned int num_delta_before_IUP_args[6] = {0, 0, 0, 0, 0, 0};
763 unsigned int num_delta_after_IUP_args[6] = {0, 0, 0, 0, 0, 0};
764 FT_UInt* args = NULL;
766 FT_Bool need_before_IUP_words = 0;
767 FT_Bool need_after_IUP_words = 0;
768 FT_Bool need_before_IUP_word_counts = 0;
769 FT_Bool need_after_IUP_word_counts = 0;
770 FT_Bool allocated_before_IUP = 0;
771 FT_Bool allocated_after_IUP = 0;
774 num_points = (unsigned int)font->loader->gloader->base.outline.n_points;
776 /* loop over all fitting control instructions */
777 for (;;)
779 const Ctrl* ctrl = TA_control_get_ctrl(font);
782 if (!ctrl)
783 break;
785 /* check type */
786 if (!(ctrl->type == Control_Delta_before_IUP
787 || ctrl->type == Control_Delta_after_IUP))
788 break;
790 /* too large values of font and glyph indices in `ctrl' */
791 /* are handled by later calls of this function */
792 if (face->face_index < ctrl->font_idx
793 || idx < ctrl->glyph_idx)
794 break;
796 if (ctrl->type == Control_Delta_before_IUP
797 && !allocated_before_IUP)
799 for (i = 0; i < 6; i++)
801 /* see the comment on allocating `ins_buf' in function */
802 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
803 /* we have to increase by 2 to push the number of argument pairs */
804 /* and the function for a LOOPCALL instruction */
805 delta_before_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 2)
806 * sizeof (FT_UInt));
807 if (!delta_before_IUP_args[i])
809 bufp = NULL;
810 goto Done;
814 allocated_before_IUP = 1;
817 if (ctrl->type == Control_Delta_after_IUP
818 && !allocated_after_IUP)
820 for (i = 0; i < 6; i++)
822 /* we have to increase by 1 for the number of argument pairs */
823 /* as needed by the DELTA instructions */
824 delta_after_IUP_args[i] = (FT_UInt*)malloc((16 * 2 * num_points + 1)
825 * sizeof (FT_UInt));
826 if (!delta_after_IUP_args[i])
828 bufp = NULL;
829 goto Done;
833 allocated_after_IUP = 1;
836 /* since we walk sequentially over all glyphs (with points), */
837 /* and the control instruction entries have the same order, */
838 /* we don't need to test for equality of font and glyph indices: */
839 /* at this very point in the code we certainly have a hit */
840 if (ctrl->type == Control_Delta_before_IUP)
842 build_delta_exception(ctrl,
843 delta_before_IUP_args,
844 num_delta_before_IUP_args);
846 if (ctrl->point_idx > 255)
847 need_before_IUP_words = 1;
849 else
851 build_delta_exception(ctrl,
852 delta_after_IUP_args,
853 num_delta_after_IUP_args);
855 if (ctrl->point_idx > 255)
856 need_after_IUP_words = 1;
859 TA_control_get_next(font);
862 /* nothing to do if no control instructions */
863 if (!(allocated_before_IUP || allocated_after_IUP))
864 return bufp;
866 /* add number of argument pairs and function number to the stacks */
867 for (i = 0; i < 6; i++)
869 if (num_delta_before_IUP_args[i])
871 unsigned int n = num_delta_before_IUP_args[i] >> 1;
874 if (n > 255)
875 need_before_IUP_word_counts = 1;
877 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) = n;
878 num_delta_before_IUP_args[i]++;
880 *(delta_before_IUP_args[i] + num_delta_before_IUP_args[i]) =
881 bci_deltap1 + (i % 3);
882 num_delta_before_IUP_args[i]++;
886 /* add number of argument pairs to the stacks */
887 for (i = 0; i < 6; i++)
889 if (num_delta_after_IUP_args[i])
891 unsigned int n = num_delta_after_IUP_args[i] >> 1;
894 if (n > 255)
895 need_after_IUP_word_counts = 1;
897 *(delta_after_IUP_args[i] + num_delta_after_IUP_args[i]) = n;
898 num_delta_after_IUP_args[i]++;
902 /* merge `before IUP' delta stacks into a single one */
903 if (need_before_IUP_words
904 || (!need_before_IUP_words && !need_before_IUP_word_counts))
906 FT_UInt num_args = 0;
909 for (i = 0; i < 6; i++)
911 FT_UInt* args_new;
912 FT_UInt num_args_new;
915 if (!num_delta_before_IUP_args[i])
916 continue;
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)
922 bufp = NULL;
923 goto Done;
926 memcpy(args_new + num_args,
927 delta_before_IUP_args[i],
928 num_delta_before_IUP_args[i] * sizeof (FT_UInt));
930 args = args_new;
931 num_args = num_args_new;
934 num_before_IUP_stack_elements = (FT_UShort)num_args;
936 bufp = TA_build_push(bufp, args, num_args, need_before_IUP_words, 1);
938 else
940 num_before_IUP_stack_elements = 0;
942 /* stack elements are bytes, but counts need words */
943 for (i = 0; i < 6; i++)
945 FT_UInt num_delta_arg;
948 if (!num_delta_before_IUP_args[i])
949 continue;
951 num_delta_arg = num_delta_before_IUP_args[i] - 2;
953 bufp = TA_build_push(bufp,
954 delta_before_IUP_args[i],
955 num_delta_arg,
956 need_before_IUP_words,
959 num_before_IUP_stack_elements += num_delta_arg + 2;
961 num_delta_arg >>= 1;
962 BCI(PUSHW_1);
963 BCI(HIGH(num_delta_arg));
964 BCI(LOW(num_delta_arg));
966 /* the function number */
967 BCI(PUSHB_1);
968 BCI(delta_before_IUP_args[i][num_delta_before_IUP_args[i] - 1]);
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);
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);
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);
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);
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);
1003 /* merge `after IUP' delta stacks into a single one */
1004 if (need_after_IUP_words
1005 || (!need_after_IUP_words && !need_after_IUP_word_counts))
1007 FT_UInt num_args = 0;
1010 for (i = 0; i < 6; i++)
1012 FT_UInt* args_new;
1013 FT_UInt num_args_new;
1016 if (!num_delta_after_IUP_args[i])
1017 continue;
1019 num_args_new = num_args + num_delta_after_IUP_args[i];
1020 args_new = (FT_UInt*)realloc(args, num_args_new * sizeof (FT_UInt));
1021 if (!args_new)
1023 bufp = NULL;
1024 goto Done;
1027 memcpy(args_new + num_args,
1028 delta_after_IUP_args[i],
1029 num_delta_after_IUP_args[i] * sizeof (FT_UInt));
1031 args = args_new;
1032 num_args = num_args_new;
1035 num_after_IUP_stack_elements = (FT_UShort)num_args;
1037 bufp = TA_build_push(bufp, args, num_args, need_after_IUP_words, 1);
1039 else
1041 num_after_IUP_stack_elements = 0;
1043 /* stack elements are bytes, but counts need words */
1044 for (i = 0; i < 6; i++)
1046 FT_UInt num_delta_arg;
1049 if (!num_delta_after_IUP_args[i])
1050 continue;
1052 num_delta_arg = num_delta_after_IUP_args[i] - 1;
1054 bufp = TA_build_push(bufp,
1055 delta_after_IUP_args[i],
1056 num_delta_arg,
1057 need_after_IUP_words,
1060 num_after_IUP_stack_elements += num_delta_arg + 1;
1062 num_delta_arg >>= 1;
1063 BCI(PUSHW_1);
1064 BCI(HIGH(num_delta_arg));
1065 BCI(LOW(num_delta_arg));
1069 /* emit y DELTA opcodes */
1070 if (num_delta_after_IUP_args[5])
1071 BCI(DELTAP3);
1072 if (num_delta_after_IUP_args[4])
1073 BCI(DELTAP2);
1074 if (num_delta_after_IUP_args[3])
1075 BCI(DELTAP1);
1077 if (num_delta_after_IUP_args[2]
1078 || num_delta_after_IUP_args[1]
1079 || num_delta_after_IUP_args[0])
1080 BCI(SVTCA_x);
1082 /* emit x DELTA opcodes */
1083 if (num_delta_after_IUP_args[2])
1084 BCI(DELTAP3);
1085 if (num_delta_after_IUP_args[1])
1086 BCI(DELTAP2);
1087 if (num_delta_after_IUP_args[0])
1088 BCI(DELTAP1);
1090 /* we need to insert a few extra bytecode instructions */
1091 /* if we have y delta exceptions before IUP */
1092 if (num_delta_before_IUP_args[5]
1093 || num_delta_before_IUP_args[4]
1094 || num_delta_before_IUP_args[3])
1096 FT_Byte* ins_extra_buf_new;
1097 FT_Byte ins_extra_len_new;
1100 ins_extra_len_new = glyph->ins_extra_len
1101 + sizeof (ins_extra_delta_exceptions);
1102 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
1103 ins_extra_len_new);
1104 if (!ins_extra_buf_new)
1106 bufp = NULL;
1107 goto Done;
1110 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1111 /* by activating `ins_extra_delta_exceptions' */
1112 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
1113 ins_extra_delta_exceptions,
1114 sizeof (ins_extra_delta_exceptions));
1116 glyph->ins_extra_buf = ins_extra_buf_new;
1117 glyph->ins_extra_len = ins_extra_len_new;
1119 /* reset `cvtl_do_iup_y' for next glyph */
1120 BCI(PUSHB_2);
1121 BCI(cvtl_do_iup_y);
1122 BCI(100);
1123 BCI(WCVTP);
1126 Done:
1127 for (i = 0; i < 6; i++)
1129 free(delta_before_IUP_args[i]);
1130 free(delta_after_IUP_args[i]);
1132 free(args);
1134 if (num_before_IUP_stack_elements > sfnt->max_stack_elements)
1135 sfnt->max_stack_elements = num_before_IUP_stack_elements;
1136 if (num_after_IUP_stack_elements > sfnt->max_stack_elements)
1137 sfnt->max_stack_elements = num_after_IUP_stack_elements;
1139 return bufp;
1143 static FT_Byte*
1144 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
1145 Recorder* recorder,
1146 FT_Byte* bufp)
1148 FONT* font = recorder->font;
1149 FT_GlyphSlot glyph = sfnt->face->glyph;
1150 FT_Vector* points = glyph->outline.points;
1151 FT_UInt num_contours = (FT_UInt)glyph->outline.n_contours;
1153 FT_UInt* args;
1154 FT_UInt* arg;
1155 FT_UInt num_args;
1157 FT_Bool need_words = 0;
1158 FT_UInt p, q;
1159 FT_UInt start, end;
1160 FT_UShort num_storage;
1161 FT_UShort num_stack_elements;
1164 num_args = 2 * num_contours + 2;
1166 /* collect all arguments temporarily in an array (in reverse order) */
1167 /* so that we can easily split into chunks of 255 args */
1168 /* as needed by NPUSHB and NPUSHW, respectively */
1169 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
1170 if (!args)
1171 return NULL;
1173 arg = args + num_args - 1;
1175 if (num_args > 0xFF)
1176 need_words = 1;
1178 if (recorder->glyph->num_components && font->hint_composites)
1179 *(arg--) = bci_scale_composite_glyph;
1180 else
1181 *(arg--) = bci_scale_glyph;
1182 *(arg--) = num_contours;
1184 start = 0;
1185 end = 0;
1187 for (p = 0; p < num_contours; p++)
1189 FT_UInt max = start;
1190 FT_UInt min = start;
1193 end = (FT_UInt)glyph->outline.contours[p];
1195 for (q = start; q <= end; q++)
1197 if (points[q].y < points[min].y)
1198 min = q;
1199 if (points[q].y > points[max].y)
1200 max = q;
1203 if (min > max)
1205 *(arg--) = TA_adjust_point_index(recorder, max);
1206 *(arg--) = TA_adjust_point_index(recorder, min);
1208 else
1210 *(arg--) = TA_adjust_point_index(recorder, min);
1211 *(arg--) = TA_adjust_point_index(recorder, max);
1214 start = end + 1;
1217 if (end > 0xFF)
1218 need_words = 1;
1220 /* with most fonts it is very rare */
1221 /* that any of the pushed arguments is larger than 0xFF, */
1222 /* thus we refrain from further optimizing this case */
1223 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
1225 BCI(CALL);
1227 num_storage = sal_segment_offset;
1228 if (num_storage > sfnt->max_storage)
1229 sfnt->max_storage = num_storage;
1231 num_stack_elements = (FT_UShort)(ADDITIONAL_STACK_ELEMENTS + num_args);
1232 if (num_stack_elements > sfnt->max_stack_elements)
1233 sfnt->max_stack_elements = num_stack_elements;
1235 free(args);
1237 return bufp;
1241 static FT_Byte*
1242 TA_font_build_subglyph_shifter(FONT* font,
1243 FT_Byte* bufp)
1245 FT_Face face = font->loader->face;
1246 FT_GlyphSlot glyph = face->glyph;
1248 TA_GlyphLoader gloader = font->loader->gloader;
1250 TA_SubGlyph subglyphs = gloader->current.subglyphs;
1251 TA_SubGlyph subglyph_limit = subglyphs + gloader->current.num_subglyphs;
1252 TA_SubGlyph subglyph;
1254 FT_Int curr_contour = 0;
1257 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
1259 FT_Error error;
1261 FT_UShort flags = subglyph->flags;
1262 FT_Pos y_offset = subglyph->arg2;
1264 FT_Int num_contours;
1267 /* load subglyph to get the number of contours */
1268 error = FT_Load_Glyph(face, (FT_UInt)subglyph->index, FT_LOAD_NO_SCALE);
1269 if (error)
1270 return NULL;
1271 num_contours = glyph->outline.n_contours;
1273 /* nothing to do if there is a point-to-point alignment */
1274 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
1275 goto End;
1277 /* nothing to do if y offset is zero */
1278 if (!y_offset)
1279 goto End;
1281 /* nothing to do if there are no contours */
1282 if (!num_contours)
1283 goto End;
1285 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1286 /* ensures that composite subglyphs are represented as simple glyphs */
1288 if (num_contours > 0xFF
1289 || curr_contour > 0xFF)
1291 BCI(PUSHW_2);
1292 BCI(HIGH(curr_contour));
1293 BCI(LOW(curr_contour));
1294 BCI(HIGH(num_contours));
1295 BCI(LOW(num_contours));
1297 else
1299 BCI(PUSHB_2);
1300 BCI(curr_contour);
1301 BCI(num_contours);
1304 /* there are high chances that this value needs PUSHW, */
1305 /* thus we handle it separately */
1306 if (y_offset > 0xFF || y_offset < 0)
1308 BCI(PUSHW_1);
1309 BCI(HIGH(y_offset));
1310 BCI(LOW(y_offset));
1312 else
1314 BCI(PUSHB_1);
1315 BCI(y_offset);
1318 BCI(PUSHB_1);
1319 BCI(bci_shift_subglyph);
1320 BCI(CALL);
1322 End:
1323 curr_contour += num_contours;
1326 return bufp;
1331 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1332 * data in four arrays (which are simple but waste a lot of memory). The
1333 * function below converts them into bytecode.
1335 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1336 * together with the edge they correspond to.
1338 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1339 * loop over the edge or edge pairs, respectively, and each edge or edge
1340 * pair contains an inner loop to emit the correponding points.
1343 static void
1344 TA_build_point_hints(Recorder* recorder,
1345 TA_GlyphHints hints)
1347 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1348 TA_Edge edges = axis->edges;
1350 FT_Byte* p = recorder->hints_record.buf;
1352 FT_UShort i;
1353 FT_UShort j;
1355 FT_UShort prev_edge;
1356 FT_UShort prev_before_edge;
1357 FT_UShort prev_after_edge;
1359 Node1* before_node;
1360 Node1* after_node;
1361 Node2* on_node;
1362 Node3* between_node;
1365 /* we store everything as 16bit numbers; */
1366 /* the function numbers (`ta_ip_before', etc.) */
1367 /* reflect the order in the TA_Action enumeration */
1369 /* ip_before_points */
1371 i = 0;
1372 for (before_node = LLRB_MIN(ip_before_points,
1373 &recorder->ip_before_points_head);
1374 before_node;
1375 before_node = LLRB_NEXT(ip_before_points,
1376 &recorder->ip_before_points_head,
1377 before_node))
1379 /* count points */
1380 i++;
1383 if (i)
1385 TA_Edge edge;
1386 FT_UShort edge_first_idx;
1389 recorder->hints_record.num_actions++;
1391 edge = edges;
1392 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1394 *(p++) = 0;
1395 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
1396 *(p++) = HIGH(edge_first_idx);
1397 *(p++) = LOW(edge_first_idx);
1398 *(p++) = HIGH(i);
1399 *(p++) = LOW(i);
1401 for (before_node = LLRB_MIN(ip_before_points,
1402 &recorder->ip_before_points_head);
1403 before_node;
1404 before_node = LLRB_NEXT(ip_before_points,
1405 &recorder->ip_before_points_head,
1406 before_node))
1408 FT_UInt point;
1411 point = TA_adjust_point_index(recorder, before_node->point);
1412 *(p++) = HIGH(point);
1413 *(p++) = LOW(point);
1417 /* ip_after_points */
1419 i = 0;
1420 for (after_node = LLRB_MIN(ip_after_points,
1421 &recorder->ip_after_points_head);
1422 after_node;
1423 after_node = LLRB_NEXT(ip_after_points,
1424 &recorder->ip_after_points_head,
1425 after_node))
1427 /* count points */
1428 i++;
1431 if (i)
1433 TA_Edge edge;
1434 FT_UShort edge_first_idx;
1437 recorder->hints_record.num_actions++;
1439 edge = edges + axis->num_edges - 1;
1440 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1442 *(p++) = 0;
1443 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
1444 *(p++) = HIGH(edge_first_idx);
1445 *(p++) = LOW(edge_first_idx);
1446 *(p++) = HIGH(i);
1447 *(p++) = LOW(i);
1449 for (after_node = LLRB_MIN(ip_after_points,
1450 &recorder->ip_after_points_head);
1451 after_node;
1452 after_node = LLRB_NEXT(ip_after_points,
1453 &recorder->ip_after_points_head,
1454 after_node))
1456 FT_UInt point;
1459 point = TA_adjust_point_index(recorder, after_node->point);
1460 *(p++) = HIGH(point);
1461 *(p++) = LOW(point);
1465 /* ip_on_point_array */
1467 prev_edge = 0xFFFF;
1468 i = 0;
1469 for (on_node = LLRB_MIN(ip_on_points,
1470 &recorder->ip_on_points_head);
1471 on_node;
1472 on_node = LLRB_NEXT(ip_on_points,
1473 &recorder->ip_on_points_head,
1474 on_node))
1476 /* count edges */
1477 if (on_node->edge != prev_edge)
1479 i++;
1480 prev_edge = on_node->edge;
1484 if (i)
1486 recorder->hints_record.num_actions++;
1488 *(p++) = 0;
1489 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
1490 *(p++) = HIGH(i);
1491 *(p++) = LOW(i);
1493 for (on_node = LLRB_MIN(ip_on_points,
1494 &recorder->ip_on_points_head);
1495 on_node;
1496 on_node = LLRB_NEXT(ip_on_points,
1497 &recorder->ip_on_points_head,
1498 on_node))
1500 Node2* edge_node;
1501 TA_Edge edge;
1502 FT_UShort edge_first_idx;
1505 edge = edges + on_node->edge;
1506 edge_first_idx = TA_get_segment_index(edge->first, recorder);
1508 *(p++) = HIGH(edge_first_idx);
1509 *(p++) = LOW(edge_first_idx);
1511 /* save current position */
1512 edge_node = on_node;
1513 j = 0;
1514 for (;
1515 on_node;
1516 on_node = LLRB_NEXT(ip_on_points,
1517 &recorder->ip_on_points_head,
1518 on_node))
1520 /* count points on current edge */
1521 if (on_node->edge != edge_node->edge)
1522 break;
1523 j++;
1526 *(p++) = HIGH(j);
1527 *(p++) = LOW(j);
1529 /* restore current position */
1530 on_node = edge_node;
1531 for (;
1532 on_node;
1533 on_node = LLRB_NEXT(ip_on_points,
1534 &recorder->ip_on_points_head,
1535 on_node))
1537 FT_UInt point;
1540 if (on_node->edge != edge_node->edge)
1541 break;
1543 point = TA_adjust_point_index(recorder, on_node->point);
1544 *(p++) = HIGH(point);
1545 *(p++) = LOW(point);
1547 /* keep track of previous node */
1548 edge_node = on_node;
1551 /* reset loop iterator by one element, then continue */
1552 on_node = edge_node;
1556 /* ip_between_point_array */
1558 prev_before_edge = 0xFFFF;
1559 prev_after_edge = 0xFFFF;
1560 i = 0;
1561 for (between_node = LLRB_MIN(ip_between_points,
1562 &recorder->ip_between_points_head);
1563 between_node;
1564 between_node = LLRB_NEXT(ip_between_points,
1565 &recorder->ip_between_points_head,
1566 between_node))
1568 /* count `(before,after)' edge pairs */
1569 if (between_node->before_edge != prev_before_edge
1570 || between_node->after_edge != prev_after_edge)
1572 i++;
1573 prev_before_edge = between_node->before_edge;
1574 prev_after_edge = between_node->after_edge;
1578 if (i)
1580 recorder->hints_record.num_actions++;
1582 *(p++) = 0;
1583 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
1584 *(p++) = HIGH(i);
1585 *(p++) = LOW(i);
1587 for (between_node = LLRB_MIN(ip_between_points,
1588 &recorder->ip_between_points_head);
1589 between_node;
1590 between_node = LLRB_NEXT(ip_between_points,
1591 &recorder->ip_between_points_head,
1592 between_node))
1594 Node3* edge_pair_node;
1595 TA_Edge before;
1596 TA_Edge after;
1597 FT_UShort before_first_idx;
1598 FT_UShort after_first_idx;
1601 before = edges + between_node->before_edge;
1602 after = edges + between_node->after_edge;
1603 before_first_idx = TA_get_segment_index(before->first, recorder);
1604 after_first_idx = TA_get_segment_index(after->first, recorder);
1606 *(p++) = HIGH(after_first_idx);
1607 *(p++) = LOW(after_first_idx);
1608 *(p++) = HIGH(before_first_idx);
1609 *(p++) = LOW(before_first_idx);
1611 /* save current position */
1612 edge_pair_node = between_node;
1613 j = 0;
1614 for (;
1615 between_node;
1616 between_node = LLRB_NEXT(ip_between_points,
1617 &recorder->ip_between_points_head,
1618 between_node))
1620 /* count points associated with current edge pair */
1621 if (between_node->before_edge != edge_pair_node->before_edge
1622 || between_node->after_edge != edge_pair_node->after_edge)
1623 break;
1624 j++;
1627 *(p++) = HIGH(j);
1628 *(p++) = LOW(j);
1630 /* restore current position */
1631 between_node = edge_pair_node;
1632 for (;
1633 between_node;
1634 between_node = LLRB_NEXT(ip_between_points,
1635 &recorder->ip_between_points_head,
1636 between_node))
1638 FT_UInt point;
1641 if (between_node->before_edge != edge_pair_node->before_edge
1642 || between_node->after_edge != edge_pair_node->after_edge)
1643 break;
1645 point = TA_adjust_point_index(recorder, between_node->point);
1646 *(p++) = HIGH(point);
1647 *(p++) = LOW(point);
1649 /* keep track of previous node */
1650 edge_pair_node = between_node;
1653 /* reset loop iterator by one element, then continue */
1654 between_node = edge_pair_node;
1658 recorder->hints_record.buf = p;
1662 static FT_Bool
1663 TA_hints_record_is_different(Hints_Record* hints_records,
1664 FT_UInt num_hints_records,
1665 FT_Byte* start,
1666 FT_Byte* end)
1668 Hints_Record last_hints_record;
1671 if (!hints_records)
1672 return 1;
1674 /* we only need to compare with the last hints record */
1675 last_hints_record = hints_records[num_hints_records - 1];
1677 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1678 return 1;
1680 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1681 return 1;
1683 return 0;
1687 static FT_Error
1688 TA_add_hints_record(Hints_Record** hints_records,
1689 FT_UInt* num_hints_records,
1690 FT_Byte* start,
1691 Hints_Record hints_record)
1693 Hints_Record* hints_records_new;
1694 FT_UInt buf_len;
1695 /* at this point, `hints_record.buf' still points into `ins_buf' */
1696 FT_Byte* end = hints_record.buf;
1699 buf_len = (FT_UInt)(end - start);
1701 /* now fill the structure completely */
1702 hints_record.buf_len = buf_len;
1703 hints_record.buf = (FT_Byte*)malloc(buf_len);
1704 if (!hints_record.buf)
1705 return FT_Err_Out_Of_Memory;
1707 memcpy(hints_record.buf, start, buf_len);
1709 (*num_hints_records)++;
1710 hints_records_new =
1711 (Hints_Record*)realloc(*hints_records, *num_hints_records
1712 * sizeof (Hints_Record));
1713 if (!hints_records_new)
1715 free(hints_record.buf);
1716 (*num_hints_records)--;
1717 return FT_Err_Out_Of_Memory;
1719 else
1720 *hints_records = hints_records_new;
1722 (*hints_records)[*num_hints_records - 1] = hints_record;
1724 return FT_Err_Ok;
1728 static FT_Byte*
1729 TA_emit_hints_record(Recorder* recorder,
1730 Hints_Record* hints_record,
1731 FT_Byte* bufp,
1732 FT_Bool optimize)
1734 FT_Byte* p;
1735 FT_Byte* endp;
1736 FT_Bool need_words = 0;
1738 FT_UInt i, j;
1739 FT_UInt num_arguments;
1740 FT_UInt num_args;
1743 /* check whether any argument is larger than 0xFF */
1744 endp = hints_record->buf + hints_record->buf_len;
1745 for (p = hints_record->buf; p < endp; p += 2)
1746 if (*p)
1748 need_words = 1;
1749 break;
1752 /* with most fonts it is very rare */
1753 /* that any of the pushed arguments is larger than 0xFF, */
1754 /* thus we refrain from further optimizing this case */
1756 num_arguments = hints_record->buf_len / 2;
1757 p = endp - 2;
1759 if (need_words)
1761 for (i = 0; i < num_arguments; i += 255)
1763 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1765 if (optimize && num_args <= 8)
1766 BCI(PUSHW_1 - 1 + num_args);
1767 else
1769 BCI(NPUSHW);
1770 BCI(num_args);
1772 for (j = 0; j < num_args; j++)
1774 BCI(*p);
1775 BCI(*(p + 1));
1776 p -= 2;
1780 else
1782 /* we only need the lower bytes */
1783 p++;
1785 for (i = 0; i < num_arguments; i += 255)
1787 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1789 if (optimize && num_args <= 8)
1790 BCI(PUSHB_1 - 1 + num_args);
1791 else
1793 BCI(NPUSHB);
1794 BCI(num_args);
1796 for (j = 0; j < num_args; j++)
1798 BCI(*p);
1799 p -= 2;
1804 /* collect stack depth data */
1805 if (num_arguments > recorder->num_stack_elements)
1806 recorder->num_stack_elements = (FT_UShort)num_arguments;
1808 return bufp;
1812 static FT_Byte*
1813 TA_emit_hints_records(Recorder* recorder,
1814 Hints_Record* hints_records,
1815 FT_UInt num_hints_records,
1816 FT_Byte* bufp,
1817 FT_Bool optimize)
1819 FT_UInt i;
1820 Hints_Record* hints_record;
1823 hints_record = hints_records;
1825 /* emit hints records in `if' clauses, */
1826 /* with the ppem size as the condition */
1827 for (i = 0; i < num_hints_records - 1; i++)
1829 BCI(MPPEM);
1830 if (hints_record->size > 0xFF)
1832 BCI(PUSHW_1);
1833 BCI(HIGH((hints_record + 1)->size));
1834 BCI(LOW((hints_record + 1)->size));
1836 else
1838 BCI(PUSHB_1);
1839 BCI((hints_record + 1)->size);
1841 BCI(LT);
1842 BCI(IF);
1843 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1844 BCI(ELSE);
1846 hints_record++;
1849 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1851 for (i = 0; i < num_hints_records - 1; i++)
1852 BCI(EIF);
1854 return bufp;
1858 static void
1859 TA_free_hints_records(Hints_Record* hints_records,
1860 FT_UInt num_hints_records)
1862 FT_UInt i;
1865 for (i = 0; i < num_hints_records; i++)
1866 free(hints_records[i].buf);
1868 free(hints_records);
1872 static FT_Byte*
1873 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1874 Recorder* recorder,
1875 TA_Edge edge,
1876 FT_UShort* wraps)
1878 TA_Segment seg;
1879 FT_UShort seg_idx;
1880 FT_UShort num_segs = 0;
1881 FT_UShort* wrap;
1882 FT_UShort num_segments;
1885 seg_idx = TA_get_segment_index(edge->first, recorder);
1886 num_segments = TA_get_segment_index(NULL, recorder);
1888 /* we store everything as 16bit numbers */
1889 *(bufp++) = HIGH(seg_idx);
1890 *(bufp++) = LOW(seg_idx);
1892 /* wrap-around segments are stored as two segments */
1893 if (edge->first->first > edge->first->last)
1894 num_segs++;
1896 seg = edge->first->edge_next;
1897 while (seg != edge->first)
1899 num_segs++;
1901 if (seg->first > seg->last)
1902 num_segs++;
1904 seg = seg->edge_next;
1907 *(bufp++) = HIGH(num_segs);
1908 *(bufp++) = LOW(num_segs);
1910 if (edge->first->first > edge->first->last)
1912 /* emit second part of wrap-around segment; */
1913 /* the bytecode positions such segments after `normal' ones */
1914 wrap = wraps;
1915 for (;;)
1917 if (seg_idx == *wrap)
1918 break;
1919 wrap++;
1922 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1923 *(bufp++) = LOW(num_segments + (wrap - wraps));
1926 seg = edge->first->edge_next;
1927 while (seg != edge->first)
1929 seg_idx = TA_get_segment_index(seg, recorder);
1931 *(bufp++) = HIGH(seg_idx);
1932 *(bufp++) = LOW(seg_idx);
1934 if (seg->first > seg->last)
1936 wrap = wraps;
1937 for (;;)
1939 if (seg_idx == *wrap)
1940 break;
1941 wrap++;
1944 *(bufp++) = HIGH(num_segments + (wrap - wraps));
1945 *(bufp++) = LOW(num_segments + (wrap - wraps));
1948 seg = seg->edge_next;
1951 return bufp;
1955 static void
1956 TA_hints_recorder(TA_Action action,
1957 TA_GlyphHints hints,
1958 TA_Dimension dim,
1959 void* arg1,
1960 TA_Edge arg2,
1961 TA_Edge arg3,
1962 TA_Edge lower_bound,
1963 TA_Edge upper_bound)
1965 TA_AxisHints axis = &hints->axis[dim];
1966 TA_Edge edges = axis->edges;
1967 TA_Point points = hints->points;
1969 TA_Segment segments = axis->segments;
1970 TA_Segment seg_limit = segments + axis->num_segments;
1971 TA_Segment seg;
1973 Recorder* recorder = (Recorder*)hints->user;
1974 SFNT* sfnt = recorder->sfnt;
1975 FONT* font = recorder->font;
1976 FT_UShort* wraps = recorder->wrap_around_segments;
1977 FT_Byte* p = recorder->hints_record.buf;
1979 TA_StyleClass style_class = font->loader->metrics->style_class;
1980 TA_ScriptClass script_class = ta_script_classes[style_class->script];
1982 FT_UInt style = style_class->style;
1983 FT_Bool top_to_bottom_hinting = script_class->top_to_bottom_hinting;
1986 if (dim == TA_DIMENSION_HORZ)
1987 return;
1989 if (!recorder->segment_map_initialized)
1991 FT_UShort* segment_map = recorder->segment_map;
1992 FT_UShort idx;
1995 idx = 0;
1996 for (seg = segments; seg < seg_limit; seg++)
1998 if (seg->edge)
1999 *segment_map = idx++;
2000 else
2001 *segment_map = 0xFFFF;
2003 segment_map++;
2005 *segment_map = idx;
2007 recorder->segment_map_initialized = 1;
2010 if (!recorder->wrap_around_segments_initialized)
2012 FT_UShort* wrap_around_segment;
2015 wrap_around_segment = recorder->wrap_around_segments;
2016 for (seg = segments; seg < seg_limit; seg++)
2017 if (seg->first > seg->last)
2018 *(wrap_around_segment++) = TA_get_segment_index(seg, recorder);
2020 recorder->wrap_around_segments_initialized = 1;
2023 /* we collect point hints for later processing */
2024 switch (action)
2026 case ta_ip_before:
2028 Node1* before_node;
2029 TA_Point point = (TA_Point)arg1;
2032 before_node = (Node1*)malloc(sizeof (Node1));
2033 if (!before_node)
2034 return;
2035 before_node->point = (FT_UShort)(point - points);
2037 LLRB_INSERT(ip_before_points,
2038 &recorder->ip_before_points_head,
2039 before_node);
2041 return;
2043 case ta_ip_after:
2045 Node1* after_node;
2046 TA_Point point = (TA_Point)arg1;
2049 after_node = (Node1*)malloc(sizeof (Node1));
2050 if (!after_node)
2051 return;
2052 after_node->point = (FT_UShort)(point - points);
2054 LLRB_INSERT(ip_after_points,
2055 &recorder->ip_after_points_head,
2056 after_node);
2058 return;
2060 case ta_ip_on:
2062 Node2* on_node;
2063 TA_Point point = (TA_Point)arg1;
2064 TA_Edge edge = arg2;
2067 on_node = (Node2*)malloc(sizeof (Node2));
2068 if (!on_node)
2069 return;
2070 on_node->edge = (FT_UShort)(edge - edges);
2071 on_node->point = (FT_UShort)(point - points);
2073 LLRB_INSERT(ip_on_points,
2074 &recorder->ip_on_points_head,
2075 on_node);
2077 return;
2079 case ta_ip_between:
2081 Node3* between_node;
2082 TA_Point point = (TA_Point)arg1;
2083 TA_Edge before = arg2;
2084 TA_Edge after = arg3;
2087 between_node = (Node3*)malloc(sizeof (Node3));
2088 if (!between_node)
2089 return;
2090 between_node->before_edge = (FT_UShort)(before - edges);
2091 between_node->after_edge = (FT_UShort)(after - edges);
2092 between_node->point = (FT_UShort)(point - points);
2094 LLRB_INSERT(ip_between_points,
2095 &recorder->ip_between_points_head,
2096 between_node);
2098 return;
2100 case ta_bound:
2101 /* we ignore the BOUND action since we signal this information */
2102 /* with the proper function number */
2103 return;
2105 default:
2106 break;
2109 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2110 /* if the value is n, the function numbers are n, ..., n+11, */
2111 /* to be differentiated with flags */
2113 switch (action)
2115 case ta_link:
2117 TA_Edge base_edge = (TA_Edge)arg1;
2118 TA_Edge stem_edge = arg2;
2119 FT_UShort base_first_idx;
2120 FT_UShort stem_first_idx;
2123 base_first_idx = TA_get_segment_index(base_edge->first, recorder);
2124 stem_first_idx = TA_get_segment_index(stem_edge->first, recorder);
2126 *(p++) = 0;
2127 *(p++) = (FT_Byte)action + ACTION_OFFSET
2128 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
2129 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
2131 *(p++) = HIGH(base_first_idx);
2132 *(p++) = LOW(base_first_idx);
2133 *(p++) = HIGH(stem_first_idx);
2134 *(p++) = LOW(stem_first_idx);
2136 p = TA_hints_recorder_handle_segments(p, recorder, stem_edge, wraps);
2138 break;
2140 case ta_anchor:
2142 TA_Edge edge = (TA_Edge)arg1;
2143 TA_Edge edge2 = arg2;
2144 FT_UShort edge_first_idx;
2145 FT_UShort edge2_first_idx;
2148 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2149 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2151 *(p++) = 0;
2152 *(p++) = (FT_Byte)action + ACTION_OFFSET
2153 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2154 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
2156 *(p++) = HIGH(edge_first_idx);
2157 *(p++) = LOW(edge_first_idx);
2158 *(p++) = HIGH(edge2_first_idx);
2159 *(p++) = LOW(edge2_first_idx);
2161 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2163 break;
2165 case ta_adjust:
2167 TA_Edge edge = (TA_Edge)arg1;
2168 TA_Edge edge2 = arg2;
2169 TA_Edge edge_minus_one = lower_bound;
2170 FT_UShort edge_first_idx;
2171 FT_UShort edge2_first_idx;
2174 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2175 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2177 *(p++) = 0;
2178 *(p++) = (FT_Byte)action + ACTION_OFFSET
2179 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2180 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2181 + 4 * (edge_minus_one != NULL) /* `bound' */
2182 + 4 * (edge_minus_one != NULL
2183 && top_to_bottom_hinting); /* `down' */
2185 *(p++) = HIGH(edge_first_idx);
2186 *(p++) = LOW(edge_first_idx);
2187 *(p++) = HIGH(edge2_first_idx);
2188 *(p++) = LOW(edge2_first_idx);
2190 if (edge_minus_one)
2192 FT_UShort edge_minus_one_first_idx;
2195 edge_minus_one_first_idx = TA_get_segment_index(
2196 edge_minus_one->first, recorder);
2198 *(p++) = HIGH(edge_minus_one_first_idx);
2199 *(p++) = LOW(edge_minus_one_first_idx);
2202 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2204 break;
2206 case ta_blue_anchor:
2208 TA_Edge edge = (TA_Edge)arg1;
2209 TA_Edge blue = arg2;
2210 FT_UShort blue_first_idx;
2211 FT_UShort edge_first_idx;
2214 blue_first_idx = TA_get_segment_index(blue->first, recorder);
2215 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2217 *(p++) = 0;
2218 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2220 *(p++) = HIGH(blue_first_idx);
2221 *(p++) = LOW(blue_first_idx);
2223 if (edge->best_blue_is_shoot)
2225 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2226 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2228 else
2230 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2231 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2234 *(p++) = HIGH(edge_first_idx);
2235 *(p++) = LOW(edge_first_idx);
2237 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2239 break;
2241 case ta_stem:
2243 TA_Edge edge = (TA_Edge)arg1;
2244 TA_Edge edge2 = arg2;
2245 TA_Edge edge_minus_one = lower_bound;
2246 FT_UShort edge_first_idx;
2247 FT_UShort edge2_first_idx;
2250 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2251 edge2_first_idx = TA_get_segment_index(edge2->first, recorder);
2253 *(p++) = 0;
2254 *(p++) = (FT_Byte)action + ACTION_OFFSET
2255 + ((edge2->flags & TA_EDGE_SERIF) != 0)
2256 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
2257 + 4 * (edge_minus_one != NULL) /* `bound' */
2258 + 4 * (edge_minus_one != NULL
2259 && top_to_bottom_hinting); /* `down' */
2261 *(p++) = HIGH(edge_first_idx);
2262 *(p++) = LOW(edge_first_idx);
2263 *(p++) = HIGH(edge2_first_idx);
2264 *(p++) = LOW(edge2_first_idx);
2266 if (edge_minus_one)
2268 FT_UShort edge_minus_one_first_idx;
2271 edge_minus_one_first_idx = TA_get_segment_index(
2272 edge_minus_one->first, recorder);
2274 *(p++) = HIGH(edge_minus_one_first_idx);
2275 *(p++) = LOW(edge_minus_one_first_idx);
2278 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2279 p = TA_hints_recorder_handle_segments(p, recorder, edge2, wraps);
2281 break;
2283 case ta_blue:
2285 TA_Edge edge = (TA_Edge)arg1;
2286 FT_UShort edge_first_idx;
2289 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2291 *(p++) = 0;
2292 *(p++) = (FT_Byte)action + ACTION_OFFSET;
2294 if (edge->best_blue_is_shoot)
2296 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2297 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
2299 else
2301 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2302 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
2305 *(p++) = HIGH(edge_first_idx);
2306 *(p++) = LOW(edge_first_idx);
2308 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2310 break;
2312 case ta_serif:
2314 TA_Edge serif = (TA_Edge)arg1;
2315 TA_Edge base = serif->serif;
2316 FT_UShort serif_first_idx;
2317 FT_UShort base_first_idx;
2320 serif_first_idx = TA_get_segment_index(serif->first, recorder);
2321 base_first_idx = TA_get_segment_index(base->first, recorder);
2323 *(p++) = 0;
2324 *(p++) = (FT_Byte)action + ACTION_OFFSET
2325 + (lower_bound != NULL)
2326 + 2 * (upper_bound != NULL)
2327 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2328 && top_to_bottom_hinting); /* `down' */
2330 *(p++) = HIGH(serif_first_idx);
2331 *(p++) = LOW(serif_first_idx);
2332 *(p++) = HIGH(base_first_idx);
2333 *(p++) = LOW(base_first_idx);
2335 if (lower_bound)
2337 FT_UShort lower_bound_first_idx;
2340 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2341 recorder);
2343 *(p++) = HIGH(lower_bound_first_idx);
2344 *(p++) = LOW(lower_bound_first_idx);
2346 if (upper_bound)
2348 FT_UShort upper_bound_first_idx;
2351 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2352 recorder);
2354 *(p++) = HIGH(upper_bound_first_idx);
2355 *(p++) = LOW(upper_bound_first_idx);
2358 p = TA_hints_recorder_handle_segments(p, recorder, serif, wraps);
2360 break;
2362 case ta_serif_anchor:
2363 case ta_serif_link2:
2365 TA_Edge edge = (TA_Edge)arg1;
2366 FT_UShort edge_first_idx;
2369 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2371 *(p++) = 0;
2372 *(p++) = (FT_Byte)action + ACTION_OFFSET
2373 + (lower_bound != NULL)
2374 + 2 * (upper_bound != NULL)
2375 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2376 && top_to_bottom_hinting); /* `down' */
2378 *(p++) = HIGH(edge_first_idx);
2379 *(p++) = LOW(edge_first_idx);
2381 if (lower_bound)
2383 FT_UShort lower_bound_first_idx;
2386 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2387 recorder);
2389 *(p++) = HIGH(lower_bound_first_idx);
2390 *(p++) = LOW(lower_bound_first_idx);
2392 if (upper_bound)
2394 FT_UShort upper_bound_first_idx;
2397 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2398 recorder);
2400 *(p++) = HIGH(upper_bound_first_idx);
2401 *(p++) = LOW(upper_bound_first_idx);
2404 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2406 break;
2408 case ta_serif_link1:
2410 TA_Edge edge = (TA_Edge)arg1;
2411 TA_Edge before = arg2;
2412 TA_Edge after = arg3;
2413 FT_UShort before_first_idx;
2414 FT_UShort edge_first_idx;
2415 FT_UShort after_first_idx;
2418 before_first_idx = TA_get_segment_index(before->first, recorder);
2419 edge_first_idx = TA_get_segment_index(edge->first, recorder);
2420 after_first_idx = TA_get_segment_index(after->first, recorder);
2422 *(p++) = 0;
2423 *(p++) = (FT_Byte)action + ACTION_OFFSET
2424 + (lower_bound != NULL)
2425 + 2 * (upper_bound != NULL)
2426 + 3 * ((lower_bound != NULL || upper_bound != NULL)
2427 && top_to_bottom_hinting); /* `down' */
2429 *(p++) = HIGH(before_first_idx);
2430 *(p++) = LOW(before_first_idx);
2431 *(p++) = HIGH(edge_first_idx);
2432 *(p++) = LOW(edge_first_idx);
2433 *(p++) = HIGH(after_first_idx);
2434 *(p++) = LOW(after_first_idx);
2436 if (lower_bound)
2438 FT_UShort lower_bound_first_idx;
2441 lower_bound_first_idx = TA_get_segment_index(lower_bound->first,
2442 recorder);
2444 *(p++) = HIGH(lower_bound_first_idx);
2445 *(p++) = LOW(lower_bound_first_idx);
2447 if (upper_bound)
2449 FT_UShort upper_bound_first_idx;
2452 upper_bound_first_idx = TA_get_segment_index(upper_bound->first,
2453 recorder);
2455 *(p++) = HIGH(upper_bound_first_idx);
2456 *(p++) = LOW(upper_bound_first_idx);
2459 p = TA_hints_recorder_handle_segments(p, recorder, edge, wraps);
2461 break;
2463 default:
2464 /* there are more cases in the enumeration */
2465 /* which are handled with flags */
2466 break;
2469 recorder->hints_record.num_actions++;
2470 recorder->hints_record.buf = p;
2474 static FT_Error
2475 TA_init_recorder(Recorder* recorder,
2476 SFNT* sfnt,
2477 FONT* font,
2478 GLYPH* glyph,
2479 TA_GlyphHints hints)
2481 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
2483 TA_Segment segments = axis->segments;
2484 TA_Segment seg_limit = segments + axis->num_segments;
2485 TA_Segment seg;
2488 recorder->sfnt = sfnt;
2489 recorder->font = font;
2490 recorder->glyph = glyph;
2492 LLRB_INIT(&recorder->ip_before_points_head);
2493 LLRB_INIT(&recorder->ip_after_points_head);
2494 LLRB_INIT(&recorder->ip_on_points_head);
2495 LLRB_INIT(&recorder->ip_between_points_head);
2497 recorder->num_stack_elements = 0;
2499 /* no need to clean up allocated arrays in case of error; */
2500 /* this is handled later by `TA_free_recorder' */
2502 /* we use segment_map[axis->num_segments] */
2503 /* as the total number of mapped segments, so allocate one more element */
2504 recorder->segment_map =
2505 (FT_UShort*)malloc((size_t)(axis->num_segments + 1) * sizeof (FT_UShort));
2506 if (!recorder->segment_map)
2507 return FT_Err_Out_Of_Memory;
2509 /* `segment_map' gets initialized later on, */
2510 /* after the first call of `ta_loader_load_glyph' */
2511 recorder->segment_map_initialized = 0;
2513 recorder->num_wrap_around_segments = 0;
2514 for (seg = segments; seg < seg_limit; seg++)
2515 if (seg->first > seg->last)
2516 recorder->num_wrap_around_segments++;
2518 recorder->wrap_around_segments =
2519 (FT_UShort*)malloc(recorder->num_wrap_around_segments
2520 * sizeof (FT_UShort));
2521 if (!recorder->wrap_around_segments)
2522 return FT_Err_Out_Of_Memory;
2524 /* `wrap_around_segments' gets initialized later on; */
2525 /* it needs function `TA_get_segment_index' which uses data */
2526 /* that hasn't been initialized yet either */
2527 recorder->wrap_around_segments_initialized = 0;
2529 return FT_Err_Ok;
2533 static void
2534 TA_reset_recorder(Recorder* recorder,
2535 FT_Byte* bufp)
2537 recorder->hints_record.buf = bufp;
2538 recorder->hints_record.num_actions = 0;
2542 static void
2543 TA_rewind_recorder(Recorder* recorder,
2544 FT_Byte* bufp,
2545 FT_UInt size)
2547 Node1* before_node;
2548 Node1* after_node;
2549 Node2* on_node;
2550 Node3* between_node;
2552 Node1* next_before_node;
2553 Node1* next_after_node;
2554 Node2* next_on_node;
2555 Node3* next_between_node;
2558 TA_reset_recorder(recorder, bufp);
2560 recorder->hints_record.size = size;
2562 /* deallocate our red-black trees */
2564 for (before_node = LLRB_MIN(ip_before_points,
2565 &recorder->ip_before_points_head);
2566 before_node;
2567 before_node = next_before_node)
2569 next_before_node = LLRB_NEXT(ip_before_points,
2570 &recorder->ip_before_points_head,
2571 before_node);
2572 LLRB_REMOVE(ip_before_points,
2573 &recorder->ip_before_points_head,
2574 before_node);
2575 free(before_node);
2578 for (after_node = LLRB_MIN(ip_after_points,
2579 &recorder->ip_after_points_head);
2580 after_node;
2581 after_node = next_after_node)
2583 next_after_node = LLRB_NEXT(ip_after_points,
2584 &recorder->ip_after_points_head,
2585 after_node);
2586 LLRB_REMOVE(ip_after_points,
2587 &recorder->ip_after_points_head,
2588 after_node);
2589 free(after_node);
2592 for (on_node = LLRB_MIN(ip_on_points,
2593 &recorder->ip_on_points_head);
2594 on_node;
2595 on_node = next_on_node)
2597 next_on_node = LLRB_NEXT(ip_on_points,
2598 &recorder->ip_on_points_head,
2599 on_node);
2600 LLRB_REMOVE(ip_on_points,
2601 &recorder->ip_on_points_head,
2602 on_node);
2603 free(on_node);
2606 for (between_node = LLRB_MIN(ip_between_points,
2607 &recorder->ip_between_points_head);
2608 between_node;
2609 between_node = next_between_node)
2611 next_between_node = LLRB_NEXT(ip_between_points,
2612 &recorder->ip_between_points_head,
2613 between_node);
2614 LLRB_REMOVE(ip_between_points,
2615 &recorder->ip_between_points_head,
2616 between_node);
2617 free(between_node);
2622 static void
2623 TA_free_recorder(Recorder* recorder)
2625 free(recorder->segment_map);
2626 free(recorder->wrap_around_segments);
2628 TA_rewind_recorder(recorder, NULL, 0);
2632 FT_Error
2633 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
2634 FONT* font,
2635 FT_Long idx)
2637 FT_Face face = sfnt->face;
2638 FT_Error error;
2640 FT_Byte* ins_buf;
2641 FT_UInt ins_len;
2642 FT_Byte* bufp;
2643 FT_Byte* p;
2645 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
2646 glyf_Data* data = (glyf_Data*)glyf_table->data;
2647 /* `idx' is never negative */
2648 GLYPH* glyph = &data->glyphs[idx];
2650 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
2651 FT_UShort* gstyles = globals->glyph_styles;
2652 FT_Bool use_gstyle_data = 1;
2654 TA_GlyphHints hints;
2656 FT_UInt num_action_hints_records = 0;
2657 FT_UInt num_point_hints_records = 0;
2658 Hints_Record* action_hints_records = NULL;
2659 Hints_Record* point_hints_records = NULL;
2661 Recorder recorder;
2662 FT_UShort num_stack_elements;
2663 FT_Bool optimize = 0;
2665 FT_Int32 load_flags;
2666 FT_UInt size;
2668 /* we store only three positions, but it simplifies the algorithm in */
2669 /* `TA_optimize_push' if we have one additional element */
2670 FT_Byte* pos[4];
2672 #ifdef TA_DEBUG
2673 int _ta_debug_save;
2674 #endif
2677 /* XXX: right now, we abuse this flag to control */
2678 /* the global behaviour of the auto-hinter */
2679 load_flags = 1 << 29; /* vertical hinting only */
2680 if (!font->adjust_subglyphs)
2682 if (font->hint_composites)
2683 load_flags |= FT_LOAD_NO_SCALE;
2684 else
2685 load_flags |= FT_LOAD_NO_RECURSE;
2688 /* computing the segments is resolution independent, */
2689 /* thus the pixel size in this call is arbitrary -- */
2690 /* however, we avoid unnecessary debugging output */
2691 /* if we use the lowest value of the hinting range */
2692 error = FT_Set_Pixel_Sizes(face,
2693 font->hinting_range_min,
2694 font->hinting_range_min);
2695 if (error)
2696 return error;
2698 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2699 /* to modify `out' directions of points at the user's request */
2700 /* (which will eventually become single-point segments) */
2701 error = TA_control_segment_dir_collect(font, face->face_index, idx);
2702 if (error)
2703 return error;
2705 #ifdef TA_DEBUG
2706 /* temporarily disable some debugging output */
2707 /* to avoid getting the information twice */
2708 _ta_debug_save = _ta_debug;
2709 _ta_debug = 0;
2710 #endif
2712 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
2713 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2715 #ifdef TA_DEBUG
2716 _ta_debug = _ta_debug_save;
2717 #endif
2719 if (error)
2720 return error;
2722 /* do nothing if we have an empty glyph */
2723 if (!(font->loader->gloader->current.num_subglyphs
2724 || face->glyph->outline.n_contours))
2725 return FT_Err_Ok;
2727 hints = &font->loader->hints;
2730 * We allocate a buffer which is certainly large enough
2731 * to hold all of the created bytecode instructions;
2732 * later on it gets reallocated to its real size.
2734 * The value `1000' is a very rough guess, not tested well.
2736 * For delta exceptions, we have three DELTA commands,
2737 * covering 3*16 ppem values.
2738 * Since a point index can be larger than 255,
2739 * we assume two bytes everywhere for the necessary PUSH calls.
2740 * This value must be doubled for the other arguments of DELTA.
2741 * Additionally, we have both x and y deltas,
2742 * which need to be handled separately in the bytecode.
2743 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2744 * adding some bytes for the necessary overhead.
2746 ins_len = (FT_UInt)(hints->num_points
2747 * (1000
2748 + ((font->control_data_head != NULL) ? 400 : 0)));
2749 ins_buf = (FT_Byte*)malloc(ins_len);
2750 if (!ins_buf)
2751 return FT_Err_Out_Of_Memory;
2753 /* handle composite glyph */
2754 if (font->loader->gloader->current.num_subglyphs)
2756 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
2757 if (!bufp)
2759 error = FT_Err_Out_Of_Memory;
2760 goto Err;
2763 use_gstyle_data = 0;
2765 goto Done1;
2769 if (font->fallback_scaling)
2771 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
2773 /* the scaling value of `none_dflt' */
2774 /* (this is, hinting without script-specific blue zones) */
2775 /* is always 1, which corresponds to a no-op */
2776 bufp = ins_buf;
2778 else
2780 /* since `TA_init_recorder' hasn't been called yet, */
2781 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2782 recorder.sfnt = sfnt;
2783 recorder.font = font;
2784 recorder.glyph = glyph;
2786 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2787 if (!bufp)
2789 error = FT_Err_Out_Of_Memory;
2790 goto Err;
2794 use_gstyle_data = 0;
2796 goto Done1;
2799 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
2800 if (error)
2801 goto Err;
2803 /* loop over a large range of pixel sizes */
2804 /* to find hints records which get pushed onto the bytecode stack */
2806 #ifdef DEBUGGING
2807 if (font->debug)
2809 int num_chars, i;
2810 char buf[256];
2813 (void)FT_Get_Glyph_Name(face, (FT_UInt)idx, buf, 256);
2815 num_chars = fprintf(stderr, "glyph %ld", idx);
2816 if (*buf)
2817 num_chars += fprintf(stderr, " (%s)", buf);
2818 fprintf(stderr, "\n");
2819 for (i = 0; i < num_chars; i++)
2820 putc('=', stderr);
2821 fprintf(stderr, "\n\n");
2824 #endif
2826 /* we temporarily use `ins_buf' to record the current glyph hints */
2827 ta_loader_register_hints_recorder(font->loader,
2828 TA_hints_recorder,
2829 (void*)&recorder);
2832 * It is important that we start the loop with the smallest PPEM value
2833 * used for hinting, since the number of segments that form an edge can
2834 * become smaller for larger PPEM values. For efficiency, we skip
2835 * non-edge one-point segments, and `TA_get_segment_index' would return
2836 * wrong indices otherwise.
2838 for (size = font->hinting_range_min;
2839 size <= font->hinting_range_max;
2840 size++)
2842 #ifdef DEBUGGING
2843 int have_dumps = 0;
2844 #endif
2847 TA_rewind_recorder(&recorder, ins_buf, size);
2849 error = FT_Set_Pixel_Sizes(face, size, size);
2850 if (error)
2851 goto Err;
2853 #ifdef DEBUGGING
2854 if (font->debug)
2856 int num_chars, i;
2859 num_chars = fprintf(stderr, "size %d\n", size);
2860 for (i = 0; i < num_chars - 1; i++)
2861 putc('-', stderr);
2862 fprintf(stderr, "\n\n");
2864 #endif
2866 /* calling `ta_loader_load_glyph' uses the */
2867 /* `TA_hints_recorder' function as a callback, */
2868 /* modifying `hints_record' */
2869 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
2870 if (error)
2871 goto Err;
2873 if (TA_hints_record_is_different(action_hints_records,
2874 num_action_hints_records,
2875 ins_buf, recorder.hints_record.buf))
2877 #ifdef DEBUGGING
2878 if (font->debug)
2880 have_dumps = 1;
2882 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2883 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2884 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2886 fprintf(stderr, "action hints record:\n");
2887 if (ins_buf == recorder.hints_record.buf)
2888 fprintf(stderr, " (none)");
2889 else
2891 fprintf(stderr, " ");
2892 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2893 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2895 fprintf(stderr, "\n");
2897 #endif
2899 error = TA_add_hints_record(&action_hints_records,
2900 &num_action_hints_records,
2901 ins_buf, recorder.hints_record);
2902 if (error)
2903 goto Err;
2906 /* now handle point records */
2908 TA_reset_recorder(&recorder, ins_buf);
2910 /* use the point hints data collected in `TA_hints_recorder' */
2911 TA_build_point_hints(&recorder, hints);
2913 if (TA_hints_record_is_different(point_hints_records,
2914 num_point_hints_records,
2915 ins_buf, recorder.hints_record.buf))
2917 #ifdef DEBUGGING
2918 if (font->debug)
2920 if (!have_dumps)
2922 int num_chars, i;
2925 num_chars = fprintf(stderr, "size %d\n", size);
2926 for (i = 0; i < num_chars - 1; i++)
2927 putc('-', stderr);
2928 fprintf(stderr, "\n\n");
2930 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2931 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2932 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2935 fprintf(stderr, "point hints record:\n");
2936 if (ins_buf == recorder.hints_record.buf)
2937 fprintf(stderr, " (none)");
2938 else
2940 fprintf(stderr, " ");
2941 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2942 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2944 fprintf(stderr, "\n\n");
2946 #endif
2948 error = TA_add_hints_record(&point_hints_records,
2949 &num_point_hints_records,
2950 ins_buf, recorder.hints_record);
2951 if (error)
2952 goto Err;
2956 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2958 /* since we only have a single empty record we just scale the glyph */
2959 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2960 if (!bufp)
2962 error = FT_Err_Out_Of_Memory;
2963 goto Err;
2966 use_gstyle_data = 0;
2968 goto Done;
2971 /* if there is only a single record, */
2972 /* we do a global optimization later on */
2973 if (num_action_hints_records > 1)
2974 optimize = 1;
2976 /* store the hints records and handle stack depth */
2977 pos[0] = ins_buf;
2978 bufp = TA_emit_hints_records(&recorder,
2979 point_hints_records,
2980 num_point_hints_records,
2981 ins_buf,
2982 optimize);
2984 num_stack_elements = recorder.num_stack_elements;
2985 recorder.num_stack_elements = 0;
2987 pos[1] = bufp;
2988 bufp = TA_emit_hints_records(&recorder,
2989 action_hints_records,
2990 num_action_hints_records,
2991 bufp,
2992 optimize);
2994 recorder.num_stack_elements += num_stack_elements;
2996 pos[2] = bufp;
2997 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2998 if (!bufp)
3000 error = FT_Err_Out_Of_Memory;
3001 goto Err;
3004 if (num_action_hints_records == 1)
3005 bufp = TA_optimize_push(ins_buf, pos);
3007 Done:
3008 TA_free_hints_records(action_hints_records, num_action_hints_records);
3009 TA_free_hints_records(point_hints_records, num_point_hints_records);
3010 TA_free_recorder(&recorder);
3012 Done1:
3013 /* handle delta exceptions */
3014 if (font->control_data_head)
3016 bufp = TA_sfnt_build_delta_exceptions(sfnt, font, idx, bufp);
3017 if (!bufp)
3019 error = FT_Err_Out_Of_Memory;
3020 goto Err;
3024 /* we need to insert a few extra bytecode instructions */
3025 /* for non-base glyphs */
3026 if (use_gstyle_data && (gstyles[idx] & TA_NONBASE))
3028 FT_Byte* ins_extra_buf_new;
3029 FT_Byte ins_extra_len_new;
3032 ins_extra_len_new = glyph->ins_extra_len
3033 + sizeof (ins_extra_ignore_std_width);
3034 ins_extra_buf_new = (FT_Byte*)realloc(glyph->ins_extra_buf,
3035 ins_extra_len_new);
3036 if (!ins_extra_buf_new)
3038 bufp = NULL;
3039 goto Done;
3042 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3043 /* by activating `ins_extra_ignore_std_width' */
3044 memcpy(ins_extra_buf_new + glyph->ins_extra_len,
3045 ins_extra_ignore_std_width,
3046 sizeof (ins_extra_ignore_std_width));
3048 glyph->ins_extra_buf = ins_extra_buf_new;
3049 glyph->ins_extra_len = ins_extra_len_new;
3051 /* reset `cvtl_ignore_std_width' for next glyph */
3052 BCI(PUSHB_2);
3053 BCI(cvtl_ignore_std_width);
3054 BCI(0);
3055 BCI(WCVTP);
3058 ins_len = (FT_UInt)(bufp - ins_buf);
3060 if (ins_len > sfnt->max_instructions)
3061 sfnt->max_instructions = (FT_UShort)ins_len;
3063 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
3064 glyph->ins_len = ins_len;
3066 return FT_Err_Ok;
3068 Err:
3069 TA_free_hints_records(action_hints_records, num_action_hints_records);
3070 TA_free_hints_records(point_hints_records, num_point_hints_records);
3071 TA_free_recorder(&recorder);
3072 free(ins_buf);
3074 return error;
3078 /* end of tabytecode.c */