4 * Copyright (C) 2011-2014 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_UShort)~0
29 int _ta_debug_global
= 0;
30 int _ta_debug_disable_horz_hints
;
31 int _ta_debug_disable_vert_hints
;
32 int _ta_debug_disable_blue_hints
;
33 void* _ta_debug_hints
;
37 typedef struct Hints_Record_
45 typedef struct Recorder_
49 GLYPH
* glyph
; /* the current glyph */
50 Hints_Record hints_record
;
52 /* some segments can `wrap around' */
53 /* a contour's start point like 24-25-26-0-1-2 */
54 /* (there can be at most one such segment per contour); */
55 /* later on we append additional records */
56 /* to split them into 24-26 and 0-2 */
57 FT_UShort
* wrap_around_segments
;
58 FT_UShort num_wrap_around_segments
;
60 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
62 /* data necessary for strong point interpolation */
63 FT_UShort
* ip_before_points
;
64 FT_UShort
* ip_after_points
;
65 FT_UShort
* ip_on_point_array
;
66 FT_UShort
* ip_between_point_array
;
68 FT_UShort num_strong_points
;
69 FT_UShort num_segments
;
73 /* this is the bytecode of the `.ttfautohint' glyph */
75 FT_Byte ttfautohint_glyph_bytecode
[7] =
78 /* increment `cvtl_is_subglyph' counter */
91 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
92 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
93 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
98 TA_build_push(FT_Byte
* bufp
,
110 for (i
= 0; i
< num_args
; i
+= 255)
112 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
114 if (optimize
&& nargs
<= 8)
115 BCI(PUSHW_1
- 1 + nargs
);
121 for (j
= 0; j
< nargs
; j
++)
131 for (i
= 0; i
< num_args
; i
+= 255)
133 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
135 if (optimize
&& nargs
<= 8)
136 BCI(PUSHB_1
- 1 + nargs
);
142 for (j
= 0; j
< nargs
; j
++)
154 /* We add a subglyph for each composite glyph. */
155 /* Since subglyphs must contain at least one point, */
156 /* we have to adjust all point indices accordingly. */
157 /* Using the `pointsums' array of the `GLYPH' structure */
158 /* it is straightforward to do that: */
159 /* Assuming that point with index x is in the interval */
160 /* pointsums[n] <= x < pointsums[n + 1], */
161 /* the new point index is x + n. */
164 TA_adjust_point_index(Recorder
* recorder
,
167 FONT
* font
= recorder
->font
;
168 GLYPH
* glyph
= recorder
->glyph
;
172 if (!glyph
->num_components
|| !font
->hint_composites
)
173 return idx
; /* not a composite glyph */
175 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
176 if (idx
< glyph
->pointsums
[i
])
183 /* we store the segments in the storage area; */
184 /* each segment record consists of the first and last point */
187 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
192 FONT
* font
= recorder
->font
;
193 TA_GlyphHints hints
= &font
->loader
->hints
;
194 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
195 TA_Point points
= hints
->points
;
196 TA_Segment segments
= axis
->segments
;
198 TA_Segment seg_limit
;
200 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
201 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
203 FT_UInt script_id
= data
->script_ids
204 [font
->loader
->metrics
->script_class
->script
];
206 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
211 FT_UShort num_segments
;
213 FT_Bool need_words
= 0;
217 FT_UShort num_packed_segments
;
218 FT_UShort num_storage
;
219 FT_UShort num_stack_elements
;
220 FT_UShort num_twilight_points
;
223 seg_limit
= segments
+ axis
->num_segments
;
224 num_segments
= axis
->num_segments
;
226 /* to pack the data in the bytecode more tightly, */
227 /* we store up to the first nine segments in nibbles if possible, */
228 /* using delta values */
230 num_packed_segments
= 0;
231 for (seg
= segments
; seg
< seg_limit
; seg
++)
233 FT_UInt first
= seg
->first
- points
;
234 FT_UInt last
= seg
->last
- points
;
237 first
= TA_adjust_point_index(recorder
, first
);
238 last
= TA_adjust_point_index(recorder
, last
);
240 if (first
- base
>= 16)
242 if (first
> last
|| last
- first
>= 16)
244 if (num_packed_segments
== 9)
246 num_packed_segments
++;
250 /* also handle wrap-around segments */
251 num_segments
+= recorder
->num_wrap_around_segments
;
253 /* wrap-around segments are pushed with four arguments; */
254 /* a segment stored in nibbles needs only one byte instead of two */
255 num_args
= num_packed_segments
256 + 2 * (num_segments
- num_packed_segments
)
257 + 2 * recorder
->num_wrap_around_segments
260 /* collect all arguments temporarily in an array (in reverse order) */
261 /* so that we can easily split into chunks of 255 args */
262 /* as needed by NPUSHB and NPUSHW, respectively */
263 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
267 arg
= args
+ num_args
- 1;
269 if (num_segments
> 0xFF)
272 /* the number of packed segments is indicated by the function number */
273 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
274 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
276 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
278 *(arg
--) = CVT_SCALING_VALUE_OFFSET(script_id
);
279 *(arg
--) = num_segments
;
282 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
284 FT_UInt first
= seg
->first
- points
;
285 FT_UInt last
= seg
->last
- points
;
290 first
= TA_adjust_point_index(recorder
, first
);
291 last
= TA_adjust_point_index(recorder
, last
);
293 low_nibble
= first
- base
;
294 high_nibble
= last
- first
;
296 *(arg
--) = 16 * high_nibble
+ low_nibble
;
301 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
303 FT_UInt first
= seg
->first
- points
;
304 FT_UInt last
= seg
->last
- points
;
307 *(arg
--) = TA_adjust_point_index(recorder
, first
);
308 *(arg
--) = TA_adjust_point_index(recorder
, last
);
310 /* we push the last and first contour point */
311 /* as a third and fourth argument in wrap-around segments */
314 for (n
= 0; n
< outline
.n_contours
; n
++)
316 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
321 *(arg
--) = TA_adjust_point_index(recorder
, end
);
326 *(arg
--) = TA_adjust_point_index(recorder
, 0);
328 *(arg
--) = TA_adjust_point_index(recorder
,
329 (FT_UInt
)outline
.contours
[n
- 1] + 1);
339 /* emit the second part of wrap-around segments as separate segments */
340 /* so that edges can easily link to them */
341 for (seg
= segments
; seg
< seg_limit
; seg
++)
343 FT_UInt first
= seg
->first
- points
;
344 FT_UInt last
= seg
->last
- points
;
349 for (n
= 0; n
< outline
.n_contours
; n
++)
351 if (first
<= (FT_UInt
)outline
.contours
[n
])
354 *(arg
--) = TA_adjust_point_index(recorder
, 0);
356 *(arg
--) = TA_adjust_point_index(recorder
,
357 (FT_UInt
)outline
.contours
[n
- 1] + 1);
362 *(arg
--) = TA_adjust_point_index(recorder
, last
);
366 /* with most fonts it is very rare */
367 /* that any of the pushed arguments is larger than 0xFF, */
368 /* thus we refrain from further optimizing this case */
369 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
373 num_storage
= sal_segment_offset
+ num_segments
* 2;
374 if (num_storage
> sfnt
->max_storage
)
375 sfnt
->max_storage
= num_storage
;
377 num_twilight_points
= num_segments
* 2;
378 if (num_twilight_points
> sfnt
->max_twilight_points
)
379 sfnt
->max_twilight_points
= num_twilight_points
;
381 /* both this function and `TA_emit_hints_record' */
382 /* push data onto the stack */
383 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
384 + recorder
->num_stack_elements
+ num_args
;
385 if (num_stack_elements
> sfnt
->max_stack_elements
)
386 sfnt
->max_stack_elements
= num_stack_elements
;
395 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
399 FONT
* font
= recorder
->font
;
400 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
401 FT_Vector
* points
= glyph
->outline
.points
;
402 FT_Int num_contours
= glyph
->outline
.n_contours
;
408 FT_Bool need_words
= 0;
411 FT_UShort num_stack_elements
;
414 num_args
= 2 * num_contours
+ 2;
416 /* collect all arguments temporarily in an array (in reverse order) */
417 /* so that we can easily split into chunks of 255 args */
418 /* as needed by NPUSHB and NPUSHW, respectively */
419 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
423 arg
= args
+ num_args
- 1;
428 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
429 *(arg
--) = bci_scale_composite_glyph
;
431 *(arg
--) = bci_scale_glyph
;
432 *(arg
--) = num_contours
;
437 for (p
= 0; p
< num_contours
; p
++)
443 end
= glyph
->outline
.contours
[p
];
445 for (q
= start
; q
<= end
; q
++)
447 if (points
[q
].y
< points
[min
].y
)
449 if (points
[q
].y
> points
[max
].y
)
455 *(arg
--) = TA_adjust_point_index(recorder
, max
);
456 *(arg
--) = TA_adjust_point_index(recorder
, min
);
460 *(arg
--) = TA_adjust_point_index(recorder
, min
);
461 *(arg
--) = TA_adjust_point_index(recorder
, max
);
470 /* with most fonts it is very rare */
471 /* that any of the pushed arguments is larger than 0xFF, */
472 /* thus we refrain from further optimizing this case */
473 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
477 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
478 if (num_stack_elements
> sfnt
->max_stack_elements
)
479 sfnt
->max_stack_elements
= num_stack_elements
;
488 TA_font_build_subglyph_shifter(FONT
* font
,
491 FT_Face face
= font
->loader
->face
;
492 FT_GlyphSlot glyph
= face
->glyph
;
494 TA_GlyphLoader gloader
= font
->loader
->gloader
;
496 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
497 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
498 TA_SubGlyph subglyph
;
500 FT_Int curr_contour
= 0;
503 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
507 FT_UShort flags
= subglyph
->flags
;
508 FT_Pos y_offset
= subglyph
->arg2
;
513 /* load subglyph to get the number of contours */
514 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
517 num_contours
= glyph
->outline
.n_contours
;
519 /* nothing to do if there is a point-to-point alignment */
520 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
523 /* nothing to do if y offset is zero */
527 /* nothing to do if there are no contours */
531 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
532 /* ensures that composite subglyphs are represented as simple glyphs */
534 if (num_contours
> 0xFF
535 || curr_contour
> 0xFF)
538 BCI(HIGH(curr_contour
));
539 BCI(LOW(curr_contour
));
540 BCI(HIGH(num_contours
));
541 BCI(LOW(num_contours
));
550 /* there are high chances that this value needs PUSHW, */
551 /* thus we handle it separately */
552 if (y_offset
> 0xFF || y_offset
< 0)
565 BCI(bci_shift_subglyph
);
569 curr_contour
+= num_contours
;
577 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
578 * data in four arrays (which are simple but waste a lot of memory). The
579 * function below converts them into bytecode.
581 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
582 * together with the edge they correspond to.
584 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
585 * loop over the edge or edge pairs, respectively, and each edge or edge
586 * pair contains an inner loop to emit the correponding points.
590 TA_build_point_hints(Recorder
* recorder
,
593 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
594 TA_Segment segments
= axis
->segments
;
595 TA_Edge edges
= axis
->edges
;
599 FT_Byte
* p
= recorder
->hints_record
.buf
;
600 FT_UShort num_edges
= axis
->num_edges
;
601 FT_UShort num_strong_points
= recorder
->num_strong_points
;
615 /* we store everything as 16bit numbers; */
616 /* the function numbers (`ta_ip_before', etc.) */
617 /* reflect the order in the TA_Action enumeration */
619 /* ip_before_points */
622 ip
= recorder
->ip_before_points
;
623 ip_limit
= ip
+ num_strong_points
;
624 for (; ip
< ip_limit
; ip
++)
634 recorder
->hints_record
.num_actions
++;
639 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
640 *(p
++) = HIGH(edge
->first
- segments
);
641 *(p
++) = LOW(edge
->first
- segments
);
645 ip
= recorder
->ip_before_points
;
647 for (; ip
< ip_limit
; ip
++)
649 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
652 *(p
++) = HIGH(point
);
657 /* ip_after_points */
660 ip
= recorder
->ip_after_points
;
661 ip_limit
= ip
+ num_strong_points
;
662 for (; ip
< ip_limit
; ip
++)
672 recorder
->hints_record
.num_actions
++;
674 edge
= edges
+ axis
->num_edges
- 1;
677 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
678 *(p
++) = HIGH(edge
->first
- segments
);
679 *(p
++) = LOW(edge
->first
- segments
);
683 ip
= recorder
->ip_after_points
;
685 for (; ip
< ip_limit
; ip
++)
687 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
690 *(p
++) = HIGH(point
);
695 /* ip_on_point_array */
698 ip
= recorder
->ip_on_point_array
;
699 ip_limit
= ip
+ num_edges
* num_strong_points
;
700 for (; ip
< ip_limit
; ip
+= num_strong_points
)
706 recorder
->hints_record
.num_actions
++;
709 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
714 ip
= recorder
->ip_on_point_array
;
715 ip_limit
= ip
+ num_edges
* num_strong_points
;
716 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
723 *(p
++) = HIGH(edge
->first
- segments
);
724 *(p
++) = LOW(edge
->first
- segments
);
728 iq_limit
= iq
+ num_strong_points
;
729 for (; iq
< iq_limit
; iq
++)
742 for (; iq
< iq_limit
; iq
++)
744 FT_UInt point
= TA_adjust_point_index(recorder
, *iq
);
747 *(p
++) = HIGH(point
);
753 /* ip_between_point_array */
756 ip
= recorder
->ip_between_point_array
;
757 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
758 for (; ip
< ip_limit
; ip
+= num_strong_points
)
764 recorder
->hints_record
.num_actions
++;
767 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
772 ip
= recorder
->ip_between_point_array
;
773 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
776 ip
+= num_edges
* num_strong_points
, i
++)
786 iq_limit
= iq
+ num_edges
* num_strong_points
;
787 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
794 *(p
++) = HIGH(after
->first
- segments
);
795 *(p
++) = LOW(after
->first
- segments
);
796 *(p
++) = HIGH(before
->first
- segments
);
797 *(p
++) = LOW(before
->first
- segments
);
801 ir_limit
= ir
+ num_strong_points
;
802 for (; ir
< ir_limit
; ir
++)
815 for (; ir
< ir_limit
; ir
++)
817 FT_UInt point
= TA_adjust_point_index(recorder
, *ir
);
820 *(p
++) = HIGH(point
);
827 recorder
->hints_record
.buf
= p
;
832 TA_hints_record_is_different(Hints_Record
* hints_records
,
833 FT_UInt num_hints_records
,
837 Hints_Record last_hints_record
;
843 /* we only need to compare with the last hints record */
844 last_hints_record
= hints_records
[num_hints_records
- 1];
846 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
849 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
857 TA_add_hints_record(Hints_Record
** hints_records
,
858 FT_UInt
* num_hints_records
,
860 Hints_Record hints_record
)
862 Hints_Record
* hints_records_new
;
864 /* at this point, `hints_record.buf' still points into `ins_buf' */
865 FT_Byte
* end
= hints_record
.buf
;
868 buf_len
= (FT_UInt
)(end
- start
);
870 /* now fill the structure completely */
871 hints_record
.buf_len
= buf_len
;
872 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
873 if (!hints_record
.buf
)
874 return FT_Err_Out_Of_Memory
;
876 memcpy(hints_record
.buf
, start
, buf_len
);
878 (*num_hints_records
)++;
880 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
881 * sizeof (Hints_Record
));
882 if (!hints_records_new
)
884 free(hints_record
.buf
);
885 (*num_hints_records
)--;
886 return FT_Err_Out_Of_Memory
;
889 *hints_records
= hints_records_new
;
891 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
898 TA_emit_hints_record(Recorder
* recorder
,
899 Hints_Record
* hints_record
,
905 FT_Bool need_words
= 0;
908 FT_UInt num_arguments
;
912 /* check whether any argument is larger than 0xFF */
913 endp
= hints_record
->buf
+ hints_record
->buf_len
;
914 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 /* emit hints records in `if' clauses, */
995 /* with the ppem size as the condition */
996 for (i
= 0; i
< num_hints_records
- 1; i
++)
999 if (hints_record
->size
> 0xFF)
1002 BCI(HIGH((hints_record
+ 1)->size
));
1003 BCI(LOW((hints_record
+ 1)->size
));
1008 BCI((hints_record
+ 1)->size
);
1012 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1018 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1020 for (i
= 0; i
< num_hints_records
- 1; i
++)
1028 TA_free_hints_records(Hints_Record
* hints_records
,
1029 FT_UInt num_hints_records
)
1034 for (i
= 0; i
< num_hints_records
; i
++)
1035 free(hints_records
[i
].buf
);
1037 free(hints_records
);
1042 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1047 TA_Segment segments
= axis
->segments
;
1050 FT_UShort num_segs
= 0;
1054 seg_idx
= edge
->first
- segments
;
1056 /* we store everything as 16bit numbers */
1057 *(bufp
++) = HIGH(seg_idx
);
1058 *(bufp
++) = LOW(seg_idx
);
1060 /* wrap-around segments are stored as two segments */
1061 if (edge
->first
->first
> edge
->first
->last
)
1064 seg
= edge
->first
->edge_next
;
1065 while (seg
!= edge
->first
)
1069 if (seg
->first
> seg
->last
)
1072 seg
= seg
->edge_next
;
1075 *(bufp
++) = HIGH(num_segs
);
1076 *(bufp
++) = LOW(num_segs
);
1078 if (edge
->first
->first
> edge
->first
->last
)
1080 /* emit second part of wrap-around segment; */
1081 /* the bytecode positions such segments after `normal' ones */
1085 if (seg_idx
== *wrap
)
1090 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1091 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1094 seg
= edge
->first
->edge_next
;
1095 while (seg
!= edge
->first
)
1097 seg_idx
= seg
- segments
;
1099 *(bufp
++) = HIGH(seg_idx
);
1100 *(bufp
++) = LOW(seg_idx
);
1102 if (seg
->first
> seg
->last
)
1107 if (seg_idx
== *wrap
)
1112 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1113 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1116 seg
= seg
->edge_next
;
1124 TA_hints_recorder(TA_Action action
,
1125 TA_GlyphHints hints
,
1130 TA_Edge lower_bound
,
1131 TA_Edge upper_bound
)
1133 TA_AxisHints axis
= &hints
->axis
[dim
];
1134 TA_Edge edges
= axis
->edges
;
1135 TA_Segment segments
= axis
->segments
;
1136 TA_Point points
= hints
->points
;
1138 Recorder
* recorder
= (Recorder
*)hints
->user
;
1139 SFNT
* sfnt
= recorder
->sfnt
;
1140 FONT
* font
= recorder
->font
;
1141 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1142 FT_Byte
* p
= recorder
->hints_record
.buf
;
1144 FT_UInt script
= font
->loader
->metrics
->script_class
->script
;
1150 if (dim
== TA_DIMENSION_HORZ
)
1153 /* we collect point hints for later processing */
1158 TA_Point point
= (TA_Point
)arg1
;
1161 ip
= recorder
->ip_before_points
;
1162 limit
= ip
+ recorder
->num_strong_points
;
1163 for (; ip
< limit
; ip
++)
1167 *ip
= point
- points
;
1176 TA_Point point
= (TA_Point
)arg1
;
1179 ip
= recorder
->ip_after_points
;
1180 limit
= ip
+ recorder
->num_strong_points
;
1181 for (; ip
< limit
; ip
++)
1185 *ip
= point
- points
;
1194 TA_Point point
= (TA_Point
)arg1
;
1195 TA_Edge edge
= arg2
;
1198 ip
= recorder
->ip_on_point_array
1199 + recorder
->num_strong_points
1201 limit
= ip
+ recorder
->num_strong_points
;
1202 for (; ip
< limit
; ip
++)
1206 *ip
= point
- points
;
1215 TA_Point point
= (TA_Point
)arg1
;
1216 TA_Edge before
= arg2
;
1217 TA_Edge after
= arg3
;
1220 /* note that `recorder->num_segments' has been used for allocation, */
1221 /* but `axis->num_edges' is used for accessing this array */
1222 ip
= recorder
->ip_between_point_array
1223 + recorder
->num_strong_points
* axis
->num_edges
1225 + recorder
->num_strong_points
1227 limit
= ip
+ recorder
->num_strong_points
;
1228 for (; ip
< limit
; ip
++)
1232 *ip
= point
- points
;
1240 /* we ignore the BOUND action since we signal this information */
1241 /* with the proper function number */
1248 /* some enum values correspond to four or eight bytecode functions; */
1249 /* if the value is n, the function numbers are n, ..., n+7, */
1250 /* to be differentiated with flags */
1256 TA_Edge base_edge
= (TA_Edge
)arg1
;
1257 TA_Edge stem_edge
= arg2
;
1261 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1262 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1263 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1265 *(p
++) = HIGH(base_edge
->first
- segments
);
1266 *(p
++) = LOW(base_edge
->first
- segments
);
1267 *(p
++) = HIGH(stem_edge
->first
- segments
);
1268 *(p
++) = LOW(stem_edge
->first
- segments
);
1270 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1276 TA_Edge edge
= (TA_Edge
)arg1
;
1277 TA_Edge edge2
= arg2
;
1281 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1282 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1283 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1285 *(p
++) = HIGH(edge
->first
- segments
);
1286 *(p
++) = LOW(edge
->first
- segments
);
1287 *(p
++) = HIGH(edge2
->first
- segments
);
1288 *(p
++) = LOW(edge2
->first
- segments
);
1290 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1296 TA_Edge edge
= (TA_Edge
)arg1
;
1297 TA_Edge edge2
= arg2
;
1298 TA_Edge edge_minus_one
= lower_bound
;
1302 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1303 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1304 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1305 + 4 * (edge_minus_one
!= NULL
);
1307 *(p
++) = HIGH(edge
->first
- segments
);
1308 *(p
++) = LOW(edge
->first
- segments
);
1309 *(p
++) = HIGH(edge2
->first
- segments
);
1310 *(p
++) = LOW(edge2
->first
- segments
);
1314 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1315 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1318 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1322 case ta_blue_anchor
:
1324 TA_Edge edge
= (TA_Edge
)arg1
;
1325 TA_Edge blue
= arg2
;
1329 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1331 *(p
++) = HIGH(blue
->first
- segments
);
1332 *(p
++) = LOW(blue
->first
- segments
);
1334 if (edge
->best_blue_is_shoot
)
1336 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(script
) + edge
->best_blue_idx
);
1337 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(script
) + edge
->best_blue_idx
);
1341 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(script
) + edge
->best_blue_idx
);
1342 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(script
) + edge
->best_blue_idx
);
1345 *(p
++) = HIGH(edge
->first
- segments
);
1346 *(p
++) = LOW(edge
->first
- segments
);
1348 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1354 TA_Edge edge
= (TA_Edge
)arg1
;
1355 TA_Edge edge2
= arg2
;
1356 TA_Edge edge_minus_one
= lower_bound
;
1360 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1361 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1362 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1363 + 4 * (edge_minus_one
!= NULL
);
1365 *(p
++) = HIGH(edge
->first
- segments
);
1366 *(p
++) = LOW(edge
->first
- segments
);
1367 *(p
++) = HIGH(edge2
->first
- segments
);
1368 *(p
++) = LOW(edge2
->first
- segments
);
1372 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1373 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1376 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1377 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1383 TA_Edge edge
= (TA_Edge
)arg1
;
1387 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1389 if (edge
->best_blue_is_shoot
)
1391 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(script
) + edge
->best_blue_idx
);
1392 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(script
) + edge
->best_blue_idx
);
1396 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(script
) + edge
->best_blue_idx
);
1397 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(script
) + edge
->best_blue_idx
);
1400 *(p
++) = HIGH(edge
->first
- segments
);
1401 *(p
++) = LOW(edge
->first
- segments
);
1403 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1409 TA_Edge serif
= (TA_Edge
)arg1
;
1410 TA_Edge base
= serif
->serif
;
1414 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1415 + (lower_bound
!= NULL
)
1416 + 2 * (upper_bound
!= NULL
);
1418 *(p
++) = HIGH(serif
->first
- segments
);
1419 *(p
++) = LOW(serif
->first
- segments
);
1420 *(p
++) = HIGH(base
->first
- segments
);
1421 *(p
++) = LOW(base
->first
- segments
);
1425 *(p
++) = HIGH(lower_bound
->first
- segments
);
1426 *(p
++) = LOW(lower_bound
->first
- segments
);
1430 *(p
++) = HIGH(upper_bound
->first
- segments
);
1431 *(p
++) = LOW(upper_bound
->first
- segments
);
1434 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1438 case ta_serif_anchor
:
1439 case ta_serif_link2
:
1441 TA_Edge edge
= (TA_Edge
)arg1
;
1445 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1446 + (lower_bound
!= NULL
)
1447 + 2 * (upper_bound
!= NULL
);
1449 *(p
++) = HIGH(edge
->first
- segments
);
1450 *(p
++) = LOW(edge
->first
- segments
);
1454 *(p
++) = HIGH(lower_bound
->first
- segments
);
1455 *(p
++) = LOW(lower_bound
->first
- segments
);
1459 *(p
++) = HIGH(upper_bound
->first
- segments
);
1460 *(p
++) = LOW(upper_bound
->first
- segments
);
1463 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1467 case ta_serif_link1
:
1469 TA_Edge edge
= (TA_Edge
)arg1
;
1470 TA_Edge before
= arg2
;
1471 TA_Edge after
= arg3
;
1475 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1476 + (lower_bound
!= NULL
)
1477 + 2 * (upper_bound
!= NULL
);
1479 *(p
++) = HIGH(before
->first
- segments
);
1480 *(p
++) = LOW(before
->first
- segments
);
1481 *(p
++) = HIGH(edge
->first
- segments
);
1482 *(p
++) = LOW(edge
->first
- segments
);
1483 *(p
++) = HIGH(after
->first
- segments
);
1484 *(p
++) = LOW(after
->first
- segments
);
1488 *(p
++) = HIGH(lower_bound
->first
- segments
);
1489 *(p
++) = LOW(lower_bound
->first
- segments
);
1493 *(p
++) = HIGH(upper_bound
->first
- segments
);
1494 *(p
++) = LOW(upper_bound
->first
- segments
);
1497 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1502 /* there are more cases in the enumeration */
1503 /* which are handled with flags */
1507 recorder
->hints_record
.num_actions
++;
1508 recorder
->hints_record
.buf
= p
;
1513 TA_init_recorder(Recorder
* recorder
,
1517 TA_GlyphHints hints
)
1519 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1520 TA_Point points
= hints
->points
;
1521 TA_Point point_limit
= points
+ hints
->num_points
;
1524 TA_Segment segments
= axis
->segments
;
1525 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1528 FT_UShort num_strong_points
= 0;
1529 FT_UShort
* wrap_around_segment
;
1531 recorder
->sfnt
= sfnt
;
1532 recorder
->font
= font
;
1533 recorder
->glyph
= glyph
;
1534 recorder
->num_segments
= axis
->num_segments
;
1536 recorder
->ip_before_points
= NULL
;
1537 recorder
->ip_after_points
= NULL
;
1538 recorder
->ip_on_point_array
= NULL
;
1539 recorder
->ip_between_point_array
= NULL
;
1541 recorder
->num_stack_elements
= 0;
1543 /* no need to clean up allocated arrays in case of error; */
1544 /* this is handled later by `TA_free_recorder' */
1546 recorder
->num_wrap_around_segments
= 0;
1547 for (seg
= segments
; seg
< seg_limit
; seg
++)
1548 if (seg
->first
> seg
->last
)
1549 recorder
->num_wrap_around_segments
++;
1551 recorder
->wrap_around_segments
=
1552 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
1553 * sizeof (FT_UShort
));
1554 if (!recorder
->wrap_around_segments
)
1555 return FT_Err_Out_Of_Memory
;
1557 wrap_around_segment
= recorder
->wrap_around_segments
;
1558 for (seg
= segments
; seg
< seg_limit
; seg
++)
1559 if (seg
->first
> seg
->last
)
1560 *(wrap_around_segment
++) = seg
- segments
;
1562 /* get number of strong points */
1563 for (point
= points
; point
< point_limit
; point
++)
1565 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1566 /* however, this value isn't known yet */
1567 /* (or rather, it can vary between different pixel sizes) */
1568 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1571 num_strong_points
++;
1574 recorder
->num_strong_points
= num_strong_points
;
1576 recorder
->ip_before_points
=
1577 (FT_UShort
*)malloc(num_strong_points
* sizeof (FT_UShort
));
1578 if (!recorder
->ip_before_points
)
1579 return FT_Err_Out_Of_Memory
;
1581 recorder
->ip_after_points
=
1582 (FT_UShort
*)malloc(num_strong_points
* sizeof (FT_UShort
));
1583 if (!recorder
->ip_after_points
)
1584 return FT_Err_Out_Of_Memory
;
1586 /* actually, we need `hints->num_edges' for the array sizes; */
1587 /* however, this value isn't known yet */
1588 /* (or rather, it can vary between different pixel sizes) */
1589 recorder
->ip_on_point_array
=
1590 (FT_UShort
*)malloc(axis
->num_segments
1591 * num_strong_points
* sizeof (FT_UShort
));
1592 if (!recorder
->ip_on_point_array
)
1593 return FT_Err_Out_Of_Memory
;
1595 recorder
->ip_between_point_array
=
1596 (FT_UShort
*)malloc(axis
->num_segments
* axis
->num_segments
1597 * num_strong_points
* sizeof (FT_UShort
));
1598 if (!recorder
->ip_between_point_array
)
1599 return FT_Err_Out_Of_Memory
;
1606 TA_reset_recorder(Recorder
* recorder
,
1609 recorder
->hints_record
.buf
= bufp
;
1610 recorder
->hints_record
.num_actions
= 0;
1615 TA_rewind_recorder(Recorder
* recorder
,
1619 TA_reset_recorder(recorder
, bufp
);
1621 recorder
->hints_record
.size
= size
;
1623 /* We later check with MISSING (which expands to 0xFF bytes) */
1625 memset(recorder
->ip_before_points
, 0xFF,
1626 recorder
->num_strong_points
* sizeof (FT_UShort
));
1627 memset(recorder
->ip_after_points
, 0xFF,
1628 recorder
->num_strong_points
* sizeof (FT_UShort
));
1630 memset(recorder
->ip_on_point_array
, 0xFF,
1631 recorder
->num_segments
1632 * recorder
->num_strong_points
* sizeof (FT_UShort
));
1633 memset(recorder
->ip_between_point_array
, 0xFF,
1634 recorder
->num_segments
* recorder
->num_segments
1635 * recorder
->num_strong_points
* sizeof (FT_UShort
));
1640 TA_free_recorder(Recorder
* recorder
)
1642 free(recorder
->wrap_around_segments
);
1644 free(recorder
->ip_before_points
);
1645 free(recorder
->ip_after_points
);
1646 free(recorder
->ip_on_point_array
);
1647 free(recorder
->ip_between_point_array
);
1652 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1656 FT_Face face
= sfnt
->face
;
1664 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1665 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1666 /* `idx' is never negative */
1667 GLYPH
* glyph
= &data
->glyphs
[idx
];
1669 TA_GlyphHints hints
;
1671 FT_UInt num_action_hints_records
= 0;
1672 FT_UInt num_point_hints_records
= 0;
1673 Hints_Record
* action_hints_records
= NULL
;
1674 Hints_Record
* point_hints_records
= NULL
;
1677 FT_UShort num_stack_elements
;
1678 FT_Bool optimize
= 0;
1680 FT_Int32 load_flags
;
1690 /* XXX: right now, we abuse this flag to control */
1691 /* the global behaviour of the auto-hinter */
1692 load_flags
= 1 << 29; /* vertical hinting only */
1693 if (!font
->pre_hinting
)
1695 if (font
->hint_composites
)
1696 load_flags
|= FT_LOAD_NO_SCALE
;
1698 load_flags
|= FT_LOAD_NO_RECURSE
;
1701 /* computing the segments is resolution independent, */
1702 /* thus the pixel size in this call is arbitrary -- */
1703 /* however, we avoid unnecessary debugging output */
1704 /* if we use the lowest value of the hinting range */
1705 error
= FT_Set_Pixel_Sizes(face
,
1706 font
->hinting_range_min
,
1707 font
->hinting_range_min
);
1712 /* temporarily disable some debugging output */
1713 /* to avoid getting the information twice */
1714 _ta_debug_save
= _ta_debug
;
1718 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1719 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
1722 _ta_debug
= _ta_debug_save
;
1728 /* do nothing if we have an empty glyph */
1729 if (!face
->glyph
->outline
.n_contours
)
1732 hints
= &font
->loader
->hints
;
1734 /* do nothing if the setup delivered the `none' script only */
1735 if (!hints
->num_points
)
1738 /* we allocate a buffer which is certainly large enough */
1739 /* to hold all of the created bytecode instructions; */
1740 /* later on it gets reallocated to its real size */
1741 ins_len
= hints
->num_points
* 1000;
1742 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1744 return FT_Err_Out_Of_Memory
;
1746 /* initialize array with an invalid bytecode */
1747 /* so that we can easily find the array length at reallocation time */
1748 memset(ins_buf
, INS_A0
, ins_len
);
1750 /* handle composite glyph */
1751 if (font
->loader
->gloader
->base
.num_subglyphs
)
1753 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1756 error
= FT_Err_Out_Of_Memory
;
1763 /* only scale the glyph if the `none' script has been used */
1764 if (font
->loader
->metrics
->script_class
== &ta_none_script_class
)
1766 /* since `TA_init_recorder' hasn't been called yet, */
1767 /* we manually initialize the `sfnt', `font', and `glyph' fields */
1768 recorder
.sfnt
= sfnt
;
1769 recorder
.font
= font
;
1770 recorder
.glyph
= glyph
;
1772 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1775 error
= FT_Err_Out_Of_Memory
;
1782 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
1786 /* loop over a large range of pixel sizes */
1787 /* to find hints records which get pushed onto the bytecode stack */
1796 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
1798 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
1800 num_chars
+= fprintf(stderr
, " (%s)", buf
);
1801 fprintf(stderr
, "\n");
1802 for (i
= 0; i
< num_chars
; i
++)
1804 fprintf(stderr
, "\n\n");
1809 /* we temporarily use `ins_buf' to record the current glyph hints */
1810 ta_loader_register_hints_recorder(font
->loader
,
1814 for (size
= font
->hinting_range_min
;
1815 size
<= font
->hinting_range_max
;
1823 TA_rewind_recorder(&recorder
, ins_buf
, size
);
1825 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1835 num_chars
= fprintf(stderr
, "size %d\n", size
);
1836 for (i
= 0; i
< num_chars
- 1; i
++)
1838 fprintf(stderr
, "\n\n");
1842 /* calling `ta_loader_load_glyph' uses the */
1843 /* `TA_hints_recorder' function as a callback, */
1844 /* modifying `hints_record' */
1845 error
= ta_loader_load_glyph(font
, face
, idx
, load_flags
);
1849 if (TA_hints_record_is_different(action_hints_records
,
1850 num_action_hints_records
,
1851 ins_buf
, recorder
.hints_record
.buf
))
1858 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1859 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1860 ta_glyph_hints_dump_points(_ta_debug_hints
);
1862 fprintf(stderr
, "action hints record:\n");
1863 if (ins_buf
== recorder
.hints_record
.buf
)
1864 fprintf(stderr
, " (none)");
1867 fprintf(stderr
, " ");
1868 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1869 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1871 fprintf(stderr
, "\n");
1875 error
= TA_add_hints_record(&action_hints_records
,
1876 &num_action_hints_records
,
1877 ins_buf
, recorder
.hints_record
);
1882 /* now handle point records */
1884 TA_reset_recorder(&recorder
, ins_buf
);
1886 /* use the point hints data collected in `TA_hints_recorder' */
1887 TA_build_point_hints(&recorder
, hints
);
1889 if (TA_hints_record_is_different(point_hints_records
,
1890 num_point_hints_records
,
1891 ins_buf
, recorder
.hints_record
.buf
))
1901 num_chars
= fprintf(stderr
, "size %d\n", size
);
1902 for (i
= 0; i
< num_chars
- 1; i
++)
1904 fprintf(stderr
, "\n\n");
1906 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1907 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1908 ta_glyph_hints_dump_points(_ta_debug_hints
);
1911 fprintf(stderr
, "point hints record:\n");
1912 if (ins_buf
== recorder
.hints_record
.buf
)
1913 fprintf(stderr
, " (none)");
1916 fprintf(stderr
, " ");
1917 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1918 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1920 fprintf(stderr
, "\n\n");
1924 error
= TA_add_hints_record(&point_hints_records
,
1925 &num_point_hints_records
,
1926 ins_buf
, recorder
.hints_record
);
1932 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
1934 /* since we only have a single empty record we just scale the glyph */
1935 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1938 error
= FT_Err_Out_Of_Memory
;
1942 /* clear the rest of the temporarily used part of `ins_buf' */
1944 while (*p
!= INS_A0
)
1950 /* if there is only a single record, */
1951 /* we do a global optimization later on */
1952 if (num_action_hints_records
> 1)
1955 /* store the hints records and handle stack depth */
1957 bufp
= TA_emit_hints_records(&recorder
,
1958 point_hints_records
,
1959 num_point_hints_records
,
1963 num_stack_elements
= recorder
.num_stack_elements
;
1964 recorder
.num_stack_elements
= 0;
1967 bufp
= TA_emit_hints_records(&recorder
,
1968 action_hints_records
,
1969 num_action_hints_records
,
1973 recorder
.num_stack_elements
+= num_stack_elements
;
1976 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
1979 error
= FT_Err_Out_Of_Memory
;
1983 /* XXX improve handling of NPUSHW */
1984 if (num_action_hints_records
== 1
1985 && *(pos
[0]) != NPUSHW
&& *(pos
[1]) != NPUSHW
&& *(pos
[2]) != NPUSHW
)
1988 * we optimize two common cases, replacing
1990 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1994 * NPUSHB (A+B[+C]) ... CALL
2007 /* the point hints records block can be missing */
2008 if (pos
[0] == pos
[1])
2014 /* there are at least two NPUSHB instructions */
2015 /* (one of them directly at the start) */
2016 sizes
[0] = *(pos
[0] + 1);
2017 sizes
[1] = *(pos
[1] + 1);
2018 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
2020 sum
= sizes
[0] + sizes
[1] + sizes
[2];
2023 goto Done2
; /* nothing to do since we need three NPUSHB */
2024 else if (!sizes
[2] && (sum
> 0xFF))
2025 goto Done2
; /* nothing to do since we need two NPUSHB */
2029 /* reduce three NPUSHB to two */
2031 new_size2
= sum
- 0xFF;
2035 /* reduce two or three NPUSHB to one */
2046 BCI(PUSHB_1
- 1 + new_size1
);
2052 for (i
= 0; i
< new_size1
; i
++)
2054 if (p
== pos
[pos_idx
])
2057 p
+= 2; /* skip old NPUSHB */
2065 BCI(PUSHB_1
- 1 + new_size2
);
2071 for (i
= 0; i
< new_size2
; i
++)
2073 if (p
== pos
[pos_idx
])
2086 /* clear the rest of the temporarily used part of `ins_buf' */
2088 while (*p
!= INS_A0
)
2092 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2093 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2094 TA_free_recorder(&recorder
);
2096 /* we are done, so reallocate the instruction array to its real size */
2097 if (*bufp
== INS_A0
)
2099 /* search backwards */
2100 while (*bufp
== INS_A0
)
2106 /* search forwards */
2107 while (*bufp
!= INS_A0
)
2112 ins_len
= bufp
- ins_buf
;
2114 if (ins_len
> sfnt
->max_instructions
)
2115 sfnt
->max_instructions
= ins_len
;
2117 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2118 glyph
->ins_len
= ins_len
;
2123 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2124 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2125 TA_free_recorder(&recorder
);
2132 /* end of tabytecode.c */