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.
17 #include "tabytecode.h"
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 */
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
;
42 typedef struct Hints_Record_
{
49 typedef struct Recorder_
{
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
;
67 /* we store the segments in the storage area; */
68 /* each segment record consists of the first and last point */
71 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
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
;
83 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
91 FT_UInt
* wrap_around_segment
;
92 FT_UInt num_wrap_around_segments
;
94 FT_Bool need_words
= 0;
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
));
132 arg
= args
+ num_args
- 1;
134 if (num_segments
> 0xFF)
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
;
149 /* we push the last and first contour point */
150 /* as a third and fourth argument in wrap-around segments */
153 for (n
= 0; n
< outline
.n_contours
; n
++)
155 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
167 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 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
;
187 for (n
= 0; n
< outline
.n_contours
; n
++)
189 if (first
<= (FT_UInt
)outline
.contours
[n
])
194 *(arg
--) = (FT_UInt
)outline
.contours
[n
- 1] + 1;
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 */
210 for (i
= 0; i
< num_args
; i
+= 255)
212 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
216 for (j
= 0; j
< nargs
; j
++)
226 for (i
= 0; i
< num_args
; i
+= 255)
228 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
232 for (j
= 0; j
< nargs
; j
++)
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
;
261 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
264 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
265 FT_Vector
* points
= glyph
->outline
.points
;
266 FT_Int num_contours
= glyph
->outline
.n_contours
;
273 FT_Bool need_words
= 0;
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
));
288 arg
= args
+ num_args
- 1;
293 *(arg
--) = bci_scale_glyph
;
294 *(arg
--) = num_contours
;
299 for (p
= 0; p
< num_contours
; p
++)
304 end
= glyph
->outline
.contours
[p
];
306 for (q
= start
; q
<= end
; q
++)
308 if (points
[q
].y
< points
[min
].y
)
310 if (points
[q
].y
> points
[max
].y
)
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 */
331 for (i
= 0; i
< num_args
; i
+= 255)
333 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
337 for (j
= 0; j
< nargs
; j
++)
347 for (i
= 0; i
< num_args
; i
+= 255)
349 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
353 for (j
= 0; j
< nargs
; j
++)
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
;
374 TA_font_build_subglyph_shifter(FONT
* font
,
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
++)
393 FT_UShort flags
= subglyph
->flags
;
394 FT_Pos y_offset
= subglyph
->arg2
;
399 /* load subglyph to get the number of contours */
400 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
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
))
409 /* nothing to do if y offset is zero */
413 /* nothing to do if there are no contours */
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)
424 BCI(HIGH(curr_contour
));
425 BCI(LOW(curr_contour
));
426 BCI(HIGH(num_contours
));
427 BCI(LOW(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)
451 BCI(bci_shift_subglyph
);
455 curr_contour
+= num_contours
;
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.
476 TA_build_point_hints(Recorder
* recorder
,
479 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
480 TA_Segment segments
= axis
->segments
;
481 TA_Edge edges
= axis
->edges
;
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
;
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 */
510 ip
= recorder
->ip_before_points
;
511 ip_limit
= ip
+ num_strong_points
;
512 for (; ip
< ip_limit
; ip
++)
522 recorder
->hints_record
.num_actions
++;
527 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
528 *(p
++) = HIGH(edge
->first
- segments
);
529 *(p
++) = LOW(edge
->first
- segments
);
533 ip
= recorder
->ip_before_points
;
535 for (; ip
< ip_limit
; ip
++)
542 /* ip_after_points */
545 ip
= recorder
->ip_after_points
;
546 ip_limit
= ip
+ num_strong_points
;
547 for (; ip
< ip_limit
; ip
++)
557 recorder
->hints_record
.num_actions
++;
559 edge
= edges
+ axis
->num_edges
- 1;
562 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
563 *(p
++) = HIGH(edge
->first
- segments
);
564 *(p
++) = LOW(edge
->first
- segments
);
568 ip
= recorder
->ip_after_points
;
570 for (; ip
< ip_limit
; ip
++)
577 /* ip_on_point_array */
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
)
588 recorder
->hints_record
.num_actions
++;
591 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
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
++)
605 *(p
++) = HIGH(edge
->first
- segments
);
606 *(p
++) = LOW(edge
->first
- segments
);
610 iq_limit
= iq
+ num_strong_points
;
611 for (; iq
< iq_limit
; iq
++)
624 for (; iq
< iq_limit
; iq
++)
632 /* ip_between_point_array */
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
)
643 recorder
->hints_record
.num_actions
++;
646 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
651 ip
= recorder
->ip_between_point_array
;
652 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
655 ip
+= num_edges
* num_strong_points
, i
++)
661 iq_limit
= iq
+ num_edges
* num_strong_points
;
662 for (; iq
< iq_limit
; iq
+= num_strong_points
, 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
);
676 ir_limit
= ir
+ num_strong_points
;
677 for (; ir
< ir_limit
; ir
++)
690 for (; ir
< ir_limit
; ir
++)
699 recorder
->hints_record
.buf
= p
;
704 TA_hints_record_is_different(Hints_Record
* hints_records
,
705 FT_UInt num_hints_records
,
709 Hints_Record last_hints_record
;
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
)
721 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
729 TA_add_hints_record(Hints_Record
** hints_records
,
730 FT_UInt
* num_hints_records
,
732 Hints_Record hints_record
)
734 Hints_Record
* hints_records_new
;
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
)++;
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
;
761 *hints_records
= hints_records_new
;
763 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
770 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
771 Hints_Record
* hints_record
,
776 FT_Bool need_words
= 0;
779 FT_UInt num_arguments
;
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)
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;
799 for (i
= 0; i
< num_arguments
; i
+= 255)
801 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
805 for (j
= 0; j
< num_args
; j
++)
815 /* we only need the lower bytes */
818 for (i
= 0; i
< num_arguments
; i
+= 255)
820 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
824 for (j
= 0; j
< num_args
; j
++)
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
;
841 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
842 Hints_Record
* hints_records
,
843 FT_UInt num_hints_records
,
847 Hints_Record
* hints_record
;
850 hints_record
= hints_records
;
852 for (i
= 0; i
< num_hints_records
- 1; i
++)
855 if (hints_record
->size
> 0xFF)
858 BCI(HIGH((hints_record
+ 1)->size
));
859 BCI(LOW((hints_record
+ 1)->size
));
864 BCI((hints_record
+ 1)->size
);
868 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
874 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
876 for (i
= 0; i
< num_hints_records
- 1; i
++)
888 TA_free_hints_records(Hints_Record
* hints_records
,
889 FT_UInt num_hints_records
)
894 for (i
= 0; i
< num_hints_records
; i
++)
895 free(hints_records
[i
].buf
);
902 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
907 TA_Segment segments
= axis
->segments
;
910 FT_UInt num_segs
= 0;
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
)
924 seg
= edge
->first
->edge_next
;
925 while (seg
!= edge
->first
)
929 if (seg
->first
> seg
->last
)
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 */
945 if (seg_idx
== *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
)
967 if (seg_idx
== *wrap
)
972 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
973 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
976 seg
= seg
->edge_next
;
984 TA_hints_recorder(TA_Action action
,
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;
1009 if (dim
== TA_DIMENSION_HORZ
)
1012 /* we collect point hints for later processing */
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
++)
1026 *ip
= point
- points
;
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
++)
1044 *ip
= point
- points
;
1053 TA_Point point
= (TA_Point
)arg1
;
1054 TA_Edge edge
= arg2
;
1057 ip
= recorder
->ip_on_point_array
1058 + recorder
->num_strong_points
1060 limit
= ip
+ recorder
->num_strong_points
;
1061 for (; ip
< limit
; ip
++)
1065 *ip
= point
- points
;
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
1084 + recorder
->num_strong_points
1086 limit
= ip
+ recorder
->num_strong_points
;
1087 for (; ip
< limit
; ip
++)
1091 *ip
= point
- points
;
1099 /* we ignore the BOUND action since we signal this information */
1100 /* with the `bound_offset' parameter below */
1112 /* this reflects the order in the TA_Action enumeration */
1114 *(p
++) = (FT_Byte
)action
+ bound_offset
+ ACTION_OFFSET
;
1120 TA_Edge base_edge
= (TA_Edge
)arg1
;
1121 TA_Edge stem_edge
= arg2
;
1125 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
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
);
1139 TA_Edge edge
= (TA_Edge
)arg1
;
1140 TA_Edge edge2
= arg2
;
1144 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
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
);
1158 TA_Edge edge
= (TA_Edge
)arg1
;
1159 TA_Edge edge2
= arg2
;
1160 TA_Edge edge_minus_one
= lower_bound
;
1164 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
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
);
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
);
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
);
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
);
1211 TA_Edge edge
= (TA_Edge
)arg1
;
1212 TA_Edge edge2
= arg2
;
1213 TA_Edge edge_minus_one
= lower_bound
;
1217 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
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
);
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
);
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
);
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
);
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
);
1272 *(p
++) = HIGH(lower_bound
->first
- segments
);
1273 *(p
++) = LOW(lower_bound
->first
- segments
);
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
);
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
);
1296 *(p
++) = HIGH(lower_bound
->first
- segments
);
1297 *(p
++) = LOW(lower_bound
->first
- segments
);
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
);
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
);
1325 *(p
++) = HIGH(lower_bound
->first
- segments
);
1326 *(p
++) = LOW(lower_bound
->first
- segments
);
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
);
1339 /* there are more cases in the enumeration */
1340 /* which are handled with the `bound_offset' parameter */
1344 recorder
->hints_record
.num_actions
++;
1345 recorder
->hints_record
.buf
= p
;
1350 TA_init_recorder(Recorder
*recorder
,
1351 FT_UInt wrap_around_size
,
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
;
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
)
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
;
1423 TA_rewind_recorder(Recorder
* recorder
,
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
));
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
);
1461 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1465 FT_Face face
= sfnt
->face
;
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
;
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);
1496 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1497 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
,
1499 | (font
->fallback_script
<< 30));
1503 /* do nothing if we have an empty glyph */
1504 if (!face
->glyph
->outline
.n_contours
)
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
);
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
);
1530 error
= FT_Err_Out_Of_Memory
;
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
);
1543 error
= FT_Err_Out_Of_Memory
;
1550 error
= TA_init_recorder(&recorder
, face
->glyph
->outline
.n_contours
,
1555 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
1558 error
= FT_Err_Out_Of_Memory
;
1562 /* now we loop over a large range of pixel sizes */
1563 /* to find hints records which get pushed onto the bytecode stack */
1566 printf("glyph %ld\n", idx
);
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
,
1576 for (size
= font
->hinting_range_min
;
1577 size
<= font
->hinting_range_max
;
1580 TA_rewind_recorder(&recorder
, bufp
, size
);
1582 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
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);
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
,
1603 bufp
, recorder
.hints_record
.buf
))
1607 printf(" %d:\n", size
);
1608 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
1609 printf(" %2d", *p
* 256 + *(p
+ 1));
1614 error
= TA_add_hints_record(&hints_records
,
1616 bufp
, recorder
.hints_record
);
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
);
1629 error
= FT_Err_Out_Of_Memory
;
1633 /* clear the rest of the temporarily used part of `ins_buf' */
1635 while (*p
!= INS_A0
)
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 */
1646 while (*p
!= INS_A0
)
1649 bufp
= TA_sfnt_emit_hints_records(sfnt
,
1650 hints_records
, num_hints_records
,
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
)
1667 /* search forwards */
1668 while (*bufp
!= INS_A0
)
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
;
1684 TA_free_hints_records(hints_records
, num_hints_records
);
1685 TA_free_recorder(&recorder
);
1693 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
1696 FT_Face face
= sfnt
->face
;
1701 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
1703 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
1707 font
->progress(idx
, face
->num_glyphs
,
1708 sfnt
- font
->sfnts
, font
->num_sfnts
,
1709 font
->progress_data
);
1715 /* end of tabytecode.c */