Recompute more fields of the `maxp' table.
[ttfautohint.git] / src / tabytecode.c
blob9febc74af093b49a362d4f06887f72a5683d0cc4
1 /* tabytecode.c */
3 /*
4 * Copyright (C) 2011 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 Hints_Record hints_record;
52 /* see explanations in `TA_sfnt_build_glyph_segments' */
53 FT_UInt* wrap_around_segments;
55 /* data necessary for strong point interpolation */
56 FT_UInt* ip_before_points;
57 FT_UInt* ip_after_points;
58 FT_UInt* ip_on_point_array;
59 FT_UInt* ip_between_point_array;
61 FT_UInt num_strong_points;
62 FT_UInt num_segments;
63 } Recorder;
66 /* we store the segments in the storage area; */
67 /* each segment record consists of the first and last point */
69 static FT_Byte*
70 TA_sfnt_build_glyph_segments(SFNT* sfnt,
71 Recorder* recorder,
72 FT_Byte* bufp)
74 FONT* font = recorder->font;
75 TA_GlyphHints hints = &font->loader->hints;
76 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
77 TA_Point points = hints->points;
78 TA_Segment segments = axis->segments;
79 TA_Segment seg;
80 TA_Segment seg_limit;
82 FT_Outline outline = font->loader->gloader->base.outline;
84 FT_UInt* args;
85 FT_UInt* arg;
86 FT_UInt num_args;
87 FT_UInt nargs;
88 FT_UInt num_segments;
90 FT_UInt* wrap_around_segment;
91 FT_UInt num_wrap_around_segments;
93 FT_Bool need_words = 0;
95 FT_Int n;
96 FT_UInt i, j;
97 FT_UInt num_storage;
98 FT_UInt num_stack_elements;
99 FT_UInt num_twilight_points;
102 seg_limit = segments + axis->num_segments;
103 num_segments = axis->num_segments;
105 /* some segments can `wrap around' */
106 /* a contour's start point like 24-25-26-0-1-2 */
107 /* (there can be at most one such segment per contour); */
108 /* we thus append additional records to split them into 24-26 and 0-2 */
109 wrap_around_segment = recorder->wrap_around_segments;
110 for (seg = segments; seg < seg_limit; seg++)
111 if (seg->first > seg->last)
113 /* the stored data is used later for edge linking */
114 *(wrap_around_segment++) = seg - segments;
117 num_wrap_around_segments = wrap_around_segment
118 - recorder->wrap_around_segments;
119 num_segments += num_wrap_around_segments;
121 /* wrap-around segments are pushed with four arguments */
122 num_args = 2 * num_segments + 2 * num_wrap_around_segments + 2;
124 /* collect all arguments temporarily in an array (in reverse order) */
125 /* so that we can easily split into chunks of 255 args */
126 /* as needed by NPUSHB and NPUSHW, respectively */
127 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
128 if (!args)
129 return NULL;
131 arg = args + num_args - 1;
133 if (num_segments > 0xFF)
134 need_words = 1;
136 *(arg--) = bci_create_segments;
137 *(arg--) = num_segments;
139 for (seg = segments; seg < seg_limit; seg++)
141 FT_UInt first = seg->first - points;
142 FT_UInt last = seg->last - points;
145 *(arg--) = first;
146 *(arg--) = last;
148 /* we push the last and first contour point */
149 /* as a third and fourth argument in wrap-around segments */
150 if (first > last)
152 for (n = 0; n < outline.n_contours; n++)
154 FT_UInt end = (FT_UInt)outline.contours[n];
157 if (first <= end)
159 *(arg--) = end;
160 if (end > 0xFF)
161 need_words = 1;
163 if (n == 0)
164 *(arg--) = 0;
165 else
166 *(arg--) = (FT_UInt)outline.contours[n - 1] + 1;
167 break;
172 if (last > 0xFF)
173 need_words = 1;
176 /* emit the second part of wrap-around segments as separate segments */
177 /* so that edges can easily link to them */
178 for (seg = segments; seg < seg_limit; seg++)
180 FT_UInt first = seg->first - points;
181 FT_UInt last = seg->last - points;
184 if (first > last)
186 for (n = 0; n < outline.n_contours; n++)
188 if (first <= (FT_UInt)outline.contours[n])
190 if (n == 0)
191 *(arg--) = 0;
192 else
193 *(arg--) = (FT_UInt)outline.contours[n - 1] + 1;
194 break;
198 *(arg--) = last;
201 /* with most fonts it is very rare */
202 /* that any of the pushed arguments is larger than 0xFF, */
203 /* thus we refrain from further optimizing this case */
205 arg = args;
207 if (need_words)
209 for (i = 0; i < num_args; i += 255)
211 nargs = (num_args - i > 255) ? 255 : num_args - i;
213 BCI(NPUSHW);
214 BCI(nargs);
215 for (j = 0; j < nargs; j++)
217 BCI(HIGH(*arg));
218 BCI(LOW(*arg));
219 arg++;
223 else
225 for (i = 0; i < num_args; i += 255)
227 nargs = (num_args - i > 255) ? 255 : num_args - i;
229 BCI(NPUSHB);
230 BCI(nargs);
231 for (j = 0; j < nargs; j++)
233 BCI(*arg);
234 arg++;
239 BCI(CALL);
241 num_storage = sal_segment_offset + num_segments * 2;
242 if (num_storage > sfnt->max_storage)
243 sfnt->max_storage = num_storage;
245 num_twilight_points = num_segments * 2;
246 if (num_twilight_points > sfnt->max_twilight_points)
247 sfnt->max_twilight_points = num_twilight_points;
249 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
250 if (num_stack_elements > sfnt->max_stack_elements)
251 sfnt->max_stack_elements = num_stack_elements;
253 free(args);
255 return bufp;
259 static FT_Byte*
260 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
261 FT_Byte* bufp)
263 FT_GlyphSlot glyph = sfnt->face->glyph;
264 FT_Vector* points = glyph->outline.points;
265 FT_Int num_contours = glyph->outline.n_contours;
267 FT_UInt* args;
268 FT_UInt* arg;
269 FT_UInt num_args;
270 FT_UInt nargs;
272 FT_Bool need_words = 0;
273 FT_Int p, q;
274 FT_UInt i, j;
275 FT_Int start, end;
276 FT_UInt num_stack_elements;
279 num_args = 2 * num_contours + 2;
281 /* collect all arguments temporarily in an array (in reverse order) */
282 /* so that we can easily split into chunks of 255 args */
283 /* as needed by NPUSHB and NPUSHW, respectively */
284 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
285 if (!args)
286 return NULL;
288 arg = args + num_args - 1;
290 if (num_args > 0xFF)
291 need_words = 1;
293 *(arg--) = bci_scale_glyph;
294 *(arg--) = num_contours;
296 start = 0;
297 end = 0;
299 for (p = 0; p < num_contours; p++)
301 FT_Int max = start;
302 FT_Int min = start;
305 end = glyph->outline.contours[p];
307 for (q = start; q <= end; q++)
309 if (points[q].y < points[min].y)
310 min = q;
311 if (points[q].y > points[max].y)
312 max = q;
315 *(arg--) = min;
316 *(arg--) = max;
318 start = end + 1;
321 if (end > 0xFF)
322 need_words = 1;
324 /* with most fonts it is very rare */
325 /* that any of the pushed arguments is larger than 0xFF, */
326 /* thus we refrain from further optimizing this case */
328 arg = args;
330 if (need_words)
332 for (i = 0; i < num_args; i += 255)
334 nargs = (num_args - i > 255) ? 255 : num_args - i;
336 BCI(NPUSHW);
337 BCI(nargs);
338 for (j = 0; j < nargs; j++)
340 BCI(HIGH(*arg));
341 BCI(LOW(*arg));
342 arg++;
346 else
348 for (i = 0; i < num_args; i += 255)
350 nargs = (num_args - i > 255) ? 255 : num_args - i;
352 BCI(NPUSHB);
353 BCI(nargs);
354 for (j = 0; j < nargs; j++)
356 BCI(*arg);
357 arg++;
362 BCI(CALL);
364 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
365 if (num_stack_elements > sfnt->max_stack_elements)
366 sfnt->max_stack_elements = num_stack_elements;
368 free(args);
370 return bufp;
374 static FT_Byte*
375 TA_font_build_subglyph_shifter(FONT* font,
376 FT_Byte* bufp)
378 FT_Face face = font->loader->face;
379 FT_GlyphSlot glyph = face->glyph;
381 TA_GlyphLoader gloader = font->loader->gloader;
383 TA_SubGlyph subglyphs = gloader->base.subglyphs;
384 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
385 TA_SubGlyph subglyph;
387 FT_Int curr_contour = 0;
390 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
392 FT_Error error;
394 FT_UShort flags = subglyph->flags;
395 FT_Pos y_offset = subglyph->arg2;
397 FT_Int num_contours;
400 /* load subglyph to get the number of contours */
401 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
402 if (error)
403 return NULL;
404 num_contours = glyph->outline.n_contours;
406 /* nothing to do if there is a point-to-point alignment */
407 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
408 goto End;
410 /* nothing to do if y offset is zero */
411 if (!y_offset)
412 goto End;
414 /* nothing to do if there are no contours */
415 if (!num_contours)
416 goto End;
418 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
419 /* ensures that composites are not resolved into simple glyphs */
421 if (num_contours > 0xFF
422 || curr_contour > 0xFF)
424 BCI(PUSHW_2);
425 BCI(HIGH(curr_contour));
426 BCI(LOW(curr_contour));
427 BCI(HIGH(num_contours));
428 BCI(LOW(num_contours));
430 else
432 BCI(PUSHB_2);
433 BCI(curr_contour);
434 BCI(num_contours);
437 /* there are high chances that this value needs PUSHW, */
438 /* thus we handle it separately */
439 if (y_offset > 0xFF || y_offset < 0)
441 BCI(PUSHW_1);
442 BCI(HIGH(y_offset));
443 BCI(LOW(y_offset));
445 else
447 BCI(PUSHB_1);
448 BCI(y_offset);
451 BCI(PUSHB_1);
452 BCI(bci_shift_subglyph);
453 BCI(CALL);
455 End:
456 curr_contour += num_contours;
459 return bufp;
464 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
465 * data in four arrays (which are simple but waste a lot of memory). The
466 * function below converts them into bytecode.
468 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
469 * together with the edge they correspond to.
471 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
472 * loop over the edge or edge pairs, respectively, and each edge or edge
473 * pair contains an inner loop to emit the correponding points.
476 static void
477 TA_build_point_hints(Recorder* recorder,
478 TA_GlyphHints hints)
480 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
481 TA_Segment segments = axis->segments;
482 TA_Edge edges = axis->edges;
484 TA_Edge edge;
485 TA_Edge before;
486 TA_Edge after;
488 FT_Byte* p = recorder->hints_record.buf;
489 FT_UInt num_edges = axis->num_edges;
490 FT_UInt num_strong_points = recorder->num_strong_points;
492 FT_UInt i;
493 FT_UInt j;
494 FT_UInt k;
496 FT_UInt* ip;
497 FT_UInt* iq;
498 FT_UInt* ir;
499 FT_UInt* ip_limit;
500 FT_UInt* iq_limit;
501 FT_UInt* ir_limit;
504 /* we store everything as 16bit numbers; */
505 /* the function numbers (`ta_ip_before', etc.) */
506 /* reflect the order in the TA_Action enumeration */
508 /* ip_before_points */
510 i = 0;
511 ip = recorder->ip_before_points;
512 ip_limit = ip + num_strong_points;
513 for (; ip < ip_limit; ip++)
515 if (*ip != MISSING)
516 i++;
517 else
518 break;
521 if (i)
523 recorder->hints_record.num_actions++;
525 edge = edges;
527 *(p++) = 0;
528 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
529 *(p++) = HIGH(edge->first - segments);
530 *(p++) = LOW(edge->first - segments);
531 *(p++) = HIGH(i);
532 *(p++) = LOW(i);
534 ip = recorder->ip_before_points;
535 ip_limit = ip + i;
536 for (; ip < ip_limit; ip++)
538 *(p++) = HIGH(*ip);
539 *(p++) = LOW(*ip);
543 /* ip_after_points */
545 i = 0;
546 ip = recorder->ip_after_points;
547 ip_limit = ip + num_strong_points;
548 for (; ip < ip_limit; ip++)
550 if (*ip != MISSING)
551 i++;
552 else
553 break;
556 if (i)
558 recorder->hints_record.num_actions++;
560 edge = edges + axis->num_edges - 1;
562 *(p++) = 0;
563 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
564 *(p++) = HIGH(edge->first - segments);
565 *(p++) = LOW(edge->first - segments);
566 *(p++) = HIGH(i);
567 *(p++) = LOW(i);
569 ip = recorder->ip_after_points;
570 ip_limit = ip + i;
571 for (; ip < ip_limit; ip++)
573 *(p++) = HIGH(*ip);
574 *(p++) = LOW(*ip);
578 /* ip_on_point_array */
580 i = 0;
581 ip = recorder->ip_on_point_array;
582 ip_limit = ip + num_edges * num_strong_points;
583 for (; ip < ip_limit; ip += num_strong_points)
584 if (*ip != MISSING)
585 i++;
587 if (i)
589 recorder->hints_record.num_actions++;
591 *(p++) = 0;
592 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
593 *(p++) = HIGH(i);
594 *(p++) = LOW(i);
596 i = 0;
597 ip = recorder->ip_on_point_array;
598 ip_limit = ip + num_edges * num_strong_points;
599 for (; ip < ip_limit; ip += num_strong_points, i++)
601 if (*ip == MISSING)
602 continue;
604 edge = edges + i;
606 *(p++) = HIGH(edge->first - segments);
607 *(p++) = LOW(edge->first - segments);
609 j = 0;
610 iq = ip;
611 iq_limit = iq + num_strong_points;
612 for (; iq < iq_limit; iq++)
614 if (*iq != MISSING)
615 j++;
616 else
617 break;
620 *(p++) = HIGH(j);
621 *(p++) = LOW(j);
623 iq = ip;
624 iq_limit = iq + j;
625 for (; iq < iq_limit; iq++)
627 *(p++) = HIGH(*iq);
628 *(p++) = LOW(*iq);
633 /* ip_between_point_array */
635 i = 0;
636 ip = recorder->ip_between_point_array;
637 ip_limit = ip + num_edges * num_edges * num_strong_points;
638 for (; ip < ip_limit; ip += num_strong_points)
639 if (*ip != MISSING)
640 i++;
642 if (i)
644 recorder->hints_record.num_actions++;
646 *(p++) = 0;
647 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
648 *(p++) = HIGH(i);
649 *(p++) = LOW(i);
651 i = 0;
652 ip = recorder->ip_between_point_array;
653 ip_limit = ip + num_edges * num_edges * num_strong_points;
654 for (;
655 ip < ip_limit;
656 ip += num_edges * num_strong_points, i++)
658 before = edges + i;
660 j = 0;
661 iq = ip;
662 iq_limit = iq + num_edges * num_strong_points;
663 for (; iq < iq_limit; iq += num_strong_points, j++)
665 if (*iq == MISSING)
666 continue;
668 after = edges + j;
670 *(p++) = HIGH(after->first - segments);
671 *(p++) = LOW(after->first - segments);
672 *(p++) = HIGH(before->first - segments);
673 *(p++) = LOW(before->first - segments);
675 k = 0;
676 ir = iq;
677 ir_limit = ir + num_strong_points;
678 for (; ir < ir_limit; ir++)
680 if (*ir != MISSING)
681 k++;
682 else
683 break;
686 *(p++) = HIGH(k);
687 *(p++) = LOW(k);
689 ir = iq;
690 ir_limit = ir + k;
691 for (; ir < ir_limit; ir++)
693 *(p++) = HIGH(*ir);
694 *(p++) = LOW(*ir);
700 recorder->hints_record.buf = p;
704 static FT_Bool
705 TA_hints_record_is_different(Hints_Record* hints_records,
706 FT_UInt num_hints_records,
707 FT_Byte* start,
708 FT_Byte* end)
710 Hints_Record last_hints_record;
713 if (!hints_records)
714 return 1;
716 /* we only need to compare with the last hints record */
717 last_hints_record = hints_records[num_hints_records - 1];
719 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
720 return 1;
722 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
723 return 1;
725 return 0;
729 static FT_Error
730 TA_add_hints_record(Hints_Record** hints_records,
731 FT_UInt* num_hints_records,
732 FT_Byte* start,
733 Hints_Record hints_record)
735 Hints_Record* hints_records_new;
736 FT_UInt buf_len;
737 /* at this point, `hints_record.buf' still points into `ins_buf' */
738 FT_Byte* end = hints_record.buf;
741 buf_len = (FT_UInt)(end - start);
743 /* now fill the structure completely */
744 hints_record.buf_len = buf_len;
745 hints_record.buf = (FT_Byte*)malloc(buf_len);
746 if (!hints_record.buf)
747 return FT_Err_Out_Of_Memory;
749 memcpy(hints_record.buf, start, buf_len);
751 (*num_hints_records)++;
752 hints_records_new =
753 (Hints_Record*)realloc(*hints_records, *num_hints_records
754 * sizeof (Hints_Record));
755 if (!hints_records_new)
757 free(hints_record.buf);
758 (*num_hints_records)--;
759 return FT_Err_Out_Of_Memory;
761 else
762 *hints_records = hints_records_new;
764 (*hints_records)[*num_hints_records - 1] = hints_record;
766 return FT_Err_Ok;
770 static FT_Byte*
771 TA_sfnt_emit_hints_record(SFNT* sfnt,
772 Hints_Record* hints_record,
773 FT_Byte* bufp)
775 FT_Byte* p;
776 FT_Byte* endp;
777 FT_Bool need_words = 0;
779 FT_UInt i, j;
780 FT_UInt num_arguments;
781 FT_UInt num_args;
782 FT_UInt num_stack_elements;
785 /* check whether any argument is larger than 0xFF */
786 endp = hints_record->buf + hints_record->buf_len;
787 for (p = hints_record->buf; p < endp; p += 2)
788 if (*p)
789 need_words = 1;
791 /* with most fonts it is very rare */
792 /* that any of the pushed arguments is larger than 0xFF, */
793 /* thus we refrain from further optimizing this case */
795 num_arguments = hints_record->buf_len / 2;
796 p = endp - 2;
798 if (need_words)
800 for (i = 0; i < num_arguments; i += 255)
802 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
804 BCI(NPUSHW);
805 BCI(num_args);
806 for (j = 0; j < num_args; j++)
808 BCI(*p);
809 BCI(*(p + 1));
810 p -= 2;
814 else
816 /* we only need the lower bytes */
817 p++;
819 for (i = 0; i < num_arguments; i += 255)
821 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
823 BCI(NPUSHB);
824 BCI(num_args);
825 for (j = 0; j < num_args; j++)
827 BCI(*p);
828 p -= 2;
833 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
834 if (num_stack_elements > sfnt->max_stack_elements)
835 sfnt->max_stack_elements = num_stack_elements;
837 return bufp;
841 static FT_Byte*
842 TA_sfnt_emit_hints_records(SFNT* sfnt,
843 Hints_Record* hints_records,
844 FT_UInt num_hints_records,
845 FT_Byte* bufp)
847 FT_UInt i;
848 Hints_Record* hints_record;
851 hints_record = hints_records;
853 for (i = 0; i < num_hints_records - 1; i++)
855 BCI(MPPEM);
856 if (hints_record->size > 0xFF)
858 BCI(PUSHW_1);
859 BCI(HIGH((hints_record + 1)->size));
860 BCI(LOW((hints_record + 1)->size));
862 else
864 BCI(PUSHB_1);
865 BCI((hints_record + 1)->size);
867 BCI(LT);
868 BCI(IF);
869 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
870 BCI(ELSE);
872 hints_record++;
875 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
877 for (i = 0; i < num_hints_records - 1; i++)
878 BCI(EIF);
880 BCI(PUSHB_1);
881 BCI(bci_hint_glyph);
882 BCI(CALL);
884 return bufp;
888 static void
889 TA_free_hints_records(Hints_Record* hints_records,
890 FT_UInt num_hints_records)
892 FT_UInt i;
895 for (i = 0; i < num_hints_records; i++)
896 free(hints_records[i].buf);
898 free(hints_records);
902 static FT_Byte*
903 TA_hints_recorder_handle_segments(FT_Byte* bufp,
904 TA_AxisHints axis,
905 TA_Edge edge,
906 FT_UInt* wraps)
908 TA_Segment segments = axis->segments;
909 TA_Segment seg;
910 FT_UInt seg_idx;
911 FT_UInt num_segs = 0;
912 FT_UInt* wrap;
915 seg_idx = edge->first - segments;
917 /* we store everything as 16bit numbers */
918 *(bufp++) = HIGH(seg_idx);
919 *(bufp++) = LOW(seg_idx);
921 /* wrap-around segments are stored as two segments */
922 if (edge->first->first > edge->first->last)
923 num_segs++;
925 seg = edge->first->edge_next;
926 while (seg != edge->first)
928 num_segs++;
930 if (seg->first > seg->last)
931 num_segs++;
933 seg = seg->edge_next;
936 *(bufp++) = HIGH(num_segs);
937 *(bufp++) = LOW(num_segs);
939 if (edge->first->first > edge->first->last)
941 /* emit second part of wrap-around segment; */
942 /* the bytecode positions such segments after `normal' ones */
943 wrap = wraps;
944 for (;;)
946 if (seg_idx == *wrap)
947 break;
948 wrap++;
951 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
952 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
955 seg = edge->first->edge_next;
956 while (seg != edge->first)
958 seg_idx = seg - segments;
960 *(bufp++) = HIGH(seg_idx);
961 *(bufp++) = LOW(seg_idx);
963 if (seg->first > seg->last)
965 wrap = wraps;
966 for (;;)
968 if (seg_idx == *wrap)
969 break;
970 wrap++;
973 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
974 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
977 seg = seg->edge_next;
980 return bufp;
984 static void
985 TA_hints_recorder(TA_Action action,
986 TA_GlyphHints hints,
987 TA_Dimension dim,
988 void* arg1,
989 TA_Edge arg2,
990 TA_Edge arg3,
991 TA_Edge lower_bound,
992 TA_Edge upper_bound)
994 TA_AxisHints axis = &hints->axis[dim];
995 TA_Edge edges = axis->edges;
996 TA_Segment segments = axis->segments;
997 TA_Point points = hints->points;
999 Recorder* recorder = (Recorder*)hints->user;
1000 FONT* font = recorder->font;
1001 FT_UInt* wraps = recorder->wrap_around_segments;
1002 FT_Byte* p = recorder->hints_record.buf;
1004 FT_Byte bound_offset = 0;
1006 FT_UInt* ip;
1007 FT_UInt* limit;
1010 if (dim == TA_DIMENSION_HORZ)
1011 return;
1013 /* we collect point hints for later processing */
1014 switch (action)
1016 case ta_ip_before:
1018 TA_Point point = (TA_Point)arg1;
1021 ip = recorder->ip_before_points;
1022 limit = ip + recorder->num_strong_points;
1023 for (; ip < limit; ip++)
1025 if (*ip == MISSING)
1027 *ip = point - points;
1028 break;
1032 return;
1034 case ta_ip_after:
1036 TA_Point point = (TA_Point)arg1;
1039 ip = recorder->ip_after_points;
1040 limit = ip + recorder->num_strong_points;
1041 for (; ip < limit; ip++)
1043 if (*ip == MISSING)
1045 *ip = point - points;
1046 break;
1050 return;
1052 case ta_ip_on:
1054 TA_Point point = (TA_Point)arg1;
1055 TA_Edge edge = arg2;
1058 ip = recorder->ip_on_point_array
1059 + recorder->num_strong_points
1060 * (edge - edges);
1061 limit = ip + recorder->num_strong_points;
1062 for (; ip < limit; ip++)
1064 if (*ip == MISSING)
1066 *ip = point - points;
1067 break;
1071 return;
1073 case ta_ip_between:
1075 TA_Point point = (TA_Point)arg1;
1076 TA_Edge before = arg2;
1077 TA_Edge after = arg3;
1080 /* note that `recorder->num_segments' has been used for allocation, */
1081 /* but `axis->num_edges' is used for accessing this array */
1082 ip = recorder->ip_between_point_array
1083 + recorder->num_strong_points * axis->num_edges
1084 * (before - edges)
1085 + recorder->num_strong_points
1086 * (after - edges);
1087 limit = ip + recorder->num_strong_points;
1088 for (; ip < limit; ip++)
1090 if (*ip == MISSING)
1092 *ip = point - points;
1093 break;
1097 return;
1099 case ta_bound:
1100 /* we ignore the BOUND action since we signal this information */
1101 /* with the `bound_offset' parameter below */
1102 return;
1104 default:
1105 break;
1108 if (lower_bound)
1109 bound_offset += 1;
1110 if (upper_bound)
1111 bound_offset += 2;
1113 /* this reflects the order in the TA_Action enumeration */
1114 *(p++) = 0;
1115 *(p++) = (FT_Byte)action + bound_offset + ACTION_OFFSET;
1117 switch (action)
1119 case ta_link:
1121 TA_Edge base_edge = (TA_Edge)arg1;
1122 TA_Edge stem_edge = arg2;
1125 *(p++) = 0;
1126 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
1127 *(p++) = 0;
1128 *(p++) = base_edge->flags & TA_EDGE_ROUND;
1129 *(p++) = HIGH(base_edge->first - segments);
1130 *(p++) = LOW(base_edge->first - segments);
1131 *(p++) = HIGH(stem_edge->first - segments);
1132 *(p++) = LOW(stem_edge->first - segments);
1134 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1136 break;
1138 case ta_anchor:
1140 TA_Edge edge = (TA_Edge)arg1;
1141 TA_Edge edge2 = arg2;
1144 *(p++) = 0;
1145 *(p++) = edge2->flags & TA_EDGE_SERIF;
1146 *(p++) = 0;
1147 *(p++) = edge->flags & TA_EDGE_ROUND;
1148 *(p++) = HIGH(edge->first - segments);
1149 *(p++) = LOW(edge->first - segments);
1150 *(p++) = HIGH(edge2->first - segments);
1151 *(p++) = LOW(edge2->first - segments);
1153 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1155 break;
1157 case ta_adjust:
1159 TA_Edge edge = (TA_Edge)arg1;
1160 TA_Edge edge2 = arg2;
1161 TA_Edge edge_minus_one = lower_bound;
1164 *(p++) = 0;
1165 *(p++) = edge2->flags & TA_EDGE_SERIF;
1166 *(p++) = 0;
1167 *(p++) = edge->flags & TA_EDGE_ROUND;
1168 *(p++) = HIGH(edge->first - segments);
1169 *(p++) = LOW(edge->first - segments);
1170 *(p++) = HIGH(edge2->first - segments);
1171 *(p++) = LOW(edge2->first - segments);
1173 if (edge_minus_one)
1175 *(p++) = HIGH(edge_minus_one->first - segments);
1176 *(p++) = LOW(edge_minus_one->first - segments);
1179 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1181 break;
1183 case ta_blue_anchor:
1185 TA_Edge edge = (TA_Edge)arg1;
1186 TA_Edge blue = arg2;
1189 *(p++) = HIGH(blue->first - segments);
1190 *(p++) = LOW(blue->first - segments);
1192 if (edge->best_blue_is_shoot)
1194 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1195 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1197 else
1199 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1200 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1203 *(p++) = HIGH(edge->first - segments);
1204 *(p++) = LOW(edge->first - segments);
1206 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1208 break;
1210 case ta_stem:
1212 TA_Edge edge = (TA_Edge)arg1;
1213 TA_Edge edge2 = arg2;
1214 TA_Edge edge_minus_one = lower_bound;
1217 *(p++) = 0;
1218 *(p++) = edge2->flags & TA_EDGE_SERIF;
1219 *(p++) = 0;
1220 *(p++) = edge->flags & TA_EDGE_ROUND;
1221 *(p++) = HIGH(edge->first - segments);
1222 *(p++) = LOW(edge->first - segments);
1223 *(p++) = HIGH(edge2->first - segments);
1224 *(p++) = LOW(edge2->first - segments);
1226 if (edge_minus_one)
1228 *(p++) = HIGH(edge_minus_one->first - segments);
1229 *(p++) = LOW(edge_minus_one->first - segments);
1232 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1233 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1235 break;
1237 case ta_blue:
1239 TA_Edge edge = (TA_Edge)arg1;
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_serif:
1262 TA_Edge serif = (TA_Edge)arg1;
1263 TA_Edge base = serif->serif;
1266 *(p++) = HIGH(serif->first - segments);
1267 *(p++) = LOW(serif->first - segments);
1268 *(p++) = HIGH(base->first - segments);
1269 *(p++) = LOW(base->first - segments);
1271 if (lower_bound)
1273 *(p++) = HIGH(lower_bound->first - segments);
1274 *(p++) = LOW(lower_bound->first - segments);
1276 if (upper_bound)
1278 *(p++) = HIGH(upper_bound->first - segments);
1279 *(p++) = LOW(upper_bound->first - segments);
1282 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1284 break;
1286 case ta_serif_anchor:
1287 case ta_serif_link2:
1289 TA_Edge edge = (TA_Edge)arg1;
1292 *(p++) = HIGH(edge->first - segments);
1293 *(p++) = LOW(edge->first - segments);
1295 if (lower_bound)
1297 *(p++) = HIGH(lower_bound->first - segments);
1298 *(p++) = LOW(lower_bound->first - segments);
1300 if (upper_bound)
1302 *(p++) = HIGH(upper_bound->first - segments);
1303 *(p++) = LOW(upper_bound->first - segments);
1306 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1308 break;
1310 case ta_serif_link1:
1312 TA_Edge edge = (TA_Edge)arg1;
1313 TA_Edge before = arg2;
1314 TA_Edge after = arg3;
1317 *(p++) = HIGH(before->first - segments);
1318 *(p++) = LOW(before->first - segments);
1319 *(p++) = HIGH(edge->first - segments);
1320 *(p++) = LOW(edge->first - segments);
1321 *(p++) = HIGH(after->first - segments);
1322 *(p++) = LOW(after->first - segments);
1324 if (lower_bound)
1326 *(p++) = HIGH(lower_bound->first - segments);
1327 *(p++) = LOW(lower_bound->first - segments);
1329 if (upper_bound)
1331 *(p++) = HIGH(upper_bound->first - segments);
1332 *(p++) = LOW(upper_bound->first - segments);
1335 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1337 break;
1339 default:
1340 /* there are more cases in the enumeration */
1341 /* which are handled with the `bound_offset' parameter */
1342 break;
1345 recorder->hints_record.num_actions++;
1346 recorder->hints_record.buf = p;
1350 static FT_Error
1351 TA_init_recorder(Recorder *recorder,
1352 FT_UInt wrap_around_size,
1353 FONT* font,
1354 TA_GlyphHints hints)
1356 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1357 TA_Point points = hints->points;
1358 TA_Point point_limit = points + hints->num_points;
1359 TA_Point point;
1361 FT_UInt num_strong_points = 0;
1364 recorder->font = font;
1365 recorder->num_segments = axis->num_segments;
1367 recorder->ip_before_points = NULL;
1368 recorder->ip_after_points = NULL;
1369 recorder->ip_on_point_array = NULL;
1370 recorder->ip_between_point_array = NULL;
1372 /* no need to clean up allocated arrays in case of error; */
1373 /* this is handled later by `TA_free_recorder' */
1375 recorder->wrap_around_segments =
1376 (FT_UInt*)malloc(wrap_around_size * sizeof (FT_UInt));
1377 if (!recorder->wrap_around_segments)
1378 return FT_Err_Out_Of_Memory;
1380 /* get number of strong points */
1381 for (point = points; point < point_limit; point++)
1383 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1384 /* however, this value isn't known yet */
1385 /* (or rather, it can vary between different pixel sizes) */
1386 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1387 continue;
1389 num_strong_points++;
1392 recorder->num_strong_points = num_strong_points;
1394 recorder->ip_before_points =
1395 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1396 if (!recorder->ip_before_points)
1397 return FT_Err_Out_Of_Memory;
1399 recorder->ip_after_points =
1400 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1401 if (!recorder->ip_after_points)
1402 return FT_Err_Out_Of_Memory;
1404 /* actually, we need `hints->num_edges' for the array sizes; */
1405 /* however, this value isn't known yet */
1406 /* (or rather, it can vary between different pixel sizes) */
1407 recorder->ip_on_point_array =
1408 (FT_UInt*)malloc(axis->num_segments
1409 * num_strong_points * sizeof (FT_UInt));
1410 if (!recorder->ip_on_point_array)
1411 return FT_Err_Out_Of_Memory;
1413 recorder->ip_between_point_array =
1414 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1415 * num_strong_points * sizeof (FT_UInt));
1416 if (!recorder->ip_between_point_array)
1417 return FT_Err_Out_Of_Memory;
1419 return FT_Err_Ok;
1423 static void
1424 TA_rewind_recorder(Recorder* recorder,
1425 FT_Byte* bufp,
1426 FT_UInt size)
1428 recorder->hints_record.buf = bufp + 2;
1429 recorder->hints_record.num_actions = 0;
1430 recorder->hints_record.size = size;
1432 /* We later check with MISSING (which expands to 0xFF bytes) */
1434 memset(recorder->ip_before_points, 0xFF,
1435 recorder->num_strong_points * sizeof (FT_UInt));
1436 memset(recorder->ip_after_points, 0xFF,
1437 recorder->num_strong_points * sizeof (FT_UInt));
1439 memset(recorder->ip_on_point_array, 0xFF,
1440 recorder->num_segments
1441 * recorder->num_strong_points * sizeof (FT_UInt));
1442 memset(recorder->ip_between_point_array, 0xFF,
1443 recorder->num_segments * recorder->num_segments
1444 * recorder->num_strong_points * sizeof (FT_UInt));
1449 static void
1450 TA_free_recorder(Recorder *recorder)
1452 free(recorder->wrap_around_segments);
1454 free(recorder->ip_before_points);
1455 free(recorder->ip_after_points);
1456 free(recorder->ip_on_point_array);
1457 free(recorder->ip_between_point_array);
1461 FT_Error
1462 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1463 FONT* font,
1464 FT_Long idx)
1466 FT_Face face = sfnt->face;
1467 FT_Error error;
1469 FT_Byte* ins_buf;
1470 FT_UInt ins_len;
1471 FT_Byte* bufp;
1472 FT_Byte* p;
1474 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1475 glyf_Data* data = (glyf_Data*)glyf_table->data;
1476 /* `idx' is never negative */
1477 GLYPH* glyph = &data->glyphs[idx];
1479 TA_GlyphHints hints;
1481 FT_UInt num_hints_records;
1482 Hints_Record* hints_records;
1484 Recorder recorder;
1486 FT_Int32 load_flags;
1487 FT_UInt size;
1490 load_flags = font->fallback_script << 30;
1491 if (!font->pre_hinting)
1492 load_flags |= FT_LOAD_NO_RECURSE;
1494 /* computing the segments is resolution independent, */
1495 /* thus the pixel size in this call is arbitrary */
1496 error = FT_Set_Pixel_Sizes(face, 20, 20);
1497 if (error)
1498 return error;
1500 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1501 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx, load_flags);
1502 if (error)
1503 return error;
1505 /* do nothing if we have an empty glyph */
1506 if (!face->glyph->outline.n_contours)
1507 return FT_Err_Ok;
1509 hints = &font->loader->hints;
1511 /* we allocate a buffer which is certainly large enough */
1512 /* to hold all of the created bytecode instructions; */
1513 /* later on it gets reallocated to its real size */
1514 ins_len = hints->num_points * 1000;
1515 ins_buf = (FT_Byte*)malloc(ins_len);
1516 if (!ins_buf)
1517 return FT_Err_Out_Of_Memory;
1519 /* initialize array with an invalid bytecode */
1520 /* so that we can easily find the array length at reallocation time */
1521 memset(ins_buf, INS_A0, ins_len);
1523 num_hints_records = 0;
1524 hints_records = NULL;
1526 /* handle composite glyph */
1527 if (font->loader->gloader->base.num_subglyphs)
1529 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1530 if (!bufp)
1532 error = FT_Err_Out_Of_Memory;
1533 goto Err;
1536 goto Done1;
1539 /* only scale the glyph if the dummy hinter has been used */
1540 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1542 bufp = TA_sfnt_build_glyph_scaler(sfnt, ins_buf);
1543 if (!bufp)
1545 error = FT_Err_Out_Of_Memory;
1546 goto Err;
1549 goto Done1;
1552 error = TA_init_recorder(&recorder, face->glyph->outline.n_contours,
1553 font, hints);
1554 if (error)
1555 goto Err;
1557 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, ins_buf);
1558 if (!bufp)
1560 error = FT_Err_Out_Of_Memory;
1561 goto Err;
1564 /* now we loop over a large range of pixel sizes */
1565 /* to find hints records which get pushed onto the bytecode stack */
1567 #ifdef DEBUGGING
1568 printf("glyph %ld\n", idx);
1569 #endif
1571 /* we temporarily use `ins_buf' to record the current glyph hints, */
1572 /* leaving two bytes at the beginning so that the number of actions */
1573 /* can be inserted later on */
1574 ta_loader_register_hints_recorder(font->loader,
1575 TA_hints_recorder,
1576 (void *)&recorder);
1578 for (size = font->hinting_range_min;
1579 size <= font->hinting_range_max;
1580 size++)
1582 TA_rewind_recorder(&recorder, bufp, size);
1584 error = FT_Set_Pixel_Sizes(face, size, size);
1585 if (error)
1586 goto Err;
1588 /* calling `ta_loader_load_glyph' uses the */
1589 /* `TA_hints_recorder' function as a callback, */
1590 /* modifying `hints_record' */
1591 error = ta_loader_load_glyph(font->loader, face, idx, load_flags);
1592 if (error)
1593 goto Err;
1595 /* append the point hints data collected in `TA_hints_recorder' */
1596 TA_build_point_hints(&recorder, hints);
1598 /* store the number of actions in `ins_buf' */
1599 *bufp = HIGH(recorder.hints_record.num_actions);
1600 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
1602 if (TA_hints_record_is_different(hints_records,
1603 num_hints_records,
1604 bufp, recorder.hints_record.buf))
1606 #ifdef DEBUGGING
1608 printf(" %d:\n", size);
1609 for (p = bufp; p < recorder.hints_record.buf; p += 2)
1610 printf(" %2d", *p * 256 + *(p + 1));
1611 printf("\n");
1613 #endif
1615 error = TA_add_hints_record(&hints_records,
1616 &num_hints_records,
1617 bufp, recorder.hints_record);
1618 if (error)
1619 goto Err;
1623 if (num_hints_records == 1 && !hints_records[0].num_actions)
1625 /* since we only have a single empty record we just scale the glyph, */
1626 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1627 bufp = TA_sfnt_build_glyph_scaler(sfnt, ins_buf);
1628 if (!bufp)
1630 error = FT_Err_Out_Of_Memory;
1631 goto Err;
1634 /* clear the rest of the temporarily used part of `ins_buf' */
1635 p = bufp;
1636 while (*p != INS_A0)
1637 *(p++) = INS_A0;
1639 goto Done;
1642 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1643 /* is shorter than the previously stored data, */
1644 /* so clear the rest of the temporarily used part of `ins_buf' */
1645 /* before appending the hints records */
1646 p = bufp;
1647 while (*p != INS_A0)
1648 *(p++) = INS_A0;
1650 bufp = TA_sfnt_emit_hints_records(sfnt,
1651 hints_records, num_hints_records,
1652 bufp);
1654 Done:
1655 TA_free_hints_records(hints_records, num_hints_records);
1656 TA_free_recorder(&recorder);
1658 /* we are done, so reallocate the instruction array to its real size */
1659 if (*bufp == INS_A0)
1661 /* search backwards */
1662 while (*bufp == INS_A0)
1663 bufp--;
1664 bufp++;
1666 else
1668 /* search forwards */
1669 while (*bufp != INS_A0)
1670 bufp++;
1673 Done1:
1674 ins_len = bufp - ins_buf;
1676 if (ins_len > sfnt->max_instructions)
1677 sfnt->max_instructions = ins_len;
1679 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
1680 glyph->ins_len = ins_len;
1682 return FT_Err_Ok;
1684 Err:
1685 TA_free_hints_records(hints_records, num_hints_records);
1686 TA_free_recorder(&recorder);
1687 free(ins_buf);
1689 return error;
1693 /* end of tabytecode.c */