Support multiple scripts. [2/7]
[ttfautohint.git] / lib / tabytecode.c
blob5871ad0283a274d139f119e64486dd4287051cc8
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2013 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_UShort)~0
24 #define DEBUGGING
27 #ifdef TA_DEBUG
28 int _ta_debug = 0;
29 int _ta_debug_disable_horz_hints;
30 int _ta_debug_disable_vert_hints;
31 int _ta_debug_disable_blue_hints;
32 void* _ta_debug_hints;
33 #endif
36 typedef struct Hints_Record_
38 FT_UInt size;
39 FT_UInt num_actions;
40 FT_Byte* buf;
41 FT_UInt buf_len;
42 } Hints_Record;
44 typedef struct Recorder_
46 SFNT* sfnt;
47 FONT* font;
48 GLYPH* glyph; /* the current glyph */
49 Hints_Record hints_record;
51 /* some segments can `wrap around' */
52 /* a contour's start point like 24-25-26-0-1-2 */
53 /* (there can be at most one such segment per contour); */
54 /* later on we append additional records */
55 /* to split them into 24-26 and 0-2 */
56 FT_UShort* wrap_around_segments;
57 FT_UShort num_wrap_around_segments;
59 FT_UShort num_stack_elements; /* the necessary stack depth so far */
61 /* data necessary for strong point interpolation */
62 FT_UShort* ip_before_points;
63 FT_UShort* ip_after_points;
64 FT_UShort* ip_on_point_array;
65 FT_UShort* ip_between_point_array;
67 FT_UShort num_strong_points;
68 FT_UShort num_segments;
69 } Recorder;
72 /* this is the bytecode of the `.ttfautohint' glyph */
74 FT_Byte ttfautohint_glyph_bytecode[7] =
77 /* increment `cvtl_is_subglyph' counter */
78 PUSHB_3,
79 cvtl_is_subglyph,
81 cvtl_is_subglyph,
82 RCVT,
83 ADD,
84 WCVTP,
90 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
91 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
92 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
93 * PUSHW_X gets used
96 FT_Byte*
97 TA_build_push(FT_Byte* bufp,
98 FT_UInt* args,
99 FT_UInt num_args,
100 FT_Bool need_words,
101 FT_Bool optimize)
103 FT_UInt* arg = args;
104 FT_UInt i, j, nargs;
107 if (need_words)
109 for (i = 0; i < num_args; i += 255)
111 nargs = (num_args - i > 255) ? 255 : num_args - i;
113 if (optimize && nargs <= 8)
114 BCI(PUSHW_1 - 1 + nargs);
115 else
117 BCI(NPUSHW);
118 BCI(nargs);
120 for (j = 0; j < nargs; j++)
122 BCI(HIGH(*arg));
123 BCI(LOW(*arg));
124 arg++;
128 else
130 for (i = 0; i < num_args; i += 255)
132 nargs = (num_args - i > 255) ? 255 : num_args - i;
134 if (optimize && nargs <= 8)
135 BCI(PUSHB_1 - 1 + nargs);
136 else
138 BCI(NPUSHB);
139 BCI(nargs);
141 for (j = 0; j < nargs; j++)
143 BCI(*arg);
144 arg++;
149 return bufp;
153 /* We add a subglyph for each composite glyph. */
154 /* Since subglyphs must contain at least one point, */
155 /* we have to adjust all point indices accordingly. */
156 /* Using the `pointsums' array of the `GLYPH' structure */
157 /* it is straightforward to do that: */
158 /* Assuming that point with index x is in the interval */
159 /* pointsums[n] <= x < pointsums[n + 1], */
160 /* the new point index is x + n. */
162 static FT_UInt
163 TA_adjust_point_index(Recorder* recorder,
164 FT_UInt idx)
166 FONT* font = recorder->font;
167 GLYPH* glyph = recorder->glyph;
168 FT_UShort i;
171 if (!glyph->num_components || !font->hint_composites)
172 return idx; /* not a composite glyph */
174 for (i = 0; i < glyph->num_pointsums; i++)
175 if (idx < glyph->pointsums[i])
176 break;
178 return idx + i;
182 /* we store the segments in the storage area; */
183 /* each segment record consists of the first and last point */
185 static FT_Byte*
186 TA_sfnt_build_glyph_segments(SFNT* sfnt,
187 Recorder* recorder,
188 FT_Byte* bufp,
189 FT_Bool optimize)
191 FONT* font = recorder->font;
192 TA_GlyphHints hints = &font->loader->hints;
193 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
194 TA_Point points = hints->points;
195 TA_Segment segments = axis->segments;
196 TA_Segment seg;
197 TA_Segment seg_limit;
199 FT_Outline outline = font->loader->gloader->base.outline;
201 FT_UInt* args;
202 FT_UInt* arg;
203 FT_UInt num_args;
204 FT_UShort num_segments;
206 FT_Bool need_words = 0;
208 FT_Int n;
209 FT_UInt base;
210 FT_UShort num_packed_segments;
211 FT_UShort num_storage;
212 FT_UShort num_stack_elements;
213 FT_UShort num_twilight_points;
216 seg_limit = segments + axis->num_segments;
217 num_segments = axis->num_segments;
219 /* to pack the data in the bytecode more tightly, */
220 /* we store up to the first nine segments in nibbles if possible, */
221 /* using delta values */
222 base = 0;
223 num_packed_segments = 0;
224 for (seg = segments; seg < seg_limit; seg++)
226 FT_UInt first = seg->first - points;
227 FT_UInt last = seg->last - points;
230 first = TA_adjust_point_index(recorder, first);
231 last = TA_adjust_point_index(recorder, last);
233 if (first - base >= 16)
234 break;
235 if (first > last || last - first >= 16)
236 break;
237 if (num_packed_segments == 9)
238 break;
239 num_packed_segments++;
240 base = last;
243 /* also handle wrap-around segments */
244 num_segments += recorder->num_wrap_around_segments;
246 /* wrap-around segments are pushed with four arguments; */
247 /* a segment stored in nibbles needs only one byte instead of two */
248 num_args = num_packed_segments
249 + 2 * (num_segments - num_packed_segments)
250 + 2 * recorder->num_wrap_around_segments
251 + 2;
253 /* collect all arguments temporarily in an array (in reverse order) */
254 /* so that we can easily split into chunks of 255 args */
255 /* as needed by NPUSHB and NPUSHW, respectively */
256 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
257 if (!args)
258 return NULL;
260 arg = args + num_args - 1;
262 if (num_segments > 0xFF)
263 need_words = 1;
265 /* the number of packed segments is indicated by the function number */
266 if (recorder->glyph->num_components && font->hint_composites)
267 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
268 else
269 *(arg--) = bci_create_segments_0 + num_packed_segments;
270 *(arg--) = num_segments;
272 base = 0;
273 for (seg = segments; seg < segments + num_packed_segments; seg++)
275 FT_UInt first = seg->first - points;
276 FT_UInt last = seg->last - points;
277 FT_UInt low_nibble;
278 FT_UInt high_nibble;
281 first = TA_adjust_point_index(recorder, first);
282 last = TA_adjust_point_index(recorder, last);
284 low_nibble = first - base;
285 high_nibble = last - first;
287 *(arg--) = 16 * high_nibble + low_nibble;
289 base = last;
292 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
294 FT_UInt first = seg->first - points;
295 FT_UInt last = seg->last - points;
298 *(arg--) = TA_adjust_point_index(recorder, first);
299 *(arg--) = TA_adjust_point_index(recorder, last);
301 /* we push the last and first contour point */
302 /* as a third and fourth argument in wrap-around segments */
303 if (first > last)
305 for (n = 0; n < outline.n_contours; n++)
307 FT_UInt end = (FT_UInt)outline.contours[n];
310 if (first <= end)
312 *(arg--) = TA_adjust_point_index(recorder, end);
313 if (end > 0xFF)
314 need_words = 1;
316 if (n == 0)
317 *(arg--) = TA_adjust_point_index(recorder, 0);
318 else
319 *(arg--) = TA_adjust_point_index(recorder,
320 (FT_UInt)outline.contours[n - 1] + 1);
321 break;
326 if (last > 0xFF)
327 need_words = 1;
330 /* emit the second part of wrap-around segments as separate segments */
331 /* so that edges can easily link to them */
332 for (seg = segments; seg < seg_limit; seg++)
334 FT_UInt first = seg->first - points;
335 FT_UInt last = seg->last - points;
338 if (first > last)
340 for (n = 0; n < outline.n_contours; n++)
342 if (first <= (FT_UInt)outline.contours[n])
344 if (n == 0)
345 *(arg--) = TA_adjust_point_index(recorder, 0);
346 else
347 *(arg--) = TA_adjust_point_index(recorder,
348 (FT_UInt)outline.contours[n - 1] + 1);
349 break;
353 *(arg--) = TA_adjust_point_index(recorder, last);
357 /* with most fonts it is very rare */
358 /* that any of the pushed arguments is larger than 0xFF, */
359 /* thus we refrain from further optimizing this case */
360 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
362 BCI(CALL);
364 num_storage = sal_segment_offset + num_segments * 2;
365 if (num_storage > sfnt->max_storage)
366 sfnt->max_storage = num_storage;
368 num_twilight_points = num_segments * 2;
369 if (num_twilight_points > sfnt->max_twilight_points)
370 sfnt->max_twilight_points = num_twilight_points;
372 /* both this function and `TA_emit_hints_record' */
373 /* push data onto the stack */
374 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
375 + recorder->num_stack_elements + num_args;
376 if (num_stack_elements > sfnt->max_stack_elements)
377 sfnt->max_stack_elements = num_stack_elements;
379 free(args);
381 return bufp;
385 static FT_Byte*
386 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
387 Recorder* recorder,
388 FT_Byte* bufp)
390 FONT* font = recorder->font;
391 FT_GlyphSlot glyph = sfnt->face->glyph;
392 FT_Vector* points = glyph->outline.points;
393 FT_Int num_contours = glyph->outline.n_contours;
395 FT_UInt* args;
396 FT_UInt* arg;
397 FT_UInt num_args;
399 FT_Bool need_words = 0;
400 FT_Int p, q;
401 FT_Int start, end;
402 FT_UShort num_stack_elements;
405 num_args = 2 * num_contours + 2;
407 /* collect all arguments temporarily in an array (in reverse order) */
408 /* so that we can easily split into chunks of 255 args */
409 /* as needed by NPUSHB and NPUSHW, respectively */
410 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
411 if (!args)
412 return NULL;
414 arg = args + num_args - 1;
416 if (num_args > 0xFF)
417 need_words = 1;
419 if (recorder->glyph->num_components && font->hint_composites)
420 *(arg--) = bci_scale_composite_glyph;
421 else
422 *(arg--) = bci_scale_glyph;
423 *(arg--) = num_contours;
425 start = 0;
426 end = 0;
428 for (p = 0; p < num_contours; p++)
430 FT_Int max = start;
431 FT_Int min = start;
434 end = glyph->outline.contours[p];
436 for (q = start; q <= end; q++)
438 if (points[q].y < points[min].y)
439 min = q;
440 if (points[q].y > points[max].y)
441 max = q;
444 if (min > max)
446 *(arg--) = TA_adjust_point_index(recorder, max);
447 *(arg--) = TA_adjust_point_index(recorder, min);
449 else
451 *(arg--) = TA_adjust_point_index(recorder, min);
452 *(arg--) = TA_adjust_point_index(recorder, max);
455 start = end + 1;
458 if (end > 0xFF)
459 need_words = 1;
461 /* with most fonts it is very rare */
462 /* that any of the pushed arguments is larger than 0xFF, */
463 /* thus we refrain from further optimizing this case */
464 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
466 BCI(CALL);
468 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
469 if (num_stack_elements > sfnt->max_stack_elements)
470 sfnt->max_stack_elements = num_stack_elements;
472 free(args);
474 return bufp;
478 static FT_Byte*
479 TA_font_build_subglyph_shifter(FONT* font,
480 FT_Byte* bufp)
482 FT_Face face = font->loader->face;
483 FT_GlyphSlot glyph = face->glyph;
485 TA_GlyphLoader gloader = font->loader->gloader;
487 TA_SubGlyph subglyphs = gloader->base.subglyphs;
488 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
489 TA_SubGlyph subglyph;
491 FT_Int curr_contour = 0;
494 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
496 FT_Error error;
498 FT_UShort flags = subglyph->flags;
499 FT_Pos y_offset = subglyph->arg2;
501 FT_Int num_contours;
504 /* load subglyph to get the number of contours */
505 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
506 if (error)
507 return NULL;
508 num_contours = glyph->outline.n_contours;
510 /* nothing to do if there is a point-to-point alignment */
511 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
512 goto End;
514 /* nothing to do if y offset is zero */
515 if (!y_offset)
516 goto End;
518 /* nothing to do if there are no contours */
519 if (!num_contours)
520 goto End;
522 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
523 /* ensures that composite subglyphs are represented as simple glyphs */
525 if (num_contours > 0xFF
526 || curr_contour > 0xFF)
528 BCI(PUSHW_2);
529 BCI(HIGH(curr_contour));
530 BCI(LOW(curr_contour));
531 BCI(HIGH(num_contours));
532 BCI(LOW(num_contours));
534 else
536 BCI(PUSHB_2);
537 BCI(curr_contour);
538 BCI(num_contours);
541 /* there are high chances that this value needs PUSHW, */
542 /* thus we handle it separately */
543 if (y_offset > 0xFF || y_offset < 0)
545 BCI(PUSHW_1);
546 BCI(HIGH(y_offset));
547 BCI(LOW(y_offset));
549 else
551 BCI(PUSHB_1);
552 BCI(y_offset);
555 BCI(PUSHB_1);
556 BCI(bci_shift_subglyph);
557 BCI(CALL);
559 End:
560 curr_contour += num_contours;
563 return bufp;
568 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
569 * data in four arrays (which are simple but waste a lot of memory). The
570 * function below converts them into bytecode.
572 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
573 * together with the edge they correspond to.
575 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
576 * loop over the edge or edge pairs, respectively, and each edge or edge
577 * pair contains an inner loop to emit the correponding points.
580 static void
581 TA_build_point_hints(Recorder* recorder,
582 TA_GlyphHints hints)
584 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
585 TA_Segment segments = axis->segments;
586 TA_Edge edges = axis->edges;
588 TA_Edge edge;
590 FT_Byte* p = recorder->hints_record.buf;
591 FT_UShort num_edges = axis->num_edges;
592 FT_UShort num_strong_points = recorder->num_strong_points;
594 FT_UShort i;
595 FT_UShort j;
596 FT_UShort k;
598 FT_UShort* ip;
599 FT_UShort* iq;
600 FT_UShort* ir;
601 FT_UShort* ip_limit;
602 FT_UShort* iq_limit;
603 FT_UShort* ir_limit;
606 /* we store everything as 16bit numbers; */
607 /* the function numbers (`ta_ip_before', etc.) */
608 /* reflect the order in the TA_Action enumeration */
610 /* ip_before_points */
612 i = 0;
613 ip = recorder->ip_before_points;
614 ip_limit = ip + num_strong_points;
615 for (; ip < ip_limit; ip++)
617 if (*ip != MISSING)
618 i++;
619 else
620 break;
623 if (i)
625 recorder->hints_record.num_actions++;
627 edge = edges;
629 *(p++) = 0;
630 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
631 *(p++) = HIGH(edge->first - segments);
632 *(p++) = LOW(edge->first - segments);
633 *(p++) = HIGH(i);
634 *(p++) = LOW(i);
636 ip = recorder->ip_before_points;
637 ip_limit = ip + i;
638 for (; ip < ip_limit; ip++)
640 FT_UInt point = TA_adjust_point_index(recorder, *ip);
643 *(p++) = HIGH(point);
644 *(p++) = LOW(point);
648 /* ip_after_points */
650 i = 0;
651 ip = recorder->ip_after_points;
652 ip_limit = ip + num_strong_points;
653 for (; ip < ip_limit; ip++)
655 if (*ip != MISSING)
656 i++;
657 else
658 break;
661 if (i)
663 recorder->hints_record.num_actions++;
665 edge = edges + axis->num_edges - 1;
667 *(p++) = 0;
668 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
669 *(p++) = HIGH(edge->first - segments);
670 *(p++) = LOW(edge->first - segments);
671 *(p++) = HIGH(i);
672 *(p++) = LOW(i);
674 ip = recorder->ip_after_points;
675 ip_limit = ip + i;
676 for (; ip < ip_limit; ip++)
678 FT_UInt point = TA_adjust_point_index(recorder, *ip);
681 *(p++) = HIGH(point);
682 *(p++) = LOW(point);
686 /* ip_on_point_array */
688 i = 0;
689 ip = recorder->ip_on_point_array;
690 ip_limit = ip + num_edges * num_strong_points;
691 for (; ip < ip_limit; ip += num_strong_points)
692 if (*ip != MISSING)
693 i++;
695 if (i)
697 recorder->hints_record.num_actions++;
699 *(p++) = 0;
700 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
701 *(p++) = HIGH(i);
702 *(p++) = LOW(i);
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, i++)
709 if (*ip == MISSING)
710 continue;
712 edge = edges + i;
714 *(p++) = HIGH(edge->first - segments);
715 *(p++) = LOW(edge->first - segments);
717 j = 0;
718 iq = ip;
719 iq_limit = iq + num_strong_points;
720 for (; iq < iq_limit; iq++)
722 if (*iq != MISSING)
723 j++;
724 else
725 break;
728 *(p++) = HIGH(j);
729 *(p++) = LOW(j);
731 iq = ip;
732 iq_limit = iq + j;
733 for (; iq < iq_limit; iq++)
735 FT_UInt point = TA_adjust_point_index(recorder, *iq);
738 *(p++) = HIGH(point);
739 *(p++) = LOW(point);
744 /* ip_between_point_array */
746 i = 0;
747 ip = recorder->ip_between_point_array;
748 ip_limit = ip + num_edges * num_edges * num_strong_points;
749 for (; ip < ip_limit; ip += num_strong_points)
750 if (*ip != MISSING)
751 i++;
753 if (i)
755 recorder->hints_record.num_actions++;
757 *(p++) = 0;
758 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
759 *(p++) = HIGH(i);
760 *(p++) = LOW(i);
762 i = 0;
763 ip = recorder->ip_between_point_array;
764 ip_limit = ip + num_edges * num_edges * num_strong_points;
765 for (;
766 ip < ip_limit;
767 ip += num_edges * num_strong_points, i++)
769 TA_Edge before;
770 TA_Edge after;
773 before = edges + i;
775 j = 0;
776 iq = ip;
777 iq_limit = iq + num_edges * num_strong_points;
778 for (; iq < iq_limit; iq += num_strong_points, j++)
780 if (*iq == MISSING)
781 continue;
783 after = edges + j;
785 *(p++) = HIGH(after->first - segments);
786 *(p++) = LOW(after->first - segments);
787 *(p++) = HIGH(before->first - segments);
788 *(p++) = LOW(before->first - segments);
790 k = 0;
791 ir = iq;
792 ir_limit = ir + num_strong_points;
793 for (; ir < ir_limit; ir++)
795 if (*ir != MISSING)
796 k++;
797 else
798 break;
801 *(p++) = HIGH(k);
802 *(p++) = LOW(k);
804 ir = iq;
805 ir_limit = ir + k;
806 for (; ir < ir_limit; ir++)
808 FT_UInt point = TA_adjust_point_index(recorder, *ir);
811 *(p++) = HIGH(point);
812 *(p++) = LOW(point);
818 recorder->hints_record.buf = p;
822 static FT_Bool
823 TA_hints_record_is_different(Hints_Record* hints_records,
824 FT_UInt num_hints_records,
825 FT_Byte* start,
826 FT_Byte* end)
828 Hints_Record last_hints_record;
831 if (!hints_records)
832 return 1;
834 /* we only need to compare with the last hints record */
835 last_hints_record = hints_records[num_hints_records - 1];
837 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
838 return 1;
840 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
841 return 1;
843 return 0;
847 static FT_Error
848 TA_add_hints_record(Hints_Record** hints_records,
849 FT_UInt* num_hints_records,
850 FT_Byte* start,
851 Hints_Record hints_record)
853 Hints_Record* hints_records_new;
854 FT_UInt buf_len;
855 /* at this point, `hints_record.buf' still points into `ins_buf' */
856 FT_Byte* end = hints_record.buf;
859 buf_len = (FT_UInt)(end - start);
861 /* now fill the structure completely */
862 hints_record.buf_len = buf_len;
863 hints_record.buf = (FT_Byte*)malloc(buf_len);
864 if (!hints_record.buf)
865 return FT_Err_Out_Of_Memory;
867 memcpy(hints_record.buf, start, buf_len);
869 (*num_hints_records)++;
870 hints_records_new =
871 (Hints_Record*)realloc(*hints_records, *num_hints_records
872 * sizeof (Hints_Record));
873 if (!hints_records_new)
875 free(hints_record.buf);
876 (*num_hints_records)--;
877 return FT_Err_Out_Of_Memory;
879 else
880 *hints_records = hints_records_new;
882 (*hints_records)[*num_hints_records - 1] = hints_record;
884 return FT_Err_Ok;
888 static FT_Byte*
889 TA_emit_hints_record(Recorder* recorder,
890 Hints_Record* hints_record,
891 FT_Byte* bufp,
892 FT_Bool optimize)
894 FT_Byte* p;
895 FT_Byte* endp;
896 FT_Bool need_words = 0;
898 FT_UInt i, j;
899 FT_UInt num_arguments;
900 FT_UInt num_args;
903 /* check whether any argument is larger than 0xFF */
904 endp = hints_record->buf + hints_record->buf_len;
905 for (p = hints_record->buf; p < endp; p += 2)
906 if (*p)
908 need_words = 1;
909 break;
912 /* with most fonts it is very rare */
913 /* that any of the pushed arguments is larger than 0xFF, */
914 /* thus we refrain from further optimizing this case */
916 num_arguments = hints_record->buf_len / 2;
917 p = endp - 2;
919 if (need_words)
921 for (i = 0; i < num_arguments; i += 255)
923 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
925 if (optimize && num_args <= 8)
926 BCI(PUSHW_1 - 1 + num_args);
927 else
929 BCI(NPUSHW);
930 BCI(num_args);
932 for (j = 0; j < num_args; j++)
934 BCI(*p);
935 BCI(*(p + 1));
936 p -= 2;
940 else
942 /* we only need the lower bytes */
943 p++;
945 for (i = 0; i < num_arguments; i += 255)
947 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
949 if (optimize && num_args <= 8)
950 BCI(PUSHB_1 - 1 + num_args);
951 else
953 BCI(NPUSHB);
954 BCI(num_args);
956 for (j = 0; j < num_args; j++)
958 BCI(*p);
959 p -= 2;
964 /* collect stack depth data */
965 if (num_arguments > recorder->num_stack_elements)
966 recorder->num_stack_elements = num_arguments;
968 return bufp;
972 static FT_Byte*
973 TA_emit_hints_records(Recorder* recorder,
974 Hints_Record* hints_records,
975 FT_UInt num_hints_records,
976 FT_Byte* bufp,
977 FT_Bool optimize)
979 FT_UInt i;
980 Hints_Record* hints_record;
983 hints_record = hints_records;
985 /* emit hints records in `if' clauses, */
986 /* with the ppem size as the condition */
987 for (i = 0; i < num_hints_records - 1; i++)
989 BCI(MPPEM);
990 if (hints_record->size > 0xFF)
992 BCI(PUSHW_1);
993 BCI(HIGH((hints_record + 1)->size));
994 BCI(LOW((hints_record + 1)->size));
996 else
998 BCI(PUSHB_1);
999 BCI((hints_record + 1)->size);
1001 BCI(LT);
1002 BCI(IF);
1003 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1004 BCI(ELSE);
1006 hints_record++;
1009 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1011 for (i = 0; i < num_hints_records - 1; i++)
1012 BCI(EIF);
1014 return bufp;
1018 static void
1019 TA_free_hints_records(Hints_Record* hints_records,
1020 FT_UInt num_hints_records)
1022 FT_UInt i;
1025 for (i = 0; i < num_hints_records; i++)
1026 free(hints_records[i].buf);
1028 free(hints_records);
1032 static FT_Byte*
1033 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1034 TA_AxisHints axis,
1035 TA_Edge edge,
1036 FT_UShort* wraps)
1038 TA_Segment segments = axis->segments;
1039 TA_Segment seg;
1040 FT_UShort seg_idx;
1041 FT_UShort num_segs = 0;
1042 FT_UShort* wrap;
1045 seg_idx = edge->first - segments;
1047 /* we store everything as 16bit numbers */
1048 *(bufp++) = HIGH(seg_idx);
1049 *(bufp++) = LOW(seg_idx);
1051 /* wrap-around segments are stored as two segments */
1052 if (edge->first->first > edge->first->last)
1053 num_segs++;
1055 seg = edge->first->edge_next;
1056 while (seg != edge->first)
1058 num_segs++;
1060 if (seg->first > seg->last)
1061 num_segs++;
1063 seg = seg->edge_next;
1066 *(bufp++) = HIGH(num_segs);
1067 *(bufp++) = LOW(num_segs);
1069 if (edge->first->first > edge->first->last)
1071 /* emit second part of wrap-around segment; */
1072 /* the bytecode positions such segments after `normal' ones */
1073 wrap = wraps;
1074 for (;;)
1076 if (seg_idx == *wrap)
1077 break;
1078 wrap++;
1081 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1082 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1085 seg = edge->first->edge_next;
1086 while (seg != edge->first)
1088 seg_idx = seg - segments;
1090 *(bufp++) = HIGH(seg_idx);
1091 *(bufp++) = LOW(seg_idx);
1093 if (seg->first > seg->last)
1095 wrap = wraps;
1096 for (;;)
1098 if (seg_idx == *wrap)
1099 break;
1100 wrap++;
1103 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1104 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1107 seg = seg->edge_next;
1110 return bufp;
1114 static void
1115 TA_hints_recorder(TA_Action action,
1116 TA_GlyphHints hints,
1117 TA_Dimension dim,
1118 void* arg1,
1119 TA_Edge arg2,
1120 TA_Edge arg3,
1121 TA_Edge lower_bound,
1122 TA_Edge upper_bound)
1124 TA_AxisHints axis = &hints->axis[dim];
1125 TA_Edge edges = axis->edges;
1126 TA_Segment segments = axis->segments;
1127 TA_Point points = hints->points;
1129 Recorder* recorder = (Recorder*)hints->user;
1130 SFNT* sfnt = recorder->sfnt;
1131 FONT* font = recorder->font;
1132 FT_UShort* wraps = recorder->wrap_around_segments;
1133 FT_Byte* p = recorder->hints_record.buf;
1135 FT_UShort* ip;
1136 FT_UShort* limit;
1139 if (dim == TA_DIMENSION_HORZ)
1140 return;
1142 /* we collect point hints for later processing */
1143 switch (action)
1145 case ta_ip_before:
1147 TA_Point point = (TA_Point)arg1;
1150 ip = recorder->ip_before_points;
1151 limit = ip + recorder->num_strong_points;
1152 for (; ip < limit; ip++)
1154 if (*ip == MISSING)
1156 *ip = point - points;
1157 break;
1161 return;
1163 case ta_ip_after:
1165 TA_Point point = (TA_Point)arg1;
1168 ip = recorder->ip_after_points;
1169 limit = ip + recorder->num_strong_points;
1170 for (; ip < limit; ip++)
1172 if (*ip == MISSING)
1174 *ip = point - points;
1175 break;
1179 return;
1181 case ta_ip_on:
1183 TA_Point point = (TA_Point)arg1;
1184 TA_Edge edge = arg2;
1187 ip = recorder->ip_on_point_array
1188 + recorder->num_strong_points
1189 * (edge - edges);
1190 limit = ip + recorder->num_strong_points;
1191 for (; ip < limit; ip++)
1193 if (*ip == MISSING)
1195 *ip = point - points;
1196 break;
1200 return;
1202 case ta_ip_between:
1204 TA_Point point = (TA_Point)arg1;
1205 TA_Edge before = arg2;
1206 TA_Edge after = arg3;
1209 /* note that `recorder->num_segments' has been used for allocation, */
1210 /* but `axis->num_edges' is used for accessing this array */
1211 ip = recorder->ip_between_point_array
1212 + recorder->num_strong_points * axis->num_edges
1213 * (before - edges)
1214 + recorder->num_strong_points
1215 * (after - edges);
1216 limit = ip + recorder->num_strong_points;
1217 for (; ip < limit; ip++)
1219 if (*ip == MISSING)
1221 *ip = point - points;
1222 break;
1226 return;
1228 case ta_bound:
1229 /* we ignore the BOUND action since we signal this information */
1230 /* with the proper function number */
1231 return;
1233 default:
1234 break;
1237 /* some enum values correspond to four or eight bytecode functions; */
1238 /* if the value is n, the function numbers are n, ..., n+7, */
1239 /* to be differentiated with flags */
1241 switch (action)
1243 case ta_link:
1245 TA_Edge base_edge = (TA_Edge)arg1;
1246 TA_Edge stem_edge = arg2;
1249 *(p++) = 0;
1250 *(p++) = (FT_Byte)action + ACTION_OFFSET
1251 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1252 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1254 *(p++) = HIGH(base_edge->first - segments);
1255 *(p++) = LOW(base_edge->first - segments);
1256 *(p++) = HIGH(stem_edge->first - segments);
1257 *(p++) = LOW(stem_edge->first - segments);
1259 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1261 break;
1263 case ta_anchor:
1265 TA_Edge edge = (TA_Edge)arg1;
1266 TA_Edge edge2 = arg2;
1269 *(p++) = 0;
1270 *(p++) = (FT_Byte)action + ACTION_OFFSET
1271 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1272 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1274 *(p++) = HIGH(edge->first - segments);
1275 *(p++) = LOW(edge->first - segments);
1276 *(p++) = HIGH(edge2->first - segments);
1277 *(p++) = LOW(edge2->first - segments);
1279 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1281 break;
1283 case ta_adjust:
1285 TA_Edge edge = (TA_Edge)arg1;
1286 TA_Edge edge2 = arg2;
1287 TA_Edge edge_minus_one = lower_bound;
1290 *(p++) = 0;
1291 *(p++) = (FT_Byte)action + ACTION_OFFSET
1292 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1293 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1294 + 4 * (edge_minus_one != NULL);
1296 *(p++) = HIGH(edge->first - segments);
1297 *(p++) = LOW(edge->first - segments);
1298 *(p++) = HIGH(edge2->first - segments);
1299 *(p++) = LOW(edge2->first - segments);
1301 if (edge_minus_one)
1303 *(p++) = HIGH(edge_minus_one->first - segments);
1304 *(p++) = LOW(edge_minus_one->first - segments);
1307 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1309 break;
1311 case ta_blue_anchor:
1313 TA_Edge edge = (TA_Edge)arg1;
1314 TA_Edge blue = arg2;
1317 *(p++) = 0;
1318 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1320 *(p++) = HIGH(blue->first - segments);
1321 *(p++) = LOW(blue->first - segments);
1323 if (edge->best_blue_is_shoot)
1325 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1326 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1328 else
1330 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1331 *(p++) = LOW(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1334 *(p++) = HIGH(edge->first - segments);
1335 *(p++) = LOW(edge->first - segments);
1337 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1339 break;
1341 case ta_stem:
1343 TA_Edge edge = (TA_Edge)arg1;
1344 TA_Edge edge2 = arg2;
1345 TA_Edge edge_minus_one = lower_bound;
1348 *(p++) = 0;
1349 *(p++) = (FT_Byte)action + ACTION_OFFSET
1350 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1351 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1352 + 4 * (edge_minus_one != NULL);
1354 *(p++) = HIGH(edge->first - segments);
1355 *(p++) = LOW(edge->first - segments);
1356 *(p++) = HIGH(edge2->first - segments);
1357 *(p++) = LOW(edge2->first - segments);
1359 if (edge_minus_one)
1361 *(p++) = HIGH(edge_minus_one->first - segments);
1362 *(p++) = LOW(edge_minus_one->first - segments);
1365 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1366 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1368 break;
1370 case ta_blue:
1372 TA_Edge edge = (TA_Edge)arg1;
1375 *(p++) = 0;
1376 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1378 if (edge->best_blue_is_shoot)
1380 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1381 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1383 else
1385 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1386 *(p++) = LOW(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1389 *(p++) = HIGH(edge->first - segments);
1390 *(p++) = LOW(edge->first - segments);
1392 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1394 break;
1396 case ta_serif:
1398 TA_Edge serif = (TA_Edge)arg1;
1399 TA_Edge base = serif->serif;
1402 *(p++) = 0;
1403 *(p++) = (FT_Byte)action + ACTION_OFFSET
1404 + (lower_bound != NULL)
1405 + 2 * (upper_bound != NULL);
1407 *(p++) = HIGH(serif->first - segments);
1408 *(p++) = LOW(serif->first - segments);
1409 *(p++) = HIGH(base->first - segments);
1410 *(p++) = LOW(base->first - segments);
1412 if (lower_bound)
1414 *(p++) = HIGH(lower_bound->first - segments);
1415 *(p++) = LOW(lower_bound->first - segments);
1417 if (upper_bound)
1419 *(p++) = HIGH(upper_bound->first - segments);
1420 *(p++) = LOW(upper_bound->first - segments);
1423 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1425 break;
1427 case ta_serif_anchor:
1428 case ta_serif_link2:
1430 TA_Edge edge = (TA_Edge)arg1;
1433 *(p++) = 0;
1434 *(p++) = (FT_Byte)action + ACTION_OFFSET
1435 + (lower_bound != NULL)
1436 + 2 * (upper_bound != NULL);
1438 *(p++) = HIGH(edge->first - segments);
1439 *(p++) = LOW(edge->first - segments);
1441 if (lower_bound)
1443 *(p++) = HIGH(lower_bound->first - segments);
1444 *(p++) = LOW(lower_bound->first - segments);
1446 if (upper_bound)
1448 *(p++) = HIGH(upper_bound->first - segments);
1449 *(p++) = LOW(upper_bound->first - segments);
1452 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1454 break;
1456 case ta_serif_link1:
1458 TA_Edge edge = (TA_Edge)arg1;
1459 TA_Edge before = arg2;
1460 TA_Edge after = arg3;
1463 *(p++) = 0;
1464 *(p++) = (FT_Byte)action + ACTION_OFFSET
1465 + (lower_bound != NULL)
1466 + 2 * (upper_bound != NULL);
1468 *(p++) = HIGH(before->first - segments);
1469 *(p++) = LOW(before->first - segments);
1470 *(p++) = HIGH(edge->first - segments);
1471 *(p++) = LOW(edge->first - segments);
1472 *(p++) = HIGH(after->first - segments);
1473 *(p++) = LOW(after->first - segments);
1475 if (lower_bound)
1477 *(p++) = HIGH(lower_bound->first - segments);
1478 *(p++) = LOW(lower_bound->first - segments);
1480 if (upper_bound)
1482 *(p++) = HIGH(upper_bound->first - segments);
1483 *(p++) = LOW(upper_bound->first - segments);
1486 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1488 break;
1490 default:
1491 /* there are more cases in the enumeration */
1492 /* which are handled with flags */
1493 break;
1496 recorder->hints_record.num_actions++;
1497 recorder->hints_record.buf = p;
1501 static FT_Error
1502 TA_init_recorder(Recorder* recorder,
1503 SFNT* sfnt,
1504 FONT* font,
1505 GLYPH* glyph,
1506 TA_GlyphHints hints)
1508 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1509 TA_Point points = hints->points;
1510 TA_Point point_limit = points + hints->num_points;
1511 TA_Point point;
1513 TA_Segment segments = axis->segments;
1514 TA_Segment seg_limit = segments + axis->num_segments;
1515 TA_Segment seg;
1517 FT_UShort num_strong_points = 0;
1518 FT_UShort* wrap_around_segment;
1520 recorder->sfnt = sfnt;
1521 recorder->font = font;
1522 recorder->glyph = glyph;
1523 recorder->num_segments = axis->num_segments;
1525 recorder->ip_before_points = NULL;
1526 recorder->ip_after_points = NULL;
1527 recorder->ip_on_point_array = NULL;
1528 recorder->ip_between_point_array = NULL;
1530 recorder->num_stack_elements = 0;
1532 /* no need to clean up allocated arrays in case of error; */
1533 /* this is handled later by `TA_free_recorder' */
1535 recorder->num_wrap_around_segments = 0;
1536 for (seg = segments; seg < seg_limit; seg++)
1537 if (seg->first > seg->last)
1538 recorder->num_wrap_around_segments++;
1540 recorder->wrap_around_segments =
1541 (FT_UShort*)malloc(recorder->num_wrap_around_segments
1542 * sizeof (FT_UShort));
1543 if (!recorder->wrap_around_segments)
1544 return FT_Err_Out_Of_Memory;
1546 wrap_around_segment = recorder->wrap_around_segments;
1547 for (seg = segments; seg < seg_limit; seg++)
1548 if (seg->first > seg->last)
1549 *(wrap_around_segment++) = seg - segments;
1551 /* get number of strong points */
1552 for (point = points; point < point_limit; point++)
1554 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1555 /* however, this value isn't known yet */
1556 /* (or rather, it can vary between different pixel sizes) */
1557 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1558 continue;
1560 num_strong_points++;
1563 recorder->num_strong_points = num_strong_points;
1565 recorder->ip_before_points =
1566 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1567 if (!recorder->ip_before_points)
1568 return FT_Err_Out_Of_Memory;
1570 recorder->ip_after_points =
1571 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1572 if (!recorder->ip_after_points)
1573 return FT_Err_Out_Of_Memory;
1575 /* actually, we need `hints->num_edges' for the array sizes; */
1576 /* however, this value isn't known yet */
1577 /* (or rather, it can vary between different pixel sizes) */
1578 recorder->ip_on_point_array =
1579 (FT_UShort*)malloc(axis->num_segments
1580 * num_strong_points * sizeof (FT_UShort));
1581 if (!recorder->ip_on_point_array)
1582 return FT_Err_Out_Of_Memory;
1584 recorder->ip_between_point_array =
1585 (FT_UShort*)malloc(axis->num_segments * axis->num_segments
1586 * num_strong_points * sizeof (FT_UShort));
1587 if (!recorder->ip_between_point_array)
1588 return FT_Err_Out_Of_Memory;
1590 return FT_Err_Ok;
1594 static void
1595 TA_reset_recorder(Recorder* recorder,
1596 FT_Byte* bufp)
1598 recorder->hints_record.buf = bufp;
1599 recorder->hints_record.num_actions = 0;
1603 static void
1604 TA_rewind_recorder(Recorder* recorder,
1605 FT_Byte* bufp,
1606 FT_UInt size)
1608 TA_reset_recorder(recorder, bufp);
1610 recorder->hints_record.size = size;
1612 /* We later check with MISSING (which expands to 0xFF bytes) */
1614 memset(recorder->ip_before_points, 0xFF,
1615 recorder->num_strong_points * sizeof (FT_UShort));
1616 memset(recorder->ip_after_points, 0xFF,
1617 recorder->num_strong_points * sizeof (FT_UShort));
1619 memset(recorder->ip_on_point_array, 0xFF,
1620 recorder->num_segments
1621 * recorder->num_strong_points * sizeof (FT_UShort));
1622 memset(recorder->ip_between_point_array, 0xFF,
1623 recorder->num_segments * recorder->num_segments
1624 * recorder->num_strong_points * sizeof (FT_UShort));
1628 static void
1629 TA_free_recorder(Recorder* recorder)
1631 free(recorder->wrap_around_segments);
1633 free(recorder->ip_before_points);
1634 free(recorder->ip_after_points);
1635 free(recorder->ip_on_point_array);
1636 free(recorder->ip_between_point_array);
1640 FT_Error
1641 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1642 FONT* font,
1643 FT_Long idx)
1645 FT_Face face = sfnt->face;
1646 FT_Error error;
1648 FT_Byte* ins_buf;
1649 FT_UInt ins_len;
1650 FT_Byte* bufp;
1651 FT_Byte* p;
1653 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1654 glyf_Data* data = (glyf_Data*)glyf_table->data;
1655 /* `idx' is never negative */
1656 GLYPH* glyph = &data->glyphs[idx];
1658 TA_GlyphHints hints;
1660 FT_UInt num_action_hints_records = 0;
1661 FT_UInt num_point_hints_records = 0;
1662 Hints_Record* action_hints_records = NULL;
1663 Hints_Record* point_hints_records = NULL;
1665 Recorder recorder;
1666 FT_UShort num_stack_elements;
1667 FT_Bool optimize = 0;
1669 FT_Int32 load_flags;
1670 FT_UInt size;
1672 FT_Byte* pos[3];
1674 #ifdef TA_DEBUG
1675 int _ta_debug_save;
1676 #endif
1679 /* XXX: right now, we abuse this flag to control */
1680 /* the global behaviour of the auto-hinter */
1681 load_flags = 1 << 29; /* vertical hinting only */
1682 if (!font->pre_hinting)
1684 if (font->hint_composites)
1685 load_flags |= FT_LOAD_NO_SCALE;
1686 else
1687 load_flags |= FT_LOAD_NO_RECURSE;
1690 /* computing the segments is resolution independent, */
1691 /* thus the pixel size in this call is arbitrary */
1692 error = FT_Set_Pixel_Sizes(face, 20, 20);
1693 if (error)
1694 return error;
1696 #ifdef TA_DEBUG
1697 /* temporarily disable debugging output */
1698 /* to avoid getting the information twice */
1699 _ta_debug_save = _ta_debug;
1700 _ta_debug = 0;
1701 #endif
1703 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1704 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1706 #ifdef TA_DEBUG
1707 _ta_debug = _ta_debug_save;
1708 #endif
1710 if (error)
1711 return error;
1713 /* do nothing if we have an empty glyph */
1714 if (!face->glyph->outline.n_contours)
1715 return FT_Err_Ok;
1717 hints = &font->loader->hints;
1719 /* do nothing if the setup delivered the `dflt' script only */
1720 if (!hints->num_points)
1721 return FT_Err_Ok;
1723 /* we allocate a buffer which is certainly large enough */
1724 /* to hold all of the created bytecode instructions; */
1725 /* later on it gets reallocated to its real size */
1726 ins_len = hints->num_points * 1000;
1727 ins_buf = (FT_Byte*)malloc(ins_len);
1728 if (!ins_buf)
1729 return FT_Err_Out_Of_Memory;
1731 /* initialize array with an invalid bytecode */
1732 /* so that we can easily find the array length at reallocation time */
1733 memset(ins_buf, INS_A0, ins_len);
1735 /* handle composite glyph */
1736 if (font->loader->gloader->base.num_subglyphs)
1738 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1739 if (!bufp)
1741 error = FT_Err_Out_Of_Memory;
1742 goto Err;
1745 goto Done1;
1748 /* only scale the glyph if the `dflt' script has been used */
1749 if (font->loader->metrics->script_class == &ta_dflt_script_class)
1751 /* since `TA_init_recorder' hasn't been called yet, */
1752 /* we manually initialize the `sfnt', `font', and `glyph' fields */
1753 recorder.sfnt = sfnt;
1754 recorder.font = font;
1755 recorder.glyph = glyph;
1757 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1758 if (!bufp)
1760 error = FT_Err_Out_Of_Memory;
1761 goto Err;
1764 goto Done1;
1767 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
1768 if (error)
1769 goto Err;
1771 /* loop over a large range of pixel sizes */
1772 /* to find hints records which get pushed onto the bytecode stack */
1774 #ifdef DEBUGGING
1775 if (font->debug)
1777 int num_chars, i;
1778 char buf[256];
1781 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1783 num_chars = fprintf(stderr, "glyph %ld", idx);
1784 if (*buf)
1785 num_chars += fprintf(stderr, " (%s)", buf);
1786 fprintf(stderr, "\n");
1787 for (i = 0; i < num_chars; i++)
1788 putc('=', stderr);
1789 fprintf(stderr, "\n\n");
1792 #endif
1794 /* we temporarily use `ins_buf' to record the current glyph hints */
1795 ta_loader_register_hints_recorder(font->loader,
1796 TA_hints_recorder,
1797 (void*)&recorder);
1799 for (size = font->hinting_range_min;
1800 size <= font->hinting_range_max;
1801 size++)
1803 #ifdef DEBUGGING
1804 int have_dumps = 0;
1805 #endif
1808 TA_rewind_recorder(&recorder, ins_buf, size);
1810 error = FT_Set_Pixel_Sizes(face, size, size);
1811 if (error)
1812 goto Err;
1814 #ifdef DEBUGGING
1815 if (font->debug)
1817 int num_chars, i;
1820 num_chars = fprintf(stderr, "size %d\n", size);
1821 for (i = 0; i < num_chars - 1; i++)
1822 putc('-', stderr);
1823 fprintf(stderr, "\n\n");
1825 #endif
1827 /* calling `ta_loader_load_glyph' uses the */
1828 /* `TA_hints_recorder' function as a callback, */
1829 /* modifying `hints_record' */
1830 error = ta_loader_load_glyph(font, face, idx, load_flags);
1831 if (error)
1832 goto Err;
1834 if (TA_hints_record_is_different(action_hints_records,
1835 num_action_hints_records,
1836 ins_buf, recorder.hints_record.buf))
1838 #ifdef DEBUGGING
1839 if (font->debug)
1841 have_dumps = 1;
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 */