4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
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
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_
50 typedef struct Recorder_
53 GLYPH
* glyph
; /* the current glyph */
54 Hints_Record hints_record
;
56 /* some segments can `wrap around' */
57 /* a contour's start point like 24-25-26-0-1-2 */
58 /* (there can be at most one such segment per contour); */
59 /* later on we append additional records */
60 /* to split them into 24-26 and 0-2 */
61 FT_UInt
* wrap_around_segments
;
62 FT_UInt num_wrap_around_segments
;
64 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
66 /* data necessary for strong point interpolation */
67 FT_UInt
* ip_before_points
;
68 FT_UInt
* ip_after_points
;
69 FT_UInt
* ip_on_point_array
;
70 FT_UInt
* ip_between_point_array
;
72 FT_UInt num_strong_points
;
77 /* We add a subglyph for each composite glyph. */
78 /* Since subglyphs must contain at least one point, */
79 /* we have to adjust all point indices accordingly. */
80 /* Using the `pointsums' array of the `GLYPH' structure */
81 /* it is straightforward to do that: */
82 /* Assuming that point with index x is in the interval */
83 /* pointsums[n] <= x < pointsums[n + 1], */
84 /* the new point index is x + n. */
87 TA_adjust_point_index(Recorder
* recorder
,
90 FONT
* font
= recorder
->font
;
91 GLYPH
* glyph
= recorder
->glyph
;
95 if (!glyph
->num_components
|| !font
->hint_with_components
)
96 return idx
; /* not a composite glyph */
98 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
99 if (idx
< glyph
->pointsums
[i
])
106 /* we store the segments in the storage area; */
107 /* each segment record consists of the first and last point */
110 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
115 FONT
* font
= recorder
->font
;
116 TA_GlyphHints hints
= &font
->loader
->hints
;
117 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
118 TA_Point points
= hints
->points
;
119 TA_Segment segments
= axis
->segments
;
121 TA_Segment seg_limit
;
123 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
129 FT_UInt num_segments
;
131 FT_Bool need_words
= 0;
136 FT_UInt num_packed_segments
;
138 FT_UInt num_stack_elements
;
139 FT_UInt num_twilight_points
;
142 seg_limit
= segments
+ axis
->num_segments
;
143 num_segments
= axis
->num_segments
;
145 /* to pack the data in the bytecode more tightly, */
146 /* we store up to the first nine segments in nibbles if possible, */
147 /* using delta values */
149 num_packed_segments
= 0;
150 for (seg
= segments
; seg
< seg_limit
; seg
++)
152 FT_UInt first
= seg
->first
- points
;
153 FT_UInt last
= seg
->last
- points
;
156 first
= TA_adjust_point_index(recorder
, first
);
157 last
= TA_adjust_point_index(recorder
, last
);
159 if (first
- base
>= 16)
161 if (first
> last
|| last
- first
>= 16)
163 if (num_packed_segments
== 9)
165 num_packed_segments
++;
169 /* also handle wrap-around segments */
170 num_segments
+= recorder
->num_wrap_around_segments
;
172 /* wrap-around segments are pushed with four arguments; */
173 /* a segment stored in nibbles needs only one byte instead of two */
174 num_args
= num_packed_segments
175 + 2 * (num_segments
- num_packed_segments
)
176 + 2 * recorder
->num_wrap_around_segments
179 /* collect all arguments temporarily in an array (in reverse order) */
180 /* so that we can easily split into chunks of 255 args */
181 /* as needed by NPUSHB and NPUSHW, respectively */
182 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
186 arg
= args
+ num_args
- 1;
188 if (num_segments
> 0xFF)
191 /* the number of packed segments is indicated by the function number */
192 if (recorder
->glyph
->num_components
&& font
->hint_with_components
)
193 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
195 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
196 *(arg
--) = num_segments
;
199 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
201 FT_UInt first
= seg
->first
- points
;
202 FT_UInt last
= seg
->last
- points
;
207 first
= TA_adjust_point_index(recorder
, first
);
208 last
= TA_adjust_point_index(recorder
, last
);
210 low_nibble
= first
- base
;
211 high_nibble
= last
- first
;
213 *(arg
--) = 16 * high_nibble
+ low_nibble
;
218 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
220 FT_UInt first
= seg
->first
- points
;
221 FT_UInt last
= seg
->last
- points
;
224 *(arg
--) = TA_adjust_point_index(recorder
, first
);
225 *(arg
--) = TA_adjust_point_index(recorder
, last
);
227 /* we push the last and first contour point */
228 /* as a third and fourth argument in wrap-around segments */
231 for (n
= 0; n
< outline
.n_contours
; n
++)
233 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
238 *(arg
--) = TA_adjust_point_index(recorder
, end
);
243 *(arg
--) = TA_adjust_point_index(recorder
, 0);
245 *(arg
--) = TA_adjust_point_index(recorder
,
246 (FT_UInt
)outline
.contours
[n
- 1] + 1);
256 /* emit the second part of wrap-around segments as separate segments */
257 /* so that edges can easily link to them */
258 for (seg
= segments
; seg
< seg_limit
; seg
++)
260 FT_UInt first
= seg
->first
- points
;
261 FT_UInt last
= seg
->last
- points
;
266 for (n
= 0; n
< outline
.n_contours
; n
++)
268 if (first
<= (FT_UInt
)outline
.contours
[n
])
271 *(arg
--) = TA_adjust_point_index(recorder
, 0);
273 *(arg
--) = TA_adjust_point_index(recorder
,
274 (FT_UInt
)outline
.contours
[n
- 1] + 1);
279 *(arg
--) = TA_adjust_point_index(recorder
, last
);
282 /* with most fonts it is very rare */
283 /* that any of the pushed arguments is larger than 0xFF, */
284 /* thus we refrain from further optimizing this case */
290 for (i
= 0; i
< num_args
; i
+= 255)
292 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
295 if (optimize
&& nargs
<= 8)
296 BCI(PUSHW_1
- 1 + nargs
);
302 for (j
= 0; j
< nargs
; j
++)
312 for (i
= 0; i
< num_args
; i
+= 255)
314 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
316 if (optimize
&& nargs
<= 8)
317 BCI(PUSHB_1
- 1 + nargs
);
323 for (j
= 0; j
< nargs
; j
++)
333 num_storage
= sal_segment_offset
+ num_segments
* 2;
334 if (num_storage
> sfnt
->max_storage
)
335 sfnt
->max_storage
= num_storage
;
337 num_twilight_points
= num_segments
* 2;
338 if (num_twilight_points
> sfnt
->max_twilight_points
)
339 sfnt
->max_twilight_points
= num_twilight_points
;
341 /* both this function and `TA_emit_hints_record' */
342 /* push data onto the stack */
343 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
344 + recorder
->num_stack_elements
+ num_args
;
345 if (num_stack_elements
> sfnt
->max_stack_elements
)
346 sfnt
->max_stack_elements
= num_stack_elements
;
355 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
359 FONT
* font
= recorder
->font
;
360 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
361 FT_Vector
* points
= glyph
->outline
.points
;
362 FT_Int num_contours
= glyph
->outline
.n_contours
;
369 FT_Bool need_words
= 0;
373 FT_UInt num_stack_elements
;
376 num_args
= 2 * num_contours
+ 2;
378 /* collect all arguments temporarily in an array (in reverse order) */
379 /* so that we can easily split into chunks of 255 args */
380 /* as needed by NPUSHB and NPUSHW, respectively */
381 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
385 arg
= args
+ num_args
- 1;
390 if (recorder
->glyph
->num_components
&& font
->hint_with_components
)
391 *(arg
--) = bci_scale_composite_glyph
;
393 *(arg
--) = bci_scale_glyph
;
394 *(arg
--) = num_contours
;
399 for (p
= 0; p
< num_contours
; p
++)
405 end
= glyph
->outline
.contours
[p
];
407 for (q
= start
; q
<= end
; q
++)
409 if (points
[q
].y
< points
[min
].y
)
411 if (points
[q
].y
> points
[max
].y
)
417 *(arg
--) = TA_adjust_point_index(recorder
, max
);
418 *(arg
--) = TA_adjust_point_index(recorder
, min
);
422 *(arg
--) = TA_adjust_point_index(recorder
, min
);
423 *(arg
--) = TA_adjust_point_index(recorder
, max
);
432 /* with most fonts it is very rare */
433 /* that any of the pushed arguments is larger than 0xFF, */
434 /* thus we refrain from further optimizing this case */
440 for (i
= 0; i
< num_args
; i
+= 255)
442 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
445 BCI(PUSHW_1
- 1 + nargs
);
451 for (j
= 0; j
< nargs
; j
++)
461 for (i
= 0; i
< num_args
; i
+= 255)
463 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
466 BCI(PUSHB_1
- 1 + nargs
);
472 for (j
= 0; j
< nargs
; j
++)
482 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
483 if (num_stack_elements
> sfnt
->max_stack_elements
)
484 sfnt
->max_stack_elements
= num_stack_elements
;
493 TA_font_build_subglyph_shifter(FONT
* font
,
496 FT_Face face
= font
->loader
->face
;
497 FT_GlyphSlot glyph
= face
->glyph
;
499 TA_GlyphLoader gloader
= font
->loader
->gloader
;
501 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
502 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
503 TA_SubGlyph subglyph
;
505 FT_Int curr_contour
= 0;
508 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
512 FT_UShort flags
= subglyph
->flags
;
513 FT_Pos y_offset
= subglyph
->arg2
;
518 /* load subglyph to get the number of contours */
519 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
522 num_contours
= glyph
->outline
.n_contours
;
524 /* nothing to do if there is a point-to-point alignment */
525 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
528 /* nothing to do if y offset is zero */
532 /* nothing to do if there are no contours */
536 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
537 /* ensures that composite subglyphs are represented as simple glyphs */
539 if (num_contours
> 0xFF
540 || curr_contour
> 0xFF)
543 BCI(HIGH(curr_contour
));
544 BCI(LOW(curr_contour
));
545 BCI(HIGH(num_contours
));
546 BCI(LOW(num_contours
));
555 /* there are high chances that this value needs PUSHW, */
556 /* thus we handle it separately */
557 if (y_offset
> 0xFF || y_offset
< 0)
570 BCI(bci_shift_subglyph
);
574 curr_contour
+= num_contours
;
582 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
583 * data in four arrays (which are simple but waste a lot of memory). The
584 * function below converts them into bytecode.
586 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
587 * together with the edge they correspond to.
589 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
590 * loop over the edge or edge pairs, respectively, and each edge or edge
591 * pair contains an inner loop to emit the correponding points.
595 TA_build_point_hints(Recorder
* recorder
,
598 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
599 TA_Segment segments
= axis
->segments
;
600 TA_Edge edges
= axis
->edges
;
606 FT_Byte
* p
= recorder
->hints_record
.buf
;
607 FT_UInt num_edges
= axis
->num_edges
;
608 FT_UInt num_strong_points
= recorder
->num_strong_points
;
622 /* we store everything as 16bit numbers; */
623 /* the function numbers (`ta_ip_before', etc.) */
624 /* reflect the order in the TA_Action enumeration */
626 /* ip_before_points */
629 ip
= recorder
->ip_before_points
;
630 ip_limit
= ip
+ num_strong_points
;
631 for (; ip
< ip_limit
; ip
++)
641 recorder
->hints_record
.num_actions
++;
646 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
647 *(p
++) = HIGH(edge
->first
- segments
);
648 *(p
++) = LOW(edge
->first
- segments
);
652 ip
= recorder
->ip_before_points
;
654 for (; ip
< ip_limit
; ip
++)
656 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
659 *(p
++) = HIGH(point
);
664 /* ip_after_points */
667 ip
= recorder
->ip_after_points
;
668 ip_limit
= ip
+ num_strong_points
;
669 for (; ip
< ip_limit
; ip
++)
679 recorder
->hints_record
.num_actions
++;
681 edge
= edges
+ axis
->num_edges
- 1;
684 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
685 *(p
++) = HIGH(edge
->first
- segments
);
686 *(p
++) = LOW(edge
->first
- segments
);
690 ip
= recorder
->ip_after_points
;
692 for (; ip
< ip_limit
; ip
++)
694 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
697 *(p
++) = HIGH(point
);
702 /* ip_on_point_array */
705 ip
= recorder
->ip_on_point_array
;
706 ip_limit
= ip
+ num_edges
* num_strong_points
;
707 for (; ip
< ip_limit
; ip
+= num_strong_points
)
713 recorder
->hints_record
.num_actions
++;
716 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
721 ip
= recorder
->ip_on_point_array
;
722 ip_limit
= ip
+ num_edges
* num_strong_points
;
723 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
730 *(p
++) = HIGH(edge
->first
- segments
);
731 *(p
++) = LOW(edge
->first
- segments
);
735 iq_limit
= iq
+ num_strong_points
;
736 for (; iq
< iq_limit
; iq
++)
749 for (; iq
< iq_limit
; iq
++)
751 FT_UInt point
= TA_adjust_point_index(recorder
, *iq
);
754 *(p
++) = HIGH(point
);
760 /* ip_between_point_array */
763 ip
= recorder
->ip_between_point_array
;
764 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
765 for (; ip
< ip_limit
; ip
+= num_strong_points
)
771 recorder
->hints_record
.num_actions
++;
774 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
779 ip
= recorder
->ip_between_point_array
;
780 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
783 ip
+= num_edges
* num_strong_points
, i
++)
789 iq_limit
= iq
+ num_edges
* num_strong_points
;
790 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
797 *(p
++) = HIGH(after
->first
- segments
);
798 *(p
++) = LOW(after
->first
- segments
);
799 *(p
++) = HIGH(before
->first
- segments
);
800 *(p
++) = LOW(before
->first
- segments
);
804 ir_limit
= ir
+ num_strong_points
;
805 for (; ir
< ir_limit
; ir
++)
818 for (; ir
< ir_limit
; ir
++)
820 FT_UInt point
= TA_adjust_point_index(recorder
, *ir
);
823 *(p
++) = HIGH(point
);
830 recorder
->hints_record
.buf
= p
;
835 TA_hints_record_is_different(Hints_Record
* hints_records
,
836 FT_UInt num_hints_records
,
840 Hints_Record last_hints_record
;
846 /* we only need to compare with the last hints record */
847 last_hints_record
= hints_records
[num_hints_records
- 1];
849 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
852 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
860 TA_add_hints_record(Hints_Record
** hints_records
,
861 FT_UInt
* num_hints_records
,
863 Hints_Record hints_record
)
865 Hints_Record
* hints_records_new
;
867 /* at this point, `hints_record.buf' still points into `ins_buf' */
868 FT_Byte
* end
= hints_record
.buf
;
871 buf_len
= (FT_UInt
)(end
- start
);
873 /* now fill the structure completely */
874 hints_record
.buf_len
= buf_len
;
875 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
876 if (!hints_record
.buf
)
877 return FT_Err_Out_Of_Memory
;
879 memcpy(hints_record
.buf
, start
, buf_len
);
881 (*num_hints_records
)++;
883 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
884 * sizeof (Hints_Record
));
885 if (!hints_records_new
)
887 free(hints_record
.buf
);
888 (*num_hints_records
)--;
889 return FT_Err_Out_Of_Memory
;
892 *hints_records
= hints_records_new
;
894 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
901 TA_emit_hints_record(Recorder
* recorder
,
902 Hints_Record
* hints_record
,
908 FT_Bool need_words
= 0;
911 FT_UInt num_arguments
;
915 /* check whether any argument is larger than 0xFF */
916 endp
= hints_record
->buf
+ hints_record
->buf_len
;
917 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
921 /* with most fonts it is very rare */
922 /* that any of the pushed arguments is larger than 0xFF, */
923 /* thus we refrain from further optimizing this case */
925 num_arguments
= hints_record
->buf_len
/ 2;
930 for (i
= 0; i
< num_arguments
; i
+= 255)
932 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
934 if (optimize
&& num_args
<= 8)
935 BCI(PUSHW_1
- 1 + num_args
);
941 for (j
= 0; j
< num_args
; j
++)
951 /* we only need the lower bytes */
954 for (i
= 0; i
< num_arguments
; i
+= 255)
956 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
958 if (optimize
&& num_args
<= 8)
959 BCI(PUSHB_1
- 1 + num_args
);
965 for (j
= 0; j
< num_args
; j
++)
973 /* collect stack depth data */
974 if (num_arguments
> recorder
->num_stack_elements
)
975 recorder
->num_stack_elements
= num_arguments
;
982 TA_emit_hints_records(Recorder
* recorder
,
983 Hints_Record
* hints_records
,
984 FT_UInt num_hints_records
,
989 Hints_Record
* hints_record
;
992 hints_record
= hints_records
;
994 for (i
= 0; i
< num_hints_records
- 1; i
++)
997 if (hints_record
->size
> 0xFF)
1000 BCI(HIGH((hints_record
+ 1)->size
));
1001 BCI(LOW((hints_record
+ 1)->size
));
1006 BCI((hints_record
+ 1)->size
);
1010 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1016 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1018 for (i
= 0; i
< num_hints_records
- 1; i
++)
1026 TA_free_hints_records(Hints_Record
* hints_records
,
1027 FT_UInt num_hints_records
)
1032 for (i
= 0; i
< num_hints_records
; i
++)
1033 free(hints_records
[i
].buf
);
1035 free(hints_records
);
1040 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1045 TA_Segment segments
= axis
->segments
;
1048 FT_UInt num_segs
= 0;
1052 seg_idx
= edge
->first
- segments
;
1054 /* we store everything as 16bit numbers */
1055 *(bufp
++) = HIGH(seg_idx
);
1056 *(bufp
++) = LOW(seg_idx
);
1058 /* wrap-around segments are stored as two segments */
1059 if (edge
->first
->first
> edge
->first
->last
)
1062 seg
= edge
->first
->edge_next
;
1063 while (seg
!= edge
->first
)
1067 if (seg
->first
> seg
->last
)
1070 seg
= seg
->edge_next
;
1073 *(bufp
++) = HIGH(num_segs
);
1074 *(bufp
++) = LOW(num_segs
);
1076 if (edge
->first
->first
> edge
->first
->last
)
1078 /* emit second part of wrap-around segment; */
1079 /* the bytecode positions such segments after `normal' ones */
1083 if (seg_idx
== *wrap
)
1088 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1089 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1092 seg
= edge
->first
->edge_next
;
1093 while (seg
!= edge
->first
)
1095 seg_idx
= seg
- segments
;
1097 *(bufp
++) = HIGH(seg_idx
);
1098 *(bufp
++) = LOW(seg_idx
);
1100 if (seg
->first
> seg
->last
)
1105 if (seg_idx
== *wrap
)
1110 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1111 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1114 seg
= seg
->edge_next
;
1122 TA_hints_recorder(TA_Action action
,
1123 TA_GlyphHints hints
,
1128 TA_Edge lower_bound
,
1129 TA_Edge upper_bound
)
1131 TA_AxisHints axis
= &hints
->axis
[dim
];
1132 TA_Edge edges
= axis
->edges
;
1133 TA_Segment segments
= axis
->segments
;
1134 TA_Point points
= hints
->points
;
1136 Recorder
* recorder
= (Recorder
*)hints
->user
;
1137 FONT
* font
= recorder
->font
;
1138 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
1139 FT_Byte
* p
= recorder
->hints_record
.buf
;
1145 if (dim
== TA_DIMENSION_HORZ
)
1148 /* we collect point hints for later processing */
1153 TA_Point point
= (TA_Point
)arg1
;
1156 ip
= recorder
->ip_before_points
;
1157 limit
= ip
+ recorder
->num_strong_points
;
1158 for (; ip
< limit
; ip
++)
1162 *ip
= point
- points
;
1171 TA_Point point
= (TA_Point
)arg1
;
1174 ip
= recorder
->ip_after_points
;
1175 limit
= ip
+ recorder
->num_strong_points
;
1176 for (; ip
< limit
; ip
++)
1180 *ip
= point
- points
;
1189 TA_Point point
= (TA_Point
)arg1
;
1190 TA_Edge edge
= arg2
;
1193 ip
= recorder
->ip_on_point_array
1194 + recorder
->num_strong_points
1196 limit
= ip
+ recorder
->num_strong_points
;
1197 for (; ip
< limit
; ip
++)
1201 *ip
= point
- points
;
1210 TA_Point point
= (TA_Point
)arg1
;
1211 TA_Edge before
= arg2
;
1212 TA_Edge after
= arg3
;
1215 /* note that `recorder->num_segments' has been used for allocation, */
1216 /* but `axis->num_edges' is used for accessing this array */
1217 ip
= recorder
->ip_between_point_array
1218 + recorder
->num_strong_points
* axis
->num_edges
1220 + recorder
->num_strong_points
1222 limit
= ip
+ recorder
->num_strong_points
;
1223 for (; ip
< limit
; ip
++)
1227 *ip
= point
- points
;
1235 /* we ignore the BOUND action since we signal this information */
1236 /* with the proper function number */
1243 /* some enum values correspond to four or eight bytecode functions; */
1244 /* if the value is n, the function numbers are n, ..., n+7, */
1245 /* to be differentiated with flags */
1251 TA_Edge base_edge
= (TA_Edge
)arg1
;
1252 TA_Edge stem_edge
= arg2
;
1256 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1257 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1258 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1260 *(p
++) = HIGH(base_edge
->first
- segments
);
1261 *(p
++) = LOW(base_edge
->first
- segments
);
1262 *(p
++) = HIGH(stem_edge
->first
- segments
);
1263 *(p
++) = LOW(stem_edge
->first
- segments
);
1265 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1271 TA_Edge edge
= (TA_Edge
)arg1
;
1272 TA_Edge edge2
= arg2
;
1276 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1277 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1278 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1280 *(p
++) = HIGH(edge
->first
- segments
);
1281 *(p
++) = LOW(edge
->first
- segments
);
1282 *(p
++) = HIGH(edge2
->first
- segments
);
1283 *(p
++) = LOW(edge2
->first
- segments
);
1285 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1291 TA_Edge edge
= (TA_Edge
)arg1
;
1292 TA_Edge edge2
= arg2
;
1293 TA_Edge edge_minus_one
= lower_bound
;
1297 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1298 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1299 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1300 + 4 * (edge_minus_one
!= NULL
);
1302 *(p
++) = HIGH(edge
->first
- segments
);
1303 *(p
++) = LOW(edge
->first
- segments
);
1304 *(p
++) = HIGH(edge2
->first
- segments
);
1305 *(p
++) = LOW(edge2
->first
- segments
);
1309 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1310 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1313 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1317 case ta_blue_anchor
:
1319 TA_Edge edge
= (TA_Edge
)arg1
;
1320 TA_Edge blue
= arg2
;
1324 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1326 *(p
++) = HIGH(blue
->first
- segments
);
1327 *(p
++) = LOW(blue
->first
- segments
);
1329 if (edge
->best_blue_is_shoot
)
1331 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1332 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1336 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1337 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1340 *(p
++) = HIGH(edge
->first
- segments
);
1341 *(p
++) = LOW(edge
->first
- segments
);
1343 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1349 TA_Edge edge
= (TA_Edge
)arg1
;
1350 TA_Edge edge2
= arg2
;
1351 TA_Edge edge_minus_one
= lower_bound
;
1355 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1356 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1357 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1358 + 4 * (edge_minus_one
!= NULL
);
1360 *(p
++) = HIGH(edge
->first
- segments
);
1361 *(p
++) = LOW(edge
->first
- segments
);
1362 *(p
++) = HIGH(edge2
->first
- segments
);
1363 *(p
++) = LOW(edge2
->first
- segments
);
1367 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1368 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1371 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1372 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1378 TA_Edge edge
= (TA_Edge
)arg1
;
1382 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1384 if (edge
->best_blue_is_shoot
)
1386 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1387 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1391 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1392 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1395 *(p
++) = HIGH(edge
->first
- segments
);
1396 *(p
++) = LOW(edge
->first
- segments
);
1398 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1404 TA_Edge serif
= (TA_Edge
)arg1
;
1405 TA_Edge base
= serif
->serif
;
1409 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1410 + (lower_bound
!= NULL
)
1411 + 2 * (upper_bound
!= NULL
);
1413 *(p
++) = HIGH(serif
->first
- segments
);
1414 *(p
++) = LOW(serif
->first
- segments
);
1415 *(p
++) = HIGH(base
->first
- segments
);
1416 *(p
++) = LOW(base
->first
- segments
);
1420 *(p
++) = HIGH(lower_bound
->first
- segments
);
1421 *(p
++) = LOW(lower_bound
->first
- segments
);
1425 *(p
++) = HIGH(upper_bound
->first
- segments
);
1426 *(p
++) = LOW(upper_bound
->first
- segments
);
1429 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1433 case ta_serif_anchor
:
1434 case ta_serif_link2
:
1436 TA_Edge edge
= (TA_Edge
)arg1
;
1440 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1441 + (lower_bound
!= NULL
)
1442 + 2 * (upper_bound
!= NULL
);
1444 *(p
++) = HIGH(edge
->first
- segments
);
1445 *(p
++) = LOW(edge
->first
- segments
);
1449 *(p
++) = HIGH(lower_bound
->first
- segments
);
1450 *(p
++) = LOW(lower_bound
->first
- segments
);
1454 *(p
++) = HIGH(upper_bound
->first
- segments
);
1455 *(p
++) = LOW(upper_bound
->first
- segments
);
1458 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1462 case ta_serif_link1
:
1464 TA_Edge edge
= (TA_Edge
)arg1
;
1465 TA_Edge before
= arg2
;
1466 TA_Edge after
= arg3
;
1470 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1471 + (lower_bound
!= NULL
)
1472 + 2 * (upper_bound
!= NULL
);
1474 *(p
++) = HIGH(before
->first
- segments
);
1475 *(p
++) = LOW(before
->first
- segments
);
1476 *(p
++) = HIGH(edge
->first
- segments
);
1477 *(p
++) = LOW(edge
->first
- segments
);
1478 *(p
++) = HIGH(after
->first
- segments
);
1479 *(p
++) = LOW(after
->first
- segments
);
1483 *(p
++) = HIGH(lower_bound
->first
- segments
);
1484 *(p
++) = LOW(lower_bound
->first
- segments
);
1488 *(p
++) = HIGH(upper_bound
->first
- segments
);
1489 *(p
++) = LOW(upper_bound
->first
- segments
);
1492 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1497 /* there are more cases in the enumeration */
1498 /* which are handled with flags */
1502 recorder
->hints_record
.num_actions
++;
1503 recorder
->hints_record
.buf
= p
;
1508 TA_init_recorder(Recorder
* recorder
,
1511 TA_GlyphHints hints
)
1513 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1514 TA_Point points
= hints
->points
;
1515 TA_Point point_limit
= points
+ hints
->num_points
;
1518 TA_Segment segments
= axis
->segments
;
1519 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1522 FT_UInt num_strong_points
= 0;
1523 FT_UInt
* wrap_around_segment
;
1525 recorder
->font
= font
;
1526 recorder
->glyph
= glyph
;
1527 recorder
->num_segments
= axis
->num_segments
;
1529 recorder
->ip_before_points
= NULL
;
1530 recorder
->ip_after_points
= NULL
;
1531 recorder
->ip_on_point_array
= NULL
;
1532 recorder
->ip_between_point_array
= NULL
;
1534 recorder
->num_stack_elements
= 0;
1536 /* no need to clean up allocated arrays in case of error; */
1537 /* this is handled later by `TA_free_recorder' */
1539 recorder
->num_wrap_around_segments
= 0;
1540 for (seg
= segments
; seg
< seg_limit
; seg
++)
1541 if (seg
->first
> seg
->last
)
1542 recorder
->num_wrap_around_segments
++;
1544 recorder
->wrap_around_segments
=
1545 (FT_UInt
*)malloc(recorder
->num_wrap_around_segments
* sizeof (FT_UInt
));
1546 if (!recorder
->wrap_around_segments
)
1547 return FT_Err_Out_Of_Memory
;
1549 wrap_around_segment
= recorder
->wrap_around_segments
;
1550 for (seg
= segments
; seg
< seg_limit
; seg
++)
1551 if (seg
->first
> seg
->last
)
1552 *(wrap_around_segment
++) = seg
- segments
;
1554 /* get number of strong points */
1555 for (point
= points
; point
< point_limit
; point
++)
1557 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1558 /* however, this value isn't known yet */
1559 /* (or rather, it can vary between different pixel sizes) */
1560 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1563 num_strong_points
++;
1566 recorder
->num_strong_points
= num_strong_points
;
1568 recorder
->ip_before_points
=
1569 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1570 if (!recorder
->ip_before_points
)
1571 return FT_Err_Out_Of_Memory
;
1573 recorder
->ip_after_points
=
1574 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1575 if (!recorder
->ip_after_points
)
1576 return FT_Err_Out_Of_Memory
;
1578 /* actually, we need `hints->num_edges' for the array sizes; */
1579 /* however, this value isn't known yet */
1580 /* (or rather, it can vary between different pixel sizes) */
1581 recorder
->ip_on_point_array
=
1582 (FT_UInt
*)malloc(axis
->num_segments
1583 * num_strong_points
* sizeof (FT_UInt
));
1584 if (!recorder
->ip_on_point_array
)
1585 return FT_Err_Out_Of_Memory
;
1587 recorder
->ip_between_point_array
=
1588 (FT_UInt
*)malloc(axis
->num_segments
* axis
->num_segments
1589 * num_strong_points
* sizeof (FT_UInt
));
1590 if (!recorder
->ip_between_point_array
)
1591 return FT_Err_Out_Of_Memory
;
1598 TA_reset_recorder(Recorder
* recorder
,
1601 recorder
->hints_record
.buf
= bufp
;
1602 recorder
->hints_record
.num_actions
= 0;
1607 TA_rewind_recorder(Recorder
* recorder
,
1611 TA_reset_recorder(recorder
, bufp
);
1613 recorder
->hints_record
.size
= size
;
1615 /* We later check with MISSING (which expands to 0xFF bytes) */
1617 memset(recorder
->ip_before_points
, 0xFF,
1618 recorder
->num_strong_points
* sizeof (FT_UInt
));
1619 memset(recorder
->ip_after_points
, 0xFF,
1620 recorder
->num_strong_points
* sizeof (FT_UInt
));
1622 memset(recorder
->ip_on_point_array
, 0xFF,
1623 recorder
->num_segments
1624 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1625 memset(recorder
->ip_between_point_array
, 0xFF,
1626 recorder
->num_segments
* recorder
->num_segments
1627 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1632 TA_free_recorder(Recorder
* recorder
)
1634 free(recorder
->wrap_around_segments
);
1636 free(recorder
->ip_before_points
);
1637 free(recorder
->ip_after_points
);
1638 free(recorder
->ip_on_point_array
);
1639 free(recorder
->ip_between_point_array
);
1644 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1648 FT_Face face
= sfnt
->face
;
1656 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1657 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1658 /* `idx' is never negative */
1659 GLYPH
* glyph
= &data
->glyphs
[idx
];
1661 TA_GlyphHints hints
;
1663 FT_UInt num_action_hints_records
= 0;
1664 FT_UInt num_point_hints_records
= 0;
1665 Hints_Record
* action_hints_records
= NULL
;
1666 Hints_Record
* point_hints_records
= NULL
;
1669 FT_UInt num_stack_elements
;
1670 FT_Bool optimize
= 0;
1672 FT_Int32 load_flags
;
1682 /* XXX: right now, we abuse this flag to control */
1683 /* the global behaviour of the auto-hinter */
1684 load_flags
= font
->fallback_script
<< 30;
1685 load_flags
|= 1 << 29; /* vertical hinting only */
1686 /* values 0 and 6-20 compressed to 4 bits */
1687 if (font
->increase_x_height
)
1688 load_flags
|= (font
->increase_x_height
- 5) << 25;
1689 if (!font
->pre_hinting
)
1691 if (font
->hint_with_components
)
1692 load_flags
|= FT_LOAD_NO_SCALE
;
1694 load_flags
|= FT_LOAD_NO_RECURSE
;
1697 /* computing the segments is resolution independent, */
1698 /* thus the pixel size in this call is arbitrary */
1699 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1704 /* temporarily disable debugging output */
1705 /* to avoid getting the information twice */
1706 _ta_debug_save
= _ta_debug
;
1710 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1711 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, load_flags
);
1714 _ta_debug
= _ta_debug_save
;
1720 /* do nothing if we have an empty glyph */
1721 if (!face
->glyph
->outline
.n_contours
)
1724 hints
= &font
->loader
->hints
;
1726 /* do nothing if the setup delivered the dummy module only */
1727 if (!hints
->num_points
)
1730 /* we allocate a buffer which is certainly large enough */
1731 /* to hold all of the created bytecode instructions; */
1732 /* later on it gets reallocated to its real size */
1733 ins_len
= hints
->num_points
* 1000;
1734 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1736 return FT_Err_Out_Of_Memory
;
1738 /* initialize array with an invalid bytecode */
1739 /* so that we can easily find the array length at reallocation time */
1740 memset(ins_buf
, INS_A0
, ins_len
);
1742 /* handle composite glyph */
1743 if (font
->loader
->gloader
->base
.num_subglyphs
)
1745 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1748 error
= FT_Err_Out_Of_Memory
;
1755 /* only scale the glyph if the dummy hinter has been used */
1756 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
1758 /* since `TA_init_recorder' hasn't been called yet, */
1759 /* we manually initialize the `font' and `glyph' fields */
1760 recorder
.font
= font
;
1761 recorder
.glyph
= glyph
;
1763 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1766 error
= FT_Err_Out_Of_Memory
;
1773 error
= TA_init_recorder(&recorder
, font
, glyph
, hints
);
1777 /* loop over a large range of pixel sizes */
1778 /* to find hints records which get pushed onto the bytecode stack */
1787 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
1789 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
1791 num_chars
+= fprintf(stderr
, " (%s)", buf
);
1792 fprintf(stderr
, "\n");
1793 for (i
= 0; i
< num_chars
; i
++)
1795 fprintf(stderr
, "\n\n");
1800 /* we temporarily use `ins_buf' to record the current glyph hints */
1801 ta_loader_register_hints_recorder(font
->loader
,
1805 for (size
= font
->hinting_range_min
;
1806 size
<= font
->hinting_range_max
;
1814 TA_rewind_recorder(&recorder
, ins_buf
, size
);
1816 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1820 /* calling `ta_loader_load_glyph' uses the */
1821 /* `TA_hints_recorder' function as a callback, */
1822 /* modifying `hints_record' */
1823 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, load_flags
);
1827 if (TA_hints_record_is_different(action_hints_records
,
1828 num_action_hints_records
,
1829 ins_buf
, recorder
.hints_record
.buf
))
1839 num_chars
= fprintf(stderr
, "size %d\n", size
);
1840 for (i
= 0; i
< num_chars
- 1; i
++)
1842 fprintf(stderr
, "\n\n");
1844 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1845 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1846 ta_glyph_hints_dump_points(_ta_debug_hints
);
1848 fprintf(stderr
, "action hints record:\n");
1849 if (ins_buf
== recorder
.hints_record
.buf
)
1850 fprintf(stderr
, " (none)");
1853 fprintf(stderr
, " ");
1854 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1855 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1857 fprintf(stderr
, "\n");
1861 error
= TA_add_hints_record(&action_hints_records
,
1862 &num_action_hints_records
,
1863 ins_buf
, recorder
.hints_record
);
1868 /* now handle point records */
1870 TA_reset_recorder(&recorder
, ins_buf
);
1872 /* use the point hints data collected in `TA_hints_recorder' */
1873 TA_build_point_hints(&recorder
, hints
);
1875 if (TA_hints_record_is_different(point_hints_records
,
1876 num_point_hints_records
,
1877 ins_buf
, recorder
.hints_record
.buf
))
1887 num_chars
= fprintf(stderr
, "size %d\n", size
);
1888 for (i
= 0; i
< num_chars
- 1; i
++)
1890 fprintf(stderr
, "\n\n");
1892 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1893 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1894 ta_glyph_hints_dump_points(_ta_debug_hints
);
1897 fprintf(stderr
, "point hints record:\n");
1898 if (ins_buf
== recorder
.hints_record
.buf
)
1899 fprintf(stderr
, " (none)");
1902 fprintf(stderr
, " ");
1903 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1904 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1906 fprintf(stderr
, "\n\n");
1910 error
= TA_add_hints_record(&point_hints_records
,
1911 &num_point_hints_records
,
1912 ins_buf
, recorder
.hints_record
);
1918 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
1920 /* since we only have a single empty record we just scale the glyph */
1921 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1924 error
= FT_Err_Out_Of_Memory
;
1928 /* clear the rest of the temporarily used part of `ins_buf' */
1930 while (*p
!= INS_A0
)
1936 /* if there is only a single record, */
1937 /* we do a global optimization later on */
1938 if (num_action_hints_records
> 1)
1941 /* store the hints records and handle stack depth */
1943 bufp
= TA_emit_hints_records(&recorder
,
1944 point_hints_records
,
1945 num_point_hints_records
,
1949 num_stack_elements
= recorder
.num_stack_elements
;
1950 recorder
.num_stack_elements
= 0;
1953 bufp
= TA_emit_hints_records(&recorder
,
1954 action_hints_records
,
1955 num_action_hints_records
,
1959 recorder
.num_stack_elements
+= num_stack_elements
;
1962 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
1965 error
= FT_Err_Out_Of_Memory
;
1969 /* XXX improve handling of NPUSHW */
1970 if (num_action_hints_records
== 1
1971 && *(pos
[0]) != NPUSHW
&& *(pos
[1]) != NPUSHW
&& *(pos
[2]) != NPUSHW
)
1974 * we optimize two common cases, replacing
1976 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1980 * NPUSHB (A+B[+C]) ... CALL
1993 /* the point hints records block can be missing */
1994 if (pos
[0] == pos
[1])
2000 /* there are at least two NPUSHB instructions */
2001 /* (one of them directly at the start) */
2002 sizes
[0] = *(pos
[0] + 1);
2003 sizes
[1] = *(pos
[1] + 1);
2004 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
2006 sum
= sizes
[0] + sizes
[1] + sizes
[2];
2009 goto Done2
; /* nothing to do since we need three NPUSHB */
2010 else if (!sizes
[2] && (sum
> 0xFF))
2011 goto Done2
; /* nothing to do since we need two NPUSHB */
2015 /* reduce three NPUSHB to two */
2017 new_size2
= sum
- 0xFF;
2021 /* reduce two or three NPUSHB to one */
2032 BCI(PUSHB_1
- 1 + new_size1
);
2038 for (i
= 0; i
< new_size1
; i
++)
2040 if (p
== pos
[pos_idx
])
2043 p
+= 2; /* skip old NPUSHB */
2051 BCI(PUSHB_1
- 1 + new_size2
);
2057 for (i
= 0; i
< new_size2
; i
++)
2059 if (p
== pos
[pos_idx
])
2072 /* clear the rest of the temporarily used part of `ins_buf' */
2074 while (*p
!= INS_A0
)
2078 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2079 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2080 TA_free_recorder(&recorder
);
2082 /* we are done, so reallocate the instruction array to its real size */
2083 if (*bufp
== INS_A0
)
2085 /* search backwards */
2086 while (*bufp
== INS_A0
)
2092 /* search forwards */
2093 while (*bufp
!= INS_A0
)
2098 ins_len
= bufp
- ins_buf
;
2100 if (ins_len
> sfnt
->max_instructions
)
2101 sfnt
->max_instructions
= ins_len
;
2103 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2104 glyph
->ins_len
= ins_len
;
2109 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2110 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2111 TA_free_recorder(&recorder
);
2118 /* end of tabytecode.c */