3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
6 #include "tabytecode.h"
10 #define MISSING (FT_UInt)~0
12 /* a simple macro to emit bytecode instructions */
13 #define BCI(code) *(bufp++) = (code)
15 /* we increase the stack depth by this amount */
16 #define ADDITIONAL_STACK_ELEMENTS 20
19 /* #define DEBUGGING */
24 int _ta_debug_disable_horz_hints
;
25 int _ta_debug_disable_vert_hints
;
26 int _ta_debug_disable_blue_hints
;
27 void* _ta_debug_hints
;
31 typedef struct Hints_Record_
{
38 typedef struct Recorder_
{
40 Hints_Record hints_record
;
42 /* see explanations in `TA_sfnt_build_glyph_segments' */
43 FT_UInt
* wrap_around_segments
;
45 /* data necessary for strong point interpolation */
46 FT_UInt
* ip_before_points
;
47 FT_UInt
* ip_after_points
;
48 FT_UInt
* ip_on_point_array
;
49 FT_UInt
* ip_between_point_array
;
51 FT_UInt num_strong_points
;
56 /* we store the segments in the storage area; */
57 /* each segment record consists of the first and last point */
60 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
64 FONT
* font
= recorder
->font
;
65 TA_GlyphHints hints
= &font
->loader
->hints
;
66 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
67 TA_Point points
= hints
->points
;
68 TA_Segment segments
= axis
->segments
;
72 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
80 FT_UInt
* wrap_around_segment
;
81 FT_UInt num_wrap_around_segments
;
83 FT_Bool need_words
= 0;
88 FT_UInt num_stack_elements
;
89 FT_UInt num_twilight_points
;
92 seg_limit
= segments
+ axis
->num_segments
;
93 num_segments
= axis
->num_segments
;
95 /* some segments can `wrap around' */
96 /* a contour's start point like 24-25-26-0-1-2 */
97 /* (there can be at most one such segment per contour); */
98 /* we thus append additional records to split them into 24-26 and 0-2 */
99 wrap_around_segment
= recorder
->wrap_around_segments
;
100 for (seg
= segments
; seg
< seg_limit
; seg
++)
101 if (seg
->first
> seg
->last
)
103 /* the stored data is used later for edge linking */
104 *(wrap_around_segment
++) = seg
- segments
;
107 num_wrap_around_segments
= wrap_around_segment
108 - recorder
->wrap_around_segments
;
109 num_segments
+= num_wrap_around_segments
;
111 /* wrap-around segments are pushed with four arguments */
112 num_args
= 2 * num_segments
+ 2 * num_wrap_around_segments
+ 2;
114 /* collect all arguments temporarily in an array (in reverse order) */
115 /* so that we can easily split into chunks of 255 args */
116 /* as needed by NPUSHB and NPUSHW, respectively */
117 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
121 arg
= args
+ num_args
- 1;
123 if (num_segments
> 0xFF)
126 *(arg
--) = bci_create_segments
;
127 *(arg
--) = num_segments
;
129 for (seg
= segments
; seg
< seg_limit
; seg
++)
131 FT_UInt first
= seg
->first
- points
;
132 FT_UInt last
= seg
->last
- points
;
138 /* we push the last and first contour point */
139 /* as a third and fourth argument in wrap-around segments */
142 for (n
= 0; n
< outline
.n_contours
; n
++)
144 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
156 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
166 /* emit the second part of wrap-around segments as separate segments */
167 /* so that edges can easily link to them */
168 for (seg
= segments
; seg
< seg_limit
; seg
++)
170 FT_UInt first
= seg
->first
- points
;
171 FT_UInt last
= seg
->last
- points
;
176 for (n
= 0; n
< outline
.n_contours
; n
++)
178 if (first
<= (FT_UInt
)outline
.contours
[n
])
183 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
191 /* with most fonts it is very rare */
192 /* that any of the pushed arguments is larger than 0xFF, */
193 /* thus we refrain from further optimizing this case */
199 for (i
= 0; i
< num_args
; i
+= 255)
201 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
205 for (j
= 0; j
< nargs
; j
++)
215 for (i
= 0; i
< num_args
; i
+= 255)
217 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
221 for (j
= 0; j
< nargs
; j
++)
231 num_storage
= sal_segment_offset
+ num_segments
* 2;
232 if (num_storage
> sfnt
->max_storage
)
233 sfnt
->max_storage
= num_storage
;
235 num_twilight_points
= num_segments
* 2;
236 if (num_twilight_points
> sfnt
->max_twilight_points
)
237 sfnt
->max_twilight_points
= num_twilight_points
;
239 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
240 if (num_stack_elements
> sfnt
->max_stack_elements
)
241 sfnt
->max_stack_elements
= num_stack_elements
;
250 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
253 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
254 FT_Vector
* points
= glyph
->outline
.points
;
255 FT_Int num_contours
= glyph
->outline
.n_contours
;
262 FT_Bool need_words
= 0;
266 FT_UInt num_stack_elements
;
268 num_args
= 2 * num_contours
+ 2;
270 /* collect all arguments temporarily in an array (in reverse order) */
271 /* so that we can easily split into chunks of 255 args */
272 /* as needed by NPUSHB and NPUSHW, respectively */
273 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
277 arg
= args
+ num_args
- 1;
282 *(arg
--) = bci_scale_glyph
;
283 *(arg
--) = num_contours
;
288 for (p
= 0; p
< num_contours
; p
++)
293 end
= glyph
->outline
.contours
[p
];
295 for (q
= start
; q
<= end
; q
++)
297 if (points
[q
].y
< points
[min
].y
)
299 if (points
[q
].y
> points
[max
].y
)
312 /* with most fonts it is very rare */
313 /* that any of the pushed arguments is larger than 0xFF, */
314 /* thus we refrain from further optimizing this case */
320 for (i
= 0; i
< num_args
; i
+= 255)
322 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
326 for (j
= 0; j
< nargs
; j
++)
336 for (i
= 0; i
< num_args
; i
+= 255)
338 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
342 for (j
= 0; j
< nargs
; j
++)
352 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
353 if (num_stack_elements
> sfnt
->max_stack_elements
)
354 sfnt
->max_stack_elements
= num_stack_elements
;
363 TA_font_build_subglyph_shifter(FONT
* font
,
366 FT_Face face
= font
->loader
->face
;
367 FT_GlyphSlot glyph
= face
->glyph
;
369 TA_GlyphLoader gloader
= font
->loader
->gloader
;
371 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
372 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
373 TA_SubGlyph subglyph
;
375 FT_Int curr_contour
= 0;
378 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
382 FT_UShort flags
= subglyph
->flags
;
383 FT_Pos y_offset
= subglyph
->arg2
;
388 /* load subglyph to get the number of contours */
389 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
392 num_contours
= glyph
->outline
.n_contours
;
394 /* nothing to do if there is a point-to-point alignment */
395 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
398 /* nothing to do if y offset is zero */
402 /* nothing to do if there are no contours */
406 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
407 /* ensures that composites are resolved into simple glyphs */
409 if (num_contours
> 0xFF
410 || curr_contour
> 0xFF)
413 BCI(HIGH(curr_contour
));
414 BCI(LOW(curr_contour
));
415 BCI(HIGH(num_contours
));
416 BCI(LOW(num_contours
));
425 /* there are high chances that this value needs PUSHW, */
426 /* thus we handle it separately */
427 if (y_offset
> 0xFF || y_offset
< 0)
440 BCI(bci_shift_subglyph
);
444 curr_contour
+= num_contours
;
452 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
453 * data in four arrays (which are simple but waste a lot of memory). The
454 * function below converts them into bytecode.
456 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
457 * together with the edge they correspond to.
459 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
460 * loop over the edge or edge pairs, respectively, and each edge or edge
461 * pair contains an inner loop to emit the correponding points.
465 TA_build_point_hints(Recorder
* recorder
,
468 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
469 TA_Segment segments
= axis
->segments
;
470 TA_Edge edges
= axis
->edges
;
476 FT_Byte
* p
= recorder
->hints_record
.buf
;
477 FT_UInt num_edges
= axis
->num_edges
;
478 FT_UInt num_strong_points
= recorder
->num_strong_points
;
492 /* we store everything as 16bit numbers; */
493 /* the function numbers (`ta_ip_before', etc.) */
494 /* reflect the order in the TA_Action enumeration */
496 /* ip_before_points */
499 ip
= recorder
->ip_before_points
;
500 ip_limit
= ip
+ num_strong_points
;
501 for (; ip
< ip_limit
; ip
++)
511 recorder
->hints_record
.num_actions
++;
516 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
517 *(p
++) = HIGH(edge
->first
- segments
);
518 *(p
++) = LOW(edge
->first
- segments
);
522 ip
= recorder
->ip_before_points
;
524 for (; ip
< ip_limit
; ip
++)
531 /* ip_after_points */
534 ip
= recorder
->ip_after_points
;
535 ip_limit
= ip
+ num_strong_points
;
536 for (; ip
< ip_limit
; ip
++)
546 recorder
->hints_record
.num_actions
++;
548 edge
= edges
+ axis
->num_edges
- 1;
551 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
552 *(p
++) = HIGH(edge
->first
- segments
);
553 *(p
++) = LOW(edge
->first
- segments
);
557 ip
= recorder
->ip_after_points
;
559 for (; ip
< ip_limit
; ip
++)
566 /* ip_on_point_array */
569 ip
= recorder
->ip_on_point_array
;
570 ip_limit
= ip
+ num_edges
* num_strong_points
;
571 for (; ip
< ip_limit
; ip
+= num_strong_points
)
577 recorder
->hints_record
.num_actions
++;
580 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
585 ip
= recorder
->ip_on_point_array
;
586 ip_limit
= ip
+ num_edges
* num_strong_points
;
587 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
594 *(p
++) = HIGH(edge
->first
- segments
);
595 *(p
++) = LOW(edge
->first
- segments
);
599 iq_limit
= iq
+ num_strong_points
;
600 for (; iq
< iq_limit
; iq
++)
613 for (; iq
< iq_limit
; iq
++)
621 /* ip_between_point_array */
624 ip
= recorder
->ip_between_point_array
;
625 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
626 for (; ip
< ip_limit
; ip
+= num_strong_points
)
632 recorder
->hints_record
.num_actions
++;
635 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
640 ip
= recorder
->ip_between_point_array
;
641 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
644 ip
+= num_edges
* num_strong_points
, i
++)
650 iq_limit
= iq
+ num_edges
* num_strong_points
;
651 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
658 *(p
++) = HIGH(after
->first
- segments
);
659 *(p
++) = LOW(after
->first
- segments
);
660 *(p
++) = HIGH(before
->first
- segments
);
661 *(p
++) = LOW(before
->first
- segments
);
665 ir_limit
= ir
+ num_strong_points
;
666 for (; ir
< ir_limit
; ir
++)
679 for (; ir
< ir_limit
; ir
++)
688 recorder
->hints_record
.buf
= p
;
693 TA_hints_record_is_different(Hints_Record
* hints_records
,
694 FT_UInt num_hints_records
,
698 Hints_Record last_hints_record
;
704 /* we only need to compare with the last hints record */
705 last_hints_record
= hints_records
[num_hints_records
- 1];
707 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
710 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
718 TA_add_hints_record(Hints_Record
** hints_records
,
719 FT_UInt
* num_hints_records
,
721 Hints_Record hints_record
)
723 Hints_Record
* hints_records_new
;
725 /* at this point, `hints_record.buf' still points into `ins_buf' */
726 FT_Byte
* end
= hints_record
.buf
;
729 buf_len
= (FT_UInt
)(end
- start
);
731 /* now fill the structure completely */
732 hints_record
.buf_len
= buf_len
;
733 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
734 if (!hints_record
.buf
)
735 return FT_Err_Out_Of_Memory
;
737 memcpy(hints_record
.buf
, start
, buf_len
);
739 (*num_hints_records
)++;
741 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
742 * sizeof (Hints_Record
));
743 if (!hints_records_new
)
745 free(hints_record
.buf
);
746 (*num_hints_records
)--;
747 return FT_Err_Out_Of_Memory
;
750 *hints_records
= hints_records_new
;
752 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
759 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
760 Hints_Record
* hints_record
,
765 FT_Bool need_words
= 0;
768 FT_UInt num_arguments
;
770 FT_UInt num_stack_elements
;
773 /* check whether any argument is larger than 0xFF */
774 endp
= hints_record
->buf
+ hints_record
->buf_len
;
775 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
779 /* with most fonts it is very rare */
780 /* that any of the pushed arguments is larger than 0xFF, */
781 /* thus we refrain from further optimizing this case */
783 num_arguments
= hints_record
->buf_len
/ 2;
788 for (i
= 0; i
< num_arguments
; i
+= 255)
790 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
794 for (j
= 0; j
< num_args
; j
++)
804 /* we only need the lower bytes */
807 for (i
= 0; i
< num_arguments
; i
+= 255)
809 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
813 for (j
= 0; j
< num_args
; j
++)
821 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
822 if (num_stack_elements
> sfnt
->max_stack_elements
)
823 sfnt
->max_stack_elements
= num_stack_elements
;
830 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
831 Hints_Record
* hints_records
,
832 FT_UInt num_hints_records
,
836 Hints_Record
* hints_record
;
839 hints_record
= hints_records
;
841 for (i
= 0; i
< num_hints_records
- 1; i
++)
844 if (hints_record
->size
> 0xFF)
847 BCI(HIGH((hints_record
+ 1)->size
));
848 BCI(LOW((hints_record
+ 1)->size
));
853 BCI((hints_record
+ 1)->size
);
857 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
863 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
865 for (i
= 0; i
< num_hints_records
- 1; i
++)
877 TA_free_hints_records(Hints_Record
* hints_records
,
878 FT_UInt num_hints_records
)
883 for (i
= 0; i
< num_hints_records
; i
++)
884 free(hints_records
[i
].buf
);
891 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
896 TA_Segment segments
= axis
->segments
;
899 FT_UInt num_segs
= 0;
903 seg_idx
= edge
->first
- segments
;
905 /* we store everything as 16bit numbers */
906 *(bufp
++) = HIGH(seg_idx
);
907 *(bufp
++) = LOW(seg_idx
);
909 /* wrap-around segments are stored as two segments */
910 if (edge
->first
->first
> edge
->first
->last
)
913 seg
= edge
->first
->edge_next
;
914 while (seg
!= edge
->first
)
918 if (seg
->first
> seg
->last
)
921 seg
= seg
->edge_next
;
924 *(bufp
++) = HIGH(num_segs
);
925 *(bufp
++) = LOW(num_segs
);
927 if (edge
->first
->first
> edge
->first
->last
)
929 /* emit second part of wrap-around segment; */
930 /* the bytecode positions such segments after `normal' ones */
934 if (seg_idx
== *wrap
)
939 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
940 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
943 seg
= edge
->first
->edge_next
;
944 while (seg
!= edge
->first
)
946 seg_idx
= seg
- segments
;
948 *(bufp
++) = HIGH(seg_idx
);
949 *(bufp
++) = LOW(seg_idx
);
951 if (seg
->first
> seg
->last
)
956 if (seg_idx
== *wrap
)
961 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
962 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
965 seg
= seg
->edge_next
;
973 TA_hints_recorder(TA_Action action
,
982 TA_AxisHints axis
= &hints
->axis
[dim
];
983 TA_Edge edges
= axis
->edges
;
984 TA_Segment segments
= axis
->segments
;
985 TA_Point points
= hints
->points
;
987 Recorder
* recorder
= (Recorder
*)hints
->user
;
988 FONT
* font
= recorder
->font
;
989 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
990 FT_Byte
* p
= recorder
->hints_record
.buf
;
992 FT_Byte bound_offset
= 0;
998 if (dim
== TA_DIMENSION_HORZ
)
1001 /* we collect point hints for later processing */
1006 TA_Point point
= (TA_Point
)arg1
;
1009 ip
= recorder
->ip_before_points
;
1010 limit
= ip
+ recorder
->num_strong_points
;
1011 for (; ip
< limit
; ip
++)
1015 *ip
= point
- points
;
1024 TA_Point point
= (TA_Point
)arg1
;
1027 ip
= recorder
->ip_after_points
;
1028 limit
= ip
+ recorder
->num_strong_points
;
1029 for (; ip
< limit
; ip
++)
1033 *ip
= point
- points
;
1042 TA_Point point
= (TA_Point
)arg1
;
1043 TA_Edge edge
= arg2
;
1046 ip
= recorder
->ip_on_point_array
1047 + recorder
->num_strong_points
1049 limit
= ip
+ recorder
->num_strong_points
;
1050 for (; ip
< limit
; ip
++)
1054 *ip
= point
- points
;
1063 TA_Point point
= (TA_Point
)arg1
;
1064 TA_Edge before
= arg2
;
1065 TA_Edge after
= arg3
;
1068 /* note that `recorder->num_segments' has been used for allocation, */
1069 /* but `axis->num_edges' is used for accessing this array */
1070 ip
= recorder
->ip_between_point_array
1071 + recorder
->num_strong_points
* axis
->num_edges
1073 + recorder
->num_strong_points
1075 limit
= ip
+ recorder
->num_strong_points
;
1076 for (; ip
< limit
; ip
++)
1080 *ip
= point
- points
;
1088 /* we ignore the BOUND action since we signal this information */
1089 /* with the `bound_offset' parameter below */
1101 /* this reflects the order in the TA_Action enumeration */
1103 *(p
++) = (FT_Byte
)action
+ bound_offset
+ ACTION_OFFSET
;
1109 TA_Edge base_edge
= (TA_Edge
)arg1
;
1110 TA_Edge stem_edge
= arg2
;
1114 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
1116 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
1117 *(p
++) = HIGH(base_edge
->first
- segments
);
1118 *(p
++) = LOW(base_edge
->first
- segments
);
1119 *(p
++) = HIGH(stem_edge
->first
- segments
);
1120 *(p
++) = LOW(stem_edge
->first
- segments
);
1122 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1128 TA_Edge edge
= (TA_Edge
)arg1
;
1129 TA_Edge edge2
= arg2
;
1133 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1135 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1136 *(p
++) = HIGH(edge
->first
- segments
);
1137 *(p
++) = LOW(edge
->first
- segments
);
1138 *(p
++) = HIGH(edge2
->first
- segments
);
1139 *(p
++) = LOW(edge2
->first
- segments
);
1141 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1147 TA_Edge edge
= (TA_Edge
)arg1
;
1148 TA_Edge edge2
= arg2
;
1149 TA_Edge edge_minus_one
= lower_bound
;
1153 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1155 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1156 *(p
++) = HIGH(edge
->first
- segments
);
1157 *(p
++) = LOW(edge
->first
- segments
);
1158 *(p
++) = HIGH(edge2
->first
- segments
);
1159 *(p
++) = LOW(edge2
->first
- segments
);
1163 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1164 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1167 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1171 case ta_blue_anchor
:
1173 TA_Edge edge
= (TA_Edge
)arg1
;
1174 TA_Edge blue
= arg2
;
1177 *(p
++) = HIGH(blue
->first
- segments
);
1178 *(p
++) = LOW(blue
->first
- segments
);
1180 if (edge
->best_blue_is_shoot
)
1182 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1183 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1187 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1188 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1191 *(p
++) = HIGH(edge
->first
- segments
);
1192 *(p
++) = LOW(edge
->first
- segments
);
1194 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1200 TA_Edge edge
= (TA_Edge
)arg1
;
1201 TA_Edge edge2
= arg2
;
1202 TA_Edge edge_minus_one
= lower_bound
;
1206 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1208 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1209 *(p
++) = HIGH(edge
->first
- segments
);
1210 *(p
++) = LOW(edge
->first
- segments
);
1211 *(p
++) = HIGH(edge2
->first
- segments
);
1212 *(p
++) = LOW(edge2
->first
- segments
);
1216 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1217 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1220 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1221 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1227 TA_Edge edge
= (TA_Edge
)arg1
;
1230 if (edge
->best_blue_is_shoot
)
1232 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1233 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1237 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1238 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1241 *(p
++) = HIGH(edge
->first
- segments
);
1242 *(p
++) = LOW(edge
->first
- segments
);
1244 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1250 TA_Edge serif
= (TA_Edge
)arg1
;
1251 TA_Edge base
= serif
->serif
;
1254 *(p
++) = HIGH(serif
->first
- segments
);
1255 *(p
++) = LOW(serif
->first
- segments
);
1256 *(p
++) = HIGH(base
->first
- segments
);
1257 *(p
++) = LOW(base
->first
- segments
);
1261 *(p
++) = HIGH(lower_bound
->first
- segments
);
1262 *(p
++) = LOW(lower_bound
->first
- segments
);
1266 *(p
++) = HIGH(upper_bound
->first
- segments
);
1267 *(p
++) = LOW(upper_bound
->first
- segments
);
1270 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1274 case ta_serif_anchor
:
1275 case ta_serif_link2
:
1277 TA_Edge edge
= (TA_Edge
)arg1
;
1280 *(p
++) = HIGH(edge
->first
- segments
);
1281 *(p
++) = LOW(edge
->first
- segments
);
1285 *(p
++) = HIGH(lower_bound
->first
- segments
);
1286 *(p
++) = LOW(lower_bound
->first
- segments
);
1290 *(p
++) = HIGH(upper_bound
->first
- segments
);
1291 *(p
++) = LOW(upper_bound
->first
- segments
);
1294 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1298 case ta_serif_link1
:
1300 TA_Edge edge
= (TA_Edge
)arg1
;
1301 TA_Edge before
= arg2
;
1302 TA_Edge after
= arg3
;
1305 *(p
++) = HIGH(before
->first
- segments
);
1306 *(p
++) = LOW(before
->first
- segments
);
1307 *(p
++) = HIGH(edge
->first
- segments
);
1308 *(p
++) = LOW(edge
->first
- segments
);
1309 *(p
++) = HIGH(after
->first
- segments
);
1310 *(p
++) = LOW(after
->first
- segments
);
1314 *(p
++) = HIGH(lower_bound
->first
- segments
);
1315 *(p
++) = LOW(lower_bound
->first
- segments
);
1319 *(p
++) = HIGH(upper_bound
->first
- segments
);
1320 *(p
++) = LOW(upper_bound
->first
- segments
);
1323 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1328 /* there are more cases in the enumeration */
1329 /* which are handled with the `bound_offset' parameter */
1333 recorder
->hints_record
.num_actions
++;
1334 recorder
->hints_record
.buf
= p
;
1339 TA_init_recorder(Recorder
*recorder
,
1340 FT_UInt wrap_around_size
,
1342 TA_GlyphHints hints
)
1344 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1345 TA_Point points
= hints
->points
;
1346 TA_Point point_limit
= points
+ hints
->num_points
;
1349 FT_UInt num_strong_points
= 0;
1352 recorder
->font
= font
;
1353 recorder
->num_segments
= axis
->num_segments
;
1355 recorder
->ip_before_points
= NULL
;
1356 recorder
->ip_after_points
= NULL
;
1357 recorder
->ip_on_point_array
= NULL
;
1358 recorder
->ip_between_point_array
= NULL
;
1360 /* no need to clean up allocated arrays in case of error; */
1361 /* this is handled later by `TA_free_recorder' */
1363 recorder
->wrap_around_segments
=
1364 (FT_UInt
*)malloc(wrap_around_size
* sizeof (FT_UInt
));
1365 if (!recorder
->wrap_around_segments
)
1366 return FT_Err_Out_Of_Memory
;
1368 /* get number of strong points */
1369 for (point
= points
; point
< point_limit
; point
++)
1371 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1372 /* however, this value isn't known yet */
1373 /* (or rather, it can vary between different pixel sizes) */
1374 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1377 num_strong_points
++;
1380 recorder
->num_strong_points
= num_strong_points
;
1382 recorder
->ip_before_points
=
1383 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1384 if (!recorder
->ip_before_points
)
1385 return FT_Err_Out_Of_Memory
;
1387 recorder
->ip_after_points
=
1388 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1389 if (!recorder
->ip_after_points
)
1390 return FT_Err_Out_Of_Memory
;
1392 /* actually, we need `hints->num_edges' for the array sizes; */
1393 /* however, this value isn't known yet */
1394 /* (or rather, it can vary between different pixel sizes) */
1395 recorder
->ip_on_point_array
=
1396 (FT_UInt
*)malloc(axis
->num_segments
1397 * num_strong_points
* sizeof (FT_UInt
));
1398 if (!recorder
->ip_on_point_array
)
1399 return FT_Err_Out_Of_Memory
;
1401 recorder
->ip_between_point_array
=
1402 (FT_UInt
*)malloc(axis
->num_segments
* axis
->num_segments
1403 * num_strong_points
* sizeof (FT_UInt
));
1404 if (!recorder
->ip_between_point_array
)
1405 return FT_Err_Out_Of_Memory
;
1412 TA_rewind_recorder(Recorder
* recorder
,
1416 recorder
->hints_record
.buf
= bufp
+ 2;
1417 recorder
->hints_record
.num_actions
= 0;
1418 recorder
->hints_record
.size
= size
;
1420 /* We later check with MISSING (which expands to 0xFF bytes) */
1422 memset(recorder
->ip_before_points
, 0xFF,
1423 recorder
->num_strong_points
* sizeof (FT_UInt
));
1424 memset(recorder
->ip_after_points
, 0xFF,
1425 recorder
->num_strong_points
* sizeof (FT_UInt
));
1427 memset(recorder
->ip_on_point_array
, 0xFF,
1428 recorder
->num_segments
1429 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1430 memset(recorder
->ip_between_point_array
, 0xFF,
1431 recorder
->num_segments
* recorder
->num_segments
1432 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1438 TA_free_recorder(Recorder
*recorder
)
1440 free(recorder
->wrap_around_segments
);
1442 free(recorder
->ip_before_points
);
1443 free(recorder
->ip_after_points
);
1444 free(recorder
->ip_on_point_array
);
1445 free(recorder
->ip_between_point_array
);
1450 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1454 FT_Face face
= sfnt
->face
;
1462 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1463 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1464 GLYPH
* glyph
= &data
->glyphs
[idx
];
1466 TA_GlyphHints hints
;
1468 FT_UInt num_hints_records
;
1469 Hints_Record
* hints_records
;
1477 return FT_Err_Invalid_Argument
;
1479 /* computing the segments is resolution independent, */
1480 /* thus the pixel size in this call is arbitrary */
1481 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1485 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1486 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
,
1487 FT_LOAD_NO_RECURSE
);
1491 /* do nothing if we have an empty glyph */
1492 if (!face
->glyph
->outline
.n_contours
)
1495 hints
= &font
->loader
->hints
;
1497 /* we allocate a buffer which is certainly large enough */
1498 /* to hold all of the created bytecode instructions; */
1499 /* later on it gets reallocated to its real size */
1500 ins_len
= hints
->num_points
* 1000;
1501 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1503 return FT_Err_Out_Of_Memory
;
1505 /* initialize array with an invalid bytecode */
1506 /* so that we can easily find the array length at reallocation time */
1507 memset(ins_buf
, INS_A0
, ins_len
);
1509 num_hints_records
= 0;
1510 hints_records
= NULL
;
1512 /* handle composite glyph */
1513 if (font
->loader
->gloader
->base
.num_subglyphs
)
1515 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1518 error
= FT_Err_Out_Of_Memory
;
1525 /* only scale the glyph if the dummy hinter has been used */
1526 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
1528 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, ins_buf
);
1531 error
= FT_Err_Out_Of_Memory
;
1538 error
= TA_init_recorder(&recorder
, face
->glyph
->outline
.n_contours
,
1543 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
1546 error
= FT_Err_Out_Of_Memory
;
1550 /* now we loop over a large range of pixel sizes */
1551 /* to find hints records which get pushed onto the bytecode stack */
1554 printf("glyph %ld\n", idx
);
1557 /* we temporarily use `ins_buf' to record the current glyph hints, */
1558 /* leaving two bytes at the beginning so that the number of actions */
1559 /* can be inserted later on */
1560 ta_loader_register_hints_recorder(font
->loader
,
1564 for (size
= font
->hinting_range_min
;
1565 size
<= font
->hinting_range_max
;
1568 TA_rewind_recorder(&recorder
, bufp
, size
);
1570 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1574 /* calling `ta_loader_load_glyph' uses the */
1575 /* `TA_hints_recorder' function as a callback, */
1576 /* modifying `hints_record' */
1577 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, 0);
1581 /* append the point hints data collected in `TA_hints_recorder' */
1582 TA_build_point_hints(&recorder
, hints
);
1584 /* store the number of actions in `ins_buf' */
1585 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
1586 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
1588 if (TA_hints_record_is_different(hints_records
,
1590 bufp
, recorder
.hints_record
.buf
))
1594 printf(" %d:\n", size
);
1595 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
1596 printf(" %2d", *p
* 256 + *(p
+ 1));
1601 error
= TA_add_hints_record(&hints_records
,
1603 bufp
, recorder
.hints_record
);
1609 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
1611 /* since we only have a single empty record we just scale the glyph, */
1612 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1613 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, ins_buf
);
1616 error
= FT_Err_Out_Of_Memory
;
1620 /* clear the rest of the temporarily used part of `ins_buf' */
1622 while (*p
!= INS_A0
)
1628 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1629 /* is shorter than the previously stored data, */
1630 /* so clear the rest of the temporarily used part of `ins_buf' */
1631 /* before appending the hints records */
1633 while (*p
!= INS_A0
)
1636 bufp
= TA_sfnt_emit_hints_records(sfnt
,
1637 hints_records
, num_hints_records
,
1641 TA_free_hints_records(hints_records
, num_hints_records
);
1642 TA_free_recorder(&recorder
);
1644 /* we are done, so reallocate the instruction array to its real size */
1645 if (*bufp
== INS_A0
)
1647 /* search backwards */
1648 while (*bufp
== INS_A0
)
1654 /* search forwards */
1655 while (*bufp
!= INS_A0
)
1660 ins_len
= bufp
- ins_buf
;
1662 if (ins_len
> sfnt
->max_instructions
)
1663 sfnt
->max_instructions
= ins_len
;
1665 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
1666 glyph
->ins_len
= ins_len
;
1671 TA_free_hints_records(hints_records
, num_hints_records
);
1672 TA_free_recorder(&recorder
);
1680 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
1683 FT_Face face
= sfnt
->face
;
1688 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
1690 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
1694 font
->progress(idx
, face
->num_glyphs
,
1695 sfnt
- font
->sfnts
, font
->num_sfnts
,
1696 font
->progress_data
);
1702 /* end of tabytecode.c */