More additions to part 7 of bytecode size reduction.
[ttfautohint.git] / lib / tabytecode.c
blob1def88c10a37f63efe7acbd9d29cbb58c9d7f151
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 = 1;
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 GLYPH* glyph = recorder->glyph;
91 FT_UShort i;
94 if (!glyph->num_components)
95 return idx; /* not a composite glyph */
97 for (i = 0; i < glyph->num_pointsums; i++)
98 if (idx < glyph->pointsums[i])
99 break;
101 return idx + i;
105 /* we store the segments in the storage area; */
106 /* each segment record consists of the first and last point */
108 static FT_Byte*
109 TA_sfnt_build_glyph_segments(SFNT* sfnt,
110 Recorder* recorder,
111 FT_Byte* bufp,
112 FT_Bool optimize)
114 FONT* font = recorder->font;
115 TA_GlyphHints hints = &font->loader->hints;
116 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
117 TA_Point points = hints->points;
118 TA_Segment segments = axis->segments;
119 TA_Segment seg;
120 TA_Segment seg_limit;
122 FT_Outline outline = font->loader->gloader->base.outline;
124 FT_UInt* args;
125 FT_UInt* arg;
126 FT_UInt num_args;
127 FT_UInt nargs;
128 FT_UInt num_segments;
130 FT_Bool need_words = 0;
132 FT_Int n;
133 FT_UInt i, j;
134 FT_UInt base;
135 FT_UInt num_packed_segments;
136 FT_UInt num_storage;
137 FT_UInt num_stack_elements;
138 FT_UInt num_twilight_points;
141 seg_limit = segments + axis->num_segments;
142 num_segments = axis->num_segments;
144 /* to pack the data in the bytecode more tightly, */
145 /* we store up to the first nine segments in nibbles if possible, */
146 /* using delta values */
147 base = 0;
148 num_packed_segments = 0;
149 for (seg = segments; seg < seg_limit; seg++)
151 FT_UInt first = seg->first - points;
152 FT_UInt last = seg->last - points;
155 first = TA_adjust_point_index(recorder, first);
156 last = TA_adjust_point_index(recorder, last);
158 if (first - base >= 16)
159 break;
160 if (first > last || last - first >= 16)
161 break;
162 if (num_packed_segments == 9)
163 break;
164 num_packed_segments++;
165 base = last;
168 /* also handle wrap-around segments */
169 num_segments += recorder->num_wrap_around_segments;
171 /* wrap-around segments are pushed with four arguments; */
172 /* a segment stored in nibbles needs only one byte instead of two */
173 num_args = num_packed_segments
174 + 2 * (num_segments - num_packed_segments)
175 + 2 * recorder->num_wrap_around_segments
176 + 2;
178 /* collect all arguments temporarily in an array (in reverse order) */
179 /* so that we can easily split into chunks of 255 args */
180 /* as needed by NPUSHB and NPUSHW, respectively */
181 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
182 if (!args)
183 return NULL;
185 arg = args + num_args - 1;
187 if (num_segments > 0xFF)
188 need_words = 1;
190 /* the number of packed segments is indicated by the function number */
191 if (recorder->glyph->num_components)
192 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
193 else
194 *(arg--) = bci_create_segments_0 + num_packed_segments;
195 *(arg--) = num_segments;
197 base = 0;
198 for (seg = segments; seg < segments + num_packed_segments; seg++)
200 FT_UInt first = seg->first - points;
201 FT_UInt last = seg->last - points;
202 FT_UInt low_nibble;
203 FT_UInt high_nibble;
206 first = TA_adjust_point_index(recorder, first);
207 last = TA_adjust_point_index(recorder, last);
209 low_nibble = first - base;
210 high_nibble = last - first;
212 *(arg--) = 16 * high_nibble + low_nibble;
214 base = last;
217 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
219 FT_UInt first = seg->first - points;
220 FT_UInt last = seg->last - points;
223 *(arg--) = TA_adjust_point_index(recorder, first);
224 *(arg--) = TA_adjust_point_index(recorder, last);
226 /* we push the last and first contour point */
227 /* as a third and fourth argument in wrap-around segments */
228 if (first > last)
230 for (n = 0; n < outline.n_contours; n++)
232 FT_UInt end = (FT_UInt)outline.contours[n];
235 if (first <= end)
237 *(arg--) = TA_adjust_point_index(recorder, end);
238 if (end > 0xFF)
239 need_words = 1;
241 if (n == 0)
242 *(arg--) = TA_adjust_point_index(recorder, 0);
243 else
244 *(arg--) = TA_adjust_point_index(recorder,
245 (FT_UInt)outline.contours[n - 1] + 1);
246 break;
251 if (last > 0xFF)
252 need_words = 1;
255 /* emit the second part of wrap-around segments as separate segments */
256 /* so that edges can easily link to them */
257 for (seg = segments; seg < seg_limit; seg++)
259 FT_UInt first = seg->first - points;
260 FT_UInt last = seg->last - points;
263 if (first > last)
265 for (n = 0; n < outline.n_contours; n++)
267 if (first <= (FT_UInt)outline.contours[n])
269 if (n == 0)
270 *(arg--) = TA_adjust_point_index(recorder, 0);
271 else
272 *(arg--) = TA_adjust_point_index(recorder,
273 (FT_UInt)outline.contours[n - 1] + 1);
274 break;
278 *(arg--) = TA_adjust_point_index(recorder, last);
281 /* with most fonts it is very rare */
282 /* that any of the pushed arguments is larger than 0xFF, */
283 /* thus we refrain from further optimizing this case */
285 arg = args;
287 if (need_words)
289 for (i = 0; i < num_args; i += 255)
291 nargs = (num_args - i > 255) ? 255 : num_args - i;
294 if (optimize && nargs <= 8)
295 BCI(PUSHW_1 - 1 + nargs);
296 else
298 BCI(NPUSHW);
299 BCI(nargs);
301 for (j = 0; j < nargs; j++)
303 BCI(HIGH(*arg));
304 BCI(LOW(*arg));
305 arg++;
309 else
311 for (i = 0; i < num_args; i += 255)
313 nargs = (num_args - i > 255) ? 255 : num_args - i;
315 if (optimize && nargs <= 8)
316 BCI(PUSHB_1 - 1 + nargs);
317 else
319 BCI(NPUSHB);
320 BCI(nargs);
322 for (j = 0; j < nargs; j++)
324 BCI(*arg);
325 arg++;
330 BCI(CALL);
332 num_storage = sal_segment_offset + num_segments * 2;
333 if (num_storage > sfnt->max_storage)
334 sfnt->max_storage = num_storage;
336 num_twilight_points = num_segments * 2;
337 if (num_twilight_points > sfnt->max_twilight_points)
338 sfnt->max_twilight_points = num_twilight_points;
340 /* both this function and `TA_emit_hints_record' */
341 /* push data onto the stack */
342 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
343 + recorder->num_stack_elements + num_args;
344 if (num_stack_elements > sfnt->max_stack_elements)
345 sfnt->max_stack_elements = num_stack_elements;
347 free(args);
349 return bufp;
353 static FT_Byte*
354 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
355 Recorder* recorder,
356 FT_Byte* bufp)
358 FT_GlyphSlot glyph = sfnt->face->glyph;
359 FT_Vector* points = glyph->outline.points;
360 FT_Int num_contours = glyph->outline.n_contours;
362 FT_UInt* args;
363 FT_UInt* arg;
364 FT_UInt num_args;
365 FT_UInt nargs;
367 FT_Bool need_words = 0;
368 FT_Int p, q;
369 FT_UInt i, j;
370 FT_Int start, end;
371 FT_UInt num_stack_elements;
374 num_args = 2 * num_contours + 2;
376 /* collect all arguments temporarily in an array (in reverse order) */
377 /* so that we can easily split into chunks of 255 args */
378 /* as needed by NPUSHB and NPUSHW, respectively */
379 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
380 if (!args)
381 return NULL;
383 arg = args + num_args - 1;
385 if (num_args > 0xFF)
386 need_words = 1;
388 if (recorder->glyph->num_components)
389 *(arg--) = bci_scale_composite_glyph;
390 else
391 *(arg--) = bci_scale_glyph;
392 *(arg--) = num_contours;
394 start = 0;
395 end = 0;
397 for (p = 0; p < num_contours; p++)
399 FT_Int max = start;
400 FT_Int min = start;
403 end = glyph->outline.contours[p];
405 for (q = start; q <= end; q++)
407 if (points[q].y < points[min].y)
408 min = q;
409 if (points[q].y > points[max].y)
410 max = q;
413 if (min > max)
415 *(arg--) = TA_adjust_point_index(recorder, max);
416 *(arg--) = TA_adjust_point_index(recorder, min);
418 else
420 *(arg--) = TA_adjust_point_index(recorder, min);
421 *(arg--) = TA_adjust_point_index(recorder, max);
424 start = end + 1;
427 if (end > 0xFF)
428 need_words = 1;
430 /* with most fonts it is very rare */
431 /* that any of the pushed arguments is larger than 0xFF, */
432 /* thus we refrain from further optimizing this case */
434 arg = args;
436 if (need_words)
438 for (i = 0; i < num_args; i += 255)
440 nargs = (num_args - i > 255) ? 255 : num_args - i;
442 if (nargs <= 8)
443 BCI(PUSHW_1 - 1 + nargs);
444 else
446 BCI(NPUSHW);
447 BCI(nargs);
449 for (j = 0; j < nargs; j++)
451 BCI(HIGH(*arg));
452 BCI(LOW(*arg));
453 arg++;
457 else
459 for (i = 0; i < num_args; i += 255)
461 nargs = (num_args - i > 255) ? 255 : num_args - i;
463 if (nargs <= 8)
464 BCI(PUSHB_1 - 1 + nargs);
465 else
467 BCI(NPUSHB);
468 BCI(nargs);
470 for (j = 0; j < nargs; j++)
472 BCI(*arg);
473 arg++;
478 BCI(CALL);
480 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
481 if (num_stack_elements > sfnt->max_stack_elements)
482 sfnt->max_stack_elements = num_stack_elements;
484 free(args);
486 return bufp;
490 static FT_Byte*
491 TA_font_build_subglyph_shifter(FONT* font,
492 FT_Byte* bufp)
494 FT_Face face = font->loader->face;
495 FT_GlyphSlot glyph = face->glyph;
497 TA_GlyphLoader gloader = font->loader->gloader;
499 TA_SubGlyph subglyphs = gloader->base.subglyphs;
500 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
501 TA_SubGlyph subglyph;
503 FT_Int curr_contour = 0;
506 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
508 FT_Error error;
510 FT_UShort flags = subglyph->flags;
511 FT_Pos y_offset = subglyph->arg2;
513 FT_Int num_contours;
516 /* load subglyph to get the number of contours */
517 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
518 if (error)
519 return NULL;
520 num_contours = glyph->outline.n_contours;
522 /* nothing to do if there is a point-to-point alignment */
523 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
524 goto End;
526 /* nothing to do if y offset is zero */
527 if (!y_offset)
528 goto End;
530 /* nothing to do if there are no contours */
531 if (!num_contours)
532 goto End;
534 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
535 /* ensures that composite subglyphs are represented as simple glyphs */
537 if (num_contours > 0xFF
538 || curr_contour > 0xFF)
540 BCI(PUSHW_2);
541 BCI(HIGH(curr_contour));
542 BCI(LOW(curr_contour));
543 BCI(HIGH(num_contours));
544 BCI(LOW(num_contours));
546 else
548 BCI(PUSHB_2);
549 BCI(curr_contour);
550 BCI(num_contours);
553 /* there are high chances that this value needs PUSHW, */
554 /* thus we handle it separately */
555 if (y_offset > 0xFF || y_offset < 0)
557 BCI(PUSHW_1);
558 BCI(HIGH(y_offset));
559 BCI(LOW(y_offset));
561 else
563 BCI(PUSHB_1);
564 BCI(y_offset);
567 BCI(PUSHB_1);
568 BCI(bci_shift_subglyph);
569 BCI(CALL);
571 End:
572 curr_contour += num_contours;
575 return bufp;
580 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
581 * data in four arrays (which are simple but waste a lot of memory). The
582 * function below converts them into bytecode.
584 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
585 * together with the edge they correspond to.
587 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
588 * loop over the edge or edge pairs, respectively, and each edge or edge
589 * pair contains an inner loop to emit the correponding points.
592 static void
593 TA_build_point_hints(Recorder* recorder,
594 TA_GlyphHints hints)
596 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
597 TA_Segment segments = axis->segments;
598 TA_Edge edges = axis->edges;
600 TA_Edge edge;
601 TA_Edge before;
602 TA_Edge after;
604 FT_Byte* p = recorder->hints_record.buf;
605 FT_UInt num_edges = axis->num_edges;
606 FT_UInt num_strong_points = recorder->num_strong_points;
608 FT_UInt i;
609 FT_UInt j;
610 FT_UInt k;
612 FT_UInt* ip;
613 FT_UInt* iq;
614 FT_UInt* ir;
615 FT_UInt* ip_limit;
616 FT_UInt* iq_limit;
617 FT_UInt* ir_limit;
620 /* we store everything as 16bit numbers; */
621 /* the function numbers (`ta_ip_before', etc.) */
622 /* reflect the order in the TA_Action enumeration */
624 /* ip_before_points */
626 i = 0;
627 ip = recorder->ip_before_points;
628 ip_limit = ip + num_strong_points;
629 for (; ip < ip_limit; ip++)
631 if (*ip != MISSING)
632 i++;
633 else
634 break;
637 if (i)
639 recorder->hints_record.num_actions++;
641 edge = edges;
643 *(p++) = 0;
644 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
645 *(p++) = HIGH(edge->first - segments);
646 *(p++) = LOW(edge->first - segments);
647 *(p++) = HIGH(i);
648 *(p++) = LOW(i);
650 ip = recorder->ip_before_points;
651 ip_limit = ip + i;
652 for (; ip < ip_limit; ip++)
654 FT_UInt point = TA_adjust_point_index(recorder, *ip);
657 *(p++) = HIGH(point);
658 *(p++) = LOW(point);
662 /* ip_after_points */
664 i = 0;
665 ip = recorder->ip_after_points;
666 ip_limit = ip + num_strong_points;
667 for (; ip < ip_limit; ip++)
669 if (*ip != MISSING)
670 i++;
671 else
672 break;
675 if (i)
677 recorder->hints_record.num_actions++;
679 edge = edges + axis->num_edges - 1;
681 *(p++) = 0;
682 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
683 *(p++) = HIGH(edge->first - segments);
684 *(p++) = LOW(edge->first - segments);
685 *(p++) = HIGH(i);
686 *(p++) = LOW(i);
688 ip = recorder->ip_after_points;
689 ip_limit = ip + i;
690 for (; ip < ip_limit; ip++)
692 FT_UInt point = TA_adjust_point_index(recorder, *ip);
695 *(p++) = HIGH(point);
696 *(p++) = LOW(point);
700 /* ip_on_point_array */
702 i = 0;
703 ip = recorder->ip_on_point_array;
704 ip_limit = ip + num_edges * num_strong_points;
705 for (; ip < ip_limit; ip += num_strong_points)
706 if (*ip != MISSING)
707 i++;
709 if (i)
711 recorder->hints_record.num_actions++;
713 *(p++) = 0;
714 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
715 *(p++) = HIGH(i);
716 *(p++) = LOW(i);
718 i = 0;
719 ip = recorder->ip_on_point_array;
720 ip_limit = ip + num_edges * num_strong_points;
721 for (; ip < ip_limit; ip += num_strong_points, i++)
723 if (*ip == MISSING)
724 continue;
726 edge = edges + i;
728 *(p++) = HIGH(edge->first - segments);
729 *(p++) = LOW(edge->first - segments);
731 j = 0;
732 iq = ip;
733 iq_limit = iq + num_strong_points;
734 for (; iq < iq_limit; iq++)
736 if (*iq != MISSING)
737 j++;
738 else
739 break;
742 *(p++) = HIGH(j);
743 *(p++) = LOW(j);
745 iq = ip;
746 iq_limit = iq + j;
747 for (; iq < iq_limit; iq++)
749 FT_UInt point = TA_adjust_point_index(recorder, *iq);
752 *(p++) = HIGH(point);
753 *(p++) = LOW(point);
758 /* ip_between_point_array */
760 i = 0;
761 ip = recorder->ip_between_point_array;
762 ip_limit = ip + num_edges * num_edges * num_strong_points;
763 for (; ip < ip_limit; ip += num_strong_points)
764 if (*ip != MISSING)
765 i++;
767 if (i)
769 recorder->hints_record.num_actions++;
771 *(p++) = 0;
772 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
773 *(p++) = HIGH(i);
774 *(p++) = LOW(i);
776 i = 0;
777 ip = recorder->ip_between_point_array;
778 ip_limit = ip + num_edges * num_edges * num_strong_points;
779 for (;
780 ip < ip_limit;
781 ip += num_edges * num_strong_points, i++)
783 before = edges + i;
785 j = 0;
786 iq = ip;
787 iq_limit = iq + num_edges * num_strong_points;
788 for (; iq < iq_limit; iq += num_strong_points, j++)
790 if (*iq == MISSING)
791 continue;
793 after = edges + j;
795 *(p++) = HIGH(after->first - segments);
796 *(p++) = LOW(after->first - segments);
797 *(p++) = HIGH(before->first - segments);
798 *(p++) = LOW(before->first - segments);
800 k = 0;
801 ir = iq;
802 ir_limit = ir + num_strong_points;
803 for (; ir < ir_limit; ir++)
805 if (*ir != MISSING)
806 k++;
807 else
808 break;
811 *(p++) = HIGH(k);
812 *(p++) = LOW(k);
814 ir = iq;
815 ir_limit = ir + k;
816 for (; ir < ir_limit; ir++)
818 FT_UInt point = TA_adjust_point_index(recorder, *ir);
821 *(p++) = HIGH(point);
822 *(p++) = LOW(point);
828 recorder->hints_record.buf = p;
832 static FT_Bool
833 TA_hints_record_is_different(Hints_Record* hints_records,
834 FT_UInt num_hints_records,
835 FT_Byte* start,
836 FT_Byte* end)
838 Hints_Record last_hints_record;
841 if (!hints_records)
842 return 1;
844 /* we only need to compare with the last hints record */
845 last_hints_record = hints_records[num_hints_records - 1];
847 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
848 return 1;
850 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
851 return 1;
853 return 0;
857 static FT_Error
858 TA_add_hints_record(Hints_Record** hints_records,
859 FT_UInt* num_hints_records,
860 FT_Byte* start,
861 Hints_Record hints_record)
863 Hints_Record* hints_records_new;
864 FT_UInt buf_len;
865 /* at this point, `hints_record.buf' still points into `ins_buf' */
866 FT_Byte* end = hints_record.buf;
869 buf_len = (FT_UInt)(end - start);
871 /* now fill the structure completely */
872 hints_record.buf_len = buf_len;
873 hints_record.buf = (FT_Byte*)malloc(buf_len);
874 if (!hints_record.buf)
875 return FT_Err_Out_Of_Memory;
877 memcpy(hints_record.buf, start, buf_len);
879 (*num_hints_records)++;
880 hints_records_new =
881 (Hints_Record*)realloc(*hints_records, *num_hints_records
882 * sizeof (Hints_Record));
883 if (!hints_records_new)
885 free(hints_record.buf);
886 (*num_hints_records)--;
887 return FT_Err_Out_Of_Memory;
889 else
890 *hints_records = hints_records_new;
892 (*hints_records)[*num_hints_records - 1] = hints_record;
894 return FT_Err_Ok;
898 static FT_Byte*
899 TA_emit_hints_record(Recorder* recorder,
900 Hints_Record* hints_record,
901 FT_Byte* bufp,
902 FT_Bool optimize)
904 FT_Byte* p;
905 FT_Byte* endp;
906 FT_Bool need_words = 0;
908 FT_UInt i, j;
909 FT_UInt num_arguments;
910 FT_UInt num_args;
913 /* check whether any argument is larger than 0xFF */
914 endp = hints_record->buf + hints_record->buf_len;
915 for (p = hints_record->buf; p < endp; p += 2)
916 if (*p)
917 need_words = 1;
919 /* with most fonts it is very rare */
920 /* that any of the pushed arguments is larger than 0xFF, */
921 /* thus we refrain from further optimizing this case */
923 num_arguments = hints_record->buf_len / 2;
924 p = endp - 2;
926 if (need_words)
928 for (i = 0; i < num_arguments; i += 255)
930 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
932 if (optimize && num_args <= 8)
933 BCI(PUSHW_1 - 1 + num_args);
934 else
936 BCI(NPUSHW);
937 BCI(num_args);
939 for (j = 0; j < num_args; j++)
941 BCI(*p);
942 BCI(*(p + 1));
943 p -= 2;
947 else
949 /* we only need the lower bytes */
950 p++;
952 for (i = 0; i < num_arguments; i += 255)
954 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
956 if (optimize && num_args <= 8)
957 BCI(PUSHB_1 - 1 + num_args);
958 else
960 BCI(NPUSHB);
961 BCI(num_args);
963 for (j = 0; j < num_args; j++)
965 BCI(*p);
966 p -= 2;
971 /* collect stack depth data */
972 if (num_arguments > recorder->num_stack_elements)
973 recorder->num_stack_elements = num_arguments;
975 return bufp;
979 static FT_Byte*
980 TA_emit_hints_records(Recorder* recorder,
981 Hints_Record* hints_records,
982 FT_UInt num_hints_records,
983 FT_Byte* bufp,
984 FT_Bool optimize)
986 FT_UInt i;
987 Hints_Record* hints_record;
990 hints_record = hints_records;
992 for (i = 0; i < num_hints_records - 1; i++)
994 BCI(MPPEM);
995 if (hints_record->size > 0xFF)
997 BCI(PUSHW_1);
998 BCI(HIGH((hints_record + 1)->size));
999 BCI(LOW((hints_record + 1)->size));
1001 else
1003 BCI(PUSHB_1);
1004 BCI((hints_record + 1)->size);
1006 BCI(LT);
1007 BCI(IF);
1008 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1009 BCI(ELSE);
1011 hints_record++;
1014 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1016 for (i = 0; i < num_hints_records - 1; i++)
1017 BCI(EIF);
1019 return bufp;
1023 static void
1024 TA_free_hints_records(Hints_Record* hints_records,
1025 FT_UInt num_hints_records)
1027 FT_UInt i;
1030 for (i = 0; i < num_hints_records; i++)
1031 free(hints_records[i].buf);
1033 free(hints_records);
1037 static FT_Byte*
1038 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1039 TA_AxisHints axis,
1040 TA_Edge edge,
1041 FT_UInt* wraps)
1043 TA_Segment segments = axis->segments;
1044 TA_Segment seg;
1045 FT_UInt seg_idx;
1046 FT_UInt num_segs = 0;
1047 FT_UInt* wrap;
1050 seg_idx = edge->first - segments;
1052 /* we store everything as 16bit numbers */
1053 *(bufp++) = HIGH(seg_idx);
1054 *(bufp++) = LOW(seg_idx);
1056 /* wrap-around segments are stored as two segments */
1057 if (edge->first->first > edge->first->last)
1058 num_segs++;
1060 seg = edge->first->edge_next;
1061 while (seg != edge->first)
1063 num_segs++;
1065 if (seg->first > seg->last)
1066 num_segs++;
1068 seg = seg->edge_next;
1071 *(bufp++) = HIGH(num_segs);
1072 *(bufp++) = LOW(num_segs);
1074 if (edge->first->first > edge->first->last)
1076 /* emit second part of wrap-around segment; */
1077 /* the bytecode positions such segments after `normal' ones */
1078 wrap = wraps;
1079 for (;;)
1081 if (seg_idx == *wrap)
1082 break;
1083 wrap++;
1086 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1087 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1090 seg = edge->first->edge_next;
1091 while (seg != edge->first)
1093 seg_idx = seg - segments;
1095 *(bufp++) = HIGH(seg_idx);
1096 *(bufp++) = LOW(seg_idx);
1098 if (seg->first > seg->last)
1100 wrap = wraps;
1101 for (;;)
1103 if (seg_idx == *wrap)
1104 break;
1105 wrap++;
1108 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1109 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1112 seg = seg->edge_next;
1115 return bufp;
1119 static void
1120 TA_hints_recorder(TA_Action action,
1121 TA_GlyphHints hints,
1122 TA_Dimension dim,
1123 void* arg1,
1124 TA_Edge arg2,
1125 TA_Edge arg3,
1126 TA_Edge lower_bound,
1127 TA_Edge upper_bound)
1129 TA_AxisHints axis = &hints->axis[dim];
1130 TA_Edge edges = axis->edges;
1131 TA_Segment segments = axis->segments;
1132 TA_Point points = hints->points;
1134 Recorder* recorder = (Recorder*)hints->user;
1135 FONT* font = recorder->font;
1136 FT_UInt* wraps = recorder->wrap_around_segments;
1137 FT_Byte* p = recorder->hints_record.buf;
1139 FT_UInt* ip;
1140 FT_UInt* limit;
1143 if (dim == TA_DIMENSION_HORZ)
1144 return;
1146 /* we collect point hints for later processing */
1147 switch (action)
1149 case ta_ip_before:
1151 TA_Point point = (TA_Point)arg1;
1154 ip = recorder->ip_before_points;
1155 limit = ip + recorder->num_strong_points;
1156 for (; ip < limit; ip++)
1158 if (*ip == MISSING)
1160 *ip = point - points;
1161 break;
1165 return;
1167 case ta_ip_after:
1169 TA_Point point = (TA_Point)arg1;
1172 ip = recorder->ip_after_points;
1173 limit = ip + recorder->num_strong_points;
1174 for (; ip < limit; ip++)
1176 if (*ip == MISSING)
1178 *ip = point - points;
1179 break;
1183 return;
1185 case ta_ip_on:
1187 TA_Point point = (TA_Point)arg1;
1188 TA_Edge edge = arg2;
1191 ip = recorder->ip_on_point_array
1192 + recorder->num_strong_points
1193 * (edge - edges);
1194 limit = ip + recorder->num_strong_points;
1195 for (; ip < limit; ip++)
1197 if (*ip == MISSING)
1199 *ip = point - points;
1200 break;
1204 return;
1206 case ta_ip_between:
1208 TA_Point point = (TA_Point)arg1;
1209 TA_Edge before = arg2;
1210 TA_Edge after = arg3;
1213 /* note that `recorder->num_segments' has been used for allocation, */
1214 /* but `axis->num_edges' is used for accessing this array */
1215 ip = recorder->ip_between_point_array
1216 + recorder->num_strong_points * axis->num_edges
1217 * (before - edges)
1218 + recorder->num_strong_points
1219 * (after - edges);
1220 limit = ip + recorder->num_strong_points;
1221 for (; ip < limit; ip++)
1223 if (*ip == MISSING)
1225 *ip = point - points;
1226 break;
1230 return;
1232 case ta_bound:
1233 /* we ignore the BOUND action since we signal this information */
1234 /* with the proper function number */
1235 return;
1237 default:
1238 break;
1241 /* some enum values correspond to four or eight bytecode functions; */
1242 /* if the value is n, the function numbers are n, ..., n+7, */
1243 /* to be differentiated with flags */
1245 switch (action)
1247 case ta_link:
1249 TA_Edge base_edge = (TA_Edge)arg1;
1250 TA_Edge stem_edge = arg2;
1253 *(p++) = 0;
1254 *(p++) = (FT_Byte)action + ACTION_OFFSET
1255 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1256 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1258 *(p++) = HIGH(base_edge->first - segments);
1259 *(p++) = LOW(base_edge->first - segments);
1260 *(p++) = HIGH(stem_edge->first - segments);
1261 *(p++) = LOW(stem_edge->first - segments);
1263 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1265 break;
1267 case ta_anchor:
1269 TA_Edge edge = (TA_Edge)arg1;
1270 TA_Edge edge2 = arg2;
1273 *(p++) = 0;
1274 *(p++) = (FT_Byte)action + ACTION_OFFSET
1275 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1276 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1278 *(p++) = HIGH(edge->first - segments);
1279 *(p++) = LOW(edge->first - segments);
1280 *(p++) = HIGH(edge2->first - segments);
1281 *(p++) = LOW(edge2->first - segments);
1283 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1285 break;
1287 case ta_adjust:
1289 TA_Edge edge = (TA_Edge)arg1;
1290 TA_Edge edge2 = arg2;
1291 TA_Edge edge_minus_one = lower_bound;
1294 *(p++) = 0;
1295 *(p++) = (FT_Byte)action + ACTION_OFFSET
1296 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1297 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1298 + 4 * (edge_minus_one != NULL);
1300 *(p++) = HIGH(edge->first - segments);
1301 *(p++) = LOW(edge->first - segments);
1302 *(p++) = HIGH(edge2->first - segments);
1303 *(p++) = LOW(edge2->first - segments);
1305 if (edge_minus_one)
1307 *(p++) = HIGH(edge_minus_one->first - segments);
1308 *(p++) = LOW(edge_minus_one->first - segments);
1311 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1313 break;
1315 case ta_blue_anchor:
1317 TA_Edge edge = (TA_Edge)arg1;
1318 TA_Edge blue = arg2;
1321 *(p++) = 0;
1322 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1324 *(p++) = HIGH(blue->first - segments);
1325 *(p++) = LOW(blue->first - segments);
1327 if (edge->best_blue_is_shoot)
1329 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1330 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1332 else
1334 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1335 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1338 *(p++) = HIGH(edge->first - segments);
1339 *(p++) = LOW(edge->first - segments);
1341 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1343 break;
1345 case ta_stem:
1347 TA_Edge edge = (TA_Edge)arg1;
1348 TA_Edge edge2 = arg2;
1349 TA_Edge edge_minus_one = lower_bound;
1352 *(p++) = 0;
1353 *(p++) = (FT_Byte)action + ACTION_OFFSET
1354 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1355 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1356 + 4 * (edge_minus_one != NULL);
1358 *(p++) = HIGH(edge->first - segments);
1359 *(p++) = LOW(edge->first - segments);
1360 *(p++) = HIGH(edge2->first - segments);
1361 *(p++) = LOW(edge2->first - segments);
1363 if (edge_minus_one)
1365 *(p++) = HIGH(edge_minus_one->first - segments);
1366 *(p++) = LOW(edge_minus_one->first - segments);
1369 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1370 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1372 break;
1374 case ta_blue:
1376 TA_Edge edge = (TA_Edge)arg1;
1379 *(p++) = 0;
1380 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1382 if (edge->best_blue_is_shoot)
1384 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1385 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1387 else
1389 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1390 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1393 *(p++) = HIGH(edge->first - segments);
1394 *(p++) = LOW(edge->first - segments);
1396 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1398 break;
1400 case ta_serif:
1402 TA_Edge serif = (TA_Edge)arg1;
1403 TA_Edge base = serif->serif;
1406 *(p++) = 0;
1407 *(p++) = (FT_Byte)action + ACTION_OFFSET
1408 + (lower_bound != NULL)
1409 + 2 * (upper_bound != NULL);
1411 *(p++) = HIGH(serif->first - segments);
1412 *(p++) = LOW(serif->first - segments);
1413 *(p++) = HIGH(base->first - segments);
1414 *(p++) = LOW(base->first - segments);
1416 if (lower_bound)
1418 *(p++) = HIGH(lower_bound->first - segments);
1419 *(p++) = LOW(lower_bound->first - segments);
1421 if (upper_bound)
1423 *(p++) = HIGH(upper_bound->first - segments);
1424 *(p++) = LOW(upper_bound->first - segments);
1427 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1429 break;
1431 case ta_serif_anchor:
1432 case ta_serif_link2:
1434 TA_Edge edge = (TA_Edge)arg1;
1437 *(p++) = 0;
1438 *(p++) = (FT_Byte)action + ACTION_OFFSET
1439 + (lower_bound != NULL)
1440 + 2 * (upper_bound != NULL);
1442 *(p++) = HIGH(edge->first - segments);
1443 *(p++) = LOW(edge->first - segments);
1445 if (lower_bound)
1447 *(p++) = HIGH(lower_bound->first - segments);
1448 *(p++) = LOW(lower_bound->first - segments);
1450 if (upper_bound)
1452 *(p++) = HIGH(upper_bound->first - segments);
1453 *(p++) = LOW(upper_bound->first - segments);
1456 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1458 break;
1460 case ta_serif_link1:
1462 TA_Edge edge = (TA_Edge)arg1;
1463 TA_Edge before = arg2;
1464 TA_Edge after = arg3;
1467 *(p++) = 0;
1468 *(p++) = (FT_Byte)action + ACTION_OFFSET
1469 + (lower_bound != NULL)
1470 + 2 * (upper_bound != NULL);
1472 *(p++) = HIGH(before->first - segments);
1473 *(p++) = LOW(before->first - segments);
1474 *(p++) = HIGH(edge->first - segments);
1475 *(p++) = LOW(edge->first - segments);
1476 *(p++) = HIGH(after->first - segments);
1477 *(p++) = LOW(after->first - segments);
1479 if (lower_bound)
1481 *(p++) = HIGH(lower_bound->first - segments);
1482 *(p++) = LOW(lower_bound->first - segments);
1484 if (upper_bound)
1486 *(p++) = HIGH(upper_bound->first - segments);
1487 *(p++) = LOW(upper_bound->first - segments);
1490 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1492 break;
1494 default:
1495 /* there are more cases in the enumeration */
1496 /* which are handled with flags */
1497 break;
1500 recorder->hints_record.num_actions++;
1501 recorder->hints_record.buf = p;
1505 static FT_Error
1506 TA_init_recorder(Recorder* recorder,
1507 FONT* font,
1508 GLYPH* glyph,
1509 TA_GlyphHints hints)
1511 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1512 TA_Point points = hints->points;
1513 TA_Point point_limit = points + hints->num_points;
1514 TA_Point point;
1516 TA_Segment segments = axis->segments;
1517 TA_Segment seg_limit = segments + axis->num_segments;
1518 TA_Segment seg;
1520 FT_UInt num_strong_points = 0;
1521 FT_UInt* wrap_around_segment;
1523 recorder->font = font;
1524 recorder->glyph = glyph;
1525 recorder->num_segments = axis->num_segments;
1527 recorder->ip_before_points = NULL;
1528 recorder->ip_after_points = NULL;
1529 recorder->ip_on_point_array = NULL;
1530 recorder->ip_between_point_array = NULL;
1532 recorder->num_stack_elements = 0;
1534 /* no need to clean up allocated arrays in case of error; */
1535 /* this is handled later by `TA_free_recorder' */
1537 recorder->num_wrap_around_segments = 0;
1538 for (seg = segments; seg < seg_limit; seg++)
1539 if (seg->first > seg->last)
1540 recorder->num_wrap_around_segments++;
1542 recorder->wrap_around_segments =
1543 (FT_UInt*)malloc(recorder->num_wrap_around_segments * sizeof (FT_UInt));
1544 if (!recorder->wrap_around_segments)
1545 return FT_Err_Out_Of_Memory;
1547 wrap_around_segment = recorder->wrap_around_segments;
1548 for (seg = segments; seg < seg_limit; seg++)
1549 if (seg->first > seg->last)
1550 *(wrap_around_segment++) = seg - segments;
1552 /* get number of strong points */
1553 for (point = points; point < point_limit; point++)
1555 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1556 /* however, this value isn't known yet */
1557 /* (or rather, it can vary between different pixel sizes) */
1558 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1559 continue;
1561 num_strong_points++;
1564 recorder->num_strong_points = num_strong_points;
1566 recorder->ip_before_points =
1567 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1568 if (!recorder->ip_before_points)
1569 return FT_Err_Out_Of_Memory;
1571 recorder->ip_after_points =
1572 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1573 if (!recorder->ip_after_points)
1574 return FT_Err_Out_Of_Memory;
1576 /* actually, we need `hints->num_edges' for the array sizes; */
1577 /* however, this value isn't known yet */
1578 /* (or rather, it can vary between different pixel sizes) */
1579 recorder->ip_on_point_array =
1580 (FT_UInt*)malloc(axis->num_segments
1581 * num_strong_points * sizeof (FT_UInt));
1582 if (!recorder->ip_on_point_array)
1583 return FT_Err_Out_Of_Memory;
1585 recorder->ip_between_point_array =
1586 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1587 * num_strong_points * sizeof (FT_UInt));
1588 if (!recorder->ip_between_point_array)
1589 return FT_Err_Out_Of_Memory;
1591 return FT_Err_Ok;
1595 static void
1596 TA_reset_recorder(Recorder* recorder,
1597 FT_Byte* bufp)
1599 recorder->hints_record.buf = bufp;
1600 recorder->hints_record.num_actions = 0;
1604 static void
1605 TA_rewind_recorder(Recorder* recorder,
1606 FT_Byte* bufp,
1607 FT_UInt size)
1609 TA_reset_recorder(recorder, bufp);
1611 recorder->hints_record.size = size;
1613 /* We later check with MISSING (which expands to 0xFF bytes) */
1615 memset(recorder->ip_before_points, 0xFF,
1616 recorder->num_strong_points * sizeof (FT_UInt));
1617 memset(recorder->ip_after_points, 0xFF,
1618 recorder->num_strong_points * sizeof (FT_UInt));
1620 memset(recorder->ip_on_point_array, 0xFF,
1621 recorder->num_segments
1622 * recorder->num_strong_points * sizeof (FT_UInt));
1623 memset(recorder->ip_between_point_array, 0xFF,
1624 recorder->num_segments * recorder->num_segments
1625 * recorder->num_strong_points * sizeof (FT_UInt));
1629 static void
1630 TA_free_recorder(Recorder* recorder)
1632 free(recorder->wrap_around_segments);
1634 free(recorder->ip_before_points);
1635 free(recorder->ip_after_points);
1636 free(recorder->ip_on_point_array);
1637 free(recorder->ip_between_point_array);
1641 FT_Error
1642 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1643 FONT* font,
1644 FT_Long idx)
1646 FT_Face face = sfnt->face;
1647 FT_Error error;
1649 FT_Byte* ins_buf;
1650 FT_UInt ins_len;
1651 FT_Byte* bufp;
1652 FT_Byte* p;
1654 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1655 glyf_Data* data = (glyf_Data*)glyf_table->data;
1656 /* `idx' is never negative */
1657 GLYPH* glyph = &data->glyphs[idx];
1659 TA_GlyphHints hints;
1661 FT_UInt num_action_hints_records;
1662 FT_UInt num_point_hints_records;
1663 Hints_Record* action_hints_records;
1664 Hints_Record* point_hints_records;
1666 Recorder recorder;
1667 FT_UInt num_stack_elements;
1668 FT_Bool optimize = 0;
1670 FT_Int32 load_flags;
1671 FT_UInt size;
1673 FT_Byte* pos[3];
1676 /* XXX: right now, we abuse this flag to control */
1677 /* the global behaviour of the auto-hinter */
1678 load_flags = font->fallback_script << 30;
1679 load_flags |= 1 << 28; /* vertical hinting only */
1680 if (font->increase_x_height)
1681 load_flags |= 1 << 29;
1682 if (!font->pre_hinting)
1683 load_flags |= FT_LOAD_NO_SCALE;
1685 /* computing the segments is resolution independent, */
1686 /* thus the pixel size in this call is arbitrary */
1687 error = FT_Set_Pixel_Sizes(face, 20, 20);
1688 if (error)
1689 return error;
1691 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1692 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1693 if (error)
1694 return error;
1696 /* do nothing if we have an empty glyph */
1697 if (!face->glyph->outline.n_contours)
1698 return FT_Err_Ok;
1700 hints = &font->loader->hints;
1702 /* do nothing if the setup delivered the dummy module only */
1703 if (!hints->num_points)
1704 return FT_Err_Ok;
1706 /* we allocate a buffer which is certainly large enough */
1707 /* to hold all of the created bytecode instructions; */
1708 /* later on it gets reallocated to its real size */
1709 ins_len = hints->num_points * 1000;
1710 ins_buf = (FT_Byte*)malloc(ins_len);
1711 if (!ins_buf)
1712 return FT_Err_Out_Of_Memory;
1714 /* initialize array with an invalid bytecode */
1715 /* so that we can easily find the array length at reallocation time */
1716 memset(ins_buf, INS_A0, ins_len);
1718 /* handle composite glyph */
1719 if (font->loader->gloader->base.num_subglyphs)
1721 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1722 if (!bufp)
1724 error = FT_Err_Out_Of_Memory;
1725 goto Err;
1728 goto Done1;
1731 /* only scale the glyph if the dummy hinter has been used */
1732 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1734 /* since `TA_init_recorder' hasn't been called yet, */
1735 /* we manually initialize the `glyph' field */
1736 recorder.glyph = glyph;
1738 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1739 if (!bufp)
1741 error = FT_Err_Out_Of_Memory;
1742 goto Err;
1745 goto Done1;
1748 error = TA_init_recorder(&recorder, font, glyph, hints);
1749 if (error)
1750 goto Err;
1752 /* loop over a large range of pixel sizes */
1753 /* to find hints records which get pushed onto the bytecode stack */
1755 #ifdef DEBUGGING
1757 int num_chars, i;
1760 num_chars = fprintf(stderr, "glyph %ld\n", idx);
1761 for (i = 0; i < num_chars - 1; i++)
1762 putc('=', stderr);
1763 fprintf(stderr, "\n\n");
1766 #endif
1768 /* we temporarily use `ins_buf' to record the current glyph hints */
1769 ta_loader_register_hints_recorder(font->loader,
1770 TA_hints_recorder,
1771 (void*)&recorder);
1773 num_action_hints_records = 0;
1774 num_point_hints_records = 0;
1775 action_hints_records = NULL;
1776 point_hints_records = NULL;
1778 for (size = font->hinting_range_min;
1779 size <= font->hinting_range_max;
1780 size++)
1782 #ifdef DEBUGGING
1783 int have_dumps = 0;
1784 #endif
1787 TA_rewind_recorder(&recorder, ins_buf, size);
1789 error = FT_Set_Pixel_Sizes(face, size, size);
1790 if (error)
1791 goto Err;
1793 /* calling `ta_loader_load_glyph' uses the */
1794 /* `TA_hints_recorder' function as a callback, */
1795 /* modifying `hints_record' */
1796 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1797 if (error)
1798 goto Err;
1800 if (TA_hints_record_is_different(action_hints_records,
1801 num_action_hints_records,
1802 ins_buf, recorder.hints_record.buf))
1804 #ifdef DEBUGGING
1806 have_dumps = 1;
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);
1814 fprintf(stderr, " action hints record:\n");
1815 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1816 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1817 fprintf(stderr, "\n");
1819 #endif
1821 error = TA_add_hints_record(&action_hints_records,
1822 &num_action_hints_records,
1823 ins_buf, recorder.hints_record);
1824 if (error)
1825 goto Err;
1828 /* now handle point records */
1830 TA_reset_recorder(&recorder, ins_buf);
1832 /* use the point hints data collected in `TA_hints_recorder' */
1833 TA_build_point_hints(&recorder, hints);
1835 if (TA_hints_record_is_different(point_hints_records,
1836 num_point_hints_records,
1837 ins_buf, recorder.hints_record.buf))
1839 #ifdef DEBUGGING
1841 if (!have_dumps)
1843 fprintf(stderr, " size %d:\n", size);
1845 ta_glyph_hints_dump_edges(_ta_debug_hints);
1846 ta_glyph_hints_dump_segments(_ta_debug_hints);
1847 ta_glyph_hints_dump_points(_ta_debug_hints);
1850 fprintf(stderr, " point hints record:\n");
1851 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1852 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1853 fprintf(stderr, "\n");
1855 #endif
1857 error = TA_add_hints_record(&point_hints_records,
1858 &num_point_hints_records,
1859 ins_buf, recorder.hints_record);
1860 if (error)
1861 goto Err;
1865 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1867 /* since we only have a single empty record we just scale the glyph */
1868 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1869 if (!bufp)
1871 error = FT_Err_Out_Of_Memory;
1872 goto Err;
1875 /* clear the rest of the temporarily used part of `ins_buf' */
1876 p = bufp;
1877 while (*p != INS_A0)
1878 *(p++) = INS_A0;
1880 goto Done;
1883 /* if there is only a single record, */
1884 /* we do a global optimization later on */
1885 if (num_action_hints_records > 1)
1886 optimize = 1;
1888 /* store the hints records and handle stack depth */
1889 pos[0] = ins_buf;
1890 bufp = TA_emit_hints_records(&recorder,
1891 point_hints_records,
1892 num_point_hints_records,
1893 ins_buf,
1894 optimize);
1896 num_stack_elements = recorder.num_stack_elements;
1897 recorder.num_stack_elements = 0;
1899 pos[1] = bufp;
1900 bufp = TA_emit_hints_records(&recorder,
1901 action_hints_records,
1902 num_action_hints_records,
1903 bufp,
1904 optimize);
1906 recorder.num_stack_elements += num_stack_elements;
1908 pos[2] = bufp;
1909 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
1910 if (!bufp)
1912 error = FT_Err_Out_Of_Memory;
1913 goto Err;
1916 /* XXX improve handling of NPUSHW */
1917 if (num_action_hints_records == 1
1918 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1921 * we optimize two common cases, replacing
1923 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1925 * with
1927 * NPUSHB (A+B[+C]) ... CALL
1929 * if possible
1931 FT_Byte sizes[3];
1932 FT_Byte new_size1;
1933 FT_Byte new_size2;
1935 FT_UInt sum;
1936 FT_UInt i;
1937 FT_UInt pos_idx;
1940 /* the point hints records block can be missing */
1941 if (pos[0] == pos[1])
1943 pos[1] = pos[2];
1944 pos[2] = NULL;
1947 /* there are at least two NPUSHB instructions */
1948 /* (one of them directly at the start) */
1949 sizes[0] = *(pos[0] + 1);
1950 sizes[1] = *(pos[1] + 1);
1951 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
1953 sum = sizes[0] + sizes[1] + sizes[2];
1955 if (sum > 2 * 0xFF)
1956 goto Done2; /* nothing to do since we need three NPUSHB */
1957 else if (!sizes[2] && (sum > 0xFF))
1958 goto Done2; /* nothing to do since we need two NPUSHB */
1960 if (sum > 0xFF)
1962 /* reduce three NPUSHB to two */
1963 new_size1 = 0xFF;
1964 new_size2 = sum - 0xFF;
1966 else
1968 /* reduce two or three NPUSHB to one */
1969 new_size1 = sum;
1970 new_size2 = 0;
1973 /* pack data */
1974 p = ins_buf;
1975 bufp = ins_buf;
1976 pos_idx = 0;
1978 if (new_size1 <= 8)
1979 BCI(PUSHB_1 - 1 + new_size1);
1980 else
1982 BCI(NPUSHB);
1983 BCI(new_size1);
1985 for (i = 0; i < new_size1; i++)
1987 if (p == pos[pos_idx])
1989 pos_idx++;
1990 p += 2; /* skip old NPUSHB */
1992 *(bufp++) = *(p++);
1995 if (new_size2)
1997 if (new_size2 <= 8)
1998 BCI(PUSHB_1 - 1 + new_size2);
1999 else
2001 BCI(NPUSHB);
2002 BCI(new_size2);
2004 for (i = 0; i < new_size2; i++)
2006 if (p == pos[pos_idx])
2008 pos_idx++;
2009 p += 2;
2011 *(bufp++) = *(p++);
2015 BCI(CALL);
2018 Done2:
2019 /* clear the rest of the temporarily used part of `ins_buf' */
2020 p = bufp;
2021 while (*p != INS_A0)
2022 *(p++) = INS_A0;
2024 Done:
2025 TA_free_hints_records(action_hints_records, num_action_hints_records);
2026 TA_free_recorder(&recorder);
2028 /* we are done, so reallocate the instruction array to its real size */
2029 if (*bufp == INS_A0)
2031 /* search backwards */
2032 while (*bufp == INS_A0)
2033 bufp--;
2034 bufp++;
2036 else
2038 /* search forwards */
2039 while (*bufp != INS_A0)
2040 bufp++;
2043 Done1:
2044 ins_len = bufp - ins_buf;
2046 if (ins_len > sfnt->max_instructions)
2047 sfnt->max_instructions = ins_len;
2049 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2050 glyph->ins_len = ins_len;
2052 return FT_Err_Ok;
2054 Err:
2055 TA_free_hints_records(action_hints_records, num_action_hints_records);
2056 TA_free_recorder(&recorder);
2057 free(ins_buf);
2059 return error;
2063 /* end of tabytecode.c */