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
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_
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 GLYPH
* glyph
= recorder
->glyph
;
94 if (!glyph
->num_components
)
95 return idx
; /* not a composite glyph */
97 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
98 if (idx
< glyph
->pointsums
[i
])
105 /* we store the segments in the storage area; */
106 /* each segment record consists of the first and last point */
109 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
113 FONT
* font
= recorder
->font
;
114 TA_GlyphHints hints
= &font
->loader
->hints
;
115 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
116 TA_Point points
= hints
->points
;
117 TA_Segment segments
= axis
->segments
;
119 TA_Segment seg_limit
;
121 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
127 FT_UInt num_segments
;
129 FT_Bool need_words
= 0;
134 FT_UInt num_packed_segments
;
136 FT_UInt num_stack_elements
;
137 FT_UInt num_twilight_points
;
140 seg_limit
= segments
+ axis
->num_segments
;
141 num_segments
= axis
->num_segments
;
143 /* to pack the data in the bytecode more tightly, */
144 /* we store up to the first nine segments in nibbles if possible, */
145 /* using delta values */
147 num_packed_segments
= 0;
148 for (seg
= segments
; seg
< seg_limit
; seg
++)
150 FT_UInt first
= seg
->first
- points
;
151 FT_UInt last
= seg
->last
- points
;
154 first
= TA_adjust_point_index(recorder
, first
);
155 last
= TA_adjust_point_index(recorder
, last
);
157 if (first
- base
>= 16)
159 if (first
> last
|| last
- first
>= 16)
161 if (num_packed_segments
== 9)
163 num_packed_segments
++;
167 /* also handle wrap-around segments */
168 num_segments
+= recorder
->num_wrap_around_segments
;
170 /* wrap-around segments are pushed with four arguments; */
171 /* a segment stored in nibbles needs only one byte instead of two */
172 num_args
= num_packed_segments
173 + 2 * (num_segments
- num_packed_segments
)
174 + 2 * recorder
->num_wrap_around_segments
177 /* collect all arguments temporarily in an array (in reverse order) */
178 /* so that we can easily split into chunks of 255 args */
179 /* as needed by NPUSHB and NPUSHW, respectively */
180 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
184 arg
= args
+ num_args
- 1;
186 if (num_segments
> 0xFF)
189 /* the number of packed segments is indicated by the function number */
190 if (recorder
->glyph
->num_components
)
191 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
193 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
194 *(arg
--) = num_segments
;
197 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
199 FT_UInt first
= seg
->first
- points
;
200 FT_UInt last
= seg
->last
- points
;
205 first
= TA_adjust_point_index(recorder
, first
);
206 last
= TA_adjust_point_index(recorder
, last
);
208 low_nibble
= first
- base
;
209 high_nibble
= last
- first
;
211 *(arg
--) = 16 * high_nibble
+ low_nibble
;
219 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
221 FT_UInt first
= seg
->first
- points
;
222 FT_UInt last
= seg
->last
- points
;
225 *(arg
--) = TA_adjust_point_index(recorder
, first
);
226 *(arg
--) = TA_adjust_point_index(recorder
, last
);
228 /* we push the last and first contour point */
229 /* as a third and fourth argument in wrap-around segments */
232 for (n
= 0; n
< outline
.n_contours
; n
++)
234 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
239 *(arg
--) = TA_adjust_point_index(recorder
, end
);
244 *(arg
--) = TA_adjust_point_index(recorder
, 0);
246 *(arg
--) = TA_adjust_point_index(recorder
,
247 (FT_UInt
)outline
.contours
[n
- 1] + 1);
257 /* emit the second part of wrap-around segments as separate segments */
258 /* so that edges can easily link to them */
259 for (seg
= segments
; seg
< seg_limit
; seg
++)
261 FT_UInt first
= seg
->first
- points
;
262 FT_UInt last
= seg
->last
- points
;
267 for (n
= 0; n
< outline
.n_contours
; n
++)
269 if (first
<= (FT_UInt
)outline
.contours
[n
])
272 *(arg
--) = TA_adjust_point_index(recorder
, 0);
274 *(arg
--) = TA_adjust_point_index(recorder
,
275 (FT_UInt
)outline
.contours
[n
- 1] + 1);
280 *(arg
--) = TA_adjust_point_index(recorder
, last
);
283 /* with most fonts it is very rare */
284 /* that any of the pushed arguments is larger than 0xFF, */
285 /* thus we refrain from further optimizing this case */
291 for (i
= 0; i
< num_args
; i
+= 255)
293 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
297 for (j
= 0; j
< nargs
; j
++)
307 for (i
= 0; i
< num_args
; i
+= 255)
309 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
313 for (j
= 0; j
< nargs
; j
++)
323 num_storage
= sal_segment_offset
+ num_segments
* 2;
324 if (num_storage
> sfnt
->max_storage
)
325 sfnt
->max_storage
= num_storage
;
327 num_twilight_points
= num_segments
* 2;
328 if (num_twilight_points
> sfnt
->max_twilight_points
)
329 sfnt
->max_twilight_points
= num_twilight_points
;
331 /* both this function and `TA_emit_hints_record' */
332 /* push data onto the stack */
333 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
334 + recorder
->num_stack_elements
+ num_args
;
335 if (num_stack_elements
> sfnt
->max_stack_elements
)
336 sfnt
->max_stack_elements
= num_stack_elements
;
345 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
349 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
350 FT_Vector
* points
= glyph
->outline
.points
;
351 FT_Int num_contours
= glyph
->outline
.n_contours
;
358 FT_Bool need_words
= 0;
362 FT_UInt num_stack_elements
;
365 num_args
= 2 * num_contours
+ 2;
367 /* collect all arguments temporarily in an array (in reverse order) */
368 /* so that we can easily split into chunks of 255 args */
369 /* as needed by NPUSHB and NPUSHW, respectively */
370 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
374 arg
= args
+ num_args
- 1;
379 if (recorder
->glyph
->num_components
)
380 *(arg
--) = bci_scale_composite_glyph
;
382 *(arg
--) = bci_scale_glyph
;
383 *(arg
--) = num_contours
;
388 for (p
= 0; p
< num_contours
; p
++)
394 end
= glyph
->outline
.contours
[p
];
396 for (q
= start
; q
<= end
; q
++)
398 if (points
[q
].y
< points
[min
].y
)
400 if (points
[q
].y
> points
[max
].y
)
406 *(arg
--) = TA_adjust_point_index(recorder
, max
);
407 *(arg
--) = TA_adjust_point_index(recorder
, min
);
411 *(arg
--) = TA_adjust_point_index(recorder
, min
);
412 *(arg
--) = TA_adjust_point_index(recorder
, max
);
421 /* with most fonts it is very rare */
422 /* that any of the pushed arguments is larger than 0xFF, */
423 /* thus we refrain from further optimizing this case */
429 for (i
= 0; i
< num_args
; i
+= 255)
431 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
434 BCI(PUSHW_1
- 1 + nargs
);
440 for (j
= 0; j
< nargs
; j
++)
450 for (i
= 0; i
< num_args
; i
+= 255)
452 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
455 BCI(PUSHB_1
- 1 + nargs
);
461 for (j
= 0; j
< nargs
; j
++)
471 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
472 if (num_stack_elements
> sfnt
->max_stack_elements
)
473 sfnt
->max_stack_elements
= num_stack_elements
;
482 TA_font_build_subglyph_shifter(FONT
* font
,
485 FT_Face face
= font
->loader
->face
;
486 FT_GlyphSlot glyph
= face
->glyph
;
488 TA_GlyphLoader gloader
= font
->loader
->gloader
;
490 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
491 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
492 TA_SubGlyph subglyph
;
494 FT_Int curr_contour
= 0;
497 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
501 FT_UShort flags
= subglyph
->flags
;
502 FT_Pos y_offset
= subglyph
->arg2
;
507 /* load subglyph to get the number of contours */
508 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
511 num_contours
= glyph
->outline
.n_contours
;
513 /* nothing to do if there is a point-to-point alignment */
514 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
517 /* nothing to do if y offset is zero */
521 /* nothing to do if there are no contours */
525 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
526 /* ensures that composite subglyphs are represented as simple glyphs */
528 if (num_contours
> 0xFF
529 || curr_contour
> 0xFF)
532 BCI(HIGH(curr_contour
));
533 BCI(LOW(curr_contour
));
534 BCI(HIGH(num_contours
));
535 BCI(LOW(num_contours
));
544 /* there are high chances that this value needs PUSHW, */
545 /* thus we handle it separately */
546 if (y_offset
> 0xFF || y_offset
< 0)
559 BCI(bci_shift_subglyph
);
563 curr_contour
+= num_contours
;
571 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
572 * data in four arrays (which are simple but waste a lot of memory). The
573 * function below converts them into bytecode.
575 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
576 * together with the edge they correspond to.
578 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
579 * loop over the edge or edge pairs, respectively, and each edge or edge
580 * pair contains an inner loop to emit the correponding points.
584 TA_build_point_hints(Recorder
* recorder
,
587 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
588 TA_Segment segments
= axis
->segments
;
589 TA_Edge edges
= axis
->edges
;
595 FT_Byte
* p
= recorder
->hints_record
.buf
;
596 FT_UInt num_edges
= axis
->num_edges
;
597 FT_UInt num_strong_points
= recorder
->num_strong_points
;
611 /* we store everything as 16bit numbers; */
612 /* the function numbers (`ta_ip_before', etc.) */
613 /* reflect the order in the TA_Action enumeration */
615 /* ip_before_points */
618 ip
= recorder
->ip_before_points
;
619 ip_limit
= ip
+ num_strong_points
;
620 for (; ip
< ip_limit
; ip
++)
630 recorder
->hints_record
.num_actions
++;
635 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
636 *(p
++) = HIGH(edge
->first
- segments
);
637 *(p
++) = LOW(edge
->first
- segments
);
641 ip
= recorder
->ip_before_points
;
643 for (; ip
< ip_limit
; ip
++)
645 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
648 *(p
++) = HIGH(point
);
653 /* ip_after_points */
656 ip
= recorder
->ip_after_points
;
657 ip_limit
= ip
+ num_strong_points
;
658 for (; ip
< ip_limit
; ip
++)
668 recorder
->hints_record
.num_actions
++;
670 edge
= edges
+ axis
->num_edges
- 1;
673 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
674 *(p
++) = HIGH(edge
->first
- segments
);
675 *(p
++) = LOW(edge
->first
- segments
);
679 ip
= recorder
->ip_after_points
;
681 for (; ip
< ip_limit
; ip
++)
683 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
686 *(p
++) = HIGH(point
);
691 /* ip_on_point_array */
694 ip
= recorder
->ip_on_point_array
;
695 ip_limit
= ip
+ num_edges
* num_strong_points
;
696 for (; ip
< ip_limit
; ip
+= num_strong_points
)
702 recorder
->hints_record
.num_actions
++;
705 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
710 ip
= recorder
->ip_on_point_array
;
711 ip_limit
= ip
+ num_edges
* num_strong_points
;
712 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
719 *(p
++) = HIGH(edge
->first
- segments
);
720 *(p
++) = LOW(edge
->first
- segments
);
724 iq_limit
= iq
+ num_strong_points
;
725 for (; iq
< iq_limit
; iq
++)
738 for (; iq
< iq_limit
; iq
++)
740 FT_UInt point
= TA_adjust_point_index(recorder
, *iq
);
743 *(p
++) = HIGH(point
);
749 /* ip_between_point_array */
752 ip
= recorder
->ip_between_point_array
;
753 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
754 for (; ip
< ip_limit
; ip
+= num_strong_points
)
760 recorder
->hints_record
.num_actions
++;
763 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
768 ip
= recorder
->ip_between_point_array
;
769 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
772 ip
+= num_edges
* num_strong_points
, i
++)
778 iq_limit
= iq
+ num_edges
* num_strong_points
;
779 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
786 *(p
++) = HIGH(after
->first
- segments
);
787 *(p
++) = LOW(after
->first
- segments
);
788 *(p
++) = HIGH(before
->first
- segments
);
789 *(p
++) = LOW(before
->first
- segments
);
793 ir_limit
= ir
+ num_strong_points
;
794 for (; ir
< ir_limit
; ir
++)
807 for (; ir
< ir_limit
; ir
++)
809 FT_UInt point
= TA_adjust_point_index(recorder
, *ir
);
812 *(p
++) = HIGH(point
);
819 recorder
->hints_record
.buf
= p
;
824 TA_hints_record_is_different(Hints_Record
* hints_records
,
825 FT_UInt num_hints_records
,
829 Hints_Record last_hints_record
;
835 /* we only need to compare with the last hints record */
836 last_hints_record
= hints_records
[num_hints_records
- 1];
838 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
841 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
849 TA_add_hints_record(Hints_Record
** hints_records
,
850 FT_UInt
* num_hints_records
,
852 Hints_Record hints_record
)
854 Hints_Record
* hints_records_new
;
856 /* at this point, `hints_record.buf' still points into `ins_buf' */
857 FT_Byte
* end
= hints_record
.buf
;
860 buf_len
= (FT_UInt
)(end
- start
);
862 /* now fill the structure completely */
863 hints_record
.buf_len
= buf_len
;
864 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
865 if (!hints_record
.buf
)
866 return FT_Err_Out_Of_Memory
;
868 memcpy(hints_record
.buf
, start
, buf_len
);
870 (*num_hints_records
)++;
872 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
873 * sizeof (Hints_Record
));
874 if (!hints_records_new
)
876 free(hints_record
.buf
);
877 (*num_hints_records
)--;
878 return FT_Err_Out_Of_Memory
;
881 *hints_records
= hints_records_new
;
883 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
890 TA_emit_hints_record(Recorder
* recorder
,
891 Hints_Record
* hints_record
,
896 FT_Bool need_words
= 0;
899 FT_UInt num_arguments
;
903 /* check whether any argument is larger than 0xFF */
904 endp
= hints_record
->buf
+ hints_record
->buf_len
;
905 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
909 /* with most fonts it is very rare */
910 /* that any of the pushed arguments is larger than 0xFF, */
911 /* thus we refrain from further optimizing this case */
913 num_arguments
= hints_record
->buf_len
/ 2;
918 for (i
= 0; i
< num_arguments
; i
+= 255)
920 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
924 for (j
= 0; j
< num_args
; j
++)
934 /* we only need the lower bytes */
937 for (i
= 0; i
< num_arguments
; i
+= 255)
939 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
943 for (j
= 0; j
< num_args
; j
++)
951 /* collect stack depth data */
952 if (num_arguments
> recorder
->num_stack_elements
)
953 recorder
->num_stack_elements
= num_arguments
;
960 TA_emit_hints_records(Recorder
* recorder
,
961 Hints_Record
* hints_records
,
962 FT_UInt num_hints_records
,
966 Hints_Record
* hints_record
;
969 hints_record
= hints_records
;
971 for (i
= 0; i
< num_hints_records
- 1; i
++)
974 if (hints_record
->size
> 0xFF)
977 BCI(HIGH((hints_record
+ 1)->size
));
978 BCI(LOW((hints_record
+ 1)->size
));
983 BCI((hints_record
+ 1)->size
);
987 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
);
993 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
);
995 for (i
= 0; i
< num_hints_records
- 1; i
++)
1003 TA_free_hints_records(Hints_Record
* hints_records
,
1004 FT_UInt num_hints_records
)
1009 for (i
= 0; i
< num_hints_records
; i
++)
1010 free(hints_records
[i
].buf
);
1012 free(hints_records
);
1017 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1022 TA_Segment segments
= axis
->segments
;
1025 FT_UInt num_segs
= 0;
1029 seg_idx
= edge
->first
- segments
;
1031 /* we store everything as 16bit numbers */
1032 *(bufp
++) = HIGH(seg_idx
);
1033 *(bufp
++) = LOW(seg_idx
);
1035 /* wrap-around segments are stored as two segments */
1036 if (edge
->first
->first
> edge
->first
->last
)
1039 seg
= edge
->first
->edge_next
;
1040 while (seg
!= edge
->first
)
1044 if (seg
->first
> seg
->last
)
1047 seg
= seg
->edge_next
;
1050 *(bufp
++) = HIGH(num_segs
);
1051 *(bufp
++) = LOW(num_segs
);
1053 if (edge
->first
->first
> edge
->first
->last
)
1055 /* emit second part of wrap-around segment; */
1056 /* the bytecode positions such segments after `normal' ones */
1060 if (seg_idx
== *wrap
)
1065 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1066 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1069 seg
= edge
->first
->edge_next
;
1070 while (seg
!= edge
->first
)
1072 seg_idx
= seg
- segments
;
1074 *(bufp
++) = HIGH(seg_idx
);
1075 *(bufp
++) = LOW(seg_idx
);
1077 if (seg
->first
> seg
->last
)
1082 if (seg_idx
== *wrap
)
1087 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1088 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1091 seg
= seg
->edge_next
;
1099 TA_hints_recorder(TA_Action action
,
1100 TA_GlyphHints hints
,
1105 TA_Edge lower_bound
,
1106 TA_Edge upper_bound
)
1108 TA_AxisHints axis
= &hints
->axis
[dim
];
1109 TA_Edge edges
= axis
->edges
;
1110 TA_Segment segments
= axis
->segments
;
1111 TA_Point points
= hints
->points
;
1113 Recorder
* recorder
= (Recorder
*)hints
->user
;
1114 FONT
* font
= recorder
->font
;
1115 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
1116 FT_Byte
* p
= recorder
->hints_record
.buf
;
1122 if (dim
== TA_DIMENSION_HORZ
)
1125 /* we collect point hints for later processing */
1130 TA_Point point
= (TA_Point
)arg1
;
1133 ip
= recorder
->ip_before_points
;
1134 limit
= ip
+ recorder
->num_strong_points
;
1135 for (; ip
< limit
; ip
++)
1139 *ip
= point
- points
;
1148 TA_Point point
= (TA_Point
)arg1
;
1151 ip
= recorder
->ip_after_points
;
1152 limit
= ip
+ recorder
->num_strong_points
;
1153 for (; ip
< limit
; ip
++)
1157 *ip
= point
- points
;
1166 TA_Point point
= (TA_Point
)arg1
;
1167 TA_Edge edge
= arg2
;
1170 ip
= recorder
->ip_on_point_array
1171 + recorder
->num_strong_points
1173 limit
= ip
+ recorder
->num_strong_points
;
1174 for (; ip
< limit
; ip
++)
1178 *ip
= point
- points
;
1187 TA_Point point
= (TA_Point
)arg1
;
1188 TA_Edge before
= arg2
;
1189 TA_Edge after
= arg3
;
1192 /* note that `recorder->num_segments' has been used for allocation, */
1193 /* but `axis->num_edges' is used for accessing this array */
1194 ip
= recorder
->ip_between_point_array
1195 + recorder
->num_strong_points
* axis
->num_edges
1197 + recorder
->num_strong_points
1199 limit
= ip
+ recorder
->num_strong_points
;
1200 for (; ip
< limit
; ip
++)
1204 *ip
= point
- points
;
1212 /* we ignore the BOUND action since we signal this information */
1213 /* with the proper function number */
1220 /* some enum values correspond to four or eight bytecode functions; */
1221 /* if the value is n, the function numbers are n, ..., n+7, */
1222 /* to be differentiated with flags */
1228 TA_Edge base_edge
= (TA_Edge
)arg1
;
1229 TA_Edge stem_edge
= arg2
;
1233 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1234 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1235 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1237 *(p
++) = HIGH(base_edge
->first
- segments
);
1238 *(p
++) = LOW(base_edge
->first
- segments
);
1239 *(p
++) = HIGH(stem_edge
->first
- segments
);
1240 *(p
++) = LOW(stem_edge
->first
- segments
);
1242 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1248 TA_Edge edge
= (TA_Edge
)arg1
;
1249 TA_Edge edge2
= arg2
;
1253 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1254 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1255 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1257 *(p
++) = HIGH(edge
->first
- segments
);
1258 *(p
++) = LOW(edge
->first
- segments
);
1259 *(p
++) = HIGH(edge2
->first
- segments
);
1260 *(p
++) = LOW(edge2
->first
- segments
);
1262 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1268 TA_Edge edge
= (TA_Edge
)arg1
;
1269 TA_Edge edge2
= arg2
;
1270 TA_Edge edge_minus_one
= lower_bound
;
1274 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1275 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1276 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1277 + 4 * (edge_minus_one
!= NULL
);
1279 *(p
++) = HIGH(edge
->first
- segments
);
1280 *(p
++) = LOW(edge
->first
- segments
);
1281 *(p
++) = HIGH(edge2
->first
- segments
);
1282 *(p
++) = LOW(edge2
->first
- segments
);
1286 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1287 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1290 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1294 case ta_blue_anchor
:
1296 TA_Edge edge
= (TA_Edge
)arg1
;
1297 TA_Edge blue
= arg2
;
1301 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1303 *(p
++) = HIGH(blue
->first
- segments
);
1304 *(p
++) = LOW(blue
->first
- segments
);
1306 if (edge
->best_blue_is_shoot
)
1308 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1309 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1313 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1314 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1317 *(p
++) = HIGH(edge
->first
- segments
);
1318 *(p
++) = LOW(edge
->first
- segments
);
1320 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1326 TA_Edge edge
= (TA_Edge
)arg1
;
1327 TA_Edge edge2
= arg2
;
1328 TA_Edge edge_minus_one
= lower_bound
;
1332 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1333 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1334 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1335 + 4 * (edge_minus_one
!= NULL
);
1337 *(p
++) = HIGH(edge
->first
- segments
);
1338 *(p
++) = LOW(edge
->first
- segments
);
1339 *(p
++) = HIGH(edge2
->first
- segments
);
1340 *(p
++) = LOW(edge2
->first
- segments
);
1344 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1345 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1348 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1349 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1355 TA_Edge edge
= (TA_Edge
)arg1
;
1359 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1361 if (edge
->best_blue_is_shoot
)
1363 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1364 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1368 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1369 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1372 *(p
++) = HIGH(edge
->first
- segments
);
1373 *(p
++) = LOW(edge
->first
- segments
);
1375 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1381 TA_Edge serif
= (TA_Edge
)arg1
;
1382 TA_Edge base
= serif
->serif
;
1386 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1387 + (lower_bound
!= NULL
)
1388 + 2 * (upper_bound
!= NULL
);
1390 *(p
++) = HIGH(serif
->first
- segments
);
1391 *(p
++) = LOW(serif
->first
- segments
);
1392 *(p
++) = HIGH(base
->first
- segments
);
1393 *(p
++) = LOW(base
->first
- segments
);
1397 *(p
++) = HIGH(lower_bound
->first
- segments
);
1398 *(p
++) = LOW(lower_bound
->first
- segments
);
1402 *(p
++) = HIGH(upper_bound
->first
- segments
);
1403 *(p
++) = LOW(upper_bound
->first
- segments
);
1406 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1410 case ta_serif_anchor
:
1411 case ta_serif_link2
:
1413 TA_Edge edge
= (TA_Edge
)arg1
;
1417 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1418 + (lower_bound
!= NULL
)
1419 + 2 * (upper_bound
!= NULL
);
1421 *(p
++) = HIGH(edge
->first
- segments
);
1422 *(p
++) = LOW(edge
->first
- segments
);
1426 *(p
++) = HIGH(lower_bound
->first
- segments
);
1427 *(p
++) = LOW(lower_bound
->first
- segments
);
1431 *(p
++) = HIGH(upper_bound
->first
- segments
);
1432 *(p
++) = LOW(upper_bound
->first
- segments
);
1435 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1439 case ta_serif_link1
:
1441 TA_Edge edge
= (TA_Edge
)arg1
;
1442 TA_Edge before
= arg2
;
1443 TA_Edge after
= arg3
;
1447 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1448 + (lower_bound
!= NULL
)
1449 + 2 * (upper_bound
!= NULL
);
1451 *(p
++) = HIGH(before
->first
- segments
);
1452 *(p
++) = LOW(before
->first
- segments
);
1453 *(p
++) = HIGH(edge
->first
- segments
);
1454 *(p
++) = LOW(edge
->first
- segments
);
1455 *(p
++) = HIGH(after
->first
- segments
);
1456 *(p
++) = LOW(after
->first
- segments
);
1460 *(p
++) = HIGH(lower_bound
->first
- segments
);
1461 *(p
++) = LOW(lower_bound
->first
- segments
);
1465 *(p
++) = HIGH(upper_bound
->first
- segments
);
1466 *(p
++) = LOW(upper_bound
->first
- segments
);
1469 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1474 /* there are more cases in the enumeration */
1475 /* which are handled with flags */
1479 recorder
->hints_record
.num_actions
++;
1480 recorder
->hints_record
.buf
= p
;
1485 TA_init_recorder(Recorder
* recorder
,
1488 TA_GlyphHints hints
)
1490 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1491 TA_Point points
= hints
->points
;
1492 TA_Point point_limit
= points
+ hints
->num_points
;
1495 TA_Segment segments
= axis
->segments
;
1496 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1499 FT_UInt num_strong_points
= 0;
1500 FT_UInt
* wrap_around_segment
;
1502 recorder
->font
= font
;
1503 recorder
->glyph
= glyph
;
1504 recorder
->num_segments
= axis
->num_segments
;
1506 recorder
->ip_before_points
= NULL
;
1507 recorder
->ip_after_points
= NULL
;
1508 recorder
->ip_on_point_array
= NULL
;
1509 recorder
->ip_between_point_array
= NULL
;
1511 recorder
->num_stack_elements
= 0;
1513 /* no need to clean up allocated arrays in case of error; */
1514 /* this is handled later by `TA_free_recorder' */
1516 recorder
->num_wrap_around_segments
= 0;
1517 for (seg
= segments
; seg
< seg_limit
; seg
++)
1518 if (seg
->first
> seg
->last
)
1519 recorder
->num_wrap_around_segments
++;
1521 recorder
->wrap_around_segments
=
1522 (FT_UInt
*)malloc(recorder
->num_wrap_around_segments
* sizeof (FT_UInt
));
1523 if (!recorder
->wrap_around_segments
)
1524 return FT_Err_Out_Of_Memory
;
1526 wrap_around_segment
= recorder
->wrap_around_segments
;
1527 for (seg
= segments
; seg
< seg_limit
; seg
++)
1528 if (seg
->first
> seg
->last
)
1529 *(wrap_around_segment
++) = seg
- segments
;
1531 /* get number of strong points */
1532 for (point
= points
; point
< point_limit
; point
++)
1534 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1535 /* however, this value isn't known yet */
1536 /* (or rather, it can vary between different pixel sizes) */
1537 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1540 num_strong_points
++;
1543 recorder
->num_strong_points
= num_strong_points
;
1545 recorder
->ip_before_points
=
1546 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1547 if (!recorder
->ip_before_points
)
1548 return FT_Err_Out_Of_Memory
;
1550 recorder
->ip_after_points
=
1551 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1552 if (!recorder
->ip_after_points
)
1553 return FT_Err_Out_Of_Memory
;
1555 /* actually, we need `hints->num_edges' for the array sizes; */
1556 /* however, this value isn't known yet */
1557 /* (or rather, it can vary between different pixel sizes) */
1558 recorder
->ip_on_point_array
=
1559 (FT_UInt
*)malloc(axis
->num_segments
1560 * num_strong_points
* sizeof (FT_UInt
));
1561 if (!recorder
->ip_on_point_array
)
1562 return FT_Err_Out_Of_Memory
;
1564 recorder
->ip_between_point_array
=
1565 (FT_UInt
*)malloc(axis
->num_segments
* axis
->num_segments
1566 * num_strong_points
* sizeof (FT_UInt
));
1567 if (!recorder
->ip_between_point_array
)
1568 return FT_Err_Out_Of_Memory
;
1575 TA_reset_recorder(Recorder
* recorder
,
1578 recorder
->hints_record
.buf
= bufp
;
1579 recorder
->hints_record
.num_actions
= 0;
1584 TA_rewind_recorder(Recorder
* recorder
,
1588 TA_reset_recorder(recorder
, bufp
);
1590 recorder
->hints_record
.size
= size
;
1592 /* We later check with MISSING (which expands to 0xFF bytes) */
1594 memset(recorder
->ip_before_points
, 0xFF,
1595 recorder
->num_strong_points
* sizeof (FT_UInt
));
1596 memset(recorder
->ip_after_points
, 0xFF,
1597 recorder
->num_strong_points
* sizeof (FT_UInt
));
1599 memset(recorder
->ip_on_point_array
, 0xFF,
1600 recorder
->num_segments
1601 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1602 memset(recorder
->ip_between_point_array
, 0xFF,
1603 recorder
->num_segments
* recorder
->num_segments
1604 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1609 TA_free_recorder(Recorder
* recorder
)
1611 free(recorder
->wrap_around_segments
);
1613 free(recorder
->ip_before_points
);
1614 free(recorder
->ip_after_points
);
1615 free(recorder
->ip_on_point_array
);
1616 free(recorder
->ip_between_point_array
);
1621 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1625 FT_Face face
= sfnt
->face
;
1633 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1634 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1635 /* `idx' is never negative */
1636 GLYPH
* glyph
= &data
->glyphs
[idx
];
1638 TA_GlyphHints hints
;
1640 FT_UInt num_action_hints_records
;
1641 FT_UInt num_point_hints_records
;
1642 Hints_Record
* action_hints_records
;
1643 Hints_Record
* point_hints_records
;
1646 FT_UInt num_stack_elements
;
1648 FT_Int32 load_flags
;
1654 /* XXX: right now, we abuse this flag to control */
1655 /* the global behaviour of the auto-hinter */
1656 load_flags
= font
->fallback_script
<< 30;
1657 load_flags
|= 1 << 28; /* vertical hinting only */
1658 if (font
->increase_x_height
)
1659 load_flags
|= 1 << 29;
1660 if (!font
->pre_hinting
)
1661 load_flags
|= FT_LOAD_NO_SCALE
;
1663 /* computing the segments is resolution independent, */
1664 /* thus the pixel size in this call is arbitrary */
1665 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1669 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1670 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, load_flags
);
1674 /* do nothing if we have an empty glyph */
1675 if (!face
->glyph
->outline
.n_contours
)
1678 hints
= &font
->loader
->hints
;
1680 /* do nothing if the setup delivered the dummy module only */
1681 if (!hints
->num_points
)
1684 /* we allocate a buffer which is certainly large enough */
1685 /* to hold all of the created bytecode instructions; */
1686 /* later on it gets reallocated to its real size */
1687 ins_len
= hints
->num_points
* 1000;
1688 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1690 return FT_Err_Out_Of_Memory
;
1692 /* initialize array with an invalid bytecode */
1693 /* so that we can easily find the array length at reallocation time */
1694 memset(ins_buf
, INS_A0
, ins_len
);
1696 /* handle composite glyph */
1697 if (font
->loader
->gloader
->base
.num_subglyphs
)
1699 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1702 error
= FT_Err_Out_Of_Memory
;
1709 /* only scale the glyph if the dummy hinter has been used */
1710 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
1712 /* since `TA_init_recorder' hasn't been called yet, */
1713 /* we manually initialize the `glyph' field */
1714 recorder
.glyph
= glyph
;
1716 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1719 error
= FT_Err_Out_Of_Memory
;
1726 error
= TA_init_recorder(&recorder
, font
, glyph
, hints
);
1730 /* loop over a large range of pixel sizes */
1731 /* to find hints records which get pushed onto the bytecode stack */
1738 num_chars
= fprintf(stderr
, "glyph %ld\n", idx
);
1739 for (i
= 0; i
< num_chars
- 1; i
++)
1741 fprintf(stderr
, "\n\n");
1746 /* we temporarily use `ins_buf' to record the current glyph hints */
1747 ta_loader_register_hints_recorder(font
->loader
,
1751 num_action_hints_records
= 0;
1752 num_point_hints_records
= 0;
1753 action_hints_records
= NULL
;
1754 point_hints_records
= NULL
;
1756 for (size
= font
->hinting_range_min
;
1757 size
<= font
->hinting_range_max
;
1765 TA_rewind_recorder(&recorder
, ins_buf
, size
);
1767 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1771 /* calling `ta_loader_load_glyph' uses the */
1772 /* `TA_hints_recorder' function as a callback, */
1773 /* modifying `hints_record' */
1774 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, load_flags
);
1778 if (TA_hints_record_is_different(action_hints_records
,
1779 num_action_hints_records
,
1780 ins_buf
, recorder
.hints_record
.buf
))
1786 fprintf(stderr
, " size %d:\n", size
);
1788 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1789 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1790 ta_glyph_hints_dump_points(_ta_debug_hints
);
1792 fprintf(stderr
, " action hints record:\n");
1793 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1794 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1795 fprintf(stderr
, "\n");
1799 error
= TA_add_hints_record(&action_hints_records
,
1800 &num_action_hints_records
,
1801 ins_buf
, recorder
.hints_record
);
1806 /* now handle point records */
1808 TA_reset_recorder(&recorder
, ins_buf
);
1810 /* use the point hints data collected in `TA_hints_recorder' */
1811 TA_build_point_hints(&recorder
, hints
);
1813 if (TA_hints_record_is_different(point_hints_records
,
1814 num_point_hints_records
,
1815 ins_buf
, recorder
.hints_record
.buf
))
1821 fprintf(stderr
, " size %d:\n", size
);
1823 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1824 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1825 ta_glyph_hints_dump_points(_ta_debug_hints
);
1828 fprintf(stderr
, " point hints record:\n");
1829 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1830 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1831 fprintf(stderr
, "\n");
1835 error
= TA_add_hints_record(&point_hints_records
,
1836 &num_point_hints_records
,
1837 ins_buf
, recorder
.hints_record
);
1843 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
1845 /* since we only have a single empty record we just scale the glyph */
1846 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1849 error
= FT_Err_Out_Of_Memory
;
1853 /* clear the rest of the temporarily used part of `ins_buf' */
1855 while (*p
!= INS_A0
)
1861 /* store the hints records and handle stack depth */
1863 bufp
= TA_emit_hints_records(&recorder
,
1864 point_hints_records
,
1865 num_point_hints_records
,
1868 num_stack_elements
= recorder
.num_stack_elements
;
1869 recorder
.num_stack_elements
= 0;
1872 bufp
= TA_emit_hints_records(&recorder
,
1873 action_hints_records
,
1874 num_action_hints_records
,
1876 recorder
.num_stack_elements
+= num_stack_elements
;
1879 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
);
1882 error
= FT_Err_Out_Of_Memory
;
1886 /* XXX do nothing if we have NPUSHW in the data */
1887 if (num_action_hints_records
== 1
1888 && *(pos
[0]) != NPUSHW
&& *(pos
[1]) != NPUSHW
&& *(pos
[2]) != NPUSHW
)
1891 * we optimize two common cases, replacing
1893 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
1897 * NPUSHB (A+B[+C]) ... CALL
1910 /* the point hints records block can be missing */
1911 if (pos
[0] == pos
[1])
1917 /* there are at least two NPUSHB instructions */
1918 /* (one of them directly at the start) */
1919 sizes
[0] = *(pos
[0] + 1);
1920 sizes
[1] = *(pos
[1] + 1);
1921 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
1923 sum
= sizes
[0] + sizes
[1] + sizes
[2];
1926 goto Done2
; /* nothing to do since we need three NPUSHB */
1927 else if (!sizes
[2] && (sum
> 0xFF))
1928 goto Done2
; /* nothing to do since we need two NPUSHB */
1932 /* reduce three NPUSHB to two */
1934 new_size2
= sum
- 0xFF;
1938 /* reduce two or three NPUSHB to one */
1949 BCI(PUSHB_1
- 1 + new_size1
);
1955 for (i
= 0; i
< new_size1
; i
++)
1957 if (p
== pos
[pos_idx
])
1960 p
+= 2; /* skip old NPUSHB */
1968 BCI(PUSHB_1
- 1 + new_size2
);
1974 for (i
= 0; i
< new_size2
; i
++)
1976 if (p
== pos
[pos_idx
])
1989 /* clear the rest of the temporarily used part of `ins_buf' */
1991 while (*p
!= INS_A0
)
1995 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
1996 TA_free_recorder(&recorder
);
1998 /* we are done, so reallocate the instruction array to its real size */
1999 if (*bufp
== INS_A0
)
2001 /* search backwards */
2002 while (*bufp
== INS_A0
)
2008 /* search forwards */
2009 while (*bufp
!= INS_A0
)
2014 ins_len
= bufp
- ins_buf
;
2016 if (ins_len
> sfnt
->max_instructions
)
2017 sfnt
->max_instructions
= ins_len
;
2019 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2020 glyph
->ins_len
= ins_len
;
2025 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2026 TA_free_recorder(&recorder
);
2033 /* end of tabytecode.c */