Minor
[ttfautohint.git] / lib / tabytecode.c
bloba23c48044056dcf7437e1a80e7ae8c104abc96b1
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 FONT* font;
47 GLYPH* glyph; /* the current glyph */
48 Hints_Record hints_record;
50 /* some segments can `wrap around' */
51 /* a contour's start point like 24-25-26-0-1-2 */
52 /* (there can be at most one such segment per contour); */
53 /* later on we append additional records */
54 /* to split them into 24-26 and 0-2 */
55 FT_UShort* wrap_around_segments;
56 FT_UShort num_wrap_around_segments;
58 FT_UShort num_stack_elements; /* the necessary stack depth so far */
60 /* data necessary for strong point interpolation */
61 FT_UShort* ip_before_points;
62 FT_UShort* ip_after_points;
63 FT_UShort* ip_on_point_array;
64 FT_UShort* ip_between_point_array;
66 FT_UShort num_strong_points;
67 FT_UShort num_segments;
68 } Recorder;
71 /* this is the bytecode of the `.ttfautohint' glyph */
73 FT_Byte ttfautohint_glyph_bytecode[7] =
76 /* increment `cvtl_is_subglyph' counter */
77 PUSHB_3,
78 cvtl_is_subglyph,
80 cvtl_is_subglyph,
81 RCVT,
82 ADD,
83 WCVTP,
89 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
90 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
91 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
92 * PUSHW_X gets used
95 FT_Byte*
96 TA_build_push(FT_Byte* bufp,
97 FT_UInt* args,
98 FT_UInt num_args,
99 FT_Bool need_words,
100 FT_Bool optimize)
102 FT_UInt* arg = args;
103 FT_UInt i, j, nargs;
106 if (need_words)
108 for (i = 0; i < num_args; i += 255)
110 nargs = (num_args - i > 255) ? 255 : num_args - i;
112 if (optimize && nargs <= 8)
113 BCI(PUSHW_1 - 1 + nargs);
114 else
116 BCI(NPUSHW);
117 BCI(nargs);
119 for (j = 0; j < nargs; j++)
121 BCI(HIGH(*arg));
122 BCI(LOW(*arg));
123 arg++;
127 else
129 for (i = 0; i < num_args; i += 255)
131 nargs = (num_args - i > 255) ? 255 : num_args - i;
133 if (optimize && nargs <= 8)
134 BCI(PUSHB_1 - 1 + nargs);
135 else
137 BCI(NPUSHB);
138 BCI(nargs);
140 for (j = 0; j < nargs; j++)
142 BCI(*arg);
143 arg++;
148 return bufp;
152 /* We add a subglyph for each composite glyph. */
153 /* Since subglyphs must contain at least one point, */
154 /* we have to adjust all point indices accordingly. */
155 /* Using the `pointsums' array of the `GLYPH' structure */
156 /* it is straightforward to do that: */
157 /* Assuming that point with index x is in the interval */
158 /* pointsums[n] <= x < pointsums[n + 1], */
159 /* the new point index is x + n. */
161 static FT_UInt
162 TA_adjust_point_index(Recorder* recorder,
163 FT_UInt idx)
165 FONT* font = recorder->font;
166 GLYPH* glyph = recorder->glyph;
167 FT_UShort i;
170 if (!glyph->num_components || !font->hint_composites)
171 return idx; /* not a composite glyph */
173 for (i = 0; i < glyph->num_pointsums; i++)
174 if (idx < glyph->pointsums[i])
175 break;
177 return idx + i;
181 /* we store the segments in the storage area; */
182 /* each segment record consists of the first and last point */
184 static FT_Byte*
185 TA_sfnt_build_glyph_segments(SFNT* sfnt,
186 Recorder* recorder,
187 FT_Byte* bufp,
188 FT_Bool optimize)
190 FONT* font = recorder->font;
191 TA_GlyphHints hints = &font->loader->hints;
192 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
193 TA_Point points = hints->points;
194 TA_Segment segments = axis->segments;
195 TA_Segment seg;
196 TA_Segment seg_limit;
198 FT_Outline outline = font->loader->gloader->base.outline;
200 FT_UInt* args;
201 FT_UInt* arg;
202 FT_UInt num_args;
203 FT_UShort num_segments;
205 FT_Bool need_words = 0;
207 FT_Int n;
208 FT_UInt base;
209 FT_UShort num_packed_segments;
210 FT_UShort num_storage;
211 FT_UShort num_stack_elements;
212 FT_UShort num_twilight_points;
215 seg_limit = segments + axis->num_segments;
216 num_segments = axis->num_segments;
218 /* to pack the data in the bytecode more tightly, */
219 /* we store up to the first nine segments in nibbles if possible, */
220 /* using delta values */
221 base = 0;
222 num_packed_segments = 0;
223 for (seg = segments; seg < seg_limit; seg++)
225 FT_UInt first = seg->first - points;
226 FT_UInt last = seg->last - points;
229 first = TA_adjust_point_index(recorder, first);
230 last = TA_adjust_point_index(recorder, last);
232 if (first - base >= 16)
233 break;
234 if (first > last || last - first >= 16)
235 break;
236 if (num_packed_segments == 9)
237 break;
238 num_packed_segments++;
239 base = last;
242 /* also handle wrap-around segments */
243 num_segments += recorder->num_wrap_around_segments;
245 /* wrap-around segments are pushed with four arguments; */
246 /* a segment stored in nibbles needs only one byte instead of two */
247 num_args = num_packed_segments
248 + 2 * (num_segments - num_packed_segments)
249 + 2 * recorder->num_wrap_around_segments
250 + 2;
252 /* collect all arguments temporarily in an array (in reverse order) */
253 /* so that we can easily split into chunks of 255 args */
254 /* as needed by NPUSHB and NPUSHW, respectively */
255 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
256 if (!args)
257 return NULL;
259 arg = args + num_args - 1;
261 if (num_segments > 0xFF)
262 need_words = 1;
264 /* the number of packed segments is indicated by the function number */
265 if (recorder->glyph->num_components && font->hint_composites)
266 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
267 else
268 *(arg--) = bci_create_segments_0 + num_packed_segments;
269 *(arg--) = num_segments;
271 base = 0;
272 for (seg = segments; seg < segments + num_packed_segments; seg++)
274 FT_UInt first = seg->first - points;
275 FT_UInt last = seg->last - points;
276 FT_UInt low_nibble;
277 FT_UInt high_nibble;
280 first = TA_adjust_point_index(recorder, first);
281 last = TA_adjust_point_index(recorder, last);
283 low_nibble = first - base;
284 high_nibble = last - first;
286 *(arg--) = 16 * high_nibble + low_nibble;
288 base = last;
291 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
293 FT_UInt first = seg->first - points;
294 FT_UInt last = seg->last - points;
297 *(arg--) = TA_adjust_point_index(recorder, first);
298 *(arg--) = TA_adjust_point_index(recorder, last);
300 /* we push the last and first contour point */
301 /* as a third and fourth argument in wrap-around segments */
302 if (first > last)
304 for (n = 0; n < outline.n_contours; n++)
306 FT_UInt end = (FT_UInt)outline.contours[n];
309 if (first <= end)
311 *(arg--) = TA_adjust_point_index(recorder, end);
312 if (end > 0xFF)
313 need_words = 1;
315 if (n == 0)
316 *(arg--) = TA_adjust_point_index(recorder, 0);
317 else
318 *(arg--) = TA_adjust_point_index(recorder,
319 (FT_UInt)outline.contours[n - 1] + 1);
320 break;
325 if (last > 0xFF)
326 need_words = 1;
329 /* emit the second part of wrap-around segments as separate segments */
330 /* so that edges can easily link to them */
331 for (seg = segments; seg < seg_limit; seg++)
333 FT_UInt first = seg->first - points;
334 FT_UInt last = seg->last - points;
337 if (first > last)
339 for (n = 0; n < outline.n_contours; n++)
341 if (first <= (FT_UInt)outline.contours[n])
343 if (n == 0)
344 *(arg--) = TA_adjust_point_index(recorder, 0);
345 else
346 *(arg--) = TA_adjust_point_index(recorder,
347 (FT_UInt)outline.contours[n - 1] + 1);
348 break;
352 *(arg--) = TA_adjust_point_index(recorder, last);
356 /* with most fonts it is very rare */
357 /* that any of the pushed arguments is larger than 0xFF, */
358 /* thus we refrain from further optimizing this case */
359 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
361 BCI(CALL);
363 num_storage = sal_segment_offset + num_segments * 2;
364 if (num_storage > sfnt->max_storage)
365 sfnt->max_storage = num_storage;
367 num_twilight_points = num_segments * 2;
368 if (num_twilight_points > sfnt->max_twilight_points)
369 sfnt->max_twilight_points = num_twilight_points;
371 /* both this function and `TA_emit_hints_record' */
372 /* push data onto the stack */
373 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
374 + recorder->num_stack_elements + num_args;
375 if (num_stack_elements > sfnt->max_stack_elements)
376 sfnt->max_stack_elements = num_stack_elements;
378 free(args);
380 return bufp;
384 static FT_Byte*
385 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
386 Recorder* recorder,
387 FT_Byte* bufp)
389 FONT* font = recorder->font;
390 FT_GlyphSlot glyph = sfnt->face->glyph;
391 FT_Vector* points = glyph->outline.points;
392 FT_Int num_contours = glyph->outline.n_contours;
394 FT_UInt* args;
395 FT_UInt* arg;
396 FT_UInt num_args;
398 FT_Bool need_words = 0;
399 FT_Int p, q;
400 FT_Int start, end;
401 FT_UShort num_stack_elements;
404 num_args = 2 * num_contours + 2;
406 /* collect all arguments temporarily in an array (in reverse order) */
407 /* so that we can easily split into chunks of 255 args */
408 /* as needed by NPUSHB and NPUSHW, respectively */
409 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
410 if (!args)
411 return NULL;
413 arg = args + num_args - 1;
415 if (num_args > 0xFF)
416 need_words = 1;
418 if (recorder->glyph->num_components && font->hint_composites)
419 *(arg--) = bci_scale_composite_glyph;
420 else
421 *(arg--) = bci_scale_glyph;
422 *(arg--) = num_contours;
424 start = 0;
425 end = 0;
427 for (p = 0; p < num_contours; p++)
429 FT_Int max = start;
430 FT_Int min = start;
433 end = glyph->outline.contours[p];
435 for (q = start; q <= end; q++)
437 if (points[q].y < points[min].y)
438 min = q;
439 if (points[q].y > points[max].y)
440 max = q;
443 if (min > max)
445 *(arg--) = TA_adjust_point_index(recorder, max);
446 *(arg--) = TA_adjust_point_index(recorder, min);
448 else
450 *(arg--) = TA_adjust_point_index(recorder, min);
451 *(arg--) = TA_adjust_point_index(recorder, max);
454 start = end + 1;
457 if (end > 0xFF)
458 need_words = 1;
460 /* with most fonts it is very rare */
461 /* that any of the pushed arguments is larger than 0xFF, */
462 /* thus we refrain from further optimizing this case */
463 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
465 BCI(CALL);
467 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
468 if (num_stack_elements > sfnt->max_stack_elements)
469 sfnt->max_stack_elements = num_stack_elements;
471 free(args);
473 return bufp;
477 static FT_Byte*
478 TA_font_build_subglyph_shifter(FONT* font,
479 FT_Byte* bufp)
481 FT_Face face = font->loader->face;
482 FT_GlyphSlot glyph = face->glyph;
484 TA_GlyphLoader gloader = font->loader->gloader;
486 TA_SubGlyph subglyphs = gloader->base.subglyphs;
487 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
488 TA_SubGlyph subglyph;
490 FT_Int curr_contour = 0;
493 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
495 FT_Error error;
497 FT_UShort flags = subglyph->flags;
498 FT_Pos y_offset = subglyph->arg2;
500 FT_Int num_contours;
503 /* load subglyph to get the number of contours */
504 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
505 if (error)
506 return NULL;
507 num_contours = glyph->outline.n_contours;
509 /* nothing to do if there is a point-to-point alignment */
510 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
511 goto End;
513 /* nothing to do if y offset is zero */
514 if (!y_offset)
515 goto End;
517 /* nothing to do if there are no contours */
518 if (!num_contours)
519 goto End;
521 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
522 /* ensures that composite subglyphs are represented as simple glyphs */
524 if (num_contours > 0xFF
525 || curr_contour > 0xFF)
527 BCI(PUSHW_2);
528 BCI(HIGH(curr_contour));
529 BCI(LOW(curr_contour));
530 BCI(HIGH(num_contours));
531 BCI(LOW(num_contours));
533 else
535 BCI(PUSHB_2);
536 BCI(curr_contour);
537 BCI(num_contours);
540 /* there are high chances that this value needs PUSHW, */
541 /* thus we handle it separately */
542 if (y_offset > 0xFF || y_offset < 0)
544 BCI(PUSHW_1);
545 BCI(HIGH(y_offset));
546 BCI(LOW(y_offset));
548 else
550 BCI(PUSHB_1);
551 BCI(y_offset);
554 BCI(PUSHB_1);
555 BCI(bci_shift_subglyph);
556 BCI(CALL);
558 End:
559 curr_contour += num_contours;
562 return bufp;
567 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
568 * data in four arrays (which are simple but waste a lot of memory). The
569 * function below converts them into bytecode.
571 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
572 * together with the edge they correspond to.
574 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
575 * loop over the edge or edge pairs, respectively, and each edge or edge
576 * pair contains an inner loop to emit the correponding points.
579 static void
580 TA_build_point_hints(Recorder* recorder,
581 TA_GlyphHints hints)
583 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
584 TA_Segment segments = axis->segments;
585 TA_Edge edges = axis->edges;
587 TA_Edge edge;
589 FT_Byte* p = recorder->hints_record.buf;
590 FT_UShort num_edges = axis->num_edges;
591 FT_UShort num_strong_points = recorder->num_strong_points;
593 FT_UShort i;
594 FT_UShort j;
595 FT_UShort k;
597 FT_UShort* ip;
598 FT_UShort* iq;
599 FT_UShort* ir;
600 FT_UShort* ip_limit;
601 FT_UShort* iq_limit;
602 FT_UShort* ir_limit;
605 /* we store everything as 16bit numbers; */
606 /* the function numbers (`ta_ip_before', etc.) */
607 /* reflect the order in the TA_Action enumeration */
609 /* ip_before_points */
611 i = 0;
612 ip = recorder->ip_before_points;
613 ip_limit = ip + num_strong_points;
614 for (; ip < ip_limit; ip++)
616 if (*ip != MISSING)
617 i++;
618 else
619 break;
622 if (i)
624 recorder->hints_record.num_actions++;
626 edge = edges;
628 *(p++) = 0;
629 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
630 *(p++) = HIGH(edge->first - segments);
631 *(p++) = LOW(edge->first - segments);
632 *(p++) = HIGH(i);
633 *(p++) = LOW(i);
635 ip = recorder->ip_before_points;
636 ip_limit = ip + i;
637 for (; ip < ip_limit; ip++)
639 FT_UInt point = TA_adjust_point_index(recorder, *ip);
642 *(p++) = HIGH(point);
643 *(p++) = LOW(point);
647 /* ip_after_points */
649 i = 0;
650 ip = recorder->ip_after_points;
651 ip_limit = ip + num_strong_points;
652 for (; ip < ip_limit; ip++)
654 if (*ip != MISSING)
655 i++;
656 else
657 break;
660 if (i)
662 recorder->hints_record.num_actions++;
664 edge = edges + axis->num_edges - 1;
666 *(p++) = 0;
667 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
668 *(p++) = HIGH(edge->first - segments);
669 *(p++) = LOW(edge->first - segments);
670 *(p++) = HIGH(i);
671 *(p++) = LOW(i);
673 ip = recorder->ip_after_points;
674 ip_limit = ip + i;
675 for (; ip < ip_limit; ip++)
677 FT_UInt point = TA_adjust_point_index(recorder, *ip);
680 *(p++) = HIGH(point);
681 *(p++) = LOW(point);
685 /* ip_on_point_array */
687 i = 0;
688 ip = recorder->ip_on_point_array;
689 ip_limit = ip + num_edges * num_strong_points;
690 for (; ip < ip_limit; ip += num_strong_points)
691 if (*ip != MISSING)
692 i++;
694 if (i)
696 recorder->hints_record.num_actions++;
698 *(p++) = 0;
699 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
700 *(p++) = HIGH(i);
701 *(p++) = LOW(i);
703 i = 0;
704 ip = recorder->ip_on_point_array;
705 ip_limit = ip + num_edges * num_strong_points;
706 for (; ip < ip_limit; ip += num_strong_points, i++)
708 if (*ip == MISSING)
709 continue;
711 edge = edges + i;
713 *(p++) = HIGH(edge->first - segments);
714 *(p++) = LOW(edge->first - segments);
716 j = 0;
717 iq = ip;
718 iq_limit = iq + num_strong_points;
719 for (; iq < iq_limit; iq++)
721 if (*iq != MISSING)
722 j++;
723 else
724 break;
727 *(p++) = HIGH(j);
728 *(p++) = LOW(j);
730 iq = ip;
731 iq_limit = iq + j;
732 for (; iq < iq_limit; iq++)
734 FT_UInt point = TA_adjust_point_index(recorder, *iq);
737 *(p++) = HIGH(point);
738 *(p++) = LOW(point);
743 /* ip_between_point_array */
745 i = 0;
746 ip = recorder->ip_between_point_array;
747 ip_limit = ip + num_edges * num_edges * num_strong_points;
748 for (; ip < ip_limit; ip += num_strong_points)
749 if (*ip != MISSING)
750 i++;
752 if (i)
754 recorder->hints_record.num_actions++;
756 *(p++) = 0;
757 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
758 *(p++) = HIGH(i);
759 *(p++) = LOW(i);
761 i = 0;
762 ip = recorder->ip_between_point_array;
763 ip_limit = ip + num_edges * num_edges * num_strong_points;
764 for (;
765 ip < ip_limit;
766 ip += num_edges * num_strong_points, i++)
768 TA_Edge before;
769 TA_Edge after;
772 before = edges + i;
774 j = 0;
775 iq = ip;
776 iq_limit = iq + num_edges * num_strong_points;
777 for (; iq < iq_limit; iq += num_strong_points, j++)
779 if (*iq == MISSING)
780 continue;
782 after = edges + j;
784 *(p++) = HIGH(after->first - segments);
785 *(p++) = LOW(after->first - segments);
786 *(p++) = HIGH(before->first - segments);
787 *(p++) = LOW(before->first - segments);
789 k = 0;
790 ir = iq;
791 ir_limit = ir + num_strong_points;
792 for (; ir < ir_limit; ir++)
794 if (*ir != MISSING)
795 k++;
796 else
797 break;
800 *(p++) = HIGH(k);
801 *(p++) = LOW(k);
803 ir = iq;
804 ir_limit = ir + k;
805 for (; ir < ir_limit; ir++)
807 FT_UInt point = TA_adjust_point_index(recorder, *ir);
810 *(p++) = HIGH(point);
811 *(p++) = LOW(point);
817 recorder->hints_record.buf = p;
821 static FT_Bool
822 TA_hints_record_is_different(Hints_Record* hints_records,
823 FT_UInt num_hints_records,
824 FT_Byte* start,
825 FT_Byte* end)
827 Hints_Record last_hints_record;
830 if (!hints_records)
831 return 1;
833 /* we only need to compare with the last hints record */
834 last_hints_record = hints_records[num_hints_records - 1];
836 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
837 return 1;
839 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
840 return 1;
842 return 0;
846 static FT_Error
847 TA_add_hints_record(Hints_Record** hints_records,
848 FT_UInt* num_hints_records,
849 FT_Byte* start,
850 Hints_Record hints_record)
852 Hints_Record* hints_records_new;
853 FT_UInt buf_len;
854 /* at this point, `hints_record.buf' still points into `ins_buf' */
855 FT_Byte* end = hints_record.buf;
858 buf_len = (FT_UInt)(end - start);
860 /* now fill the structure completely */
861 hints_record.buf_len = buf_len;
862 hints_record.buf = (FT_Byte*)malloc(buf_len);
863 if (!hints_record.buf)
864 return FT_Err_Out_Of_Memory;
866 memcpy(hints_record.buf, start, buf_len);
868 (*num_hints_records)++;
869 hints_records_new =
870 (Hints_Record*)realloc(*hints_records, *num_hints_records
871 * sizeof (Hints_Record));
872 if (!hints_records_new)
874 free(hints_record.buf);
875 (*num_hints_records)--;
876 return FT_Err_Out_Of_Memory;
878 else
879 *hints_records = hints_records_new;
881 (*hints_records)[*num_hints_records - 1] = hints_record;
883 return FT_Err_Ok;
887 static FT_Byte*
888 TA_emit_hints_record(Recorder* recorder,
889 Hints_Record* hints_record,
890 FT_Byte* bufp,
891 FT_Bool optimize)
893 FT_Byte* p;
894 FT_Byte* endp;
895 FT_Bool need_words = 0;
897 FT_UInt i, j;
898 FT_UInt num_arguments;
899 FT_UInt num_args;
902 /* check whether any argument is larger than 0xFF */
903 endp = hints_record->buf + hints_record->buf_len;
904 for (p = hints_record->buf; p < endp; p += 2)
905 if (*p)
907 need_words = 1;
908 break;
911 /* with most fonts it is very rare */
912 /* that any of the pushed arguments is larger than 0xFF, */
913 /* thus we refrain from further optimizing this case */
915 num_arguments = hints_record->buf_len / 2;
916 p = endp - 2;
918 if (need_words)
920 for (i = 0; i < num_arguments; i += 255)
922 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
924 if (optimize && num_args <= 8)
925 BCI(PUSHW_1 - 1 + num_args);
926 else
928 BCI(NPUSHW);
929 BCI(num_args);
931 for (j = 0; j < num_args; j++)
933 BCI(*p);
934 BCI(*(p + 1));
935 p -= 2;
939 else
941 /* we only need the lower bytes */
942 p++;
944 for (i = 0; i < num_arguments; i += 255)
946 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
948 if (optimize && num_args <= 8)
949 BCI(PUSHB_1 - 1 + num_args);
950 else
952 BCI(NPUSHB);
953 BCI(num_args);
955 for (j = 0; j < num_args; j++)
957 BCI(*p);
958 p -= 2;
963 /* collect stack depth data */
964 if (num_arguments > recorder->num_stack_elements)
965 recorder->num_stack_elements = num_arguments;
967 return bufp;
971 static FT_Byte*
972 TA_emit_hints_records(Recorder* recorder,
973 Hints_Record* hints_records,
974 FT_UInt num_hints_records,
975 FT_Byte* bufp,
976 FT_Bool optimize)
978 FT_UInt i;
979 Hints_Record* hints_record;
982 hints_record = hints_records;
984 /* emit hints records in `if' clauses, */
985 /* with the ppem size as the condition */
986 for (i = 0; i < num_hints_records - 1; i++)
988 BCI(MPPEM);
989 if (hints_record->size > 0xFF)
991 BCI(PUSHW_1);
992 BCI(HIGH((hints_record + 1)->size));
993 BCI(LOW((hints_record + 1)->size));
995 else
997 BCI(PUSHB_1);
998 BCI((hints_record + 1)->size);
1000 BCI(LT);
1001 BCI(IF);
1002 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1003 BCI(ELSE);
1005 hints_record++;
1008 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1010 for (i = 0; i < num_hints_records - 1; i++)
1011 BCI(EIF);
1013 return bufp;
1017 static void
1018 TA_free_hints_records(Hints_Record* hints_records,
1019 FT_UInt num_hints_records)
1021 FT_UInt i;
1024 for (i = 0; i < num_hints_records; i++)
1025 free(hints_records[i].buf);
1027 free(hints_records);
1031 static FT_Byte*
1032 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1033 TA_AxisHints axis,
1034 TA_Edge edge,
1035 FT_UShort* wraps)
1037 TA_Segment segments = axis->segments;
1038 TA_Segment seg;
1039 FT_UShort seg_idx;
1040 FT_UShort num_segs = 0;
1041 FT_UShort* wrap;
1044 seg_idx = edge->first - segments;
1046 /* we store everything as 16bit numbers */
1047 *(bufp++) = HIGH(seg_idx);
1048 *(bufp++) = LOW(seg_idx);
1050 /* wrap-around segments are stored as two segments */
1051 if (edge->first->first > edge->first->last)
1052 num_segs++;
1054 seg = edge->first->edge_next;
1055 while (seg != edge->first)
1057 num_segs++;
1059 if (seg->first > seg->last)
1060 num_segs++;
1062 seg = seg->edge_next;
1065 *(bufp++) = HIGH(num_segs);
1066 *(bufp++) = LOW(num_segs);
1068 if (edge->first->first > edge->first->last)
1070 /* emit second part of wrap-around segment; */
1071 /* the bytecode positions such segments after `normal' ones */
1072 wrap = wraps;
1073 for (;;)
1075 if (seg_idx == *wrap)
1076 break;
1077 wrap++;
1080 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1081 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1084 seg = edge->first->edge_next;
1085 while (seg != edge->first)
1087 seg_idx = seg - segments;
1089 *(bufp++) = HIGH(seg_idx);
1090 *(bufp++) = LOW(seg_idx);
1092 if (seg->first > seg->last)
1094 wrap = wraps;
1095 for (;;)
1097 if (seg_idx == *wrap)
1098 break;
1099 wrap++;
1102 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1103 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1106 seg = seg->edge_next;
1109 return bufp;
1113 static void
1114 TA_hints_recorder(TA_Action action,
1115 TA_GlyphHints hints,
1116 TA_Dimension dim,
1117 void* arg1,
1118 TA_Edge arg2,
1119 TA_Edge arg3,
1120 TA_Edge lower_bound,
1121 TA_Edge upper_bound)
1123 TA_AxisHints axis = &hints->axis[dim];
1124 TA_Edge edges = axis->edges;
1125 TA_Segment segments = axis->segments;
1126 TA_Point points = hints->points;
1128 Recorder* recorder = (Recorder*)hints->user;
1129 FONT* font = recorder->font;
1130 FT_UShort* wraps = recorder->wrap_around_segments;
1131 FT_Byte* p = recorder->hints_record.buf;
1133 FT_UShort* ip;
1134 FT_UShort* limit;
1137 if (dim == TA_DIMENSION_HORZ)
1138 return;
1140 /* we collect point hints for later processing */
1141 switch (action)
1143 case ta_ip_before:
1145 TA_Point point = (TA_Point)arg1;
1148 ip = recorder->ip_before_points;
1149 limit = ip + recorder->num_strong_points;
1150 for (; ip < limit; ip++)
1152 if (*ip == MISSING)
1154 *ip = point - points;
1155 break;
1159 return;
1161 case ta_ip_after:
1163 TA_Point point = (TA_Point)arg1;
1166 ip = recorder->ip_after_points;
1167 limit = ip + recorder->num_strong_points;
1168 for (; ip < limit; ip++)
1170 if (*ip == MISSING)
1172 *ip = point - points;
1173 break;
1177 return;
1179 case ta_ip_on:
1181 TA_Point point = (TA_Point)arg1;
1182 TA_Edge edge = arg2;
1185 ip = recorder->ip_on_point_array
1186 + recorder->num_strong_points
1187 * (edge - edges);
1188 limit = ip + recorder->num_strong_points;
1189 for (; ip < limit; ip++)
1191 if (*ip == MISSING)
1193 *ip = point - points;
1194 break;
1198 return;
1200 case ta_ip_between:
1202 TA_Point point = (TA_Point)arg1;
1203 TA_Edge before = arg2;
1204 TA_Edge after = arg3;
1207 /* note that `recorder->num_segments' has been used for allocation, */
1208 /* but `axis->num_edges' is used for accessing this array */
1209 ip = recorder->ip_between_point_array
1210 + recorder->num_strong_points * axis->num_edges
1211 * (before - edges)
1212 + recorder->num_strong_points
1213 * (after - edges);
1214 limit = ip + recorder->num_strong_points;
1215 for (; ip < limit; ip++)
1217 if (*ip == MISSING)
1219 *ip = point - points;
1220 break;
1224 return;
1226 case ta_bound:
1227 /* we ignore the BOUND action since we signal this information */
1228 /* with the proper function number */
1229 return;
1231 default:
1232 break;
1235 /* some enum values correspond to four or eight bytecode functions; */
1236 /* if the value is n, the function numbers are n, ..., n+7, */
1237 /* to be differentiated with flags */
1239 switch (action)
1241 case ta_link:
1243 TA_Edge base_edge = (TA_Edge)arg1;
1244 TA_Edge stem_edge = arg2;
1247 *(p++) = 0;
1248 *(p++) = (FT_Byte)action + ACTION_OFFSET
1249 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1250 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1252 *(p++) = HIGH(base_edge->first - segments);
1253 *(p++) = LOW(base_edge->first - segments);
1254 *(p++) = HIGH(stem_edge->first - segments);
1255 *(p++) = LOW(stem_edge->first - segments);
1257 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1259 break;
1261 case ta_anchor:
1263 TA_Edge edge = (TA_Edge)arg1;
1264 TA_Edge edge2 = arg2;
1267 *(p++) = 0;
1268 *(p++) = (FT_Byte)action + ACTION_OFFSET
1269 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1270 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1272 *(p++) = HIGH(edge->first - segments);
1273 *(p++) = LOW(edge->first - segments);
1274 *(p++) = HIGH(edge2->first - segments);
1275 *(p++) = LOW(edge2->first - segments);
1277 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1279 break;
1281 case ta_adjust:
1283 TA_Edge edge = (TA_Edge)arg1;
1284 TA_Edge edge2 = arg2;
1285 TA_Edge edge_minus_one = lower_bound;
1288 *(p++) = 0;
1289 *(p++) = (FT_Byte)action + ACTION_OFFSET
1290 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1291 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1292 + 4 * (edge_minus_one != NULL);
1294 *(p++) = HIGH(edge->first - segments);
1295 *(p++) = LOW(edge->first - segments);
1296 *(p++) = HIGH(edge2->first - segments);
1297 *(p++) = LOW(edge2->first - segments);
1299 if (edge_minus_one)
1301 *(p++) = HIGH(edge_minus_one->first - segments);
1302 *(p++) = LOW(edge_minus_one->first - segments);
1305 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1307 break;
1309 case ta_blue_anchor:
1311 TA_Edge edge = (TA_Edge)arg1;
1312 TA_Edge blue = arg2;
1315 *(p++) = 0;
1316 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1318 *(p++) = HIGH(blue->first - segments);
1319 *(p++) = LOW(blue->first - segments);
1321 if (edge->best_blue_is_shoot)
1323 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1324 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1326 else
1328 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1329 *(p++) = LOW(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1332 *(p++) = HIGH(edge->first - segments);
1333 *(p++) = LOW(edge->first - segments);
1335 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1337 break;
1339 case ta_stem:
1341 TA_Edge edge = (TA_Edge)arg1;
1342 TA_Edge edge2 = arg2;
1343 TA_Edge edge_minus_one = lower_bound;
1346 *(p++) = 0;
1347 *(p++) = (FT_Byte)action + ACTION_OFFSET
1348 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1349 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1350 + 4 * (edge_minus_one != NULL);
1352 *(p++) = HIGH(edge->first - segments);
1353 *(p++) = LOW(edge->first - segments);
1354 *(p++) = HIGH(edge2->first - segments);
1355 *(p++) = LOW(edge2->first - segments);
1357 if (edge_minus_one)
1359 *(p++) = HIGH(edge_minus_one->first - segments);
1360 *(p++) = LOW(edge_minus_one->first - segments);
1363 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1364 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1366 break;
1368 case ta_blue:
1370 TA_Edge edge = (TA_Edge)arg1;
1373 *(p++) = 0;
1374 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1376 if (edge->best_blue_is_shoot)
1378 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1379 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET + edge->best_blue_idx);
1381 else
1383 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1384 *(p++) = LOW(CVT_BLUE_REFS_OFFSET + edge->best_blue_idx);
1387 *(p++) = HIGH(edge->first - segments);
1388 *(p++) = LOW(edge->first - segments);
1390 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1392 break;
1394 case ta_serif:
1396 TA_Edge serif = (TA_Edge)arg1;
1397 TA_Edge base = serif->serif;
1400 *(p++) = 0;
1401 *(p++) = (FT_Byte)action + ACTION_OFFSET
1402 + (lower_bound != NULL)
1403 + 2 * (upper_bound != NULL);
1405 *(p++) = HIGH(serif->first - segments);
1406 *(p++) = LOW(serif->first - segments);
1407 *(p++) = HIGH(base->first - segments);
1408 *(p++) = LOW(base->first - segments);
1410 if (lower_bound)
1412 *(p++) = HIGH(lower_bound->first - segments);
1413 *(p++) = LOW(lower_bound->first - segments);
1415 if (upper_bound)
1417 *(p++) = HIGH(upper_bound->first - segments);
1418 *(p++) = LOW(upper_bound->first - segments);
1421 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1423 break;
1425 case ta_serif_anchor:
1426 case ta_serif_link2:
1428 TA_Edge edge = (TA_Edge)arg1;
1431 *(p++) = 0;
1432 *(p++) = (FT_Byte)action + ACTION_OFFSET
1433 + (lower_bound != NULL)
1434 + 2 * (upper_bound != NULL);
1436 *(p++) = HIGH(edge->first - segments);
1437 *(p++) = LOW(edge->first - segments);
1439 if (lower_bound)
1441 *(p++) = HIGH(lower_bound->first - segments);
1442 *(p++) = LOW(lower_bound->first - segments);
1444 if (upper_bound)
1446 *(p++) = HIGH(upper_bound->first - segments);
1447 *(p++) = LOW(upper_bound->first - segments);
1450 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1452 break;
1454 case ta_serif_link1:
1456 TA_Edge edge = (TA_Edge)arg1;
1457 TA_Edge before = arg2;
1458 TA_Edge after = arg3;
1461 *(p++) = 0;
1462 *(p++) = (FT_Byte)action + ACTION_OFFSET
1463 + (lower_bound != NULL)
1464 + 2 * (upper_bound != NULL);
1466 *(p++) = HIGH(before->first - segments);
1467 *(p++) = LOW(before->first - segments);
1468 *(p++) = HIGH(edge->first - segments);
1469 *(p++) = LOW(edge->first - segments);
1470 *(p++) = HIGH(after->first - segments);
1471 *(p++) = LOW(after->first - segments);
1473 if (lower_bound)
1475 *(p++) = HIGH(lower_bound->first - segments);
1476 *(p++) = LOW(lower_bound->first - segments);
1478 if (upper_bound)
1480 *(p++) = HIGH(upper_bound->first - segments);
1481 *(p++) = LOW(upper_bound->first - segments);
1484 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1486 break;
1488 default:
1489 /* there are more cases in the enumeration */
1490 /* which are handled with flags */
1491 break;
1494 recorder->hints_record.num_actions++;
1495 recorder->hints_record.buf = p;
1499 static FT_Error
1500 TA_init_recorder(Recorder* recorder,
1501 FONT* font,
1502 GLYPH* glyph,
1503 TA_GlyphHints hints)
1505 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1506 TA_Point points = hints->points;
1507 TA_Point point_limit = points + hints->num_points;
1508 TA_Point point;
1510 TA_Segment segments = axis->segments;
1511 TA_Segment seg_limit = segments + axis->num_segments;
1512 TA_Segment seg;
1514 FT_UShort num_strong_points = 0;
1515 FT_UShort* wrap_around_segment;
1517 recorder->font = font;
1518 recorder->glyph = glyph;
1519 recorder->num_segments = axis->num_segments;
1521 recorder->ip_before_points = NULL;
1522 recorder->ip_after_points = NULL;
1523 recorder->ip_on_point_array = NULL;
1524 recorder->ip_between_point_array = NULL;
1526 recorder->num_stack_elements = 0;
1528 /* no need to clean up allocated arrays in case of error; */
1529 /* this is handled later by `TA_free_recorder' */
1531 recorder->num_wrap_around_segments = 0;
1532 for (seg = segments; seg < seg_limit; seg++)
1533 if (seg->first > seg->last)
1534 recorder->num_wrap_around_segments++;
1536 recorder->wrap_around_segments =
1537 (FT_UShort*)malloc(recorder->num_wrap_around_segments
1538 * sizeof (FT_UShort));
1539 if (!recorder->wrap_around_segments)
1540 return FT_Err_Out_Of_Memory;
1542 wrap_around_segment = recorder->wrap_around_segments;
1543 for (seg = segments; seg < seg_limit; seg++)
1544 if (seg->first > seg->last)
1545 *(wrap_around_segment++) = seg - segments;
1547 /* get number of strong points */
1548 for (point = points; point < point_limit; point++)
1550 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1551 /* however, this value isn't known yet */
1552 /* (or rather, it can vary between different pixel sizes) */
1553 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1554 continue;
1556 num_strong_points++;
1559 recorder->num_strong_points = num_strong_points;
1561 recorder->ip_before_points =
1562 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1563 if (!recorder->ip_before_points)
1564 return FT_Err_Out_Of_Memory;
1566 recorder->ip_after_points =
1567 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1568 if (!recorder->ip_after_points)
1569 return FT_Err_Out_Of_Memory;
1571 /* actually, we need `hints->num_edges' for the array sizes; */
1572 /* however, this value isn't known yet */
1573 /* (or rather, it can vary between different pixel sizes) */
1574 recorder->ip_on_point_array =
1575 (FT_UShort*)malloc(axis->num_segments
1576 * num_strong_points * sizeof (FT_UShort));
1577 if (!recorder->ip_on_point_array)
1578 return FT_Err_Out_Of_Memory;
1580 recorder->ip_between_point_array =
1581 (FT_UShort*)malloc(axis->num_segments * axis->num_segments
1582 * num_strong_points * sizeof (FT_UShort));
1583 if (!recorder->ip_between_point_array)
1584 return FT_Err_Out_Of_Memory;
1586 return FT_Err_Ok;
1590 static void
1591 TA_reset_recorder(Recorder* recorder,
1592 FT_Byte* bufp)
1594 recorder->hints_record.buf = bufp;
1595 recorder->hints_record.num_actions = 0;
1599 static void
1600 TA_rewind_recorder(Recorder* recorder,
1601 FT_Byte* bufp,
1602 FT_UInt size)
1604 TA_reset_recorder(recorder, bufp);
1606 recorder->hints_record.size = size;
1608 /* We later check with MISSING (which expands to 0xFF bytes) */
1610 memset(recorder->ip_before_points, 0xFF,
1611 recorder->num_strong_points * sizeof (FT_UShort));
1612 memset(recorder->ip_after_points, 0xFF,
1613 recorder->num_strong_points * sizeof (FT_UShort));
1615 memset(recorder->ip_on_point_array, 0xFF,
1616 recorder->num_segments
1617 * recorder->num_strong_points * sizeof (FT_UShort));
1618 memset(recorder->ip_between_point_array, 0xFF,
1619 recorder->num_segments * recorder->num_segments
1620 * recorder->num_strong_points * sizeof (FT_UShort));
1624 static void
1625 TA_free_recorder(Recorder* recorder)
1627 free(recorder->wrap_around_segments);
1629 free(recorder->ip_before_points);
1630 free(recorder->ip_after_points);
1631 free(recorder->ip_on_point_array);
1632 free(recorder->ip_between_point_array);
1636 FT_Error
1637 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1638 FONT* font,
1639 FT_Long idx)
1641 FT_Face face = sfnt->face;
1642 FT_Error error;
1644 FT_Byte* ins_buf;
1645 FT_UInt ins_len;
1646 FT_Byte* bufp;
1647 FT_Byte* p;
1649 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1650 glyf_Data* data = (glyf_Data*)glyf_table->data;
1651 /* `idx' is never negative */
1652 GLYPH* glyph = &data->glyphs[idx];
1654 TA_GlyphHints hints;
1656 FT_UInt num_action_hints_records = 0;
1657 FT_UInt num_point_hints_records = 0;
1658 Hints_Record* action_hints_records = NULL;
1659 Hints_Record* point_hints_records = NULL;
1661 Recorder recorder;
1662 FT_UShort num_stack_elements;
1663 FT_Bool optimize = 0;
1665 FT_Int32 load_flags;
1666 FT_UInt size;
1668 FT_Byte* pos[3];
1670 #ifdef TA_DEBUG
1671 int _ta_debug_save;
1672 #endif
1675 /* XXX: right now, we abuse this flag to control */
1676 /* the global behaviour of the auto-hinter */
1677 load_flags = 1 << 29; /* vertical hinting only */
1678 if (!font->pre_hinting)
1680 if (font->hint_composites)
1681 load_flags |= FT_LOAD_NO_SCALE;
1682 else
1683 load_flags |= FT_LOAD_NO_RECURSE;
1686 /* computing the segments is resolution independent, */
1687 /* thus the pixel size in this call is arbitrary */
1688 error = FT_Set_Pixel_Sizes(face, 20, 20);
1689 if (error)
1690 return error;
1692 #ifdef TA_DEBUG
1693 /* temporarily disable debugging output */
1694 /* to avoid getting the information twice */
1695 _ta_debug_save = _ta_debug;
1696 _ta_debug = 0;
1697 #endif
1699 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1700 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1702 #ifdef TA_DEBUG
1703 _ta_debug = _ta_debug_save;
1704 #endif
1706 if (error)
1707 return error;
1709 /* do nothing if we have an empty glyph */
1710 if (!face->glyph->outline.n_contours)
1711 return FT_Err_Ok;
1713 hints = &font->loader->hints;
1715 /* do nothing if the setup delivered the `dflt' script only */
1716 if (!hints->num_points)
1717 return FT_Err_Ok;
1719 /* we allocate a buffer which is certainly large enough */
1720 /* to hold all of the created bytecode instructions; */
1721 /* later on it gets reallocated to its real size */
1722 ins_len = hints->num_points * 1000;
1723 ins_buf = (FT_Byte*)malloc(ins_len);
1724 if (!ins_buf)
1725 return FT_Err_Out_Of_Memory;
1727 /* initialize array with an invalid bytecode */
1728 /* so that we can easily find the array length at reallocation time */
1729 memset(ins_buf, INS_A0, ins_len);
1731 /* handle composite glyph */
1732 if (font->loader->gloader->base.num_subglyphs)
1734 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1735 if (!bufp)
1737 error = FT_Err_Out_Of_Memory;
1738 goto Err;
1741 goto Done1;
1744 /* only scale the glyph if the `dflt' script has been used */
1745 if (font->loader->metrics->script_class == &ta_dflt_script_class)
1747 /* since `TA_init_recorder' hasn't been called yet, */
1748 /* we manually initialize the `font' and `glyph' fields */
1749 recorder.font = font;
1750 recorder.glyph = glyph;
1752 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1753 if (!bufp)
1755 error = FT_Err_Out_Of_Memory;
1756 goto Err;
1759 goto Done1;
1762 error = TA_init_recorder(&recorder, font, glyph, hints);
1763 if (error)
1764 goto Err;
1766 /* loop over a large range of pixel sizes */
1767 /* to find hints records which get pushed onto the bytecode stack */
1769 #ifdef DEBUGGING
1770 if (font->debug)
1772 int num_chars, i;
1773 char buf[256];
1776 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1778 num_chars = fprintf(stderr, "glyph %ld", idx);
1779 if (*buf)
1780 num_chars += fprintf(stderr, " (%s)", buf);
1781 fprintf(stderr, "\n");
1782 for (i = 0; i < num_chars; i++)
1783 putc('=', stderr);
1784 fprintf(stderr, "\n\n");
1787 #endif
1789 /* we temporarily use `ins_buf' to record the current glyph hints */
1790 ta_loader_register_hints_recorder(font->loader,
1791 TA_hints_recorder,
1792 (void*)&recorder);
1794 for (size = font->hinting_range_min;
1795 size <= font->hinting_range_max;
1796 size++)
1798 #ifdef DEBUGGING
1799 int have_dumps = 0;
1800 #endif
1803 TA_rewind_recorder(&recorder, ins_buf, size);
1805 error = FT_Set_Pixel_Sizes(face, size, size);
1806 if (error)
1807 goto Err;
1809 #ifdef DEBUGGING
1810 if (font->debug)
1812 int num_chars, i;
1815 num_chars = fprintf(stderr, "size %d\n", size);
1816 for (i = 0; i < num_chars - 1; i++)
1817 putc('-', stderr);
1818 fprintf(stderr, "\n\n");
1820 #endif
1822 /* calling `ta_loader_load_glyph' uses the */
1823 /* `TA_hints_recorder' function as a callback, */
1824 /* modifying `hints_record' */
1825 error = ta_loader_load_glyph(font, face, idx, load_flags);
1826 if (error)
1827 goto Err;
1829 if (TA_hints_record_is_different(action_hints_records,
1830 num_action_hints_records,
1831 ins_buf, recorder.hints_record.buf))
1833 #ifdef DEBUGGING
1834 if (font->debug)
1836 have_dumps = 1;
1838 ta_glyph_hints_dump_edges(_ta_debug_hints);
1839 ta_glyph_hints_dump_segments(_ta_debug_hints);
1840 ta_glyph_hints_dump_points(_ta_debug_hints);
1842 fprintf(stderr, "action hints record:\n");
1843 if (ins_buf == recorder.hints_record.buf)
1844 fprintf(stderr, " (none)");
1845 else
1847 fprintf(stderr, " ");
1848 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1849 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1851 fprintf(stderr, "\n");
1853 #endif
1855 error = TA_add_hints_record(&action_hints_records,
1856 &num_action_hints_records,
1857 ins_buf, recorder.hints_record);
1858 if (error)
1859 goto Err;
1862 /* now handle point records */
1864 TA_reset_recorder(&recorder, ins_buf);
1866 /* use the point hints data collected in `TA_hints_recorder' */
1867 TA_build_point_hints(&recorder, hints);
1869 if (TA_hints_record_is_different(point_hints_records,
1870 num_point_hints_records,
1871 ins_buf, recorder.hints_record.buf))
1873 #ifdef DEBUGGING
1874 if (font->debug)
1876 if (!have_dumps)
1878 int num_chars, i;
1881 num_chars = fprintf(stderr, "size %d\n", size);
1882 for (i = 0; i < num_chars - 1; i++)
1883 putc('-', stderr);
1884 fprintf(stderr, "\n\n");
1886 ta_glyph_hints_dump_edges(_ta_debug_hints);
1887 ta_glyph_hints_dump_segments(_ta_debug_hints);
1888 ta_glyph_hints_dump_points(_ta_debug_hints);
1891 fprintf(stderr, "point hints record:\n");
1892 if (ins_buf == recorder.hints_record.buf)
1893 fprintf(stderr, " (none)");
1894 else
1896 fprintf(stderr, " ");
1897 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1898 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1900 fprintf(stderr, "\n\n");
1902 #endif
1904 error = TA_add_hints_record(&point_hints_records,
1905 &num_point_hints_records,
1906 ins_buf, recorder.hints_record);
1907 if (error)
1908 goto Err;
1912 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1914 /* since we only have a single empty record we just scale the glyph */
1915 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1916 if (!bufp)
1918 error = FT_Err_Out_Of_Memory;
1919 goto Err;
1922 /* clear the rest of the temporarily used part of `ins_buf' */
1923 p = bufp;
1924 while (*p != INS_A0)
1925 *(p++) = INS_A0;
1927 goto Done;
1930 /* if there is only a single record, */
1931 /* we do a global optimization later on */
1932 if (num_action_hints_records > 1)
1933 optimize = 1;
1935 /* store the hints records and handle stack depth */
1936 pos[0] = ins_buf;
1937 bufp = TA_emit_hints_records(&recorder,
1938 point_hints_records,
1939 num_point_hints_records,
1940 ins_buf,
1941 optimize);
1943 num_stack_elements = recorder.num_stack_elements;
1944 recorder.num_stack_elements = 0;
1946 pos[1] = bufp;
1947 bufp = TA_emit_hints_records(&recorder,
1948 action_hints_records,
1949 num_action_hints_records,
1950 bufp,
1951 optimize);
1953 recorder.num_stack_elements += num_stack_elements;
1955 pos[2] = bufp;
1956 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
1957 if (!bufp)
1959 error = FT_Err_Out_Of_Memory;
1960 goto Err;
1963 /* XXX improve handling of NPUSHW */
1964 if (num_action_hints_records == 1
1965 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1968 * we optimize two common cases, replacing
1970 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1972 * with
1974 * NPUSHB (A+B[+C]) ... CALL
1976 * if possible
1978 FT_Byte sizes[3];
1979 FT_Byte new_size1;
1980 FT_Byte new_size2;
1982 FT_UInt sum;
1983 FT_UInt i;
1984 FT_UInt pos_idx;
1987 /* the point hints records block can be missing */
1988 if (pos[0] == pos[1])
1990 pos[1] = pos[2];
1991 pos[2] = NULL;
1994 /* there are at least two NPUSHB instructions */
1995 /* (one of them directly at the start) */
1996 sizes[0] = *(pos[0] + 1);
1997 sizes[1] = *(pos[1] + 1);
1998 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
2000 sum = sizes[0] + sizes[1] + sizes[2];
2002 if (sum > 2 * 0xFF)
2003 goto Done2; /* nothing to do since we need three NPUSHB */
2004 else if (!sizes[2] && (sum > 0xFF))
2005 goto Done2; /* nothing to do since we need two NPUSHB */
2007 if (sum > 0xFF)
2009 /* reduce three NPUSHB to two */
2010 new_size1 = 0xFF;
2011 new_size2 = sum - 0xFF;
2013 else
2015 /* reduce two or three NPUSHB to one */
2016 new_size1 = sum;
2017 new_size2 = 0;
2020 /* pack data */
2021 p = ins_buf;
2022 bufp = ins_buf;
2023 pos_idx = 0;
2025 if (new_size1 <= 8)
2026 BCI(PUSHB_1 - 1 + new_size1);
2027 else
2029 BCI(NPUSHB);
2030 BCI(new_size1);
2032 for (i = 0; i < new_size1; i++)
2034 if (p == pos[pos_idx])
2036 pos_idx++;
2037 p += 2; /* skip old NPUSHB */
2039 *(bufp++) = *(p++);
2042 if (new_size2)
2044 if (new_size2 <= 8)
2045 BCI(PUSHB_1 - 1 + new_size2);
2046 else
2048 BCI(NPUSHB);
2049 BCI(new_size2);
2051 for (i = 0; i < new_size2; i++)
2053 if (p == pos[pos_idx])
2055 pos_idx++;
2056 p += 2;
2058 *(bufp++) = *(p++);
2062 BCI(CALL);
2065 Done2:
2066 /* clear the rest of the temporarily used part of `ins_buf' */
2067 p = bufp;
2068 while (*p != INS_A0)
2069 *(p++) = INS_A0;
2071 Done:
2072 TA_free_hints_records(action_hints_records, num_action_hints_records);
2073 TA_free_hints_records(point_hints_records, num_point_hints_records);
2074 TA_free_recorder(&recorder);
2076 /* we are done, so reallocate the instruction array to its real size */
2077 if (*bufp == INS_A0)
2079 /* search backwards */
2080 while (*bufp == INS_A0)
2081 bufp--;
2082 bufp++;
2084 else
2086 /* search forwards */
2087 while (*bufp != INS_A0)
2088 bufp++;
2091 Done1:
2092 ins_len = bufp - ins_buf;
2094 if (ins_len > sfnt->max_instructions)
2095 sfnt->max_instructions = ins_len;
2097 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2098 glyph->ins_len = ins_len;
2100 return FT_Err_Ok;
2102 Err:
2103 TA_free_hints_records(action_hints_records, num_action_hints_records);
2104 TA_free_hints_records(point_hints_records, num_point_hints_records);
2105 TA_free_recorder(&recorder);
2106 free(ins_buf);
2108 return error;
2112 /* end of tabytecode.c */