Addition to previous commit.
[ttfautohint.git] / lib / tabytecode.c
blob335ae7b0d84acff224c167205b01163885769068
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
17 #include <string.h>
20 #undef MISSING
21 #define MISSING (FT_UInt)~0
23 /* a simple macro to emit bytecode instructions */
24 #define BCI(code) *(bufp++) = (code)
26 /* we increase the stack depth by this amount */
27 #define ADDITIONAL_STACK_ELEMENTS 20
30 /* #define DEBUGGING */
33 #ifdef TA_DEBUG
34 int _ta_debug = 1;
35 int _ta_debug_disable_horz_hints;
36 int _ta_debug_disable_vert_hints;
37 int _ta_debug_disable_blue_hints;
38 void* _ta_debug_hints;
39 #endif
42 typedef struct Hints_Record_
44 FT_UInt size;
45 FT_UInt num_actions;
46 FT_Byte* buf;
47 FT_UInt buf_len;
48 } Hints_Record;
50 typedef struct Recorder_
52 FONT* font;
53 GLYPH* glyph; /* the current glyph */
54 Hints_Record hints_record;
56 /* some segments can `wrap around' */
57 /* a contour's start point like 24-25-26-0-1-2 */
58 /* (there can be at most one such segment per contour); */
59 /* later on we append additional records */
60 /* to split them into 24-26 and 0-2 */
61 FT_UInt* wrap_around_segments;
62 FT_UInt num_wrap_around_segments;
64 FT_UShort num_stack_elements; /* the necessary stack depth so far */
66 /* data necessary for strong point interpolation */
67 FT_UInt* ip_before_points;
68 FT_UInt* ip_after_points;
69 FT_UInt* ip_on_point_array;
70 FT_UInt* ip_between_point_array;
72 FT_UInt num_strong_points;
73 FT_UInt num_segments;
74 } Recorder;
77 /* We add a subglyph for each composite glyph. */
78 /* Since subglyphs must contain at least one point, */
79 /* we have to adjust all point indices accordingly. */
80 /* Using the `pointsums' array of the `GLYPH' structure */
81 /* it is straightforward to do that: */
82 /* Assuming that point with index x is in the interval */
83 /* pointsums[n] <= x < pointsums[n + 1], */
84 /* the new point index is x + n. */
86 static FT_UInt
87 TA_adjust_point_index(Recorder* recorder,
88 FT_UInt idx)
90 GLYPH* glyph = recorder->glyph;
91 FT_UShort i;
94 if (!glyph->num_components)
95 return idx; /* not a composite glyph */
97 for (i = 0; i < glyph->num_pointsums; i++)
98 if (idx < glyph->pointsums[i])
99 break;
101 return idx + i;
105 /* we store the segments in the storage area; */
106 /* each segment record consists of the first and last point */
108 static FT_Byte*
109 TA_sfnt_build_glyph_segments(SFNT* sfnt,
110 Recorder* recorder,
111 FT_Byte* bufp)
113 FONT* font = recorder->font;
114 TA_GlyphHints hints = &font->loader->hints;
115 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
116 TA_Point points = hints->points;
117 TA_Segment segments = axis->segments;
118 TA_Segment seg;
119 TA_Segment seg_limit;
121 FT_Outline outline = font->loader->gloader->base.outline;
123 FT_UInt* args;
124 FT_UInt* arg;
125 FT_UInt num_args;
126 FT_UInt nargs;
127 FT_UInt num_segments;
129 FT_Bool need_words = 0;
131 FT_Int n;
132 FT_UInt i, j;
133 FT_UInt base;
134 FT_UInt num_packed_segments;
135 FT_UInt num_storage;
136 FT_UInt num_stack_elements;
137 FT_UInt num_twilight_points;
140 seg_limit = segments + axis->num_segments;
141 num_segments = axis->num_segments;
143 /* to pack the data in the bytecode more tightly, */
144 /* we store up to the first nine segments in nibbles if possible, */
145 /* using delta values */
146 base = 0;
147 num_packed_segments = 0;
148 for (seg = segments; seg < seg_limit; seg++)
150 FT_UInt first = seg->first - points;
151 FT_UInt last = seg->last - points;
154 first = TA_adjust_point_index(recorder, first);
155 last = TA_adjust_point_index(recorder, last);
157 if (first - base >= 16)
158 break;
159 if (first > last || last - first >= 16)
160 break;
161 if (num_packed_segments == 9)
162 break;
163 num_packed_segments++;
164 base = last;
167 /* also handle wrap-around segments */
168 num_segments += recorder->num_wrap_around_segments;
170 /* wrap-around segments are pushed with four arguments; */
171 /* a segment stored in nibbles needs only one byte instead of two */
172 num_args = num_packed_segments
173 + 2 * (num_segments - num_packed_segments)
174 + 2 * recorder->num_wrap_around_segments
175 + 2;
177 /* collect all arguments temporarily in an array (in reverse order) */
178 /* so that we can easily split into chunks of 255 args */
179 /* as needed by NPUSHB and NPUSHW, respectively */
180 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
181 if (!args)
182 return NULL;
184 arg = args + num_args - 1;
186 if (num_segments > 0xFF)
187 need_words = 1;
189 /* the number of packed segments is indicated by the function number */
190 if (recorder->glyph->num_components)
191 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
192 else
193 *(arg--) = bci_create_segments_0 + num_packed_segments;
194 *(arg--) = num_segments;
196 base = 0;
197 for (seg = segments; seg < segments + num_packed_segments; seg++)
199 FT_UInt first = seg->first - points;
200 FT_UInt last = seg->last - points;
201 FT_UInt low_nibble;
202 FT_UInt high_nibble;
205 first = TA_adjust_point_index(recorder, first);
206 last = TA_adjust_point_index(recorder, last);
208 low_nibble = first - base;
209 high_nibble = last - first;
211 *(arg--) = 16 * high_nibble + low_nibble;
213 base = last;
215 if (last > 0xFF)
216 need_words = 1;
219 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
221 FT_UInt first = seg->first - points;
222 FT_UInt last = seg->last - points;
225 *(arg--) = TA_adjust_point_index(recorder, first);
226 *(arg--) = TA_adjust_point_index(recorder, last);
228 /* we push the last and first contour point */
229 /* as a third and fourth argument in wrap-around segments */
230 if (first > last)
232 for (n = 0; n < outline.n_contours; n++)
234 FT_UInt end = (FT_UInt)outline.contours[n];
237 if (first <= end)
239 *(arg--) = TA_adjust_point_index(recorder, end);
240 if (end > 0xFF)
241 need_words = 1;
243 if (n == 0)
244 *(arg--) = TA_adjust_point_index(recorder, 0);
245 else
246 *(arg--) = TA_adjust_point_index(recorder,
247 (FT_UInt)outline.contours[n - 1] + 1);
248 break;
253 if (last > 0xFF)
254 need_words = 1;
257 /* emit the second part of wrap-around segments as separate segments */
258 /* so that edges can easily link to them */
259 for (seg = segments; seg < seg_limit; seg++)
261 FT_UInt first = seg->first - points;
262 FT_UInt last = seg->last - points;
265 if (first > last)
267 for (n = 0; n < outline.n_contours; n++)
269 if (first <= (FT_UInt)outline.contours[n])
271 if (n == 0)
272 *(arg--) = TA_adjust_point_index(recorder, 0);
273 else
274 *(arg--) = TA_adjust_point_index(recorder,
275 (FT_UInt)outline.contours[n - 1] + 1);
276 break;
280 *(arg--) = TA_adjust_point_index(recorder, last);
283 /* with most fonts it is very rare */
284 /* that any of the pushed arguments is larger than 0xFF, */
285 /* thus we refrain from further optimizing this case */
287 arg = args;
289 if (need_words)
291 for (i = 0; i < num_args; i += 255)
293 nargs = (num_args - i > 255) ? 255 : num_args - i;
295 BCI(NPUSHW);
296 BCI(nargs);
297 for (j = 0; j < nargs; j++)
299 BCI(HIGH(*arg));
300 BCI(LOW(*arg));
301 arg++;
305 else
307 for (i = 0; i < num_args; i += 255)
309 nargs = (num_args - i > 255) ? 255 : num_args - i;
311 BCI(NPUSHB);
312 BCI(nargs);
313 for (j = 0; j < nargs; j++)
315 BCI(*arg);
316 arg++;
321 BCI(CALL);
323 num_storage = sal_segment_offset + num_segments * 2;
324 if (num_storage > sfnt->max_storage)
325 sfnt->max_storage = num_storage;
327 num_twilight_points = num_segments * 2;
328 if (num_twilight_points > sfnt->max_twilight_points)
329 sfnt->max_twilight_points = num_twilight_points;
331 /* both this function and `TA_emit_hints_record' */
332 /* push data onto the stack */
333 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
334 + recorder->num_stack_elements + num_args;
335 if (num_stack_elements > sfnt->max_stack_elements)
336 sfnt->max_stack_elements = num_stack_elements;
338 free(args);
340 return bufp;
344 static FT_Byte*
345 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
346 Recorder* recorder,
347 FT_Byte* bufp)
349 FT_GlyphSlot glyph = sfnt->face->glyph;
350 FT_Vector* points = glyph->outline.points;
351 FT_Int num_contours = glyph->outline.n_contours;
353 FT_UInt* args;
354 FT_UInt* arg;
355 FT_UInt num_args;
356 FT_UInt nargs;
358 FT_Bool need_words = 0;
359 FT_Int p, q;
360 FT_UInt i, j;
361 FT_Int start, end;
362 FT_UInt num_stack_elements;
365 num_args = 2 * num_contours + 2;
367 /* collect all arguments temporarily in an array (in reverse order) */
368 /* so that we can easily split into chunks of 255 args */
369 /* as needed by NPUSHB and NPUSHW, respectively */
370 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
371 if (!args)
372 return NULL;
374 arg = args + num_args - 1;
376 if (num_args > 0xFF)
377 need_words = 1;
379 if (recorder->glyph->num_components)
380 *(arg--) = bci_scale_composite_glyph;
381 else
382 *(arg--) = bci_scale_glyph;
383 *(arg--) = num_contours;
385 start = 0;
386 end = 0;
388 for (p = 0; p < num_contours; p++)
390 FT_Int max = start;
391 FT_Int min = start;
394 end = glyph->outline.contours[p];
396 for (q = start; q <= end; q++)
398 if (points[q].y < points[min].y)
399 min = q;
400 if (points[q].y > points[max].y)
401 max = q;
404 if (min > max)
406 *(arg--) = TA_adjust_point_index(recorder, max);
407 *(arg--) = TA_adjust_point_index(recorder, min);
409 else
411 *(arg--) = TA_adjust_point_index(recorder, min);
412 *(arg--) = TA_adjust_point_index(recorder, max);
415 start = end + 1;
418 if (end > 0xFF)
419 need_words = 1;
421 /* with most fonts it is very rare */
422 /* that any of the pushed arguments is larger than 0xFF, */
423 /* thus we refrain from further optimizing this case */
425 arg = args;
427 if (need_words)
429 for (i = 0; i < num_args; i += 255)
431 nargs = (num_args - i > 255) ? 255 : num_args - i;
433 if (nargs <= 8)
434 BCI(PUSHW_1 - 1 + nargs);
435 else
437 BCI(NPUSHW);
438 BCI(nargs);
440 for (j = 0; j < nargs; j++)
442 BCI(HIGH(*arg));
443 BCI(LOW(*arg));
444 arg++;
448 else
450 for (i = 0; i < num_args; i += 255)
452 nargs = (num_args - i > 255) ? 255 : num_args - i;
454 if (nargs <= 8)
455 BCI(PUSHB_1 - 1 + nargs);
456 else
458 BCI(NPUSHB);
459 BCI(nargs);
461 for (j = 0; j < nargs; j++)
463 BCI(*arg);
464 arg++;
469 BCI(CALL);
471 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
472 if (num_stack_elements > sfnt->max_stack_elements)
473 sfnt->max_stack_elements = num_stack_elements;
475 free(args);
477 return bufp;
481 static FT_Byte*
482 TA_font_build_subglyph_shifter(FONT* font,
483 FT_Byte* bufp)
485 FT_Face face = font->loader->face;
486 FT_GlyphSlot glyph = face->glyph;
488 TA_GlyphLoader gloader = font->loader->gloader;
490 TA_SubGlyph subglyphs = gloader->base.subglyphs;
491 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
492 TA_SubGlyph subglyph;
494 FT_Int curr_contour = 0;
497 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
499 FT_Error error;
501 FT_UShort flags = subglyph->flags;
502 FT_Pos y_offset = subglyph->arg2;
504 FT_Int num_contours;
507 /* load subglyph to get the number of contours */
508 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
509 if (error)
510 return NULL;
511 num_contours = glyph->outline.n_contours;
513 /* nothing to do if there is a point-to-point alignment */
514 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
515 goto End;
517 /* nothing to do if y offset is zero */
518 if (!y_offset)
519 goto End;
521 /* nothing to do if there are no contours */
522 if (!num_contours)
523 goto End;
525 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
526 /* ensures that composite subglyphs are represented as simple glyphs */
528 if (num_contours > 0xFF
529 || curr_contour > 0xFF)
531 BCI(PUSHW_2);
532 BCI(HIGH(curr_contour));
533 BCI(LOW(curr_contour));
534 BCI(HIGH(num_contours));
535 BCI(LOW(num_contours));
537 else
539 BCI(PUSHB_2);
540 BCI(curr_contour);
541 BCI(num_contours);
544 /* there are high chances that this value needs PUSHW, */
545 /* thus we handle it separately */
546 if (y_offset > 0xFF || y_offset < 0)
548 BCI(PUSHW_1);
549 BCI(HIGH(y_offset));
550 BCI(LOW(y_offset));
552 else
554 BCI(PUSHB_1);
555 BCI(y_offset);
558 BCI(PUSHB_1);
559 BCI(bci_shift_subglyph);
560 BCI(CALL);
562 End:
563 curr_contour += num_contours;
566 return bufp;
571 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
572 * data in four arrays (which are simple but waste a lot of memory). The
573 * function below converts them into bytecode.
575 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
576 * together with the edge they correspond to.
578 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
579 * loop over the edge or edge pairs, respectively, and each edge or edge
580 * pair contains an inner loop to emit the correponding points.
583 static void
584 TA_build_point_hints(Recorder* recorder,
585 TA_GlyphHints hints)
587 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
588 TA_Segment segments = axis->segments;
589 TA_Edge edges = axis->edges;
591 TA_Edge edge;
592 TA_Edge before;
593 TA_Edge after;
595 FT_Byte* p = recorder->hints_record.buf;
596 FT_UInt num_edges = axis->num_edges;
597 FT_UInt num_strong_points = recorder->num_strong_points;
599 FT_UInt i;
600 FT_UInt j;
601 FT_UInt k;
603 FT_UInt* ip;
604 FT_UInt* iq;
605 FT_UInt* ir;
606 FT_UInt* ip_limit;
607 FT_UInt* iq_limit;
608 FT_UInt* ir_limit;
611 /* we store everything as 16bit numbers; */
612 /* the function numbers (`ta_ip_before', etc.) */
613 /* reflect the order in the TA_Action enumeration */
615 /* ip_before_points */
617 i = 0;
618 ip = recorder->ip_before_points;
619 ip_limit = ip + num_strong_points;
620 for (; ip < ip_limit; ip++)
622 if (*ip != MISSING)
623 i++;
624 else
625 break;
628 if (i)
630 recorder->hints_record.num_actions++;
632 edge = edges;
634 *(p++) = 0;
635 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
636 *(p++) = HIGH(edge->first - segments);
637 *(p++) = LOW(edge->first - segments);
638 *(p++) = HIGH(i);
639 *(p++) = LOW(i);
641 ip = recorder->ip_before_points;
642 ip_limit = ip + i;
643 for (; ip < ip_limit; ip++)
645 FT_UInt point = TA_adjust_point_index(recorder, *ip);
648 *(p++) = HIGH(point);
649 *(p++) = LOW(point);
653 /* ip_after_points */
655 i = 0;
656 ip = recorder->ip_after_points;
657 ip_limit = ip + num_strong_points;
658 for (; ip < ip_limit; ip++)
660 if (*ip != MISSING)
661 i++;
662 else
663 break;
666 if (i)
668 recorder->hints_record.num_actions++;
670 edge = edges + axis->num_edges - 1;
672 *(p++) = 0;
673 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
674 *(p++) = HIGH(edge->first - segments);
675 *(p++) = LOW(edge->first - segments);
676 *(p++) = HIGH(i);
677 *(p++) = LOW(i);
679 ip = recorder->ip_after_points;
680 ip_limit = ip + i;
681 for (; ip < ip_limit; ip++)
683 FT_UInt point = TA_adjust_point_index(recorder, *ip);
686 *(p++) = HIGH(point);
687 *(p++) = LOW(point);
691 /* ip_on_point_array */
693 i = 0;
694 ip = recorder->ip_on_point_array;
695 ip_limit = ip + num_edges * num_strong_points;
696 for (; ip < ip_limit; ip += num_strong_points)
697 if (*ip != MISSING)
698 i++;
700 if (i)
702 recorder->hints_record.num_actions++;
704 *(p++) = 0;
705 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
706 *(p++) = HIGH(i);
707 *(p++) = LOW(i);
709 i = 0;
710 ip = recorder->ip_on_point_array;
711 ip_limit = ip + num_edges * num_strong_points;
712 for (; ip < ip_limit; ip += num_strong_points, i++)
714 if (*ip == MISSING)
715 continue;
717 edge = edges + i;
719 *(p++) = HIGH(edge->first - segments);
720 *(p++) = LOW(edge->first - segments);
722 j = 0;
723 iq = ip;
724 iq_limit = iq + num_strong_points;
725 for (; iq < iq_limit; iq++)
727 if (*iq != MISSING)
728 j++;
729 else
730 break;
733 *(p++) = HIGH(j);
734 *(p++) = LOW(j);
736 iq = ip;
737 iq_limit = iq + j;
738 for (; iq < iq_limit; iq++)
740 FT_UInt point = TA_adjust_point_index(recorder, *iq);
743 *(p++) = HIGH(point);
744 *(p++) = LOW(point);
749 /* ip_between_point_array */
751 i = 0;
752 ip = recorder->ip_between_point_array;
753 ip_limit = ip + num_edges * num_edges * num_strong_points;
754 for (; ip < ip_limit; ip += num_strong_points)
755 if (*ip != MISSING)
756 i++;
758 if (i)
760 recorder->hints_record.num_actions++;
762 *(p++) = 0;
763 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
764 *(p++) = HIGH(i);
765 *(p++) = LOW(i);
767 i = 0;
768 ip = recorder->ip_between_point_array;
769 ip_limit = ip + num_edges * num_edges * num_strong_points;
770 for (;
771 ip < ip_limit;
772 ip += num_edges * num_strong_points, i++)
774 before = edges + i;
776 j = 0;
777 iq = ip;
778 iq_limit = iq + num_edges * num_strong_points;
779 for (; iq < iq_limit; iq += num_strong_points, j++)
781 if (*iq == MISSING)
782 continue;
784 after = edges + j;
786 *(p++) = HIGH(after->first - segments);
787 *(p++) = LOW(after->first - segments);
788 *(p++) = HIGH(before->first - segments);
789 *(p++) = LOW(before->first - segments);
791 k = 0;
792 ir = iq;
793 ir_limit = ir + num_strong_points;
794 for (; ir < ir_limit; ir++)
796 if (*ir != MISSING)
797 k++;
798 else
799 break;
802 *(p++) = HIGH(k);
803 *(p++) = LOW(k);
805 ir = iq;
806 ir_limit = ir + k;
807 for (; ir < ir_limit; ir++)
809 FT_UInt point = TA_adjust_point_index(recorder, *ir);
812 *(p++) = HIGH(point);
813 *(p++) = LOW(point);
819 recorder->hints_record.buf = p;
823 static FT_Bool
824 TA_hints_record_is_different(Hints_Record* hints_records,
825 FT_UInt num_hints_records,
826 FT_Byte* start,
827 FT_Byte* end)
829 Hints_Record last_hints_record;
832 if (!hints_records)
833 return 1;
835 /* we only need to compare with the last hints record */
836 last_hints_record = hints_records[num_hints_records - 1];
838 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
839 return 1;
841 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
842 return 1;
844 return 0;
848 static FT_Error
849 TA_add_hints_record(Hints_Record** hints_records,
850 FT_UInt* num_hints_records,
851 FT_Byte* start,
852 Hints_Record hints_record)
854 Hints_Record* hints_records_new;
855 FT_UInt buf_len;
856 /* at this point, `hints_record.buf' still points into `ins_buf' */
857 FT_Byte* end = hints_record.buf;
860 buf_len = (FT_UInt)(end - start);
862 /* now fill the structure completely */
863 hints_record.buf_len = buf_len;
864 hints_record.buf = (FT_Byte*)malloc(buf_len);
865 if (!hints_record.buf)
866 return FT_Err_Out_Of_Memory;
868 memcpy(hints_record.buf, start, buf_len);
870 (*num_hints_records)++;
871 hints_records_new =
872 (Hints_Record*)realloc(*hints_records, *num_hints_records
873 * sizeof (Hints_Record));
874 if (!hints_records_new)
876 free(hints_record.buf);
877 (*num_hints_records)--;
878 return FT_Err_Out_Of_Memory;
880 else
881 *hints_records = hints_records_new;
883 (*hints_records)[*num_hints_records - 1] = hints_record;
885 return FT_Err_Ok;
889 static FT_Byte*
890 TA_emit_hints_record(Recorder* recorder,
891 Hints_Record* hints_record,
892 FT_Byte* bufp)
894 FT_Byte* p;
895 FT_Byte* endp;
896 FT_Bool need_words = 0;
898 FT_UInt i, j;
899 FT_UInt num_arguments;
900 FT_UInt num_args;
903 /* check whether any argument is larger than 0xFF */
904 endp = hints_record->buf + hints_record->buf_len;
905 for (p = hints_record->buf; p < endp; p += 2)
906 if (*p)
907 need_words = 1;
909 /* with most fonts it is very rare */
910 /* that any of the pushed arguments is larger than 0xFF, */
911 /* thus we refrain from further optimizing this case */
913 num_arguments = hints_record->buf_len / 2;
914 p = endp - 2;
916 if (need_words)
918 for (i = 0; i < num_arguments; i += 255)
920 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
922 BCI(NPUSHW);
923 BCI(num_args);
924 for (j = 0; j < num_args; j++)
926 BCI(*p);
927 BCI(*(p + 1));
928 p -= 2;
932 else
934 /* we only need the lower bytes */
935 p++;
937 for (i = 0; i < num_arguments; i += 255)
939 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
941 BCI(NPUSHB);
942 BCI(num_args);
943 for (j = 0; j < num_args; j++)
945 BCI(*p);
946 p -= 2;
951 /* collect stack depth data */
952 if (num_arguments > recorder->num_stack_elements)
953 recorder->num_stack_elements = num_arguments;
955 return bufp;
959 static FT_Byte*
960 TA_emit_hints_records(Recorder* recorder,
961 Hints_Record* hints_records,
962 FT_UInt num_hints_records,
963 FT_Byte* bufp)
965 FT_UInt i;
966 Hints_Record* hints_record;
969 hints_record = hints_records;
971 for (i = 0; i < num_hints_records - 1; i++)
973 BCI(MPPEM);
974 if (hints_record->size > 0xFF)
976 BCI(PUSHW_1);
977 BCI(HIGH((hints_record + 1)->size));
978 BCI(LOW((hints_record + 1)->size));
980 else
982 BCI(PUSHB_1);
983 BCI((hints_record + 1)->size);
985 BCI(LT);
986 BCI(IF);
987 bufp = TA_emit_hints_record(recorder, hints_record, bufp);
988 BCI(ELSE);
990 hints_record++;
993 bufp = TA_emit_hints_record(recorder, hints_record, bufp);
995 for (i = 0; i < num_hints_records - 1; i++)
996 BCI(EIF);
998 return bufp;
1002 static void
1003 TA_free_hints_records(Hints_Record* hints_records,
1004 FT_UInt num_hints_records)
1006 FT_UInt i;
1009 for (i = 0; i < num_hints_records; i++)
1010 free(hints_records[i].buf);
1012 free(hints_records);
1016 static FT_Byte*
1017 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1018 TA_AxisHints axis,
1019 TA_Edge edge,
1020 FT_UInt* wraps)
1022 TA_Segment segments = axis->segments;
1023 TA_Segment seg;
1024 FT_UInt seg_idx;
1025 FT_UInt num_segs = 0;
1026 FT_UInt* wrap;
1029 seg_idx = edge->first - segments;
1031 /* we store everything as 16bit numbers */
1032 *(bufp++) = HIGH(seg_idx);
1033 *(bufp++) = LOW(seg_idx);
1035 /* wrap-around segments are stored as two segments */
1036 if (edge->first->first > edge->first->last)
1037 num_segs++;
1039 seg = edge->first->edge_next;
1040 while (seg != edge->first)
1042 num_segs++;
1044 if (seg->first > seg->last)
1045 num_segs++;
1047 seg = seg->edge_next;
1050 *(bufp++) = HIGH(num_segs);
1051 *(bufp++) = LOW(num_segs);
1053 if (edge->first->first > edge->first->last)
1055 /* emit second part of wrap-around segment; */
1056 /* the bytecode positions such segments after `normal' ones */
1057 wrap = wraps;
1058 for (;;)
1060 if (seg_idx == *wrap)
1061 break;
1062 wrap++;
1065 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1066 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1069 seg = edge->first->edge_next;
1070 while (seg != edge->first)
1072 seg_idx = seg - segments;
1074 *(bufp++) = HIGH(seg_idx);
1075 *(bufp++) = LOW(seg_idx);
1077 if (seg->first > seg->last)
1079 wrap = wraps;
1080 for (;;)
1082 if (seg_idx == *wrap)
1083 break;
1084 wrap++;
1087 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1088 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1091 seg = seg->edge_next;
1094 return bufp;
1098 static void
1099 TA_hints_recorder(TA_Action action,
1100 TA_GlyphHints hints,
1101 TA_Dimension dim,
1102 void* arg1,
1103 TA_Edge arg2,
1104 TA_Edge arg3,
1105 TA_Edge lower_bound,
1106 TA_Edge upper_bound)
1108 TA_AxisHints axis = &hints->axis[dim];
1109 TA_Edge edges = axis->edges;
1110 TA_Segment segments = axis->segments;
1111 TA_Point points = hints->points;
1113 Recorder* recorder = (Recorder*)hints->user;
1114 FONT* font = recorder->font;
1115 FT_UInt* wraps = recorder->wrap_around_segments;
1116 FT_Byte* p = recorder->hints_record.buf;
1118 FT_UInt* ip;
1119 FT_UInt* limit;
1122 if (dim == TA_DIMENSION_HORZ)
1123 return;
1125 /* we collect point hints for later processing */
1126 switch (action)
1128 case ta_ip_before:
1130 TA_Point point = (TA_Point)arg1;
1133 ip = recorder->ip_before_points;
1134 limit = ip + recorder->num_strong_points;
1135 for (; ip < limit; ip++)
1137 if (*ip == MISSING)
1139 *ip = point - points;
1140 break;
1144 return;
1146 case ta_ip_after:
1148 TA_Point point = (TA_Point)arg1;
1151 ip = recorder->ip_after_points;
1152 limit = ip + recorder->num_strong_points;
1153 for (; ip < limit; ip++)
1155 if (*ip == MISSING)
1157 *ip = point - points;
1158 break;
1162 return;
1164 case ta_ip_on:
1166 TA_Point point = (TA_Point)arg1;
1167 TA_Edge edge = arg2;
1170 ip = recorder->ip_on_point_array
1171 + recorder->num_strong_points
1172 * (edge - edges);
1173 limit = ip + recorder->num_strong_points;
1174 for (; ip < limit; ip++)
1176 if (*ip == MISSING)
1178 *ip = point - points;
1179 break;
1183 return;
1185 case ta_ip_between:
1187 TA_Point point = (TA_Point)arg1;
1188 TA_Edge before = arg2;
1189 TA_Edge after = arg3;
1192 /* note that `recorder->num_segments' has been used for allocation, */
1193 /* but `axis->num_edges' is used for accessing this array */
1194 ip = recorder->ip_between_point_array
1195 + recorder->num_strong_points * axis->num_edges
1196 * (before - edges)
1197 + recorder->num_strong_points
1198 * (after - edges);
1199 limit = ip + recorder->num_strong_points;
1200 for (; ip < limit; ip++)
1202 if (*ip == MISSING)
1204 *ip = point - points;
1205 break;
1209 return;
1211 case ta_bound:
1212 /* we ignore the BOUND action since we signal this information */
1213 /* with the proper function number */
1214 return;
1216 default:
1217 break;
1220 /* some enum values correspond to four or eight bytecode functions; */
1221 /* if the value is n, the function numbers are n, ..., n+7, */
1222 /* to be differentiated with flags */
1224 switch (action)
1226 case ta_link:
1228 TA_Edge base_edge = (TA_Edge)arg1;
1229 TA_Edge stem_edge = arg2;
1232 *(p++) = 0;
1233 *(p++) = (FT_Byte)action + ACTION_OFFSET
1234 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1235 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1237 *(p++) = HIGH(base_edge->first - segments);
1238 *(p++) = LOW(base_edge->first - segments);
1239 *(p++) = HIGH(stem_edge->first - segments);
1240 *(p++) = LOW(stem_edge->first - segments);
1242 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1244 break;
1246 case ta_anchor:
1248 TA_Edge edge = (TA_Edge)arg1;
1249 TA_Edge edge2 = arg2;
1252 *(p++) = 0;
1253 *(p++) = (FT_Byte)action + ACTION_OFFSET
1254 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1255 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1257 *(p++) = HIGH(edge->first - segments);
1258 *(p++) = LOW(edge->first - segments);
1259 *(p++) = HIGH(edge2->first - segments);
1260 *(p++) = LOW(edge2->first - segments);
1262 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1264 break;
1266 case ta_adjust:
1268 TA_Edge edge = (TA_Edge)arg1;
1269 TA_Edge edge2 = arg2;
1270 TA_Edge edge_minus_one = lower_bound;
1273 *(p++) = 0;
1274 *(p++) = (FT_Byte)action + ACTION_OFFSET
1275 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1276 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1277 + 4 * (edge_minus_one != NULL);
1279 *(p++) = HIGH(edge->first - segments);
1280 *(p++) = LOW(edge->first - segments);
1281 *(p++) = HIGH(edge2->first - segments);
1282 *(p++) = LOW(edge2->first - segments);
1284 if (edge_minus_one)
1286 *(p++) = HIGH(edge_minus_one->first - segments);
1287 *(p++) = LOW(edge_minus_one->first - segments);
1290 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1292 break;
1294 case ta_blue_anchor:
1296 TA_Edge edge = (TA_Edge)arg1;
1297 TA_Edge blue = arg2;
1300 *(p++) = 0;
1301 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1303 *(p++) = HIGH(blue->first - segments);
1304 *(p++) = LOW(blue->first - segments);
1306 if (edge->best_blue_is_shoot)
1308 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1309 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1311 else
1313 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1314 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1317 *(p++) = HIGH(edge->first - segments);
1318 *(p++) = LOW(edge->first - segments);
1320 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1322 break;
1324 case ta_stem:
1326 TA_Edge edge = (TA_Edge)arg1;
1327 TA_Edge edge2 = arg2;
1328 TA_Edge edge_minus_one = lower_bound;
1331 *(p++) = 0;
1332 *(p++) = (FT_Byte)action + ACTION_OFFSET
1333 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1334 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1335 + 4 * (edge_minus_one != NULL);
1337 *(p++) = HIGH(edge->first - segments);
1338 *(p++) = LOW(edge->first - segments);
1339 *(p++) = HIGH(edge2->first - segments);
1340 *(p++) = LOW(edge2->first - segments);
1342 if (edge_minus_one)
1344 *(p++) = HIGH(edge_minus_one->first - segments);
1345 *(p++) = LOW(edge_minus_one->first - segments);
1348 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1349 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1351 break;
1353 case ta_blue:
1355 TA_Edge edge = (TA_Edge)arg1;
1358 *(p++) = 0;
1359 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1361 if (edge->best_blue_is_shoot)
1363 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1364 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1366 else
1368 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1369 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1372 *(p++) = HIGH(edge->first - segments);
1373 *(p++) = LOW(edge->first - segments);
1375 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1377 break;
1379 case ta_serif:
1381 TA_Edge serif = (TA_Edge)arg1;
1382 TA_Edge base = serif->serif;
1385 *(p++) = 0;
1386 *(p++) = (FT_Byte)action + ACTION_OFFSET
1387 + (lower_bound != NULL)
1388 + 2 * (upper_bound != NULL);
1390 *(p++) = HIGH(serif->first - segments);
1391 *(p++) = LOW(serif->first - segments);
1392 *(p++) = HIGH(base->first - segments);
1393 *(p++) = LOW(base->first - segments);
1395 if (lower_bound)
1397 *(p++) = HIGH(lower_bound->first - segments);
1398 *(p++) = LOW(lower_bound->first - segments);
1400 if (upper_bound)
1402 *(p++) = HIGH(upper_bound->first - segments);
1403 *(p++) = LOW(upper_bound->first - segments);
1406 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1408 break;
1410 case ta_serif_anchor:
1411 case ta_serif_link2:
1413 TA_Edge edge = (TA_Edge)arg1;
1416 *(p++) = 0;
1417 *(p++) = (FT_Byte)action + ACTION_OFFSET
1418 + (lower_bound != NULL)
1419 + 2 * (upper_bound != NULL);
1421 *(p++) = HIGH(edge->first - segments);
1422 *(p++) = LOW(edge->first - segments);
1424 if (lower_bound)
1426 *(p++) = HIGH(lower_bound->first - segments);
1427 *(p++) = LOW(lower_bound->first - segments);
1429 if (upper_bound)
1431 *(p++) = HIGH(upper_bound->first - segments);
1432 *(p++) = LOW(upper_bound->first - segments);
1435 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1437 break;
1439 case ta_serif_link1:
1441 TA_Edge edge = (TA_Edge)arg1;
1442 TA_Edge before = arg2;
1443 TA_Edge after = arg3;
1446 *(p++) = 0;
1447 *(p++) = (FT_Byte)action + ACTION_OFFSET
1448 + (lower_bound != NULL)
1449 + 2 * (upper_bound != NULL);
1451 *(p++) = HIGH(before->first - segments);
1452 *(p++) = LOW(before->first - segments);
1453 *(p++) = HIGH(edge->first - segments);
1454 *(p++) = LOW(edge->first - segments);
1455 *(p++) = HIGH(after->first - segments);
1456 *(p++) = LOW(after->first - segments);
1458 if (lower_bound)
1460 *(p++) = HIGH(lower_bound->first - segments);
1461 *(p++) = LOW(lower_bound->first - segments);
1463 if (upper_bound)
1465 *(p++) = HIGH(upper_bound->first - segments);
1466 *(p++) = LOW(upper_bound->first - segments);
1469 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1471 break;
1473 default:
1474 /* there are more cases in the enumeration */
1475 /* which are handled with flags */
1476 break;
1479 recorder->hints_record.num_actions++;
1480 recorder->hints_record.buf = p;
1484 static FT_Error
1485 TA_init_recorder(Recorder* recorder,
1486 FONT* font,
1487 GLYPH* glyph,
1488 TA_GlyphHints hints)
1490 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1491 TA_Point points = hints->points;
1492 TA_Point point_limit = points + hints->num_points;
1493 TA_Point point;
1495 TA_Segment segments = axis->segments;
1496 TA_Segment seg_limit = segments + axis->num_segments;
1497 TA_Segment seg;
1499 FT_UInt num_strong_points = 0;
1500 FT_UInt* wrap_around_segment;
1502 recorder->font = font;
1503 recorder->glyph = glyph;
1504 recorder->num_segments = axis->num_segments;
1506 recorder->ip_before_points = NULL;
1507 recorder->ip_after_points = NULL;
1508 recorder->ip_on_point_array = NULL;
1509 recorder->ip_between_point_array = NULL;
1511 recorder->num_stack_elements = 0;
1513 /* no need to clean up allocated arrays in case of error; */
1514 /* this is handled later by `TA_free_recorder' */
1516 recorder->num_wrap_around_segments = 0;
1517 for (seg = segments; seg < seg_limit; seg++)
1518 if (seg->first > seg->last)
1519 recorder->num_wrap_around_segments++;
1521 recorder->wrap_around_segments =
1522 (FT_UInt*)malloc(recorder->num_wrap_around_segments * sizeof (FT_UInt));
1523 if (!recorder->wrap_around_segments)
1524 return FT_Err_Out_Of_Memory;
1526 wrap_around_segment = recorder->wrap_around_segments;
1527 for (seg = segments; seg < seg_limit; seg++)
1528 if (seg->first > seg->last)
1529 *(wrap_around_segment++) = seg - segments;
1531 /* get number of strong points */
1532 for (point = points; point < point_limit; point++)
1534 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1535 /* however, this value isn't known yet */
1536 /* (or rather, it can vary between different pixel sizes) */
1537 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1538 continue;
1540 num_strong_points++;
1543 recorder->num_strong_points = num_strong_points;
1545 recorder->ip_before_points =
1546 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1547 if (!recorder->ip_before_points)
1548 return FT_Err_Out_Of_Memory;
1550 recorder->ip_after_points =
1551 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1552 if (!recorder->ip_after_points)
1553 return FT_Err_Out_Of_Memory;
1555 /* actually, we need `hints->num_edges' for the array sizes; */
1556 /* however, this value isn't known yet */
1557 /* (or rather, it can vary between different pixel sizes) */
1558 recorder->ip_on_point_array =
1559 (FT_UInt*)malloc(axis->num_segments
1560 * num_strong_points * sizeof (FT_UInt));
1561 if (!recorder->ip_on_point_array)
1562 return FT_Err_Out_Of_Memory;
1564 recorder->ip_between_point_array =
1565 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1566 * num_strong_points * sizeof (FT_UInt));
1567 if (!recorder->ip_between_point_array)
1568 return FT_Err_Out_Of_Memory;
1570 return FT_Err_Ok;
1574 static void
1575 TA_reset_recorder(Recorder* recorder,
1576 FT_Byte* bufp)
1578 recorder->hints_record.buf = bufp;
1579 recorder->hints_record.num_actions = 0;
1583 static void
1584 TA_rewind_recorder(Recorder* recorder,
1585 FT_Byte* bufp,
1586 FT_UInt size)
1588 TA_reset_recorder(recorder, bufp);
1590 recorder->hints_record.size = size;
1592 /* We later check with MISSING (which expands to 0xFF bytes) */
1594 memset(recorder->ip_before_points, 0xFF,
1595 recorder->num_strong_points * sizeof (FT_UInt));
1596 memset(recorder->ip_after_points, 0xFF,
1597 recorder->num_strong_points * sizeof (FT_UInt));
1599 memset(recorder->ip_on_point_array, 0xFF,
1600 recorder->num_segments
1601 * recorder->num_strong_points * sizeof (FT_UInt));
1602 memset(recorder->ip_between_point_array, 0xFF,
1603 recorder->num_segments * recorder->num_segments
1604 * recorder->num_strong_points * sizeof (FT_UInt));
1608 static void
1609 TA_free_recorder(Recorder* recorder)
1611 free(recorder->wrap_around_segments);
1613 free(recorder->ip_before_points);
1614 free(recorder->ip_after_points);
1615 free(recorder->ip_on_point_array);
1616 free(recorder->ip_between_point_array);
1620 FT_Error
1621 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1622 FONT* font,
1623 FT_Long idx)
1625 FT_Face face = sfnt->face;
1626 FT_Error error;
1628 FT_Byte* ins_buf;
1629 FT_UInt ins_len;
1630 FT_Byte* bufp;
1631 FT_Byte* p;
1633 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1634 glyf_Data* data = (glyf_Data*)glyf_table->data;
1635 /* `idx' is never negative */
1636 GLYPH* glyph = &data->glyphs[idx];
1638 TA_GlyphHints hints;
1640 FT_UInt num_action_hints_records;
1641 FT_UInt num_point_hints_records;
1642 Hints_Record* action_hints_records;
1643 Hints_Record* point_hints_records;
1645 Recorder recorder;
1646 FT_UInt num_stack_elements;
1648 FT_Int32 load_flags;
1649 FT_UInt size;
1651 FT_Byte* pos[3];
1654 /* XXX: right now, we abuse this flag to control */
1655 /* the global behaviour of the auto-hinter */
1656 load_flags = font->fallback_script << 30;
1657 load_flags |= 1 << 28; /* vertical hinting only */
1658 if (font->increase_x_height)
1659 load_flags |= 1 << 29;
1660 if (!font->pre_hinting)
1661 load_flags |= FT_LOAD_NO_SCALE;
1663 /* computing the segments is resolution independent, */
1664 /* thus the pixel size in this call is arbitrary */
1665 error = FT_Set_Pixel_Sizes(face, 20, 20);
1666 if (error)
1667 return error;
1669 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1670 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1671 if (error)
1672 return error;
1674 /* do nothing if we have an empty glyph */
1675 if (!face->glyph->outline.n_contours)
1676 return FT_Err_Ok;
1678 hints = &font->loader->hints;
1680 /* do nothing if the setup delivered the dummy module only */
1681 if (!hints->num_points)
1682 return FT_Err_Ok;
1684 /* we allocate a buffer which is certainly large enough */
1685 /* to hold all of the created bytecode instructions; */
1686 /* later on it gets reallocated to its real size */
1687 ins_len = hints->num_points * 1000;
1688 ins_buf = (FT_Byte*)malloc(ins_len);
1689 if (!ins_buf)
1690 return FT_Err_Out_Of_Memory;
1692 /* initialize array with an invalid bytecode */
1693 /* so that we can easily find the array length at reallocation time */
1694 memset(ins_buf, INS_A0, ins_len);
1696 /* handle composite glyph */
1697 if (font->loader->gloader->base.num_subglyphs)
1699 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1700 if (!bufp)
1702 error = FT_Err_Out_Of_Memory;
1703 goto Err;
1706 goto Done1;
1709 /* only scale the glyph if the dummy hinter has been used */
1710 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1712 /* since `TA_init_recorder' hasn't been called yet, */
1713 /* we manually initialize the `glyph' field */
1714 recorder.glyph = glyph;
1716 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1717 if (!bufp)
1719 error = FT_Err_Out_Of_Memory;
1720 goto Err;
1723 goto Done1;
1726 error = TA_init_recorder(&recorder, font, glyph, hints);
1727 if (error)
1728 goto Err;
1730 /* loop over a large range of pixel sizes */
1731 /* to find hints records which get pushed onto the bytecode stack */
1733 #ifdef DEBUGGING
1735 int num_chars, i;
1738 num_chars = fprintf(stderr, "glyph %ld\n", idx);
1739 for (i = 0; i < num_chars - 1; i++)
1740 putc('=', stderr);
1741 fprintf(stderr, "\n\n");
1744 #endif
1746 /* we temporarily use `ins_buf' to record the current glyph hints */
1747 ta_loader_register_hints_recorder(font->loader,
1748 TA_hints_recorder,
1749 (void*)&recorder);
1751 num_action_hints_records = 0;
1752 num_point_hints_records = 0;
1753 action_hints_records = NULL;
1754 point_hints_records = NULL;
1756 for (size = font->hinting_range_min;
1757 size <= font->hinting_range_max;
1758 size++)
1760 #ifdef DEBUGGING
1761 int have_dumps = 0;
1762 #endif
1765 TA_rewind_recorder(&recorder, ins_buf, size);
1767 error = FT_Set_Pixel_Sizes(face, size, size);
1768 if (error)
1769 goto Err;
1771 /* calling `ta_loader_load_glyph' uses the */
1772 /* `TA_hints_recorder' function as a callback, */
1773 /* modifying `hints_record' */
1774 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1775 if (error)
1776 goto Err;
1778 if (TA_hints_record_is_different(action_hints_records,
1779 num_action_hints_records,
1780 ins_buf, recorder.hints_record.buf))
1782 #ifdef DEBUGGING
1784 have_dumps = 1;
1786 fprintf(stderr, " size %d:\n", size);
1788 ta_glyph_hints_dump_edges(_ta_debug_hints);
1789 ta_glyph_hints_dump_segments(_ta_debug_hints);
1790 ta_glyph_hints_dump_points(_ta_debug_hints);
1792 fprintf(stderr, " action hints record:\n");
1793 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1794 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1795 fprintf(stderr, "\n");
1797 #endif
1799 error = TA_add_hints_record(&action_hints_records,
1800 &num_action_hints_records,
1801 ins_buf, recorder.hints_record);
1802 if (error)
1803 goto Err;
1806 /* now handle point records */
1808 TA_reset_recorder(&recorder, ins_buf);
1810 /* use the point hints data collected in `TA_hints_recorder' */
1811 TA_build_point_hints(&recorder, hints);
1813 if (TA_hints_record_is_different(point_hints_records,
1814 num_point_hints_records,
1815 ins_buf, recorder.hints_record.buf))
1817 #ifdef DEBUGGING
1819 if (!have_dumps)
1821 fprintf(stderr, " size %d:\n", size);
1823 ta_glyph_hints_dump_edges(_ta_debug_hints);
1824 ta_glyph_hints_dump_segments(_ta_debug_hints);
1825 ta_glyph_hints_dump_points(_ta_debug_hints);
1828 fprintf(stderr, " point hints record:\n");
1829 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1830 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1831 fprintf(stderr, "\n");
1833 #endif
1835 error = TA_add_hints_record(&point_hints_records,
1836 &num_point_hints_records,
1837 ins_buf, recorder.hints_record);
1838 if (error)
1839 goto Err;
1843 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1845 /* since we only have a single empty record we just scale the glyph */
1846 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1847 if (!bufp)
1849 error = FT_Err_Out_Of_Memory;
1850 goto Err;
1853 /* clear the rest of the temporarily used part of `ins_buf' */
1854 p = bufp;
1855 while (*p != INS_A0)
1856 *(p++) = INS_A0;
1858 goto Done;
1861 /* store the hints records and handle stack depth */
1862 pos[0] = ins_buf;
1863 bufp = TA_emit_hints_records(&recorder,
1864 point_hints_records,
1865 num_point_hints_records,
1866 ins_buf);
1868 num_stack_elements = recorder.num_stack_elements;
1869 recorder.num_stack_elements = 0;
1871 pos[1] = bufp;
1872 bufp = TA_emit_hints_records(&recorder,
1873 action_hints_records,
1874 num_action_hints_records,
1875 bufp);
1876 recorder.num_stack_elements += num_stack_elements;
1878 pos[2] = bufp;
1879 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp);
1880 if (!bufp)
1882 error = FT_Err_Out_Of_Memory;
1883 goto Err;
1886 /* XXX do nothing if we have NPUSHW in the data */
1887 if (num_action_hints_records == 1
1888 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1891 * we optimize two common cases, replacing
1893 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1895 * with
1897 * NPUSHB (A+B[+C]) ... CALL
1899 * if possible
1901 FT_Byte sizes[3];
1902 FT_Byte new_size1;
1903 FT_Byte new_size2;
1905 FT_UInt sum;
1906 FT_UInt i;
1907 FT_UInt pos_idx;
1910 /* the point hints records block can be missing */
1911 if (pos[0] == pos[1])
1913 pos[1] = pos[2];
1914 pos[2] = NULL;
1917 /* there are at least two NPUSHB instructions */
1918 /* (one of them directly at the start) */
1919 sizes[0] = *(pos[0] + 1);
1920 sizes[1] = *(pos[1] + 1);
1921 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
1923 sum = sizes[0] + sizes[1] + sizes[2];
1925 if (sum > 2 * 0xFF)
1926 goto Done2; /* nothing to do since we need three NPUSHB */
1927 else if (!sizes[2] && (sum > 0xFF))
1928 goto Done2; /* nothing to do since we need two NPUSHB */
1930 if (sum > 0xFF)
1932 /* reduce three NPUSHB to two */
1933 new_size1 = 0xFF;
1934 new_size2 = sum - 0xFF;
1936 else
1938 /* reduce two or three NPUSHB to one */
1939 new_size1 = sum;
1940 new_size2 = 0;
1943 /* pack data */
1944 p = ins_buf;
1945 bufp = ins_buf;
1946 pos_idx = 0;
1948 if (new_size1 <= 8)
1949 BCI(PUSHB_1 - 1 + new_size1);
1950 else
1952 BCI(NPUSHB);
1953 BCI(new_size1);
1955 for (i = 0; i < new_size1; i++)
1957 if (p == pos[pos_idx])
1959 pos_idx++;
1960 p += 2; /* skip old NPUSHB */
1962 *(bufp++) = *(p++);
1965 if (new_size2)
1967 if (new_size2 <= 8)
1968 BCI(PUSHB_1 - 1 + new_size2);
1969 else
1971 BCI(NPUSHB);
1972 BCI(new_size2);
1974 for (i = 0; i < new_size2; i++)
1976 if (p == pos[pos_idx])
1978 pos_idx++;
1979 p += 2;
1981 *(bufp++) = *(p++);
1985 BCI(CALL);
1988 Done2:
1989 /* clear the rest of the temporarily used part of `ins_buf' */
1990 p = bufp;
1991 while (*p != INS_A0)
1992 *(p++) = INS_A0;
1994 Done:
1995 TA_free_hints_records(action_hints_records, num_action_hints_records);
1996 TA_free_recorder(&recorder);
1998 /* we are done, so reallocate the instruction array to its real size */
1999 if (*bufp == INS_A0)
2001 /* search backwards */
2002 while (*bufp == INS_A0)
2003 bufp--;
2004 bufp++;
2006 else
2008 /* search forwards */
2009 while (*bufp != INS_A0)
2010 bufp++;
2013 Done1:
2014 ins_len = bufp - ins_buf;
2016 if (ins_len > sfnt->max_instructions)
2017 sfnt->max_instructions = ins_len;
2019 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2020 glyph->ins_len = ins_len;
2022 return FT_Err_Ok;
2024 Err:
2025 TA_free_hints_records(action_hints_records, num_action_hints_records);
2026 TA_free_recorder(&recorder);
2027 free(ins_buf);
2029 return error;
2033 /* end of tabytecode.c */