Move common code into a new function, `TA_build_push'.
[ttfautohint.git] / lib / tabytecode.c
blobe35c6d44a9c0e852b8eddd53e9734d7c3e06cb0b
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_UShort)~0
23 /* we increase the stack depth by this amount */
24 #define ADDITIONAL_STACK_ELEMENTS 20
27 #define DEBUGGING
30 #ifdef TA_DEBUG
31 int _ta_debug = 0;
32 int _ta_debug_disable_horz_hints;
33 int _ta_debug_disable_vert_hints;
34 int _ta_debug_disable_blue_hints;
35 void* _ta_debug_hints;
36 #endif
39 typedef struct Hints_Record_
41 FT_UInt size;
42 FT_UInt num_actions;
43 FT_Byte* buf;
44 FT_UInt buf_len;
45 } Hints_Record;
47 typedef struct Recorder_
49 FONT* font;
50 GLYPH* glyph; /* the current glyph */
51 Hints_Record hints_record;
53 /* some segments can `wrap around' */
54 /* a contour's start point like 24-25-26-0-1-2 */
55 /* (there can be at most one such segment per contour); */
56 /* later on we append additional records */
57 /* to split them into 24-26 and 0-2 */
58 FT_UShort* wrap_around_segments;
59 FT_UShort num_wrap_around_segments;
61 FT_UShort num_stack_elements; /* the necessary stack depth so far */
63 /* data necessary for strong point interpolation */
64 FT_UShort* ip_before_points;
65 FT_UShort* ip_after_points;
66 FT_UShort* ip_on_point_array;
67 FT_UShort* ip_between_point_array;
69 FT_UShort num_strong_points;
70 FT_UShort num_segments;
71 } Recorder;
74 /* this is the bytecode of the `.ttfautohint' glyph */
76 FT_Byte ttfautohint_glyph_bytecode[7] =
79 /* increment `cvtl_is_subglyph' counter */
80 PUSHB_3,
81 cvtl_is_subglyph,
83 cvtl_is_subglyph,
84 RCVT,
85 ADD,
86 WCVTP,
92 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
93 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
94 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
95 * PUSHW_X gets used
98 FT_Byte*
99 TA_build_push(FT_Byte* bufp,
100 FT_UInt* args,
101 FT_UInt num_args,
102 FT_Bool need_words,
103 FT_Bool optimize)
105 FT_UInt* arg = args;
106 FT_UInt i, j, nargs;
109 if (need_words)
111 for (i = 0; i < num_args; i += 255)
113 nargs = (num_args - i > 255) ? 255 : num_args - i;
115 if (optimize && nargs <= 8)
116 BCI(PUSHW_1 - 1 + nargs);
117 else
119 BCI(NPUSHW);
120 BCI(nargs);
122 for (j = 0; j < nargs; j++)
124 BCI(HIGH(*arg));
125 BCI(LOW(*arg));
126 arg++;
130 else
132 for (i = 0; i < num_args; i += 255)
134 nargs = (num_args - i > 255) ? 255 : num_args - i;
136 if (optimize && nargs <= 8)
137 BCI(PUSHB_1 - 1 + nargs);
138 else
140 BCI(NPUSHB);
141 BCI(nargs);
143 for (j = 0; j < nargs; j++)
145 BCI(*arg);
146 arg++;
151 return bufp;
155 /* We add a subglyph for each composite glyph. */
156 /* Since subglyphs must contain at least one point, */
157 /* we have to adjust all point indices accordingly. */
158 /* Using the `pointsums' array of the `GLYPH' structure */
159 /* it is straightforward to do that: */
160 /* Assuming that point with index x is in the interval */
161 /* pointsums[n] <= x < pointsums[n + 1], */
162 /* the new point index is x + n. */
164 static FT_UInt
165 TA_adjust_point_index(Recorder* recorder,
166 FT_UInt idx)
168 FONT* font = recorder->font;
169 GLYPH* glyph = recorder->glyph;
170 FT_UShort i;
173 if (!glyph->num_components || !font->hint_with_components)
174 return idx; /* not a composite glyph */
176 for (i = 0; i < glyph->num_pointsums; i++)
177 if (idx < glyph->pointsums[i])
178 break;
180 return idx + i;
184 /* we store the segments in the storage area; */
185 /* each segment record consists of the first and last point */
187 static FT_Byte*
188 TA_sfnt_build_glyph_segments(SFNT* sfnt,
189 Recorder* recorder,
190 FT_Byte* bufp,
191 FT_Bool optimize)
193 FONT* font = recorder->font;
194 TA_GlyphHints hints = &font->loader->hints;
195 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
196 TA_Point points = hints->points;
197 TA_Segment segments = axis->segments;
198 TA_Segment seg;
199 TA_Segment seg_limit;
201 FT_Outline outline = font->loader->gloader->base.outline;
203 FT_UInt* args;
204 FT_UInt* arg;
205 FT_UInt num_args;
206 FT_UShort num_segments;
208 FT_Bool need_words = 0;
210 FT_Int n;
211 FT_UInt base;
212 FT_UShort num_packed_segments;
213 FT_UShort num_storage;
214 FT_UShort num_stack_elements;
215 FT_UShort num_twilight_points;
218 seg_limit = segments + axis->num_segments;
219 num_segments = axis->num_segments;
221 /* to pack the data in the bytecode more tightly, */
222 /* we store up to the first nine segments in nibbles if possible, */
223 /* using delta values */
224 base = 0;
225 num_packed_segments = 0;
226 for (seg = segments; seg < seg_limit; seg++)
228 FT_UInt first = seg->first - points;
229 FT_UInt last = seg->last - points;
232 first = TA_adjust_point_index(recorder, first);
233 last = TA_adjust_point_index(recorder, last);
235 if (first - base >= 16)
236 break;
237 if (first > last || last - first >= 16)
238 break;
239 if (num_packed_segments == 9)
240 break;
241 num_packed_segments++;
242 base = last;
245 /* also handle wrap-around segments */
246 num_segments += recorder->num_wrap_around_segments;
248 /* wrap-around segments are pushed with four arguments; */
249 /* a segment stored in nibbles needs only one byte instead of two */
250 num_args = num_packed_segments
251 + 2 * (num_segments - num_packed_segments)
252 + 2 * recorder->num_wrap_around_segments
253 + 2;
255 /* collect all arguments temporarily in an array (in reverse order) */
256 /* so that we can easily split into chunks of 255 args */
257 /* as needed by NPUSHB and NPUSHW, respectively */
258 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
259 if (!args)
260 return NULL;
262 arg = args + num_args - 1;
264 if (num_segments > 0xFF)
265 need_words = 1;
267 /* the number of packed segments is indicated by the function number */
268 if (recorder->glyph->num_components && font->hint_with_components)
269 *(arg--) = bci_create_segments_composite_0 + num_packed_segments;
270 else
271 *(arg--) = bci_create_segments_0 + num_packed_segments;
272 *(arg--) = num_segments;
274 base = 0;
275 for (seg = segments; seg < segments + num_packed_segments; seg++)
277 FT_UInt first = seg->first - points;
278 FT_UInt last = seg->last - points;
279 FT_UInt low_nibble;
280 FT_UInt high_nibble;
283 first = TA_adjust_point_index(recorder, first);
284 last = TA_adjust_point_index(recorder, last);
286 low_nibble = first - base;
287 high_nibble = last - first;
289 *(arg--) = 16 * high_nibble + low_nibble;
291 base = last;
294 for (seg = segments + num_packed_segments; seg < seg_limit; seg++)
296 FT_UInt first = seg->first - points;
297 FT_UInt last = seg->last - points;
300 *(arg--) = TA_adjust_point_index(recorder, first);
301 *(arg--) = TA_adjust_point_index(recorder, last);
303 /* we push the last and first contour point */
304 /* as a third and fourth argument in wrap-around segments */
305 if (first > last)
307 for (n = 0; n < outline.n_contours; n++)
309 FT_UInt end = (FT_UInt)outline.contours[n];
312 if (first <= end)
314 *(arg--) = TA_adjust_point_index(recorder, end);
315 if (end > 0xFF)
316 need_words = 1;
318 if (n == 0)
319 *(arg--) = TA_adjust_point_index(recorder, 0);
320 else
321 *(arg--) = TA_adjust_point_index(recorder,
322 (FT_UInt)outline.contours[n - 1] + 1);
323 break;
328 if (last > 0xFF)
329 need_words = 1;
332 /* emit the second part of wrap-around segments as separate segments */
333 /* so that edges can easily link to them */
334 for (seg = segments; seg < seg_limit; seg++)
336 FT_UInt first = seg->first - points;
337 FT_UInt last = seg->last - points;
340 if (first > last)
342 for (n = 0; n < outline.n_contours; n++)
344 if (first <= (FT_UInt)outline.contours[n])
346 if (n == 0)
347 *(arg--) = TA_adjust_point_index(recorder, 0);
348 else
349 *(arg--) = TA_adjust_point_index(recorder,
350 (FT_UInt)outline.contours[n - 1] + 1);
351 break;
355 *(arg--) = TA_adjust_point_index(recorder, last);
359 /* with most fonts it is very rare */
360 /* that any of the pushed arguments is larger than 0xFF, */
361 /* thus we refrain from further optimizing this case */
362 bufp = TA_build_push(bufp, args, num_args, need_words, optimize);
364 BCI(CALL);
366 num_storage = sal_segment_offset + num_segments * 2;
367 if (num_storage > sfnt->max_storage)
368 sfnt->max_storage = num_storage;
370 num_twilight_points = num_segments * 2;
371 if (num_twilight_points > sfnt->max_twilight_points)
372 sfnt->max_twilight_points = num_twilight_points;
374 /* both this function and `TA_emit_hints_record' */
375 /* push data onto the stack */
376 num_stack_elements = ADDITIONAL_STACK_ELEMENTS
377 + recorder->num_stack_elements + num_args;
378 if (num_stack_elements > sfnt->max_stack_elements)
379 sfnt->max_stack_elements = num_stack_elements;
381 free(args);
383 return bufp;
387 static FT_Byte*
388 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
389 Recorder* recorder,
390 FT_Byte* bufp)
392 FONT* font = recorder->font;
393 FT_GlyphSlot glyph = sfnt->face->glyph;
394 FT_Vector* points = glyph->outline.points;
395 FT_Int num_contours = glyph->outline.n_contours;
397 FT_UInt* args;
398 FT_UInt* arg;
399 FT_UInt num_args;
401 FT_Bool need_words = 0;
402 FT_Int p, q;
403 FT_Int start, end;
404 FT_UShort num_stack_elements;
407 num_args = 2 * num_contours + 2;
409 /* collect all arguments temporarily in an array (in reverse order) */
410 /* so that we can easily split into chunks of 255 args */
411 /* as needed by NPUSHB and NPUSHW, respectively */
412 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
413 if (!args)
414 return NULL;
416 arg = args + num_args - 1;
418 if (num_args > 0xFF)
419 need_words = 1;
421 if (recorder->glyph->num_components && font->hint_with_components)
422 *(arg--) = bci_scale_composite_glyph;
423 else
424 *(arg--) = bci_scale_glyph;
425 *(arg--) = num_contours;
427 start = 0;
428 end = 0;
430 for (p = 0; p < num_contours; p++)
432 FT_Int max = start;
433 FT_Int min = start;
436 end = glyph->outline.contours[p];
438 for (q = start; q <= end; q++)
440 if (points[q].y < points[min].y)
441 min = q;
442 if (points[q].y > points[max].y)
443 max = q;
446 if (min > max)
448 *(arg--) = TA_adjust_point_index(recorder, max);
449 *(arg--) = TA_adjust_point_index(recorder, min);
451 else
453 *(arg--) = TA_adjust_point_index(recorder, min);
454 *(arg--) = TA_adjust_point_index(recorder, max);
457 start = end + 1;
460 if (end > 0xFF)
461 need_words = 1;
463 /* with most fonts it is very rare */
464 /* that any of the pushed arguments is larger than 0xFF, */
465 /* thus we refrain from further optimizing this case */
466 bufp = TA_build_push(bufp, args, num_args, need_words, 1);
468 BCI(CALL);
470 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
471 if (num_stack_elements > sfnt->max_stack_elements)
472 sfnt->max_stack_elements = num_stack_elements;
474 free(args);
476 return bufp;
480 static FT_Byte*
481 TA_font_build_subglyph_shifter(FONT* font,
482 FT_Byte* bufp)
484 FT_Face face = font->loader->face;
485 FT_GlyphSlot glyph = face->glyph;
487 TA_GlyphLoader gloader = font->loader->gloader;
489 TA_SubGlyph subglyphs = gloader->base.subglyphs;
490 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
491 TA_SubGlyph subglyph;
493 FT_Int curr_contour = 0;
496 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
498 FT_Error error;
500 FT_UShort flags = subglyph->flags;
501 FT_Pos y_offset = subglyph->arg2;
503 FT_Int num_contours;
506 /* load subglyph to get the number of contours */
507 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
508 if (error)
509 return NULL;
510 num_contours = glyph->outline.n_contours;
512 /* nothing to do if there is a point-to-point alignment */
513 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
514 goto End;
516 /* nothing to do if y offset is zero */
517 if (!y_offset)
518 goto End;
520 /* nothing to do if there are no contours */
521 if (!num_contours)
522 goto End;
524 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
525 /* ensures that composite subglyphs are represented as simple glyphs */
527 if (num_contours > 0xFF
528 || curr_contour > 0xFF)
530 BCI(PUSHW_2);
531 BCI(HIGH(curr_contour));
532 BCI(LOW(curr_contour));
533 BCI(HIGH(num_contours));
534 BCI(LOW(num_contours));
536 else
538 BCI(PUSHB_2);
539 BCI(curr_contour);
540 BCI(num_contours);
543 /* there are high chances that this value needs PUSHW, */
544 /* thus we handle it separately */
545 if (y_offset > 0xFF || y_offset < 0)
547 BCI(PUSHW_1);
548 BCI(HIGH(y_offset));
549 BCI(LOW(y_offset));
551 else
553 BCI(PUSHB_1);
554 BCI(y_offset);
557 BCI(PUSHB_1);
558 BCI(bci_shift_subglyph);
559 BCI(CALL);
561 End:
562 curr_contour += num_contours;
565 return bufp;
570 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
571 * data in four arrays (which are simple but waste a lot of memory). The
572 * function below converts them into bytecode.
574 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
575 * together with the edge they correspond to.
577 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
578 * loop over the edge or edge pairs, respectively, and each edge or edge
579 * pair contains an inner loop to emit the correponding points.
582 static void
583 TA_build_point_hints(Recorder* recorder,
584 TA_GlyphHints hints)
586 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
587 TA_Segment segments = axis->segments;
588 TA_Edge edges = axis->edges;
590 TA_Edge edge;
591 TA_Edge before;
592 TA_Edge after;
594 FT_Byte* p = recorder->hints_record.buf;
595 FT_UShort num_edges = axis->num_edges;
596 FT_UShort num_strong_points = recorder->num_strong_points;
598 FT_UShort i;
599 FT_UShort j;
600 FT_UShort k;
602 FT_UShort* ip;
603 FT_UShort* iq;
604 FT_UShort* ir;
605 FT_UShort* ip_limit;
606 FT_UShort* iq_limit;
607 FT_UShort* ir_limit;
610 /* we store everything as 16bit numbers; */
611 /* the function numbers (`ta_ip_before', etc.) */
612 /* reflect the order in the TA_Action enumeration */
614 /* ip_before_points */
616 i = 0;
617 ip = recorder->ip_before_points;
618 ip_limit = ip + num_strong_points;
619 for (; ip < ip_limit; ip++)
621 if (*ip != MISSING)
622 i++;
623 else
624 break;
627 if (i)
629 recorder->hints_record.num_actions++;
631 edge = edges;
633 *(p++) = 0;
634 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
635 *(p++) = HIGH(edge->first - segments);
636 *(p++) = LOW(edge->first - segments);
637 *(p++) = HIGH(i);
638 *(p++) = LOW(i);
640 ip = recorder->ip_before_points;
641 ip_limit = ip + i;
642 for (; ip < ip_limit; ip++)
644 FT_UInt point = TA_adjust_point_index(recorder, *ip);
647 *(p++) = HIGH(point);
648 *(p++) = LOW(point);
652 /* ip_after_points */
654 i = 0;
655 ip = recorder->ip_after_points;
656 ip_limit = ip + num_strong_points;
657 for (; ip < ip_limit; ip++)
659 if (*ip != MISSING)
660 i++;
661 else
662 break;
665 if (i)
667 recorder->hints_record.num_actions++;
669 edge = edges + axis->num_edges - 1;
671 *(p++) = 0;
672 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
673 *(p++) = HIGH(edge->first - segments);
674 *(p++) = LOW(edge->first - segments);
675 *(p++) = HIGH(i);
676 *(p++) = LOW(i);
678 ip = recorder->ip_after_points;
679 ip_limit = ip + i;
680 for (; ip < ip_limit; ip++)
682 FT_UInt point = TA_adjust_point_index(recorder, *ip);
685 *(p++) = HIGH(point);
686 *(p++) = LOW(point);
690 /* ip_on_point_array */
692 i = 0;
693 ip = recorder->ip_on_point_array;
694 ip_limit = ip + num_edges * num_strong_points;
695 for (; ip < ip_limit; ip += num_strong_points)
696 if (*ip != MISSING)
697 i++;
699 if (i)
701 recorder->hints_record.num_actions++;
703 *(p++) = 0;
704 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
705 *(p++) = HIGH(i);
706 *(p++) = LOW(i);
708 i = 0;
709 ip = recorder->ip_on_point_array;
710 ip_limit = ip + num_edges * num_strong_points;
711 for (; ip < ip_limit; ip += num_strong_points, i++)
713 if (*ip == MISSING)
714 continue;
716 edge = edges + i;
718 *(p++) = HIGH(edge->first - segments);
719 *(p++) = LOW(edge->first - segments);
721 j = 0;
722 iq = ip;
723 iq_limit = iq + num_strong_points;
724 for (; iq < iq_limit; iq++)
726 if (*iq != MISSING)
727 j++;
728 else
729 break;
732 *(p++) = HIGH(j);
733 *(p++) = LOW(j);
735 iq = ip;
736 iq_limit = iq + j;
737 for (; iq < iq_limit; iq++)
739 FT_UInt point = TA_adjust_point_index(recorder, *iq);
742 *(p++) = HIGH(point);
743 *(p++) = LOW(point);
748 /* ip_between_point_array */
750 i = 0;
751 ip = recorder->ip_between_point_array;
752 ip_limit = ip + num_edges * num_edges * num_strong_points;
753 for (; ip < ip_limit; ip += num_strong_points)
754 if (*ip != MISSING)
755 i++;
757 if (i)
759 recorder->hints_record.num_actions++;
761 *(p++) = 0;
762 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
763 *(p++) = HIGH(i);
764 *(p++) = LOW(i);
766 i = 0;
767 ip = recorder->ip_between_point_array;
768 ip_limit = ip + num_edges * num_edges * num_strong_points;
769 for (;
770 ip < ip_limit;
771 ip += num_edges * num_strong_points, i++)
773 before = edges + i;
775 j = 0;
776 iq = ip;
777 iq_limit = iq + num_edges * num_strong_points;
778 for (; iq < iq_limit; iq += num_strong_points, j++)
780 if (*iq == MISSING)
781 continue;
783 after = edges + j;
785 *(p++) = HIGH(after->first - segments);
786 *(p++) = LOW(after->first - segments);
787 *(p++) = HIGH(before->first - segments);
788 *(p++) = LOW(before->first - segments);
790 k = 0;
791 ir = iq;
792 ir_limit = ir + num_strong_points;
793 for (; ir < ir_limit; ir++)
795 if (*ir != MISSING)
796 k++;
797 else
798 break;
801 *(p++) = HIGH(k);
802 *(p++) = LOW(k);
804 ir = iq;
805 ir_limit = ir + k;
806 for (; ir < ir_limit; ir++)
808 FT_UInt point = TA_adjust_point_index(recorder, *ir);
811 *(p++) = HIGH(point);
812 *(p++) = LOW(point);
818 recorder->hints_record.buf = p;
822 static FT_Bool
823 TA_hints_record_is_different(Hints_Record* hints_records,
824 FT_UInt num_hints_records,
825 FT_Byte* start,
826 FT_Byte* end)
828 Hints_Record last_hints_record;
831 if (!hints_records)
832 return 1;
834 /* we only need to compare with the last hints record */
835 last_hints_record = hints_records[num_hints_records - 1];
837 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
838 return 1;
840 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
841 return 1;
843 return 0;
847 static FT_Error
848 TA_add_hints_record(Hints_Record** hints_records,
849 FT_UInt* num_hints_records,
850 FT_Byte* start,
851 Hints_Record hints_record)
853 Hints_Record* hints_records_new;
854 FT_UInt buf_len;
855 /* at this point, `hints_record.buf' still points into `ins_buf' */
856 FT_Byte* end = hints_record.buf;
859 buf_len = (FT_UInt)(end - start);
861 /* now fill the structure completely */
862 hints_record.buf_len = buf_len;
863 hints_record.buf = (FT_Byte*)malloc(buf_len);
864 if (!hints_record.buf)
865 return FT_Err_Out_Of_Memory;
867 memcpy(hints_record.buf, start, buf_len);
869 (*num_hints_records)++;
870 hints_records_new =
871 (Hints_Record*)realloc(*hints_records, *num_hints_records
872 * sizeof (Hints_Record));
873 if (!hints_records_new)
875 free(hints_record.buf);
876 (*num_hints_records)--;
877 return FT_Err_Out_Of_Memory;
879 else
880 *hints_records = hints_records_new;
882 (*hints_records)[*num_hints_records - 1] = hints_record;
884 return FT_Err_Ok;
888 static FT_Byte*
889 TA_emit_hints_record(Recorder* recorder,
890 Hints_Record* hints_record,
891 FT_Byte* bufp,
892 FT_Bool optimize)
894 FT_Byte* p;
895 FT_Byte* endp;
896 FT_Bool need_words = 0;
898 FT_UInt i, j;
899 FT_UInt num_arguments;
900 FT_UInt num_args;
903 /* check whether any argument is larger than 0xFF */
904 endp = hints_record->buf + hints_record->buf_len;
905 for (p = hints_record->buf; p < endp; p += 2)
906 if (*p)
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 if (optimize && num_args <= 8)
923 BCI(PUSHW_1 - 1 + num_args);
924 else
926 BCI(NPUSHW);
927 BCI(num_args);
929 for (j = 0; j < num_args; j++)
931 BCI(*p);
932 BCI(*(p + 1));
933 p -= 2;
937 else
939 /* we only need the lower bytes */
940 p++;
942 for (i = 0; i < num_arguments; i += 255)
944 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
946 if (optimize && num_args <= 8)
947 BCI(PUSHB_1 - 1 + num_args);
948 else
950 BCI(NPUSHB);
951 BCI(num_args);
953 for (j = 0; j < num_args; j++)
955 BCI(*p);
956 p -= 2;
961 /* collect stack depth data */
962 if (num_arguments > recorder->num_stack_elements)
963 recorder->num_stack_elements = num_arguments;
965 return bufp;
969 static FT_Byte*
970 TA_emit_hints_records(Recorder* recorder,
971 Hints_Record* hints_records,
972 FT_UInt num_hints_records,
973 FT_Byte* bufp,
974 FT_Bool optimize)
976 FT_UInt i;
977 Hints_Record* hints_record;
980 hints_record = hints_records;
982 for (i = 0; i < num_hints_records - 1; i++)
984 BCI(MPPEM);
985 if (hints_record->size > 0xFF)
987 BCI(PUSHW_1);
988 BCI(HIGH((hints_record + 1)->size));
989 BCI(LOW((hints_record + 1)->size));
991 else
993 BCI(PUSHB_1);
994 BCI((hints_record + 1)->size);
996 BCI(LT);
997 BCI(IF);
998 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
999 BCI(ELSE);
1001 hints_record++;
1004 bufp = TA_emit_hints_record(recorder, hints_record, bufp, optimize);
1006 for (i = 0; i < num_hints_records - 1; i++)
1007 BCI(EIF);
1009 return bufp;
1013 static void
1014 TA_free_hints_records(Hints_Record* hints_records,
1015 FT_UInt num_hints_records)
1017 FT_UInt i;
1020 for (i = 0; i < num_hints_records; i++)
1021 free(hints_records[i].buf);
1023 free(hints_records);
1027 static FT_Byte*
1028 TA_hints_recorder_handle_segments(FT_Byte* bufp,
1029 TA_AxisHints axis,
1030 TA_Edge edge,
1031 FT_UShort* wraps)
1033 TA_Segment segments = axis->segments;
1034 TA_Segment seg;
1035 FT_UShort seg_idx;
1036 FT_UShort num_segs = 0;
1037 FT_UShort* wrap;
1040 seg_idx = edge->first - segments;
1042 /* we store everything as 16bit numbers */
1043 *(bufp++) = HIGH(seg_idx);
1044 *(bufp++) = LOW(seg_idx);
1046 /* wrap-around segments are stored as two segments */
1047 if (edge->first->first > edge->first->last)
1048 num_segs++;
1050 seg = edge->first->edge_next;
1051 while (seg != edge->first)
1053 num_segs++;
1055 if (seg->first > seg->last)
1056 num_segs++;
1058 seg = seg->edge_next;
1061 *(bufp++) = HIGH(num_segs);
1062 *(bufp++) = LOW(num_segs);
1064 if (edge->first->first > edge->first->last)
1066 /* emit second part of wrap-around segment; */
1067 /* the bytecode positions such segments after `normal' ones */
1068 wrap = wraps;
1069 for (;;)
1071 if (seg_idx == *wrap)
1072 break;
1073 wrap++;
1076 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1077 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1080 seg = edge->first->edge_next;
1081 while (seg != edge->first)
1083 seg_idx = seg - segments;
1085 *(bufp++) = HIGH(seg_idx);
1086 *(bufp++) = LOW(seg_idx);
1088 if (seg->first > seg->last)
1090 wrap = wraps;
1091 for (;;)
1093 if (seg_idx == *wrap)
1094 break;
1095 wrap++;
1098 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1099 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1102 seg = seg->edge_next;
1105 return bufp;
1109 static void
1110 TA_hints_recorder(TA_Action action,
1111 TA_GlyphHints hints,
1112 TA_Dimension dim,
1113 void* arg1,
1114 TA_Edge arg2,
1115 TA_Edge arg3,
1116 TA_Edge lower_bound,
1117 TA_Edge upper_bound)
1119 TA_AxisHints axis = &hints->axis[dim];
1120 TA_Edge edges = axis->edges;
1121 TA_Segment segments = axis->segments;
1122 TA_Point points = hints->points;
1124 Recorder* recorder = (Recorder*)hints->user;
1125 FONT* font = recorder->font;
1126 FT_UShort* wraps = recorder->wrap_around_segments;
1127 FT_Byte* p = recorder->hints_record.buf;
1129 FT_UShort* ip;
1130 FT_UShort* limit;
1133 if (dim == TA_DIMENSION_HORZ)
1134 return;
1136 /* we collect point hints for later processing */
1137 switch (action)
1139 case ta_ip_before:
1141 TA_Point point = (TA_Point)arg1;
1144 ip = recorder->ip_before_points;
1145 limit = ip + recorder->num_strong_points;
1146 for (; ip < limit; ip++)
1148 if (*ip == MISSING)
1150 *ip = point - points;
1151 break;
1155 return;
1157 case ta_ip_after:
1159 TA_Point point = (TA_Point)arg1;
1162 ip = recorder->ip_after_points;
1163 limit = ip + recorder->num_strong_points;
1164 for (; ip < limit; ip++)
1166 if (*ip == MISSING)
1168 *ip = point - points;
1169 break;
1173 return;
1175 case ta_ip_on:
1177 TA_Point point = (TA_Point)arg1;
1178 TA_Edge edge = arg2;
1181 ip = recorder->ip_on_point_array
1182 + recorder->num_strong_points
1183 * (edge - edges);
1184 limit = ip + recorder->num_strong_points;
1185 for (; ip < limit; ip++)
1187 if (*ip == MISSING)
1189 *ip = point - points;
1190 break;
1194 return;
1196 case ta_ip_between:
1198 TA_Point point = (TA_Point)arg1;
1199 TA_Edge before = arg2;
1200 TA_Edge after = arg3;
1203 /* note that `recorder->num_segments' has been used for allocation, */
1204 /* but `axis->num_edges' is used for accessing this array */
1205 ip = recorder->ip_between_point_array
1206 + recorder->num_strong_points * axis->num_edges
1207 * (before - edges)
1208 + recorder->num_strong_points
1209 * (after - edges);
1210 limit = ip + recorder->num_strong_points;
1211 for (; ip < limit; ip++)
1213 if (*ip == MISSING)
1215 *ip = point - points;
1216 break;
1220 return;
1222 case ta_bound:
1223 /* we ignore the BOUND action since we signal this information */
1224 /* with the proper function number */
1225 return;
1227 default:
1228 break;
1231 /* some enum values correspond to four or eight bytecode functions; */
1232 /* if the value is n, the function numbers are n, ..., n+7, */
1233 /* to be differentiated with flags */
1235 switch (action)
1237 case ta_link:
1239 TA_Edge base_edge = (TA_Edge)arg1;
1240 TA_Edge stem_edge = arg2;
1243 *(p++) = 0;
1244 *(p++) = (FT_Byte)action + ACTION_OFFSET
1245 + ((stem_edge->flags & TA_EDGE_SERIF) != 0)
1246 + 2 * ((base_edge->flags & TA_EDGE_ROUND) != 0);
1248 *(p++) = HIGH(base_edge->first - segments);
1249 *(p++) = LOW(base_edge->first - segments);
1250 *(p++) = HIGH(stem_edge->first - segments);
1251 *(p++) = LOW(stem_edge->first - segments);
1253 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1255 break;
1257 case ta_anchor:
1259 TA_Edge edge = (TA_Edge)arg1;
1260 TA_Edge edge2 = arg2;
1263 *(p++) = 0;
1264 *(p++) = (FT_Byte)action + ACTION_OFFSET
1265 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1266 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0);
1268 *(p++) = HIGH(edge->first - segments);
1269 *(p++) = LOW(edge->first - segments);
1270 *(p++) = HIGH(edge2->first - segments);
1271 *(p++) = LOW(edge2->first - segments);
1273 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1275 break;
1277 case ta_adjust:
1279 TA_Edge edge = (TA_Edge)arg1;
1280 TA_Edge edge2 = arg2;
1281 TA_Edge edge_minus_one = lower_bound;
1284 *(p++) = 0;
1285 *(p++) = (FT_Byte)action + ACTION_OFFSET
1286 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1287 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1288 + 4 * (edge_minus_one != NULL);
1290 *(p++) = HIGH(edge->first - segments);
1291 *(p++) = LOW(edge->first - segments);
1292 *(p++) = HIGH(edge2->first - segments);
1293 *(p++) = LOW(edge2->first - segments);
1295 if (edge_minus_one)
1297 *(p++) = HIGH(edge_minus_one->first - segments);
1298 *(p++) = LOW(edge_minus_one->first - segments);
1301 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1303 break;
1305 case ta_blue_anchor:
1307 TA_Edge edge = (TA_Edge)arg1;
1308 TA_Edge blue = arg2;
1311 *(p++) = 0;
1312 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1314 *(p++) = HIGH(blue->first - segments);
1315 *(p++) = LOW(blue->first - segments);
1317 if (edge->best_blue_is_shoot)
1319 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1320 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1322 else
1324 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1325 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1328 *(p++) = HIGH(edge->first - segments);
1329 *(p++) = LOW(edge->first - segments);
1331 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1333 break;
1335 case ta_stem:
1337 TA_Edge edge = (TA_Edge)arg1;
1338 TA_Edge edge2 = arg2;
1339 TA_Edge edge_minus_one = lower_bound;
1342 *(p++) = 0;
1343 *(p++) = (FT_Byte)action + ACTION_OFFSET
1344 + ((edge2->flags & TA_EDGE_SERIF) != 0)
1345 + 2 * ((edge->flags & TA_EDGE_ROUND) != 0)
1346 + 4 * (edge_minus_one != NULL);
1348 *(p++) = HIGH(edge->first - segments);
1349 *(p++) = LOW(edge->first - segments);
1350 *(p++) = HIGH(edge2->first - segments);
1351 *(p++) = LOW(edge2->first - segments);
1353 if (edge_minus_one)
1355 *(p++) = HIGH(edge_minus_one->first - segments);
1356 *(p++) = LOW(edge_minus_one->first - segments);
1359 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1360 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1362 break;
1364 case ta_blue:
1366 TA_Edge edge = (TA_Edge)arg1;
1369 *(p++) = 0;
1370 *(p++) = (FT_Byte)action + ACTION_OFFSET;
1372 if (edge->best_blue_is_shoot)
1374 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1375 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1377 else
1379 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1380 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1383 *(p++) = HIGH(edge->first - segments);
1384 *(p++) = LOW(edge->first - segments);
1386 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1388 break;
1390 case ta_serif:
1392 TA_Edge serif = (TA_Edge)arg1;
1393 TA_Edge base = serif->serif;
1396 *(p++) = 0;
1397 *(p++) = (FT_Byte)action + ACTION_OFFSET
1398 + (lower_bound != NULL)
1399 + 2 * (upper_bound != NULL);
1401 *(p++) = HIGH(serif->first - segments);
1402 *(p++) = LOW(serif->first - segments);
1403 *(p++) = HIGH(base->first - segments);
1404 *(p++) = LOW(base->first - segments);
1406 if (lower_bound)
1408 *(p++) = HIGH(lower_bound->first - segments);
1409 *(p++) = LOW(lower_bound->first - segments);
1411 if (upper_bound)
1413 *(p++) = HIGH(upper_bound->first - segments);
1414 *(p++) = LOW(upper_bound->first - segments);
1417 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1419 break;
1421 case ta_serif_anchor:
1422 case ta_serif_link2:
1424 TA_Edge edge = (TA_Edge)arg1;
1427 *(p++) = 0;
1428 *(p++) = (FT_Byte)action + ACTION_OFFSET
1429 + (lower_bound != NULL)
1430 + 2 * (upper_bound != NULL);
1432 *(p++) = HIGH(edge->first - segments);
1433 *(p++) = LOW(edge->first - segments);
1435 if (lower_bound)
1437 *(p++) = HIGH(lower_bound->first - segments);
1438 *(p++) = LOW(lower_bound->first - segments);
1440 if (upper_bound)
1442 *(p++) = HIGH(upper_bound->first - segments);
1443 *(p++) = LOW(upper_bound->first - segments);
1446 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1448 break;
1450 case ta_serif_link1:
1452 TA_Edge edge = (TA_Edge)arg1;
1453 TA_Edge before = arg2;
1454 TA_Edge after = arg3;
1457 *(p++) = 0;
1458 *(p++) = (FT_Byte)action + ACTION_OFFSET
1459 + (lower_bound != NULL)
1460 + 2 * (upper_bound != NULL);
1462 *(p++) = HIGH(before->first - segments);
1463 *(p++) = LOW(before->first - segments);
1464 *(p++) = HIGH(edge->first - segments);
1465 *(p++) = LOW(edge->first - segments);
1466 *(p++) = HIGH(after->first - segments);
1467 *(p++) = LOW(after->first - segments);
1469 if (lower_bound)
1471 *(p++) = HIGH(lower_bound->first - segments);
1472 *(p++) = LOW(lower_bound->first - segments);
1474 if (upper_bound)
1476 *(p++) = HIGH(upper_bound->first - segments);
1477 *(p++) = LOW(upper_bound->first - segments);
1480 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1482 break;
1484 default:
1485 /* there are more cases in the enumeration */
1486 /* which are handled with flags */
1487 break;
1490 recorder->hints_record.num_actions++;
1491 recorder->hints_record.buf = p;
1495 static FT_Error
1496 TA_init_recorder(Recorder* recorder,
1497 FONT* font,
1498 GLYPH* glyph,
1499 TA_GlyphHints hints)
1501 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1502 TA_Point points = hints->points;
1503 TA_Point point_limit = points + hints->num_points;
1504 TA_Point point;
1506 TA_Segment segments = axis->segments;
1507 TA_Segment seg_limit = segments + axis->num_segments;
1508 TA_Segment seg;
1510 FT_UShort num_strong_points = 0;
1511 FT_UShort* wrap_around_segment;
1513 recorder->font = font;
1514 recorder->glyph = glyph;
1515 recorder->num_segments = axis->num_segments;
1517 recorder->ip_before_points = NULL;
1518 recorder->ip_after_points = NULL;
1519 recorder->ip_on_point_array = NULL;
1520 recorder->ip_between_point_array = NULL;
1522 recorder->num_stack_elements = 0;
1524 /* no need to clean up allocated arrays in case of error; */
1525 /* this is handled later by `TA_free_recorder' */
1527 recorder->num_wrap_around_segments = 0;
1528 for (seg = segments; seg < seg_limit; seg++)
1529 if (seg->first > seg->last)
1530 recorder->num_wrap_around_segments++;
1532 recorder->wrap_around_segments =
1533 (FT_UShort*)malloc(recorder->num_wrap_around_segments
1534 * sizeof (FT_UShort));
1535 if (!recorder->wrap_around_segments)
1536 return FT_Err_Out_Of_Memory;
1538 wrap_around_segment = recorder->wrap_around_segments;
1539 for (seg = segments; seg < seg_limit; seg++)
1540 if (seg->first > seg->last)
1541 *(wrap_around_segment++) = seg - segments;
1543 /* get number of strong points */
1544 for (point = points; point < point_limit; point++)
1546 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1547 /* however, this value isn't known yet */
1548 /* (or rather, it can vary between different pixel sizes) */
1549 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1550 continue;
1552 num_strong_points++;
1555 recorder->num_strong_points = num_strong_points;
1557 recorder->ip_before_points =
1558 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1559 if (!recorder->ip_before_points)
1560 return FT_Err_Out_Of_Memory;
1562 recorder->ip_after_points =
1563 (FT_UShort*)malloc(num_strong_points * sizeof (FT_UShort));
1564 if (!recorder->ip_after_points)
1565 return FT_Err_Out_Of_Memory;
1567 /* actually, we need `hints->num_edges' for the array sizes; */
1568 /* however, this value isn't known yet */
1569 /* (or rather, it can vary between different pixel sizes) */
1570 recorder->ip_on_point_array =
1571 (FT_UShort*)malloc(axis->num_segments
1572 * num_strong_points * sizeof (FT_UShort));
1573 if (!recorder->ip_on_point_array)
1574 return FT_Err_Out_Of_Memory;
1576 recorder->ip_between_point_array =
1577 (FT_UShort*)malloc(axis->num_segments * axis->num_segments
1578 * num_strong_points * sizeof (FT_UShort));
1579 if (!recorder->ip_between_point_array)
1580 return FT_Err_Out_Of_Memory;
1582 return FT_Err_Ok;
1586 static void
1587 TA_reset_recorder(Recorder* recorder,
1588 FT_Byte* bufp)
1590 recorder->hints_record.buf = bufp;
1591 recorder->hints_record.num_actions = 0;
1595 static void
1596 TA_rewind_recorder(Recorder* recorder,
1597 FT_Byte* bufp,
1598 FT_UInt size)
1600 TA_reset_recorder(recorder, bufp);
1602 recorder->hints_record.size = size;
1604 /* We later check with MISSING (which expands to 0xFF bytes) */
1606 memset(recorder->ip_before_points, 0xFF,
1607 recorder->num_strong_points * sizeof (FT_UShort));
1608 memset(recorder->ip_after_points, 0xFF,
1609 recorder->num_strong_points * sizeof (FT_UShort));
1611 memset(recorder->ip_on_point_array, 0xFF,
1612 recorder->num_segments
1613 * recorder->num_strong_points * sizeof (FT_UShort));
1614 memset(recorder->ip_between_point_array, 0xFF,
1615 recorder->num_segments * recorder->num_segments
1616 * recorder->num_strong_points * sizeof (FT_UShort));
1620 static void
1621 TA_free_recorder(Recorder* recorder)
1623 free(recorder->wrap_around_segments);
1625 free(recorder->ip_before_points);
1626 free(recorder->ip_after_points);
1627 free(recorder->ip_on_point_array);
1628 free(recorder->ip_between_point_array);
1632 FT_Error
1633 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1634 FONT* font,
1635 FT_Long idx)
1637 FT_Face face = sfnt->face;
1638 FT_Error error;
1640 FT_Byte* ins_buf;
1641 FT_UInt ins_len;
1642 FT_Byte* bufp;
1643 FT_Byte* p;
1645 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1646 glyf_Data* data = (glyf_Data*)glyf_table->data;
1647 /* `idx' is never negative */
1648 GLYPH* glyph = &data->glyphs[idx];
1650 TA_GlyphHints hints;
1652 FT_UInt num_action_hints_records = 0;
1653 FT_UInt num_point_hints_records = 0;
1654 Hints_Record* action_hints_records = NULL;
1655 Hints_Record* point_hints_records = NULL;
1657 Recorder recorder;
1658 FT_UShort num_stack_elements;
1659 FT_Bool optimize = 0;
1661 FT_Int32 load_flags;
1662 FT_UInt size;
1664 FT_Byte* pos[3];
1666 #ifdef TA_DEBUG
1667 int _ta_debug_save;
1668 #endif
1671 /* XXX: right now, we abuse this flag to control */
1672 /* the global behaviour of the auto-hinter */
1673 load_flags = 1 << 29; /* vertical hinting only */
1674 if (!font->pre_hinting)
1676 if (font->hint_with_components)
1677 load_flags |= FT_LOAD_NO_SCALE;
1678 else
1679 load_flags |= FT_LOAD_NO_RECURSE;
1682 /* computing the segments is resolution independent, */
1683 /* thus the pixel size in this call is arbitrary */
1684 error = FT_Set_Pixel_Sizes(face, 20, 20);
1685 if (error)
1686 return error;
1688 #ifdef TA_DEBUG
1689 /* temporarily disable debugging output */
1690 /* to avoid getting the information twice */
1691 _ta_debug_save = _ta_debug;
1692 _ta_debug = 0;
1693 #endif
1695 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1696 error = ta_loader_load_glyph(font, face, (FT_UInt)idx, load_flags);
1698 #ifdef TA_DEBUG
1699 _ta_debug = _ta_debug_save;
1700 #endif
1702 if (error)
1703 return error;
1705 /* do nothing if we have an empty glyph */
1706 if (!face->glyph->outline.n_contours)
1707 return FT_Err_Ok;
1709 hints = &font->loader->hints;
1711 /* do nothing if the setup delivered the dummy module only */
1712 if (!hints->num_points)
1713 return FT_Err_Ok;
1715 /* we allocate a buffer which is certainly large enough */
1716 /* to hold all of the created bytecode instructions; */
1717 /* later on it gets reallocated to its real size */
1718 ins_len = hints->num_points * 1000;
1719 ins_buf = (FT_Byte*)malloc(ins_len);
1720 if (!ins_buf)
1721 return FT_Err_Out_Of_Memory;
1723 /* initialize array with an invalid bytecode */
1724 /* so that we can easily find the array length at reallocation time */
1725 memset(ins_buf, INS_A0, ins_len);
1727 /* handle composite glyph */
1728 if (font->loader->gloader->base.num_subglyphs)
1730 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1731 if (!bufp)
1733 error = FT_Err_Out_Of_Memory;
1734 goto Err;
1737 goto Done1;
1740 /* only scale the glyph if the dummy hinter has been used */
1741 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1743 /* since `TA_init_recorder' hasn't been called yet, */
1744 /* we manually initialize the `font' and `glyph' fields */
1745 recorder.font = font;
1746 recorder.glyph = glyph;
1748 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1749 if (!bufp)
1751 error = FT_Err_Out_Of_Memory;
1752 goto Err;
1755 goto Done1;
1758 error = TA_init_recorder(&recorder, font, glyph, hints);
1759 if (error)
1760 goto Err;
1762 /* loop over a large range of pixel sizes */
1763 /* to find hints records which get pushed onto the bytecode stack */
1765 #ifdef DEBUGGING
1766 if (font->debug)
1768 int num_chars, i;
1769 char buf[256];
1772 (void)FT_Get_Glyph_Name(face, idx, buf, 256);
1774 num_chars = fprintf(stderr, "glyph %ld", idx);
1775 if (*buf)
1776 num_chars += fprintf(stderr, " (%s)", buf);
1777 fprintf(stderr, "\n");
1778 for (i = 0; i < num_chars; i++)
1779 putc('=', stderr);
1780 fprintf(stderr, "\n\n");
1783 #endif
1785 /* we temporarily use `ins_buf' to record the current glyph hints */
1786 ta_loader_register_hints_recorder(font->loader,
1787 TA_hints_recorder,
1788 (void*)&recorder);
1790 for (size = font->hinting_range_min;
1791 size <= font->hinting_range_max;
1792 size++)
1794 #ifdef DEBUGGING
1795 int have_dumps = 0;
1796 #endif
1799 TA_rewind_recorder(&recorder, ins_buf, size);
1801 error = FT_Set_Pixel_Sizes(face, size, size);
1802 if (error)
1803 goto Err;
1805 #ifdef DEBUGGING
1806 if (font->debug)
1808 int num_chars, i;
1811 num_chars = fprintf(stderr, "size %d\n", size);
1812 for (i = 0; i < num_chars - 1; i++)
1813 putc('-', stderr);
1814 fprintf(stderr, "\n\n");
1816 #endif
1818 /* calling `ta_loader_load_glyph' uses the */
1819 /* `TA_hints_recorder' function as a callback, */
1820 /* modifying `hints_record' */
1821 error = ta_loader_load_glyph(font, face, idx, load_flags);
1822 if (error)
1823 goto Err;
1825 if (TA_hints_record_is_different(action_hints_records,
1826 num_action_hints_records,
1827 ins_buf, recorder.hints_record.buf))
1829 #ifdef DEBUGGING
1830 if (font->debug)
1832 have_dumps = 1;
1834 ta_glyph_hints_dump_edges(_ta_debug_hints);
1835 ta_glyph_hints_dump_segments(_ta_debug_hints);
1836 ta_glyph_hints_dump_points(_ta_debug_hints);
1838 fprintf(stderr, "action hints record:\n");
1839 if (ins_buf == recorder.hints_record.buf)
1840 fprintf(stderr, " (none)");
1841 else
1843 fprintf(stderr, " ");
1844 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1845 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1847 fprintf(stderr, "\n");
1849 #endif
1851 error = TA_add_hints_record(&action_hints_records,
1852 &num_action_hints_records,
1853 ins_buf, recorder.hints_record);
1854 if (error)
1855 goto Err;
1858 /* now handle point records */
1860 TA_reset_recorder(&recorder, ins_buf);
1862 /* use the point hints data collected in `TA_hints_recorder' */
1863 TA_build_point_hints(&recorder, hints);
1865 if (TA_hints_record_is_different(point_hints_records,
1866 num_point_hints_records,
1867 ins_buf, recorder.hints_record.buf))
1869 #ifdef DEBUGGING
1870 if (font->debug)
1872 if (!have_dumps)
1874 int num_chars, i;
1877 num_chars = fprintf(stderr, "size %d\n", size);
1878 for (i = 0; i < num_chars - 1; i++)
1879 putc('-', stderr);
1880 fprintf(stderr, "\n\n");
1882 ta_glyph_hints_dump_edges(_ta_debug_hints);
1883 ta_glyph_hints_dump_segments(_ta_debug_hints);
1884 ta_glyph_hints_dump_points(_ta_debug_hints);
1887 fprintf(stderr, "point hints record:\n");
1888 if (ins_buf == recorder.hints_record.buf)
1889 fprintf(stderr, " (none)");
1890 else
1892 fprintf(stderr, " ");
1893 for (p = ins_buf; p < recorder.hints_record.buf; p += 2)
1894 fprintf(stderr, " %2d", *p * 256 + *(p + 1));
1896 fprintf(stderr, "\n\n");
1898 #endif
1900 error = TA_add_hints_record(&point_hints_records,
1901 &num_point_hints_records,
1902 ins_buf, recorder.hints_record);
1903 if (error)
1904 goto Err;
1908 if (num_action_hints_records == 1 && !action_hints_records[0].num_actions)
1910 /* since we only have a single empty record we just scale the glyph */
1911 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1912 if (!bufp)
1914 error = FT_Err_Out_Of_Memory;
1915 goto Err;
1918 /* clear the rest of the temporarily used part of `ins_buf' */
1919 p = bufp;
1920 while (*p != INS_A0)
1921 *(p++) = INS_A0;
1923 goto Done;
1926 /* if there is only a single record, */
1927 /* we do a global optimization later on */
1928 if (num_action_hints_records > 1)
1929 optimize = 1;
1931 /* store the hints records and handle stack depth */
1932 pos[0] = ins_buf;
1933 bufp = TA_emit_hints_records(&recorder,
1934 point_hints_records,
1935 num_point_hints_records,
1936 ins_buf,
1937 optimize);
1939 num_stack_elements = recorder.num_stack_elements;
1940 recorder.num_stack_elements = 0;
1942 pos[1] = bufp;
1943 bufp = TA_emit_hints_records(&recorder,
1944 action_hints_records,
1945 num_action_hints_records,
1946 bufp,
1947 optimize);
1949 recorder.num_stack_elements += num_stack_elements;
1951 pos[2] = bufp;
1952 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, bufp, optimize);
1953 if (!bufp)
1955 error = FT_Err_Out_Of_Memory;
1956 goto Err;
1959 /* XXX improve handling of NPUSHW */
1960 if (num_action_hints_records == 1
1961 && *(pos[0]) != NPUSHW && *(pos[1]) != NPUSHW && *(pos[2]) != NPUSHW)
1964 * we optimize two common cases, replacing
1966 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1968 * with
1970 * NPUSHB (A+B[+C]) ... CALL
1972 * if possible
1974 FT_Byte sizes[3];
1975 FT_Byte new_size1;
1976 FT_Byte new_size2;
1978 FT_UInt sum;
1979 FT_UInt i;
1980 FT_UInt pos_idx;
1983 /* the point hints records block can be missing */
1984 if (pos[0] == pos[1])
1986 pos[1] = pos[2];
1987 pos[2] = NULL;
1990 /* there are at least two NPUSHB instructions */
1991 /* (one of them directly at the start) */
1992 sizes[0] = *(pos[0] + 1);
1993 sizes[1] = *(pos[1] + 1);
1994 sizes[2] = pos[2] ? *(pos[2] + 1) : 0;
1996 sum = sizes[0] + sizes[1] + sizes[2];
1998 if (sum > 2 * 0xFF)
1999 goto Done2; /* nothing to do since we need three NPUSHB */
2000 else if (!sizes[2] && (sum > 0xFF))
2001 goto Done2; /* nothing to do since we need two NPUSHB */
2003 if (sum > 0xFF)
2005 /* reduce three NPUSHB to two */
2006 new_size1 = 0xFF;
2007 new_size2 = sum - 0xFF;
2009 else
2011 /* reduce two or three NPUSHB to one */
2012 new_size1 = sum;
2013 new_size2 = 0;
2016 /* pack data */
2017 p = ins_buf;
2018 bufp = ins_buf;
2019 pos_idx = 0;
2021 if (new_size1 <= 8)
2022 BCI(PUSHB_1 - 1 + new_size1);
2023 else
2025 BCI(NPUSHB);
2026 BCI(new_size1);
2028 for (i = 0; i < new_size1; i++)
2030 if (p == pos[pos_idx])
2032 pos_idx++;
2033 p += 2; /* skip old NPUSHB */
2035 *(bufp++) = *(p++);
2038 if (new_size2)
2040 if (new_size2 <= 8)
2041 BCI(PUSHB_1 - 1 + new_size2);
2042 else
2044 BCI(NPUSHB);
2045 BCI(new_size2);
2047 for (i = 0; i < new_size2; i++)
2049 if (p == pos[pos_idx])
2051 pos_idx++;
2052 p += 2;
2054 *(bufp++) = *(p++);
2058 BCI(CALL);
2061 Done2:
2062 /* clear the rest of the temporarily used part of `ins_buf' */
2063 p = bufp;
2064 while (*p != INS_A0)
2065 *(p++) = INS_A0;
2067 Done:
2068 TA_free_hints_records(action_hints_records, num_action_hints_records);
2069 TA_free_hints_records(point_hints_records, num_point_hints_records);
2070 TA_free_recorder(&recorder);
2072 /* we are done, so reallocate the instruction array to its real size */
2073 if (*bufp == INS_A0)
2075 /* search backwards */
2076 while (*bufp == INS_A0)
2077 bufp--;
2078 bufp++;
2080 else
2082 /* search forwards */
2083 while (*bufp != INS_A0)
2084 bufp++;
2087 Done1:
2088 ins_len = bufp - ins_buf;
2090 if (ins_len > sfnt->max_instructions)
2091 sfnt->max_instructions = ins_len;
2093 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
2094 glyph->ins_len = ins_len;
2096 return FT_Err_Ok;
2098 Err:
2099 TA_free_hints_records(action_hints_records, num_action_hints_records);
2100 TA_free_hints_records(point_hints_records, num_point_hints_records);
2101 TA_free_recorder(&recorder);
2102 free(ins_buf);
2104 return error;
2108 /* end of tabytecode.c */