Make pre-hinting work again.
[ttfautohint.git] / src / tabytecode.c
blob338af1becf9b1bb186ac199c8781eca082c15f13
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"
19 #undef MISSING
20 #define MISSING (FT_UInt)~0
22 /* a simple macro to emit bytecode instructions */
23 #define BCI(code) *(bufp++) = (code)
25 /* we increase the stack depth by this amount */
26 #define ADDITIONAL_STACK_ELEMENTS 20
29 /* #define DEBUGGING */
32 #ifdef TA_DEBUG
33 int _ta_debug = 1;
34 int _ta_debug_disable_horz_hints;
35 int _ta_debug_disable_vert_hints;
36 int _ta_debug_disable_blue_hints;
37 void* _ta_debug_hints;
38 #endif
41 typedef struct Hints_Record_ {
42 FT_UInt size;
43 FT_UInt num_actions;
44 FT_Byte* buf;
45 FT_UInt buf_len;
46 } Hints_Record;
48 typedef struct Recorder_ {
49 FONT* font;
50 GLYPH* glyph; /* the current glyph */
51 Hints_Record hints_record;
53 /* see explanations in `TA_sfnt_build_glyph_segments' */
54 FT_UInt* wrap_around_segments;
56 /* data necessary for strong point interpolation */
57 FT_UInt* ip_before_points;
58 FT_UInt* ip_after_points;
59 FT_UInt* ip_on_point_array;
60 FT_UInt* ip_between_point_array;
62 FT_UInt num_strong_points;
63 FT_UInt num_segments;
64 } Recorder;
67 /* We add a subglyph for each composite glyph. */
68 /* Since subglyphs must contain at least one point, */
69 /* we have to adjust all point indices accordingly. */
70 /* Using the `pointsums' array of the `GLYPH' structure */
71 /* it is straightforward to do that: */
72 /* Assuming that point with index x is in the interval */
73 /* pointsums[n] <= x < pointsums[n + 1], */
74 /* the new point index is x + n. */
76 static FT_UInt
77 TA_adjust_point_index(Recorder* recorder,
78 FT_UInt idx)
80 GLYPH* glyph = recorder->glyph;
81 FT_UShort i;
84 if (!glyph->num_components)
85 return idx; /* not a composite glyph */
87 for (i = 0; i < glyph->num_pointsums; i++)
88 if (idx < glyph->pointsums[i])
89 break;
91 return idx + i;
95 /* we store the segments in the storage area; */
96 /* each segment record consists of the first and last point */
98 static FT_Byte*
99 TA_sfnt_build_glyph_segments(SFNT* sfnt,
100 Recorder* recorder,
101 FT_Byte* bufp)
103 FONT* font = recorder->font;
104 TA_GlyphHints hints = &font->loader->hints;
105 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
106 TA_Point points = hints->points;
107 TA_Segment segments = axis->segments;
108 TA_Segment seg;
109 TA_Segment seg_limit;
111 FT_Outline outline = font->loader->gloader->base.outline;
113 FT_UInt* args;
114 FT_UInt* arg;
115 FT_UInt num_args;
116 FT_UInt nargs;
117 FT_UInt num_segments;
119 FT_UInt* wrap_around_segment;
120 FT_UInt num_wrap_around_segments;
122 FT_Bool need_words = 0;
124 FT_Int n;
125 FT_UInt i, j;
126 FT_UInt num_storage;
127 FT_UInt num_stack_elements;
128 FT_UInt num_twilight_points;
131 seg_limit = segments + axis->num_segments;
132 num_segments = axis->num_segments;
134 /* some segments can `wrap around' */
135 /* a contour's start point like 24-25-26-0-1-2 */
136 /* (there can be at most one such segment per contour); */
137 /* we thus append additional records to split them into 24-26 and 0-2 */
138 wrap_around_segment = recorder->wrap_around_segments;
139 for (seg = segments; seg < seg_limit; seg++)
140 if (seg->first > seg->last)
142 /* the stored data is used later for edge linking */
143 *(wrap_around_segment++) = seg - segments;
146 num_wrap_around_segments = wrap_around_segment
147 - recorder->wrap_around_segments;
148 num_segments += num_wrap_around_segments;
150 /* wrap-around segments are pushed with four arguments */
151 num_args = 2 * num_segments + 2 * num_wrap_around_segments + 2;
153 /* collect all arguments temporarily in an array (in reverse order) */
154 /* so that we can easily split into chunks of 255 args */
155 /* as needed by NPUSHB and NPUSHW, respectively */
156 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
157 if (!args)
158 return NULL;
160 arg = args + num_args - 1;
162 if (num_segments > 0xFF)
163 need_words = 1;
165 if (recorder->glyph->num_components)
166 *(arg--) = bci_create_segments_composite;
167 else
168 *(arg--) = bci_create_segments;
169 *(arg--) = num_segments;
171 for (seg = segments; seg < seg_limit; seg++)
173 FT_UInt first = seg->first - points;
174 FT_UInt last = seg->last - points;
177 *(arg--) = TA_adjust_point_index(recorder, first);
178 *(arg--) = TA_adjust_point_index(recorder, last);
180 /* we push the last and first contour point */
181 /* as a third and fourth argument in wrap-around segments */
182 if (first > last)
184 for (n = 0; n < outline.n_contours; n++)
186 FT_UInt end = (FT_UInt)outline.contours[n];
189 if (first <= end)
191 *(arg--) = TA_adjust_point_index(recorder, end);
192 if (end > 0xFF)
193 need_words = 1;
195 if (n == 0)
196 *(arg--) = TA_adjust_point_index(recorder, 0);
197 else
198 *(arg--) = TA_adjust_point_index(recorder,
199 (FT_UInt)outline.contours[n - 1] + 1);
200 break;
205 if (last > 0xFF)
206 need_words = 1;
209 /* emit the second part of wrap-around segments as separate segments */
210 /* so that edges can easily link to them */
211 for (seg = segments; seg < seg_limit; seg++)
213 FT_UInt first = seg->first - points;
214 FT_UInt last = seg->last - points;
217 if (first > last)
219 for (n = 0; n < outline.n_contours; n++)
221 if (first <= (FT_UInt)outline.contours[n])
223 if (n == 0)
224 *(arg--) = TA_adjust_point_index(recorder, 0);
225 else
226 *(arg--) = TA_adjust_point_index(recorder,
227 (FT_UInt)outline.contours[n - 1] + 1);
228 break;
232 *(arg--) = TA_adjust_point_index(recorder, last);
235 /* with most fonts it is very rare */
236 /* that any of the pushed arguments is larger than 0xFF, */
237 /* thus we refrain from further optimizing this case */
239 arg = args;
241 if (need_words)
243 for (i = 0; i < num_args; i += 255)
245 nargs = (num_args - i > 255) ? 255 : num_args - i;
247 BCI(NPUSHW);
248 BCI(nargs);
249 for (j = 0; j < nargs; j++)
251 BCI(HIGH(*arg));
252 BCI(LOW(*arg));
253 arg++;
257 else
259 for (i = 0; i < num_args; i += 255)
261 nargs = (num_args - i > 255) ? 255 : num_args - i;
263 BCI(NPUSHB);
264 BCI(nargs);
265 for (j = 0; j < nargs; j++)
267 BCI(*arg);
268 arg++;
273 BCI(CALL);
275 num_storage = sal_segment_offset + num_segments * 2;
276 if (num_storage > sfnt->max_storage)
277 sfnt->max_storage = num_storage;
279 num_twilight_points = num_segments * 2;
280 if (num_twilight_points > sfnt->max_twilight_points)
281 sfnt->max_twilight_points = num_twilight_points;
283 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
284 if (num_stack_elements > sfnt->max_stack_elements)
285 sfnt->max_stack_elements = num_stack_elements;
287 free(args);
289 return bufp;
293 static FT_Byte*
294 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
295 Recorder* recorder,
296 FT_Byte* bufp)
298 FT_GlyphSlot glyph = sfnt->face->glyph;
299 FT_Vector* points = glyph->outline.points;
300 FT_Int num_contours = glyph->outline.n_contours;
302 FT_UInt* args;
303 FT_UInt* arg;
304 FT_UInt num_args;
305 FT_UInt nargs;
307 FT_Bool need_words = 0;
308 FT_Int p, q;
309 FT_UInt i, j;
310 FT_Int start, end;
311 FT_UInt num_stack_elements;
314 num_args = 2 * num_contours + 2;
316 /* collect all arguments temporarily in an array (in reverse order) */
317 /* so that we can easily split into chunks of 255 args */
318 /* as needed by NPUSHB and NPUSHW, respectively */
319 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
320 if (!args)
321 return NULL;
323 arg = args + num_args - 1;
325 if (num_args > 0xFF)
326 need_words = 1;
328 if (recorder->glyph->num_components)
329 *(arg--) = bci_scale_composite_glyph;
330 else
331 *(arg--) = bci_scale_glyph;
332 *(arg--) = num_contours;
334 start = 0;
335 end = 0;
337 for (p = 0; p < num_contours; p++)
339 FT_Int max = start;
340 FT_Int min = start;
343 end = glyph->outline.contours[p];
345 for (q = start; q <= end; q++)
347 if (points[q].y < points[min].y)
348 min = q;
349 if (points[q].y > points[max].y)
350 max = q;
353 *(arg--) = TA_adjust_point_index(recorder, min);
354 *(arg--) = TA_adjust_point_index(recorder, max);
356 start = end + 1;
359 if (end > 0xFF)
360 need_words = 1;
362 /* with most fonts it is very rare */
363 /* that any of the pushed arguments is larger than 0xFF, */
364 /* thus we refrain from further optimizing this case */
366 arg = args;
368 if (need_words)
370 for (i = 0; i < num_args; i += 255)
372 nargs = (num_args - i > 255) ? 255 : num_args - i;
374 BCI(NPUSHW);
375 BCI(nargs);
376 for (j = 0; j < nargs; j++)
378 BCI(HIGH(*arg));
379 BCI(LOW(*arg));
380 arg++;
384 else
386 for (i = 0; i < num_args; i += 255)
388 nargs = (num_args - i > 255) ? 255 : num_args - i;
390 BCI(NPUSHB);
391 BCI(nargs);
392 for (j = 0; j < nargs; j++)
394 BCI(*arg);
395 arg++;
400 BCI(CALL);
402 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
403 if (num_stack_elements > sfnt->max_stack_elements)
404 sfnt->max_stack_elements = num_stack_elements;
406 free(args);
408 return bufp;
412 static FT_Byte*
413 TA_font_build_subglyph_shifter(FONT* font,
414 FT_Byte* bufp)
416 FT_Face face = font->loader->face;
417 FT_GlyphSlot glyph = face->glyph;
419 TA_GlyphLoader gloader = font->loader->gloader;
421 TA_SubGlyph subglyphs = gloader->base.subglyphs;
422 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
423 TA_SubGlyph subglyph;
425 FT_Int curr_contour = 0;
428 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
430 FT_Error error;
432 FT_UShort flags = subglyph->flags;
433 FT_Pos y_offset = subglyph->arg2;
435 FT_Int num_contours;
438 /* load subglyph to get the number of contours */
439 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
440 if (error)
441 return NULL;
442 num_contours = glyph->outline.n_contours;
444 /* nothing to do if there is a point-to-point alignment */
445 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
446 goto End;
448 /* nothing to do if y offset is zero */
449 if (!y_offset)
450 goto End;
452 /* nothing to do if there are no contours */
453 if (!num_contours)
454 goto End;
456 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
457 /* ensures that composite subglyphs are represented as simple glyphs */
459 if (num_contours > 0xFF
460 || curr_contour > 0xFF)
462 BCI(PUSHW_2);
463 BCI(HIGH(curr_contour));
464 BCI(LOW(curr_contour));
465 BCI(HIGH(num_contours));
466 BCI(LOW(num_contours));
468 else
470 BCI(PUSHB_2);
471 BCI(curr_contour);
472 BCI(num_contours);
475 /* there are high chances that this value needs PUSHW, */
476 /* thus we handle it separately */
477 if (y_offset > 0xFF || y_offset < 0)
479 BCI(PUSHW_1);
480 BCI(HIGH(y_offset));
481 BCI(LOW(y_offset));
483 else
485 BCI(PUSHB_1);
486 BCI(y_offset);
489 BCI(PUSHB_1);
490 BCI(bci_shift_subglyph);
491 BCI(CALL);
493 End:
494 curr_contour += num_contours;
497 return bufp;
502 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
503 * data in four arrays (which are simple but waste a lot of memory). The
504 * function below converts them into bytecode.
506 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
507 * together with the edge they correspond to.
509 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
510 * loop over the edge or edge pairs, respectively, and each edge or edge
511 * pair contains an inner loop to emit the correponding points.
514 static void
515 TA_build_point_hints(Recorder* recorder,
516 TA_GlyphHints hints)
518 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
519 TA_Segment segments = axis->segments;
520 TA_Edge edges = axis->edges;
522 TA_Edge edge;
523 TA_Edge before;
524 TA_Edge after;
526 FT_Byte* p = recorder->hints_record.buf;
527 FT_UInt num_edges = axis->num_edges;
528 FT_UInt num_strong_points = recorder->num_strong_points;
530 FT_UInt i;
531 FT_UInt j;
532 FT_UInt k;
534 FT_UInt* ip;
535 FT_UInt* iq;
536 FT_UInt* ir;
537 FT_UInt* ip_limit;
538 FT_UInt* iq_limit;
539 FT_UInt* ir_limit;
542 /* we store everything as 16bit numbers; */
543 /* the function numbers (`ta_ip_before', etc.) */
544 /* reflect the order in the TA_Action enumeration */
546 /* ip_before_points */
548 i = 0;
549 ip = recorder->ip_before_points;
550 ip_limit = ip + num_strong_points;
551 for (; ip < ip_limit; ip++)
553 if (*ip != MISSING)
554 i++;
555 else
556 break;
559 if (i)
561 recorder->hints_record.num_actions++;
563 edge = edges;
565 *(p++) = 0;
566 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
567 *(p++) = HIGH(edge->first - segments);
568 *(p++) = LOW(edge->first - segments);
569 *(p++) = HIGH(i);
570 *(p++) = LOW(i);
572 ip = recorder->ip_before_points;
573 ip_limit = ip + i;
574 for (; ip < ip_limit; ip++)
576 FT_UInt point = TA_adjust_point_index(recorder, *ip);
579 *(p++) = HIGH(point);
580 *(p++) = LOW(point);
584 /* ip_after_points */
586 i = 0;
587 ip = recorder->ip_after_points;
588 ip_limit = ip + num_strong_points;
589 for (; ip < ip_limit; ip++)
591 if (*ip != MISSING)
592 i++;
593 else
594 break;
597 if (i)
599 recorder->hints_record.num_actions++;
601 edge = edges + axis->num_edges - 1;
603 *(p++) = 0;
604 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
605 *(p++) = HIGH(edge->first - segments);
606 *(p++) = LOW(edge->first - segments);
607 *(p++) = HIGH(i);
608 *(p++) = LOW(i);
610 ip = recorder->ip_after_points;
611 ip_limit = ip + i;
612 for (; ip < ip_limit; ip++)
614 FT_UInt point = TA_adjust_point_index(recorder, *ip);
617 *(p++) = HIGH(point);
618 *(p++) = LOW(point);
622 /* ip_on_point_array */
624 i = 0;
625 ip = recorder->ip_on_point_array;
626 ip_limit = ip + num_edges * num_strong_points;
627 for (; ip < ip_limit; ip += num_strong_points)
628 if (*ip != MISSING)
629 i++;
631 if (i)
633 recorder->hints_record.num_actions++;
635 *(p++) = 0;
636 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
637 *(p++) = HIGH(i);
638 *(p++) = LOW(i);
640 i = 0;
641 ip = recorder->ip_on_point_array;
642 ip_limit = ip + num_edges * num_strong_points;
643 for (; ip < ip_limit; ip += num_strong_points, i++)
645 if (*ip == MISSING)
646 continue;
648 edge = edges + i;
650 *(p++) = HIGH(edge->first - segments);
651 *(p++) = LOW(edge->first - segments);
653 j = 0;
654 iq = ip;
655 iq_limit = iq + num_strong_points;
656 for (; iq < iq_limit; iq++)
658 if (*iq != MISSING)
659 j++;
660 else
661 break;
664 *(p++) = HIGH(j);
665 *(p++) = LOW(j);
667 iq = ip;
668 iq_limit = iq + j;
669 for (; iq < iq_limit; iq++)
671 FT_UInt point = TA_adjust_point_index(recorder, *iq);
674 *(p++) = HIGH(point);
675 *(p++) = LOW(point);
680 /* ip_between_point_array */
682 i = 0;
683 ip = recorder->ip_between_point_array;
684 ip_limit = ip + num_edges * num_edges * num_strong_points;
685 for (; ip < ip_limit; ip += num_strong_points)
686 if (*ip != MISSING)
687 i++;
689 if (i)
691 recorder->hints_record.num_actions++;
693 *(p++) = 0;
694 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
695 *(p++) = HIGH(i);
696 *(p++) = LOW(i);
698 i = 0;
699 ip = recorder->ip_between_point_array;
700 ip_limit = ip + num_edges * num_edges * num_strong_points;
701 for (;
702 ip < ip_limit;
703 ip += num_edges * num_strong_points, i++)
705 before = edges + i;
707 j = 0;
708 iq = ip;
709 iq_limit = iq + num_edges * num_strong_points;
710 for (; iq < iq_limit; iq += num_strong_points, j++)
712 if (*iq == MISSING)
713 continue;
715 after = edges + j;
717 *(p++) = HIGH(after->first - segments);
718 *(p++) = LOW(after->first - segments);
719 *(p++) = HIGH(before->first - segments);
720 *(p++) = LOW(before->first - segments);
722 k = 0;
723 ir = iq;
724 ir_limit = ir + num_strong_points;
725 for (; ir < ir_limit; ir++)
727 if (*ir != MISSING)
728 k++;
729 else
730 break;
733 *(p++) = HIGH(k);
734 *(p++) = LOW(k);
736 ir = iq;
737 ir_limit = ir + k;
738 for (; ir < ir_limit; ir++)
740 FT_UInt point = TA_adjust_point_index(recorder, *ir);
743 *(p++) = HIGH(point);
744 *(p++) = LOW(point);
750 recorder->hints_record.buf = p;
754 static FT_Bool
755 TA_hints_record_is_different(Hints_Record* hints_records,
756 FT_UInt num_hints_records,
757 FT_Byte* start,
758 FT_Byte* end)
760 Hints_Record last_hints_record;
763 if (!hints_records)
764 return 1;
766 /* we only need to compare with the last hints record */
767 last_hints_record = hints_records[num_hints_records - 1];
769 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
770 return 1;
772 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
773 return 1;
775 return 0;
779 static FT_Error
780 TA_add_hints_record(Hints_Record** hints_records,
781 FT_UInt* num_hints_records,
782 FT_Byte* start,
783 Hints_Record hints_record)
785 Hints_Record* hints_records_new;
786 FT_UInt buf_len;
787 /* at this point, `hints_record.buf' still points into `ins_buf' */
788 FT_Byte* end = hints_record.buf;
791 buf_len = (FT_UInt)(end - start);
793 /* now fill the structure completely */
794 hints_record.buf_len = buf_len;
795 hints_record.buf = (FT_Byte*)malloc(buf_len);
796 if (!hints_record.buf)
797 return FT_Err_Out_Of_Memory;
799 memcpy(hints_record.buf, start, buf_len);
801 (*num_hints_records)++;
802 hints_records_new =
803 (Hints_Record*)realloc(*hints_records, *num_hints_records
804 * sizeof (Hints_Record));
805 if (!hints_records_new)
807 free(hints_record.buf);
808 (*num_hints_records)--;
809 return FT_Err_Out_Of_Memory;
811 else
812 *hints_records = hints_records_new;
814 (*hints_records)[*num_hints_records - 1] = hints_record;
816 return FT_Err_Ok;
820 static FT_Byte*
821 TA_sfnt_emit_hints_record(SFNT* sfnt,
822 Hints_Record* hints_record,
823 FT_Byte* bufp)
825 FT_Byte* p;
826 FT_Byte* endp;
827 FT_Bool need_words = 0;
829 FT_UInt i, j;
830 FT_UInt num_arguments;
831 FT_UInt num_args;
832 FT_UInt num_stack_elements;
835 /* check whether any argument is larger than 0xFF */
836 endp = hints_record->buf + hints_record->buf_len;
837 for (p = hints_record->buf; p < endp; p += 2)
838 if (*p)
839 need_words = 1;
841 /* with most fonts it is very rare */
842 /* that any of the pushed arguments is larger than 0xFF, */
843 /* thus we refrain from further optimizing this case */
845 num_arguments = hints_record->buf_len / 2;
846 p = endp - 2;
848 if (need_words)
850 for (i = 0; i < num_arguments; i += 255)
852 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
854 BCI(NPUSHW);
855 BCI(num_args);
856 for (j = 0; j < num_args; j++)
858 BCI(*p);
859 BCI(*(p + 1));
860 p -= 2;
864 else
866 /* we only need the lower bytes */
867 p++;
869 for (i = 0; i < num_arguments; i += 255)
871 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
873 BCI(NPUSHB);
874 BCI(num_args);
875 for (j = 0; j < num_args; j++)
877 BCI(*p);
878 p -= 2;
883 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
884 if (num_stack_elements > sfnt->max_stack_elements)
885 sfnt->max_stack_elements = num_stack_elements;
887 return bufp;
891 static FT_Byte*
892 TA_sfnt_emit_hints_records(SFNT* sfnt,
893 Hints_Record* hints_records,
894 FT_UInt num_hints_records,
895 FT_Byte* bufp)
897 FT_UInt i;
898 Hints_Record* hints_record;
901 hints_record = hints_records;
903 for (i = 0; i < num_hints_records - 1; i++)
905 BCI(MPPEM);
906 if (hints_record->size > 0xFF)
908 BCI(PUSHW_1);
909 BCI(HIGH((hints_record + 1)->size));
910 BCI(LOW((hints_record + 1)->size));
912 else
914 BCI(PUSHB_1);
915 BCI((hints_record + 1)->size);
917 BCI(LT);
918 BCI(IF);
919 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
920 BCI(ELSE);
922 hints_record++;
925 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
927 for (i = 0; i < num_hints_records - 1; i++)
928 BCI(EIF);
930 BCI(PUSHB_1);
931 BCI(bci_hint_glyph);
932 BCI(CALL);
934 return bufp;
938 static void
939 TA_free_hints_records(Hints_Record* hints_records,
940 FT_UInt num_hints_records)
942 FT_UInt i;
945 for (i = 0; i < num_hints_records; i++)
946 free(hints_records[i].buf);
948 free(hints_records);
952 static FT_Byte*
953 TA_hints_recorder_handle_segments(FT_Byte* bufp,
954 TA_AxisHints axis,
955 TA_Edge edge,
956 FT_UInt* wraps)
958 TA_Segment segments = axis->segments;
959 TA_Segment seg;
960 FT_UInt seg_idx;
961 FT_UInt num_segs = 0;
962 FT_UInt* wrap;
965 seg_idx = edge->first - segments;
967 /* we store everything as 16bit numbers */
968 *(bufp++) = HIGH(seg_idx);
969 *(bufp++) = LOW(seg_idx);
971 /* wrap-around segments are stored as two segments */
972 if (edge->first->first > edge->first->last)
973 num_segs++;
975 seg = edge->first->edge_next;
976 while (seg != edge->first)
978 num_segs++;
980 if (seg->first > seg->last)
981 num_segs++;
983 seg = seg->edge_next;
986 *(bufp++) = HIGH(num_segs);
987 *(bufp++) = LOW(num_segs);
989 if (edge->first->first > edge->first->last)
991 /* emit second part of wrap-around segment; */
992 /* the bytecode positions such segments after `normal' ones */
993 wrap = wraps;
994 for (;;)
996 if (seg_idx == *wrap)
997 break;
998 wrap++;
1001 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1002 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1005 seg = edge->first->edge_next;
1006 while (seg != edge->first)
1008 seg_idx = seg - segments;
1010 *(bufp++) = HIGH(seg_idx);
1011 *(bufp++) = LOW(seg_idx);
1013 if (seg->first > seg->last)
1015 wrap = wraps;
1016 for (;;)
1018 if (seg_idx == *wrap)
1019 break;
1020 wrap++;
1023 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
1024 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
1027 seg = seg->edge_next;
1030 return bufp;
1034 static void
1035 TA_hints_recorder(TA_Action action,
1036 TA_GlyphHints hints,
1037 TA_Dimension dim,
1038 void* arg1,
1039 TA_Edge arg2,
1040 TA_Edge arg3,
1041 TA_Edge lower_bound,
1042 TA_Edge upper_bound)
1044 TA_AxisHints axis = &hints->axis[dim];
1045 TA_Edge edges = axis->edges;
1046 TA_Segment segments = axis->segments;
1047 TA_Point points = hints->points;
1049 Recorder* recorder = (Recorder*)hints->user;
1050 FONT* font = recorder->font;
1051 FT_UInt* wraps = recorder->wrap_around_segments;
1052 FT_Byte* p = recorder->hints_record.buf;
1054 FT_Byte bound_offset = 0;
1056 FT_UInt* ip;
1057 FT_UInt* limit;
1060 if (dim == TA_DIMENSION_HORZ)
1061 return;
1063 /* we collect point hints for later processing */
1064 switch (action)
1066 case ta_ip_before:
1068 TA_Point point = (TA_Point)arg1;
1071 ip = recorder->ip_before_points;
1072 limit = ip + recorder->num_strong_points;
1073 for (; ip < limit; ip++)
1075 if (*ip == MISSING)
1077 *ip = point - points;
1078 break;
1082 return;
1084 case ta_ip_after:
1086 TA_Point point = (TA_Point)arg1;
1089 ip = recorder->ip_after_points;
1090 limit = ip + recorder->num_strong_points;
1091 for (; ip < limit; ip++)
1093 if (*ip == MISSING)
1095 *ip = point - points;
1096 break;
1100 return;
1102 case ta_ip_on:
1104 TA_Point point = (TA_Point)arg1;
1105 TA_Edge edge = arg2;
1108 ip = recorder->ip_on_point_array
1109 + recorder->num_strong_points
1110 * (edge - edges);
1111 limit = ip + recorder->num_strong_points;
1112 for (; ip < limit; ip++)
1114 if (*ip == MISSING)
1116 *ip = point - points;
1117 break;
1121 return;
1123 case ta_ip_between:
1125 TA_Point point = (TA_Point)arg1;
1126 TA_Edge before = arg2;
1127 TA_Edge after = arg3;
1130 /* note that `recorder->num_segments' has been used for allocation, */
1131 /* but `axis->num_edges' is used for accessing this array */
1132 ip = recorder->ip_between_point_array
1133 + recorder->num_strong_points * axis->num_edges
1134 * (before - edges)
1135 + recorder->num_strong_points
1136 * (after - edges);
1137 limit = ip + recorder->num_strong_points;
1138 for (; ip < limit; ip++)
1140 if (*ip == MISSING)
1142 *ip = point - points;
1143 break;
1147 return;
1149 case ta_bound:
1150 /* we ignore the BOUND action since we signal this information */
1151 /* with the `bound_offset' parameter below */
1152 return;
1154 default:
1155 break;
1158 if (lower_bound)
1159 bound_offset += 1;
1160 if (upper_bound)
1161 bound_offset += 2;
1163 /* this reflects the order in the TA_Action enumeration */
1164 *(p++) = 0;
1165 *(p++) = (FT_Byte)action + bound_offset + ACTION_OFFSET;
1167 switch (action)
1169 case ta_link:
1171 TA_Edge base_edge = (TA_Edge)arg1;
1172 TA_Edge stem_edge = arg2;
1175 *(p++) = 0;
1176 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
1177 *(p++) = 0;
1178 *(p++) = base_edge->flags & TA_EDGE_ROUND;
1179 *(p++) = HIGH(base_edge->first - segments);
1180 *(p++) = LOW(base_edge->first - segments);
1181 *(p++) = HIGH(stem_edge->first - segments);
1182 *(p++) = LOW(stem_edge->first - segments);
1184 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1186 break;
1188 case ta_anchor:
1190 TA_Edge edge = (TA_Edge)arg1;
1191 TA_Edge edge2 = arg2;
1194 *(p++) = 0;
1195 *(p++) = edge2->flags & TA_EDGE_SERIF;
1196 *(p++) = 0;
1197 *(p++) = edge->flags & TA_EDGE_ROUND;
1198 *(p++) = HIGH(edge->first - segments);
1199 *(p++) = LOW(edge->first - segments);
1200 *(p++) = HIGH(edge2->first - segments);
1201 *(p++) = LOW(edge2->first - segments);
1203 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1205 break;
1207 case ta_adjust:
1209 TA_Edge edge = (TA_Edge)arg1;
1210 TA_Edge edge2 = arg2;
1211 TA_Edge edge_minus_one = lower_bound;
1214 *(p++) = 0;
1215 *(p++) = edge2->flags & TA_EDGE_SERIF;
1216 *(p++) = 0;
1217 *(p++) = edge->flags & TA_EDGE_ROUND;
1218 *(p++) = HIGH(edge->first - segments);
1219 *(p++) = LOW(edge->first - segments);
1220 *(p++) = HIGH(edge2->first - segments);
1221 *(p++) = LOW(edge2->first - segments);
1223 if (edge_minus_one)
1225 *(p++) = HIGH(edge_minus_one->first - segments);
1226 *(p++) = LOW(edge_minus_one->first - segments);
1229 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1231 break;
1233 case ta_blue_anchor:
1235 TA_Edge edge = (TA_Edge)arg1;
1236 TA_Edge blue = arg2;
1239 *(p++) = HIGH(blue->first - segments);
1240 *(p++) = LOW(blue->first - segments);
1242 if (edge->best_blue_is_shoot)
1244 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1245 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1247 else
1249 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1250 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1253 *(p++) = HIGH(edge->first - segments);
1254 *(p++) = LOW(edge->first - segments);
1256 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1258 break;
1260 case ta_stem:
1262 TA_Edge edge = (TA_Edge)arg1;
1263 TA_Edge edge2 = arg2;
1264 TA_Edge edge_minus_one = lower_bound;
1267 *(p++) = 0;
1268 *(p++) = edge2->flags & TA_EDGE_SERIF;
1269 *(p++) = 0;
1270 *(p++) = edge->flags & TA_EDGE_ROUND;
1271 *(p++) = HIGH(edge->first - segments);
1272 *(p++) = LOW(edge->first - segments);
1273 *(p++) = HIGH(edge2->first - segments);
1274 *(p++) = LOW(edge2->first - segments);
1276 if (edge_minus_one)
1278 *(p++) = HIGH(edge_minus_one->first - segments);
1279 *(p++) = LOW(edge_minus_one->first - segments);
1282 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1283 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1285 break;
1287 case ta_blue:
1289 TA_Edge edge = (TA_Edge)arg1;
1292 if (edge->best_blue_is_shoot)
1294 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1295 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1297 else
1299 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1300 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1303 *(p++) = HIGH(edge->first - segments);
1304 *(p++) = LOW(edge->first - segments);
1306 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1308 break;
1310 case ta_serif:
1312 TA_Edge serif = (TA_Edge)arg1;
1313 TA_Edge base = serif->serif;
1316 *(p++) = HIGH(serif->first - segments);
1317 *(p++) = LOW(serif->first - segments);
1318 *(p++) = HIGH(base->first - segments);
1319 *(p++) = LOW(base->first - segments);
1321 if (lower_bound)
1323 *(p++) = HIGH(lower_bound->first - segments);
1324 *(p++) = LOW(lower_bound->first - segments);
1326 if (upper_bound)
1328 *(p++) = HIGH(upper_bound->first - segments);
1329 *(p++) = LOW(upper_bound->first - segments);
1332 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1334 break;
1336 case ta_serif_anchor:
1337 case ta_serif_link2:
1339 TA_Edge edge = (TA_Edge)arg1;
1342 *(p++) = HIGH(edge->first - segments);
1343 *(p++) = LOW(edge->first - segments);
1345 if (lower_bound)
1347 *(p++) = HIGH(lower_bound->first - segments);
1348 *(p++) = LOW(lower_bound->first - segments);
1350 if (upper_bound)
1352 *(p++) = HIGH(upper_bound->first - segments);
1353 *(p++) = LOW(upper_bound->first - segments);
1356 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1358 break;
1360 case ta_serif_link1:
1362 TA_Edge edge = (TA_Edge)arg1;
1363 TA_Edge before = arg2;
1364 TA_Edge after = arg3;
1367 *(p++) = HIGH(before->first - segments);
1368 *(p++) = LOW(before->first - segments);
1369 *(p++) = HIGH(edge->first - segments);
1370 *(p++) = LOW(edge->first - segments);
1371 *(p++) = HIGH(after->first - segments);
1372 *(p++) = LOW(after->first - segments);
1374 if (lower_bound)
1376 *(p++) = HIGH(lower_bound->first - segments);
1377 *(p++) = LOW(lower_bound->first - segments);
1379 if (upper_bound)
1381 *(p++) = HIGH(upper_bound->first - segments);
1382 *(p++) = LOW(upper_bound->first - segments);
1385 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1387 break;
1389 default:
1390 /* there are more cases in the enumeration */
1391 /* which are handled with the `bound_offset' parameter */
1392 break;
1395 recorder->hints_record.num_actions++;
1396 recorder->hints_record.buf = p;
1400 static FT_Error
1401 TA_init_recorder(Recorder *recorder,
1402 FT_UInt wrap_around_size,
1403 FONT* font,
1404 GLYPH* glyph,
1405 TA_GlyphHints hints)
1407 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1408 TA_Point points = hints->points;
1409 TA_Point point_limit = points + hints->num_points;
1410 TA_Point point;
1412 FT_UInt num_strong_points = 0;
1415 recorder->font = font;
1416 recorder->glyph = glyph;
1417 recorder->num_segments = axis->num_segments;
1419 recorder->ip_before_points = NULL;
1420 recorder->ip_after_points = NULL;
1421 recorder->ip_on_point_array = NULL;
1422 recorder->ip_between_point_array = NULL;
1424 /* no need to clean up allocated arrays in case of error; */
1425 /* this is handled later by `TA_free_recorder' */
1427 recorder->wrap_around_segments =
1428 (FT_UInt*)malloc(wrap_around_size * sizeof (FT_UInt));
1429 if (!recorder->wrap_around_segments)
1430 return FT_Err_Out_Of_Memory;
1432 /* get number of strong points */
1433 for (point = points; point < point_limit; point++)
1435 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1436 /* however, this value isn't known yet */
1437 /* (or rather, it can vary between different pixel sizes) */
1438 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1439 continue;
1441 num_strong_points++;
1444 recorder->num_strong_points = num_strong_points;
1446 recorder->ip_before_points =
1447 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1448 if (!recorder->ip_before_points)
1449 return FT_Err_Out_Of_Memory;
1451 recorder->ip_after_points =
1452 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1453 if (!recorder->ip_after_points)
1454 return FT_Err_Out_Of_Memory;
1456 /* actually, we need `hints->num_edges' for the array sizes; */
1457 /* however, this value isn't known yet */
1458 /* (or rather, it can vary between different pixel sizes) */
1459 recorder->ip_on_point_array =
1460 (FT_UInt*)malloc(axis->num_segments
1461 * num_strong_points * sizeof (FT_UInt));
1462 if (!recorder->ip_on_point_array)
1463 return FT_Err_Out_Of_Memory;
1465 recorder->ip_between_point_array =
1466 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1467 * num_strong_points * sizeof (FT_UInt));
1468 if (!recorder->ip_between_point_array)
1469 return FT_Err_Out_Of_Memory;
1471 return FT_Err_Ok;
1475 static void
1476 TA_rewind_recorder(Recorder* recorder,
1477 FT_Byte* bufp,
1478 FT_UInt size)
1480 recorder->hints_record.buf = bufp + 2;
1481 recorder->hints_record.num_actions = 0;
1482 recorder->hints_record.size = size;
1484 /* We later check with MISSING (which expands to 0xFF bytes) */
1486 memset(recorder->ip_before_points, 0xFF,
1487 recorder->num_strong_points * sizeof (FT_UInt));
1488 memset(recorder->ip_after_points, 0xFF,
1489 recorder->num_strong_points * sizeof (FT_UInt));
1491 memset(recorder->ip_on_point_array, 0xFF,
1492 recorder->num_segments
1493 * recorder->num_strong_points * sizeof (FT_UInt));
1494 memset(recorder->ip_between_point_array, 0xFF,
1495 recorder->num_segments * recorder->num_segments
1496 * recorder->num_strong_points * sizeof (FT_UInt));
1501 static void
1502 TA_free_recorder(Recorder *recorder)
1504 free(recorder->wrap_around_segments);
1506 free(recorder->ip_before_points);
1507 free(recorder->ip_after_points);
1508 free(recorder->ip_on_point_array);
1509 free(recorder->ip_between_point_array);
1513 FT_Error
1514 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1515 FONT* font,
1516 FT_Long idx)
1518 FT_Face face = sfnt->face;
1519 FT_Error error;
1521 FT_Byte* ins_buf;
1522 FT_UInt ins_len;
1523 FT_Byte* bufp;
1524 FT_Byte* p;
1526 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1527 glyf_Data* data = (glyf_Data*)glyf_table->data;
1528 /* `idx' is never negative */
1529 GLYPH* glyph = &data->glyphs[idx];
1531 TA_GlyphHints hints;
1533 FT_UInt num_hints_records;
1534 Hints_Record* hints_records;
1536 Recorder recorder;
1538 FT_Int32 load_flags;
1539 FT_UInt size;
1542 load_flags = font->fallback_script << 30;
1543 if (!font->pre_hinting)
1544 load_flags |= FT_LOAD_NO_SCALE;
1546 /* computing the segments is resolution independent, */
1547 /* thus the pixel size in this call is arbitrary */
1548 error = FT_Set_Pixel_Sizes(face, 20, 20);
1549 if (error)
1550 return error;
1552 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1553 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1554 if (error)
1555 return error;
1557 /* do nothing if we have an empty glyph */
1558 if (!face->glyph->outline.n_contours)
1559 return FT_Err_Ok;
1561 hints = &font->loader->hints;
1563 /* we allocate a buffer which is certainly large enough */
1564 /* to hold all of the created bytecode instructions; */
1565 /* later on it gets reallocated to its real size */
1566 ins_len = hints->num_points * 1000;
1567 ins_buf = (FT_Byte*)malloc(ins_len);
1568 if (!ins_buf)
1569 return FT_Err_Out_Of_Memory;
1571 /* initialize array with an invalid bytecode */
1572 /* so that we can easily find the array length at reallocation time */
1573 memset(ins_buf, INS_A0, ins_len);
1575 num_hints_records = 0;
1576 hints_records = NULL;
1578 /* handle composite glyph */
1579 if (font->loader->gloader->base.num_subglyphs)
1581 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1582 if (!bufp)
1584 error = FT_Err_Out_Of_Memory;
1585 goto Err;
1588 goto Done1;
1591 /* only scale the glyph if the dummy hinter has been used */
1592 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1594 /* since `TA_init_recorder' hasn't been called yet, */
1595 /* we manually initialize the `glyph' field */
1596 recorder.glyph = glyph;
1598 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1599 if (!bufp)
1601 error = FT_Err_Out_Of_Memory;
1602 goto Err;
1605 goto Done1;
1608 error = TA_init_recorder(&recorder, face->glyph->outline.n_contours,
1609 font, glyph, hints);
1610 if (error)
1611 goto Err;
1613 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, ins_buf);
1614 if (!bufp)
1616 error = FT_Err_Out_Of_Memory;
1617 goto Err;
1620 /* now we loop over a large range of pixel sizes */
1621 /* to find hints records which get pushed onto the bytecode stack */
1623 #ifdef DEBUGGING
1624 printf("glyph %ld\n", idx);
1625 #endif
1627 /* we temporarily use `ins_buf' to record the current glyph hints, */
1628 /* leaving two bytes at the beginning so that the number of actions */
1629 /* can be inserted later on */
1630 ta_loader_register_hints_recorder(font->loader,
1631 TA_hints_recorder,
1632 (void *)&recorder);
1634 for (size = font->hinting_range_min;
1635 size <= font->hinting_range_max;
1636 size++)
1638 TA_rewind_recorder(&recorder, bufp, size);
1640 error = FT_Set_Pixel_Sizes(face, size, size);
1641 if (error)
1642 goto Err;
1644 /* calling `ta_loader_load_glyph' uses the */
1645 /* `TA_hints_recorder' function as a callback, */
1646 /* modifying `hints_record' */
1647 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1648 if (error)
1649 goto Err;
1651 /* append the point hints data collected in `TA_hints_recorder' */
1652 TA_build_point_hints(&recorder, hints);
1654 /* store the number of actions in `ins_buf' */
1655 *bufp = HIGH(recorder.hints_record.num_actions);
1656 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
1658 if (TA_hints_record_is_different(hints_records,
1659 num_hints_records,
1660 bufp, recorder.hints_record.buf))
1662 #ifdef DEBUGGING
1664 printf(" %d:\n", size);
1665 for (p = bufp; p < recorder.hints_record.buf; p += 2)
1666 printf(" %2d", *p * 256 + *(p + 1));
1667 printf("\n");
1669 #endif
1671 error = TA_add_hints_record(&hints_records,
1672 &num_hints_records,
1673 bufp, recorder.hints_record);
1674 if (error)
1675 goto Err;
1679 if (num_hints_records == 1 && !hints_records[0].num_actions)
1681 /* since we only have a single empty record we just scale the glyph, */
1682 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1683 bufp = TA_sfnt_build_glyph_scaler(sfnt, &recorder, ins_buf);
1684 if (!bufp)
1686 error = FT_Err_Out_Of_Memory;
1687 goto Err;
1690 /* clear the rest of the temporarily used part of `ins_buf' */
1691 p = bufp;
1692 while (*p != INS_A0)
1693 *(p++) = INS_A0;
1695 goto Done;
1698 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1699 /* is shorter than the previously stored data, */
1700 /* so clear the rest of the temporarily used part of `ins_buf' */
1701 /* before appending the hints records */
1702 p = bufp;
1703 while (*p != INS_A0)
1704 *(p++) = INS_A0;
1706 bufp = TA_sfnt_emit_hints_records(sfnt,
1707 hints_records, num_hints_records,
1708 bufp);
1710 Done:
1711 TA_free_hints_records(hints_records, num_hints_records);
1712 TA_free_recorder(&recorder);
1714 /* we are done, so reallocate the instruction array to its real size */
1715 if (*bufp == INS_A0)
1717 /* search backwards */
1718 while (*bufp == INS_A0)
1719 bufp--;
1720 bufp++;
1722 else
1724 /* search forwards */
1725 while (*bufp != INS_A0)
1726 bufp++;
1729 Done1:
1730 ins_len = bufp - ins_buf;
1732 if (ins_len > sfnt->max_instructions)
1733 sfnt->max_instructions = ins_len;
1735 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
1736 glyph->ins_len = ins_len;
1738 return FT_Err_Ok;
1740 Err:
1741 TA_free_hints_records(hints_records, num_hints_records);
1742 TA_free_recorder(&recorder);
1743 free(ins_buf);
1745 return error;
1749 /* end of tabytecode.c */