Reduce size of generated bytecode, part 5.
[ttfautohint.git] / lib / tabytecode.c
blob88861b0be2185ad4db7ff2146288a5113d96b169
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2012 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"
19 #undef MISSING
20 #define MISSING (FT_UInt)~0
22 /* a simple macro to emit bytecode instructions */
23 #define BCI(code) *(bufp++) = (code)
25 /* we increase the stack depth by this amount */
26 #define ADDITIONAL_STACK_ELEMENTS 20
29 /* #define DEBUGGING */
32 #ifdef TA_DEBUG
33 int _ta_debug = 1;
34 int _ta_debug_disable_horz_hints;
35 int _ta_debug_disable_vert_hints;
36 int _ta_debug_disable_blue_hints;
37 void* _ta_debug_hints;
38 #endif
41 typedef struct Hints_Record_
43 FT_UInt size;
44 FT_UInt num_actions;
45 FT_Byte* buf;
46 FT_UInt buf_len;
47 } Hints_Record;
49 typedef struct Recorder_
51 FONT* font;
52 GLYPH* glyph; /* the current glyph */
53 Hints_Record hints_record;
55 /* some segments can `wrap around' */
56 /* a contour's start point like 24-25-26-0-1-2 */
57 /* (there can be at most one such segment per contour); */
58 /* later on we append additional records */
59 /* to split them into 24-26 and 0-2 */
60 FT_UInt* wrap_around_segments;
61 FT_UInt num_wrap_around_segments;
63 FT_UShort num_stack_elements; /* the necessary stack depth so far */
65 /* data necessary for strong point interpolation */
66 FT_UInt* ip_before_points;
67 FT_UInt* ip_after_points;
68 FT_UInt* ip_on_point_array;
69 FT_UInt* ip_between_point_array;
71 FT_UInt num_strong_points;
72 FT_UInt num_segments;
73 } Recorder;
76 /* We add a subglyph for each composite glyph. */
77 /* Since subglyphs must contain at least one point, */
78 /* we have to adjust all point indices accordingly. */
79 /* Using the `pointsums' array of the `GLYPH' structure */
80 /* it is straightforward to do that: */
81 /* Assuming that point with index x is in the interval */
82 /* pointsums[n] <= x < pointsums[n + 1], */
83 /* the new point index is x + n. */
85 static FT_UInt
86 TA_adjust_point_index(Recorder* recorder,
87 FT_UInt idx)
89 GLYPH* glyph = recorder->glyph;
90 FT_UShort i;
93 if (!glyph->num_components)
94 return idx; /* not a composite glyph */
96 for (i = 0; i < glyph->num_pointsums; i++)
97 if (idx < glyph->pointsums[i])
98 break;
100 return idx + i;
104 /* we store the segments in the storage area; */
105 /* each segment record consists of the first and last point */
107 static FT_Byte*
108 TA_sfnt_build_glyph_segments(SFNT* sfnt,
109 Recorder* recorder,
110 FT_Byte* bufp)
112 FONT* font = recorder->font;
113 TA_GlyphHints hints = &font->loader->hints;
114 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
115 TA_Point points = hints->points;
116 TA_Segment segments = axis->segments;
117 TA_Segment seg;
118 TA_Segment seg_limit;
120 FT_Outline outline = font->loader->gloader->base.outline;
122 FT_UInt* args;
123 FT_UInt* arg;
124 FT_UInt num_args;
125 FT_UInt nargs;
126 FT_UInt num_segments;
128 FT_Bool need_words = 0;
130 FT_Int n;
131 FT_UInt i, j;
132 FT_UInt base;
133 FT_UInt num_packed_segments;
134 FT_UInt num_storage;
135 FT_UInt num_stack_elements;
136 FT_UInt num_twilight_points;
139 seg_limit = segments + axis->num_segments;
140 num_segments = axis->num_segments;
142 /* to pack the data in the bytecode more tightly, */
143 /* we store up to the first nine segments in nibbles if possible, */
144 /* using delta values */
145 base = 0;
146 num_packed_segments = 0;
147 for (seg = segments; seg < seg_limit; seg++)
149 FT_UInt first = seg->first - points;
150 FT_UInt last = seg->last - points;
153 first = TA_adjust_point_index(recorder, first);
154 last = TA_adjust_point_index(recorder, last);
156 if (first - base >= 16)
157 break;
158 if (first > last || last - first >= 16)
159 break;
160 if (num_packed_segments == 9)
161 break;
162 num_packed_segments++;
163 base = last;
166 /* also handle wrap-around segments */
167 num_segments += recorder->num_wrap_around_segments;
169 /* wrap-around segments are pushed with four arguments; */
170 /* a segment stored in nibbles needs only one byte instead of two */
171 num_args = num_packed_segments
172 + 2 * (num_segments - num_packed_segments)
173 + 2 * recorder->num_wrap_around_segments
174 + 2;
176 /* collect all arguments temporarily in an array (in reverse order) */
177 /* so that we can easily split into chunks of 255 args */
178 /* as needed by NPUSHB and NPUSHW, respectively */
179 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
180 if (!args)
181 return NULL;
183 arg = args + num_args - 1;
185 if (num_segments > 0xFF)
186 need_words = 1;
188 /* the number of packed segments is indicated by the function number */
189 if (recorder->glyph->num_components)
190 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
191 else
192 *(arg--) = bci_create_segments_0 + num_packed_segments;
193 *(arg--) = num_segments;
195 base = 0;
196 for (seg = segments; seg < segments + num_packed_segments; seg++)
198 FT_UInt first = seg->first - points;
199 FT_UInt last = seg->last - points;
200 FT_UInt low_nibble;
201 FT_UInt high_nibble;
204 first = TA_adjust_point_index(recorder, first);
205 last = TA_adjust_point_index(recorder, last);
207 low_nibble = first - base;
208 high_nibble = last - first;
210 *(arg--) = 16 * high_nibble + low_nibble;
212 base = last;
214 if (last > 0xFF)
215 need_words = 1;
218 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
220 FT_UInt first = seg->first - points;
221 FT_UInt last = seg->last - points;
224 *(arg--) = TA_adjust_point_index(recorder, first);
225 *(arg--) = TA_adjust_point_index(recorder, last);
227 /* we push the last and first contour point */
228 /* as a third and fourth argument in wrap-around segments */
229 if (first > last)
231 for (n = 0; n < outline.n_contours; n++)
233 FT_UInt end = (FT_UInt)outline.contours[n];
236 if (first <= end)
238 *(arg--) = TA_adjust_point_index(recorder, end);
239 if (end > 0xFF)
240 need_words = 1;
242 if (n == 0)
243 *(arg--) = TA_adjust_point_index(recorder, 0);
244 else
245 *(arg--) = TA_adjust_point_index(recorder,
246 (FT_UInt)outline.contours[n - 1] + 1);
247 break;
252 if (last > 0xFF)
253 need_words = 1;
256 /* emit the second part of wrap-around segments as separate segments */
257 /* so that edges can easily link to them */
258 for (seg = segments; seg < seg_limit; seg++)
260 FT_UInt first = seg->first - points;
261 FT_UInt last = seg->last - points;
264 if (first > last)
266 for (n = 0; n < outline.n_contours; n++)
268 if (first <= (FT_UInt)outline.contours[n])
270 if (n == 0)
271 *(arg--) = TA_adjust_point_index(recorder, 0);
272 else
273 *(arg--) = TA_adjust_point_index(recorder,
274 (FT_UInt)outline.contours[n - 1] + 1);
275 break;
279 *(arg--) = TA_adjust_point_index(recorder, last);
282 /* with most fonts it is very rare */
283 /* that any of the pushed arguments is larger than 0xFF, */
284 /* thus we refrain from further optimizing this case */
286 arg = args;
288 if (need_words)
290 for (i = 0; i < num_args; i += 255)
292 nargs = (num_args - i > 255) ? 255 : num_args - i;
294 BCI(NPUSHW);
295 BCI(nargs);
296 for (j = 0; j < nargs; j++)
298 BCI(HIGH(*arg));
299 BCI(LOW(*arg));
300 arg++;
304 else
306 for (i = 0; i < num_args; i += 255)
308 nargs = (num_args - i > 255) ? 255 : num_args - i;
310 BCI(NPUSHB);
311 BCI(nargs);
312 for (j = 0; j < nargs; j++)
314 BCI(*arg);
315 arg++;
320 BCI(CALL);
322 num_storage = sal_segment_offset + num_segments * 2;
323 if (num_storage > sfnt->max_storage)
324 sfnt->max_storage = num_storage;
326 num_twilight_points = num_segments * 2;
327 if (num_twilight_points > sfnt->max_twilight_points)
328 sfnt->max_twilight_points = num_twilight_points;
330 /* both this function and `TA_emit_hints_record' */
331 /* push data onto the stack */
332 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
333 + recorder->num_stack_elements + num_args;
334 if (num_stack_elements > sfnt->max_stack_elements)
335 sfnt->max_stack_elements = num_stack_elements;
337 free(args);
339 return bufp;
343 static FT_Byte*
344 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
345 Recorder* recorder,
346 FT_Byte* bufp)
348 FT_GlyphSlot glyph = sfnt->face->glyph;
349 FT_Vector* points = glyph->outline.points;
350 FT_Int num_contours = glyph->outline.n_contours;
352 FT_UInt* args;
353 FT_UInt* arg;
354 FT_UInt num_args;
355 FT_UInt nargs;
357 FT_Bool need_words = 0;
358 FT_Int p, q;
359 FT_UInt i, j;
360 FT_Int start, end;
361 FT_UInt num_stack_elements;
364 num_args = 2 * num_contours + 2;
366 /* collect all arguments temporarily in an array (in reverse order) */
367 /* so that we can easily split into chunks of 255 args */
368 /* as needed by NPUSHB and NPUSHW, respectively */
369 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
370 if (!args)
371 return NULL;
373 arg = args + num_args - 1;
375 if (num_args > 0xFF)
376 need_words = 1;
378 if (recorder->glyph->num_components)
379 *(arg--) = bci_scale_composite_glyph;
380 else
381 *(arg--) = bci_scale_glyph;
382 *(arg--) = num_contours;
384 start = 0;
385 end = 0;
387 for (p = 0; p < num_contours; p++)
389 FT_Int max = start;
390 FT_Int min = start;
393 end = glyph->outline.contours[p];
395 for (q = start; q <= end; q++)
397 if (points[q].y < points[min].y)
398 min = q;
399 if (points[q].y > points[max].y)
400 max = q;
403 if (min > max)
405 *(arg--) = TA_adjust_point_index(recorder, max);
406 *(arg--) = TA_adjust_point_index(recorder, min);
408 else
410 *(arg--) = TA_adjust_point_index(recorder, min);
411 *(arg--) = TA_adjust_point_index(recorder, max);
414 start = end + 1;
417 if (end > 0xFF)
418 need_words = 1;
420 /* with most fonts it is very rare */
421 /* that any of the pushed arguments is larger than 0xFF, */
422 /* thus we refrain from further optimizing this case */
424 arg = args;
426 if (need_words)
428 for (i = 0; i < num_args; i += 255)
430 nargs = (num_args - i > 255) ? 255 : num_args - i;
432 BCI(NPUSHW);
433 BCI(nargs);
434 for (j = 0; j < nargs; j++)
436 BCI(HIGH(*arg));
437 BCI(LOW(*arg));
438 arg++;
442 else
444 for (i = 0; i < num_args; i += 255)
446 nargs = (num_args - i > 255) ? 255 : num_args - i;
448 BCI(NPUSHB);
449 BCI(nargs);
450 for (j = 0; j < nargs; j++)
452 BCI(*arg);
453 arg++;
458 BCI(CALL);
460 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
461 if (num_stack_elements > sfnt->max_stack_elements)
462 sfnt->max_stack_elements = num_stack_elements;
464 free(args);
466 return bufp;
470 static FT_Byte*
471 TA_font_build_subglyph_shifter(FONT* font,
472 FT_Byte* bufp)
474 FT_Face face = font->loader->face;
475 FT_GlyphSlot glyph = face->glyph;
477 TA_GlyphLoader gloader = font->loader->gloader;
479 TA_SubGlyph subglyphs = gloader->base.subglyphs;
480 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
481 TA_SubGlyph subglyph;
483 FT_Int curr_contour = 0;
486 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
488 FT_Error error;
490 FT_UShort flags = subglyph->flags;
491 FT_Pos y_offset = subglyph->arg2;
493 FT_Int num_contours;
496 /* load subglyph to get the number of contours */
497 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
498 if (error)
499 return NULL;
500 num_contours = glyph->outline.n_contours;
502 /* nothing to do if there is a point-to-point alignment */
503 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
504 goto End;
506 /* nothing to do if y offset is zero */
507 if (!y_offset)
508 goto End;
510 /* nothing to do if there are no contours */
511 if (!num_contours)
512 goto End;
514 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
515 /* ensures that composite subglyphs are represented as simple glyphs */
517 if (num_contours > 0xFF
518 || curr_contour > 0xFF)
520 BCI(PUSHW_2);
521 BCI(HIGH(curr_contour));
522 BCI(LOW(curr_contour));
523 BCI(HIGH(num_contours));
524 BCI(LOW(num_contours));
526 else
528 BCI(PUSHB_2);
529 BCI(curr_contour);
530 BCI(num_contours);
533 /* there are high chances that this value needs PUSHW, */
534 /* thus we handle it separately */
535 if (y_offset > 0xFF || y_offset < 0)
537 BCI(PUSHW_1);
538 BCI(HIGH(y_offset));
539 BCI(LOW(y_offset));
541 else
543 BCI(PUSHB_1);
544 BCI(y_offset);
547 BCI(PUSHB_1);
548 BCI(bci_shift_subglyph);
549 BCI(CALL);
551 End:
552 curr_contour += num_contours;
555 return bufp;
560 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
561 * data in four arrays (which are simple but waste a lot of memory). The
562 * function below converts them into bytecode.
564 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
565 * together with the edge they correspond to.
567 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
568 * loop over the edge or edge pairs, respectively, and each edge or edge
569 * pair contains an inner loop to emit the correponding points.
572 static void
573 TA_build_point_hints(Recorder* recorder,
574 TA_GlyphHints hints)
576 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
577 TA_Segment segments = axis->segments;
578 TA_Edge edges = axis->edges;
580 TA_Edge edge;
581 TA_Edge before;
582 TA_Edge after;
584 FT_Byte* p = recorder->hints_record.buf;
585 FT_UInt num_edges = axis->num_edges;
586 FT_UInt num_strong_points = recorder->num_strong_points;
588 FT_UInt i;
589 FT_UInt j;
590 FT_UInt k;
592 FT_UInt* ip;
593 FT_UInt* iq;
594 FT_UInt* ir;
595 FT_UInt* ip_limit;
596 FT_UInt* iq_limit;
597 FT_UInt* ir_limit;
600 /* we store everything as 16bit numbers; */
601 /* the function numbers (`ta_ip_before', etc.) */
602 /* reflect the order in the TA_Action enumeration */
604 /* ip_before_points */
606 i = 0;
607 ip = recorder->ip_before_points;
608 ip_limit = ip + num_strong_points;
609 for (; ip < ip_limit; ip++)
611 if (*ip != MISSING)
612 i++;
613 else
614 break;
617 if (i)
619 recorder->hints_record.num_actions++;
621 edge = edges;
623 *(p++) = 0;
624 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
625 *(p++) = HIGH(edge->first - segments);
626 *(p++) = LOW(edge->first - segments);
627 *(p++) = HIGH(i);
628 *(p++) = LOW(i);
630 ip = recorder->ip_before_points;
631 ip_limit = ip + i;
632 for (; ip < ip_limit; ip++)
634 FT_UInt point = TA_adjust_point_index(recorder, *ip);
637 *(p++) = HIGH(point);
638 *(p++) = LOW(point);
642 /* ip_after_points */
644 i = 0;
645 ip = recorder->ip_after_points;
646 ip_limit = ip + num_strong_points;
647 for (; ip < ip_limit; ip++)
649 if (*ip != MISSING)
650 i++;
651 else
652 break;
655 if (i)
657 recorder->hints_record.num_actions++;
659 edge = edges + axis->num_edges - 1;
661 *(p++) = 0;
662 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
663 *(p++) = HIGH(edge->first - segments);
664 *(p++) = LOW(edge->first - segments);
665 *(p++) = HIGH(i);
666 *(p++) = LOW(i);
668 ip = recorder->ip_after_points;
669 ip_limit = ip + i;
670 for (; ip < ip_limit; ip++)
672 FT_UInt point = TA_adjust_point_index(recorder, *ip);
675 *(p++) = HIGH(point);
676 *(p++) = LOW(point);
680 /* ip_on_point_array */
682 i = 0;
683 ip = recorder->ip_on_point_array;
684 ip_limit = ip + num_edges * num_strong_points;
685 for (; ip < ip_limit; ip += num_strong_points)
686 if (*ip != MISSING)
687 i++;
689 if (i)
691 recorder->hints_record.num_actions++;
693 *(p++) = 0;
694 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
695 *(p++) = HIGH(i);
696 *(p++) = LOW(i);
698 i = 0;
699 ip = recorder->ip_on_point_array;
700 ip_limit = ip + num_edges * num_strong_points;
701 for (; ip < ip_limit; ip += num_strong_points, i++)
703 if (*ip == MISSING)
704 continue;
706 edge = edges + i;
708 *(p++) = HIGH(edge->first - segments);
709 *(p++) = LOW(edge->first - segments);
711 j = 0;
712 iq = ip;
713 iq_limit = iq + num_strong_points;
714 for (; iq < iq_limit; iq++)
716 if (*iq != MISSING)
717 j++;
718 else
719 break;
722 *(p++) = HIGH(j);
723 *(p++) = LOW(j);
725 iq = ip;
726 iq_limit = iq + j;
727 for (; iq < iq_limit; iq++)
729 FT_UInt point = TA_adjust_point_index(recorder, *iq);
732 *(p++) = HIGH(point);
733 *(p++) = LOW(point);
738 /* ip_between_point_array */
740 i = 0;
741 ip = recorder->ip_between_point_array;
742 ip_limit = ip + num_edges * num_edges * num_strong_points;
743 for (; ip < ip_limit; ip += num_strong_points)
744 if (*ip != MISSING)
745 i++;
747 if (i)
749 recorder->hints_record.num_actions++;
751 *(p++) = 0;
752 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
753 *(p++) = HIGH(i);
754 *(p++) = LOW(i);
756 i = 0;
757 ip = recorder->ip_between_point_array;
758 ip_limit = ip + num_edges * num_edges * num_strong_points;
759 for (;
760 ip < ip_limit;
761 ip += num_edges * num_strong_points, i++)
763 before = edges + i;
765 j = 0;
766 iq = ip;
767 iq_limit = iq + num_edges * num_strong_points;
768 for (; iq < iq_limit; iq += num_strong_points, j++)
770 if (*iq == MISSING)
771 continue;
773 after = edges + j;
775 *(p++) = HIGH(after->first - segments);
776 *(p++) = LOW(after->first - segments);
777 *(p++) = HIGH(before->first - segments);
778 *(p++) = LOW(before->first - segments);
780 k = 0;
781 ir = iq;
782 ir_limit = ir + num_strong_points;
783 for (; ir < ir_limit; ir++)
785 if (*ir != MISSING)
786 k++;
787 else
788 break;
791 *(p++) = HIGH(k);
792 *(p++) = LOW(k);
794 ir = iq;
795 ir_limit = ir + k;
796 for (; ir < ir_limit; ir++)
798 FT_UInt point = TA_adjust_point_index(recorder, *ir);
801 *(p++) = HIGH(point);
802 *(p++) = LOW(point);
808 recorder->hints_record.buf = p;
812 static FT_Bool
813 TA_hints_record_is_different(Hints_Record* hints_records,
814 FT_UInt num_hints_records,
815 FT_Byte* start,
816 FT_Byte* end)
818 Hints_Record last_hints_record;
821 if (!hints_records)
822 return 1;
824 /* we only need to compare with the last hints record */
825 last_hints_record = hints_records[num_hints_records - 1];
827 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
828 return 1;
830 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
831 return 1;
833 return 0;
837 static FT_Error
838 TA_add_hints_record(Hints_Record** hints_records,
839 FT_UInt* num_hints_records,
840 FT_Byte* start,
841 Hints_Record hints_record)
843 Hints_Record* hints_records_new;
844 FT_UInt buf_len;
845 /* at this point, `hints_record.buf' still points into `ins_buf' */
846 FT_Byte* end = hints_record.buf;
849 buf_len = (FT_UInt)(end - start);
851 /* now fill the structure completely */
852 hints_record.buf_len = buf_len;
853 hints_record.buf = (FT_Byte*)malloc(buf_len);
854 if (!hints_record.buf)
855 return FT_Err_Out_Of_Memory;
857 memcpy(hints_record.buf, start, buf_len);
859 (*num_hints_records)++;
860 hints_records_new =
861 (Hints_Record*)realloc(*hints_records, *num_hints_records
862 * sizeof (Hints_Record));
863 if (!hints_records_new)
865 free(hints_record.buf);
866 (*num_hints_records)--;
867 return FT_Err_Out_Of_Memory;
869 else
870 *hints_records = hints_records_new;
872 (*hints_records)[*num_hints_records - 1] = hints_record;
874 return FT_Err_Ok;
878 static FT_Byte*
879 TA_emit_hints_record(Recorder* recorder,
880 Hints_Record* hints_record,
881 FT_Byte* bufp)
883 FT_Byte* p;
884 FT_Byte* endp;
885 FT_Bool need_words = 0;
887 FT_UInt i, j;
888 FT_UInt num_arguments;
889 FT_UInt num_args;
892 /* check whether any argument is larger than 0xFF */
893 endp = hints_record->buf + hints_record->buf_len;
894 for (p = hints_record->buf; p < endp; p += 2)
895 if (*p)
896 need_words = 1;
898 /* with most fonts it is very rare */
899 /* that any of the pushed arguments is larger than 0xFF, */
900 /* thus we refrain from further optimizing this case */
902 num_arguments = hints_record->buf_len / 2;
903 p = endp - 2;
905 if (need_words)
907 for (i = 0; i < num_arguments; i += 255)
909 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
911 BCI(NPUSHW);
912 BCI(num_args);
913 for (j = 0; j < num_args; j++)
915 BCI(*p);
916 BCI(*(p + 1));
917 p -= 2;
921 else
923 /* we only need the lower bytes */
924 p++;
926 for (i = 0; i < num_arguments; i += 255)
928 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
930 BCI(NPUSHB);
931 BCI(num_args);
932 for (j = 0; j < num_args; j++)
934 BCI(*p);
935 p -= 2;
940 /* collect stack depth data */
941 if (num_arguments > recorder->num_stack_elements)
942 recorder->num_stack_elements = num_arguments;
944 return bufp;
948 static FT_Byte*
949 TA_emit_hints_records(Recorder* recorder,
950 Hints_Record* hints_records,
951 FT_UInt num_hints_records,
952 FT_Byte* bufp)
954 FT_UInt i;
955 Hints_Record* hints_record;
958 hints_record = hints_records;
960 for (i = 0; i < num_hints_records - 1; i++)
962 BCI(MPPEM);
963 if (hints_record->size > 0xFF)
965 BCI(PUSHW_1);
966 BCI(HIGH((hints_record + 1)->size));
967 BCI(LOW((hints_record + 1)->size));
969 else
971 BCI(PUSHB_1);
972 BCI((hints_record + 1)->size);
974 BCI(LT);
975 BCI(IF);
976 bufp = TA_emit_hints_record(recorder, hints_record, bufp);
977 BCI(ELSE);
979 hints_record++;
982 bufp = TA_emit_hints_record(recorder, hints_record, bufp);
984 for (i = 0; i < num_hints_records - 1; i++)
985 BCI(EIF);
987 return bufp;
991 static void
992 TA_free_hints_records(Hints_Record* hints_records,
993 FT_UInt num_hints_records)
995 FT_UInt i;
998 for (i = 0; i < num_hints_records; i++)
999 free(hints_records[i].buf);
1001 free(hints_records);
1005 static FT_Byte*
1006 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1007 TA_AxisHints axis,
1008 TA_Edge edge,
1009 FT_UInt* wraps)
1011 TA_Segment segments = axis->segments;
1012 TA_Segment seg;
1013 FT_UInt seg_idx;
1014 FT_UInt num_segs = 0;
1015 FT_UInt* wrap;
1018 seg_idx = edge->first - segments;
1020 /* we store everything as 16bit numbers */
1021 *(bufp++) = HIGH(seg_idx);
1022 *(bufp++) = LOW(seg_idx);
1024 /* wrap-around segments are stored as two segments */
1025 if (edge->first->first > edge->first->last)
1026 num_segs++;
1028 seg = edge->first->edge_next;
1029 while (seg != edge->first)
1031 num_segs++;
1033 if (seg->first > seg->last)
1034 num_segs++;
1036 seg = seg->edge_next;
1039 *(bufp++) = HIGH(num_segs);
1040 *(bufp++) = LOW(num_segs);
1042 if (edge->first->first > edge->first->last)
1044 /* emit second part of wrap-around segment; */
1045 /* the bytecode positions such segments after `normal' ones */
1046 wrap = wraps;
1047 for (;;)
1049 if (seg_idx == *wrap)
1050 break;
1051 wrap++;
1054 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1055 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1058 seg = edge->first->edge_next;
1059 while (seg != edge->first)
1061 seg_idx = seg - segments;
1063 *(bufp++) = HIGH(seg_idx);
1064 *(bufp++) = LOW(seg_idx);
1066 if (seg->first > seg->last)
1068 wrap = wraps;
1069 for (;;)
1071 if (seg_idx == *wrap)
1072 break;
1073 wrap++;
1076 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1077 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1080 seg = seg->edge_next;
1083 return bufp;
1087 static void
1088 TA_hints_recorder(TA_Action action,
1089 TA_GlyphHints hints,
1090 TA_Dimension dim,
1091 void* arg1,
1092 TA_Edge arg2,
1093 TA_Edge arg3,
1094 TA_Edge lower_bound,
1095 TA_Edge upper_bound)
1097 TA_AxisHints axis = &hints->axis[dim];
1098 TA_Edge edges = axis->edges;
1099 TA_Segment segments = axis->segments;
1100 TA_Point points = hints->points;
1102 Recorder* recorder = (Recorder*)hints->user;
1103 FONT* font = recorder->font;
1104 FT_UInt* wraps = recorder->wrap_around_segments;
1105 FT_Byte* p = recorder->hints_record.buf;
1107 FT_UInt* ip;
1108 FT_UInt* limit;
1111 if (dim == TA_DIMENSION_HORZ)
1112 return;
1114 /* we collect point hints for later processing */
1115 switch (action)
1117 case ta_ip_before:
1119 TA_Point point = (TA_Point)arg1;
1122 ip = recorder->ip_before_points;
1123 limit = ip + recorder->num_strong_points;
1124 for (; ip < limit; ip++)
1126 if (*ip == MISSING)
1128 *ip = point - points;
1129 break;
1133 return;
1135 case ta_ip_after:
1137 TA_Point point = (TA_Point)arg1;
1140 ip = recorder->ip_after_points;
1141 limit = ip + recorder->num_strong_points;
1142 for (; ip < limit; ip++)
1144 if (*ip == MISSING)
1146 *ip = point - points;
1147 break;
1151 return;
1153 case ta_ip_on:
1155 TA_Point point = (TA_Point)arg1;
1156 TA_Edge edge = arg2;
1159 ip = recorder->ip_on_point_array
1160 + recorder->num_strong_points
1161 * (edge - edges);
1162 limit = ip + recorder->num_strong_points;
1163 for (; ip < limit; ip++)
1165 if (*ip == MISSING)
1167 *ip = point - points;
1168 break;
1172 return;
1174 case ta_ip_between:
1176 TA_Point point = (TA_Point)arg1;
1177 TA_Edge before = arg2;
1178 TA_Edge after = arg3;
1181 /* note that `recorder->num_segments' has been used for allocation, */
1182 /* but `axis->num_edges' is used for accessing this array */
1183 ip = recorder->ip_between_point_array
1184 + recorder->num_strong_points * axis->num_edges
1185 * (before - edges)
1186 + recorder->num_strong_points
1187 * (after - edges);
1188 limit = ip + recorder->num_strong_points;
1189 for (; ip < limit; ip++)
1191 if (*ip == MISSING)
1193 *ip = point - points;
1194 break;
1198 return;
1200 case ta_bound:
1201 /* we ignore the BOUND action since we signal this information */
1202 /* with the proper function number */
1203 return;
1205 default:
1206 break;
1209 /* some enum values correspond to four or eight bytecode functions; */
1210 /* if the value is n, the function numbers are n, ..., n+7, */
1211 /* to be differentiated with flags */
1213 switch (action)
1215 case ta_link:
1217 TA_Edge base_edge = (TA_Edge)arg1;
1218 TA_Edge stem_edge = arg2;
1221 *(p++) = 0;
1222 *(p++) = (FT_Byte)action + ACTION_OFFSET
1223 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1224 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1226 *(p++) = HIGH(base_edge->first - segments);
1227 *(p++) = LOW(base_edge->first - segments);
1228 *(p++) = HIGH(stem_edge->first - segments);
1229 *(p++) = LOW(stem_edge->first - segments);
1231 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1233 break;
1235 case ta_anchor:
1237 TA_Edge edge = (TA_Edge)arg1;
1238 TA_Edge edge2 = arg2;
1241 *(p++) = 0;
1242 *(p++) = (FT_Byte)action + ACTION_OFFSET
1243 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1244 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1246 *(p++) = HIGH(edge->first - segments);
1247 *(p++) = LOW(edge->first - segments);
1248 *(p++) = HIGH(edge2->first - segments);
1249 *(p++) = LOW(edge2->first - segments);
1251 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1253 break;
1255 case ta_adjust:
1257 TA_Edge edge = (TA_Edge)arg1;
1258 TA_Edge edge2 = arg2;
1259 TA_Edge edge_minus_one = lower_bound;
1262 *(p++) = 0;
1263 *(p++) = (FT_Byte)action + ACTION_OFFSET
1264 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1265 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1266 + 4 * (edge_minus_one != NULL);
1268 *(p++) = HIGH(edge->first - segments);
1269 *(p++) = LOW(edge->first - segments);
1270 *(p++) = HIGH(edge2->first - segments);
1271 *(p++) = LOW(edge2->first - segments);
1273 if (edge_minus_one)
1275 *(p++) = HIGH(edge_minus_one->first - segments);
1276 *(p++) = LOW(edge_minus_one->first - segments);
1279 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1281 break;
1283 case ta_blue_anchor:
1285 TA_Edge edge = (TA_Edge)arg1;
1286 TA_Edge blue = arg2;
1289 *(p++) = 0;
1290 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1292 *(p++) = HIGH(blue->first - segments);
1293 *(p++) = LOW(blue->first - segments);
1295 if (edge->best_blue_is_shoot)
1297 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1298 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1300 else
1302 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1303 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1306 *(p++) = HIGH(edge->first - segments);
1307 *(p++) = LOW(edge->first - segments);
1309 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1311 break;
1313 case ta_stem:
1315 TA_Edge edge = (TA_Edge)arg1;
1316 TA_Edge edge2 = arg2;
1317 TA_Edge edge_minus_one = lower_bound;
1320 *(p++) = 0;
1321 *(p++) = (FT_Byte)action + ACTION_OFFSET
1322 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1323 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1324 + 4 * (edge_minus_one != NULL);
1326 *(p++) = HIGH(edge->first - segments);
1327 *(p++) = LOW(edge->first - segments);
1328 *(p++) = HIGH(edge2->first - segments);
1329 *(p++) = LOW(edge2->first - segments);
1331 if (edge_minus_one)
1333 *(p++) = HIGH(edge_minus_one->first - segments);
1334 *(p++) = LOW(edge_minus_one->first - segments);
1337 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1338 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1340 break;
1342 case ta_blue:
1344 TA_Edge edge = (TA_Edge)arg1;
1347 *(p++) = 0;
1348 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1350 if (edge->best_blue_is_shoot)
1352 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1353 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1355 else
1357 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1358 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1361 *(p++) = HIGH(edge->first - segments);
1362 *(p++) = LOW(edge->first - segments);
1364 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1366 break;
1368 case ta_serif:
1370 TA_Edge serif = (TA_Edge)arg1;
1371 TA_Edge base = serif->serif;
1374 *(p++) = 0;
1375 *(p++) = (FT_Byte)action + ACTION_OFFSET
1376 + (lower_bound != NULL)
1377 + 2 * (upper_bound != NULL);
1379 *(p++) = HIGH(serif->first - segments);
1380 *(p++) = LOW(serif->first - segments);
1381 *(p++) = HIGH(base->first - segments);
1382 *(p++) = LOW(base->first - segments);
1384 if (lower_bound)
1386 *(p++) = HIGH(lower_bound->first - segments);
1387 *(p++) = LOW(lower_bound->first - segments);
1389 if (upper_bound)
1391 *(p++) = HIGH(upper_bound->first - segments);
1392 *(p++) = LOW(upper_bound->first - segments);
1395 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1397 break;
1399 case ta_serif_anchor:
1400 case ta_serif_link2:
1402 TA_Edge edge = (TA_Edge)arg1;
1405 *(p++) = 0;
1406 *(p++) = (FT_Byte)action + ACTION_OFFSET
1407 + (lower_bound != NULL)
1408 + 2 * (upper_bound != NULL);
1410 *(p++) = HIGH(edge->first - segments);
1411 *(p++) = LOW(edge->first - segments);
1413 if (lower_bound)
1415 *(p++) = HIGH(lower_bound->first - segments);
1416 *(p++) = LOW(lower_bound->first - segments);
1418 if (upper_bound)
1420 *(p++) = HIGH(upper_bound->first - segments);
1421 *(p++) = LOW(upper_bound->first - segments);
1424 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1426 break;
1428 case ta_serif_link1:
1430 TA_Edge edge = (TA_Edge)arg1;
1431 TA_Edge before = arg2;
1432 TA_Edge after = arg3;
1435 *(p++) = 0;
1436 *(p++) = (FT_Byte)action + ACTION_OFFSET
1437 + (lower_bound != NULL)
1438 + 2 * (upper_bound != NULL);
1440 *(p++) = HIGH(before->first - segments);
1441 *(p++) = LOW(before->first - segments);
1442 *(p++) = HIGH(edge->first - segments);
1443 *(p++) = LOW(edge->first - segments);
1444 *(p++) = HIGH(after->first - segments);
1445 *(p++) = LOW(after->first - segments);
1447 if (lower_bound)
1449 *(p++) = HIGH(lower_bound->first - segments);
1450 *(p++) = LOW(lower_bound->first - segments);
1452 if (upper_bound)
1454 *(p++) = HIGH(upper_bound->first - segments);
1455 *(p++) = LOW(upper_bound->first - segments);
1458 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1460 break;
1462 default:
1463 /* there are more cases in the enumeration */
1464 /* which are handled with flags */
1465 break;
1468 recorder->hints_record.num_actions++;
1469 recorder->hints_record.buf = p;
1473 static FT_Error
1474 TA_init_recorder(Recorder* recorder,
1475 FONT* font,
1476 GLYPH* glyph,
1477 TA_GlyphHints hints)
1479 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1480 TA_Point points = hints->points;
1481 TA_Point point_limit = points + hints->num_points;
1482 TA_Point point;
1484 TA_Segment segments = axis->segments;
1485 TA_Segment seg_limit = segments + axis->num_segments;
1486 TA_Segment seg;
1488 FT_UInt num_strong_points = 0;
1489 FT_UInt* wrap_around_segment;
1491 recorder->font = font;
1492 recorder->glyph = glyph;
1493 recorder->num_segments = axis->num_segments;
1495 recorder->ip_before_points = NULL;
1496 recorder->ip_after_points = NULL;
1497 recorder->ip_on_point_array = NULL;
1498 recorder->ip_between_point_array = NULL;
1500 recorder->num_stack_elements = 0;
1502 /* no need to clean up allocated arrays in case of error; */
1503 /* this is handled later by `TA_free_recorder' */
1505 recorder->num_wrap_around_segments = 0;
1506 for (seg = segments; seg < seg_limit; seg++)
1507 if (seg->first > seg->last)
1508 recorder->num_wrap_around_segments++;
1510 recorder->wrap_around_segments =
1511 (FT_UInt*)malloc(recorder->num_wrap_around_segments * sizeof (FT_UInt));
1512 if (!recorder->wrap_around_segments)
1513 return FT_Err_Out_Of_Memory;
1515 wrap_around_segment = recorder->wrap_around_segments;
1516 for (seg = segments; seg < seg_limit; seg++)
1517 if (seg->first > seg->last)
1518 *(wrap_around_segment++) = seg - segments;
1520 /* get number of strong points */
1521 for (point = points; point < point_limit; point++)
1523 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1524 /* however, this value isn't known yet */
1525 /* (or rather, it can vary between different pixel sizes) */
1526 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1527 continue;
1529 num_strong_points++;
1532 recorder->num_strong_points = num_strong_points;
1534 recorder->ip_before_points =
1535 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1536 if (!recorder->ip_before_points)
1537 return FT_Err_Out_Of_Memory;
1539 recorder->ip_after_points =
1540 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1541 if (!recorder->ip_after_points)
1542 return FT_Err_Out_Of_Memory;
1544 /* actually, we need `hints->num_edges' for the array sizes; */
1545 /* however, this value isn't known yet */
1546 /* (or rather, it can vary between different pixel sizes) */
1547 recorder->ip_on_point_array =
1548 (FT_UInt*)malloc(axis->num_segments
1549 * num_strong_points * sizeof (FT_UInt));
1550 if (!recorder->ip_on_point_array)
1551 return FT_Err_Out_Of_Memory;
1553 recorder->ip_between_point_array =
1554 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1555 * num_strong_points * sizeof (FT_UInt));
1556 if (!recorder->ip_between_point_array)
1557 return FT_Err_Out_Of_Memory;
1559 return FT_Err_Ok;
1563 static void
1564 TA_reset_recorder(Recorder* recorder,
1565 FT_Byte* bufp)
1567 recorder->hints_record.buf = bufp;
1568 recorder->hints_record.num_actions = 0;
1572 static void
1573 TA_rewind_recorder(Recorder* recorder,
1574 FT_Byte* bufp,
1575 FT_UInt size)
1577 TA_reset_recorder(recorder, bufp);
1579 recorder->hints_record.size = size;
1581 /* We later check with MISSING (which expands to 0xFF bytes) */
1583 memset(recorder->ip_before_points, 0xFF,
1584 recorder->num_strong_points * sizeof (FT_UInt));
1585 memset(recorder->ip_after_points, 0xFF,
1586 recorder->num_strong_points * sizeof (FT_UInt));
1588 memset(recorder->ip_on_point_array, 0xFF,
1589 recorder->num_segments
1590 * recorder->num_strong_points * sizeof (FT_UInt));
1591 memset(recorder->ip_between_point_array, 0xFF,
1592 recorder->num_segments * recorder->num_segments
1593 * recorder->num_strong_points * sizeof (FT_UInt));
1597 static void
1598 TA_free_recorder(Recorder* recorder)
1600 free(recorder->wrap_around_segments);
1602 free(recorder->ip_before_points);
1603 free(recorder->ip_after_points);
1604 free(recorder->ip_on_point_array);
1605 free(recorder->ip_between_point_array);
1609 FT_Error
1610 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1611 FONT* font,
1612 FT_Long idx)
1614 FT_Face face = sfnt->face;
1615 FT_Error error;
1617 FT_Byte* ins_buf;
1618 FT_UInt ins_len;
1619 FT_Byte* bufp;
1620 FT_Byte* p;
1622 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1623 glyf_Data* data = (glyf_Data*)glyf_table->data;
1624 /* `idx' is never negative */
1625 GLYPH* glyph = &data->glyphs[idx];
1627 TA_GlyphHints hints;
1629 FT_UInt num_action_hints_records;
1630 FT_UInt num_point_hints_records;
1631 Hints_Record* action_hints_records;
1632 Hints_Record* point_hints_records;
1634 Recorder recorder;
1635 FT_UInt num_stack_elements;
1637 FT_Int32 load_flags;
1638 FT_UInt size;
1641 /* XXX: right now, we abuse this flag to control */
1642 /* the global behaviour of the auto-hinter */
1643 load_flags = font->fallback_script << 30;
1644 load_flags |= 1 << 28; /* vertical hinting only */
1645 if (font->increase_x_height)
1646 load_flags |= 1 << 29;
1647 if (!font->pre_hinting)
1648 load_flags |= FT_LOAD_NO_SCALE;
1650 /* computing the segments is resolution independent, */
1651 /* thus the pixel size in this call is arbitrary */
1652 error = FT_Set_Pixel_Sizes(face, 20, 20);
1653 if (error)
1654 return error;
1656 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1657 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1658 if (error)
1659 return error;
1661 /* do nothing if we have an empty glyph */
1662 if (!face->glyph->outline.n_contours)
1663 return FT_Err_Ok;
1665 hints = &font->loader->hints;
1667 /* do nothing if the setup delivered the dummy module only */
1668 if (!hints->num_points)
1669 return FT_Err_Ok;
1671 /* we allocate a buffer which is certainly large enough */
1672 /* to hold all of the created bytecode instructions; */
1673 /* later on it gets reallocated to its real size */
1674 ins_len = hints->num_points * 1000;
1675 ins_buf = (FT_Byte*)malloc(ins_len);
1676 if (!ins_buf)
1677 return FT_Err_Out_Of_Memory;
1679 /* initialize array with an invalid bytecode */
1680 /* so that we can easily find the array length at reallocation time */
1681 memset(ins_buf, INS_A0, ins_len);
1683 /* handle composite glyph */
1684 if (font->loader->gloader->base.num_subglyphs)
1686 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1687 if (!bufp)
1689 error = FT_Err_Out_Of_Memory;
1690 goto Err;
1693 goto Done1;
1696 /* only scale the glyph if the dummy hinter has been used */
1697 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1699 /* since `TA_init_recorder' hasn't been called yet, */
1700 /* we manually initialize the `glyph' field */
1701 recorder.glyph = glyph;
1703 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1704 if (!bufp)
1706 error = FT_Err_Out_Of_Memory;
1707 goto Err;
1710 goto Done1;
1713 error = TA_init_recorder(&recorder, font, glyph, hints);
1714 if (error)
1715 goto Err;
1717 /* loop over a large range of pixel sizes */
1718 /* to find hints records which get pushed onto the bytecode stack */
1720 #ifdef DEBUGGING
1722 int num_chars, i;
1725 num_chars = fprintf(stderr, "glyph %ld\n", idx);
1726 for (i = 0; i < num_chars - 1; i++)
1727 putc('=', stderr);
1728 fprintf(stderr, "\n\n");
1731 #endif
1733 /* we temporarily use `ins_buf' to record the current glyph hints */
1734 ta_loader_register_hints_recorder(font->loader,
1735 TA_hints_recorder,
1736 (void*)&recorder);
1738 num_action_hints_records = 0;
1739 num_point_hints_records = 0;
1740 action_hints_records = NULL;
1741 point_hints_records = NULL;
1743 for (size = font->hinting_range_min;
1744 size <= font->hinting_range_max;
1745 size++)
1747 #ifdef DEBUGGING
1748 int have_dumps = 0;
1749 #endif
1752 TA_rewind_recorder(&recorder, ins_buf, size);
1754 error = FT_Set_Pixel_Sizes(face, size, size);
1755 if (error)
1756 goto Err;
1758 /* calling `ta_loader_load_glyph' uses the */
1759 /* `TA_hints_recorder' function as a callback, */
1760 /* modifying `hints_record' */
1761 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1762 if (error)
1763 goto Err;
1765 if (TA_hints_record_is_different(action_hints_records,
1766 num_action_hints_records,
1767 ins_buf, recorder.hints_record.buf))
1769 #ifdef DEBUGGING
1771 have_dumps = 1;
1773 fprintf(stderr, " size %d:\n", size);
1775 ta_glyph_hints_dump_edges(_ta_debug_hints);
1776 ta_glyph_hints_dump_segments(_ta_debug_hints);
1777 ta_glyph_hints_dump_points(_ta_debug_hints);
1779 fprintf(stderr, " action hints record:\n");
1780 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1781 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1782 fprintf(stderr, "\n");
1784 #endif
1786 error = TA_add_hints_record(&action_hints_records,
1787 &num_action_hints_records,
1788 ins_buf, recorder.hints_record);
1789 if (error)
1790 goto Err;
1793 /* now handle point records */
1795 TA_reset_recorder(&recorder, ins_buf);
1797 /* use the point hints data collected in `TA_hints_recorder' */
1798 TA_build_point_hints(&recorder, hints);
1800 if (TA_hints_record_is_different(point_hints_records,
1801 num_point_hints_records,
1802 ins_buf, recorder.hints_record.buf))
1804 #ifdef DEBUGGING
1806 if (!have_dumps)
1808 fprintf(stderr, " size %d:\n", size);
1810 ta_glyph_hints_dump_edges(_ta_debug_hints);
1811 ta_glyph_hints_dump_segments(_ta_debug_hints);
1812 ta_glyph_hints_dump_points(_ta_debug_hints);
1815 fprintf(stderr, " point hints record:\n");
1816 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1817 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1818 fprintf(stderr, "\n");
1820 #endif
1822 error = TA_add_hints_record(&point_hints_records,
1823 &num_point_hints_records,
1824 ins_buf, recorder.hints_record);
1825 if (error)
1826 goto Err;
1830 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1832 /* since we only have a single empty record we just scale the glyph */
1833 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1834 if (!bufp)
1836 error = FT_Err_Out_Of_Memory;
1837 goto Err;
1840 /* clear the rest of the temporarily used part of `ins_buf' */
1841 p = bufp;
1842 while (*p != INS_A0)
1843 *(p++) = INS_A0;
1845 goto Done;
1848 /* store the hints records and handle stack depth */
1849 bufp = TA_emit_hints_records(&recorder,
1850 point_hints_records,
1851 num_point_hints_records,
1852 ins_buf);
1853 num_stack_elements = recorder.num_stack_elements;
1854 recorder.num_stack_elements = 0;
1855 bufp = TA_emit_hints_records(&recorder,
1856 action_hints_records,
1857 num_action_hints_records,
1858 bufp);
1859 recorder.num_stack_elements += num_stack_elements;
1861 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp);
1862 if (!bufp)
1864 error = FT_Err_Out_Of_Memory;
1865 goto Err;
1868 /* clear the rest of the temporarily used part of `ins_buf' */
1869 p = bufp;
1870 while (*p != INS_A0)
1871 *(p++) = INS_A0;
1873 Done:
1874 TA_free_hints_records(action_hints_records, num_action_hints_records);
1875 TA_free_recorder(&recorder);
1877 /* we are done, so reallocate the instruction array to its real size */
1878 if (*bufp == INS_A0)
1880 /* search backwards */
1881 while (*bufp == INS_A0)
1882 bufp--;
1883 bufp++;
1885 else
1887 /* search forwards */
1888 while (*bufp != INS_A0)
1889 bufp++;
1892 Done1:
1893 ins_len = bufp - ins_buf;
1895 if (ins_len > sfnt->max_instructions)
1896 sfnt->max_instructions = ins_len;
1898 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
1899 glyph->ins_len = ins_len;
1901 return FT_Err_Ok;
1903 Err:
1904 TA_free_hints_records(action_hints_records, num_action_hints_records);
1905 TA_free_recorder(&recorder);
1906 free(ins_buf);
1908 return error;
1912 /* end of tabytecode.c */