Don't hint horizontally.
[ttfautohint.git] / lib / tabytecode.c
blob0e41c83e0989305788186b5298465cc8a7fc1400
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 /* see explanations in `TA_sfnt_build_glyph_segments' */
56 FT_UInt* wrap_around_segments;
58 /* data necessary for strong point interpolation */
59 FT_UInt* ip_before_points;
60 FT_UInt* ip_after_points;
61 FT_UInt* ip_on_point_array;
62 FT_UInt* ip_between_point_array;
64 FT_UInt num_strong_points;
65 FT_UInt num_segments;
66 } Recorder;
69 /* We add a subglyph for each composite glyph. */
70 /* Since subglyphs must contain at least one point, */
71 /* we have to adjust all point indices accordingly. */
72 /* Using the `pointsums' array of the `GLYPH' structure */
73 /* it is straightforward to do that: */
74 /* Assuming that point with index x is in the interval */
75 /* pointsums[n] <= x < pointsums[n + 1], */
76 /* the new point index is x + n. */
78 static FT_UInt
79 TA_adjust_point_index(Recorder* recorder,
80 FT_UInt idx)
82 GLYPH* glyph = recorder->glyph;
83 FT_UShort i;
86 if (!glyph->num_components)
87 return idx; /* not a composite glyph */
89 for (i = 0; i < glyph->num_pointsums; i++)
90 if (idx < glyph->pointsums[i])
91 break;
93 return idx + i;
97 /* we store the segments in the storage area; */
98 /* each segment record consists of the first and last point */
100 static FT_Byte*
101 TA_sfnt_build_glyph_segments(SFNT* sfnt,
102 Recorder* recorder,
103 FT_Byte* bufp)
105 FONT* font = recorder->font;
106 TA_GlyphHints hints = &font->loader->hints;
107 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
108 TA_Point points = hints->points;
109 TA_Segment segments = axis->segments;
110 TA_Segment seg;
111 TA_Segment seg_limit;
113 FT_Outline outline = font->loader->gloader->base.outline;
115 FT_UInt* args;
116 FT_UInt* arg;
117 FT_UInt num_args;
118 FT_UInt nargs;
119 FT_UInt num_segments;
121 FT_UInt* wrap_around_segment;
122 FT_UInt num_wrap_around_segments;
124 FT_Bool need_words = 0;
126 FT_Int n;
127 FT_UInt i, j;
128 FT_UInt num_storage;
129 FT_UInt num_stack_elements;
130 FT_UInt num_twilight_points;
133 seg_limit = segments + axis->num_segments;
134 num_segments = axis->num_segments;
136 /* some segments can `wrap around' */
137 /* a contour's start point like 24-25-26-0-1-2 */
138 /* (there can be at most one such segment per contour); */
139 /* we thus append additional records to split them into 24-26 and 0-2 */
140 wrap_around_segment = recorder->wrap_around_segments;
141 for (seg = segments; seg < seg_limit; seg++)
142 if (seg->first > seg->last)
144 /* the stored data is used later for edge linking */
145 *(wrap_around_segment++) = seg - segments;
148 num_wrap_around_segments = wrap_around_segment
149 - recorder->wrap_around_segments;
150 num_segments += num_wrap_around_segments;
152 /* wrap-around segments are pushed with four arguments */
153 num_args = 2 * num_segments + 2 * num_wrap_around_segments + 2;
155 /* collect all arguments temporarily in an array (in reverse order) */
156 /* so that we can easily split into chunks of 255 args */
157 /* as needed by NPUSHB and NPUSHW, respectively */
158 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
159 if (!args)
160 return NULL;
162 arg = args + num_args - 1;
164 if (num_segments > 0xFF)
165 need_words = 1;
167 if (recorder->glyph->num_components)
168 *(arg--) = bci_create_segments_composite;
169 else
170 *(arg--) = bci_create_segments;
171 *(arg--) = num_segments;
173 for (seg = segments; seg < seg_limit; seg++)
175 FT_UInt first = seg->first - points;
176 FT_UInt last = seg->last - points;
179 *(arg--) = TA_adjust_point_index(recorder, first);
180 *(arg--) = TA_adjust_point_index(recorder, last);
182 /* we push the last and first contour point */
183 /* as a third and fourth argument in wrap-around segments */
184 if (first > last)
186 for (n = 0; n < outline.n_contours; n++)
188 FT_UInt end = (FT_UInt)outline.contours[n];
191 if (first <= end)
193 *(arg--) = TA_adjust_point_index(recorder, end);
194 if (end > 0xFF)
195 need_words = 1;
197 if (n == 0)
198 *(arg--) = TA_adjust_point_index(recorder, 0);
199 else
200 *(arg--) = TA_adjust_point_index(recorder,
201 (FT_UInt)outline.contours[n - 1] + 1);
202 break;
207 if (last > 0xFF)
208 need_words = 1;
211 /* emit the second part of wrap-around segments as separate segments */
212 /* so that edges can easily link to them */
213 for (seg = segments; seg < seg_limit; seg++)
215 FT_UInt first = seg->first - points;
216 FT_UInt last = seg->last - points;
219 if (first > last)
221 for (n = 0; n < outline.n_contours; n++)
223 if (first <= (FT_UInt)outline.contours[n])
225 if (n == 0)
226 *(arg--) = TA_adjust_point_index(recorder, 0);
227 else
228 *(arg--) = TA_adjust_point_index(recorder,
229 (FT_UInt)outline.contours[n - 1] + 1);
230 break;
234 *(arg--) = TA_adjust_point_index(recorder, last);
237 /* with most fonts it is very rare */
238 /* that any of the pushed arguments is larger than 0xFF, */
239 /* thus we refrain from further optimizing this case */
241 arg = args;
243 if (need_words)
245 for (i = 0; i < num_args; i += 255)
247 nargs = (num_args - i > 255) ? 255 : num_args - i;
249 BCI(NPUSHW);
250 BCI(nargs);
251 for (j = 0; j < nargs; j++)
253 BCI(HIGH(*arg));
254 BCI(LOW(*arg));
255 arg++;
259 else
261 for (i = 0; i < num_args; i += 255)
263 nargs = (num_args - i > 255) ? 255 : num_args - i;
265 BCI(NPUSHB);
266 BCI(nargs);
267 for (j = 0; j < nargs; j++)
269 BCI(*arg);
270 arg++;
275 BCI(CALL);
277 num_storage = sal_segment_offset + num_segments * 2;
278 if (num_storage > sfnt->max_storage)
279 sfnt->max_storage = num_storage;
281 num_twilight_points = num_segments * 2;
282 if (num_twilight_points > sfnt->max_twilight_points)
283 sfnt->max_twilight_points = num_twilight_points;
285 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
286 if (num_stack_elements > sfnt->max_stack_elements)
287 sfnt->max_stack_elements = num_stack_elements;
289 free(args);
291 return bufp;
295 static FT_Byte*
296 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
297 Recorder* recorder,
298 FT_Byte* bufp)
300 FT_GlyphSlot glyph = sfnt->face->glyph;
301 FT_Vector* points = glyph->outline.points;
302 FT_Int num_contours = glyph->outline.n_contours;
304 FT_UInt* args;
305 FT_UInt* arg;
306 FT_UInt num_args;
307 FT_UInt nargs;
309 FT_Bool need_words = 0;
310 FT_Int p, q;
311 FT_UInt i, j;
312 FT_Int start, end;
313 FT_UInt num_stack_elements;
316 num_args = 2 * num_contours + 2;
318 /* collect all arguments temporarily in an array (in reverse order) */
319 /* so that we can easily split into chunks of 255 args */
320 /* as needed by NPUSHB and NPUSHW, respectively */
321 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
322 if (!args)
323 return NULL;
325 arg = args + num_args - 1;
327 if (num_args > 0xFF)
328 need_words = 1;
330 if (recorder->glyph->num_components)
331 *(arg--) = bci_scale_composite_glyph;
332 else
333 *(arg--) = bci_scale_glyph;
334 *(arg--) = num_contours;
336 start = 0;
337 end = 0;
339 for (p = 0; p < num_contours; p++)
341 FT_Int max = start;
342 FT_Int min = start;
345 end = glyph->outline.contours[p];
347 for (q = start; q <= end; q++)
349 if (points[q].y < points[min].y)
350 min = q;
351 if (points[q].y > points[max].y)
352 max = q;
355 *(arg--) = TA_adjust_point_index(recorder, min);
356 *(arg--) = TA_adjust_point_index(recorder, max);
358 start = end + 1;
361 if (end > 0xFF)
362 need_words = 1;
364 /* with most fonts it is very rare */
365 /* that any of the pushed arguments is larger than 0xFF, */
366 /* thus we refrain from further optimizing this case */
368 arg = args;
370 if (need_words)
372 for (i = 0; i < num_args; i += 255)
374 nargs = (num_args - i > 255) ? 255 : num_args - i;
376 BCI(NPUSHW);
377 BCI(nargs);
378 for (j = 0; j < nargs; j++)
380 BCI(HIGH(*arg));
381 BCI(LOW(*arg));
382 arg++;
386 else
388 for (i = 0; i < num_args; i += 255)
390 nargs = (num_args - i > 255) ? 255 : num_args - i;
392 BCI(NPUSHB);
393 BCI(nargs);
394 for (j = 0; j < nargs; j++)
396 BCI(*arg);
397 arg++;
402 BCI(CALL);
404 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
405 if (num_stack_elements > sfnt->max_stack_elements)
406 sfnt->max_stack_elements = num_stack_elements;
408 free(args);
410 return bufp;
414 static FT_Byte*
415 TA_font_build_subglyph_shifter(FONT* font,
416 FT_Byte* bufp)
418 FT_Face face = font->loader->face;
419 FT_GlyphSlot glyph = face->glyph;
421 TA_GlyphLoader gloader = font->loader->gloader;
423 TA_SubGlyph subglyphs = gloader->base.subglyphs;
424 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
425 TA_SubGlyph subglyph;
427 FT_Int curr_contour = 0;
430 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
432 FT_Error error;
434 FT_UShort flags = subglyph->flags;
435 FT_Pos y_offset = subglyph->arg2;
437 FT_Int num_contours;
440 /* load subglyph to get the number of contours */
441 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
442 if (error)
443 return NULL;
444 num_contours = glyph->outline.n_contours;
446 /* nothing to do if there is a point-to-point alignment */
447 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
448 goto End;
450 /* nothing to do if y offset is zero */
451 if (!y_offset)
452 goto End;
454 /* nothing to do if there are no contours */
455 if (!num_contours)
456 goto End;
458 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
459 /* ensures that composite subglyphs are represented as simple glyphs */
461 if (num_contours > 0xFF
462 || curr_contour > 0xFF)
464 BCI(PUSHW_2);
465 BCI(HIGH(curr_contour));
466 BCI(LOW(curr_contour));
467 BCI(HIGH(num_contours));
468 BCI(LOW(num_contours));
470 else
472 BCI(PUSHB_2);
473 BCI(curr_contour);
474 BCI(num_contours);
477 /* there are high chances that this value needs PUSHW, */
478 /* thus we handle it separately */
479 if (y_offset > 0xFF || y_offset < 0)
481 BCI(PUSHW_1);
482 BCI(HIGH(y_offset));
483 BCI(LOW(y_offset));
485 else
487 BCI(PUSHB_1);
488 BCI(y_offset);
491 BCI(PUSHB_1);
492 BCI(bci_shift_subglyph);
493 BCI(CALL);
495 End:
496 curr_contour += num_contours;
499 return bufp;
504 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
505 * data in four arrays (which are simple but waste a lot of memory). The
506 * function below converts them into bytecode.
508 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
509 * together with the edge they correspond to.
511 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
512 * loop over the edge or edge pairs, respectively, and each edge or edge
513 * pair contains an inner loop to emit the correponding points.
516 static void
517 TA_build_point_hints(Recorder* recorder,
518 TA_GlyphHints hints)
520 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
521 TA_Segment segments = axis->segments;
522 TA_Edge edges = axis->edges;
524 TA_Edge edge;
525 TA_Edge before;
526 TA_Edge after;
528 FT_Byte* p = recorder->hints_record.buf;
529 FT_UInt num_edges = axis->num_edges;
530 FT_UInt num_strong_points = recorder->num_strong_points;
532 FT_UInt i;
533 FT_UInt j;
534 FT_UInt k;
536 FT_UInt* ip;
537 FT_UInt* iq;
538 FT_UInt* ir;
539 FT_UInt* ip_limit;
540 FT_UInt* iq_limit;
541 FT_UInt* ir_limit;
544 /* we store everything as 16bit numbers; */
545 /* the function numbers (`ta_ip_before', etc.) */
546 /* reflect the order in the TA_Action enumeration */
548 /* ip_before_points */
550 i = 0;
551 ip = recorder->ip_before_points;
552 ip_limit = ip + num_strong_points;
553 for (; ip < ip_limit; ip++)
555 if (*ip != MISSING)
556 i++;
557 else
558 break;
561 if (i)
563 recorder->hints_record.num_actions++;
565 edge = edges;
567 *(p++) = 0;
568 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
569 *(p++) = HIGH(edge->first - segments);
570 *(p++) = LOW(edge->first - segments);
571 *(p++) = HIGH(i);
572 *(p++) = LOW(i);
574 ip = recorder->ip_before_points;
575 ip_limit = ip + i;
576 for (; ip < ip_limit; ip++)
578 FT_UInt point = TA_adjust_point_index(recorder, *ip);
581 *(p++) = HIGH(point);
582 *(p++) = LOW(point);
586 /* ip_after_points */
588 i = 0;
589 ip = recorder->ip_after_points;
590 ip_limit = ip + num_strong_points;
591 for (; ip < ip_limit; ip++)
593 if (*ip != MISSING)
594 i++;
595 else
596 break;
599 if (i)
601 recorder->hints_record.num_actions++;
603 edge = edges + axis->num_edges - 1;
605 *(p++) = 0;
606 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
607 *(p++) = HIGH(edge->first - segments);
608 *(p++) = LOW(edge->first - segments);
609 *(p++) = HIGH(i);
610 *(p++) = LOW(i);
612 ip = recorder->ip_after_points;
613 ip_limit = ip + i;
614 for (; ip < ip_limit; ip++)
616 FT_UInt point = TA_adjust_point_index(recorder, *ip);
619 *(p++) = HIGH(point);
620 *(p++) = LOW(point);
624 /* ip_on_point_array */
626 i = 0;
627 ip = recorder->ip_on_point_array;
628 ip_limit = ip + num_edges * num_strong_points;
629 for (; ip < ip_limit; ip += num_strong_points)
630 if (*ip != MISSING)
631 i++;
633 if (i)
635 recorder->hints_record.num_actions++;
637 *(p++) = 0;
638 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
639 *(p++) = HIGH(i);
640 *(p++) = LOW(i);
642 i = 0;
643 ip = recorder->ip_on_point_array;
644 ip_limit = ip + num_edges * num_strong_points;
645 for (; ip < ip_limit; ip += num_strong_points, i++)
647 if (*ip == MISSING)
648 continue;
650 edge = edges + i;
652 *(p++) = HIGH(edge->first - segments);
653 *(p++) = LOW(edge->first - segments);
655 j = 0;
656 iq = ip;
657 iq_limit = iq + num_strong_points;
658 for (; iq < iq_limit; iq++)
660 if (*iq != MISSING)
661 j++;
662 else
663 break;
666 *(p++) = HIGH(j);
667 *(p++) = LOW(j);
669 iq = ip;
670 iq_limit = iq + j;
671 for (; iq < iq_limit; iq++)
673 FT_UInt point = TA_adjust_point_index(recorder, *iq);
676 *(p++) = HIGH(point);
677 *(p++) = LOW(point);
682 /* ip_between_point_array */
684 i = 0;
685 ip = recorder->ip_between_point_array;
686 ip_limit = ip + num_edges * num_edges * num_strong_points;
687 for (; ip < ip_limit; ip += num_strong_points)
688 if (*ip != MISSING)
689 i++;
691 if (i)
693 recorder->hints_record.num_actions++;
695 *(p++) = 0;
696 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
697 *(p++) = HIGH(i);
698 *(p++) = LOW(i);
700 i = 0;
701 ip = recorder->ip_between_point_array;
702 ip_limit = ip + num_edges * num_edges * num_strong_points;
703 for (;
704 ip < ip_limit;
705 ip += num_edges * num_strong_points, i++)
707 before = edges + i;
709 j = 0;
710 iq = ip;
711 iq_limit = iq + num_edges * num_strong_points;
712 for (; iq < iq_limit; iq += num_strong_points, j++)
714 if (*iq == MISSING)
715 continue;
717 after = edges + j;
719 *(p++) = HIGH(after->first - segments);
720 *(p++) = LOW(after->first - segments);
721 *(p++) = HIGH(before->first - segments);
722 *(p++) = LOW(before->first - segments);
724 k = 0;
725 ir = iq;
726 ir_limit = ir + num_strong_points;
727 for (; ir < ir_limit; ir++)
729 if (*ir != MISSING)
730 k++;
731 else
732 break;
735 *(p++) = HIGH(k);
736 *(p++) = LOW(k);
738 ir = iq;
739 ir_limit = ir + k;
740 for (; ir < ir_limit; ir++)
742 FT_UInt point = TA_adjust_point_index(recorder, *ir);
745 *(p++) = HIGH(point);
746 *(p++) = LOW(point);
752 recorder->hints_record.buf = p;
756 static FT_Bool
757 TA_hints_record_is_different(Hints_Record* hints_records,
758 FT_UInt num_hints_records,
759 FT_Byte* start,
760 FT_Byte* end)
762 Hints_Record last_hints_record;
765 if (!hints_records)
766 return 1;
768 /* we only need to compare with the last hints record */
769 last_hints_record = hints_records[num_hints_records - 1];
771 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
772 return 1;
774 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
775 return 1;
777 return 0;
781 static FT_Error
782 TA_add_hints_record(Hints_Record** hints_records,
783 FT_UInt* num_hints_records,
784 FT_Byte* start,
785 Hints_Record hints_record)
787 Hints_Record* hints_records_new;
788 FT_UInt buf_len;
789 /* at this point, `hints_record.buf' still points into `ins_buf' */
790 FT_Byte* end = hints_record.buf;
793 buf_len = (FT_UInt)(end - start);
795 /* now fill the structure completely */
796 hints_record.buf_len = buf_len;
797 hints_record.buf = (FT_Byte*)malloc(buf_len);
798 if (!hints_record.buf)
799 return FT_Err_Out_Of_Memory;
801 memcpy(hints_record.buf, start, buf_len);
803 (*num_hints_records)++;
804 hints_records_new =
805 (Hints_Record*)realloc(*hints_records, *num_hints_records
806 * sizeof (Hints_Record));
807 if (!hints_records_new)
809 free(hints_record.buf);
810 (*num_hints_records)--;
811 return FT_Err_Out_Of_Memory;
813 else
814 *hints_records = hints_records_new;
816 (*hints_records)[*num_hints_records - 1] = hints_record;
818 return FT_Err_Ok;
822 static FT_Byte*
823 TA_sfnt_emit_hints_record(SFNT* sfnt,
824 Hints_Record* hints_record,
825 FT_Byte* bufp)
827 FT_Byte* p;
828 FT_Byte* endp;
829 FT_Bool need_words = 0;
831 FT_UInt i, j;
832 FT_UInt num_arguments;
833 FT_UInt num_args;
834 FT_UInt num_stack_elements;
837 /* check whether any argument is larger than 0xFF */
838 endp = hints_record->buf + hints_record->buf_len;
839 for (p = hints_record->buf; p < endp; p += 2)
840 if (*p)
841 need_words = 1;
843 /* with most fonts it is very rare */
844 /* that any of the pushed arguments is larger than 0xFF, */
845 /* thus we refrain from further optimizing this case */
847 num_arguments = hints_record->buf_len / 2;
848 p = endp - 2;
850 if (need_words)
852 for (i = 0; i < num_arguments; i += 255)
854 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
856 BCI(NPUSHW);
857 BCI(num_args);
858 for (j = 0; j < num_args; j++)
860 BCI(*p);
861 BCI(*(p + 1));
862 p -= 2;
866 else
868 /* we only need the lower bytes */
869 p++;
871 for (i = 0; i < num_arguments; i += 255)
873 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
875 BCI(NPUSHB);
876 BCI(num_args);
877 for (j = 0; j < num_args; j++)
879 BCI(*p);
880 p -= 2;
885 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
886 if (num_stack_elements > sfnt->max_stack_elements)
887 sfnt->max_stack_elements = num_stack_elements;
889 return bufp;
893 static FT_Byte*
894 TA_sfnt_emit_hints_records(SFNT* sfnt,
895 Hints_Record* hints_records,
896 FT_UInt num_hints_records,
897 FT_Byte* bufp)
899 FT_UInt i;
900 Hints_Record* hints_record;
903 hints_record = hints_records;
905 for (i = 0; i < num_hints_records - 1; i++)
907 BCI(MPPEM);
908 if (hints_record->size > 0xFF)
910 BCI(PUSHW_1);
911 BCI(HIGH((hints_record + 1)->size));
912 BCI(LOW((hints_record + 1)->size));
914 else
916 BCI(PUSHB_1);
917 BCI((hints_record + 1)->size);
919 BCI(LT);
920 BCI(IF);
921 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
922 BCI(ELSE);
924 hints_record++;
927 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
929 for (i = 0; i < num_hints_records - 1; i++)
930 BCI(EIF);
932 BCI(PUSHB_1);
933 BCI(bci_hint_glyph);
934 BCI(CALL);
936 return bufp;
940 static void
941 TA_free_hints_records(Hints_Record* hints_records,
942 FT_UInt num_hints_records)
944 FT_UInt i;
947 for (i = 0; i < num_hints_records; i++)
948 free(hints_records[i].buf);
950 free(hints_records);
954 static FT_Byte*
955 TA_hints_recorder_handle_segments(FT_Byte* bufp,
956 TA_AxisHints axis,
957 TA_Edge edge,
958 FT_UInt* wraps)
960 TA_Segment segments = axis->segments;
961 TA_Segment seg;
962 FT_UInt seg_idx;
963 FT_UInt num_segs = 0;
964 FT_UInt* wrap;
967 seg_idx = edge->first - segments;
969 /* we store everything as 16bit numbers */
970 *(bufp++) = HIGH(seg_idx);
971 *(bufp++) = LOW(seg_idx);
973 /* wrap-around segments are stored as two segments */
974 if (edge->first->first > edge->first->last)
975 num_segs++;
977 seg = edge->first->edge_next;
978 while (seg != edge->first)
980 num_segs++;
982 if (seg->first > seg->last)
983 num_segs++;
985 seg = seg->edge_next;
988 *(bufp++) = HIGH(num_segs);
989 *(bufp++) = LOW(num_segs);
991 if (edge->first->first > edge->first->last)
993 /* emit second part of wrap-around segment; */
994 /* the bytecode positions such segments after `normal' ones */
995 wrap = wraps;
996 for (;;)
998 if (seg_idx == *wrap)
999 break;
1000 wrap++;
1003 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1004 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1007 seg = edge->first->edge_next;
1008 while (seg != edge->first)
1010 seg_idx = seg - segments;
1012 *(bufp++) = HIGH(seg_idx);
1013 *(bufp++) = LOW(seg_idx);
1015 if (seg->first > seg->last)
1017 wrap = wraps;
1018 for (;;)
1020 if (seg_idx == *wrap)
1021 break;
1022 wrap++;
1025 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1026 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1029 seg = seg->edge_next;
1032 return bufp;
1036 static void
1037 TA_hints_recorder(TA_Action action,
1038 TA_GlyphHints hints,
1039 TA_Dimension dim,
1040 void* arg1,
1041 TA_Edge arg2,
1042 TA_Edge arg3,
1043 TA_Edge lower_bound,
1044 TA_Edge upper_bound)
1046 TA_AxisHints axis = &hints->axis[dim];
1047 TA_Edge edges = axis->edges;
1048 TA_Segment segments = axis->segments;
1049 TA_Point points = hints->points;
1051 Recorder* recorder = (Recorder*)hints->user;
1052 FONT* font = recorder->font;
1053 FT_UInt* wraps = recorder->wrap_around_segments;
1054 FT_Byte* p = recorder->hints_record.buf;
1056 FT_Byte bound_offset = 0;
1058 FT_UInt* ip;
1059 FT_UInt* limit;
1062 if (dim == TA_DIMENSION_HORZ)
1063 return;
1065 /* we collect point hints for later processing */
1066 switch (action)
1068 case ta_ip_before:
1070 TA_Point point = (TA_Point)arg1;
1073 ip = recorder->ip_before_points;
1074 limit = ip + recorder->num_strong_points;
1075 for (; ip < limit; ip++)
1077 if (*ip == MISSING)
1079 *ip = point - points;
1080 break;
1084 return;
1086 case ta_ip_after:
1088 TA_Point point = (TA_Point)arg1;
1091 ip = recorder->ip_after_points;
1092 limit = ip + recorder->num_strong_points;
1093 for (; ip < limit; ip++)
1095 if (*ip == MISSING)
1097 *ip = point - points;
1098 break;
1102 return;
1104 case ta_ip_on:
1106 TA_Point point = (TA_Point)arg1;
1107 TA_Edge edge = arg2;
1110 ip = recorder->ip_on_point_array
1111 + recorder->num_strong_points
1112 * (edge - edges);
1113 limit = ip + recorder->num_strong_points;
1114 for (; ip < limit; ip++)
1116 if (*ip == MISSING)
1118 *ip = point - points;
1119 break;
1123 return;
1125 case ta_ip_between:
1127 TA_Point point = (TA_Point)arg1;
1128 TA_Edge before = arg2;
1129 TA_Edge after = arg3;
1132 /* note that `recorder->num_segments' has been used for allocation, */
1133 /* but `axis->num_edges' is used for accessing this array */
1134 ip = recorder->ip_between_point_array
1135 + recorder->num_strong_points * axis->num_edges
1136 * (before - edges)
1137 + recorder->num_strong_points
1138 * (after - edges);
1139 limit = ip + recorder->num_strong_points;
1140 for (; ip < limit; ip++)
1142 if (*ip == MISSING)
1144 *ip = point - points;
1145 break;
1149 return;
1151 case ta_bound:
1152 /* we ignore the BOUND action since we signal this information */
1153 /* with the `bound_offset' parameter below */
1154 return;
1156 default:
1157 break;
1160 if (lower_bound)
1161 bound_offset += 1;
1162 if (upper_bound)
1163 bound_offset += 2;
1165 /* this reflects the order in the TA_Action enumeration */
1166 *(p++) = 0;
1167 *(p++) = (FT_Byte)action + bound_offset + ACTION_OFFSET;
1169 switch (action)
1171 case ta_link:
1173 TA_Edge base_edge = (TA_Edge)arg1;
1174 TA_Edge stem_edge = arg2;
1177 *(p++) = 0;
1178 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
1179 *(p++) = 0;
1180 *(p++) = base_edge->flags & TA_EDGE_ROUND;
1181 *(p++) = HIGH(base_edge->first - segments);
1182 *(p++) = LOW(base_edge->first - segments);
1183 *(p++) = HIGH(stem_edge->first - segments);
1184 *(p++) = LOW(stem_edge->first - segments);
1186 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1188 break;
1190 case ta_anchor:
1192 TA_Edge edge = (TA_Edge)arg1;
1193 TA_Edge edge2 = arg2;
1196 *(p++) = 0;
1197 *(p++) = edge2->flags & TA_EDGE_SERIF;
1198 *(p++) = 0;
1199 *(p++) = edge->flags & TA_EDGE_ROUND;
1200 *(p++) = HIGH(edge->first - segments);
1201 *(p++) = LOW(edge->first - segments);
1202 *(p++) = HIGH(edge2->first - segments);
1203 *(p++) = LOW(edge2->first - segments);
1205 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1207 break;
1209 case ta_adjust:
1211 TA_Edge edge = (TA_Edge)arg1;
1212 TA_Edge edge2 = arg2;
1213 TA_Edge edge_minus_one = lower_bound;
1216 *(p++) = 0;
1217 *(p++) = edge2->flags & TA_EDGE_SERIF;
1218 *(p++) = 0;
1219 *(p++) = edge->flags & TA_EDGE_ROUND;
1220 *(p++) = HIGH(edge->first - segments);
1221 *(p++) = LOW(edge->first - segments);
1222 *(p++) = HIGH(edge2->first - segments);
1223 *(p++) = LOW(edge2->first - segments);
1225 if (edge_minus_one)
1227 *(p++) = HIGH(edge_minus_one->first - segments);
1228 *(p++) = LOW(edge_minus_one->first - segments);
1231 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1233 break;
1235 case ta_blue_anchor:
1237 TA_Edge edge = (TA_Edge)arg1;
1238 TA_Edge blue = arg2;
1241 *(p++) = HIGH(blue->first - segments);
1242 *(p++) = LOW(blue->first - segments);
1244 if (edge->best_blue_is_shoot)
1246 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1247 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1249 else
1251 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1252 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1255 *(p++) = HIGH(edge->first - segments);
1256 *(p++) = LOW(edge->first - segments);
1258 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1260 break;
1262 case ta_stem:
1264 TA_Edge edge = (TA_Edge)arg1;
1265 TA_Edge edge2 = arg2;
1266 TA_Edge edge_minus_one = lower_bound;
1269 *(p++) = 0;
1270 *(p++) = edge2->flags & TA_EDGE_SERIF;
1271 *(p++) = 0;
1272 *(p++) = edge->flags & TA_EDGE_ROUND;
1273 *(p++) = HIGH(edge->first - segments);
1274 *(p++) = LOW(edge->first - segments);
1275 *(p++) = HIGH(edge2->first - segments);
1276 *(p++) = LOW(edge2->first - segments);
1278 if (edge_minus_one)
1280 *(p++) = HIGH(edge_minus_one->first - segments);
1281 *(p++) = LOW(edge_minus_one->first - segments);
1284 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1285 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1287 break;
1289 case ta_blue:
1291 TA_Edge edge = (TA_Edge)arg1;
1294 if (edge->best_blue_is_shoot)
1296 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1297 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1299 else
1301 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1302 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1305 *(p++) = HIGH(edge->first - segments);
1306 *(p++) = LOW(edge->first - segments);
1308 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1310 break;
1312 case ta_serif:
1314 TA_Edge serif = (TA_Edge)arg1;
1315 TA_Edge base = serif->serif;
1318 *(p++) = HIGH(serif->first - segments);
1319 *(p++) = LOW(serif->first - segments);
1320 *(p++) = HIGH(base->first - segments);
1321 *(p++) = LOW(base->first - segments);
1323 if (lower_bound)
1325 *(p++) = HIGH(lower_bound->first - segments);
1326 *(p++) = LOW(lower_bound->first - segments);
1328 if (upper_bound)
1330 *(p++) = HIGH(upper_bound->first - segments);
1331 *(p++) = LOW(upper_bound->first - segments);
1334 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1336 break;
1338 case ta_serif_anchor:
1339 case ta_serif_link2:
1341 TA_Edge edge = (TA_Edge)arg1;
1344 *(p++) = HIGH(edge->first - segments);
1345 *(p++) = LOW(edge->first - segments);
1347 if (lower_bound)
1349 *(p++) = HIGH(lower_bound->first - segments);
1350 *(p++) = LOW(lower_bound->first - segments);
1352 if (upper_bound)
1354 *(p++) = HIGH(upper_bound->first - segments);
1355 *(p++) = LOW(upper_bound->first - segments);
1358 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1360 break;
1362 case ta_serif_link1:
1364 TA_Edge edge = (TA_Edge)arg1;
1365 TA_Edge before = arg2;
1366 TA_Edge after = arg3;
1369 *(p++) = HIGH(before->first - segments);
1370 *(p++) = LOW(before->first - segments);
1371 *(p++) = HIGH(edge->first - segments);
1372 *(p++) = LOW(edge->first - segments);
1373 *(p++) = HIGH(after->first - segments);
1374 *(p++) = LOW(after->first - segments);
1376 if (lower_bound)
1378 *(p++) = HIGH(lower_bound->first - segments);
1379 *(p++) = LOW(lower_bound->first - segments);
1381 if (upper_bound)
1383 *(p++) = HIGH(upper_bound->first - segments);
1384 *(p++) = LOW(upper_bound->first - segments);
1387 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1389 break;
1391 default:
1392 /* there are more cases in the enumeration */
1393 /* which are handled with the `bound_offset' parameter */
1394 break;
1397 recorder->hints_record.num_actions++;
1398 recorder->hints_record.buf = p;
1402 static FT_Error
1403 TA_init_recorder(Recorder* recorder,
1404 FT_UInt wrap_around_size,
1405 FONT* font,
1406 GLYPH* glyph,
1407 TA_GlyphHints hints)
1409 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1410 TA_Point points = hints->points;
1411 TA_Point point_limit = points + hints->num_points;
1412 TA_Point point;
1414 FT_UInt num_strong_points = 0;
1417 recorder->font = font;
1418 recorder->glyph = glyph;
1419 recorder->num_segments = axis->num_segments;
1421 recorder->ip_before_points = NULL;
1422 recorder->ip_after_points = NULL;
1423 recorder->ip_on_point_array = NULL;
1424 recorder->ip_between_point_array = NULL;
1426 /* no need to clean up allocated arrays in case of error; */
1427 /* this is handled later by `TA_free_recorder' */
1429 recorder->wrap_around_segments =
1430 (FT_UInt*)malloc(wrap_around_size * sizeof (FT_UInt));
1431 if (!recorder->wrap_around_segments)
1432 return FT_Err_Out_Of_Memory;
1434 /* get number of strong points */
1435 for (point = points; point < point_limit; point++)
1437 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1438 /* however, this value isn't known yet */
1439 /* (or rather, it can vary between different pixel sizes) */
1440 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1441 continue;
1443 num_strong_points++;
1446 recorder->num_strong_points = num_strong_points;
1448 recorder->ip_before_points =
1449 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1450 if (!recorder->ip_before_points)
1451 return FT_Err_Out_Of_Memory;
1453 recorder->ip_after_points =
1454 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1455 if (!recorder->ip_after_points)
1456 return FT_Err_Out_Of_Memory;
1458 /* actually, we need `hints->num_edges' for the array sizes; */
1459 /* however, this value isn't known yet */
1460 /* (or rather, it can vary between different pixel sizes) */
1461 recorder->ip_on_point_array =
1462 (FT_UInt*)malloc(axis->num_segments
1463 * num_strong_points * sizeof (FT_UInt));
1464 if (!recorder->ip_on_point_array)
1465 return FT_Err_Out_Of_Memory;
1467 recorder->ip_between_point_array =
1468 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1469 * num_strong_points * sizeof (FT_UInt));
1470 if (!recorder->ip_between_point_array)
1471 return FT_Err_Out_Of_Memory;
1473 return FT_Err_Ok;
1477 static void
1478 TA_rewind_recorder(Recorder* recorder,
1479 FT_Byte* bufp,
1480 FT_UInt size)
1482 recorder->hints_record.buf = bufp + 2;
1483 recorder->hints_record.num_actions = 0;
1484 recorder->hints_record.size = size;
1486 /* We later check with MISSING (which expands to 0xFF bytes) */
1488 memset(recorder->ip_before_points, 0xFF,
1489 recorder->num_strong_points * sizeof (FT_UInt));
1490 memset(recorder->ip_after_points, 0xFF,
1491 recorder->num_strong_points * sizeof (FT_UInt));
1493 memset(recorder->ip_on_point_array, 0xFF,
1494 recorder->num_segments
1495 * recorder->num_strong_points * sizeof (FT_UInt));
1496 memset(recorder->ip_between_point_array, 0xFF,
1497 recorder->num_segments * recorder->num_segments
1498 * recorder->num_strong_points * sizeof (FT_UInt));
1503 static void
1504 TA_free_recorder(Recorder* recorder)
1506 free(recorder->wrap_around_segments);
1508 free(recorder->ip_before_points);
1509 free(recorder->ip_after_points);
1510 free(recorder->ip_on_point_array);
1511 free(recorder->ip_between_point_array);
1515 FT_Error
1516 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1517 FONT* font,
1518 FT_Long idx)
1520 FT_Face face = sfnt->face;
1521 FT_Error error;
1523 FT_Byte* ins_buf;
1524 FT_UInt ins_len;
1525 FT_Byte* bufp;
1526 FT_Byte* p;
1528 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1529 glyf_Data* data = (glyf_Data*)glyf_table->data;
1530 /* `idx' is never negative */
1531 GLYPH* glyph = &data->glyphs[idx];
1533 TA_GlyphHints hints;
1535 FT_UInt num_hints_records;
1536 Hints_Record* hints_records;
1538 Recorder recorder;
1540 FT_Int32 load_flags;
1541 FT_UInt size;
1544 /* XXX: right now, we abuse this flag to control */
1545 /* the global behaviour of the auto-hinter */
1546 load_flags = font->fallback_script << 30;
1547 load_flags |= 1 << 28; /* vertical hinting only */
1548 if (font->increase_x_height)
1549 load_flags |= 1 << 29;
1550 if (!font->pre_hinting)
1551 load_flags |= FT_LOAD_NO_SCALE;
1553 /* computing the segments is resolution independent, */
1554 /* thus the pixel size in this call is arbitrary */
1555 error = FT_Set_Pixel_Sizes(face, 20, 20);
1556 if (error)
1557 return error;
1559 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1560 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1561 if (error)
1562 return error;
1564 /* do nothing if we have an empty glyph */
1565 if (!face->glyph->outline.n_contours)
1566 return FT_Err_Ok;
1568 hints = &font->loader->hints;
1570 /* do nothing if the setup delivered the dummy module only */
1571 if (!hints->num_points)
1572 return FT_Err_Ok;
1574 /* we allocate a buffer which is certainly large enough */
1575 /* to hold all of the created bytecode instructions; */
1576 /* later on it gets reallocated to its real size */
1577 ins_len = hints->num_points * 1000;
1578 ins_buf = (FT_Byte*)malloc(ins_len);
1579 if (!ins_buf)
1580 return FT_Err_Out_Of_Memory;
1582 /* initialize array with an invalid bytecode */
1583 /* so that we can easily find the array length at reallocation time */
1584 memset(ins_buf, INS_A0, ins_len);
1586 num_hints_records = 0;
1587 hints_records = NULL;
1589 /* handle composite glyph */
1590 if (font->loader->gloader->base.num_subglyphs)
1592 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1593 if (!bufp)
1595 error = FT_Err_Out_Of_Memory;
1596 goto Err;
1599 goto Done1;
1602 /* only scale the glyph if the dummy hinter has been used */
1603 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1605 /* since `TA_init_recorder' hasn't been called yet, */
1606 /* we manually initialize the `glyph' field */
1607 recorder.glyph = glyph;
1609 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1610 if (!bufp)
1612 error = FT_Err_Out_Of_Memory;
1613 goto Err;
1616 goto Done1;
1619 error = TA_init_recorder(&recorder, face->glyph->outline.n_contours,
1620 font, glyph, hints);
1621 if (error)
1622 goto Err;
1624 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, ins_buf);
1625 if (!bufp)
1627 error = FT_Err_Out_Of_Memory;
1628 goto Err;
1631 /* now we loop over a large range of pixel sizes */
1632 /* to find hints records which get pushed onto the bytecode stack */
1634 #ifdef DEBUGGING
1636 int num_chars, i;
1639 num_chars = fprintf(stderr, "glyph %ld\n", idx);
1640 for (i = 0; i < num_chars - 1; i++)
1641 putc('=', stderr);
1642 fprintf(stderr, "\n\n");
1645 #endif
1647 /* we temporarily use `ins_buf' to record the current glyph hints, */
1648 /* leaving two bytes at the beginning so that the number of actions */
1649 /* can be inserted later on */
1650 ta_loader_register_hints_recorder(font->loader,
1651 TA_hints_recorder,
1652 (void*)&recorder);
1654 for (size = font->hinting_range_min;
1655 size <= font->hinting_range_max;
1656 size++)
1658 TA_rewind_recorder(&recorder, bufp, size);
1660 error = FT_Set_Pixel_Sizes(face, size, size);
1661 if (error)
1662 goto Err;
1664 /* calling `ta_loader_load_glyph' uses the */
1665 /* `TA_hints_recorder' function as a callback, */
1666 /* modifying `hints_record' */
1667 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1668 if (error)
1669 goto Err;
1671 /* append the point hints data collected in `TA_hints_recorder' */
1672 TA_build_point_hints(&recorder, hints);
1674 /* store the number of actions in `ins_buf' */
1675 *bufp = HIGH(recorder.hints_record.num_actions);
1676 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
1678 if (TA_hints_record_is_different(hints_records,
1679 num_hints_records,
1680 bufp, recorder.hints_record.buf))
1682 #ifdef DEBUGGING
1684 fprintf(stderr, " size %d:\n", size);
1686 ta_glyph_hints_dump_edges(_ta_debug_hints);
1687 ta_glyph_hints_dump_segments(_ta_debug_hints);
1688 ta_glyph_hints_dump_points(_ta_debug_hints);
1690 fprintf(stderr, " hints record:\n");
1691 for (p = bufp; p < recorder.hints_record.buf; p += 2)
1692 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1693 fprintf(stderr, "\n");
1695 #endif
1697 error = TA_add_hints_record(&hints_records,
1698 &num_hints_records,
1699 bufp, recorder.hints_record);
1700 if (error)
1701 goto Err;
1705 if (num_hints_records == 1 && !hints_records[0].num_actions)
1707 /* since we only have a single empty record we just scale the glyph, */
1708 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1709 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1710 if (!bufp)
1712 error = FT_Err_Out_Of_Memory;
1713 goto Err;
1716 /* clear the rest of the temporarily used part of `ins_buf' */
1717 p = bufp;
1718 while (*p != INS_A0)
1719 *(p++) = INS_A0;
1721 goto Done;
1724 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1725 /* is shorter than the previously stored data, */
1726 /* so clear the rest of the temporarily used part of `ins_buf' */
1727 /* before appending the hints records */
1728 p = bufp;
1729 while (*p != INS_A0)
1730 *(p++) = INS_A0;
1732 bufp = TA_sfnt_emit_hints_records(sfnt,
1733 hints_records, num_hints_records,
1734 bufp);
1736 Done:
1737 TA_free_hints_records(hints_records, num_hints_records);
1738 TA_free_recorder(&recorder);
1740 /* we are done, so reallocate the instruction array to its real size */
1741 if (*bufp == INS_A0)
1743 /* search backwards */
1744 while (*bufp == INS_A0)
1745 bufp--;
1746 bufp++;
1748 else
1750 /* search forwards */
1751 while (*bufp != INS_A0)
1752 bufp++;
1755 Done1:
1756 ins_len = bufp - ins_buf;
1758 if (ins_len > sfnt->max_instructions)
1759 sfnt->max_instructions = ins_len;
1761 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
1762 glyph->ins_len = ins_len;
1764 return FT_Err_Ok;
1766 Err:
1767 TA_free_hints_records(hints_records, num_hints_records);
1768 TA_free_recorder(&recorder);
1769 free(ins_buf);
1771 return error;
1775 /* end of tabytecode.c */