Typo.
[ttfautohint.git] / src / tabytecode.c
blobfdc9ed199e60e5480f46772e7c7569e29da2ccf6
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"
17 #include "tabytecode.h"
20 #undef MISSING
21 #define MISSING (FT_UInt)~0
23 /* a simple macro to emit bytecode instructions */
24 #define BCI(code) *(bufp++) = (code)
26 /* we increase the stack depth by this amount */
27 #define ADDITIONAL_STACK_ELEMENTS 20
30 /* #define DEBUGGING */
33 #ifdef TA_DEBUG
34 int _ta_debug = 1;
35 int _ta_debug_disable_horz_hints;
36 int _ta_debug_disable_vert_hints;
37 int _ta_debug_disable_blue_hints;
38 void* _ta_debug_hints;
39 #endif
42 typedef struct Hints_Record_ {
43 FT_UInt size;
44 FT_UInt num_actions;
45 FT_Byte* buf;
46 FT_UInt buf_len;
47 } Hints_Record;
49 typedef struct Recorder_ {
50 FONT* font;
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 store the segments in the storage area; */
68 /* each segment record consists of the first and last point */
70 static FT_Byte*
71 TA_sfnt_build_glyph_segments(SFNT* sfnt,
72 Recorder* recorder,
73 FT_Byte* bufp)
75 FONT* font = recorder->font;
76 TA_GlyphHints hints = &font->loader->hints;
77 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
78 TA_Point points = hints->points;
79 TA_Segment segments = axis->segments;
80 TA_Segment seg;
81 TA_Segment seg_limit;
83 FT_Outline outline = font->loader->gloader->base.outline;
85 FT_UInt* args;
86 FT_UInt* arg;
87 FT_UInt num_args;
88 FT_UInt nargs;
89 FT_UInt num_segments;
91 FT_UInt* wrap_around_segment;
92 FT_UInt num_wrap_around_segments;
94 FT_Bool need_words = 0;
96 FT_Int n;
97 FT_UInt i, j;
98 FT_UInt num_storage;
99 FT_UInt num_stack_elements;
100 FT_UInt num_twilight_points;
103 seg_limit = segments + axis->num_segments;
104 num_segments = axis->num_segments;
106 /* some segments can `wrap around' */
107 /* a contour's start point like 24-25-26-0-1-2 */
108 /* (there can be at most one such segment per contour); */
109 /* we thus append additional records to split them into 24-26 and 0-2 */
110 wrap_around_segment = recorder->wrap_around_segments;
111 for (seg = segments; seg < seg_limit; seg++)
112 if (seg->first > seg->last)
114 /* the stored data is used later for edge linking */
115 *(wrap_around_segment++) = seg - segments;
118 num_wrap_around_segments = wrap_around_segment
119 - recorder->wrap_around_segments;
120 num_segments += num_wrap_around_segments;
122 /* wrap-around segments are pushed with four arguments */
123 num_args = 2 * num_segments + 2 * num_wrap_around_segments + 2;
125 /* collect all arguments temporarily in an array (in reverse order) */
126 /* so that we can easily split into chunks of 255 args */
127 /* as needed by NPUSHB and NPUSHW, respectively */
128 args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt));
129 if (!args)
130 return NULL;
132 arg = args + num_args - 1;
134 if (num_segments > 0xFF)
135 need_words = 1;
137 *(arg--) = bci_create_segments;
138 *(arg--) = num_segments;
140 for (seg = segments; seg < seg_limit; seg++)
142 FT_UInt first = seg->first - points;
143 FT_UInt last = seg->last - points;
146 *(arg--) = first;
147 *(arg--) = last;
149 /* we push the last and first contour point */
150 /* as a third and fourth argument in wrap-around segments */
151 if (first > last)
153 for (n = 0; n < outline.n_contours; n++)
155 FT_UInt end = (FT_UInt)outline.contours[n];
158 if (first <= end)
160 *(arg--) = end;
161 if (end > 0xFF)
162 need_words = 1;
164 if (n == 0)
165 *(arg--) = 0;
166 else
167 *(arg--) = (FT_UInt)outline.contours[n - 1] + 1;
168 break;
173 if (last > 0xFF)
174 need_words = 1;
177 /* emit the second part of wrap-around segments as separate segments */
178 /* so that edges can easily link to them */
179 for (seg = segments; seg < seg_limit; seg++)
181 FT_UInt first = seg->first - points;
182 FT_UInt last = seg->last - points;
185 if (first > last)
187 for (n = 0; n < outline.n_contours; n++)
189 if (first <= (FT_UInt)outline.contours[n])
191 if (n == 0)
192 *(arg--) = 0;
193 else
194 *(arg--) = (FT_UInt)outline.contours[n - 1] + 1;
195 break;
199 *(arg--) = last;
202 /* with most fonts it is very rare */
203 /* that any of the pushed arguments is larger than 0xFF, */
204 /* thus we refrain from further optimizing this case */
206 arg = args;
208 if (need_words)
210 for (i = 0; i < num_args; i += 255)
212 nargs = (num_args - i > 255) ? 255 : num_args - i;
214 BCI(NPUSHW);
215 BCI(nargs);
216 for (j = 0; j < nargs; j++)
218 BCI(HIGH(*arg));
219 BCI(LOW(*arg));
220 arg++;
224 else
226 for (i = 0; i < num_args; i += 255)
228 nargs = (num_args - i > 255) ? 255 : num_args - i;
230 BCI(NPUSHB);
231 BCI(nargs);
232 for (j = 0; j < nargs; j++)
234 BCI(*arg);
235 arg++;
240 BCI(CALL);
242 num_storage = sal_segment_offset + num_segments * 2;
243 if (num_storage > sfnt->max_storage)
244 sfnt->max_storage = num_storage;
246 num_twilight_points = num_segments * 2;
247 if (num_twilight_points > sfnt->max_twilight_points)
248 sfnt->max_twilight_points = num_twilight_points;
250 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
251 if (num_stack_elements > sfnt->max_stack_elements)
252 sfnt->max_stack_elements = num_stack_elements;
254 free(args);
256 return bufp;
260 static FT_Byte*
261 TA_sfnt_build_glyph_scaler(SFNT* sfnt,
262 FT_Byte* bufp)
264 FT_GlyphSlot glyph = sfnt->face->glyph;
265 FT_Vector* points = glyph->outline.points;
266 FT_Int num_contours = glyph->outline.n_contours;
268 FT_UInt* args;
269 FT_UInt* arg;
270 FT_UInt num_args;
271 FT_UInt nargs;
273 FT_Bool need_words = 0;
274 FT_Int p, q;
275 FT_UInt i, j;
276 FT_Int start, end;
277 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;
304 end = glyph->outline.contours[p];
306 for (q = start; q <= end; q++)
308 if (points[q].y < points[min].y)
309 min = q;
310 if (points[q].y > points[max].y)
311 max = q;
314 *(arg--) = min;
315 *(arg--) = max;
317 start = end + 1;
320 if (end > 0xFF)
321 need_words = 1;
323 /* with most fonts it is very rare */
324 /* that any of the pushed arguments is larger than 0xFF, */
325 /* thus we refrain from further optimizing this case */
327 arg = args;
329 if (need_words)
331 for (i = 0; i < num_args; i += 255)
333 nargs = (num_args - i > 255) ? 255 : num_args - i;
335 BCI(NPUSHW);
336 BCI(nargs);
337 for (j = 0; j < nargs; j++)
339 BCI(HIGH(*arg));
340 BCI(LOW(*arg));
341 arg++;
345 else
347 for (i = 0; i < num_args; i += 255)
349 nargs = (num_args - i > 255) ? 255 : num_args - i;
351 BCI(NPUSHB);
352 BCI(nargs);
353 for (j = 0; j < nargs; j++)
355 BCI(*arg);
356 arg++;
361 BCI(CALL);
363 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args;
364 if (num_stack_elements > sfnt->max_stack_elements)
365 sfnt->max_stack_elements = num_stack_elements;
367 free(args);
369 return bufp;
373 static FT_Byte*
374 TA_font_build_subglyph_shifter(FONT* font,
375 FT_Byte* bufp)
377 FT_Face face = font->loader->face;
378 FT_GlyphSlot glyph = face->glyph;
380 TA_GlyphLoader gloader = font->loader->gloader;
382 TA_SubGlyph subglyphs = gloader->base.subglyphs;
383 TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs;
384 TA_SubGlyph subglyph;
386 FT_Int curr_contour = 0;
389 for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++)
391 FT_Error error;
393 FT_UShort flags = subglyph->flags;
394 FT_Pos y_offset = subglyph->arg2;
396 FT_Int num_contours;
399 /* load subglyph to get the number of contours */
400 error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE);
401 if (error)
402 return NULL;
403 num_contours = glyph->outline.n_contours;
405 /* nothing to do if there is a point-to-point alignment */
406 if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES))
407 goto End;
409 /* nothing to do if y offset is zero */
410 if (!y_offset)
411 goto End;
413 /* nothing to do if there are no contours */
414 if (!num_contours)
415 goto End;
417 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
418 /* ensures that composites are resolved into simple glyphs */
420 if (num_contours > 0xFF
421 || curr_contour > 0xFF)
423 BCI(PUSHW_2);
424 BCI(HIGH(curr_contour));
425 BCI(LOW(curr_contour));
426 BCI(HIGH(num_contours));
427 BCI(LOW(num_contours));
429 else
431 BCI(PUSHB_2);
432 BCI(curr_contour);
433 BCI(num_contours);
436 /* there are high chances that this value needs PUSHW, */
437 /* thus we handle it separately */
438 if (y_offset > 0xFF || y_offset < 0)
440 BCI(PUSHW_1);
441 BCI(HIGH(y_offset));
442 BCI(LOW(y_offset));
444 else
446 BCI(PUSHB_1);
447 BCI(y_offset);
450 BCI(PUSHB_1);
451 BCI(bci_shift_subglyph);
452 BCI(CALL);
454 End:
455 curr_contour += num_contours;
458 return bufp;
463 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
464 * data in four arrays (which are simple but waste a lot of memory). The
465 * function below converts them into bytecode.
467 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
468 * together with the edge they correspond to.
470 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
471 * loop over the edge or edge pairs, respectively, and each edge or edge
472 * pair contains an inner loop to emit the correponding points.
475 static void
476 TA_build_point_hints(Recorder* recorder,
477 TA_GlyphHints hints)
479 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
480 TA_Segment segments = axis->segments;
481 TA_Edge edges = axis->edges;
483 TA_Edge edge;
484 TA_Edge before;
485 TA_Edge after;
487 FT_Byte* p = recorder->hints_record.buf;
488 FT_UInt num_edges = axis->num_edges;
489 FT_UInt num_strong_points = recorder->num_strong_points;
491 FT_UInt i;
492 FT_UInt j;
493 FT_UInt k;
495 FT_UInt* ip;
496 FT_UInt* iq;
497 FT_UInt* ir;
498 FT_UInt* ip_limit;
499 FT_UInt* iq_limit;
500 FT_UInt* ir_limit;
503 /* we store everything as 16bit numbers; */
504 /* the function numbers (`ta_ip_before', etc.) */
505 /* reflect the order in the TA_Action enumeration */
507 /* ip_before_points */
509 i = 0;
510 ip = recorder->ip_before_points;
511 ip_limit = ip + num_strong_points;
512 for (; ip < ip_limit; ip++)
514 if (*ip != MISSING)
515 i++;
516 else
517 break;
520 if (i)
522 recorder->hints_record.num_actions++;
524 edge = edges;
526 *(p++) = 0;
527 *(p++) = (FT_Byte)ta_ip_before + ACTION_OFFSET;
528 *(p++) = HIGH(edge->first - segments);
529 *(p++) = LOW(edge->first - segments);
530 *(p++) = HIGH(i);
531 *(p++) = LOW(i);
533 ip = recorder->ip_before_points;
534 ip_limit = ip + i;
535 for (; ip < ip_limit; ip++)
537 *(p++) = HIGH(*ip);
538 *(p++) = LOW(*ip);
542 /* ip_after_points */
544 i = 0;
545 ip = recorder->ip_after_points;
546 ip_limit = ip + num_strong_points;
547 for (; ip < ip_limit; ip++)
549 if (*ip != MISSING)
550 i++;
551 else
552 break;
555 if (i)
557 recorder->hints_record.num_actions++;
559 edge = edges + axis->num_edges - 1;
561 *(p++) = 0;
562 *(p++) = (FT_Byte)ta_ip_after + ACTION_OFFSET;
563 *(p++) = HIGH(edge->first - segments);
564 *(p++) = LOW(edge->first - segments);
565 *(p++) = HIGH(i);
566 *(p++) = LOW(i);
568 ip = recorder->ip_after_points;
569 ip_limit = ip + i;
570 for (; ip < ip_limit; ip++)
572 *(p++) = HIGH(*ip);
573 *(p++) = LOW(*ip);
577 /* ip_on_point_array */
579 i = 0;
580 ip = recorder->ip_on_point_array;
581 ip_limit = ip + num_edges * num_strong_points;
582 for (; ip < ip_limit; ip += num_strong_points)
583 if (*ip != MISSING)
584 i++;
586 if (i)
588 recorder->hints_record.num_actions++;
590 *(p++) = 0;
591 *(p++) = (FT_Byte)ta_ip_on + ACTION_OFFSET;
592 *(p++) = HIGH(i);
593 *(p++) = LOW(i);
595 i = 0;
596 ip = recorder->ip_on_point_array;
597 ip_limit = ip + num_edges * num_strong_points;
598 for (; ip < ip_limit; ip += num_strong_points, i++)
600 if (*ip == MISSING)
601 continue;
603 edge = edges + i;
605 *(p++) = HIGH(edge->first - segments);
606 *(p++) = LOW(edge->first - segments);
608 j = 0;
609 iq = ip;
610 iq_limit = iq + num_strong_points;
611 for (; iq < iq_limit; iq++)
613 if (*iq != MISSING)
614 j++;
615 else
616 break;
619 *(p++) = HIGH(j);
620 *(p++) = LOW(j);
622 iq = ip;
623 iq_limit = iq + j;
624 for (; iq < iq_limit; iq++)
626 *(p++) = HIGH(*iq);
627 *(p++) = LOW(*iq);
632 /* ip_between_point_array */
634 i = 0;
635 ip = recorder->ip_between_point_array;
636 ip_limit = ip + num_edges * num_edges * num_strong_points;
637 for (; ip < ip_limit; ip += num_strong_points)
638 if (*ip != MISSING)
639 i++;
641 if (i)
643 recorder->hints_record.num_actions++;
645 *(p++) = 0;
646 *(p++) = (FT_Byte)ta_ip_between + ACTION_OFFSET;
647 *(p++) = HIGH(i);
648 *(p++) = LOW(i);
650 i = 0;
651 ip = recorder->ip_between_point_array;
652 ip_limit = ip + num_edges * num_edges * num_strong_points;
653 for (;
654 ip < ip_limit;
655 ip += num_edges * num_strong_points, i++)
657 before = edges + i;
659 j = 0;
660 iq = ip;
661 iq_limit = iq + num_edges * num_strong_points;
662 for (; iq < iq_limit; iq += num_strong_points, j++)
664 if (*iq == MISSING)
665 continue;
667 after = edges + j;
669 *(p++) = HIGH(after->first - segments);
670 *(p++) = LOW(after->first - segments);
671 *(p++) = HIGH(before->first - segments);
672 *(p++) = LOW(before->first - segments);
674 k = 0;
675 ir = iq;
676 ir_limit = ir + num_strong_points;
677 for (; ir < ir_limit; ir++)
679 if (*ir != MISSING)
680 k++;
681 else
682 break;
685 *(p++) = HIGH(k);
686 *(p++) = LOW(k);
688 ir = iq;
689 ir_limit = ir + k;
690 for (; ir < ir_limit; ir++)
692 *(p++) = HIGH(*ir);
693 *(p++) = LOW(*ir);
699 recorder->hints_record.buf = p;
703 static FT_Bool
704 TA_hints_record_is_different(Hints_Record* hints_records,
705 FT_UInt num_hints_records,
706 FT_Byte* start,
707 FT_Byte* end)
709 Hints_Record last_hints_record;
712 if (!hints_records)
713 return 1;
715 /* we only need to compare with the last hints record */
716 last_hints_record = hints_records[num_hints_records - 1];
718 if ((FT_UInt)(end - start) != last_hints_record.buf_len)
719 return 1;
721 if (memcmp(start, last_hints_record.buf, last_hints_record.buf_len))
722 return 1;
724 return 0;
728 static FT_Error
729 TA_add_hints_record(Hints_Record** hints_records,
730 FT_UInt* num_hints_records,
731 FT_Byte* start,
732 Hints_Record hints_record)
734 Hints_Record* hints_records_new;
735 FT_UInt buf_len;
736 /* at this point, `hints_record.buf' still points into `ins_buf' */
737 FT_Byte* end = hints_record.buf;
740 buf_len = (FT_UInt)(end - start);
742 /* now fill the structure completely */
743 hints_record.buf_len = buf_len;
744 hints_record.buf = (FT_Byte*)malloc(buf_len);
745 if (!hints_record.buf)
746 return FT_Err_Out_Of_Memory;
748 memcpy(hints_record.buf, start, buf_len);
750 (*num_hints_records)++;
751 hints_records_new =
752 (Hints_Record*)realloc(*hints_records, *num_hints_records
753 * sizeof (Hints_Record));
754 if (!hints_records_new)
756 free(hints_record.buf);
757 (*num_hints_records)--;
758 return FT_Err_Out_Of_Memory;
760 else
761 *hints_records = hints_records_new;
763 (*hints_records)[*num_hints_records - 1] = hints_record;
765 return FT_Err_Ok;
769 static FT_Byte*
770 TA_sfnt_emit_hints_record(SFNT* sfnt,
771 Hints_Record* hints_record,
772 FT_Byte* bufp)
774 FT_Byte* p;
775 FT_Byte* endp;
776 FT_Bool need_words = 0;
778 FT_UInt i, j;
779 FT_UInt num_arguments;
780 FT_UInt num_args;
781 FT_UInt num_stack_elements;
784 /* check whether any argument is larger than 0xFF */
785 endp = hints_record->buf + hints_record->buf_len;
786 for (p = hints_record->buf; p < endp; p += 2)
787 if (*p)
788 need_words = 1;
790 /* with most fonts it is very rare */
791 /* that any of the pushed arguments is larger than 0xFF, */
792 /* thus we refrain from further optimizing this case */
794 num_arguments = hints_record->buf_len / 2;
795 p = endp - 2;
797 if (need_words)
799 for (i = 0; i < num_arguments; i += 255)
801 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
803 BCI(NPUSHW);
804 BCI(num_args);
805 for (j = 0; j < num_args; j++)
807 BCI(*p);
808 BCI(*(p + 1));
809 p -= 2;
813 else
815 /* we only need the lower bytes */
816 p++;
818 for (i = 0; i < num_arguments; i += 255)
820 num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i);
822 BCI(NPUSHB);
823 BCI(num_args);
824 for (j = 0; j < num_args; j++)
826 BCI(*p);
827 p -= 2;
832 num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments;
833 if (num_stack_elements > sfnt->max_stack_elements)
834 sfnt->max_stack_elements = num_stack_elements;
836 return bufp;
840 static FT_Byte*
841 TA_sfnt_emit_hints_records(SFNT* sfnt,
842 Hints_Record* hints_records,
843 FT_UInt num_hints_records,
844 FT_Byte* bufp)
846 FT_UInt i;
847 Hints_Record* hints_record;
850 hints_record = hints_records;
852 for (i = 0; i < num_hints_records - 1; i++)
854 BCI(MPPEM);
855 if (hints_record->size > 0xFF)
857 BCI(PUSHW_1);
858 BCI(HIGH((hints_record + 1)->size));
859 BCI(LOW((hints_record + 1)->size));
861 else
863 BCI(PUSHB_1);
864 BCI((hints_record + 1)->size);
866 BCI(LT);
867 BCI(IF);
868 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
869 BCI(ELSE);
871 hints_record++;
874 bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp);
876 for (i = 0; i < num_hints_records - 1; i++)
877 BCI(EIF);
879 BCI(PUSHB_1);
880 BCI(bci_hint_glyph);
881 BCI(CALL);
883 return bufp;
887 static void
888 TA_free_hints_records(Hints_Record* hints_records,
889 FT_UInt num_hints_records)
891 FT_UInt i;
894 for (i = 0; i < num_hints_records; i++)
895 free(hints_records[i].buf);
897 free(hints_records);
901 static FT_Byte*
902 TA_hints_recorder_handle_segments(FT_Byte* bufp,
903 TA_AxisHints axis,
904 TA_Edge edge,
905 FT_UInt* wraps)
907 TA_Segment segments = axis->segments;
908 TA_Segment seg;
909 FT_UInt seg_idx;
910 FT_UInt num_segs = 0;
911 FT_UInt* wrap;
914 seg_idx = edge->first - segments;
916 /* we store everything as 16bit numbers */
917 *(bufp++) = HIGH(seg_idx);
918 *(bufp++) = LOW(seg_idx);
920 /* wrap-around segments are stored as two segments */
921 if (edge->first->first > edge->first->last)
922 num_segs++;
924 seg = edge->first->edge_next;
925 while (seg != edge->first)
927 num_segs++;
929 if (seg->first > seg->last)
930 num_segs++;
932 seg = seg->edge_next;
935 *(bufp++) = HIGH(num_segs);
936 *(bufp++) = LOW(num_segs);
938 if (edge->first->first > edge->first->last)
940 /* emit second part of wrap-around segment; */
941 /* the bytecode positions such segments after `normal' ones */
942 wrap = wraps;
943 for (;;)
945 if (seg_idx == *wrap)
946 break;
947 wrap++;
950 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
951 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
954 seg = edge->first->edge_next;
955 while (seg != edge->first)
957 seg_idx = seg - segments;
959 *(bufp++) = HIGH(seg_idx);
960 *(bufp++) = LOW(seg_idx);
962 if (seg->first > seg->last)
964 wrap = wraps;
965 for (;;)
967 if (seg_idx == *wrap)
968 break;
969 wrap++;
972 *(bufp++) = HIGH(axis->num_segments + (wrap - wraps));
973 *(bufp++) = LOW(axis->num_segments + (wrap - wraps));
976 seg = seg->edge_next;
979 return bufp;
983 static void
984 TA_hints_recorder(TA_Action action,
985 TA_GlyphHints hints,
986 TA_Dimension dim,
987 void* arg1,
988 TA_Edge arg2,
989 TA_Edge arg3,
990 TA_Edge lower_bound,
991 TA_Edge upper_bound)
993 TA_AxisHints axis = &hints->axis[dim];
994 TA_Edge edges = axis->edges;
995 TA_Segment segments = axis->segments;
996 TA_Point points = hints->points;
998 Recorder* recorder = (Recorder*)hints->user;
999 FONT* font = recorder->font;
1000 FT_UInt* wraps = recorder->wrap_around_segments;
1001 FT_Byte* p = recorder->hints_record.buf;
1003 FT_Byte bound_offset = 0;
1005 FT_UInt* ip;
1006 FT_UInt* limit;
1009 if (dim == TA_DIMENSION_HORZ)
1010 return;
1012 /* we collect point hints for later processing */
1013 switch (action)
1015 case ta_ip_before:
1017 TA_Point point = (TA_Point)arg1;
1020 ip = recorder->ip_before_points;
1021 limit = ip + recorder->num_strong_points;
1022 for (; ip < limit; ip++)
1024 if (*ip == MISSING)
1026 *ip = point - points;
1027 break;
1031 return;
1033 case ta_ip_after:
1035 TA_Point point = (TA_Point)arg1;
1038 ip = recorder->ip_after_points;
1039 limit = ip + recorder->num_strong_points;
1040 for (; ip < limit; ip++)
1042 if (*ip == MISSING)
1044 *ip = point - points;
1045 break;
1049 return;
1051 case ta_ip_on:
1053 TA_Point point = (TA_Point)arg1;
1054 TA_Edge edge = arg2;
1057 ip = recorder->ip_on_point_array
1058 + recorder->num_strong_points
1059 * (edge - edges);
1060 limit = ip + recorder->num_strong_points;
1061 for (; ip < limit; ip++)
1063 if (*ip == MISSING)
1065 *ip = point - points;
1066 break;
1070 return;
1072 case ta_ip_between:
1074 TA_Point point = (TA_Point)arg1;
1075 TA_Edge before = arg2;
1076 TA_Edge after = arg3;
1079 /* note that `recorder->num_segments' has been used for allocation, */
1080 /* but `axis->num_edges' is used for accessing this array */
1081 ip = recorder->ip_between_point_array
1082 + recorder->num_strong_points * axis->num_edges
1083 * (before - edges)
1084 + recorder->num_strong_points
1085 * (after - edges);
1086 limit = ip + recorder->num_strong_points;
1087 for (; ip < limit; ip++)
1089 if (*ip == MISSING)
1091 *ip = point - points;
1092 break;
1096 return;
1098 case ta_bound:
1099 /* we ignore the BOUND action since we signal this information */
1100 /* with the `bound_offset' parameter below */
1101 return;
1103 default:
1104 break;
1107 if (lower_bound)
1108 bound_offset += 1;
1109 if (upper_bound)
1110 bound_offset += 2;
1112 /* this reflects the order in the TA_Action enumeration */
1113 *(p++) = 0;
1114 *(p++) = (FT_Byte)action + bound_offset + ACTION_OFFSET;
1116 switch (action)
1118 case ta_link:
1120 TA_Edge base_edge = (TA_Edge)arg1;
1121 TA_Edge stem_edge = arg2;
1124 *(p++) = 0;
1125 *(p++) = stem_edge->flags & TA_EDGE_SERIF;
1126 *(p++) = 0;
1127 *(p++) = base_edge->flags & TA_EDGE_ROUND;
1128 *(p++) = HIGH(base_edge->first - segments);
1129 *(p++) = LOW(base_edge->first - segments);
1130 *(p++) = HIGH(stem_edge->first - segments);
1131 *(p++) = LOW(stem_edge->first - segments);
1133 p = TA_hints_recorder_handle_segments(p, axis, stem_edge, wraps);
1135 break;
1137 case ta_anchor:
1139 TA_Edge edge = (TA_Edge)arg1;
1140 TA_Edge edge2 = arg2;
1143 *(p++) = 0;
1144 *(p++) = edge2->flags & TA_EDGE_SERIF;
1145 *(p++) = 0;
1146 *(p++) = edge->flags & TA_EDGE_ROUND;
1147 *(p++) = HIGH(edge->first - segments);
1148 *(p++) = LOW(edge->first - segments);
1149 *(p++) = HIGH(edge2->first - segments);
1150 *(p++) = LOW(edge2->first - segments);
1152 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1154 break;
1156 case ta_adjust:
1158 TA_Edge edge = (TA_Edge)arg1;
1159 TA_Edge edge2 = arg2;
1160 TA_Edge edge_minus_one = lower_bound;
1163 *(p++) = 0;
1164 *(p++) = edge2->flags & TA_EDGE_SERIF;
1165 *(p++) = 0;
1166 *(p++) = edge->flags & TA_EDGE_ROUND;
1167 *(p++) = HIGH(edge->first - segments);
1168 *(p++) = LOW(edge->first - segments);
1169 *(p++) = HIGH(edge2->first - segments);
1170 *(p++) = LOW(edge2->first - segments);
1172 if (edge_minus_one)
1174 *(p++) = HIGH(edge_minus_one->first - segments);
1175 *(p++) = LOW(edge_minus_one->first - segments);
1178 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1180 break;
1182 case ta_blue_anchor:
1184 TA_Edge edge = (TA_Edge)arg1;
1185 TA_Edge blue = arg2;
1188 *(p++) = HIGH(blue->first - segments);
1189 *(p++) = LOW(blue->first - segments);
1191 if (edge->best_blue_is_shoot)
1193 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1194 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1196 else
1198 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1199 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1202 *(p++) = HIGH(edge->first - segments);
1203 *(p++) = LOW(edge->first - segments);
1205 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1207 break;
1209 case ta_stem:
1211 TA_Edge edge = (TA_Edge)arg1;
1212 TA_Edge edge2 = arg2;
1213 TA_Edge edge_minus_one = lower_bound;
1216 *(p++) = 0;
1217 *(p++) = edge2->flags & TA_EDGE_SERIF;
1218 *(p++) = 0;
1219 *(p++) = edge->flags & TA_EDGE_ROUND;
1220 *(p++) = HIGH(edge->first - segments);
1221 *(p++) = LOW(edge->first - segments);
1222 *(p++) = HIGH(edge2->first - segments);
1223 *(p++) = LOW(edge2->first - segments);
1225 if (edge_minus_one)
1227 *(p++) = HIGH(edge_minus_one->first - segments);
1228 *(p++) = LOW(edge_minus_one->first - segments);
1231 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1232 p = TA_hints_recorder_handle_segments(p, axis, edge2, wraps);
1234 break;
1236 case ta_blue:
1238 TA_Edge edge = (TA_Edge)arg1;
1241 if (edge->best_blue_is_shoot)
1243 *(p++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1244 *(p++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font) + edge->best_blue_idx);
1246 else
1248 *(p++) = HIGH(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1249 *(p++) = LOW(CVT_BLUE_REFS_OFFSET(font) + edge->best_blue_idx);
1252 *(p++) = HIGH(edge->first - segments);
1253 *(p++) = LOW(edge->first - segments);
1255 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1257 break;
1259 case ta_serif:
1261 TA_Edge serif = (TA_Edge)arg1;
1262 TA_Edge base = serif->serif;
1265 *(p++) = HIGH(serif->first - segments);
1266 *(p++) = LOW(serif->first - segments);
1267 *(p++) = HIGH(base->first - segments);
1268 *(p++) = LOW(base->first - segments);
1270 if (lower_bound)
1272 *(p++) = HIGH(lower_bound->first - segments);
1273 *(p++) = LOW(lower_bound->first - segments);
1275 if (upper_bound)
1277 *(p++) = HIGH(upper_bound->first - segments);
1278 *(p++) = LOW(upper_bound->first - segments);
1281 p = TA_hints_recorder_handle_segments(p, axis, serif, wraps);
1283 break;
1285 case ta_serif_anchor:
1286 case ta_serif_link2:
1288 TA_Edge edge = (TA_Edge)arg1;
1291 *(p++) = HIGH(edge->first - segments);
1292 *(p++) = LOW(edge->first - segments);
1294 if (lower_bound)
1296 *(p++) = HIGH(lower_bound->first - segments);
1297 *(p++) = LOW(lower_bound->first - segments);
1299 if (upper_bound)
1301 *(p++) = HIGH(upper_bound->first - segments);
1302 *(p++) = LOW(upper_bound->first - segments);
1305 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1307 break;
1309 case ta_serif_link1:
1311 TA_Edge edge = (TA_Edge)arg1;
1312 TA_Edge before = arg2;
1313 TA_Edge after = arg3;
1316 *(p++) = HIGH(before->first - segments);
1317 *(p++) = LOW(before->first - segments);
1318 *(p++) = HIGH(edge->first - segments);
1319 *(p++) = LOW(edge->first - segments);
1320 *(p++) = HIGH(after->first - segments);
1321 *(p++) = LOW(after->first - segments);
1323 if (lower_bound)
1325 *(p++) = HIGH(lower_bound->first - segments);
1326 *(p++) = LOW(lower_bound->first - segments);
1328 if (upper_bound)
1330 *(p++) = HIGH(upper_bound->first - segments);
1331 *(p++) = LOW(upper_bound->first - segments);
1334 p = TA_hints_recorder_handle_segments(p, axis, edge, wraps);
1336 break;
1338 default:
1339 /* there are more cases in the enumeration */
1340 /* which are handled with the `bound_offset' parameter */
1341 break;
1344 recorder->hints_record.num_actions++;
1345 recorder->hints_record.buf = p;
1349 static FT_Error
1350 TA_init_recorder(Recorder *recorder,
1351 FT_UInt wrap_around_size,
1352 FONT* font,
1353 TA_GlyphHints hints)
1355 TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT];
1356 TA_Point points = hints->points;
1357 TA_Point point_limit = points + hints->num_points;
1358 TA_Point point;
1360 FT_UInt num_strong_points = 0;
1363 recorder->font = font;
1364 recorder->num_segments = axis->num_segments;
1366 recorder->ip_before_points = NULL;
1367 recorder->ip_after_points = NULL;
1368 recorder->ip_on_point_array = NULL;
1369 recorder->ip_between_point_array = NULL;
1371 /* no need to clean up allocated arrays in case of error; */
1372 /* this is handled later by `TA_free_recorder' */
1374 recorder->wrap_around_segments =
1375 (FT_UInt*)malloc(wrap_around_size * sizeof (FT_UInt));
1376 if (!recorder->wrap_around_segments)
1377 return FT_Err_Out_Of_Memory;
1379 /* get number of strong points */
1380 for (point = points; point < point_limit; point++)
1382 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1383 /* however, this value isn't known yet */
1384 /* (or rather, it can vary between different pixel sizes) */
1385 if (point->flags & TA_FLAG_WEAK_INTERPOLATION)
1386 continue;
1388 num_strong_points++;
1391 recorder->num_strong_points = num_strong_points;
1393 recorder->ip_before_points =
1394 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1395 if (!recorder->ip_before_points)
1396 return FT_Err_Out_Of_Memory;
1398 recorder->ip_after_points =
1399 (FT_UInt*)malloc(num_strong_points * sizeof (FT_UInt));
1400 if (!recorder->ip_after_points)
1401 return FT_Err_Out_Of_Memory;
1403 /* actually, we need `hints->num_edges' for the array sizes; */
1404 /* however, this value isn't known yet */
1405 /* (or rather, it can vary between different pixel sizes) */
1406 recorder->ip_on_point_array =
1407 (FT_UInt*)malloc(axis->num_segments
1408 * num_strong_points * sizeof (FT_UInt));
1409 if (!recorder->ip_on_point_array)
1410 return FT_Err_Out_Of_Memory;
1412 recorder->ip_between_point_array =
1413 (FT_UInt*)malloc(axis->num_segments * axis->num_segments
1414 * num_strong_points * sizeof (FT_UInt));
1415 if (!recorder->ip_between_point_array)
1416 return FT_Err_Out_Of_Memory;
1418 return FT_Err_Ok;
1422 static void
1423 TA_rewind_recorder(Recorder* recorder,
1424 FT_Byte* bufp,
1425 FT_UInt size)
1427 recorder->hints_record.buf = bufp + 2;
1428 recorder->hints_record.num_actions = 0;
1429 recorder->hints_record.size = size;
1431 /* We later check with MISSING (which expands to 0xFF bytes) */
1433 memset(recorder->ip_before_points, 0xFF,
1434 recorder->num_strong_points * sizeof (FT_UInt));
1435 memset(recorder->ip_after_points, 0xFF,
1436 recorder->num_strong_points * sizeof (FT_UInt));
1438 memset(recorder->ip_on_point_array, 0xFF,
1439 recorder->num_segments
1440 * recorder->num_strong_points * sizeof (FT_UInt));
1441 memset(recorder->ip_between_point_array, 0xFF,
1442 recorder->num_segments * recorder->num_segments
1443 * recorder->num_strong_points * sizeof (FT_UInt));
1448 static void
1449 TA_free_recorder(Recorder *recorder)
1451 free(recorder->wrap_around_segments);
1453 free(recorder->ip_before_points);
1454 free(recorder->ip_after_points);
1455 free(recorder->ip_on_point_array);
1456 free(recorder->ip_between_point_array);
1460 static FT_Error
1461 TA_sfnt_build_glyph_instructions(SFNT* sfnt,
1462 FONT* font,
1463 FT_Long idx)
1465 FT_Face face = sfnt->face;
1466 FT_Error error;
1468 FT_Byte* ins_buf;
1469 FT_UInt ins_len;
1470 FT_Byte* bufp;
1471 FT_Byte* p;
1473 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
1474 glyf_Data* data = (glyf_Data*)glyf_table->data;
1475 GLYPH* glyph = &data->glyphs[idx];
1477 TA_GlyphHints hints;
1479 FT_UInt num_hints_records;
1480 Hints_Record* hints_records;
1482 Recorder recorder;
1484 FT_UInt size;
1487 if (idx < 0)
1488 return FT_Err_Invalid_Argument;
1490 /* computing the segments is resolution independent, */
1491 /* thus the pixel size in this call is arbitrary */
1492 error = FT_Set_Pixel_Sizes(face, 20, 20);
1493 if (error)
1494 return error;
1496 ta_loader_register_hints_recorder(font->loader, NULL, NULL);
1497 error = ta_loader_load_glyph(font->loader, face, (FT_UInt)idx,
1498 FT_LOAD_NO_RECURSE
1499 | (font->fallback_script << 30));
1500 if (error)
1501 return error;
1503 /* do nothing if we have an empty glyph */
1504 if (!face->glyph->outline.n_contours)
1505 return FT_Err_Ok;
1507 hints = &font->loader->hints;
1509 /* we allocate a buffer which is certainly large enough */
1510 /* to hold all of the created bytecode instructions; */
1511 /* later on it gets reallocated to its real size */
1512 ins_len = hints->num_points * 1000;
1513 ins_buf = (FT_Byte*)malloc(ins_len);
1514 if (!ins_buf)
1515 return FT_Err_Out_Of_Memory;
1517 /* initialize array with an invalid bytecode */
1518 /* so that we can easily find the array length at reallocation time */
1519 memset(ins_buf, INS_A0, ins_len);
1521 num_hints_records = 0;
1522 hints_records = NULL;
1524 /* handle composite glyph */
1525 if (font->loader->gloader->base.num_subglyphs)
1527 bufp = TA_font_build_subglyph_shifter(font, ins_buf);
1528 if (!bufp)
1530 error = FT_Err_Out_Of_Memory;
1531 goto Err;
1534 goto Done1;
1537 /* only scale the glyph if the dummy hinter has been used */
1538 if (font->loader->metrics->clazz == &ta_dummy_script_class)
1540 bufp = TA_sfnt_build_glyph_scaler(sfnt, ins_buf);
1541 if (!bufp)
1543 error = FT_Err_Out_Of_Memory;
1544 goto Err;
1547 goto Done1;
1550 error = TA_init_recorder(&recorder, face->glyph->outline.n_contours,
1551 font, hints);
1552 if (error)
1553 goto Err;
1555 bufp = TA_sfnt_build_glyph_segments(sfnt, &recorder, ins_buf);
1556 if (!bufp)
1558 error = FT_Err_Out_Of_Memory;
1559 goto Err;
1562 /* now we loop over a large range of pixel sizes */
1563 /* to find hints records which get pushed onto the bytecode stack */
1565 #ifdef DEBUGGING
1566 printf("glyph %ld\n", idx);
1567 #endif
1569 /* we temporarily use `ins_buf' to record the current glyph hints, */
1570 /* leaving two bytes at the beginning so that the number of actions */
1571 /* can be inserted later on */
1572 ta_loader_register_hints_recorder(font->loader,
1573 TA_hints_recorder,
1574 (void *)&recorder);
1576 for (size = font->hinting_range_min;
1577 size <= font->hinting_range_max;
1578 size++)
1580 TA_rewind_recorder(&recorder, bufp, size);
1582 error = FT_Set_Pixel_Sizes(face, size, size);
1583 if (error)
1584 goto Err;
1586 /* calling `ta_loader_load_glyph' uses the */
1587 /* `TA_hints_recorder' function as a callback, */
1588 /* modifying `hints_record' */
1589 error = ta_loader_load_glyph(font->loader, face, idx,
1590 font->fallback_script << 30);
1591 if (error)
1592 goto Err;
1594 /* append the point hints data collected in `TA_hints_recorder' */
1595 TA_build_point_hints(&recorder, hints);
1597 /* store the number of actions in `ins_buf' */
1598 *bufp = HIGH(recorder.hints_record.num_actions);
1599 *(bufp + 1) = LOW(recorder.hints_record.num_actions);
1601 if (TA_hints_record_is_different(hints_records,
1602 num_hints_records,
1603 bufp, recorder.hints_record.buf))
1605 #ifdef DEBUGGING
1607 printf(" %d:\n", size);
1608 for (p = bufp; p < recorder.hints_record.buf; p += 2)
1609 printf(" %2d", *p * 256 + *(p + 1));
1610 printf("\n");
1612 #endif
1614 error = TA_add_hints_record(&hints_records,
1615 &num_hints_records,
1616 bufp, recorder.hints_record);
1617 if (error)
1618 goto Err;
1622 if (num_hints_records == 1 && !hints_records[0].num_actions)
1624 /* since we only have a single empty record we just scale the glyph, */
1625 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1626 bufp = TA_sfnt_build_glyph_scaler(sfnt, ins_buf);
1627 if (!bufp)
1629 error = FT_Err_Out_Of_Memory;
1630 goto Err;
1633 /* clear the rest of the temporarily used part of `ins_buf' */
1634 p = bufp;
1635 while (*p != INS_A0)
1636 *(p++) = INS_A0;
1638 goto Done;
1641 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1642 /* is shorter than the previously stored data, */
1643 /* so clear the rest of the temporarily used part of `ins_buf' */
1644 /* before appending the hints records */
1645 p = bufp;
1646 while (*p != INS_A0)
1647 *(p++) = INS_A0;
1649 bufp = TA_sfnt_emit_hints_records(sfnt,
1650 hints_records, num_hints_records,
1651 bufp);
1653 Done:
1654 TA_free_hints_records(hints_records, num_hints_records);
1655 TA_free_recorder(&recorder);
1657 /* we are done, so reallocate the instruction array to its real size */
1658 if (*bufp == INS_A0)
1660 /* search backwards */
1661 while (*bufp == INS_A0)
1662 bufp--;
1663 bufp++;
1665 else
1667 /* search forwards */
1668 while (*bufp != INS_A0)
1669 bufp++;
1672 Done1:
1673 ins_len = bufp - ins_buf;
1675 if (ins_len > sfnt->max_instructions)
1676 sfnt->max_instructions = ins_len;
1678 glyph->ins_buf = (FT_Byte*)realloc(ins_buf, ins_len);
1679 glyph->ins_len = ins_len;
1681 return FT_Err_Ok;
1683 Err:
1684 TA_free_hints_records(hints_records, num_hints_records);
1685 TA_free_recorder(&recorder);
1686 free(ins_buf);
1688 return error;
1692 FT_Error
1693 TA_sfnt_build_glyf_hints(SFNT* sfnt,
1694 FONT* font)
1696 FT_Face face = sfnt->face;
1697 FT_Long idx;
1698 FT_Error error;
1701 for (idx = 0; idx < face->num_glyphs; idx++)
1703 error = TA_sfnt_build_glyph_instructions(sfnt, font, idx);
1704 if (error)
1705 return error;
1706 if (font->progress)
1707 font->progress(idx, face->num_glyphs,
1708 sfnt - font->sfnts, font->num_sfnts,
1709 font->progress_data);
1712 return FT_Err_Ok;
1715 /* end of tabytecode.c */