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.
20 #define MISSING (FT_UInt)~0
22 /* a simple macro to emit bytecode instructions */
23 #define BCI(code) *(bufp++) = (code)
25 /* we increase the stack depth by this amount */
26 #define ADDITIONAL_STACK_ELEMENTS 20
29 /* #define DEBUGGING */
34 int _ta_debug_disable_horz_hints
;
35 int _ta_debug_disable_vert_hints
;
36 int _ta_debug_disable_blue_hints
;
37 void* _ta_debug_hints
;
41 typedef struct Hints_Record_
49 typedef struct Recorder_
52 GLYPH
* glyph
; /* the current glyph */
53 Hints_Record hints_record
;
55 /* some segments can `wrap around' */
56 /* a contour's start point like 24-25-26-0-1-2 */
57 /* (there can be at most one such segment per contour); */
58 /* later on we append additional records */
59 /* to split them into 24-26 and 0-2 */
60 FT_UInt
* wrap_around_segments
;
61 FT_UInt num_wrap_around_segments
;
63 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
65 /* data necessary for strong point interpolation */
66 FT_UInt
* ip_before_points
;
67 FT_UInt
* ip_after_points
;
68 FT_UInt
* ip_on_point_array
;
69 FT_UInt
* ip_between_point_array
;
71 FT_UInt num_strong_points
;
76 /* We add a subglyph for each composite glyph. */
77 /* Since subglyphs must contain at least one point, */
78 /* we have to adjust all point indices accordingly. */
79 /* Using the `pointsums' array of the `GLYPH' structure */
80 /* it is straightforward to do that: */
81 /* Assuming that point with index x is in the interval */
82 /* pointsums[n] <= x < pointsums[n + 1], */
83 /* the new point index is x + n. */
86 TA_adjust_point_index(Recorder
* recorder
,
89 GLYPH
* glyph
= recorder
->glyph
;
93 if (!glyph
->num_components
)
94 return idx
; /* not a composite glyph */
96 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
97 if (idx
< glyph
->pointsums
[i
])
104 /* we store the segments in the storage area; */
105 /* each segment record consists of the first and last point */
108 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
112 FONT
* font
= recorder
->font
;
113 TA_GlyphHints hints
= &font
->loader
->hints
;
114 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
115 TA_Point points
= hints
->points
;
116 TA_Segment segments
= axis
->segments
;
118 TA_Segment seg_limit
;
120 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
126 FT_UInt num_segments
;
128 FT_Bool need_words
= 0;
133 FT_UInt num_packed_segments
;
135 FT_UInt num_stack_elements
;
136 FT_UInt num_twilight_points
;
139 seg_limit
= segments
+ axis
->num_segments
;
140 num_segments
= axis
->num_segments
;
142 /* to pack the data in the bytecode more tightly, */
143 /* we store up to the first nine segments in nibbles if possible, */
144 /* using delta values */
146 num_packed_segments
= 0;
147 for (seg
= segments
; seg
< seg_limit
; seg
++)
149 FT_UInt first
= seg
->first
- points
;
150 FT_UInt last
= seg
->last
- points
;
153 first
= TA_adjust_point_index(recorder
, first
);
154 last
= TA_adjust_point_index(recorder
, last
);
156 if (first
- base
>= 16)
158 if (first
> last
|| last
- first
>= 16)
160 if (num_packed_segments
== 9)
162 num_packed_segments
++;
166 /* also handle wrap-around segments */
167 num_segments
+= recorder
->num_wrap_around_segments
;
169 /* wrap-around segments are pushed with four arguments; */
170 /* a segment stored in nibbles needs only one byte instead of two */
171 num_args
= num_packed_segments
172 + 2 * (num_segments
- num_packed_segments
)
173 + 2 * recorder
->num_wrap_around_segments
176 /* collect all arguments temporarily in an array (in reverse order) */
177 /* so that we can easily split into chunks of 255 args */
178 /* as needed by NPUSHB and NPUSHW, respectively */
179 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
183 arg
= args
+ num_args
- 1;
185 if (num_segments
> 0xFF)
188 /* the number of packed segments is indicated by the function number */
189 if (recorder
->glyph
->num_components
)
190 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
192 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
193 *(arg
--) = num_segments
;
196 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
198 FT_UInt first
= seg
->first
- points
;
199 FT_UInt last
= seg
->last
- points
;
204 first
= TA_adjust_point_index(recorder
, first
);
205 last
= TA_adjust_point_index(recorder
, last
);
207 low_nibble
= first
- base
;
208 high_nibble
= last
- first
;
210 *(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
;
296 for (j
= 0; j
< nargs
; j
++)
306 for (i
= 0; i
< num_args
; i
+= 255)
308 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
312 for (j
= 0; j
< nargs
; j
++)
322 num_storage
= sal_segment_offset
+ num_segments
* 2;
323 if (num_storage
> sfnt
->max_storage
)
324 sfnt
->max_storage
= num_storage
;
326 num_twilight_points
= num_segments
* 2;
327 if (num_twilight_points
> sfnt
->max_twilight_points
)
328 sfnt
->max_twilight_points
= num_twilight_points
;
330 /* both this function and `TA_emit_hints_record' */
331 /* push data onto the stack */
332 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
333 + recorder
->num_stack_elements
+ num_args
;
334 if (num_stack_elements
> sfnt
->max_stack_elements
)
335 sfnt
->max_stack_elements
= num_stack_elements
;
344 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
348 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
349 FT_Vector
* points
= glyph
->outline
.points
;
350 FT_Int num_contours
= glyph
->outline
.n_contours
;
357 FT_Bool need_words
= 0;
361 FT_UInt num_stack_elements
;
364 num_args
= 2 * num_contours
+ 2;
366 /* collect all arguments temporarily in an array (in reverse order) */
367 /* so that we can easily split into chunks of 255 args */
368 /* as needed by NPUSHB and NPUSHW, respectively */
369 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
373 arg
= args
+ num_args
- 1;
378 if (recorder
->glyph
->num_components
)
379 *(arg
--) = bci_scale_composite_glyph
;
381 *(arg
--) = bci_scale_glyph
;
382 *(arg
--) = num_contours
;
387 for (p
= 0; p
< num_contours
; p
++)
393 end
= glyph
->outline
.contours
[p
];
395 for (q
= start
; q
<= end
; q
++)
397 if (points
[q
].y
< points
[min
].y
)
399 if (points
[q
].y
> points
[max
].y
)
405 *(arg
--) = TA_adjust_point_index(recorder
, max
);
406 *(arg
--) = TA_adjust_point_index(recorder
, min
);
410 *(arg
--) = TA_adjust_point_index(recorder
, min
);
411 *(arg
--) = TA_adjust_point_index(recorder
, max
);
420 /* with most fonts it is very rare */
421 /* that any of the pushed arguments is larger than 0xFF, */
422 /* thus we refrain from further optimizing this case */
428 for (i
= 0; i
< num_args
; i
+= 255)
430 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
434 for (j
= 0; j
< nargs
; j
++)
444 for (i
= 0; i
< num_args
; i
+= 255)
446 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
450 for (j
= 0; j
< nargs
; j
++)
460 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
461 if (num_stack_elements
> sfnt
->max_stack_elements
)
462 sfnt
->max_stack_elements
= num_stack_elements
;
471 TA_font_build_subglyph_shifter(FONT
* font
,
474 FT_Face face
= font
->loader
->face
;
475 FT_GlyphSlot glyph
= face
->glyph
;
477 TA_GlyphLoader gloader
= font
->loader
->gloader
;
479 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
480 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
481 TA_SubGlyph subglyph
;
483 FT_Int curr_contour
= 0;
486 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
490 FT_UShort flags
= subglyph
->flags
;
491 FT_Pos y_offset
= subglyph
->arg2
;
496 /* load subglyph to get the number of contours */
497 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
500 num_contours
= glyph
->outline
.n_contours
;
502 /* nothing to do if there is a point-to-point alignment */
503 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
506 /* nothing to do if y offset is zero */
510 /* nothing to do if there are no contours */
514 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
515 /* ensures that composite subglyphs are represented as simple glyphs */
517 if (num_contours
> 0xFF
518 || curr_contour
> 0xFF)
521 BCI(HIGH(curr_contour
));
522 BCI(LOW(curr_contour
));
523 BCI(HIGH(num_contours
));
524 BCI(LOW(num_contours
));
533 /* there are high chances that this value needs PUSHW, */
534 /* thus we handle it separately */
535 if (y_offset
> 0xFF || y_offset
< 0)
548 BCI(bci_shift_subglyph
);
552 curr_contour
+= num_contours
;
560 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
561 * data in four arrays (which are simple but waste a lot of memory). The
562 * function below converts them into bytecode.
564 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
565 * together with the edge they correspond to.
567 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
568 * loop over the edge or edge pairs, respectively, and each edge or edge
569 * pair contains an inner loop to emit the correponding points.
573 TA_build_point_hints(Recorder
* recorder
,
576 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
577 TA_Segment segments
= axis
->segments
;
578 TA_Edge edges
= axis
->edges
;
584 FT_Byte
* p
= recorder
->hints_record
.buf
;
585 FT_UInt num_edges
= axis
->num_edges
;
586 FT_UInt num_strong_points
= recorder
->num_strong_points
;
600 /* we store everything as 16bit numbers; */
601 /* the function numbers (`ta_ip_before', etc.) */
602 /* reflect the order in the TA_Action enumeration */
604 /* ip_before_points */
607 ip
= recorder
->ip_before_points
;
608 ip_limit
= ip
+ num_strong_points
;
609 for (; ip
< ip_limit
; ip
++)
619 recorder
->hints_record
.num_actions
++;
624 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
625 *(p
++) = HIGH(edge
->first
- segments
);
626 *(p
++) = LOW(edge
->first
- segments
);
630 ip
= recorder
->ip_before_points
;
632 for (; ip
< ip_limit
; ip
++)
634 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
637 *(p
++) = HIGH(point
);
642 /* ip_after_points */
645 ip
= recorder
->ip_after_points
;
646 ip_limit
= ip
+ num_strong_points
;
647 for (; ip
< ip_limit
; ip
++)
657 recorder
->hints_record
.num_actions
++;
659 edge
= edges
+ axis
->num_edges
- 1;
662 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
663 *(p
++) = HIGH(edge
->first
- segments
);
664 *(p
++) = LOW(edge
->first
- segments
);
668 ip
= recorder
->ip_after_points
;
670 for (; ip
< ip_limit
; ip
++)
672 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
675 *(p
++) = HIGH(point
);
680 /* ip_on_point_array */
683 ip
= recorder
->ip_on_point_array
;
684 ip_limit
= ip
+ num_edges
* num_strong_points
;
685 for (; ip
< ip_limit
; ip
+= num_strong_points
)
691 recorder
->hints_record
.num_actions
++;
694 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
699 ip
= recorder
->ip_on_point_array
;
700 ip_limit
= ip
+ num_edges
* num_strong_points
;
701 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
708 *(p
++) = HIGH(edge
->first
- segments
);
709 *(p
++) = LOW(edge
->first
- segments
);
713 iq_limit
= iq
+ num_strong_points
;
714 for (; iq
< iq_limit
; iq
++)
727 for (; iq
< iq_limit
; iq
++)
729 FT_UInt point
= TA_adjust_point_index(recorder
, *iq
);
732 *(p
++) = HIGH(point
);
738 /* ip_between_point_array */
741 ip
= recorder
->ip_between_point_array
;
742 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
743 for (; ip
< ip_limit
; ip
+= num_strong_points
)
749 recorder
->hints_record
.num_actions
++;
752 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
757 ip
= recorder
->ip_between_point_array
;
758 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
761 ip
+= num_edges
* num_strong_points
, i
++)
767 iq_limit
= iq
+ num_edges
* num_strong_points
;
768 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
775 *(p
++) = HIGH(after
->first
- segments
);
776 *(p
++) = LOW(after
->first
- segments
);
777 *(p
++) = HIGH(before
->first
- segments
);
778 *(p
++) = LOW(before
->first
- segments
);
782 ir_limit
= ir
+ num_strong_points
;
783 for (; ir
< ir_limit
; ir
++)
796 for (; ir
< ir_limit
; ir
++)
798 FT_UInt point
= TA_adjust_point_index(recorder
, *ir
);
801 *(p
++) = HIGH(point
);
808 recorder
->hints_record
.buf
= p
;
813 TA_hints_record_is_different(Hints_Record
* hints_records
,
814 FT_UInt num_hints_records
,
818 Hints_Record last_hints_record
;
824 /* we only need to compare with the last hints record */
825 last_hints_record
= hints_records
[num_hints_records
- 1];
827 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
830 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
838 TA_add_hints_record(Hints_Record
** hints_records
,
839 FT_UInt
* num_hints_records
,
841 Hints_Record hints_record
)
843 Hints_Record
* hints_records_new
;
845 /* at this point, `hints_record.buf' still points into `ins_buf' */
846 FT_Byte
* end
= hints_record
.buf
;
849 buf_len
= (FT_UInt
)(end
- start
);
851 /* now fill the structure completely */
852 hints_record
.buf_len
= buf_len
;
853 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
854 if (!hints_record
.buf
)
855 return FT_Err_Out_Of_Memory
;
857 memcpy(hints_record
.buf
, start
, buf_len
);
859 (*num_hints_records
)++;
861 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
862 * sizeof (Hints_Record
));
863 if (!hints_records_new
)
865 free(hints_record
.buf
);
866 (*num_hints_records
)--;
867 return FT_Err_Out_Of_Memory
;
870 *hints_records
= hints_records_new
;
872 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
879 TA_emit_hints_record(Recorder
* recorder
,
880 Hints_Record
* hints_record
,
885 FT_Bool need_words
= 0;
888 FT_UInt num_arguments
;
892 /* check whether any argument is larger than 0xFF */
893 endp
= hints_record
->buf
+ hints_record
->buf_len
;
894 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
898 /* with most fonts it is very rare */
899 /* that any of the pushed arguments is larger than 0xFF, */
900 /* thus we refrain from further optimizing this case */
902 num_arguments
= hints_record
->buf_len
/ 2;
907 for (i
= 0; i
< num_arguments
; i
+= 255)
909 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
913 for (j
= 0; j
< num_args
; j
++)
923 /* we only need the lower bytes */
926 for (i
= 0; i
< num_arguments
; i
+= 255)
928 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
932 for (j
= 0; j
< num_args
; j
++)
940 /* collect stack depth data */
941 if (num_arguments
> recorder
->num_stack_elements
)
942 recorder
->num_stack_elements
= num_arguments
;
949 TA_emit_hints_records(Recorder
* recorder
,
950 Hints_Record
* hints_records
,
951 FT_UInt num_hints_records
,
955 Hints_Record
* hints_record
;
958 hints_record
= hints_records
;
960 for (i
= 0; i
< num_hints_records
- 1; i
++)
963 if (hints_record
->size
> 0xFF)
966 BCI(HIGH((hints_record
+ 1)->size
));
967 BCI(LOW((hints_record
+ 1)->size
));
972 BCI((hints_record
+ 1)->size
);
976 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
);
982 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
);
984 for (i
= 0; i
< num_hints_records
- 1; i
++)
992 TA_free_hints_records(Hints_Record
* hints_records
,
993 FT_UInt num_hints_records
)
998 for (i
= 0; i
< num_hints_records
; i
++)
999 free(hints_records
[i
].buf
);
1001 free(hints_records
);
1006 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1011 TA_Segment segments
= axis
->segments
;
1014 FT_UInt num_segs
= 0;
1018 seg_idx
= edge
->first
- segments
;
1020 /* we store everything as 16bit numbers */
1021 *(bufp
++) = HIGH(seg_idx
);
1022 *(bufp
++) = LOW(seg_idx
);
1024 /* wrap-around segments are stored as two segments */
1025 if (edge
->first
->first
> edge
->first
->last
)
1028 seg
= edge
->first
->edge_next
;
1029 while (seg
!= edge
->first
)
1033 if (seg
->first
> seg
->last
)
1036 seg
= seg
->edge_next
;
1039 *(bufp
++) = HIGH(num_segs
);
1040 *(bufp
++) = LOW(num_segs
);
1042 if (edge
->first
->first
> edge
->first
->last
)
1044 /* emit second part of wrap-around segment; */
1045 /* the bytecode positions such segments after `normal' ones */
1049 if (seg_idx
== *wrap
)
1054 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1055 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1058 seg
= edge
->first
->edge_next
;
1059 while (seg
!= edge
->first
)
1061 seg_idx
= seg
- segments
;
1063 *(bufp
++) = HIGH(seg_idx
);
1064 *(bufp
++) = LOW(seg_idx
);
1066 if (seg
->first
> seg
->last
)
1071 if (seg_idx
== *wrap
)
1076 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1077 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1080 seg
= seg
->edge_next
;
1088 TA_hints_recorder(TA_Action action
,
1089 TA_GlyphHints hints
,
1094 TA_Edge lower_bound
,
1095 TA_Edge upper_bound
)
1097 TA_AxisHints axis
= &hints
->axis
[dim
];
1098 TA_Edge edges
= axis
->edges
;
1099 TA_Segment segments
= axis
->segments
;
1100 TA_Point points
= hints
->points
;
1102 Recorder
* recorder
= (Recorder
*)hints
->user
;
1103 FONT
* font
= recorder
->font
;
1104 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
1105 FT_Byte
* p
= recorder
->hints_record
.buf
;
1111 if (dim
== TA_DIMENSION_HORZ
)
1114 /* we collect point hints for later processing */
1119 TA_Point point
= (TA_Point
)arg1
;
1122 ip
= recorder
->ip_before_points
;
1123 limit
= ip
+ recorder
->num_strong_points
;
1124 for (; ip
< limit
; ip
++)
1128 *ip
= point
- points
;
1137 TA_Point point
= (TA_Point
)arg1
;
1140 ip
= recorder
->ip_after_points
;
1141 limit
= ip
+ recorder
->num_strong_points
;
1142 for (; ip
< limit
; ip
++)
1146 *ip
= point
- points
;
1155 TA_Point point
= (TA_Point
)arg1
;
1156 TA_Edge edge
= arg2
;
1159 ip
= recorder
->ip_on_point_array
1160 + recorder
->num_strong_points
1162 limit
= ip
+ recorder
->num_strong_points
;
1163 for (; ip
< limit
; ip
++)
1167 *ip
= point
- points
;
1176 TA_Point point
= (TA_Point
)arg1
;
1177 TA_Edge before
= arg2
;
1178 TA_Edge after
= arg3
;
1181 /* note that `recorder->num_segments' has been used for allocation, */
1182 /* but `axis->num_edges' is used for accessing this array */
1183 ip
= recorder
->ip_between_point_array
1184 + recorder
->num_strong_points
* axis
->num_edges
1186 + recorder
->num_strong_points
1188 limit
= ip
+ recorder
->num_strong_points
;
1189 for (; ip
< limit
; ip
++)
1193 *ip
= point
- points
;
1201 /* we ignore the BOUND action since we signal this information */
1202 /* with the proper function number */
1209 /* some enum values correspond to four or eight bytecode functions; */
1210 /* if the value is n, the function numbers are n, ..., n+7, */
1211 /* to be differentiated with flags */
1217 TA_Edge base_edge
= (TA_Edge
)arg1
;
1218 TA_Edge stem_edge
= arg2
;
1222 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1223 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1224 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1226 *(p
++) = HIGH(base_edge
->first
- segments
);
1227 *(p
++) = LOW(base_edge
->first
- segments
);
1228 *(p
++) = HIGH(stem_edge
->first
- segments
);
1229 *(p
++) = LOW(stem_edge
->first
- segments
);
1231 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1237 TA_Edge edge
= (TA_Edge
)arg1
;
1238 TA_Edge edge2
= arg2
;
1242 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1243 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1244 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1246 *(p
++) = HIGH(edge
->first
- segments
);
1247 *(p
++) = LOW(edge
->first
- segments
);
1248 *(p
++) = HIGH(edge2
->first
- segments
);
1249 *(p
++) = LOW(edge2
->first
- segments
);
1251 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1257 TA_Edge edge
= (TA_Edge
)arg1
;
1258 TA_Edge edge2
= arg2
;
1259 TA_Edge edge_minus_one
= lower_bound
;
1263 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1264 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1265 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1266 + 4 * (edge_minus_one
!= NULL
);
1268 *(p
++) = HIGH(edge
->first
- segments
);
1269 *(p
++) = LOW(edge
->first
- segments
);
1270 *(p
++) = HIGH(edge2
->first
- segments
);
1271 *(p
++) = LOW(edge2
->first
- segments
);
1275 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1276 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1279 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1283 case ta_blue_anchor
:
1285 TA_Edge edge
= (TA_Edge
)arg1
;
1286 TA_Edge blue
= arg2
;
1290 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1292 *(p
++) = HIGH(blue
->first
- segments
);
1293 *(p
++) = LOW(blue
->first
- segments
);
1295 if (edge
->best_blue_is_shoot
)
1297 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1298 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1302 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1303 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1306 *(p
++) = HIGH(edge
->first
- segments
);
1307 *(p
++) = LOW(edge
->first
- segments
);
1309 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1315 TA_Edge edge
= (TA_Edge
)arg1
;
1316 TA_Edge edge2
= arg2
;
1317 TA_Edge edge_minus_one
= lower_bound
;
1321 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1322 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1323 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1324 + 4 * (edge_minus_one
!= NULL
);
1326 *(p
++) = HIGH(edge
->first
- segments
);
1327 *(p
++) = LOW(edge
->first
- segments
);
1328 *(p
++) = HIGH(edge2
->first
- segments
);
1329 *(p
++) = LOW(edge2
->first
- segments
);
1333 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1334 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1337 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1338 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1344 TA_Edge edge
= (TA_Edge
)arg1
;
1348 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1350 if (edge
->best_blue_is_shoot
)
1352 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1353 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1357 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1358 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1361 *(p
++) = HIGH(edge
->first
- segments
);
1362 *(p
++) = LOW(edge
->first
- segments
);
1364 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1370 TA_Edge serif
= (TA_Edge
)arg1
;
1371 TA_Edge base
= serif
->serif
;
1375 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1376 + (lower_bound
!= NULL
)
1377 + 2 * (upper_bound
!= NULL
);
1379 *(p
++) = HIGH(serif
->first
- segments
);
1380 *(p
++) = LOW(serif
->first
- segments
);
1381 *(p
++) = HIGH(base
->first
- segments
);
1382 *(p
++) = LOW(base
->first
- segments
);
1386 *(p
++) = HIGH(lower_bound
->first
- segments
);
1387 *(p
++) = LOW(lower_bound
->first
- segments
);
1391 *(p
++) = HIGH(upper_bound
->first
- segments
);
1392 *(p
++) = LOW(upper_bound
->first
- segments
);
1395 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1399 case ta_serif_anchor
:
1400 case ta_serif_link2
:
1402 TA_Edge edge
= (TA_Edge
)arg1
;
1406 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1407 + (lower_bound
!= NULL
)
1408 + 2 * (upper_bound
!= NULL
);
1410 *(p
++) = HIGH(edge
->first
- segments
);
1411 *(p
++) = LOW(edge
->first
- segments
);
1415 *(p
++) = HIGH(lower_bound
->first
- segments
);
1416 *(p
++) = LOW(lower_bound
->first
- segments
);
1420 *(p
++) = HIGH(upper_bound
->first
- segments
);
1421 *(p
++) = LOW(upper_bound
->first
- segments
);
1424 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1428 case ta_serif_link1
:
1430 TA_Edge edge
= (TA_Edge
)arg1
;
1431 TA_Edge before
= arg2
;
1432 TA_Edge after
= arg3
;
1436 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1437 + (lower_bound
!= NULL
)
1438 + 2 * (upper_bound
!= NULL
);
1440 *(p
++) = HIGH(before
->first
- segments
);
1441 *(p
++) = LOW(before
->first
- segments
);
1442 *(p
++) = HIGH(edge
->first
- segments
);
1443 *(p
++) = LOW(edge
->first
- segments
);
1444 *(p
++) = HIGH(after
->first
- segments
);
1445 *(p
++) = LOW(after
->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
);
1463 /* there are more cases in the enumeration */
1464 /* which are handled with flags */
1468 recorder
->hints_record
.num_actions
++;
1469 recorder
->hints_record
.buf
= p
;
1474 TA_init_recorder(Recorder
* recorder
,
1477 TA_GlyphHints hints
)
1479 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1480 TA_Point points
= hints
->points
;
1481 TA_Point point_limit
= points
+ hints
->num_points
;
1484 TA_Segment segments
= axis
->segments
;
1485 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1488 FT_UInt num_strong_points
= 0;
1489 FT_UInt
* wrap_around_segment
;
1491 recorder
->font
= font
;
1492 recorder
->glyph
= glyph
;
1493 recorder
->num_segments
= axis
->num_segments
;
1495 recorder
->ip_before_points
= NULL
;
1496 recorder
->ip_after_points
= NULL
;
1497 recorder
->ip_on_point_array
= NULL
;
1498 recorder
->ip_between_point_array
= NULL
;
1500 recorder
->num_stack_elements
= 0;
1502 /* no need to clean up allocated arrays in case of error; */
1503 /* this is handled later by `TA_free_recorder' */
1505 recorder
->num_wrap_around_segments
= 0;
1506 for (seg
= segments
; seg
< seg_limit
; seg
++)
1507 if (seg
->first
> seg
->last
)
1508 recorder
->num_wrap_around_segments
++;
1510 recorder
->wrap_around_segments
=
1511 (FT_UInt
*)malloc(recorder
->num_wrap_around_segments
* sizeof (FT_UInt
));
1512 if (!recorder
->wrap_around_segments
)
1513 return FT_Err_Out_Of_Memory
;
1515 wrap_around_segment
= recorder
->wrap_around_segments
;
1516 for (seg
= segments
; seg
< seg_limit
; seg
++)
1517 if (seg
->first
> seg
->last
)
1518 *(wrap_around_segment
++) = seg
- segments
;
1520 /* get number of strong points */
1521 for (point
= points
; point
< point_limit
; point
++)
1523 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1524 /* however, this value isn't known yet */
1525 /* (or rather, it can vary between different pixel sizes) */
1526 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1529 num_strong_points
++;
1532 recorder
->num_strong_points
= num_strong_points
;
1534 recorder
->ip_before_points
=
1535 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1536 if (!recorder
->ip_before_points
)
1537 return FT_Err_Out_Of_Memory
;
1539 recorder
->ip_after_points
=
1540 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1541 if (!recorder
->ip_after_points
)
1542 return FT_Err_Out_Of_Memory
;
1544 /* actually, we need `hints->num_edges' for the array sizes; */
1545 /* however, this value isn't known yet */
1546 /* (or rather, it can vary between different pixel sizes) */
1547 recorder
->ip_on_point_array
=
1548 (FT_UInt
*)malloc(axis
->num_segments
1549 * num_strong_points
* sizeof (FT_UInt
));
1550 if (!recorder
->ip_on_point_array
)
1551 return FT_Err_Out_Of_Memory
;
1553 recorder
->ip_between_point_array
=
1554 (FT_UInt
*)malloc(axis
->num_segments
* axis
->num_segments
1555 * num_strong_points
* sizeof (FT_UInt
));
1556 if (!recorder
->ip_between_point_array
)
1557 return FT_Err_Out_Of_Memory
;
1564 TA_reset_recorder(Recorder
* recorder
,
1567 recorder
->hints_record
.buf
= bufp
;
1568 recorder
->hints_record
.num_actions
= 0;
1573 TA_rewind_recorder(Recorder
* recorder
,
1577 TA_reset_recorder(recorder
, bufp
);
1579 recorder
->hints_record
.size
= size
;
1581 /* We later check with MISSING (which expands to 0xFF bytes) */
1583 memset(recorder
->ip_before_points
, 0xFF,
1584 recorder
->num_strong_points
* sizeof (FT_UInt
));
1585 memset(recorder
->ip_after_points
, 0xFF,
1586 recorder
->num_strong_points
* sizeof (FT_UInt
));
1588 memset(recorder
->ip_on_point_array
, 0xFF,
1589 recorder
->num_segments
1590 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1591 memset(recorder
->ip_between_point_array
, 0xFF,
1592 recorder
->num_segments
* recorder
->num_segments
1593 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1598 TA_free_recorder(Recorder
* recorder
)
1600 free(recorder
->wrap_around_segments
);
1602 free(recorder
->ip_before_points
);
1603 free(recorder
->ip_after_points
);
1604 free(recorder
->ip_on_point_array
);
1605 free(recorder
->ip_between_point_array
);
1610 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1614 FT_Face face
= sfnt
->face
;
1622 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1623 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1624 /* `idx' is never negative */
1625 GLYPH
* glyph
= &data
->glyphs
[idx
];
1627 TA_GlyphHints hints
;
1629 FT_UInt num_action_hints_records
;
1630 FT_UInt num_point_hints_records
;
1631 Hints_Record
* action_hints_records
;
1632 Hints_Record
* point_hints_records
;
1635 FT_UInt num_stack_elements
;
1637 FT_Int32 load_flags
;
1641 /* XXX: right now, we abuse this flag to control */
1642 /* the global behaviour of the auto-hinter */
1643 load_flags
= font
->fallback_script
<< 30;
1644 load_flags
|= 1 << 28; /* vertical hinting only */
1645 if (font
->increase_x_height
)
1646 load_flags
|= 1 << 29;
1647 if (!font
->pre_hinting
)
1648 load_flags
|= FT_LOAD_NO_SCALE
;
1650 /* computing the segments is resolution independent, */
1651 /* thus the pixel size in this call is arbitrary */
1652 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1656 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1657 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, load_flags
);
1661 /* do nothing if we have an empty glyph */
1662 if (!face
->glyph
->outline
.n_contours
)
1665 hints
= &font
->loader
->hints
;
1667 /* do nothing if the setup delivered the dummy module only */
1668 if (!hints
->num_points
)
1671 /* we allocate a buffer which is certainly large enough */
1672 /* to hold all of the created bytecode instructions; */
1673 /* later on it gets reallocated to its real size */
1674 ins_len
= hints
->num_points
* 1000;
1675 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1677 return FT_Err_Out_Of_Memory
;
1679 /* initialize array with an invalid bytecode */
1680 /* so that we can easily find the array length at reallocation time */
1681 memset(ins_buf
, INS_A0
, ins_len
);
1683 /* handle composite glyph */
1684 if (font
->loader
->gloader
->base
.num_subglyphs
)
1686 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1689 error
= FT_Err_Out_Of_Memory
;
1696 /* only scale the glyph if the dummy hinter has been used */
1697 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
1699 /* since `TA_init_recorder' hasn't been called yet, */
1700 /* we manually initialize the `glyph' field */
1701 recorder
.glyph
= glyph
;
1703 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1706 error
= FT_Err_Out_Of_Memory
;
1713 error
= TA_init_recorder(&recorder
, font
, glyph
, hints
);
1717 /* loop over a large range of pixel sizes */
1718 /* to find hints records which get pushed onto the bytecode stack */
1725 num_chars
= fprintf(stderr
, "glyph %ld\n", idx
);
1726 for (i
= 0; i
< num_chars
- 1; i
++)
1728 fprintf(stderr
, "\n\n");
1733 /* we temporarily use `ins_buf' to record the current glyph hints */
1734 ta_loader_register_hints_recorder(font
->loader
,
1738 num_action_hints_records
= 0;
1739 num_point_hints_records
= 0;
1740 action_hints_records
= NULL
;
1741 point_hints_records
= NULL
;
1743 for (size
= font
->hinting_range_min
;
1744 size
<= font
->hinting_range_max
;
1752 TA_rewind_recorder(&recorder
, ins_buf
, size
);
1754 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1758 /* calling `ta_loader_load_glyph' uses the */
1759 /* `TA_hints_recorder' function as a callback, */
1760 /* modifying `hints_record' */
1761 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, load_flags
);
1765 if (TA_hints_record_is_different(action_hints_records
,
1766 num_action_hints_records
,
1767 ins_buf
, recorder
.hints_record
.buf
))
1773 fprintf(stderr
, " size %d:\n", size
);
1775 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1776 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1777 ta_glyph_hints_dump_points(_ta_debug_hints
);
1779 fprintf(stderr
, " action hints record:\n");
1780 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1781 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1782 fprintf(stderr
, "\n");
1786 error
= TA_add_hints_record(&action_hints_records
,
1787 &num_action_hints_records
,
1788 ins_buf
, recorder
.hints_record
);
1793 /* now handle point records */
1795 TA_reset_recorder(&recorder
, ins_buf
);
1797 /* use the point hints data collected in `TA_hints_recorder' */
1798 TA_build_point_hints(&recorder
, hints
);
1800 if (TA_hints_record_is_different(point_hints_records
,
1801 num_point_hints_records
,
1802 ins_buf
, recorder
.hints_record
.buf
))
1808 fprintf(stderr
, " size %d:\n", size
);
1810 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1811 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1812 ta_glyph_hints_dump_points(_ta_debug_hints
);
1815 fprintf(stderr
, " point hints record:\n");
1816 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
1817 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1818 fprintf(stderr
, "\n");
1822 error
= TA_add_hints_record(&point_hints_records
,
1823 &num_point_hints_records
,
1824 ins_buf
, recorder
.hints_record
);
1830 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
1832 /* since we only have a single empty record we just scale the glyph */
1833 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1836 error
= FT_Err_Out_Of_Memory
;
1840 /* clear the rest of the temporarily used part of `ins_buf' */
1842 while (*p
!= INS_A0
)
1848 /* store the hints records and handle stack depth */
1849 bufp
= TA_emit_hints_records(&recorder
,
1850 point_hints_records
,
1851 num_point_hints_records
,
1853 num_stack_elements
= recorder
.num_stack_elements
;
1854 recorder
.num_stack_elements
= 0;
1855 bufp
= TA_emit_hints_records(&recorder
,
1856 action_hints_records
,
1857 num_action_hints_records
,
1859 recorder
.num_stack_elements
+= num_stack_elements
;
1861 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
);
1864 error
= FT_Err_Out_Of_Memory
;
1868 /* clear the rest of the temporarily used part of `ins_buf' */
1870 while (*p
!= INS_A0
)
1874 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
1875 TA_free_recorder(&recorder
);
1877 /* we are done, so reallocate the instruction array to its real size */
1878 if (*bufp
== INS_A0
)
1880 /* search backwards */
1881 while (*bufp
== INS_A0
)
1887 /* search forwards */
1888 while (*bufp
!= INS_A0
)
1893 ins_len
= bufp
- ins_buf
;
1895 if (ins_len
> sfnt
->max_instructions
)
1896 sfnt
->max_instructions
= ins_len
;
1898 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
1899 glyph
->ins_len
= ins_len
;
1904 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
1905 TA_free_recorder(&recorder
);
1912 /* end of tabytecode.c */