[gui] Add file type classes to drag & drop support.
[ttfautohint.git] / lib / tabytecode.c
blob46c8b2ee8faa487ac6e850e856c41bf0d4676148
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2014 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include <string.h>
17 #include <stdbool.h> /* for llrb.h */
19 #include "llrb.h" /* a red-black tree implementation */
21 #include "ta.h"
22 #include "tahints.h"
25 #define DEBUGGING
28 #ifdef TA_DEBUG
29 int _ta_debug = 0;
30 int _ta_debug_global = 0;
31 int _ta_debug_disable_horz_hints;
32 int _ta_debug_disable_vert_hints;
33 int _ta_debug_disable_blue_hints;
34 void* _ta_debug_hints;
35 #endif
38 /* node structures for point hints */
40 typedef struct Node1 Node1;
41 struct Node1
43 LLRB_ENTRY(Node1) entry1;
44 FT_UShort point;
47 typedef struct Node2 Node2;
48 struct Node2
50 LLRB_ENTRY(Node2) entry2;
51 FT_UShort edge;
52 FT_UShort point;
55 typedef struct Node3 Node3;
56 struct Node3
58 LLRB_ENTRY(Node3) entry3;
59 FT_UShort before_edge;
60 FT_UShort after_edge;
61 FT_UShort point;
65 /* comparison functions for our red-black trees */
67 static int
68 node1cmp(Node1* e1,
69 Node1* e2)
71 /* sort by points */
72 return e1->point - e2->point;
75 static int
76 node2cmp(Node2* e1,
77 Node2* e2)
79 FT_Int delta;
82 /* sort by edges ... */
83 delta = (FT_Int)e1->edge - (FT_Int)e2->edge;
84 if (delta)
85 return delta;
87 /* ... then by points */
88 return (FT_Int)e1->point - (FT_Int)e2->point;
91 static int
92 node3cmp(Node3* e1,
93 Node3* e2)
95 FT_Int delta;
98 /* sort by `before' edges ... */
99 delta = (FT_Int)e1->before_edge - (FT_Int)e2->before_edge;
100 if (delta)
101 return delta;
103 /* ... then by `after' edges ... */
104 delta = (FT_Int)e1->after_edge - (FT_Int)e2->after_edge;
105 if (delta)
106 return delta;
108 /* ... then by points */
109 return (FT_Int)e1->point - (FT_Int)e2->point;
113 /* the red-black tree function bodies */
114 typedef struct ip_before_points ip_before_points;
115 typedef struct ip_after_points ip_after_points;
116 typedef struct ip_on_points ip_on_points;
117 typedef struct ip_between_points ip_between_points;
119 LLRB_HEAD(ip_before_points, Node1);
120 LLRB_HEAD(ip_after_points, Node1);
121 LLRB_HEAD(ip_on_points, Node2);
122 LLRB_HEAD(ip_between_points, Node3);
124 /* no trailing semicolon in the next four lines */
125 LLRB_GENERATE_STATIC(ip_before_points, Node1, entry1, node1cmp)
126 LLRB_GENERATE_STATIC(ip_after_points, Node1, entry1, node1cmp)
127 LLRB_GENERATE_STATIC(ip_on_points, Node2, entry2, node2cmp)
128 LLRB_GENERATE_STATIC(ip_between_points, Node3, entry3, node3cmp)
131 typedef struct Hints_Record_
133 FT_UInt size;
134 FT_UInt num_actions;
135 FT_Byte* buf;
136 FT_UInt buf_len;
137 } Hints_Record;
139 typedef struct Recorder_
141 SFNT* sfnt;
142 FONT* font;
143 GLYPH* glyph; /* the current glyph */
144 Hints_Record hints_record;
146 /* some segments can `wrap around' */
147 /* a contour's start point like 24-25-26-0-1-2 */
148 /* (there can be at most one such segment per contour); */
149 /* later on we append additional records */
150 /* to split them into 24-26 and 0-2 */
151 FT_UShort* wrap_around_segments;
152 FT_UShort num_wrap_around_segments;
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 FT_UShort num_strong_points;
163 FT_UShort num_segments;
164 } Recorder;
167 /* this is the bytecode of the `.ttfautohint' glyph */
169 FT_Byte ttfautohint_glyph_bytecode[7] =
172 /* increment `cvtl_is_subglyph' counter */
173 PUSHB_3,
174 cvtl_is_subglyph,
175 100,
176 cvtl_is_subglyph,
177 RCVT,
178 ADD,
179 WCVTP,
185 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
186 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
187 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
188 * PUSHW_X gets used
191 FT_Byte*
192 TA_build_push(FT_Byte* bufp,
193 FT_UInt* args,
194 FT_UInt num_args,
195 FT_Bool need_words,
196 FT_Bool optimize)
198 FT_UInt* arg = args;
199 FT_UInt i, j, nargs;
202 if (need_words)
204 for (i = 0; i < num_args; i += 255)
206 nargs = (num_args - i > 255) ? 255 : num_args - i;
208 if (optimize && nargs <= 8)
209 BCI(PUSHW_1 - 1 + nargs);
210 else
212 BCI(NPUSHW);
213 BCI(nargs);
215 for (j = 0; j < nargs; j++)
217 BCI(HIGH(*arg));
218 BCI(LOW(*arg));
219 arg++;
223 else
225 for (i = 0; i < num_args; i += 255)
227 nargs = (num_args - i > 255) ? 255 : num_args - i;
229 if (optimize && nargs <= 8)
230 BCI(PUSHB_1 - 1 + nargs);
231 else
233 BCI(NPUSHB);
234 BCI(nargs);
236 for (j = 0; j < nargs; j++)
238 BCI(*arg);
239 arg++;
244 return bufp;
248 /* We add a subglyph for each composite glyph. */
249 /* Since subglyphs must contain at least one point, */
250 /* we have to adjust all point indices accordingly. */
251 /* Using the `pointsums' array of the `GLYPH' structure */
252 /* it is straightforward to do that: */
253 /* Assuming that point with index x is in the interval */
254 /* pointsums[n] <= x < pointsums[n + 1], */
255 /* the new point index is x + n. */
257 static FT_UInt
258 TA_adjust_point_index(Recorder* recorder,
259 FT_UInt idx)
261 FONT* font = recorder->font;
262 GLYPH* glyph = recorder->glyph;
263 FT_UShort i;
266 if (!glyph->num_components || !font->hint_composites)
267 return idx; /* not a composite glyph */
269 for (i = 0; i < glyph->num_pointsums; i++)
270 if (idx < glyph->pointsums[i])
271 break;
273 return idx + i;
277 /* we store the segments in the storage area; */
278 /* each segment record consists of the first and last point */
280 static FT_Byte*
281 TA_sfnt_build_glyph_segments(SFNT* sfnt,
282 Recorder* recorder,
283 FT_Byte* bufp,
284 FT_Bool optimize)
286 FONT* font = recorder->font;
287 TA_GlyphHints hints = &font->loader->hints;
288 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
289 TA_Point points = hints->points;
290 TA_Segment segments = axis->segments;
291 TA_Segment seg;
292 TA_Segment seg_limit;
294 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
295 glyf_Data* data = (glyf_Data*)glyf_table->data;
297 FT_UInt style_id = data->style_ids
298 [font->loader->metrics->style_class->style];
300 FT_Outline outline = font->loader->gloader->base.outline;
302 FT_UInt* args;
303 FT_UInt* arg;
304 FT_UInt num_args;
305 FT_UShort num_segments;
307 FT_Bool need_words = 0;
309 FT_Int n;
310 FT_UInt base;
311 FT_UShort num_packed_segments;
312 FT_UShort num_storage;
313 FT_UShort num_stack_elements;
314 FT_UShort num_twilight_points;
317 seg_limit = segments + axis->num_segments;
318 num_segments = axis->num_segments;
320 /* to pack the data in the bytecode more tightly, */
321 /* we store up to the first nine segments in nibbles if possible, */
322 /* using delta values */
323 base = 0;
324 num_packed_segments = 0;
325 for (seg = segments; seg < seg_limit; seg++)
327 FT_UInt first = seg->first - points;
328 FT_UInt last = seg->last - points;
331 first = TA_adjust_point_index(recorder, first);
332 last = TA_adjust_point_index(recorder, last);
334 if (first - base >= 16)
335 break;
336 if (first > last || last - first >= 16)
337 break;
338 if (num_packed_segments == 9)
339 break;
340 num_packed_segments++;
341 base = last;
344 /* also handle wrap-around segments */
345 num_segments += recorder->num_wrap_around_segments;
347 /* wrap-around segments are pushed with four arguments; */
348 /* a segment stored in nibbles needs only one byte instead of two */
349 num_args = num_packed_segments
350 + 2 * (num_segments - num_packed_segments)
351 + 2 * recorder->num_wrap_around_segments
352 + 3;
354 /* collect all arguments temporarily in an array (in reverse order) */
355 /* so that we can easily split into chunks of 255 args */
356 /* as needed by NPUSHB and NPUSHW, respectively */
357 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
358 if (!args)
359 return NULL;
361 arg = args + num_args - 1;
363 if (num_segments > 0xFF)
364 need_words = 1;
366 /* the number of packed segments is indicated by the function number */
367 if (recorder->glyph->num_components && font->hint_composites)
368 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
369 else
370 *(arg--) = bci_create_segments_0 + num_packed_segments;
372 *(arg--) = CVT_SCALING_VALUE_OFFSET(style_id);
373 *(arg--) = num_segments;
375 base = 0;
376 for (seg = segments; seg < segments + num_packed_segments; seg++)
378 FT_UInt first = seg->first - points;
379 FT_UInt last = seg->last - points;
380 FT_UInt low_nibble;
381 FT_UInt high_nibble;
384 first = TA_adjust_point_index(recorder, first);
385 last = TA_adjust_point_index(recorder, last);
387 low_nibble = first - base;
388 high_nibble = last - first;
390 *(arg--) = 16 * high_nibble + low_nibble;
392 base = last;
395 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
397 FT_UInt first = seg->first - points;
398 FT_UInt last = seg->last - points;
401 *(arg--) = TA_adjust_point_index(recorder, first);
402 *(arg--) = TA_adjust_point_index(recorder, last);
404 /* we push the last and first contour point */
405 /* as a third and fourth argument in wrap-around segments */
406 if (first > last)
408 for (n = 0; n < outline.n_contours; n++)
410 FT_UInt end = (FT_UInt)outline.contours[n];
413 if (first <= end)
415 *(arg--) = TA_adjust_point_index(recorder, end);
416 if (end > 0xFF)
417 need_words = 1;
419 if (n == 0)
420 *(arg--) = TA_adjust_point_index(recorder, 0);
421 else
422 *(arg--) = TA_adjust_point_index(recorder,
423 (FT_UInt)outline.contours[n - 1] + 1);
424 break;
429 if (last > 0xFF)
430 need_words = 1;
433 /* emit the second part of wrap-around segments as separate segments */
434 /* so that edges can easily link to them */
435 for (seg = segments; seg < seg_limit; seg++)
437 FT_UInt first = seg->first - points;
438 FT_UInt last = seg->last - points;
441 if (first > last)
443 for (n = 0; n < outline.n_contours; n++)
445 if (first <= (FT_UInt)outline.contours[n])
447 if (n == 0)
448 *(arg--) = TA_adjust_point_index(recorder, 0);
449 else
450 *(arg--) = TA_adjust_point_index(recorder,
451 (FT_UInt)outline.contours[n - 1] + 1);
452 break;
456 *(arg--) = TA_adjust_point_index(recorder, last);
460 /* with most fonts it is very rare */
461 /* that any of the pushed arguments is larger than 0xFF, */
462 /* thus we refrain from further optimizing this case */
463 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
465 BCI(CALL);
467 num_storage = sal_segment_offset + num_segments * 2;
468 if (num_storage > sfnt->max_storage)
469 sfnt->max_storage = num_storage;
471 num_twilight_points = num_segments * 2;
472 if (num_twilight_points > sfnt->max_twilight_points)
473 sfnt->max_twilight_points = num_twilight_points;
475 /* both this function and `TA_emit_hints_record' */
476 /* push data onto the stack */
477 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
478 + recorder->num_stack_elements + num_args;
479 if (num_stack_elements > sfnt->max_stack_elements)
480 sfnt->max_stack_elements = num_stack_elements;
482 free(args);
484 return bufp;
488 static FT_Byte*
489 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
490 Recorder* recorder,
491 FT_Byte* bufp)
493 FONT* font = recorder->font;
494 FT_GlyphSlot glyph = sfnt->face->glyph;
495 FT_Vector* points = glyph->outline.points;
496 FT_Int num_contours = glyph->outline.n_contours;
498 FT_UInt* args;
499 FT_UInt* arg;
500 FT_UInt num_args;
502 FT_Bool need_words = 0;
503 FT_Int p, q;
504 FT_Int start, end;
505 FT_UShort num_stack_elements;
508 num_args = 2 * num_contours + 2;
510 /* collect all arguments temporarily in an array (in reverse order) */
511 /* so that we can easily split into chunks of 255 args */
512 /* as needed by NPUSHB and NPUSHW, respectively */
513 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
514 if (!args)
515 return NULL;
517 arg = args + num_args - 1;
519 if (num_args > 0xFF)
520 need_words = 1;
522 if (recorder->glyph->num_components && font->hint_composites)
523 *(arg--) = bci_scale_composite_glyph;
524 else
525 *(arg--) = bci_scale_glyph;
526 *(arg--) = num_contours;
528 start = 0;
529 end = 0;
531 for (p = 0; p < num_contours; p++)
533 FT_Int max = start;
534 FT_Int min = start;
537 end = glyph->outline.contours[p];
539 for (q = start; q <= end; q++)
541 if (points[q].y < points[min].y)
542 min = q;
543 if (points[q].y > points[max].y)
544 max = q;
547 if (min > max)
549 *(arg--) = TA_adjust_point_index(recorder, max);
550 *(arg--) = TA_adjust_point_index(recorder, min);
552 else
554 *(arg--) = TA_adjust_point_index(recorder, min);
555 *(arg--) = TA_adjust_point_index(recorder, max);
558 start = end + 1;
561 if (end > 0xFF)
562 need_words = 1;
564 /* with most fonts it is very rare */
565 /* that any of the pushed arguments is larger than 0xFF, */
566 /* thus we refrain from further optimizing this case */
567 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
569 BCI(CALL);
571 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
572 if (num_stack_elements > sfnt->max_stack_elements)
573 sfnt->max_stack_elements = num_stack_elements;
575 free(args);
577 return bufp;
581 static FT_Byte*
582 TA_font_build_subglyph_shifter(FONT* font,
583 FT_Byte* bufp)
585 FT_Face face = font->loader->face;
586 FT_GlyphSlot glyph = face->glyph;
588 TA_GlyphLoader gloader = font->loader->gloader;
590 TA_SubGlyph subglyphs = gloader->base.subglyphs;
591 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
592 TA_SubGlyph subglyph;
594 FT_Int curr_contour = 0;
597 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
599 FT_Error error;
601 FT_UShort flags = subglyph->flags;
602 FT_Pos y_offset = subglyph->arg2;
604 FT_Int num_contours;
607 /* load subglyph to get the number of contours */
608 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
609 if (error)
610 return NULL;
611 num_contours = glyph->outline.n_contours;
613 /* nothing to do if there is a point-to-point alignment */
614 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
615 goto End;
617 /* nothing to do if y offset is zero */
618 if (!y_offset)
619 goto End;
621 /* nothing to do if there are no contours */
622 if (!num_contours)
623 goto End;
625 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
626 /* ensures that composite subglyphs are represented as simple glyphs */
628 if (num_contours > 0xFF
629 || curr_contour > 0xFF)
631 BCI(PUSHW_2);
632 BCI(HIGH(curr_contour));
633 BCI(LOW(curr_contour));
634 BCI(HIGH(num_contours));
635 BCI(LOW(num_contours));
637 else
639 BCI(PUSHB_2);
640 BCI(curr_contour);
641 BCI(num_contours);
644 /* there are high chances that this value needs PUSHW, */
645 /* thus we handle it separately */
646 if (y_offset > 0xFF || y_offset < 0)
648 BCI(PUSHW_1);
649 BCI(HIGH(y_offset));
650 BCI(LOW(y_offset));
652 else
654 BCI(PUSHB_1);
655 BCI(y_offset);
658 BCI(PUSHB_1);
659 BCI(bci_shift_subglyph);
660 BCI(CALL);
662 End:
663 curr_contour += num_contours;
666 return bufp;
671 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
672 * data in four arrays (which are simple but waste a lot of memory). The
673 * function below converts them into bytecode.
675 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
676 * together with the edge they correspond to.
678 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
679 * loop over the edge or edge pairs, respectively, and each edge or edge
680 * pair contains an inner loop to emit the correponding points.
683 static void
684 TA_build_point_hints(Recorder* recorder,
685 TA_GlyphHints hints)
687 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
688 TA_Segment segments = axis->segments;
689 TA_Edge edges = axis->edges;
691 FT_Byte* p = recorder->hints_record.buf;
693 FT_UShort i;
694 FT_UShort j;
696 FT_UShort prev_edge;
697 FT_UShort prev_before_edge;
698 FT_UShort prev_after_edge;
700 Node1* before_node;
701 Node1* after_node;
702 Node2* on_node;
703 Node3* between_node;
706 /* we store everything as 16bit numbers; */
707 /* the function numbers (`ta_ip_before', etc.) */
708 /* reflect the order in the TA_Action enumeration */
710 /* ip_before_points */
712 i = 0;
713 for (before_node = LLRB_MIN(ip_before_points,
714 &recorder->ip_before_points_head);
715 before_node;
716 before_node = LLRB_NEXT(ip_before_points,
717 &recorder->ip_before_points_head,
718 before_node))
720 /* count points */
721 i++;
724 if (i)
726 TA_Edge edge;
729 recorder->hints_record.num_actions++;
731 edge = edges;
733 *(p++) = 0;
734 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
735 *(p++) = HIGH(edge->first - segments);
736 *(p++) = LOW(edge->first - segments);
737 *(p++) = HIGH(i);
738 *(p++) = LOW(i);
740 for (before_node = LLRB_MIN(ip_before_points,
741 &recorder->ip_before_points_head);
742 before_node;
743 before_node = LLRB_NEXT(ip_before_points,
744 &recorder->ip_before_points_head,
745 before_node))
747 FT_UInt point;
750 point = TA_adjust_point_index(recorder, before_node->point);
751 *(p++) = HIGH(point);
752 *(p++) = LOW(point);
756 /* ip_after_points */
758 i = 0;
759 for (after_node = LLRB_MIN(ip_after_points,
760 &recorder->ip_after_points_head);
761 after_node;
762 after_node = LLRB_NEXT(ip_after_points,
763 &recorder->ip_after_points_head,
764 after_node))
766 /* count points */
767 i++;
770 if (i)
772 TA_Edge edge;
775 recorder->hints_record.num_actions++;
777 edge = edges + axis->num_edges - 1;
779 *(p++) = 0;
780 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
781 *(p++) = HIGH(edge->first - segments);
782 *(p++) = LOW(edge->first - segments);
783 *(p++) = HIGH(i);
784 *(p++) = LOW(i);
786 for (after_node = LLRB_MIN(ip_after_points,
787 &recorder->ip_after_points_head);
788 after_node;
789 after_node = LLRB_NEXT(ip_after_points,
790 &recorder->ip_after_points_head,
791 after_node))
793 FT_UInt point;
796 point = TA_adjust_point_index(recorder, after_node->point);
797 *(p++) = HIGH(point);
798 *(p++) = LOW(point);
802 /* ip_on_point_array */
804 prev_edge = 0xFFFF;
805 i = 0;
806 for (on_node = LLRB_MIN(ip_on_points,
807 &recorder->ip_on_points_head);
808 on_node;
809 on_node = LLRB_NEXT(ip_on_points,
810 &recorder->ip_on_points_head,
811 on_node))
813 /* count edges */
814 if (on_node->edge != prev_edge)
816 i++;
817 prev_edge = on_node->edge;
821 if (i)
823 recorder->hints_record.num_actions++;
825 *(p++) = 0;
826 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
827 *(p++) = HIGH(i);
828 *(p++) = LOW(i);
830 for (on_node = LLRB_MIN(ip_on_points,
831 &recorder->ip_on_points_head);
832 on_node;
833 on_node = LLRB_NEXT(ip_on_points,
834 &recorder->ip_on_points_head,
835 on_node))
837 Node2* edge_node;
838 TA_Edge edge;
841 edge = edges + on_node->edge;
843 *(p++) = HIGH(edge->first - segments);
844 *(p++) = LOW(edge->first - segments);
846 /* save current position */
847 edge_node = on_node;
848 j = 0;
849 for (;
850 on_node;
851 on_node = LLRB_NEXT(ip_on_points,
852 &recorder->ip_on_points_head,
853 on_node))
855 /* count points on current edge */
856 if (on_node->edge != edge_node->edge)
857 break;
858 j++;
861 *(p++) = HIGH(j);
862 *(p++) = LOW(j);
864 /* restore current position */
865 on_node = edge_node;
866 for (;
867 on_node;
868 on_node = LLRB_NEXT(ip_on_points,
869 &recorder->ip_on_points_head,
870 on_node))
872 FT_UInt point;
875 if (on_node->edge != edge_node->edge)
876 break;
878 point = TA_adjust_point_index(recorder, on_node->point);
879 *(p++) = HIGH(point);
880 *(p++) = LOW(point);
882 /* keep track of previous node */
883 edge_node = on_node;
886 /* reset loop iterator by one element, then continue */
887 on_node = edge_node;
891 /* ip_between_point_array */
893 prev_before_edge = 0xFFFF;
894 prev_after_edge = 0xFFFF;
895 i = 0;
896 for (between_node = LLRB_MIN(ip_between_points,
897 &recorder->ip_between_points_head);
898 between_node;
899 between_node = LLRB_NEXT(ip_between_points,
900 &recorder->ip_between_points_head,
901 between_node))
903 /* count `(before,after)' edge pairs */
904 if (between_node->before_edge != prev_before_edge
905 || between_node->after_edge != prev_after_edge)
907 i++;
908 prev_before_edge = between_node->before_edge;
909 prev_after_edge = between_node->after_edge;
913 if (i)
915 recorder->hints_record.num_actions++;
917 *(p++) = 0;
918 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
919 *(p++) = HIGH(i);
920 *(p++) = LOW(i);
922 for (between_node = LLRB_MIN(ip_between_points,
923 &recorder->ip_between_points_head);
924 between_node;
925 between_node = LLRB_NEXT(ip_between_points,
926 &recorder->ip_between_points_head,
927 between_node))
929 Node3* edge_pair_node;
930 TA_Edge before;
931 TA_Edge after;
934 before = edges + between_node->before_edge;
935 after = edges + between_node->after_edge;
937 *(p++) = HIGH(after->first - segments);
938 *(p++) = LOW(after->first - segments);
939 *(p++) = HIGH(before->first - segments);
940 *(p++) = LOW(before->first - segments);
942 /* save current position */
943 edge_pair_node = between_node;
944 j = 0;
945 for (;
946 between_node;
947 between_node = LLRB_NEXT(ip_between_points,
948 &recorder->ip_between_points_head,
949 between_node))
951 /* count points associated with current edge pair */
952 if (between_node->before_edge != edge_pair_node->before_edge
953 || between_node->after_edge != edge_pair_node->after_edge)
954 break;
955 j++;
958 *(p++) = HIGH(j);
959 *(p++) = LOW(j);
961 /* restore current position */
962 between_node = edge_pair_node;
963 for (;
964 between_node;
965 between_node = LLRB_NEXT(ip_between_points,
966 &recorder->ip_between_points_head,
967 between_node))
969 FT_UInt point;
972 if (between_node->before_edge != edge_pair_node->before_edge
973 || between_node->after_edge != edge_pair_node->after_edge)
974 break;
976 point = TA_adjust_point_index(recorder, between_node->point);
977 *(p++) = HIGH(point);
978 *(p++) = LOW(point);
980 /* keep track of previous node */
981 edge_pair_node = between_node;
984 /* reset loop iterator by one element, then continue */
985 between_node = edge_pair_node;
989 recorder->hints_record.buf = p;
993 static FT_Bool
994 TA_hints_record_is_different(Hints_Record* hints_records,
995 FT_UInt num_hints_records,
996 FT_Byte* start,
997 FT_Byte* end)
999 Hints_Record last_hints_record;
1002 if (!hints_records)
1003 return 1;
1005 /* we only need to compare with the last hints record */
1006 last_hints_record = hints_records[num_hints_records - 1];
1008 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
1009 return 1;
1011 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
1012 return 1;
1014 return 0;
1018 static FT_Error
1019 TA_add_hints_record(Hints_Record** hints_records,
1020 FT_UInt* num_hints_records,
1021 FT_Byte* start,
1022 Hints_Record hints_record)
1024 Hints_Record* hints_records_new;
1025 FT_UInt buf_len;
1026 /* at this point, `hints_record.buf' still points into `ins_buf' */
1027 FT_Byte* end = hints_record.buf;
1030 buf_len = (FT_UInt)(end - start);
1032 /* now fill the structure completely */
1033 hints_record.buf_len = buf_len;
1034 hints_record.buf = (FT_Byte*)malloc(buf_len);
1035 if (!hints_record.buf)
1036 return FT_Err_Out_Of_Memory;
1038 memcpy(hints_record.buf, start, buf_len);
1040 (*num_hints_records)++;
1041 hints_records_new =
1042 (Hints_Record*)realloc(*hints_records, *num_hints_records
1043 * sizeof (Hints_Record));
1044 if (!hints_records_new)
1046 free(hints_record.buf);
1047 (*num_hints_records)--;
1048 return FT_Err_Out_Of_Memory;
1050 else
1051 *hints_records = hints_records_new;
1053 (*hints_records)[*num_hints_records - 1] = hints_record;
1055 return FT_Err_Ok;
1059 static FT_Byte*
1060 TA_emit_hints_record(Recorder* recorder,
1061 Hints_Record* hints_record,
1062 FT_Byte* bufp,
1063 FT_Bool optimize)
1065 FT_Byte* p;
1066 FT_Byte* endp;
1067 FT_Bool need_words = 0;
1069 FT_UInt i, j;
1070 FT_UInt num_arguments;
1071 FT_UInt num_args;
1074 /* check whether any argument is larger than 0xFF */
1075 endp = hints_record->buf + hints_record->buf_len;
1076 for (p = hints_record->buf; p < endp; p += 2)
1077 if (*p)
1079 need_words = 1;
1080 break;
1083 /* with most fonts it is very rare */
1084 /* that any of the pushed arguments is larger than 0xFF, */
1085 /* thus we refrain from further optimizing this case */
1087 num_arguments = hints_record->buf_len / 2;
1088 p = endp - 2;
1090 if (need_words)
1092 for (i = 0; i < num_arguments; i += 255)
1094 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1096 if (optimize && num_args <= 8)
1097 BCI(PUSHW_1 - 1 + num_args);
1098 else
1100 BCI(NPUSHW);
1101 BCI(num_args);
1103 for (j = 0; j < num_args; j++)
1105 BCI(*p);
1106 BCI(*(p + 1));
1107 p -= 2;
1111 else
1113 /* we only need the lower bytes */
1114 p++;
1116 for (i = 0; i < num_arguments; i += 255)
1118 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
1120 if (optimize && num_args <= 8)
1121 BCI(PUSHB_1 - 1 + num_args);
1122 else
1124 BCI(NPUSHB);
1125 BCI(num_args);
1127 for (j = 0; j < num_args; j++)
1129 BCI(*p);
1130 p -= 2;
1135 /* collect stack depth data */
1136 if (num_arguments > recorder->num_stack_elements)
1137 recorder->num_stack_elements = num_arguments;
1139 return bufp;
1143 static FT_Byte*
1144 TA_emit_hints_records(Recorder* recorder,
1145 Hints_Record* hints_records,
1146 FT_UInt num_hints_records,
1147 FT_Byte* bufp,
1148 FT_Bool optimize)
1150 FT_UInt i;
1151 Hints_Record* hints_record;
1154 hints_record = hints_records;
1156 /* emit hints records in `if' clauses, */
1157 /* with the ppem size as the condition */
1158 for (i = 0; i < num_hints_records - 1; i++)
1160 BCI(MPPEM);
1161 if (hints_record->size > 0xFF)
1163 BCI(PUSHW_1);
1164 BCI(HIGH((hints_record + 1)->size));
1165 BCI(LOW((hints_record + 1)->size));
1167 else
1169 BCI(PUSHB_1);
1170 BCI((hints_record + 1)->size);
1172 BCI(LT);
1173 BCI(IF);
1174 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1175 BCI(ELSE);
1177 hints_record++;
1180 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1182 for (i = 0; i < num_hints_records - 1; i++)
1183 BCI(EIF);
1185 return bufp;
1189 static void
1190 TA_free_hints_records(Hints_Record* hints_records,
1191 FT_UInt num_hints_records)
1193 FT_UInt i;
1196 for (i = 0; i < num_hints_records; i++)
1197 free(hints_records[i].buf);
1199 free(hints_records);
1203 static FT_Byte*
1204 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1205 TA_AxisHints axis,
1206 TA_Edge edge,
1207 FT_UShort* wraps)
1209 TA_Segment segments = axis->segments;
1210 TA_Segment seg;
1211 FT_UShort seg_idx;
1212 FT_UShort num_segs = 0;
1213 FT_UShort* wrap;
1216 seg_idx = edge->first - segments;
1218 /* we store everything as 16bit numbers */
1219 *(bufp++) = HIGH(seg_idx);
1220 *(bufp++) = LOW(seg_idx);
1222 /* wrap-around segments are stored as two segments */
1223 if (edge->first->first > edge->first->last)
1224 num_segs++;
1226 seg = edge->first->edge_next;
1227 while (seg != edge->first)
1229 num_segs++;
1231 if (seg->first > seg->last)
1232 num_segs++;
1234 seg = seg->edge_next;
1237 *(bufp++) = HIGH(num_segs);
1238 *(bufp++) = LOW(num_segs);
1240 if (edge->first->first > edge->first->last)
1242 /* emit second part of wrap-around segment; */
1243 /* the bytecode positions such segments after `normal' ones */
1244 wrap = wraps;
1245 for (;;)
1247 if (seg_idx == *wrap)
1248 break;
1249 wrap++;
1252 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1253 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1256 seg = edge->first->edge_next;
1257 while (seg != edge->first)
1259 seg_idx = seg - segments;
1261 *(bufp++) = HIGH(seg_idx);
1262 *(bufp++) = LOW(seg_idx);
1264 if (seg->first > seg->last)
1266 wrap = wraps;
1267 for (;;)
1269 if (seg_idx == *wrap)
1270 break;
1271 wrap++;
1274 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1275 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1278 seg = seg->edge_next;
1281 return bufp;
1285 static void
1286 TA_hints_recorder(TA_Action action,
1287 TA_GlyphHints hints,
1288 TA_Dimension dim,
1289 void* arg1,
1290 TA_Edge arg2,
1291 TA_Edge arg3,
1292 TA_Edge lower_bound,
1293 TA_Edge upper_bound)
1295 TA_AxisHints axis = &hints->axis[dim];
1296 TA_Edge edges = axis->edges;
1297 TA_Segment segments = axis->segments;
1298 TA_Point points = hints->points;
1300 Recorder* recorder = (Recorder*)hints->user;
1301 SFNT* sfnt = recorder->sfnt;
1302 FONT* font = recorder->font;
1303 FT_UShort* wraps = recorder->wrap_around_segments;
1304 FT_Byte* p = recorder->hints_record.buf;
1306 FT_UInt style = font->loader->metrics->style_class->style;
1309 if (dim == TA_DIMENSION_HORZ)
1310 return;
1312 /* we collect point hints for later processing */
1313 switch (action)
1315 case ta_ip_before:
1317 Node1* before_node;
1318 TA_Point point = (TA_Point)arg1;
1321 before_node = (Node1*)malloc(sizeof (Node1));
1322 if (!before_node)
1323 return;
1324 before_node->point = point - points;
1326 LLRB_INSERT(ip_before_points,
1327 &recorder->ip_before_points_head,
1328 before_node);
1330 return;
1332 case ta_ip_after:
1334 Node1* after_node;
1335 TA_Point point = (TA_Point)arg1;
1338 after_node = (Node1*)malloc(sizeof (Node1));
1339 if (!after_node)
1340 return;
1341 after_node->point = point - points;
1343 LLRB_INSERT(ip_after_points,
1344 &recorder->ip_after_points_head,
1345 after_node);
1347 return;
1349 case ta_ip_on:
1351 Node2* on_node;
1352 TA_Point point = (TA_Point)arg1;
1353 TA_Edge edge = arg2;
1356 on_node = (Node2*)malloc(sizeof (Node2));
1357 if (!on_node)
1358 return;
1359 on_node->edge = edge - edges;
1360 on_node->point = point - points;
1362 LLRB_INSERT(ip_on_points,
1363 &recorder->ip_on_points_head,
1364 on_node);
1366 return;
1368 case ta_ip_between:
1370 Node3* between_node;
1371 TA_Point point = (TA_Point)arg1;
1372 TA_Edge before = arg2;
1373 TA_Edge after = arg3;
1376 between_node = (Node3*)malloc(sizeof (Node3));
1377 if (!between_node)
1378 return;
1379 between_node->before_edge = before - edges;
1380 between_node->after_edge = after - edges;
1381 between_node->point = point - points;
1383 LLRB_INSERT(ip_between_points,
1384 &recorder->ip_between_points_head,
1385 between_node);
1387 return;
1389 case ta_bound:
1390 /* we ignore the BOUND action since we signal this information */
1391 /* with the proper function number */
1392 return;
1394 default:
1395 break;
1398 /* some enum values correspond to four or eight bytecode functions; */
1399 /* if the value is n, the function numbers are n, ..., n+7, */
1400 /* to be differentiated with flags */
1402 switch (action)
1404 case ta_link:
1406 TA_Edge base_edge = (TA_Edge)arg1;
1407 TA_Edge stem_edge = arg2;
1410 *(p++) = 0;
1411 *(p++) = (FT_Byte)action + ACTION_OFFSET
1412 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1413 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1415 *(p++) = HIGH(base_edge->first - segments);
1416 *(p++) = LOW(base_edge->first - segments);
1417 *(p++) = HIGH(stem_edge->first - segments);
1418 *(p++) = LOW(stem_edge->first - segments);
1420 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1422 break;
1424 case ta_anchor:
1426 TA_Edge edge = (TA_Edge)arg1;
1427 TA_Edge edge2 = arg2;
1430 *(p++) = 0;
1431 *(p++) = (FT_Byte)action + ACTION_OFFSET
1432 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1433 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1435 *(p++) = HIGH(edge->first - segments);
1436 *(p++) = LOW(edge->first - segments);
1437 *(p++) = HIGH(edge2->first - segments);
1438 *(p++) = LOW(edge2->first - segments);
1440 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1442 break;
1444 case ta_adjust:
1446 TA_Edge edge = (TA_Edge)arg1;
1447 TA_Edge edge2 = arg2;
1448 TA_Edge edge_minus_one = lower_bound;
1451 *(p++) = 0;
1452 *(p++) = (FT_Byte)action + ACTION_OFFSET
1453 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1454 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1455 + 4 * (edge_minus_one != NULL);
1457 *(p++) = HIGH(edge->first - segments);
1458 *(p++) = LOW(edge->first - segments);
1459 *(p++) = HIGH(edge2->first - segments);
1460 *(p++) = LOW(edge2->first - segments);
1462 if (edge_minus_one)
1464 *(p++) = HIGH(edge_minus_one->first - segments);
1465 *(p++) = LOW(edge_minus_one->first - segments);
1468 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1470 break;
1472 case ta_blue_anchor:
1474 TA_Edge edge = (TA_Edge)arg1;
1475 TA_Edge blue = arg2;
1478 *(p++) = 0;
1479 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1481 *(p++) = HIGH(blue->first - segments);
1482 *(p++) = LOW(blue->first - segments);
1484 if (edge->best_blue_is_shoot)
1486 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1487 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1489 else
1491 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1492 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1495 *(p++) = HIGH(edge->first - segments);
1496 *(p++) = LOW(edge->first - segments);
1498 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1500 break;
1502 case ta_stem:
1504 TA_Edge edge = (TA_Edge)arg1;
1505 TA_Edge edge2 = arg2;
1506 TA_Edge edge_minus_one = lower_bound;
1509 *(p++) = 0;
1510 *(p++) = (FT_Byte)action + ACTION_OFFSET
1511 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1512 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1513 + 4 * (edge_minus_one != NULL);
1515 *(p++) = HIGH(edge->first - segments);
1516 *(p++) = LOW(edge->first - segments);
1517 *(p++) = HIGH(edge2->first - segments);
1518 *(p++) = LOW(edge2->first - segments);
1520 if (edge_minus_one)
1522 *(p++) = HIGH(edge_minus_one->first - segments);
1523 *(p++) = LOW(edge_minus_one->first - segments);
1526 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1527 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1529 break;
1531 case ta_blue:
1533 TA_Edge edge = (TA_Edge)arg1;
1536 *(p++) = 0;
1537 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1539 if (edge->best_blue_is_shoot)
1541 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1542 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style) + edge->best_blue_idx);
1544 else
1546 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1547 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(style) + edge->best_blue_idx);
1550 *(p++) = HIGH(edge->first - segments);
1551 *(p++) = LOW(edge->first - segments);
1553 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1555 break;
1557 case ta_serif:
1559 TA_Edge serif = (TA_Edge)arg1;
1560 TA_Edge base = serif->serif;
1563 *(p++) = 0;
1564 *(p++) = (FT_Byte)action + ACTION_OFFSET
1565 + (lower_bound != NULL)
1566 + 2 * (upper_bound != NULL);
1568 *(p++) = HIGH(serif->first - segments);
1569 *(p++) = LOW(serif->first - segments);
1570 *(p++) = HIGH(base->first - segments);
1571 *(p++) = LOW(base->first - segments);
1573 if (lower_bound)
1575 *(p++) = HIGH(lower_bound->first - segments);
1576 *(p++) = LOW(lower_bound->first - segments);
1578 if (upper_bound)
1580 *(p++) = HIGH(upper_bound->first - segments);
1581 *(p++) = LOW(upper_bound->first - segments);
1584 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1586 break;
1588 case ta_serif_anchor:
1589 case ta_serif_link2:
1591 TA_Edge edge = (TA_Edge)arg1;
1594 *(p++) = 0;
1595 *(p++) = (FT_Byte)action + ACTION_OFFSET
1596 + (lower_bound != NULL)
1597 + 2 * (upper_bound != NULL);
1599 *(p++) = HIGH(edge->first - segments);
1600 *(p++) = LOW(edge->first - segments);
1602 if (lower_bound)
1604 *(p++) = HIGH(lower_bound->first - segments);
1605 *(p++) = LOW(lower_bound->first - segments);
1607 if (upper_bound)
1609 *(p++) = HIGH(upper_bound->first - segments);
1610 *(p++) = LOW(upper_bound->first - segments);
1613 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1615 break;
1617 case ta_serif_link1:
1619 TA_Edge edge = (TA_Edge)arg1;
1620 TA_Edge before = arg2;
1621 TA_Edge after = arg3;
1624 *(p++) = 0;
1625 *(p++) = (FT_Byte)action + ACTION_OFFSET
1626 + (lower_bound != NULL)
1627 + 2 * (upper_bound != NULL);
1629 *(p++) = HIGH(before->first - segments);
1630 *(p++) = LOW(before->first - segments);
1631 *(p++) = HIGH(edge->first - segments);
1632 *(p++) = LOW(edge->first - segments);
1633 *(p++) = HIGH(after->first - segments);
1634 *(p++) = LOW(after->first - segments);
1636 if (lower_bound)
1638 *(p++) = HIGH(lower_bound->first - segments);
1639 *(p++) = LOW(lower_bound->first - segments);
1641 if (upper_bound)
1643 *(p++) = HIGH(upper_bound->first - segments);
1644 *(p++) = LOW(upper_bound->first - segments);
1647 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1649 break;
1651 default:
1652 /* there are more cases in the enumeration */
1653 /* which are handled with flags */
1654 break;
1657 recorder->hints_record.num_actions++;
1658 recorder->hints_record.buf = p;
1662 static FT_Error
1663 TA_init_recorder(Recorder* recorder,
1664 SFNT* sfnt,
1665 FONT* font,
1666 GLYPH* glyph,
1667 TA_GlyphHints hints)
1669 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1670 TA_Point points = hints->points;
1671 TA_Point point_limit = points + hints->num_points;
1672 TA_Point point;
1674 TA_Segment segments = axis->segments;
1675 TA_Segment seg_limit = segments + axis->num_segments;
1676 TA_Segment seg;
1678 FT_UShort num_strong_points = 0;
1679 FT_UShort* wrap_around_segment;
1681 recorder->sfnt = sfnt;
1682 recorder->font = font;
1683 recorder->glyph = glyph;
1684 recorder->num_segments = axis->num_segments;
1686 LLRB_INIT(&recorder->ip_before_points_head);
1687 LLRB_INIT(&recorder->ip_after_points_head);
1688 LLRB_INIT(&recorder->ip_on_points_head);
1689 LLRB_INIT(&recorder->ip_between_points_head);
1691 recorder->num_stack_elements = 0;
1693 /* no need to clean up allocated arrays in case of error; */
1694 /* this is handled later by `TA_free_recorder' */
1696 recorder->num_wrap_around_segments = 0;
1697 for (seg = segments; seg < seg_limit; seg++)
1698 if (seg->first > seg->last)
1699 recorder->num_wrap_around_segments++;
1701 recorder->wrap_around_segments =
1702 (FT_UShort*)malloc(recorder->num_wrap_around_segments
1703 * sizeof (FT_UShort));
1704 if (!recorder->wrap_around_segments)
1705 return FT_Err_Out_Of_Memory;
1707 wrap_around_segment = recorder->wrap_around_segments;
1708 for (seg = segments; seg < seg_limit; seg++)
1709 if (seg->first > seg->last)
1710 *(wrap_around_segment++) = seg - segments;
1712 /* get number of strong points */
1713 for (point = points; point < point_limit; point++)
1715 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1716 /* however, this value isn't known yet */
1717 /* (or rather, it can vary between different pixel sizes) */
1718 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1719 continue;
1721 num_strong_points++;
1724 recorder->num_strong_points = num_strong_points;
1726 return FT_Err_Ok;
1730 static void
1731 TA_reset_recorder(Recorder* recorder,
1732 FT_Byte* bufp)
1734 recorder->hints_record.buf = bufp;
1735 recorder->hints_record.num_actions = 0;
1739 static void
1740 TA_rewind_recorder(Recorder* recorder,
1741 FT_Byte* bufp,
1742 FT_UInt size)
1744 Node1* before_node;
1745 Node1* after_node;
1746 Node2* on_node;
1747 Node3* between_node;
1749 Node1* next_before_node;
1750 Node1* next_after_node;
1751 Node2* next_on_node;
1752 Node3* next_between_node;
1755 TA_reset_recorder(recorder, bufp);
1757 recorder->hints_record.size = size;
1759 /* deallocate our red-black trees */
1761 for (before_node = LLRB_MIN(ip_before_points,
1762 &recorder->ip_before_points_head);
1763 before_node;
1764 before_node = next_before_node)
1766 next_before_node = LLRB_NEXT(ip_before_points,
1767 &recorder->ip_before_points_head,
1768 before_node);
1769 LLRB_REMOVE(ip_before_points,
1770 &recorder->ip_before_points_head,
1771 before_node);
1772 free(before_node);
1775 for (after_node = LLRB_MIN(ip_after_points,
1776 &recorder->ip_after_points_head);
1777 after_node;
1778 after_node = next_after_node)
1780 next_after_node = LLRB_NEXT(ip_after_points,
1781 &recorder->ip_after_points_head,
1782 after_node);
1783 LLRB_REMOVE(ip_after_points,
1784 &recorder->ip_after_points_head,
1785 after_node);
1786 free(after_node);
1789 for (on_node = LLRB_MIN(ip_on_points,
1790 &recorder->ip_on_points_head);
1791 on_node;
1792 on_node = next_on_node)
1794 next_on_node = LLRB_NEXT(ip_on_points,
1795 &recorder->ip_on_points_head,
1796 on_node);
1797 LLRB_REMOVE(ip_on_points,
1798 &recorder->ip_on_points_head,
1799 on_node);
1800 free(on_node);
1803 for (between_node = LLRB_MIN(ip_between_points,
1804 &recorder->ip_between_points_head);
1805 between_node;
1806 between_node = next_between_node)
1808 next_between_node = LLRB_NEXT(ip_between_points,
1809 &recorder->ip_between_points_head,
1810 between_node);
1811 LLRB_REMOVE(ip_between_points,
1812 &recorder->ip_between_points_head,
1813 between_node);
1814 free(between_node);
1819 static void
1820 TA_free_recorder(Recorder* recorder)
1822 free(recorder->wrap_around_segments);
1824 TA_rewind_recorder(recorder, NULL, 0);
1828 FT_Error
1829 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1830 FONT* font,
1831 FT_Long idx)
1833 FT_Face face = sfnt->face;
1834 FT_Error error;
1836 FT_Byte* ins_buf;
1837 FT_UInt ins_len;
1838 FT_Byte* bufp;
1839 FT_Byte* p;
1841 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1842 glyf_Data* data = (glyf_Data*)glyf_table->data;
1843 /* `idx' is never negative */
1844 GLYPH* glyph = &data->glyphs[idx];
1846 TA_GlyphHints hints;
1848 FT_UInt num_action_hints_records = 0;
1849 FT_UInt num_point_hints_records = 0;
1850 Hints_Record* action_hints_records = NULL;
1851 Hints_Record* point_hints_records = NULL;
1853 Recorder recorder;
1854 FT_UShort num_stack_elements;
1855 FT_Bool optimize = 0;
1857 FT_Int32 load_flags;
1858 FT_UInt size;
1860 FT_Byte* pos[3];
1862 #ifdef TA_DEBUG
1863 int _ta_debug_save;
1864 #endif
1867 /* XXX: right now, we abuse this flag to control */
1868 /* the global behaviour of the auto-hinter */
1869 load_flags = 1 << 29; /* vertical hinting only */
1870 if (!font->adjust_subglyphs)
1872 if (font->hint_composites)
1873 load_flags |= FT_LOAD_NO_SCALE;
1874 else
1875 load_flags |= FT_LOAD_NO_RECURSE;
1878 /* computing the segments is resolution independent, */
1879 /* thus the pixel size in this call is arbitrary -- */
1880 /* however, we avoid unnecessary debugging output */
1881 /* if we use the lowest value of the hinting range */
1882 error = FT_Set_Pixel_Sizes(face,
1883 font->hinting_range_min,
1884 font->hinting_range_min);
1885 if (error)
1886 return error;
1888 #ifdef TA_DEBUG
1889 /* temporarily disable some debugging output */
1890 /* to avoid getting the information twice */
1891 _ta_debug_save = _ta_debug;
1892 _ta_debug = 0;
1893 #endif
1895 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1896 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1898 #ifdef TA_DEBUG
1899 _ta_debug = _ta_debug_save;
1900 #endif
1902 if (error)
1903 return error;
1905 /* do nothing if we have an empty glyph */
1906 if (!face->glyph->outline.n_contours)
1907 return FT_Err_Ok;
1909 hints = &font->loader->hints;
1911 /* do nothing if the setup delivered the `none_dflt' style only */
1912 if (!hints->num_points)
1913 return FT_Err_Ok;
1915 /* we allocate a buffer which is certainly large enough */
1916 /* to hold all of the created bytecode instructions; */
1917 /* later on it gets reallocated to its real size */
1918 ins_len = hints->num_points * 1000;
1919 ins_buf = (FT_Byte*)malloc(ins_len);
1920 if (!ins_buf)
1921 return FT_Err_Out_Of_Memory;
1923 /* initialize array with an invalid bytecode */
1924 /* so that we can easily find the array length at reallocation time */
1925 memset(ins_buf, INS_A0, ins_len);
1927 /* handle composite glyph */
1928 if (font->loader->gloader->base.num_subglyphs)
1930 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1931 if (!bufp)
1933 error = FT_Err_Out_Of_Memory;
1934 goto Err;
1937 goto Done1;
1940 /* only scale the glyph if the `none_dflt' style has been used */
1941 if (font->loader->metrics->style_class == &ta_none_dflt_style_class)
1943 /* since `TA_init_recorder' hasn't been called yet, */
1944 /* we manually initialize the `sfnt', `font', and `glyph' fields */
1945 recorder.sfnt = sfnt;
1946 recorder.font = font;
1947 recorder.glyph = glyph;
1949 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1950 if (!bufp)
1952 error = FT_Err_Out_Of_Memory;
1953 goto Err;
1956 goto Done1;
1959 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
1960 if (error)
1961 goto Err;
1963 /* loop over a large range of pixel sizes */
1964 /* to find hints records which get pushed onto the bytecode stack */
1966 #ifdef DEBUGGING
1967 if (font->debug)
1969 int num_chars, i;
1970 char buf[256];
1973 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1975 num_chars = fprintf(stderr, "glyph %ld", idx);
1976 if (*buf)
1977 num_chars += fprintf(stderr, " (%s)", buf);
1978 fprintf(stderr, "\n");
1979 for (i = 0; i < num_chars; i++)
1980 putc('=', stderr);
1981 fprintf(stderr, "\n\n");
1984 #endif
1986 /* we temporarily use `ins_buf' to record the current glyph hints */
1987 ta_loader_register_hints_recorder(font->loader,
1988 TA_hints_recorder,
1989 (void*)&recorder);
1991 for (size = font->hinting_range_min;
1992 size <= font->hinting_range_max;
1993 size++)
1995 #ifdef DEBUGGING
1996 int have_dumps = 0;
1997 #endif
2000 TA_rewind_recorder(&recorder, ins_buf, size);
2002 error = FT_Set_Pixel_Sizes(face, size, size);
2003 if (error)
2004 goto Err;
2006 #ifdef DEBUGGING
2007 if (font->debug)
2009 int num_chars, i;
2012 num_chars = fprintf(stderr, "size %d\n", size);
2013 for (i = 0; i < num_chars - 1; i++)
2014 putc('-', stderr);
2015 fprintf(stderr, "\n\n");
2017 #endif
2019 /* calling `ta_loader_load_glyph' uses the */
2020 /* `TA_hints_recorder' function as a callback, */
2021 /* modifying `hints_record' */
2022 error = ta_loader_load_glyph(font, face, idx, load_flags);
2023 if (error)
2024 goto Err;
2026 if (TA_hints_record_is_different(action_hints_records,
2027 num_action_hints_records,
2028 ins_buf, recorder.hints_record.buf))
2030 #ifdef DEBUGGING
2031 if (font->debug)
2033 have_dumps = 1;
2035 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2036 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2037 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2039 fprintf(stderr, "action hints record:\n");
2040 if (ins_buf == recorder.hints_record.buf)
2041 fprintf(stderr, " (none)");
2042 else
2044 fprintf(stderr, " ");
2045 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2046 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2048 fprintf(stderr, "\n");
2050 #endif
2052 error = TA_add_hints_record(&action_hints_records,
2053 &num_action_hints_records,
2054 ins_buf, recorder.hints_record);
2055 if (error)
2056 goto Err;
2059 /* now handle point records */
2061 TA_reset_recorder(&recorder, ins_buf);
2063 /* use the point hints data collected in `TA_hints_recorder' */
2064 TA_build_point_hints(&recorder, hints);
2066 if (TA_hints_record_is_different(point_hints_records,
2067 num_point_hints_records,
2068 ins_buf, recorder.hints_record.buf))
2070 #ifdef DEBUGGING
2071 if (font->debug)
2073 if (!have_dumps)
2075 int num_chars, i;
2078 num_chars = fprintf(stderr, "size %d\n", size);
2079 for (i = 0; i < num_chars - 1; i++)
2080 putc('-', stderr);
2081 fprintf(stderr, "\n\n");
2083 ta_glyph_hints_dump_edges((TA_GlyphHints)_ta_debug_hints);
2084 ta_glyph_hints_dump_segments((TA_GlyphHints)_ta_debug_hints);
2085 ta_glyph_hints_dump_points((TA_GlyphHints)_ta_debug_hints);
2088 fprintf(stderr, "point hints record:\n");
2089 if (ins_buf == recorder.hints_record.buf)
2090 fprintf(stderr, " (none)");
2091 else
2093 fprintf(stderr, " ");
2094 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
2095 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
2097 fprintf(stderr, "\n\n");
2099 #endif
2101 error = TA_add_hints_record(&point_hints_records,
2102 &num_point_hints_records,
2103 ins_buf, recorder.hints_record);
2104 if (error)
2105 goto Err;
2109 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
2111 /* since we only have a single empty record we just scale the glyph */
2112 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
2113 if (!bufp)
2115 error = FT_Err_Out_Of_Memory;
2116 goto Err;
2119 /* clear the rest of the temporarily used part of `ins_buf' */
2120 p = bufp;
2121 while (*p != INS_A0)
2122 *(p++) = INS_A0;
2124 goto Done;
2127 /* if there is only a single record, */
2128 /* we do a global optimization later on */
2129 if (num_action_hints_records > 1)
2130 optimize = 1;
2132 /* store the hints records and handle stack depth */
2133 pos[0] = ins_buf;
2134 bufp = TA_emit_hints_records(&recorder,
2135 point_hints_records,
2136 num_point_hints_records,
2137 ins_buf,
2138 optimize);
2140 num_stack_elements = recorder.num_stack_elements;
2141 recorder.num_stack_elements = 0;
2143 pos[1] = bufp;
2144 bufp = TA_emit_hints_records(&recorder,
2145 action_hints_records,
2146 num_action_hints_records,
2147 bufp,
2148 optimize);
2150 recorder.num_stack_elements += num_stack_elements;
2152 pos[2] = bufp;
2153 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
2154 if (!bufp)
2156 error = FT_Err_Out_Of_Memory;
2157 goto Err;
2160 /* XXX improve handling of NPUSHW */
2161 if (num_action_hints_records == 1
2162 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
2165 * we optimize two common cases, replacing
2167 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
2169 * with
2171 * NPUSHB (A+B[+C]) ... CALL
2173 * if possible
2175 FT_Byte sizes[3];
2176 FT_Byte new_size1;
2177 FT_Byte new_size2;
2179 FT_UInt sum;
2180 FT_UInt i;
2181 FT_UInt pos_idx;
2184 /* the point hints records block can be missing */
2185 if (pos[0] == pos[1])
2187 pos[1] = pos[2];
2188 pos[2] = NULL;
2191 /* there are at least two NPUSHB instructions */
2192 /* (one of them directly at the start) */
2193 sizes[0] = *(pos[0] + 1);
2194 sizes[1] = *(pos[1] + 1);
2195 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
2197 sum = sizes[0] + sizes[1] + sizes[2];
2199 if (sum > 2 * 0xFF)
2200 goto Done2; /* nothing to do since we need three NPUSHB */
2201 else if (!sizes[2] && (sum > 0xFF))
2202 goto Done2; /* nothing to do since we need two NPUSHB */
2204 if (sum > 0xFF)
2206 /* reduce three NPUSHB to two */
2207 new_size1 = 0xFF;
2208 new_size2 = sum - 0xFF;
2210 else
2212 /* reduce two or three NPUSHB to one */
2213 new_size1 = sum;
2214 new_size2 = 0;
2217 /* pack data */
2218 p = ins_buf;
2219 bufp = ins_buf;
2220 pos_idx = 0;
2222 if (new_size1 <= 8)
2223 BCI(PUSHB_1 - 1 + new_size1);
2224 else
2226 BCI(NPUSHB);
2227 BCI(new_size1);
2229 for (i = 0; i < new_size1; i++)
2231 if (p == pos[pos_idx])
2233 pos_idx++;
2234 p += 2; /* skip old NPUSHB */
2236 *(bufp++) = *(p++);
2239 if (new_size2)
2241 if (new_size2 <= 8)
2242 BCI(PUSHB_1 - 1 + new_size2);
2243 else
2245 BCI(NPUSHB);
2246 BCI(new_size2);
2248 for (i = 0; i < new_size2; i++)
2250 if (p == pos[pos_idx])
2252 pos_idx++;
2253 p += 2;
2255 *(bufp++) = *(p++);
2259 BCI(CALL);
2262 Done2:
2263 /* clear the rest of the temporarily used part of `ins_buf' */
2264 p = bufp;
2265 while (*p != INS_A0)
2266 *(p++) = INS_A0;
2268 Done:
2269 TA_free_hints_records(action_hints_records, num_action_hints_records);
2270 TA_free_hints_records(point_hints_records, num_point_hints_records);
2271 TA_free_recorder(&recorder);
2273 /* we are done, so reallocate the instruction array to its real size */
2274 if (*bufp == INS_A0)
2276 /* search backwards */
2277 while (*bufp == INS_A0)
2278 bufp--;
2279 bufp++;
2281 else
2283 /* search forwards */
2284 while (*bufp != INS_A0)
2285 bufp++;
2288 Done1:
2289 ins_len = bufp - ins_buf;
2291 if (ins_len > sfnt->max_instructions)
2292 sfnt->max_instructions = ins_len;
2294 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2295 glyph->ins_len = ins_len;
2297 return FT_Err_Ok;
2299 Err:
2300 TA_free_hints_records(action_hints_records, num_action_hints_records);
2301 TA_free_hints_records(point_hints_records, num_point_hints_records);
2302 TA_free_recorder(&recorder);
2303 free(ins_buf);
2305 return error;
2309 /* end of tabytecode.c */