Update file `no-copyright' and run `update-copyright'.
[ttfautohint.git] / lib / tabytecode.c
blob91509299e57b3595c57b019e197ff5bf7dfb7ecf
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2014 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_global = 0;
30 int _ta_debug_disable_horz_hints;
31 int _ta_debug_disable_vert_hints;
32 int _ta_debug_disable_blue_hints;
33 void* _ta_debug_hints;
34 #endif
37 typedef struct Hints_Record_
39 FT_UInt size;
40 FT_UInt num_actions;
41 FT_Byte* buf;
42 FT_UInt buf_len;
43 } Hints_Record;
45 typedef struct Recorder_
47 SFNT* sfnt;
48 FONT* font;
49 GLYPH* glyph; /* the current glyph */
50 Hints_Record hints_record;
52 /* some segments can `wrap around' */
53 /* a contour's start point like 24-25-26-0-1-2 */
54 /* (there can be at most one such segment per contour); */
55 /* later on we append additional records */
56 /* to split them into 24-26 and 0-2 */
57 FT_UShort* wrap_around_segments;
58 FT_UShort num_wrap_around_segments;
60 FT_UShort num_stack_elements; /* the necessary stack depth so far */
62 /* data necessary for strong point interpolation */
63 FT_UShort* ip_before_points;
64 FT_UShort* ip_after_points;
65 FT_UShort* ip_on_point_array;
66 FT_UShort* ip_between_point_array;
68 FT_UShort num_strong_points;
69 FT_UShort num_segments;
70 } Recorder;
73 /* this is the bytecode of the `.ttfautohint' glyph */
75 FT_Byte ttfautohint_glyph_bytecode[7] =
78 /* increment `cvtl_is_subglyph' counter */
79 PUSHB_3,
80 cvtl_is_subglyph,
81 100,
82 cvtl_is_subglyph,
83 RCVT,
84 ADD,
85 WCVTP,
91 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
92 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
93 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
94 * PUSHW_X gets used
97 FT_Byte*
98 TA_build_push(FT_Byte* bufp,
99 FT_UInt* args,
100 FT_UInt num_args,
101 FT_Bool need_words,
102 FT_Bool optimize)
104 FT_UInt* arg = args;
105 FT_UInt i, j, nargs;
108 if (need_words)
110 for (i = 0; i < num_args; i += 255)
112 nargs = (num_args - i > 255) ? 255 : num_args - i;
114 if (optimize && nargs <= 8)
115 BCI(PUSHW_1 - 1 + nargs);
116 else
118 BCI(NPUSHW);
119 BCI(nargs);
121 for (j = 0; j < nargs; j++)
123 BCI(HIGH(*arg));
124 BCI(LOW(*arg));
125 arg++;
129 else
131 for (i = 0; i < num_args; i += 255)
133 nargs = (num_args - i > 255) ? 255 : num_args - i;
135 if (optimize && nargs <= 8)
136 BCI(PUSHB_1 - 1 + nargs);
137 else
139 BCI(NPUSHB);
140 BCI(nargs);
142 for (j = 0; j < nargs; j++)
144 BCI(*arg);
145 arg++;
150 return bufp;
154 /* We add a subglyph for each composite glyph. */
155 /* Since subglyphs must contain at least one point, */
156 /* we have to adjust all point indices accordingly. */
157 /* Using the `pointsums' array of the `GLYPH' structure */
158 /* it is straightforward to do that: */
159 /* Assuming that point with index x is in the interval */
160 /* pointsums[n] <= x < pointsums[n + 1], */
161 /* the new point index is x + n. */
163 static FT_UInt
164 TA_adjust_point_index(Recorder* recorder,
165 FT_UInt idx)
167 FONT* font = recorder->font;
168 GLYPH* glyph = recorder->glyph;
169 FT_UShort i;
172 if (!glyph->num_components || !font->hint_composites)
173 return idx; /* not a composite glyph */
175 for (i = 0; i < glyph->num_pointsums; i++)
176 if (idx < glyph->pointsums[i])
177 break;
179 return idx + i;
183 /* we store the segments in the storage area; */
184 /* each segment record consists of the first and last point */
186 static FT_Byte*
187 TA_sfnt_build_glyph_segments(SFNT* sfnt,
188 Recorder* recorder,
189 FT_Byte* bufp,
190 FT_Bool optimize)
192 FONT* font = recorder->font;
193 TA_GlyphHints hints = &font->loader->hints;
194 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
195 TA_Point points = hints->points;
196 TA_Segment segments = axis->segments;
197 TA_Segment seg;
198 TA_Segment seg_limit;
200 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
201 glyf_Data* data = (glyf_Data*)glyf_table->data;
203 FT_UInt script_id = data->script_ids
204 [font->loader->metrics->script_class->script];
206 FT_Outline outline = font->loader->gloader->base.outline;
208 FT_UInt* args;
209 FT_UInt* arg;
210 FT_UInt num_args;
211 FT_UShort num_segments;
213 FT_Bool need_words = 0;
215 FT_Int n;
216 FT_UInt base;
217 FT_UShort num_packed_segments;
218 FT_UShort num_storage;
219 FT_UShort num_stack_elements;
220 FT_UShort num_twilight_points;
223 seg_limit = segments + axis->num_segments;
224 num_segments = axis->num_segments;
226 /* to pack the data in the bytecode more tightly, */
227 /* we store up to the first nine segments in nibbles if possible, */
228 /* using delta values */
229 base = 0;
230 num_packed_segments = 0;
231 for (seg = segments; seg < seg_limit; seg++)
233 FT_UInt first = seg->first - points;
234 FT_UInt last = seg->last - points;
237 first = TA_adjust_point_index(recorder, first);
238 last = TA_adjust_point_index(recorder, last);
240 if (first - base >= 16)
241 break;
242 if (first > last || last - first >= 16)
243 break;
244 if (num_packed_segments == 9)
245 break;
246 num_packed_segments++;
247 base = last;
250 /* also handle wrap-around segments */
251 num_segments += recorder->num_wrap_around_segments;
253 /* wrap-around segments are pushed with four arguments; */
254 /* a segment stored in nibbles needs only one byte instead of two */
255 num_args = num_packed_segments
256 + 2 * (num_segments - num_packed_segments)
257 + 2 * recorder->num_wrap_around_segments
258 + 3;
260 /* collect all arguments temporarily in an array (in reverse order) */
261 /* so that we can easily split into chunks of 255 args */
262 /* as needed by NPUSHB and NPUSHW, respectively */
263 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
264 if (!args)
265 return NULL;
267 arg = args + num_args - 1;
269 if (num_segments > 0xFF)
270 need_words = 1;
272 /* the number of packed segments is indicated by the function number */
273 if (recorder->glyph->num_components && font->hint_composites)
274 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
275 else
276 *(arg--) = bci_create_segments_0 + num_packed_segments;
278 *(arg--) = CVT_SCALING_VALUE_OFFSET(script_id);
279 *(arg--) = num_segments;
281 base = 0;
282 for (seg = segments; seg < segments + num_packed_segments; seg++)
284 FT_UInt first = seg->first - points;
285 FT_UInt last = seg->last - points;
286 FT_UInt low_nibble;
287 FT_UInt high_nibble;
290 first = TA_adjust_point_index(recorder, first);
291 last = TA_adjust_point_index(recorder, last);
293 low_nibble = first - base;
294 high_nibble = last - first;
296 *(arg--) = 16 * high_nibble + low_nibble;
298 base = last;
301 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
303 FT_UInt first = seg->first - points;
304 FT_UInt last = seg->last - points;
307 *(arg--) = TA_adjust_point_index(recorder, first);
308 *(arg--) = TA_adjust_point_index(recorder, last);
310 /* we push the last and first contour point */
311 /* as a third and fourth argument in wrap-around segments */
312 if (first > last)
314 for (n = 0; n < outline.n_contours; n++)
316 FT_UInt end = (FT_UInt)outline.contours[n];
319 if (first <= end)
321 *(arg--) = TA_adjust_point_index(recorder, end);
322 if (end > 0xFF)
323 need_words = 1;
325 if (n == 0)
326 *(arg--) = TA_adjust_point_index(recorder, 0);
327 else
328 *(arg--) = TA_adjust_point_index(recorder,
329 (FT_UInt)outline.contours[n - 1] + 1);
330 break;
335 if (last > 0xFF)
336 need_words = 1;
339 /* emit the second part of wrap-around segments as separate segments */
340 /* so that edges can easily link to them */
341 for (seg = segments; seg < seg_limit; seg++)
343 FT_UInt first = seg->first - points;
344 FT_UInt last = seg->last - points;
347 if (first > last)
349 for (n = 0; n < outline.n_contours; n++)
351 if (first <= (FT_UInt)outline.contours[n])
353 if (n == 0)
354 *(arg--) = TA_adjust_point_index(recorder, 0);
355 else
356 *(arg--) = TA_adjust_point_index(recorder,
357 (FT_UInt)outline.contours[n - 1] + 1);
358 break;
362 *(arg--) = TA_adjust_point_index(recorder, last);
366 /* with most fonts it is very rare */
367 /* that any of the pushed arguments is larger than 0xFF, */
368 /* thus we refrain from further optimizing this case */
369 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
371 BCI(CALL);
373 num_storage = sal_segment_offset + num_segments * 2;
374 if (num_storage > sfnt->max_storage)
375 sfnt->max_storage = num_storage;
377 num_twilight_points = num_segments * 2;
378 if (num_twilight_points > sfnt->max_twilight_points)
379 sfnt->max_twilight_points = num_twilight_points;
381 /* both this function and `TA_emit_hints_record' */
382 /* push data onto the stack */
383 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
384 + recorder->num_stack_elements + num_args;
385 if (num_stack_elements > sfnt->max_stack_elements)
386 sfnt->max_stack_elements = num_stack_elements;
388 free(args);
390 return bufp;
394 static FT_Byte*
395 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
396 Recorder* recorder,
397 FT_Byte* bufp)
399 FONT* font = recorder->font;
400 FT_GlyphSlot glyph = sfnt->face->glyph;
401 FT_Vector* points = glyph->outline.points;
402 FT_Int num_contours = glyph->outline.n_contours;
404 FT_UInt* args;
405 FT_UInt* arg;
406 FT_UInt num_args;
408 FT_Bool need_words = 0;
409 FT_Int p, q;
410 FT_Int start, end;
411 FT_UShort num_stack_elements;
414 num_args = 2 * num_contours + 2;
416 /* collect all arguments temporarily in an array (in reverse order) */
417 /* so that we can easily split into chunks of 255 args */
418 /* as needed by NPUSHB and NPUSHW, respectively */
419 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
420 if (!args)
421 return NULL;
423 arg = args + num_args - 1;
425 if (num_args > 0xFF)
426 need_words = 1;
428 if (recorder->glyph->num_components && font->hint_composites)
429 *(arg--) = bci_scale_composite_glyph;
430 else
431 *(arg--) = bci_scale_glyph;
432 *(arg--) = num_contours;
434 start = 0;
435 end = 0;
437 for (p = 0; p < num_contours; p++)
439 FT_Int max = start;
440 FT_Int min = start;
443 end = glyph->outline.contours[p];
445 for (q = start; q <= end; q++)
447 if (points[q].y < points[min].y)
448 min = q;
449 if (points[q].y > points[max].y)
450 max = q;
453 if (min > max)
455 *(arg--) = TA_adjust_point_index(recorder, max);
456 *(arg--) = TA_adjust_point_index(recorder, min);
458 else
460 *(arg--) = TA_adjust_point_index(recorder, min);
461 *(arg--) = TA_adjust_point_index(recorder, max);
464 start = end + 1;
467 if (end > 0xFF)
468 need_words = 1;
470 /* with most fonts it is very rare */
471 /* that any of the pushed arguments is larger than 0xFF, */
472 /* thus we refrain from further optimizing this case */
473 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
475 BCI(CALL);
477 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
478 if (num_stack_elements > sfnt->max_stack_elements)
479 sfnt->max_stack_elements = num_stack_elements;
481 free(args);
483 return bufp;
487 static FT_Byte*
488 TA_font_build_subglyph_shifter(FONT* font,
489 FT_Byte* bufp)
491 FT_Face face = font->loader->face;
492 FT_GlyphSlot glyph = face->glyph;
494 TA_GlyphLoader gloader = font->loader->gloader;
496 TA_SubGlyph subglyphs = gloader->base.subglyphs;
497 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
498 TA_SubGlyph subglyph;
500 FT_Int curr_contour = 0;
503 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
505 FT_Error error;
507 FT_UShort flags = subglyph->flags;
508 FT_Pos y_offset = subglyph->arg2;
510 FT_Int num_contours;
513 /* load subglyph to get the number of contours */
514 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
515 if (error)
516 return NULL;
517 num_contours = glyph->outline.n_contours;
519 /* nothing to do if there is a point-to-point alignment */
520 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
521 goto End;
523 /* nothing to do if y offset is zero */
524 if (!y_offset)
525 goto End;
527 /* nothing to do if there are no contours */
528 if (!num_contours)
529 goto End;
531 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
532 /* ensures that composite subglyphs are represented as simple glyphs */
534 if (num_contours > 0xFF
535 || curr_contour > 0xFF)
537 BCI(PUSHW_2);
538 BCI(HIGH(curr_contour));
539 BCI(LOW(curr_contour));
540 BCI(HIGH(num_contours));
541 BCI(LOW(num_contours));
543 else
545 BCI(PUSHB_2);
546 BCI(curr_contour);
547 BCI(num_contours);
550 /* there are high chances that this value needs PUSHW, */
551 /* thus we handle it separately */
552 if (y_offset > 0xFF || y_offset < 0)
554 BCI(PUSHW_1);
555 BCI(HIGH(y_offset));
556 BCI(LOW(y_offset));
558 else
560 BCI(PUSHB_1);
561 BCI(y_offset);
564 BCI(PUSHB_1);
565 BCI(bci_shift_subglyph);
566 BCI(CALL);
568 End:
569 curr_contour += num_contours;
572 return bufp;
577 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
578 * data in four arrays (which are simple but waste a lot of memory). The
579 * function below converts them into bytecode.
581 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
582 * together with the edge they correspond to.
584 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
585 * loop over the edge or edge pairs, respectively, and each edge or edge
586 * pair contains an inner loop to emit the correponding points.
589 static void
590 TA_build_point_hints(Recorder* recorder,
591 TA_GlyphHints hints)
593 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
594 TA_Segment segments = axis->segments;
595 TA_Edge edges = axis->edges;
597 TA_Edge edge;
599 FT_Byte* p = recorder->hints_record.buf;
600 FT_UShort num_edges = axis->num_edges;
601 FT_UShort num_strong_points = recorder->num_strong_points;
603 FT_UShort i;
604 FT_UShort j;
605 FT_UShort k;
607 FT_UShort* ip;
608 FT_UShort* iq;
609 FT_UShort* ir;
610 FT_UShort* ip_limit;
611 FT_UShort* iq_limit;
612 FT_UShort* ir_limit;
615 /* we store everything as 16bit numbers; */
616 /* the function numbers (`ta_ip_before', etc.) */
617 /* reflect the order in the TA_Action enumeration */
619 /* ip_before_points */
621 i = 0;
622 ip = recorder->ip_before_points;
623 ip_limit = ip + num_strong_points;
624 for (; ip < ip_limit; ip++)
626 if (*ip != MISSING)
627 i++;
628 else
629 break;
632 if (i)
634 recorder->hints_record.num_actions++;
636 edge = edges;
638 *(p++) = 0;
639 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
640 *(p++) = HIGH(edge->first - segments);
641 *(p++) = LOW(edge->first - segments);
642 *(p++) = HIGH(i);
643 *(p++) = LOW(i);
645 ip = recorder->ip_before_points;
646 ip_limit = ip + i;
647 for (; ip < ip_limit; ip++)
649 FT_UInt point = TA_adjust_point_index(recorder, *ip);
652 *(p++) = HIGH(point);
653 *(p++) = LOW(point);
657 /* ip_after_points */
659 i = 0;
660 ip = recorder->ip_after_points;
661 ip_limit = ip + num_strong_points;
662 for (; ip < ip_limit; ip++)
664 if (*ip != MISSING)
665 i++;
666 else
667 break;
670 if (i)
672 recorder->hints_record.num_actions++;
674 edge = edges + axis->num_edges - 1;
676 *(p++) = 0;
677 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
678 *(p++) = HIGH(edge->first - segments);
679 *(p++) = LOW(edge->first - segments);
680 *(p++) = HIGH(i);
681 *(p++) = LOW(i);
683 ip = recorder->ip_after_points;
684 ip_limit = ip + i;
685 for (; ip < ip_limit; ip++)
687 FT_UInt point = TA_adjust_point_index(recorder, *ip);
690 *(p++) = HIGH(point);
691 *(p++) = LOW(point);
695 /* ip_on_point_array */
697 i = 0;
698 ip = recorder->ip_on_point_array;
699 ip_limit = ip + num_edges * num_strong_points;
700 for (; ip < ip_limit; ip += num_strong_points)
701 if (*ip != MISSING)
702 i++;
704 if (i)
706 recorder->hints_record.num_actions++;
708 *(p++) = 0;
709 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
710 *(p++) = HIGH(i);
711 *(p++) = LOW(i);
713 i = 0;
714 ip = recorder->ip_on_point_array;
715 ip_limit = ip + num_edges * num_strong_points;
716 for (; ip < ip_limit; ip += num_strong_points, i++)
718 if (*ip == MISSING)
719 continue;
721 edge = edges + i;
723 *(p++) = HIGH(edge->first - segments);
724 *(p++) = LOW(edge->first - segments);
726 j = 0;
727 iq = ip;
728 iq_limit = iq + num_strong_points;
729 for (; iq < iq_limit; iq++)
731 if (*iq != MISSING)
732 j++;
733 else
734 break;
737 *(p++) = HIGH(j);
738 *(p++) = LOW(j);
740 iq = ip;
741 iq_limit = iq + j;
742 for (; iq < iq_limit; iq++)
744 FT_UInt point = TA_adjust_point_index(recorder, *iq);
747 *(p++) = HIGH(point);
748 *(p++) = LOW(point);
753 /* ip_between_point_array */
755 i = 0;
756 ip = recorder->ip_between_point_array;
757 ip_limit = ip + num_edges * num_edges * num_strong_points;
758 for (; ip < ip_limit; ip += num_strong_points)
759 if (*ip != MISSING)
760 i++;
762 if (i)
764 recorder->hints_record.num_actions++;
766 *(p++) = 0;
767 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
768 *(p++) = HIGH(i);
769 *(p++) = LOW(i);
771 i = 0;
772 ip = recorder->ip_between_point_array;
773 ip_limit = ip + num_edges * num_edges * num_strong_points;
774 for (;
775 ip < ip_limit;
776 ip += num_edges * num_strong_points, i++)
778 TA_Edge before;
779 TA_Edge after;
782 before = edges + i;
784 j = 0;
785 iq = ip;
786 iq_limit = iq + num_edges * num_strong_points;
787 for (; iq < iq_limit; iq += num_strong_points, j++)
789 if (*iq == MISSING)
790 continue;
792 after = edges + j;
794 *(p++) = HIGH(after->first - segments);
795 *(p++) = LOW(after->first - segments);
796 *(p++) = HIGH(before->first - segments);
797 *(p++) = LOW(before->first - segments);
799 k = 0;
800 ir = iq;
801 ir_limit = ir + num_strong_points;
802 for (; ir < ir_limit; ir++)
804 if (*ir != MISSING)
805 k++;
806 else
807 break;
810 *(p++) = HIGH(k);
811 *(p++) = LOW(k);
813 ir = iq;
814 ir_limit = ir + k;
815 for (; ir < ir_limit; ir++)
817 FT_UInt point = TA_adjust_point_index(recorder, *ir);
820 *(p++) = HIGH(point);
821 *(p++) = LOW(point);
827 recorder->hints_record.buf = p;
831 static FT_Bool
832 TA_hints_record_is_different(Hints_Record* hints_records,
833 FT_UInt num_hints_records,
834 FT_Byte* start,
835 FT_Byte* end)
837 Hints_Record last_hints_record;
840 if (!hints_records)
841 return 1;
843 /* we only need to compare with the last hints record */
844 last_hints_record = hints_records[num_hints_records - 1];
846 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
847 return 1;
849 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
850 return 1;
852 return 0;
856 static FT_Error
857 TA_add_hints_record(Hints_Record** hints_records,
858 FT_UInt* num_hints_records,
859 FT_Byte* start,
860 Hints_Record hints_record)
862 Hints_Record* hints_records_new;
863 FT_UInt buf_len;
864 /* at this point, `hints_record.buf' still points into `ins_buf' */
865 FT_Byte* end = hints_record.buf;
868 buf_len = (FT_UInt)(end - start);
870 /* now fill the structure completely */
871 hints_record.buf_len = buf_len;
872 hints_record.buf = (FT_Byte*)malloc(buf_len);
873 if (!hints_record.buf)
874 return FT_Err_Out_Of_Memory;
876 memcpy(hints_record.buf, start, buf_len);
878 (*num_hints_records)++;
879 hints_records_new =
880 (Hints_Record*)realloc(*hints_records, *num_hints_records
881 * sizeof (Hints_Record));
882 if (!hints_records_new)
884 free(hints_record.buf);
885 (*num_hints_records)--;
886 return FT_Err_Out_Of_Memory;
888 else
889 *hints_records = hints_records_new;
891 (*hints_records)[*num_hints_records - 1] = hints_record;
893 return FT_Err_Ok;
897 static FT_Byte*
898 TA_emit_hints_record(Recorder* recorder,
899 Hints_Record* hints_record,
900 FT_Byte* bufp,
901 FT_Bool optimize)
903 FT_Byte* p;
904 FT_Byte* endp;
905 FT_Bool need_words = 0;
907 FT_UInt i, j;
908 FT_UInt num_arguments;
909 FT_UInt num_args;
912 /* check whether any argument is larger than 0xFF */
913 endp = hints_record->buf + hints_record->buf_len;
914 for (p = hints_record->buf; p < endp; p += 2)
915 if (*p)
917 need_words = 1;
918 break;
921 /* with most fonts it is very rare */
922 /* that any of the pushed arguments is larger than 0xFF, */
923 /* thus we refrain from further optimizing this case */
925 num_arguments = hints_record->buf_len / 2;
926 p = endp - 2;
928 if (need_words)
930 for (i = 0; i < num_arguments; i += 255)
932 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
934 if (optimize && num_args <= 8)
935 BCI(PUSHW_1 - 1 + num_args);
936 else
938 BCI(NPUSHW);
939 BCI(num_args);
941 for (j = 0; j < num_args; j++)
943 BCI(*p);
944 BCI(*(p + 1));
945 p -= 2;
949 else
951 /* we only need the lower bytes */
952 p++;
954 for (i = 0; i < num_arguments; i += 255)
956 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
958 if (optimize && num_args <= 8)
959 BCI(PUSHB_1 - 1 + num_args);
960 else
962 BCI(NPUSHB);
963 BCI(num_args);
965 for (j = 0; j < num_args; j++)
967 BCI(*p);
968 p -= 2;
973 /* collect stack depth data */
974 if (num_arguments > recorder->num_stack_elements)
975 recorder->num_stack_elements = num_arguments;
977 return bufp;
981 static FT_Byte*
982 TA_emit_hints_records(Recorder* recorder,
983 Hints_Record* hints_records,
984 FT_UInt num_hints_records,
985 FT_Byte* bufp,
986 FT_Bool optimize)
988 FT_UInt i;
989 Hints_Record* hints_record;
992 hints_record = hints_records;
994 /* emit hints records in `if' clauses, */
995 /* with the ppem size as the condition */
996 for (i = 0; i < num_hints_records - 1; i++)
998 BCI(MPPEM);
999 if (hints_record->size > 0xFF)
1001 BCI(PUSHW_1);
1002 BCI(HIGH((hints_record + 1)->size));
1003 BCI(LOW((hints_record + 1)->size));
1005 else
1007 BCI(PUSHB_1);
1008 BCI((hints_record + 1)->size);
1010 BCI(LT);
1011 BCI(IF);
1012 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1013 BCI(ELSE);
1015 hints_record++;
1018 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1020 for (i = 0; i < num_hints_records - 1; i++)
1021 BCI(EIF);
1023 return bufp;
1027 static void
1028 TA_free_hints_records(Hints_Record* hints_records,
1029 FT_UInt num_hints_records)
1031 FT_UInt i;
1034 for (i = 0; i < num_hints_records; i++)
1035 free(hints_records[i].buf);
1037 free(hints_records);
1041 static FT_Byte*
1042 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1043 TA_AxisHints axis,
1044 TA_Edge edge,
1045 FT_UShort* wraps)
1047 TA_Segment segments = axis->segments;
1048 TA_Segment seg;
1049 FT_UShort seg_idx;
1050 FT_UShort num_segs = 0;
1051 FT_UShort* wrap;
1054 seg_idx = edge->first - segments;
1056 /* we store everything as 16bit numbers */
1057 *(bufp++) = HIGH(seg_idx);
1058 *(bufp++) = LOW(seg_idx);
1060 /* wrap-around segments are stored as two segments */
1061 if (edge->first->first > edge->first->last)
1062 num_segs++;
1064 seg = edge->first->edge_next;
1065 while (seg != edge->first)
1067 num_segs++;
1069 if (seg->first > seg->last)
1070 num_segs++;
1072 seg = seg->edge_next;
1075 *(bufp++) = HIGH(num_segs);
1076 *(bufp++) = LOW(num_segs);
1078 if (edge->first->first > edge->first->last)
1080 /* emit second part of wrap-around segment; */
1081 /* the bytecode positions such segments after `normal' ones */
1082 wrap = wraps;
1083 for (;;)
1085 if (seg_idx == *wrap)
1086 break;
1087 wrap++;
1090 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1091 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1094 seg = edge->first->edge_next;
1095 while (seg != edge->first)
1097 seg_idx = seg - segments;
1099 *(bufp++) = HIGH(seg_idx);
1100 *(bufp++) = LOW(seg_idx);
1102 if (seg->first > seg->last)
1104 wrap = wraps;
1105 for (;;)
1107 if (seg_idx == *wrap)
1108 break;
1109 wrap++;
1112 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1113 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1116 seg = seg->edge_next;
1119 return bufp;
1123 static void
1124 TA_hints_recorder(TA_Action action,
1125 TA_GlyphHints hints,
1126 TA_Dimension dim,
1127 void* arg1,
1128 TA_Edge arg2,
1129 TA_Edge arg3,
1130 TA_Edge lower_bound,
1131 TA_Edge upper_bound)
1133 TA_AxisHints axis = &hints->axis[dim];
1134 TA_Edge edges = axis->edges;
1135 TA_Segment segments = axis->segments;
1136 TA_Point points = hints->points;
1138 Recorder* recorder = (Recorder*)hints->user;
1139 SFNT* sfnt = recorder->sfnt;
1140 FONT* font = recorder->font;
1141 FT_UShort* wraps = recorder->wrap_around_segments;
1142 FT_Byte* p = recorder->hints_record.buf;
1144 FT_UInt script = font->loader->metrics->script_class->script;
1146 FT_UShort* ip;
1147 FT_UShort* limit;
1150 if (dim == TA_DIMENSION_HORZ)
1151 return;
1153 /* we collect point hints for later processing */
1154 switch (action)
1156 case ta_ip_before:
1158 TA_Point point = (TA_Point)arg1;
1161 ip = recorder->ip_before_points;
1162 limit = ip + recorder->num_strong_points;
1163 for (; ip < limit; ip++)
1165 if (*ip == MISSING)
1167 *ip = point - points;
1168 break;
1172 return;
1174 case ta_ip_after:
1176 TA_Point point = (TA_Point)arg1;
1179 ip = recorder->ip_after_points;
1180 limit = ip + recorder->num_strong_points;
1181 for (; ip < limit; ip++)
1183 if (*ip == MISSING)
1185 *ip = point - points;
1186 break;
1190 return;
1192 case ta_ip_on:
1194 TA_Point point = (TA_Point)arg1;
1195 TA_Edge edge = arg2;
1198 ip = recorder->ip_on_point_array
1199 + recorder->num_strong_points
1200 * (edge - edges);
1201 limit = ip + recorder->num_strong_points;
1202 for (; ip < limit; ip++)
1204 if (*ip == MISSING)
1206 *ip = point - points;
1207 break;
1211 return;
1213 case ta_ip_between:
1215 TA_Point point = (TA_Point)arg1;
1216 TA_Edge before = arg2;
1217 TA_Edge after = arg3;
1220 /* note that `recorder->num_segments' has been used for allocation, */
1221 /* but `axis->num_edges' is used for accessing this array */
1222 ip = recorder->ip_between_point_array
1223 + recorder->num_strong_points * axis->num_edges
1224 * (before - edges)
1225 + recorder->num_strong_points
1226 * (after - edges);
1227 limit = ip + recorder->num_strong_points;
1228 for (; ip < limit; ip++)
1230 if (*ip == MISSING)
1232 *ip = point - points;
1233 break;
1237 return;
1239 case ta_bound:
1240 /* we ignore the BOUND action since we signal this information */
1241 /* with the proper function number */
1242 return;
1244 default:
1245 break;
1248 /* some enum values correspond to four or eight bytecode functions; */
1249 /* if the value is n, the function numbers are n, ..., n+7, */
1250 /* to be differentiated with flags */
1252 switch (action)
1254 case ta_link:
1256 TA_Edge base_edge = (TA_Edge)arg1;
1257 TA_Edge stem_edge = arg2;
1260 *(p++) = 0;
1261 *(p++) = (FT_Byte)action + ACTION_OFFSET
1262 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1263 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1265 *(p++) = HIGH(base_edge->first - segments);
1266 *(p++) = LOW(base_edge->first - segments);
1267 *(p++) = HIGH(stem_edge->first - segments);
1268 *(p++) = LOW(stem_edge->first - segments);
1270 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1272 break;
1274 case ta_anchor:
1276 TA_Edge edge = (TA_Edge)arg1;
1277 TA_Edge edge2 = arg2;
1280 *(p++) = 0;
1281 *(p++) = (FT_Byte)action + ACTION_OFFSET
1282 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1283 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1285 *(p++) = HIGH(edge->first - segments);
1286 *(p++) = LOW(edge->first - segments);
1287 *(p++) = HIGH(edge2->first - segments);
1288 *(p++) = LOW(edge2->first - segments);
1290 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1292 break;
1294 case ta_adjust:
1296 TA_Edge edge = (TA_Edge)arg1;
1297 TA_Edge edge2 = arg2;
1298 TA_Edge edge_minus_one = lower_bound;
1301 *(p++) = 0;
1302 *(p++) = (FT_Byte)action + ACTION_OFFSET
1303 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1304 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1305 + 4 * (edge_minus_one != NULL);
1307 *(p++) = HIGH(edge->first - segments);
1308 *(p++) = LOW(edge->first - segments);
1309 *(p++) = HIGH(edge2->first - segments);
1310 *(p++) = LOW(edge2->first - segments);
1312 if (edge_minus_one)
1314 *(p++) = HIGH(edge_minus_one->first - segments);
1315 *(p++) = LOW(edge_minus_one->first - segments);
1318 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1320 break;
1322 case ta_blue_anchor:
1324 TA_Edge edge = (TA_Edge)arg1;
1325 TA_Edge blue = arg2;
1328 *(p++) = 0;
1329 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1331 *(p++) = HIGH(blue->first - segments);
1332 *(p++) = LOW(blue->first - segments);
1334 if (edge->best_blue_is_shoot)
1336 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(script) + edge->best_blue_idx);
1337 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(script) + edge->best_blue_idx);
1339 else
1341 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(script) + edge->best_blue_idx);
1342 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(script) + edge->best_blue_idx);
1345 *(p++) = HIGH(edge->first - segments);
1346 *(p++) = LOW(edge->first - segments);
1348 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1350 break;
1352 case ta_stem:
1354 TA_Edge edge = (TA_Edge)arg1;
1355 TA_Edge edge2 = arg2;
1356 TA_Edge edge_minus_one = lower_bound;
1359 *(p++) = 0;
1360 *(p++) = (FT_Byte)action + ACTION_OFFSET
1361 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1362 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1363 + 4 * (edge_minus_one != NULL);
1365 *(p++) = HIGH(edge->first - segments);
1366 *(p++) = LOW(edge->first - segments);
1367 *(p++) = HIGH(edge2->first - segments);
1368 *(p++) = LOW(edge2->first - segments);
1370 if (edge_minus_one)
1372 *(p++) = HIGH(edge_minus_one->first - segments);
1373 *(p++) = LOW(edge_minus_one->first - segments);
1376 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1377 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1379 break;
1381 case ta_blue:
1383 TA_Edge edge = (TA_Edge)arg1;
1386 *(p++) = 0;
1387 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1389 if (edge->best_blue_is_shoot)
1391 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(script) + edge->best_blue_idx);
1392 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(script) + edge->best_blue_idx);
1394 else
1396 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(script) + edge->best_blue_idx);
1397 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(script) + edge->best_blue_idx);
1400 *(p++) = HIGH(edge->first - segments);
1401 *(p++) = LOW(edge->first - segments);
1403 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1405 break;
1407 case ta_serif:
1409 TA_Edge serif = (TA_Edge)arg1;
1410 TA_Edge base = serif->serif;
1413 *(p++) = 0;
1414 *(p++) = (FT_Byte)action + ACTION_OFFSET
1415 + (lower_bound != NULL)
1416 + 2 * (upper_bound != NULL);
1418 *(p++) = HIGH(serif->first - segments);
1419 *(p++) = LOW(serif->first - segments);
1420 *(p++) = HIGH(base->first - segments);
1421 *(p++) = LOW(base->first - segments);
1423 if (lower_bound)
1425 *(p++) = HIGH(lower_bound->first - segments);
1426 *(p++) = LOW(lower_bound->first - segments);
1428 if (upper_bound)
1430 *(p++) = HIGH(upper_bound->first - segments);
1431 *(p++) = LOW(upper_bound->first - segments);
1434 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1436 break;
1438 case ta_serif_anchor:
1439 case ta_serif_link2:
1441 TA_Edge edge = (TA_Edge)arg1;
1444 *(p++) = 0;
1445 *(p++) = (FT_Byte)action + ACTION_OFFSET
1446 + (lower_bound != NULL)
1447 + 2 * (upper_bound != NULL);
1449 *(p++) = HIGH(edge->first - segments);
1450 *(p++) = LOW(edge->first - segments);
1452 if (lower_bound)
1454 *(p++) = HIGH(lower_bound->first - segments);
1455 *(p++) = LOW(lower_bound->first - segments);
1457 if (upper_bound)
1459 *(p++) = HIGH(upper_bound->first - segments);
1460 *(p++) = LOW(upper_bound->first - segments);
1463 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1465 break;
1467 case ta_serif_link1:
1469 TA_Edge edge = (TA_Edge)arg1;
1470 TA_Edge before = arg2;
1471 TA_Edge after = arg3;
1474 *(p++) = 0;
1475 *(p++) = (FT_Byte)action + ACTION_OFFSET
1476 + (lower_bound != NULL)
1477 + 2 * (upper_bound != NULL);
1479 *(p++) = HIGH(before->first - segments);
1480 *(p++) = LOW(before->first - segments);
1481 *(p++) = HIGH(edge->first - segments);
1482 *(p++) = LOW(edge->first - segments);
1483 *(p++) = HIGH(after->first - segments);
1484 *(p++) = LOW(after->first - segments);
1486 if (lower_bound)
1488 *(p++) = HIGH(lower_bound->first - segments);
1489 *(p++) = LOW(lower_bound->first - segments);
1491 if (upper_bound)
1493 *(p++) = HIGH(upper_bound->first - segments);
1494 *(p++) = LOW(upper_bound->first - segments);
1497 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1499 break;
1501 default:
1502 /* there are more cases in the enumeration */
1503 /* which are handled with flags */
1504 break;
1507 recorder->hints_record.num_actions++;
1508 recorder->hints_record.buf = p;
1512 static FT_Error
1513 TA_init_recorder(Recorder* recorder,
1514 SFNT* sfnt,
1515 FONT* font,
1516 GLYPH* glyph,
1517 TA_GlyphHints hints)
1519 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1520 TA_Point points = hints->points;
1521 TA_Point point_limit = points + hints->num_points;
1522 TA_Point point;
1524 TA_Segment segments = axis->segments;
1525 TA_Segment seg_limit = segments + axis->num_segments;
1526 TA_Segment seg;
1528 FT_UShort num_strong_points = 0;
1529 FT_UShort* wrap_around_segment;
1531 recorder->sfnt = sfnt;
1532 recorder->font = font;
1533 recorder->glyph = glyph;
1534 recorder->num_segments = axis->num_segments;
1536 recorder->ip_before_points = NULL;
1537 recorder->ip_after_points = NULL;
1538 recorder->ip_on_point_array = NULL;
1539 recorder->ip_between_point_array = NULL;
1541 recorder->num_stack_elements = 0;
1543 /* no need to clean up allocated arrays in case of error; */
1544 /* this is handled later by `TA_free_recorder' */
1546 recorder->num_wrap_around_segments = 0;
1547 for (seg = segments; seg < seg_limit; seg++)
1548 if (seg->first > seg->last)
1549 recorder->num_wrap_around_segments++;
1551 recorder->wrap_around_segments =
1552 (FT_UShort*)malloc(recorder->num_wrap_around_segments
1553 * sizeof (FT_UShort));
1554 if (!recorder->wrap_around_segments)
1555 return FT_Err_Out_Of_Memory;
1557 wrap_around_segment = recorder->wrap_around_segments;
1558 for (seg = segments; seg < seg_limit; seg++)
1559 if (seg->first > seg->last)
1560 *(wrap_around_segment++) = seg - segments;
1562 /* get number of strong points */
1563 for (point = points; point < point_limit; point++)
1565 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1566 /* however, this value isn't known yet */
1567 /* (or rather, it can vary between different pixel sizes) */
1568 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1569 continue;
1571 num_strong_points++;
1574 recorder->num_strong_points = num_strong_points;
1576 recorder->ip_before_points =
1577 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1578 if (!recorder->ip_before_points)
1579 return FT_Err_Out_Of_Memory;
1581 recorder->ip_after_points =
1582 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1583 if (!recorder->ip_after_points)
1584 return FT_Err_Out_Of_Memory;
1586 /* actually, we need `hints->num_edges' for the array sizes; */
1587 /* however, this value isn't known yet */
1588 /* (or rather, it can vary between different pixel sizes) */
1589 recorder->ip_on_point_array =
1590 (FT_UShort*)malloc(axis->num_segments
1591 * num_strong_points * sizeof (FT_UShort));
1592 if (!recorder->ip_on_point_array)
1593 return FT_Err_Out_Of_Memory;
1595 recorder->ip_between_point_array =
1596 (FT_UShort*)malloc(axis->num_segments * axis->num_segments
1597 * num_strong_points * sizeof (FT_UShort));
1598 if (!recorder->ip_between_point_array)
1599 return FT_Err_Out_Of_Memory;
1601 return FT_Err_Ok;
1605 static void
1606 TA_reset_recorder(Recorder* recorder,
1607 FT_Byte* bufp)
1609 recorder->hints_record.buf = bufp;
1610 recorder->hints_record.num_actions = 0;
1614 static void
1615 TA_rewind_recorder(Recorder* recorder,
1616 FT_Byte* bufp,
1617 FT_UInt size)
1619 TA_reset_recorder(recorder, bufp);
1621 recorder->hints_record.size = size;
1623 /* We later check with MISSING (which expands to 0xFF bytes) */
1625 memset(recorder->ip_before_points, 0xFF,
1626 recorder->num_strong_points * sizeof (FT_UShort));
1627 memset(recorder->ip_after_points, 0xFF,
1628 recorder->num_strong_points * sizeof (FT_UShort));
1630 memset(recorder->ip_on_point_array, 0xFF,
1631 recorder->num_segments
1632 * recorder->num_strong_points * sizeof (FT_UShort));
1633 memset(recorder->ip_between_point_array, 0xFF,
1634 recorder->num_segments * recorder->num_segments
1635 * recorder->num_strong_points * sizeof (FT_UShort));
1639 static void
1640 TA_free_recorder(Recorder* recorder)
1642 free(recorder->wrap_around_segments);
1644 free(recorder->ip_before_points);
1645 free(recorder->ip_after_points);
1646 free(recorder->ip_on_point_array);
1647 free(recorder->ip_between_point_array);
1651 FT_Error
1652 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1653 FONT* font,
1654 FT_Long idx)
1656 FT_Face face = sfnt->face;
1657 FT_Error error;
1659 FT_Byte* ins_buf;
1660 FT_UInt ins_len;
1661 FT_Byte* bufp;
1662 FT_Byte* p;
1664 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1665 glyf_Data* data = (glyf_Data*)glyf_table->data;
1666 /* `idx' is never negative */
1667 GLYPH* glyph = &data->glyphs[idx];
1669 TA_GlyphHints hints;
1671 FT_UInt num_action_hints_records = 0;
1672 FT_UInt num_point_hints_records = 0;
1673 Hints_Record* action_hints_records = NULL;
1674 Hints_Record* point_hints_records = NULL;
1676 Recorder recorder;
1677 FT_UShort num_stack_elements;
1678 FT_Bool optimize = 0;
1680 FT_Int32 load_flags;
1681 FT_UInt size;
1683 FT_Byte* pos[3];
1685 #ifdef TA_DEBUG
1686 int _ta_debug_save;
1687 #endif
1690 /* XXX: right now, we abuse this flag to control */
1691 /* the global behaviour of the auto-hinter */
1692 load_flags = 1 << 29; /* vertical hinting only */
1693 if (!font->pre_hinting)
1695 if (font->hint_composites)
1696 load_flags |= FT_LOAD_NO_SCALE;
1697 else
1698 load_flags |= FT_LOAD_NO_RECURSE;
1701 /* computing the segments is resolution independent, */
1702 /* thus the pixel size in this call is arbitrary -- */
1703 /* however, we avoid unnecessary debugging output */
1704 /* if we use the lowest value of the hinting range */
1705 error = FT_Set_Pixel_Sizes(face,
1706 font->hinting_range_min,
1707 font->hinting_range_min);
1708 if (error)
1709 return error;
1711 #ifdef TA_DEBUG
1712 /* temporarily disable some debugging output */
1713 /* to avoid getting the information twice */
1714 _ta_debug_save = _ta_debug;
1715 _ta_debug = 0;
1716 #endif
1718 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1719 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1721 #ifdef TA_DEBUG
1722 _ta_debug = _ta_debug_save;
1723 #endif
1725 if (error)
1726 return error;
1728 /* do nothing if we have an empty glyph */
1729 if (!face->glyph->outline.n_contours)
1730 return FT_Err_Ok;
1732 hints = &font->loader->hints;
1734 /* do nothing if the setup delivered the `none' script only */
1735 if (!hints->num_points)
1736 return FT_Err_Ok;
1738 /* we allocate a buffer which is certainly large enough */
1739 /* to hold all of the created bytecode instructions; */
1740 /* later on it gets reallocated to its real size */
1741 ins_len = hints->num_points * 1000;
1742 ins_buf = (FT_Byte*)malloc(ins_len);
1743 if (!ins_buf)
1744 return FT_Err_Out_Of_Memory;
1746 /* initialize array with an invalid bytecode */
1747 /* so that we can easily find the array length at reallocation time */
1748 memset(ins_buf, INS_A0, ins_len);
1750 /* handle composite glyph */
1751 if (font->loader->gloader->base.num_subglyphs)
1753 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1754 if (!bufp)
1756 error = FT_Err_Out_Of_Memory;
1757 goto Err;
1760 goto Done1;
1763 /* only scale the glyph if the `none' script has been used */
1764 if (font->loader->metrics->script_class == &ta_none_script_class)
1766 /* since `TA_init_recorder' hasn't been called yet, */
1767 /* we manually initialize the `sfnt', `font', and `glyph' fields */
1768 recorder.sfnt = sfnt;
1769 recorder.font = font;
1770 recorder.glyph = glyph;
1772 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1773 if (!bufp)
1775 error = FT_Err_Out_Of_Memory;
1776 goto Err;
1779 goto Done1;
1782 error = TA_init_recorder(&recorder, sfnt, font, glyph, hints);
1783 if (error)
1784 goto Err;
1786 /* loop over a large range of pixel sizes */
1787 /* to find hints records which get pushed onto the bytecode stack */
1789 #ifdef DEBUGGING
1790 if (font->debug)
1792 int num_chars, i;
1793 char buf[256];
1796 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1798 num_chars = fprintf(stderr, "glyph %ld", idx);
1799 if (*buf)
1800 num_chars += fprintf(stderr, " (%s)", buf);
1801 fprintf(stderr, "\n");
1802 for (i = 0; i < num_chars; i++)
1803 putc('=', stderr);
1804 fprintf(stderr, "\n\n");
1807 #endif
1809 /* we temporarily use `ins_buf' to record the current glyph hints */
1810 ta_loader_register_hints_recorder(font->loader,
1811 TA_hints_recorder,
1812 (void*)&recorder);
1814 for (size = font->hinting_range_min;
1815 size <= font->hinting_range_max;
1816 size++)
1818 #ifdef DEBUGGING
1819 int have_dumps = 0;
1820 #endif
1823 TA_rewind_recorder(&recorder, ins_buf, size);
1825 error = FT_Set_Pixel_Sizes(face, size, size);
1826 if (error)
1827 goto Err;
1829 #ifdef DEBUGGING
1830 if (font->debug)
1832 int num_chars, i;
1835 num_chars = fprintf(stderr, "size %d\n", size);
1836 for (i = 0; i < num_chars - 1; i++)
1837 putc('-', stderr);
1838 fprintf(stderr, "\n\n");
1840 #endif
1842 /* calling `ta_loader_load_glyph' uses the */
1843 /* `TA_hints_recorder' function as a callback, */
1844 /* modifying `hints_record' */
1845 error = ta_loader_load_glyph(font, face, idx, load_flags);
1846 if (error)
1847 goto Err;
1849 if (TA_hints_record_is_different(action_hints_records,
1850 num_action_hints_records,
1851 ins_buf, recorder.hints_record.buf))
1853 #ifdef DEBUGGING
1854 if (font->debug)
1856 have_dumps = 1;
1858 ta_glyph_hints_dump_edges(_ta_debug_hints);
1859 ta_glyph_hints_dump_segments(_ta_debug_hints);
1860 ta_glyph_hints_dump_points(_ta_debug_hints);
1862 fprintf(stderr, "action hints record:\n");
1863 if (ins_buf == recorder.hints_record.buf)
1864 fprintf(stderr, " (none)");
1865 else
1867 fprintf(stderr, " ");
1868 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1869 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1871 fprintf(stderr, "\n");
1873 #endif
1875 error = TA_add_hints_record(&action_hints_records,
1876 &num_action_hints_records,
1877 ins_buf, recorder.hints_record);
1878 if (error)
1879 goto Err;
1882 /* now handle point records */
1884 TA_reset_recorder(&recorder, ins_buf);
1886 /* use the point hints data collected in `TA_hints_recorder' */
1887 TA_build_point_hints(&recorder, hints);
1889 if (TA_hints_record_is_different(point_hints_records,
1890 num_point_hints_records,
1891 ins_buf, recorder.hints_record.buf))
1893 #ifdef DEBUGGING
1894 if (font->debug)
1896 if (!have_dumps)
1898 int num_chars, i;
1901 num_chars = fprintf(stderr, "size %d\n", size);
1902 for (i = 0; i < num_chars - 1; i++)
1903 putc('-', stderr);
1904 fprintf(stderr, "\n\n");
1906 ta_glyph_hints_dump_edges(_ta_debug_hints);
1907 ta_glyph_hints_dump_segments(_ta_debug_hints);
1908 ta_glyph_hints_dump_points(_ta_debug_hints);
1911 fprintf(stderr, "point hints record:\n");
1912 if (ins_buf == recorder.hints_record.buf)
1913 fprintf(stderr, " (none)");
1914 else
1916 fprintf(stderr, " ");
1917 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1918 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1920 fprintf(stderr, "\n\n");
1922 #endif
1924 error = TA_add_hints_record(&point_hints_records,
1925 &num_point_hints_records,
1926 ins_buf, recorder.hints_record);
1927 if (error)
1928 goto Err;
1932 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1934 /* since we only have a single empty record we just scale the glyph */
1935 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1936 if (!bufp)
1938 error = FT_Err_Out_Of_Memory;
1939 goto Err;
1942 /* clear the rest of the temporarily used part of `ins_buf' */
1943 p = bufp;
1944 while (*p != INS_A0)
1945 *(p++) = INS_A0;
1947 goto Done;
1950 /* if there is only a single record, */
1951 /* we do a global optimization later on */
1952 if (num_action_hints_records > 1)
1953 optimize = 1;
1955 /* store the hints records and handle stack depth */
1956 pos[0] = ins_buf;
1957 bufp = TA_emit_hints_records(&recorder,
1958 point_hints_records,
1959 num_point_hints_records,
1960 ins_buf,
1961 optimize);
1963 num_stack_elements = recorder.num_stack_elements;
1964 recorder.num_stack_elements = 0;
1966 pos[1] = bufp;
1967 bufp = TA_emit_hints_records(&recorder,
1968 action_hints_records,
1969 num_action_hints_records,
1970 bufp,
1971 optimize);
1973 recorder.num_stack_elements += num_stack_elements;
1975 pos[2] = bufp;
1976 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
1977 if (!bufp)
1979 error = FT_Err_Out_Of_Memory;
1980 goto Err;
1983 /* XXX improve handling of NPUSHW */
1984 if (num_action_hints_records == 1
1985 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1988 * we optimize two common cases, replacing
1990 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1992 * with
1994 * NPUSHB (A+B[+C]) ... CALL
1996 * if possible
1998 FT_Byte sizes[3];
1999 FT_Byte new_size1;
2000 FT_Byte new_size2;
2002 FT_UInt sum;
2003 FT_UInt i;
2004 FT_UInt pos_idx;
2007 /* the point hints records block can be missing */
2008 if (pos[0] == pos[1])
2010 pos[1] = pos[2];
2011 pos[2] = NULL;
2014 /* there are at least two NPUSHB instructions */
2015 /* (one of them directly at the start) */
2016 sizes[0] = *(pos[0] + 1);
2017 sizes[1] = *(pos[1] + 1);
2018 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
2020 sum = sizes[0] + sizes[1] + sizes[2];
2022 if (sum > 2 * 0xFF)
2023 goto Done2; /* nothing to do since we need three NPUSHB */
2024 else if (!sizes[2] && (sum > 0xFF))
2025 goto Done2; /* nothing to do since we need two NPUSHB */
2027 if (sum > 0xFF)
2029 /* reduce three NPUSHB to two */
2030 new_size1 = 0xFF;
2031 new_size2 = sum - 0xFF;
2033 else
2035 /* reduce two or three NPUSHB to one */
2036 new_size1 = sum;
2037 new_size2 = 0;
2040 /* pack data */
2041 p = ins_buf;
2042 bufp = ins_buf;
2043 pos_idx = 0;
2045 if (new_size1 <= 8)
2046 BCI(PUSHB_1 - 1 + new_size1);
2047 else
2049 BCI(NPUSHB);
2050 BCI(new_size1);
2052 for (i = 0; i < new_size1; i++)
2054 if (p == pos[pos_idx])
2056 pos_idx++;
2057 p += 2; /* skip old NPUSHB */
2059 *(bufp++) = *(p++);
2062 if (new_size2)
2064 if (new_size2 <= 8)
2065 BCI(PUSHB_1 - 1 + new_size2);
2066 else
2068 BCI(NPUSHB);
2069 BCI(new_size2);
2071 for (i = 0; i < new_size2; i++)
2073 if (p == pos[pos_idx])
2075 pos_idx++;
2076 p += 2;
2078 *(bufp++) = *(p++);
2082 BCI(CALL);
2085 Done2:
2086 /* clear the rest of the temporarily used part of `ins_buf' */
2087 p = bufp;
2088 while (*p != INS_A0)
2089 *(p++) = INS_A0;
2091 Done:
2092 TA_free_hints_records(action_hints_records, num_action_hints_records);
2093 TA_free_hints_records(point_hints_records, num_point_hints_records);
2094 TA_free_recorder(&recorder);
2096 /* we are done, so reallocate the instruction array to its real size */
2097 if (*bufp == INS_A0)
2099 /* search backwards */
2100 while (*bufp == INS_A0)
2101 bufp--;
2102 bufp++;
2104 else
2106 /* search forwards */
2107 while (*bufp != INS_A0)
2108 bufp++;
2111 Done1:
2112 ins_len = bufp - ins_buf;
2114 if (ins_len > sfnt->max_instructions)
2115 sfnt->max_instructions = ins_len;
2117 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2118 glyph->ins_len = ins_len;
2120 return FT_Err_Ok;
2122 Err:
2123 TA_free_hints_records(action_hints_records, num_action_hints_records);
2124 TA_free_hints_records(point_hints_records, num_point_hints_records);
2125 TA_free_recorder(&recorder);
2126 free(ins_buf);
2128 return error;
2132 /* end of tabytecode.c */