Synchronize with FreeType.
[ttfautohint.git] / lib / tabytecode.c
blob547d5a2794c2d2bced8dd49b46c538bc331e5e25
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"
17 #include <string.h>
20 #undef MISSING
21 #define MISSING (FT_UInt)~0
23 /* a simple macro to emit bytecode instructions */
24 #define BCI(code) *(bufp++) = (code)
26 /* we increase the stack depth by this amount */
27 #define ADDITIONAL_STACK_ELEMENTS 20
30 #define DEBUGGING
33 #ifdef TA_DEBUG
34 int _ta_debug = 0;
35 int _ta_debug_disable_horz_hints;
36 int _ta_debug_disable_vert_hints;
37 int _ta_debug_disable_blue_hints;
38 void* _ta_debug_hints;
39 #endif
42 typedef struct Hints_Record_
44 FT_UInt size;
45 FT_UInt num_actions;
46 FT_Byte* buf;
47 FT_UInt buf_len;
48 } Hints_Record;
50 typedef struct Recorder_
52 FONT* font;
53 GLYPH* glyph; /* the current glyph */
54 Hints_Record hints_record;
56 /* some segments can `wrap around' */
57 /* a contour's start point like 24-25-26-0-1-2 */
58 /* (there can be at most one such segment per contour); */
59 /* later on we append additional records */
60 /* to split them into 24-26 and 0-2 */
61 FT_UInt* wrap_around_segments;
62 FT_UInt num_wrap_around_segments;
64 FT_UShort num_stack_elements; /* the necessary stack depth so far */
66 /* data necessary for strong point interpolation */
67 FT_UInt* ip_before_points;
68 FT_UInt* ip_after_points;
69 FT_UInt* ip_on_point_array;
70 FT_UInt* ip_between_point_array;
72 FT_UInt num_strong_points;
73 FT_UInt num_segments;
74 } Recorder;
77 /* We add a subglyph for each composite glyph. */
78 /* Since subglyphs must contain at least one point, */
79 /* we have to adjust all point indices accordingly. */
80 /* Using the `pointsums' array of the `GLYPH' structure */
81 /* it is straightforward to do that: */
82 /* Assuming that point with index x is in the interval */
83 /* pointsums[n] <= x < pointsums[n + 1], */
84 /* the new point index is x + n. */
86 static FT_UInt
87 TA_adjust_point_index(Recorder* recorder,
88 FT_UInt idx)
90 FONT* font = recorder->font;
91 GLYPH* glyph = recorder->glyph;
92 FT_UShort i;
95 if (!glyph->num_components || !font->hint_with_components)
96 return idx; /* not a composite glyph */
98 for (i = 0; i < glyph->num_pointsums; i++)
99 if (idx < glyph->pointsums[i])
100 break;
102 return idx + i;
106 /* we store the segments in the storage area; */
107 /* each segment record consists of the first and last point */
109 static FT_Byte*
110 TA_sfnt_build_glyph_segments(SFNT* sfnt,
111 Recorder* recorder,
112 FT_Byte* bufp,
113 FT_Bool optimize)
115 FONT* font = recorder->font;
116 TA_GlyphHints hints = &font->loader->hints;
117 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
118 TA_Point points = hints->points;
119 TA_Segment segments = axis->segments;
120 TA_Segment seg;
121 TA_Segment seg_limit;
123 FT_Outline outline = font->loader->gloader->base.outline;
125 FT_UInt* args;
126 FT_UInt* arg;
127 FT_UInt num_args;
128 FT_UInt nargs;
129 FT_UInt num_segments;
131 FT_Bool need_words = 0;
133 FT_Int n;
134 FT_UInt i, j;
135 FT_UInt base;
136 FT_UInt num_packed_segments;
137 FT_UInt num_storage;
138 FT_UInt num_stack_elements;
139 FT_UInt num_twilight_points;
142 seg_limit = segments + axis->num_segments;
143 num_segments = axis->num_segments;
145 /* to pack the data in the bytecode more tightly, */
146 /* we store up to the first nine segments in nibbles if possible, */
147 /* using delta values */
148 base = 0;
149 num_packed_segments = 0;
150 for (seg = segments; seg < seg_limit; seg++)
152 FT_UInt first = seg->first - points;
153 FT_UInt last = seg->last - points;
156 first = TA_adjust_point_index(recorder, first);
157 last = TA_adjust_point_index(recorder, last);
159 if (first - base >= 16)
160 break;
161 if (first > last || last - first >= 16)
162 break;
163 if (num_packed_segments == 9)
164 break;
165 num_packed_segments++;
166 base = last;
169 /* also handle wrap-around segments */
170 num_segments += recorder->num_wrap_around_segments;
172 /* wrap-around segments are pushed with four arguments; */
173 /* a segment stored in nibbles needs only one byte instead of two */
174 num_args = num_packed_segments
175 + 2 * (num_segments - num_packed_segments)
176 + 2 * recorder->num_wrap_around_segments
177 + 2;
179 /* collect all arguments temporarily in an array (in reverse order) */
180 /* so that we can easily split into chunks of 255 args */
181 /* as needed by NPUSHB and NPUSHW, respectively */
182 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
183 if (!args)
184 return NULL;
186 arg = args + num_args - 1;
188 if (num_segments > 0xFF)
189 need_words = 1;
191 /* the number of packed segments is indicated by the function number */
192 if (recorder->glyph->num_components && font->hint_with_components)
193 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
194 else
195 *(arg--) = bci_create_segments_0 + num_packed_segments;
196 *(arg--) = num_segments;
198 base = 0;
199 for (seg = segments; seg < segments + num_packed_segments; seg++)
201 FT_UInt first = seg->first - points;
202 FT_UInt last = seg->last - points;
203 FT_UInt low_nibble;
204 FT_UInt high_nibble;
207 first = TA_adjust_point_index(recorder, first);
208 last = TA_adjust_point_index(recorder, last);
210 low_nibble = first - base;
211 high_nibble = last - first;
213 *(arg--) = 16 * high_nibble + low_nibble;
215 base = last;
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;
295 if (optimize && nargs <= 8)
296 BCI(PUSHW_1 - 1 + nargs);
297 else
299 BCI(NPUSHW);
300 BCI(nargs);
302 for (j = 0; j < nargs; j++)
304 BCI(HIGH(*arg));
305 BCI(LOW(*arg));
306 arg++;
310 else
312 for (i = 0; i < num_args; i += 255)
314 nargs = (num_args - i > 255) ? 255 : num_args - i;
316 if (optimize && nargs <= 8)
317 BCI(PUSHB_1 - 1 + nargs);
318 else
320 BCI(NPUSHB);
321 BCI(nargs);
323 for (j = 0; j < nargs; j++)
325 BCI(*arg);
326 arg++;
331 BCI(CALL);
333 num_storage = sal_segment_offset + num_segments * 2;
334 if (num_storage > sfnt->max_storage)
335 sfnt->max_storage = num_storage;
337 num_twilight_points = num_segments * 2;
338 if (num_twilight_points > sfnt->max_twilight_points)
339 sfnt->max_twilight_points = num_twilight_points;
341 /* both this function and `TA_emit_hints_record' */
342 /* push data onto the stack */
343 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
344 + recorder->num_stack_elements + num_args;
345 if (num_stack_elements > sfnt->max_stack_elements)
346 sfnt->max_stack_elements = num_stack_elements;
348 free(args);
350 return bufp;
354 static FT_Byte*
355 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
356 Recorder* recorder,
357 FT_Byte* bufp)
359 FONT* font = recorder->font;
360 FT_GlyphSlot glyph = sfnt->face->glyph;
361 FT_Vector* points = glyph->outline.points;
362 FT_Int num_contours = glyph->outline.n_contours;
364 FT_UInt* args;
365 FT_UInt* arg;
366 FT_UInt num_args;
367 FT_UInt nargs;
369 FT_Bool need_words = 0;
370 FT_Int p, q;
371 FT_UInt i, j;
372 FT_Int start, end;
373 FT_UInt num_stack_elements;
376 num_args = 2 * num_contours + 2;
378 /* collect all arguments temporarily in an array (in reverse order) */
379 /* so that we can easily split into chunks of 255 args */
380 /* as needed by NPUSHB and NPUSHW, respectively */
381 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
382 if (!args)
383 return NULL;
385 arg = args + num_args - 1;
387 if (num_args > 0xFF)
388 need_words = 1;
390 if (recorder->glyph->num_components && font->hint_with_components)
391 *(arg--) = bci_scale_composite_glyph;
392 else
393 *(arg--) = bci_scale_glyph;
394 *(arg--) = num_contours;
396 start = 0;
397 end = 0;
399 for (p = 0; p < num_contours; p++)
401 FT_Int max = start;
402 FT_Int min = start;
405 end = glyph->outline.contours[p];
407 for (q = start; q <= end; q++)
409 if (points[q].y < points[min].y)
410 min = q;
411 if (points[q].y > points[max].y)
412 max = q;
415 if (min > max)
417 *(arg--) = TA_adjust_point_index(recorder, max);
418 *(arg--) = TA_adjust_point_index(recorder, min);
420 else
422 *(arg--) = TA_adjust_point_index(recorder, min);
423 *(arg--) = TA_adjust_point_index(recorder, max);
426 start = end + 1;
429 if (end > 0xFF)
430 need_words = 1;
432 /* with most fonts it is very rare */
433 /* that any of the pushed arguments is larger than 0xFF, */
434 /* thus we refrain from further optimizing this case */
436 arg = args;
438 if (need_words)
440 for (i = 0; i < num_args; i += 255)
442 nargs = (num_args - i > 255) ? 255 : num_args - i;
444 if (nargs <= 8)
445 BCI(PUSHW_1 - 1 + nargs);
446 else
448 BCI(NPUSHW);
449 BCI(nargs);
451 for (j = 0; j < nargs; j++)
453 BCI(HIGH(*arg));
454 BCI(LOW(*arg));
455 arg++;
459 else
461 for (i = 0; i < num_args; i += 255)
463 nargs = (num_args - i > 255) ? 255 : num_args - i;
465 if (nargs <= 8)
466 BCI(PUSHB_1 - 1 + nargs);
467 else
469 BCI(NPUSHB);
470 BCI(nargs);
472 for (j = 0; j < nargs; j++)
474 BCI(*arg);
475 arg++;
480 BCI(CALL);
482 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
483 if (num_stack_elements > sfnt->max_stack_elements)
484 sfnt->max_stack_elements = num_stack_elements;
486 free(args);
488 return bufp;
492 static FT_Byte*
493 TA_font_build_subglyph_shifter(FONT* font,
494 FT_Byte* bufp)
496 FT_Face face = font->loader->face;
497 FT_GlyphSlot glyph = face->glyph;
499 TA_GlyphLoader gloader = font->loader->gloader;
501 TA_SubGlyph subglyphs = gloader->base.subglyphs;
502 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
503 TA_SubGlyph subglyph;
505 FT_Int curr_contour = 0;
508 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
510 FT_Error error;
512 FT_UShort flags = subglyph->flags;
513 FT_Pos y_offset = subglyph->arg2;
515 FT_Int num_contours;
518 /* load subglyph to get the number of contours */
519 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
520 if (error)
521 return NULL;
522 num_contours = glyph->outline.n_contours;
524 /* nothing to do if there is a point-to-point alignment */
525 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
526 goto End;
528 /* nothing to do if y offset is zero */
529 if (!y_offset)
530 goto End;
532 /* nothing to do if there are no contours */
533 if (!num_contours)
534 goto End;
536 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
537 /* ensures that composite subglyphs are represented as simple glyphs */
539 if (num_contours > 0xFF
540 || curr_contour > 0xFF)
542 BCI(PUSHW_2);
543 BCI(HIGH(curr_contour));
544 BCI(LOW(curr_contour));
545 BCI(HIGH(num_contours));
546 BCI(LOW(num_contours));
548 else
550 BCI(PUSHB_2);
551 BCI(curr_contour);
552 BCI(num_contours);
555 /* there are high chances that this value needs PUSHW, */
556 /* thus we handle it separately */
557 if (y_offset > 0xFF || y_offset < 0)
559 BCI(PUSHW_1);
560 BCI(HIGH(y_offset));
561 BCI(LOW(y_offset));
563 else
565 BCI(PUSHB_1);
566 BCI(y_offset);
569 BCI(PUSHB_1);
570 BCI(bci_shift_subglyph);
571 BCI(CALL);
573 End:
574 curr_contour += num_contours;
577 return bufp;
582 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
583 * data in four arrays (which are simple but waste a lot of memory). The
584 * function below converts them into bytecode.
586 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
587 * together with the edge they correspond to.
589 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
590 * loop over the edge or edge pairs, respectively, and each edge or edge
591 * pair contains an inner loop to emit the correponding points.
594 static void
595 TA_build_point_hints(Recorder* recorder,
596 TA_GlyphHints hints)
598 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
599 TA_Segment segments = axis->segments;
600 TA_Edge edges = axis->edges;
602 TA_Edge edge;
603 TA_Edge before;
604 TA_Edge after;
606 FT_Byte* p = recorder->hints_record.buf;
607 FT_UInt num_edges = axis->num_edges;
608 FT_UInt num_strong_points = recorder->num_strong_points;
610 FT_UInt i;
611 FT_UInt j;
612 FT_UInt k;
614 FT_UInt* ip;
615 FT_UInt* iq;
616 FT_UInt* ir;
617 FT_UInt* ip_limit;
618 FT_UInt* iq_limit;
619 FT_UInt* ir_limit;
622 /* we store everything as 16bit numbers; */
623 /* the function numbers (`ta_ip_before', etc.) */
624 /* reflect the order in the TA_Action enumeration */
626 /* ip_before_points */
628 i = 0;
629 ip = recorder->ip_before_points;
630 ip_limit = ip + num_strong_points;
631 for (; ip < ip_limit; ip++)
633 if (*ip != MISSING)
634 i++;
635 else
636 break;
639 if (i)
641 recorder->hints_record.num_actions++;
643 edge = edges;
645 *(p++) = 0;
646 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
647 *(p++) = HIGH(edge->first - segments);
648 *(p++) = LOW(edge->first - segments);
649 *(p++) = HIGH(i);
650 *(p++) = LOW(i);
652 ip = recorder->ip_before_points;
653 ip_limit = ip + i;
654 for (; ip < ip_limit; ip++)
656 FT_UInt point = TA_adjust_point_index(recorder, *ip);
659 *(p++) = HIGH(point);
660 *(p++) = LOW(point);
664 /* ip_after_points */
666 i = 0;
667 ip = recorder->ip_after_points;
668 ip_limit = ip + num_strong_points;
669 for (; ip < ip_limit; ip++)
671 if (*ip != MISSING)
672 i++;
673 else
674 break;
677 if (i)
679 recorder->hints_record.num_actions++;
681 edge = edges + axis->num_edges - 1;
683 *(p++) = 0;
684 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
685 *(p++) = HIGH(edge->first - segments);
686 *(p++) = LOW(edge->first - segments);
687 *(p++) = HIGH(i);
688 *(p++) = LOW(i);
690 ip = recorder->ip_after_points;
691 ip_limit = ip + i;
692 for (; ip < ip_limit; ip++)
694 FT_UInt point = TA_adjust_point_index(recorder, *ip);
697 *(p++) = HIGH(point);
698 *(p++) = LOW(point);
702 /* ip_on_point_array */
704 i = 0;
705 ip = recorder->ip_on_point_array;
706 ip_limit = ip + num_edges * num_strong_points;
707 for (; ip < ip_limit; ip += num_strong_points)
708 if (*ip != MISSING)
709 i++;
711 if (i)
713 recorder->hints_record.num_actions++;
715 *(p++) = 0;
716 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
717 *(p++) = HIGH(i);
718 *(p++) = LOW(i);
720 i = 0;
721 ip = recorder->ip_on_point_array;
722 ip_limit = ip + num_edges * num_strong_points;
723 for (; ip < ip_limit; ip += num_strong_points, i++)
725 if (*ip == MISSING)
726 continue;
728 edge = edges + i;
730 *(p++) = HIGH(edge->first - segments);
731 *(p++) = LOW(edge->first - segments);
733 j = 0;
734 iq = ip;
735 iq_limit = iq + num_strong_points;
736 for (; iq < iq_limit; iq++)
738 if (*iq != MISSING)
739 j++;
740 else
741 break;
744 *(p++) = HIGH(j);
745 *(p++) = LOW(j);
747 iq = ip;
748 iq_limit = iq + j;
749 for (; iq < iq_limit; iq++)
751 FT_UInt point = TA_adjust_point_index(recorder, *iq);
754 *(p++) = HIGH(point);
755 *(p++) = LOW(point);
760 /* ip_between_point_array */
762 i = 0;
763 ip = recorder->ip_between_point_array;
764 ip_limit = ip + num_edges * num_edges * num_strong_points;
765 for (; ip < ip_limit; ip += num_strong_points)
766 if (*ip != MISSING)
767 i++;
769 if (i)
771 recorder->hints_record.num_actions++;
773 *(p++) = 0;
774 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
775 *(p++) = HIGH(i);
776 *(p++) = LOW(i);
778 i = 0;
779 ip = recorder->ip_between_point_array;
780 ip_limit = ip + num_edges * num_edges * num_strong_points;
781 for (;
782 ip < ip_limit;
783 ip += num_edges * num_strong_points, i++)
785 before = edges + i;
787 j = 0;
788 iq = ip;
789 iq_limit = iq + num_edges * num_strong_points;
790 for (; iq < iq_limit; iq += num_strong_points, j++)
792 if (*iq == MISSING)
793 continue;
795 after = edges + j;
797 *(p++) = HIGH(after->first - segments);
798 *(p++) = LOW(after->first - segments);
799 *(p++) = HIGH(before->first - segments);
800 *(p++) = LOW(before->first - segments);
802 k = 0;
803 ir = iq;
804 ir_limit = ir + num_strong_points;
805 for (; ir < ir_limit; ir++)
807 if (*ir != MISSING)
808 k++;
809 else
810 break;
813 *(p++) = HIGH(k);
814 *(p++) = LOW(k);
816 ir = iq;
817 ir_limit = ir + k;
818 for (; ir < ir_limit; ir++)
820 FT_UInt point = TA_adjust_point_index(recorder, *ir);
823 *(p++) = HIGH(point);
824 *(p++) = LOW(point);
830 recorder->hints_record.buf = p;
834 static FT_Bool
835 TA_hints_record_is_different(Hints_Record* hints_records,
836 FT_UInt num_hints_records,
837 FT_Byte* start,
838 FT_Byte* end)
840 Hints_Record last_hints_record;
843 if (!hints_records)
844 return 1;
846 /* we only need to compare with the last hints record */
847 last_hints_record = hints_records[num_hints_records - 1];
849 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
850 return 1;
852 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
853 return 1;
855 return 0;
859 static FT_Error
860 TA_add_hints_record(Hints_Record** hints_records,
861 FT_UInt* num_hints_records,
862 FT_Byte* start,
863 Hints_Record hints_record)
865 Hints_Record* hints_records_new;
866 FT_UInt buf_len;
867 /* at this point, `hints_record.buf' still points into `ins_buf' */
868 FT_Byte* end = hints_record.buf;
871 buf_len = (FT_UInt)(end - start);
873 /* now fill the structure completely */
874 hints_record.buf_len = buf_len;
875 hints_record.buf = (FT_Byte*)malloc(buf_len);
876 if (!hints_record.buf)
877 return FT_Err_Out_Of_Memory;
879 memcpy(hints_record.buf, start, buf_len);
881 (*num_hints_records)++;
882 hints_records_new =
883 (Hints_Record*)realloc(*hints_records, *num_hints_records
884 * sizeof (Hints_Record));
885 if (!hints_records_new)
887 free(hints_record.buf);
888 (*num_hints_records)--;
889 return FT_Err_Out_Of_Memory;
891 else
892 *hints_records = hints_records_new;
894 (*hints_records)[*num_hints_records - 1] = hints_record;
896 return FT_Err_Ok;
900 static FT_Byte*
901 TA_emit_hints_record(Recorder* recorder,
902 Hints_Record* hints_record,
903 FT_Byte* bufp,
904 FT_Bool optimize)
906 FT_Byte* p;
907 FT_Byte* endp;
908 FT_Bool need_words = 0;
910 FT_UInt i, j;
911 FT_UInt num_arguments;
912 FT_UInt num_args;
915 /* check whether any argument is larger than 0xFF */
916 endp = hints_record->buf + hints_record->buf_len;
917 for (p = hints_record->buf; p < endp; p += 2)
918 if (*p)
919 need_words = 1;
921 /* with most fonts it is very rare */
922 /* that any of the pushed arguments is larger than 0xFF, */
923 /* thus we refrain from further optimizing this case */
925 num_arguments = hints_record->buf_len / 2;
926 p = endp - 2;
928 if (need_words)
930 for (i = 0; i < num_arguments; i += 255)
932 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
934 if (optimize && num_args <= 8)
935 BCI(PUSHW_1 - 1 + num_args);
936 else
938 BCI(NPUSHW);
939 BCI(num_args);
941 for (j = 0; j < num_args; j++)
943 BCI(*p);
944 BCI(*(p + 1));
945 p -= 2;
949 else
951 /* we only need the lower bytes */
952 p++;
954 for (i = 0; i < num_arguments; i += 255)
956 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
958 if (optimize && num_args <= 8)
959 BCI(PUSHB_1 - 1 + num_args);
960 else
962 BCI(NPUSHB);
963 BCI(num_args);
965 for (j = 0; j < num_args; j++)
967 BCI(*p);
968 p -= 2;
973 /* collect stack depth data */
974 if (num_arguments > recorder->num_stack_elements)
975 recorder->num_stack_elements = num_arguments;
977 return bufp;
981 static FT_Byte*
982 TA_emit_hints_records(Recorder* recorder,
983 Hints_Record* hints_records,
984 FT_UInt num_hints_records,
985 FT_Byte* bufp,
986 FT_Bool optimize)
988 FT_UInt i;
989 Hints_Record* hints_record;
992 hints_record = hints_records;
994 for (i = 0; i < num_hints_records - 1; i++)
996 BCI(MPPEM);
997 if (hints_record->size > 0xFF)
999 BCI(PUSHW_1);
1000 BCI(HIGH((hints_record + 1)->size));
1001 BCI(LOW((hints_record + 1)->size));
1003 else
1005 BCI(PUSHB_1);
1006 BCI((hints_record + 1)->size);
1008 BCI(LT);
1009 BCI(IF);
1010 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1011 BCI(ELSE);
1013 hints_record++;
1016 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1018 for (i = 0; i < num_hints_records - 1; i++)
1019 BCI(EIF);
1021 return bufp;
1025 static void
1026 TA_free_hints_records(Hints_Record* hints_records,
1027 FT_UInt num_hints_records)
1029 FT_UInt i;
1032 for (i = 0; i < num_hints_records; i++)
1033 free(hints_records[i].buf);
1035 free(hints_records);
1039 static FT_Byte*
1040 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1041 TA_AxisHints axis,
1042 TA_Edge edge,
1043 FT_UInt* wraps)
1045 TA_Segment segments = axis->segments;
1046 TA_Segment seg;
1047 FT_UInt seg_idx;
1048 FT_UInt num_segs = 0;
1049 FT_UInt* wrap;
1052 seg_idx = edge->first - segments;
1054 /* we store everything as 16bit numbers */
1055 *(bufp++) = HIGH(seg_idx);
1056 *(bufp++) = LOW(seg_idx);
1058 /* wrap-around segments are stored as two segments */
1059 if (edge->first->first > edge->first->last)
1060 num_segs++;
1062 seg = edge->first->edge_next;
1063 while (seg != edge->first)
1065 num_segs++;
1067 if (seg->first > seg->last)
1068 num_segs++;
1070 seg = seg->edge_next;
1073 *(bufp++) = HIGH(num_segs);
1074 *(bufp++) = LOW(num_segs);
1076 if (edge->first->first > edge->first->last)
1078 /* emit second part of wrap-around segment; */
1079 /* the bytecode positions such segments after `normal' ones */
1080 wrap = wraps;
1081 for (;;)
1083 if (seg_idx == *wrap)
1084 break;
1085 wrap++;
1088 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1089 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1092 seg = edge->first->edge_next;
1093 while (seg != edge->first)
1095 seg_idx = seg - segments;
1097 *(bufp++) = HIGH(seg_idx);
1098 *(bufp++) = LOW(seg_idx);
1100 if (seg->first > seg->last)
1102 wrap = wraps;
1103 for (;;)
1105 if (seg_idx == *wrap)
1106 break;
1107 wrap++;
1110 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1111 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1114 seg = seg->edge_next;
1117 return bufp;
1121 static void
1122 TA_hints_recorder(TA_Action action,
1123 TA_GlyphHints hints,
1124 TA_Dimension dim,
1125 void* arg1,
1126 TA_Edge arg2,
1127 TA_Edge arg3,
1128 TA_Edge lower_bound,
1129 TA_Edge upper_bound)
1131 TA_AxisHints axis = &hints->axis[dim];
1132 TA_Edge edges = axis->edges;
1133 TA_Segment segments = axis->segments;
1134 TA_Point points = hints->points;
1136 Recorder* recorder = (Recorder*)hints->user;
1137 FONT* font = recorder->font;
1138 FT_UInt* wraps = recorder->wrap_around_segments;
1139 FT_Byte* p = recorder->hints_record.buf;
1141 FT_UInt* ip;
1142 FT_UInt* limit;
1145 if (dim == TA_DIMENSION_HORZ)
1146 return;
1148 /* we collect point hints for later processing */
1149 switch (action)
1151 case ta_ip_before:
1153 TA_Point point = (TA_Point)arg1;
1156 ip = recorder->ip_before_points;
1157 limit = ip + recorder->num_strong_points;
1158 for (; ip < limit; ip++)
1160 if (*ip == MISSING)
1162 *ip = point - points;
1163 break;
1167 return;
1169 case ta_ip_after:
1171 TA_Point point = (TA_Point)arg1;
1174 ip = recorder->ip_after_points;
1175 limit = ip + recorder->num_strong_points;
1176 for (; ip < limit; ip++)
1178 if (*ip == MISSING)
1180 *ip = point - points;
1181 break;
1185 return;
1187 case ta_ip_on:
1189 TA_Point point = (TA_Point)arg1;
1190 TA_Edge edge = arg2;
1193 ip = recorder->ip_on_point_array
1194 + recorder->num_strong_points
1195 * (edge - edges);
1196 limit = ip + recorder->num_strong_points;
1197 for (; ip < limit; ip++)
1199 if (*ip == MISSING)
1201 *ip = point - points;
1202 break;
1206 return;
1208 case ta_ip_between:
1210 TA_Point point = (TA_Point)arg1;
1211 TA_Edge before = arg2;
1212 TA_Edge after = arg3;
1215 /* note that `recorder->num_segments' has been used for allocation, */
1216 /* but `axis->num_edges' is used for accessing this array */
1217 ip = recorder->ip_between_point_array
1218 + recorder->num_strong_points * axis->num_edges
1219 * (before - edges)
1220 + recorder->num_strong_points
1221 * (after - edges);
1222 limit = ip + recorder->num_strong_points;
1223 for (; ip < limit; ip++)
1225 if (*ip == MISSING)
1227 *ip = point - points;
1228 break;
1232 return;
1234 case ta_bound:
1235 /* we ignore the BOUND action since we signal this information */
1236 /* with the proper function number */
1237 return;
1239 default:
1240 break;
1243 /* some enum values correspond to four or eight bytecode functions; */
1244 /* if the value is n, the function numbers are n, ..., n+7, */
1245 /* to be differentiated with flags */
1247 switch (action)
1249 case ta_link:
1251 TA_Edge base_edge = (TA_Edge)arg1;
1252 TA_Edge stem_edge = arg2;
1255 *(p++) = 0;
1256 *(p++) = (FT_Byte)action + ACTION_OFFSET
1257 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1258 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1260 *(p++) = HIGH(base_edge->first - segments);
1261 *(p++) = LOW(base_edge->first - segments);
1262 *(p++) = HIGH(stem_edge->first - segments);
1263 *(p++) = LOW(stem_edge->first - segments);
1265 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1267 break;
1269 case ta_anchor:
1271 TA_Edge edge = (TA_Edge)arg1;
1272 TA_Edge edge2 = arg2;
1275 *(p++) = 0;
1276 *(p++) = (FT_Byte)action + ACTION_OFFSET
1277 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1278 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1280 *(p++) = HIGH(edge->first - segments);
1281 *(p++) = LOW(edge->first - segments);
1282 *(p++) = HIGH(edge2->first - segments);
1283 *(p++) = LOW(edge2->first - segments);
1285 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1287 break;
1289 case ta_adjust:
1291 TA_Edge edge = (TA_Edge)arg1;
1292 TA_Edge edge2 = arg2;
1293 TA_Edge edge_minus_one = lower_bound;
1296 *(p++) = 0;
1297 *(p++) = (FT_Byte)action + ACTION_OFFSET
1298 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1299 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1300 + 4 * (edge_minus_one != NULL);
1302 *(p++) = HIGH(edge->first - segments);
1303 *(p++) = LOW(edge->first - segments);
1304 *(p++) = HIGH(edge2->first - segments);
1305 *(p++) = LOW(edge2->first - segments);
1307 if (edge_minus_one)
1309 *(p++) = HIGH(edge_minus_one->first - segments);
1310 *(p++) = LOW(edge_minus_one->first - segments);
1313 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1315 break;
1317 case ta_blue_anchor:
1319 TA_Edge edge = (TA_Edge)arg1;
1320 TA_Edge blue = arg2;
1323 *(p++) = 0;
1324 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1326 *(p++) = HIGH(blue->first - segments);
1327 *(p++) = LOW(blue->first - segments);
1329 if (edge->best_blue_is_shoot)
1331 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1332 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1334 else
1336 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1337 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1340 *(p++) = HIGH(edge->first - segments);
1341 *(p++) = LOW(edge->first - segments);
1343 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1345 break;
1347 case ta_stem:
1349 TA_Edge edge = (TA_Edge)arg1;
1350 TA_Edge edge2 = arg2;
1351 TA_Edge edge_minus_one = lower_bound;
1354 *(p++) = 0;
1355 *(p++) = (FT_Byte)action + ACTION_OFFSET
1356 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1357 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1358 + 4 * (edge_minus_one != NULL);
1360 *(p++) = HIGH(edge->first - segments);
1361 *(p++) = LOW(edge->first - segments);
1362 *(p++) = HIGH(edge2->first - segments);
1363 *(p++) = LOW(edge2->first - segments);
1365 if (edge_minus_one)
1367 *(p++) = HIGH(edge_minus_one->first - segments);
1368 *(p++) = LOW(edge_minus_one->first - segments);
1371 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1372 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1374 break;
1376 case ta_blue:
1378 TA_Edge edge = (TA_Edge)arg1;
1381 *(p++) = 0;
1382 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1384 if (edge->best_blue_is_shoot)
1386 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1387 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1389 else
1391 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1392 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1395 *(p++) = HIGH(edge->first - segments);
1396 *(p++) = LOW(edge->first - segments);
1398 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1400 break;
1402 case ta_serif:
1404 TA_Edge serif = (TA_Edge)arg1;
1405 TA_Edge base = serif->serif;
1408 *(p++) = 0;
1409 *(p++) = (FT_Byte)action + ACTION_OFFSET
1410 + (lower_bound != NULL)
1411 + 2 * (upper_bound != NULL);
1413 *(p++) = HIGH(serif->first - segments);
1414 *(p++) = LOW(serif->first - segments);
1415 *(p++) = HIGH(base->first - segments);
1416 *(p++) = LOW(base->first - segments);
1418 if (lower_bound)
1420 *(p++) = HIGH(lower_bound->first - segments);
1421 *(p++) = LOW(lower_bound->first - segments);
1423 if (upper_bound)
1425 *(p++) = HIGH(upper_bound->first - segments);
1426 *(p++) = LOW(upper_bound->first - segments);
1429 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1431 break;
1433 case ta_serif_anchor:
1434 case ta_serif_link2:
1436 TA_Edge edge = (TA_Edge)arg1;
1439 *(p++) = 0;
1440 *(p++) = (FT_Byte)action + ACTION_OFFSET
1441 + (lower_bound != NULL)
1442 + 2 * (upper_bound != NULL);
1444 *(p++) = HIGH(edge->first - segments);
1445 *(p++) = LOW(edge->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 case ta_serif_link1:
1464 TA_Edge edge = (TA_Edge)arg1;
1465 TA_Edge before = arg2;
1466 TA_Edge after = arg3;
1469 *(p++) = 0;
1470 *(p++) = (FT_Byte)action + ACTION_OFFSET
1471 + (lower_bound != NULL)
1472 + 2 * (upper_bound != NULL);
1474 *(p++) = HIGH(before->first - segments);
1475 *(p++) = LOW(before->first - segments);
1476 *(p++) = HIGH(edge->first - segments);
1477 *(p++) = LOW(edge->first - segments);
1478 *(p++) = HIGH(after->first - segments);
1479 *(p++) = LOW(after->first - segments);
1481 if (lower_bound)
1483 *(p++) = HIGH(lower_bound->first - segments);
1484 *(p++) = LOW(lower_bound->first - segments);
1486 if (upper_bound)
1488 *(p++) = HIGH(upper_bound->first - segments);
1489 *(p++) = LOW(upper_bound->first - segments);
1492 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1494 break;
1496 default:
1497 /* there are more cases in the enumeration */
1498 /* which are handled with flags */
1499 break;
1502 recorder->hints_record.num_actions++;
1503 recorder->hints_record.buf = p;
1507 static FT_Error
1508 TA_init_recorder(Recorder* recorder,
1509 FONT* font,
1510 GLYPH* glyph,
1511 TA_GlyphHints hints)
1513 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1514 TA_Point points = hints->points;
1515 TA_Point point_limit = points + hints->num_points;
1516 TA_Point point;
1518 TA_Segment segments = axis->segments;
1519 TA_Segment seg_limit = segments + axis->num_segments;
1520 TA_Segment seg;
1522 FT_UInt num_strong_points = 0;
1523 FT_UInt* wrap_around_segment;
1525 recorder->font = font;
1526 recorder->glyph = glyph;
1527 recorder->num_segments = axis->num_segments;
1529 recorder->ip_before_points = NULL;
1530 recorder->ip_after_points = NULL;
1531 recorder->ip_on_point_array = NULL;
1532 recorder->ip_between_point_array = NULL;
1534 recorder->num_stack_elements = 0;
1536 /* no need to clean up allocated arrays in case of error; */
1537 /* this is handled later by `TA_free_recorder' */
1539 recorder->num_wrap_around_segments = 0;
1540 for (seg = segments; seg < seg_limit; seg++)
1541 if (seg->first > seg->last)
1542 recorder->num_wrap_around_segments++;
1544 recorder->wrap_around_segments =
1545 (FT_UInt*)malloc(recorder->num_wrap_around_segments * sizeof (FT_UInt));
1546 if (!recorder->wrap_around_segments)
1547 return FT_Err_Out_Of_Memory;
1549 wrap_around_segment = recorder->wrap_around_segments;
1550 for (seg = segments; seg < seg_limit; seg++)
1551 if (seg->first > seg->last)
1552 *(wrap_around_segment++) = seg - segments;
1554 /* get number of strong points */
1555 for (point = points; point < point_limit; point++)
1557 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1558 /* however, this value isn't known yet */
1559 /* (or rather, it can vary between different pixel sizes) */
1560 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1561 continue;
1563 num_strong_points++;
1566 recorder->num_strong_points = num_strong_points;
1568 recorder->ip_before_points =
1569 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1570 if (!recorder->ip_before_points)
1571 return FT_Err_Out_Of_Memory;
1573 recorder->ip_after_points =
1574 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1575 if (!recorder->ip_after_points)
1576 return FT_Err_Out_Of_Memory;
1578 /* actually, we need `hints->num_edges' for the array sizes; */
1579 /* however, this value isn't known yet */
1580 /* (or rather, it can vary between different pixel sizes) */
1581 recorder->ip_on_point_array =
1582 (FT_UInt*)malloc(axis->num_segments
1583 * num_strong_points * sizeof (FT_UInt));
1584 if (!recorder->ip_on_point_array)
1585 return FT_Err_Out_Of_Memory;
1587 recorder->ip_between_point_array =
1588 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1589 * num_strong_points * sizeof (FT_UInt));
1590 if (!recorder->ip_between_point_array)
1591 return FT_Err_Out_Of_Memory;
1593 return FT_Err_Ok;
1597 static void
1598 TA_reset_recorder(Recorder* recorder,
1599 FT_Byte* bufp)
1601 recorder->hints_record.buf = bufp;
1602 recorder->hints_record.num_actions = 0;
1606 static void
1607 TA_rewind_recorder(Recorder* recorder,
1608 FT_Byte* bufp,
1609 FT_UInt size)
1611 TA_reset_recorder(recorder, bufp);
1613 recorder->hints_record.size = size;
1615 /* We later check with MISSING (which expands to 0xFF bytes) */
1617 memset(recorder->ip_before_points, 0xFF,
1618 recorder->num_strong_points * sizeof (FT_UInt));
1619 memset(recorder->ip_after_points, 0xFF,
1620 recorder->num_strong_points * sizeof (FT_UInt));
1622 memset(recorder->ip_on_point_array, 0xFF,
1623 recorder->num_segments
1624 * recorder->num_strong_points * sizeof (FT_UInt));
1625 memset(recorder->ip_between_point_array, 0xFF,
1626 recorder->num_segments * recorder->num_segments
1627 * recorder->num_strong_points * sizeof (FT_UInt));
1631 static void
1632 TA_free_recorder(Recorder* recorder)
1634 free(recorder->wrap_around_segments);
1636 free(recorder->ip_before_points);
1637 free(recorder->ip_after_points);
1638 free(recorder->ip_on_point_array);
1639 free(recorder->ip_between_point_array);
1643 FT_Error
1644 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1645 FONT* font,
1646 FT_Long idx)
1648 FT_Face face = sfnt->face;
1649 FT_Error error;
1651 FT_Byte* ins_buf;
1652 FT_UInt ins_len;
1653 FT_Byte* bufp;
1654 FT_Byte* p;
1656 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1657 glyf_Data* data = (glyf_Data*)glyf_table->data;
1658 /* `idx' is never negative */
1659 GLYPH* glyph = &data->glyphs[idx];
1661 TA_GlyphHints hints;
1663 FT_UInt num_action_hints_records = 0;
1664 FT_UInt num_point_hints_records = 0;
1665 Hints_Record* action_hints_records = NULL;
1666 Hints_Record* point_hints_records = NULL;
1668 Recorder recorder;
1669 FT_UInt num_stack_elements;
1670 FT_Bool optimize = 0;
1672 FT_Int32 load_flags;
1673 FT_UInt size;
1675 FT_Byte* pos[3];
1677 #ifdef TA_DEBUG
1678 int _ta_debug_save;
1679 #endif
1682 /* XXX: right now, we abuse this flag to control */
1683 /* the global behaviour of the auto-hinter */
1684 load_flags = 1 << 29; /* vertical hinting only */
1685 /* values 0 and 6-20 compressed to 4 bits */
1686 if (font->increase_x_height)
1687 load_flags |= (font->increase_x_height - 5) << 25;
1688 if (!font->pre_hinting)
1690 if (font->hint_with_components)
1691 load_flags |= FT_LOAD_NO_SCALE;
1692 else
1693 load_flags |= FT_LOAD_NO_RECURSE;
1696 /* computing the segments is resolution independent, */
1697 /* thus the pixel size in this call is arbitrary */
1698 error = FT_Set_Pixel_Sizes(face, 20, 20);
1699 if (error)
1700 return error;
1702 #ifdef TA_DEBUG
1703 /* temporarily disable debugging output */
1704 /* to avoid getting the information twice */
1705 _ta_debug_save = _ta_debug;
1706 _ta_debug = 0;
1707 #endif
1709 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1710 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1712 #ifdef TA_DEBUG
1713 _ta_debug = _ta_debug_save;
1714 #endif
1716 if (error)
1717 return error;
1719 /* do nothing if we have an empty glyph */
1720 if (!face->glyph->outline.n_contours)
1721 return FT_Err_Ok;
1723 hints = &font->loader->hints;
1725 /* do nothing if the setup delivered the dummy module only */
1726 if (!hints->num_points)
1727 return FT_Err_Ok;
1729 /* we allocate a buffer which is certainly large enough */
1730 /* to hold all of the created bytecode instructions; */
1731 /* later on it gets reallocated to its real size */
1732 ins_len = hints->num_points * 1000;
1733 ins_buf = (FT_Byte*)malloc(ins_len);
1734 if (!ins_buf)
1735 return FT_Err_Out_Of_Memory;
1737 /* initialize array with an invalid bytecode */
1738 /* so that we can easily find the array length at reallocation time */
1739 memset(ins_buf, INS_A0, ins_len);
1741 /* handle composite glyph */
1742 if (font->loader->gloader->base.num_subglyphs)
1744 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1745 if (!bufp)
1747 error = FT_Err_Out_Of_Memory;
1748 goto Err;
1751 goto Done1;
1754 /* only scale the glyph if the dummy hinter has been used */
1755 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1757 /* since `TA_init_recorder' hasn't been called yet, */
1758 /* we manually initialize the `font' and `glyph' fields */
1759 recorder.font = font;
1760 recorder.glyph = glyph;
1762 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1763 if (!bufp)
1765 error = FT_Err_Out_Of_Memory;
1766 goto Err;
1769 goto Done1;
1772 error = TA_init_recorder(&recorder, font, glyph, hints);
1773 if (error)
1774 goto Err;
1776 /* loop over a large range of pixel sizes */
1777 /* to find hints records which get pushed onto the bytecode stack */
1779 #ifdef DEBUGGING
1780 if (font->debug)
1782 int num_chars, i;
1783 char buf[256];
1786 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1788 num_chars = fprintf(stderr, "glyph %ld", idx);
1789 if (*buf)
1790 num_chars += fprintf(stderr, " (%s)", buf);
1791 fprintf(stderr, "\n");
1792 for (i = 0; i < num_chars; i++)
1793 putc('=', stderr);
1794 fprintf(stderr, "\n\n");
1797 #endif
1799 /* we temporarily use `ins_buf' to record the current glyph hints */
1800 ta_loader_register_hints_recorder(font->loader,
1801 TA_hints_recorder,
1802 (void*)&recorder);
1804 for (size = font->hinting_range_min;
1805 size <= font->hinting_range_max;
1806 size++)
1808 #ifdef DEBUGGING
1809 int have_dumps = 0;
1810 #endif
1813 TA_rewind_recorder(&recorder, ins_buf, size);
1815 error = FT_Set_Pixel_Sizes(face, size, size);
1816 if (error)
1817 goto Err;
1819 /* calling `ta_loader_load_glyph' uses the */
1820 /* `TA_hints_recorder' function as a callback, */
1821 /* modifying `hints_record' */
1822 error = ta_loader_load_glyph(font, face, idx, load_flags);
1823 if (error)
1824 goto Err;
1826 if (TA_hints_record_is_different(action_hints_records,
1827 num_action_hints_records,
1828 ins_buf, recorder.hints_record.buf))
1830 #ifdef DEBUGGING
1831 if (font->debug)
1833 int num_chars, i;
1836 have_dumps = 1;
1838 num_chars = fprintf(stderr, "size %d\n", size);
1839 for (i = 0; i < num_chars - 1; i++)
1840 putc('-', stderr);
1841 fprintf(stderr, "\n\n");
1843 ta_glyph_hints_dump_edges(_ta_debug_hints);
1844 ta_glyph_hints_dump_segments(_ta_debug_hints);
1845 ta_glyph_hints_dump_points(_ta_debug_hints);
1847 fprintf(stderr, "action hints record:\n");
1848 if (ins_buf == recorder.hints_record.buf)
1849 fprintf(stderr, " (none)");
1850 else
1852 fprintf(stderr, " ");
1853 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1854 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1856 fprintf(stderr, "\n");
1858 #endif
1860 error = TA_add_hints_record(&action_hints_records,
1861 &num_action_hints_records,
1862 ins_buf, recorder.hints_record);
1863 if (error)
1864 goto Err;
1867 /* now handle point records */
1869 TA_reset_recorder(&recorder, ins_buf);
1871 /* use the point hints data collected in `TA_hints_recorder' */
1872 TA_build_point_hints(&recorder, hints);
1874 if (TA_hints_record_is_different(point_hints_records,
1875 num_point_hints_records,
1876 ins_buf, recorder.hints_record.buf))
1878 #ifdef DEBUGGING
1879 if (font->debug)
1881 if (!have_dumps)
1883 int num_chars, i;
1886 num_chars = fprintf(stderr, "size %d\n", size);
1887 for (i = 0; i < num_chars - 1; i++)
1888 putc('-', stderr);
1889 fprintf(stderr, "\n\n");
1891 ta_glyph_hints_dump_edges(_ta_debug_hints);
1892 ta_glyph_hints_dump_segments(_ta_debug_hints);
1893 ta_glyph_hints_dump_points(_ta_debug_hints);
1896 fprintf(stderr, "point hints record:\n");
1897 if (ins_buf == recorder.hints_record.buf)
1898 fprintf(stderr, " (none)");
1899 else
1901 fprintf(stderr, " ");
1902 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1903 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1905 fprintf(stderr, "\n\n");
1907 #endif
1909 error = TA_add_hints_record(&point_hints_records,
1910 &num_point_hints_records,
1911 ins_buf, recorder.hints_record);
1912 if (error)
1913 goto Err;
1917 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1919 /* since we only have a single empty record we just scale the glyph */
1920 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1921 if (!bufp)
1923 error = FT_Err_Out_Of_Memory;
1924 goto Err;
1927 /* clear the rest of the temporarily used part of `ins_buf' */
1928 p = bufp;
1929 while (*p != INS_A0)
1930 *(p++) = INS_A0;
1932 goto Done;
1935 /* if there is only a single record, */
1936 /* we do a global optimization later on */
1937 if (num_action_hints_records > 1)
1938 optimize = 1;
1940 /* store the hints records and handle stack depth */
1941 pos[0] = ins_buf;
1942 bufp = TA_emit_hints_records(&recorder,
1943 point_hints_records,
1944 num_point_hints_records,
1945 ins_buf,
1946 optimize);
1948 num_stack_elements = recorder.num_stack_elements;
1949 recorder.num_stack_elements = 0;
1951 pos[1] = bufp;
1952 bufp = TA_emit_hints_records(&recorder,
1953 action_hints_records,
1954 num_action_hints_records,
1955 bufp,
1956 optimize);
1958 recorder.num_stack_elements += num_stack_elements;
1960 pos[2] = bufp;
1961 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
1962 if (!bufp)
1964 error = FT_Err_Out_Of_Memory;
1965 goto Err;
1968 /* XXX improve handling of NPUSHW */
1969 if (num_action_hints_records == 1
1970 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1973 * we optimize two common cases, replacing
1975 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1977 * with
1979 * NPUSHB (A+B[+C]) ... CALL
1981 * if possible
1983 FT_Byte sizes[3];
1984 FT_Byte new_size1;
1985 FT_Byte new_size2;
1987 FT_UInt sum;
1988 FT_UInt i;
1989 FT_UInt pos_idx;
1992 /* the point hints records block can be missing */
1993 if (pos[0] == pos[1])
1995 pos[1] = pos[2];
1996 pos[2] = NULL;
1999 /* there are at least two NPUSHB instructions */
2000 /* (one of them directly at the start) */
2001 sizes[0] = *(pos[0] + 1);
2002 sizes[1] = *(pos[1] + 1);
2003 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
2005 sum = sizes[0] + sizes[1] + sizes[2];
2007 if (sum > 2 * 0xFF)
2008 goto Done2; /* nothing to do since we need three NPUSHB */
2009 else if (!sizes[2] && (sum > 0xFF))
2010 goto Done2; /* nothing to do since we need two NPUSHB */
2012 if (sum > 0xFF)
2014 /* reduce three NPUSHB to two */
2015 new_size1 = 0xFF;
2016 new_size2 = sum - 0xFF;
2018 else
2020 /* reduce two or three NPUSHB to one */
2021 new_size1 = sum;
2022 new_size2 = 0;
2025 /* pack data */
2026 p = ins_buf;
2027 bufp = ins_buf;
2028 pos_idx = 0;
2030 if (new_size1 <= 8)
2031 BCI(PUSHB_1 - 1 + new_size1);
2032 else
2034 BCI(NPUSHB);
2035 BCI(new_size1);
2037 for (i = 0; i < new_size1; i++)
2039 if (p == pos[pos_idx])
2041 pos_idx++;
2042 p += 2; /* skip old NPUSHB */
2044 *(bufp++) = *(p++);
2047 if (new_size2)
2049 if (new_size2 <= 8)
2050 BCI(PUSHB_1 - 1 + new_size2);
2051 else
2053 BCI(NPUSHB);
2054 BCI(new_size2);
2056 for (i = 0; i < new_size2; i++)
2058 if (p == pos[pos_idx])
2060 pos_idx++;
2061 p += 2;
2063 *(bufp++) = *(p++);
2067 BCI(CALL);
2070 Done2:
2071 /* clear the rest of the temporarily used part of `ins_buf' */
2072 p = bufp;
2073 while (*p != INS_A0)
2074 *(p++) = INS_A0;
2076 Done:
2077 TA_free_hints_records(action_hints_records, num_action_hints_records);
2078 TA_free_hints_records(point_hints_records, num_point_hints_records);
2079 TA_free_recorder(&recorder);
2081 /* we are done, so reallocate the instruction array to its real size */
2082 if (*bufp == INS_A0)
2084 /* search backwards */
2085 while (*bufp == INS_A0)
2086 bufp--;
2087 bufp++;
2089 else
2091 /* search forwards */
2092 while (*bufp != INS_A0)
2093 bufp++;
2096 Done1:
2097 ins_len = bufp - ins_buf;
2099 if (ins_len > sfnt->max_instructions)
2100 sfnt->max_instructions = ins_len;
2102 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2103 glyph->ins_len = ins_len;
2105 return FT_Err_Ok;
2107 Err:
2108 TA_free_hints_records(action_hints_records, num_action_hints_records);
2109 TA_free_hints_records(point_hints_records, num_point_hints_records);
2110 TA_free_recorder(&recorder);
2111 free(ins_buf);
2113 return error;
2117 /* end of tabytecode.c */