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 /* see explanations in `TA_sfnt_build_glyph_segments' */
56 FT_UInt
* wrap_around_segments
;
58 /* data necessary for strong point interpolation */
59 FT_UInt
* ip_before_points
;
60 FT_UInt
* ip_after_points
;
61 FT_UInt
* ip_on_point_array
;
62 FT_UInt
* ip_between_point_array
;
64 FT_UInt num_strong_points
;
69 /* We add a subglyph for each composite glyph. */
70 /* Since subglyphs must contain at least one point, */
71 /* we have to adjust all point indices accordingly. */
72 /* Using the `pointsums' array of the `GLYPH' structure */
73 /* it is straightforward to do that: */
74 /* Assuming that point with index x is in the interval */
75 /* pointsums[n] <= x < pointsums[n + 1], */
76 /* the new point index is x + n. */
79 TA_adjust_point_index(Recorder
* recorder
,
82 GLYPH
* glyph
= recorder
->glyph
;
86 if (!glyph
->num_components
)
87 return idx
; /* not a composite glyph */
89 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
90 if (idx
< glyph
->pointsums
[i
])
97 /* we store the segments in the storage area; */
98 /* each segment record consists of the first and last point */
101 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
105 FONT
* font
= recorder
->font
;
106 TA_GlyphHints hints
= &font
->loader
->hints
;
107 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
108 TA_Point points
= hints
->points
;
109 TA_Segment segments
= axis
->segments
;
111 TA_Segment seg_limit
;
113 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
119 FT_UInt num_segments
;
121 FT_UInt
* wrap_around_segment
;
122 FT_UInt num_wrap_around_segments
;
124 FT_Bool need_words
= 0;
129 FT_UInt num_stack_elements
;
130 FT_UInt num_twilight_points
;
133 seg_limit
= segments
+ axis
->num_segments
;
134 num_segments
= axis
->num_segments
;
136 /* some segments can `wrap around' */
137 /* a contour's start point like 24-25-26-0-1-2 */
138 /* (there can be at most one such segment per contour); */
139 /* we thus append additional records to split them into 24-26 and 0-2 */
140 wrap_around_segment
= recorder
->wrap_around_segments
;
141 for (seg
= segments
; seg
< seg_limit
; seg
++)
142 if (seg
->first
> seg
->last
)
144 /* the stored data is used later for edge linking */
145 *(wrap_around_segment
++) = seg
- segments
;
148 num_wrap_around_segments
= wrap_around_segment
149 - recorder
->wrap_around_segments
;
150 num_segments
+= num_wrap_around_segments
;
152 /* wrap-around segments are pushed with four arguments */
153 num_args
= 2 * num_segments
+ 2 * num_wrap_around_segments
+ 2;
155 /* collect all arguments temporarily in an array (in reverse order) */
156 /* so that we can easily split into chunks of 255 args */
157 /* as needed by NPUSHB and NPUSHW, respectively */
158 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
162 arg
= args
+ num_args
- 1;
164 if (num_segments
> 0xFF)
167 if (recorder
->glyph
->num_components
)
168 *(arg
--) = bci_create_segments_composite
;
170 *(arg
--) = bci_create_segments
;
171 *(arg
--) = num_segments
;
173 for (seg
= segments
; seg
< seg_limit
; seg
++)
175 FT_UInt first
= seg
->first
- points
;
176 FT_UInt last
= seg
->last
- points
;
179 *(arg
--) = TA_adjust_point_index(recorder
, first
);
180 *(arg
--) = TA_adjust_point_index(recorder
, last
);
182 /* we push the last and first contour point */
183 /* as a third and fourth argument in wrap-around segments */
186 for (n
= 0; n
< outline
.n_contours
; n
++)
188 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
193 *(arg
--) = TA_adjust_point_index(recorder
, end
);
198 *(arg
--) = TA_adjust_point_index(recorder
, 0);
200 *(arg
--) = TA_adjust_point_index(recorder
,
201 (FT_UInt
)outline
.contours
[n
- 1] + 1);
211 /* emit the second part of wrap-around segments as separate segments */
212 /* so that edges can easily link to them */
213 for (seg
= segments
; seg
< seg_limit
; seg
++)
215 FT_UInt first
= seg
->first
- points
;
216 FT_UInt last
= seg
->last
- points
;
221 for (n
= 0; n
< outline
.n_contours
; n
++)
223 if (first
<= (FT_UInt
)outline
.contours
[n
])
226 *(arg
--) = TA_adjust_point_index(recorder
, 0);
228 *(arg
--) = TA_adjust_point_index(recorder
,
229 (FT_UInt
)outline
.contours
[n
- 1] + 1);
234 *(arg
--) = TA_adjust_point_index(recorder
, last
);
237 /* with most fonts it is very rare */
238 /* that any of the pushed arguments is larger than 0xFF, */
239 /* thus we refrain from further optimizing this case */
245 for (i
= 0; i
< num_args
; i
+= 255)
247 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
251 for (j
= 0; j
< nargs
; j
++)
261 for (i
= 0; i
< num_args
; i
+= 255)
263 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
267 for (j
= 0; j
< nargs
; j
++)
277 num_storage
= sal_segment_offset
+ num_segments
* 2;
278 if (num_storage
> sfnt
->max_storage
)
279 sfnt
->max_storage
= num_storage
;
281 num_twilight_points
= num_segments
* 2;
282 if (num_twilight_points
> sfnt
->max_twilight_points
)
283 sfnt
->max_twilight_points
= num_twilight_points
;
285 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
286 if (num_stack_elements
> sfnt
->max_stack_elements
)
287 sfnt
->max_stack_elements
= num_stack_elements
;
296 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
300 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
301 FT_Vector
* points
= glyph
->outline
.points
;
302 FT_Int num_contours
= glyph
->outline
.n_contours
;
309 FT_Bool need_words
= 0;
313 FT_UInt num_stack_elements
;
316 num_args
= 2 * num_contours
+ 2;
318 /* collect all arguments temporarily in an array (in reverse order) */
319 /* so that we can easily split into chunks of 255 args */
320 /* as needed by NPUSHB and NPUSHW, respectively */
321 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
325 arg
= args
+ num_args
- 1;
330 if (recorder
->glyph
->num_components
)
331 *(arg
--) = bci_scale_composite_glyph
;
333 *(arg
--) = bci_scale_glyph
;
334 *(arg
--) = num_contours
;
339 for (p
= 0; p
< num_contours
; p
++)
345 end
= glyph
->outline
.contours
[p
];
347 for (q
= start
; q
<= end
; q
++)
349 if (points
[q
].y
< points
[min
].y
)
351 if (points
[q
].y
> points
[max
].y
)
355 *(arg
--) = TA_adjust_point_index(recorder
, min
);
356 *(arg
--) = TA_adjust_point_index(recorder
, max
);
364 /* with most fonts it is very rare */
365 /* that any of the pushed arguments is larger than 0xFF, */
366 /* thus we refrain from further optimizing this case */
372 for (i
= 0; i
< num_args
; i
+= 255)
374 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
378 for (j
= 0; j
< nargs
; j
++)
388 for (i
= 0; i
< num_args
; i
+= 255)
390 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
394 for (j
= 0; j
< nargs
; j
++)
404 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
405 if (num_stack_elements
> sfnt
->max_stack_elements
)
406 sfnt
->max_stack_elements
= num_stack_elements
;
415 TA_font_build_subglyph_shifter(FONT
* font
,
418 FT_Face face
= font
->loader
->face
;
419 FT_GlyphSlot glyph
= face
->glyph
;
421 TA_GlyphLoader gloader
= font
->loader
->gloader
;
423 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
424 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
425 TA_SubGlyph subglyph
;
427 FT_Int curr_contour
= 0;
430 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
434 FT_UShort flags
= subglyph
->flags
;
435 FT_Pos y_offset
= subglyph
->arg2
;
440 /* load subglyph to get the number of contours */
441 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
444 num_contours
= glyph
->outline
.n_contours
;
446 /* nothing to do if there is a point-to-point alignment */
447 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
450 /* nothing to do if y offset is zero */
454 /* nothing to do if there are no contours */
458 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
459 /* ensures that composite subglyphs are represented as simple glyphs */
461 if (num_contours
> 0xFF
462 || curr_contour
> 0xFF)
465 BCI(HIGH(curr_contour
));
466 BCI(LOW(curr_contour
));
467 BCI(HIGH(num_contours
));
468 BCI(LOW(num_contours
));
477 /* there are high chances that this value needs PUSHW, */
478 /* thus we handle it separately */
479 if (y_offset
> 0xFF || y_offset
< 0)
492 BCI(bci_shift_subglyph
);
496 curr_contour
+= num_contours
;
504 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
505 * data in four arrays (which are simple but waste a lot of memory). The
506 * function below converts them into bytecode.
508 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
509 * together with the edge they correspond to.
511 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
512 * loop over the edge or edge pairs, respectively, and each edge or edge
513 * pair contains an inner loop to emit the correponding points.
517 TA_build_point_hints(Recorder
* recorder
,
520 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
521 TA_Segment segments
= axis
->segments
;
522 TA_Edge edges
= axis
->edges
;
528 FT_Byte
* p
= recorder
->hints_record
.buf
;
529 FT_UInt num_edges
= axis
->num_edges
;
530 FT_UInt num_strong_points
= recorder
->num_strong_points
;
544 /* we store everything as 16bit numbers; */
545 /* the function numbers (`ta_ip_before', etc.) */
546 /* reflect the order in the TA_Action enumeration */
548 /* ip_before_points */
551 ip
= recorder
->ip_before_points
;
552 ip_limit
= ip
+ num_strong_points
;
553 for (; ip
< ip_limit
; ip
++)
563 recorder
->hints_record
.num_actions
++;
568 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
569 *(p
++) = HIGH(edge
->first
- segments
);
570 *(p
++) = LOW(edge
->first
- segments
);
574 ip
= recorder
->ip_before_points
;
576 for (; ip
< ip_limit
; ip
++)
578 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
581 *(p
++) = HIGH(point
);
586 /* ip_after_points */
589 ip
= recorder
->ip_after_points
;
590 ip_limit
= ip
+ num_strong_points
;
591 for (; ip
< ip_limit
; ip
++)
601 recorder
->hints_record
.num_actions
++;
603 edge
= edges
+ axis
->num_edges
- 1;
606 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
607 *(p
++) = HIGH(edge
->first
- segments
);
608 *(p
++) = LOW(edge
->first
- segments
);
612 ip
= recorder
->ip_after_points
;
614 for (; ip
< ip_limit
; ip
++)
616 FT_UInt point
= TA_adjust_point_index(recorder
, *ip
);
619 *(p
++) = HIGH(point
);
624 /* ip_on_point_array */
627 ip
= recorder
->ip_on_point_array
;
628 ip_limit
= ip
+ num_edges
* num_strong_points
;
629 for (; ip
< ip_limit
; ip
+= num_strong_points
)
635 recorder
->hints_record
.num_actions
++;
638 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
643 ip
= recorder
->ip_on_point_array
;
644 ip_limit
= ip
+ num_edges
* num_strong_points
;
645 for (; ip
< ip_limit
; ip
+= num_strong_points
, i
++)
652 *(p
++) = HIGH(edge
->first
- segments
);
653 *(p
++) = LOW(edge
->first
- segments
);
657 iq_limit
= iq
+ num_strong_points
;
658 for (; iq
< iq_limit
; iq
++)
671 for (; iq
< iq_limit
; iq
++)
673 FT_UInt point
= TA_adjust_point_index(recorder
, *iq
);
676 *(p
++) = HIGH(point
);
682 /* ip_between_point_array */
685 ip
= recorder
->ip_between_point_array
;
686 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
687 for (; ip
< ip_limit
; ip
+= num_strong_points
)
693 recorder
->hints_record
.num_actions
++;
696 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
701 ip
= recorder
->ip_between_point_array
;
702 ip_limit
= ip
+ num_edges
* num_edges
* num_strong_points
;
705 ip
+= num_edges
* num_strong_points
, i
++)
711 iq_limit
= iq
+ num_edges
* num_strong_points
;
712 for (; iq
< iq_limit
; iq
+= num_strong_points
, j
++)
719 *(p
++) = HIGH(after
->first
- segments
);
720 *(p
++) = LOW(after
->first
- segments
);
721 *(p
++) = HIGH(before
->first
- segments
);
722 *(p
++) = LOW(before
->first
- segments
);
726 ir_limit
= ir
+ num_strong_points
;
727 for (; ir
< ir_limit
; ir
++)
740 for (; ir
< ir_limit
; ir
++)
742 FT_UInt point
= TA_adjust_point_index(recorder
, *ir
);
745 *(p
++) = HIGH(point
);
752 recorder
->hints_record
.buf
= p
;
757 TA_hints_record_is_different(Hints_Record
* hints_records
,
758 FT_UInt num_hints_records
,
762 Hints_Record last_hints_record
;
768 /* we only need to compare with the last hints record */
769 last_hints_record
= hints_records
[num_hints_records
- 1];
771 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
774 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
782 TA_add_hints_record(Hints_Record
** hints_records
,
783 FT_UInt
* num_hints_records
,
785 Hints_Record hints_record
)
787 Hints_Record
* hints_records_new
;
789 /* at this point, `hints_record.buf' still points into `ins_buf' */
790 FT_Byte
* end
= hints_record
.buf
;
793 buf_len
= (FT_UInt
)(end
- start
);
795 /* now fill the structure completely */
796 hints_record
.buf_len
= buf_len
;
797 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
798 if (!hints_record
.buf
)
799 return FT_Err_Out_Of_Memory
;
801 memcpy(hints_record
.buf
, start
, buf_len
);
803 (*num_hints_records
)++;
805 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
806 * sizeof (Hints_Record
));
807 if (!hints_records_new
)
809 free(hints_record
.buf
);
810 (*num_hints_records
)--;
811 return FT_Err_Out_Of_Memory
;
814 *hints_records
= hints_records_new
;
816 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
823 TA_sfnt_emit_hints_record(SFNT
* sfnt
,
824 Hints_Record
* hints_record
,
829 FT_Bool need_words
= 0;
832 FT_UInt num_arguments
;
834 FT_UInt num_stack_elements
;
837 /* check whether any argument is larger than 0xFF */
838 endp
= hints_record
->buf
+ hints_record
->buf_len
;
839 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
843 /* with most fonts it is very rare */
844 /* that any of the pushed arguments is larger than 0xFF, */
845 /* thus we refrain from further optimizing this case */
847 num_arguments
= hints_record
->buf_len
/ 2;
852 for (i
= 0; i
< num_arguments
; i
+= 255)
854 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
858 for (j
= 0; j
< num_args
; j
++)
868 /* we only need the lower bytes */
871 for (i
= 0; i
< num_arguments
; i
+= 255)
873 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
877 for (j
= 0; j
< num_args
; j
++)
885 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_arguments
;
886 if (num_stack_elements
> sfnt
->max_stack_elements
)
887 sfnt
->max_stack_elements
= num_stack_elements
;
894 TA_sfnt_emit_hints_records(SFNT
* sfnt
,
895 Hints_Record
* hints_records
,
896 FT_UInt num_hints_records
,
900 Hints_Record
* hints_record
;
903 hints_record
= hints_records
;
905 for (i
= 0; i
< num_hints_records
- 1; i
++)
908 if (hints_record
->size
> 0xFF)
911 BCI(HIGH((hints_record
+ 1)->size
));
912 BCI(LOW((hints_record
+ 1)->size
));
917 BCI((hints_record
+ 1)->size
);
921 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
927 bufp
= TA_sfnt_emit_hints_record(sfnt
, hints_record
, bufp
);
929 for (i
= 0; i
< num_hints_records
- 1; i
++)
941 TA_free_hints_records(Hints_Record
* hints_records
,
942 FT_UInt num_hints_records
)
947 for (i
= 0; i
< num_hints_records
; i
++)
948 free(hints_records
[i
].buf
);
955 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
960 TA_Segment segments
= axis
->segments
;
963 FT_UInt num_segs
= 0;
967 seg_idx
= edge
->first
- segments
;
969 /* we store everything as 16bit numbers */
970 *(bufp
++) = HIGH(seg_idx
);
971 *(bufp
++) = LOW(seg_idx
);
973 /* wrap-around segments are stored as two segments */
974 if (edge
->first
->first
> edge
->first
->last
)
977 seg
= edge
->first
->edge_next
;
978 while (seg
!= edge
->first
)
982 if (seg
->first
> seg
->last
)
985 seg
= seg
->edge_next
;
988 *(bufp
++) = HIGH(num_segs
);
989 *(bufp
++) = LOW(num_segs
);
991 if (edge
->first
->first
> edge
->first
->last
)
993 /* emit second part of wrap-around segment; */
994 /* the bytecode positions such segments after `normal' ones */
998 if (seg_idx
== *wrap
)
1003 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1004 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1007 seg
= edge
->first
->edge_next
;
1008 while (seg
!= edge
->first
)
1010 seg_idx
= seg
- segments
;
1012 *(bufp
++) = HIGH(seg_idx
);
1013 *(bufp
++) = LOW(seg_idx
);
1015 if (seg
->first
> seg
->last
)
1020 if (seg_idx
== *wrap
)
1025 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1026 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1029 seg
= seg
->edge_next
;
1037 TA_hints_recorder(TA_Action action
,
1038 TA_GlyphHints hints
,
1043 TA_Edge lower_bound
,
1044 TA_Edge upper_bound
)
1046 TA_AxisHints axis
= &hints
->axis
[dim
];
1047 TA_Edge edges
= axis
->edges
;
1048 TA_Segment segments
= axis
->segments
;
1049 TA_Point points
= hints
->points
;
1051 Recorder
* recorder
= (Recorder
*)hints
->user
;
1052 FONT
* font
= recorder
->font
;
1053 FT_UInt
* wraps
= recorder
->wrap_around_segments
;
1054 FT_Byte
* p
= recorder
->hints_record
.buf
;
1056 FT_Byte bound_offset
= 0;
1062 if (dim
== TA_DIMENSION_HORZ
)
1065 /* we collect point hints for later processing */
1070 TA_Point point
= (TA_Point
)arg1
;
1073 ip
= recorder
->ip_before_points
;
1074 limit
= ip
+ recorder
->num_strong_points
;
1075 for (; ip
< limit
; ip
++)
1079 *ip
= point
- points
;
1088 TA_Point point
= (TA_Point
)arg1
;
1091 ip
= recorder
->ip_after_points
;
1092 limit
= ip
+ recorder
->num_strong_points
;
1093 for (; ip
< limit
; ip
++)
1097 *ip
= point
- points
;
1106 TA_Point point
= (TA_Point
)arg1
;
1107 TA_Edge edge
= arg2
;
1110 ip
= recorder
->ip_on_point_array
1111 + recorder
->num_strong_points
1113 limit
= ip
+ recorder
->num_strong_points
;
1114 for (; ip
< limit
; ip
++)
1118 *ip
= point
- points
;
1127 TA_Point point
= (TA_Point
)arg1
;
1128 TA_Edge before
= arg2
;
1129 TA_Edge after
= arg3
;
1132 /* note that `recorder->num_segments' has been used for allocation, */
1133 /* but `axis->num_edges' is used for accessing this array */
1134 ip
= recorder
->ip_between_point_array
1135 + recorder
->num_strong_points
* axis
->num_edges
1137 + recorder
->num_strong_points
1139 limit
= ip
+ recorder
->num_strong_points
;
1140 for (; ip
< limit
; ip
++)
1144 *ip
= point
- points
;
1152 /* we ignore the BOUND action since we signal this information */
1153 /* with the `bound_offset' parameter below */
1165 /* this reflects the order in the TA_Action enumeration */
1167 *(p
++) = (FT_Byte
)action
+ bound_offset
+ ACTION_OFFSET
;
1173 TA_Edge base_edge
= (TA_Edge
)arg1
;
1174 TA_Edge stem_edge
= arg2
;
1178 *(p
++) = stem_edge
->flags
& TA_EDGE_SERIF
;
1180 *(p
++) = base_edge
->flags
& TA_EDGE_ROUND
;
1181 *(p
++) = HIGH(base_edge
->first
- segments
);
1182 *(p
++) = LOW(base_edge
->first
- segments
);
1183 *(p
++) = HIGH(stem_edge
->first
- segments
);
1184 *(p
++) = LOW(stem_edge
->first
- segments
);
1186 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1192 TA_Edge edge
= (TA_Edge
)arg1
;
1193 TA_Edge edge2
= arg2
;
1197 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1199 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1200 *(p
++) = HIGH(edge
->first
- segments
);
1201 *(p
++) = LOW(edge
->first
- segments
);
1202 *(p
++) = HIGH(edge2
->first
- segments
);
1203 *(p
++) = LOW(edge2
->first
- segments
);
1205 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1211 TA_Edge edge
= (TA_Edge
)arg1
;
1212 TA_Edge edge2
= arg2
;
1213 TA_Edge edge_minus_one
= lower_bound
;
1217 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1219 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1220 *(p
++) = HIGH(edge
->first
- segments
);
1221 *(p
++) = LOW(edge
->first
- segments
);
1222 *(p
++) = HIGH(edge2
->first
- segments
);
1223 *(p
++) = LOW(edge2
->first
- segments
);
1227 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1228 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1231 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1235 case ta_blue_anchor
:
1237 TA_Edge edge
= (TA_Edge
)arg1
;
1238 TA_Edge blue
= arg2
;
1241 *(p
++) = HIGH(blue
->first
- segments
);
1242 *(p
++) = LOW(blue
->first
- segments
);
1244 if (edge
->best_blue_is_shoot
)
1246 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1247 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1251 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1252 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1255 *(p
++) = HIGH(edge
->first
- segments
);
1256 *(p
++) = LOW(edge
->first
- segments
);
1258 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1264 TA_Edge edge
= (TA_Edge
)arg1
;
1265 TA_Edge edge2
= arg2
;
1266 TA_Edge edge_minus_one
= lower_bound
;
1270 *(p
++) = edge2
->flags
& TA_EDGE_SERIF
;
1272 *(p
++) = edge
->flags
& TA_EDGE_ROUND
;
1273 *(p
++) = HIGH(edge
->first
- segments
);
1274 *(p
++) = LOW(edge
->first
- segments
);
1275 *(p
++) = HIGH(edge2
->first
- segments
);
1276 *(p
++) = LOW(edge2
->first
- segments
);
1280 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1281 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1284 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1285 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1291 TA_Edge edge
= (TA_Edge
)arg1
;
1294 if (edge
->best_blue_is_shoot
)
1296 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1297 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(font
) + edge
->best_blue_idx
);
1301 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1302 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(font
) + edge
->best_blue_idx
);
1305 *(p
++) = HIGH(edge
->first
- segments
);
1306 *(p
++) = LOW(edge
->first
- segments
);
1308 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1314 TA_Edge serif
= (TA_Edge
)arg1
;
1315 TA_Edge base
= serif
->serif
;
1318 *(p
++) = HIGH(serif
->first
- segments
);
1319 *(p
++) = LOW(serif
->first
- segments
);
1320 *(p
++) = HIGH(base
->first
- segments
);
1321 *(p
++) = LOW(base
->first
- segments
);
1325 *(p
++) = HIGH(lower_bound
->first
- segments
);
1326 *(p
++) = LOW(lower_bound
->first
- segments
);
1330 *(p
++) = HIGH(upper_bound
->first
- segments
);
1331 *(p
++) = LOW(upper_bound
->first
- segments
);
1334 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1338 case ta_serif_anchor
:
1339 case ta_serif_link2
:
1341 TA_Edge edge
= (TA_Edge
)arg1
;
1344 *(p
++) = HIGH(edge
->first
- segments
);
1345 *(p
++) = LOW(edge
->first
- segments
);
1349 *(p
++) = HIGH(lower_bound
->first
- segments
);
1350 *(p
++) = LOW(lower_bound
->first
- segments
);
1354 *(p
++) = HIGH(upper_bound
->first
- segments
);
1355 *(p
++) = LOW(upper_bound
->first
- segments
);
1358 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1362 case ta_serif_link1
:
1364 TA_Edge edge
= (TA_Edge
)arg1
;
1365 TA_Edge before
= arg2
;
1366 TA_Edge after
= arg3
;
1369 *(p
++) = HIGH(before
->first
- segments
);
1370 *(p
++) = LOW(before
->first
- segments
);
1371 *(p
++) = HIGH(edge
->first
- segments
);
1372 *(p
++) = LOW(edge
->first
- segments
);
1373 *(p
++) = HIGH(after
->first
- segments
);
1374 *(p
++) = LOW(after
->first
- segments
);
1378 *(p
++) = HIGH(lower_bound
->first
- segments
);
1379 *(p
++) = LOW(lower_bound
->first
- segments
);
1383 *(p
++) = HIGH(upper_bound
->first
- segments
);
1384 *(p
++) = LOW(upper_bound
->first
- segments
);
1387 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1392 /* there are more cases in the enumeration */
1393 /* which are handled with the `bound_offset' parameter */
1397 recorder
->hints_record
.num_actions
++;
1398 recorder
->hints_record
.buf
= p
;
1403 TA_init_recorder(Recorder
* recorder
,
1404 FT_UInt wrap_around_size
,
1407 TA_GlyphHints hints
)
1409 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1410 TA_Point points
= hints
->points
;
1411 TA_Point point_limit
= points
+ hints
->num_points
;
1414 FT_UInt num_strong_points
= 0;
1417 recorder
->font
= font
;
1418 recorder
->glyph
= glyph
;
1419 recorder
->num_segments
= axis
->num_segments
;
1421 recorder
->ip_before_points
= NULL
;
1422 recorder
->ip_after_points
= NULL
;
1423 recorder
->ip_on_point_array
= NULL
;
1424 recorder
->ip_between_point_array
= NULL
;
1426 /* no need to clean up allocated arrays in case of error; */
1427 /* this is handled later by `TA_free_recorder' */
1429 recorder
->wrap_around_segments
=
1430 (FT_UInt
*)malloc(wrap_around_size
* sizeof (FT_UInt
));
1431 if (!recorder
->wrap_around_segments
)
1432 return FT_Err_Out_Of_Memory
;
1434 /* get number of strong points */
1435 for (point
= points
; point
< point_limit
; point
++)
1437 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1438 /* however, this value isn't known yet */
1439 /* (or rather, it can vary between different pixel sizes) */
1440 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1443 num_strong_points
++;
1446 recorder
->num_strong_points
= num_strong_points
;
1448 recorder
->ip_before_points
=
1449 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1450 if (!recorder
->ip_before_points
)
1451 return FT_Err_Out_Of_Memory
;
1453 recorder
->ip_after_points
=
1454 (FT_UInt
*)malloc(num_strong_points
* sizeof (FT_UInt
));
1455 if (!recorder
->ip_after_points
)
1456 return FT_Err_Out_Of_Memory
;
1458 /* actually, we need `hints->num_edges' for the array sizes; */
1459 /* however, this value isn't known yet */
1460 /* (or rather, it can vary between different pixel sizes) */
1461 recorder
->ip_on_point_array
=
1462 (FT_UInt
*)malloc(axis
->num_segments
1463 * num_strong_points
* sizeof (FT_UInt
));
1464 if (!recorder
->ip_on_point_array
)
1465 return FT_Err_Out_Of_Memory
;
1467 recorder
->ip_between_point_array
=
1468 (FT_UInt
*)malloc(axis
->num_segments
* axis
->num_segments
1469 * num_strong_points
* sizeof (FT_UInt
));
1470 if (!recorder
->ip_between_point_array
)
1471 return FT_Err_Out_Of_Memory
;
1478 TA_rewind_recorder(Recorder
* recorder
,
1482 recorder
->hints_record
.buf
= bufp
+ 2;
1483 recorder
->hints_record
.num_actions
= 0;
1484 recorder
->hints_record
.size
= size
;
1486 /* We later check with MISSING (which expands to 0xFF bytes) */
1488 memset(recorder
->ip_before_points
, 0xFF,
1489 recorder
->num_strong_points
* sizeof (FT_UInt
));
1490 memset(recorder
->ip_after_points
, 0xFF,
1491 recorder
->num_strong_points
* sizeof (FT_UInt
));
1493 memset(recorder
->ip_on_point_array
, 0xFF,
1494 recorder
->num_segments
1495 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1496 memset(recorder
->ip_between_point_array
, 0xFF,
1497 recorder
->num_segments
* recorder
->num_segments
1498 * recorder
->num_strong_points
* sizeof (FT_UInt
));
1504 TA_free_recorder(Recorder
* recorder
)
1506 free(recorder
->wrap_around_segments
);
1508 free(recorder
->ip_before_points
);
1509 free(recorder
->ip_after_points
);
1510 free(recorder
->ip_on_point_array
);
1511 free(recorder
->ip_between_point_array
);
1516 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1520 FT_Face face
= sfnt
->face
;
1528 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1529 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1530 /* `idx' is never negative */
1531 GLYPH
* glyph
= &data
->glyphs
[idx
];
1533 TA_GlyphHints hints
;
1535 FT_UInt num_hints_records
;
1536 Hints_Record
* hints_records
;
1540 FT_Int32 load_flags
;
1544 /* XXX: right now, we abuse this flag to control */
1545 /* the global behaviour of the auto-hinter */
1546 load_flags
= font
->fallback_script
<< 30;
1547 load_flags
|= 1 << 28; /* vertical hinting only */
1548 if (font
->increase_x_height
)
1549 load_flags
|= 1 << 29;
1550 if (!font
->pre_hinting
)
1551 load_flags
|= FT_LOAD_NO_SCALE
;
1553 /* computing the segments is resolution independent, */
1554 /* thus the pixel size in this call is arbitrary */
1555 error
= FT_Set_Pixel_Sizes(face
, 20, 20);
1559 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1560 error
= ta_loader_load_glyph(font
->loader
, face
, (FT_UInt
)idx
, load_flags
);
1564 /* do nothing if we have an empty glyph */
1565 if (!face
->glyph
->outline
.n_contours
)
1568 hints
= &font
->loader
->hints
;
1570 /* do nothing if the setup delivered the dummy module only */
1571 if (!hints
->num_points
)
1574 /* we allocate a buffer which is certainly large enough */
1575 /* to hold all of the created bytecode instructions; */
1576 /* later on it gets reallocated to its real size */
1577 ins_len
= hints
->num_points
* 1000;
1578 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1580 return FT_Err_Out_Of_Memory
;
1582 /* initialize array with an invalid bytecode */
1583 /* so that we can easily find the array length at reallocation time */
1584 memset(ins_buf
, INS_A0
, ins_len
);
1586 num_hints_records
= 0;
1587 hints_records
= NULL
;
1589 /* handle composite glyph */
1590 if (font
->loader
->gloader
->base
.num_subglyphs
)
1592 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1595 error
= FT_Err_Out_Of_Memory
;
1602 /* only scale the glyph if the dummy hinter has been used */
1603 if (font
->loader
->metrics
->clazz
== &ta_dummy_script_class
)
1605 /* since `TA_init_recorder' hasn't been called yet, */
1606 /* we manually initialize the `glyph' field */
1607 recorder
.glyph
= glyph
;
1609 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1612 error
= FT_Err_Out_Of_Memory
;
1619 error
= TA_init_recorder(&recorder
, face
->glyph
->outline
.n_contours
,
1620 font
, glyph
, hints
);
1624 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, ins_buf
);
1627 error
= FT_Err_Out_Of_Memory
;
1631 /* now we loop over a large range of pixel sizes */
1632 /* to find hints records which get pushed onto the bytecode stack */
1639 num_chars
= fprintf(stderr
, "glyph %ld\n", idx
);
1640 for (i
= 0; i
< num_chars
- 1; i
++)
1642 fprintf(stderr
, "\n\n");
1647 /* we temporarily use `ins_buf' to record the current glyph hints, */
1648 /* leaving two bytes at the beginning so that the number of actions */
1649 /* can be inserted later on */
1650 ta_loader_register_hints_recorder(font
->loader
,
1654 for (size
= font
->hinting_range_min
;
1655 size
<= font
->hinting_range_max
;
1658 TA_rewind_recorder(&recorder
, bufp
, size
);
1660 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
1664 /* calling `ta_loader_load_glyph' uses the */
1665 /* `TA_hints_recorder' function as a callback, */
1666 /* modifying `hints_record' */
1667 error
= ta_loader_load_glyph(font
->loader
, face
, idx
, load_flags
);
1671 /* append the point hints data collected in `TA_hints_recorder' */
1672 TA_build_point_hints(&recorder
, hints
);
1674 /* store the number of actions in `ins_buf' */
1675 *bufp
= HIGH(recorder
.hints_record
.num_actions
);
1676 *(bufp
+ 1) = LOW(recorder
.hints_record
.num_actions
);
1678 if (TA_hints_record_is_different(hints_records
,
1680 bufp
, recorder
.hints_record
.buf
))
1684 fprintf(stderr
, " size %d:\n", size
);
1686 ta_glyph_hints_dump_edges(_ta_debug_hints
);
1687 ta_glyph_hints_dump_segments(_ta_debug_hints
);
1688 ta_glyph_hints_dump_points(_ta_debug_hints
);
1690 fprintf(stderr
, " hints record:\n");
1691 for (p
= bufp
; p
< recorder
.hints_record
.buf
; p
+= 2)
1692 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
1693 fprintf(stderr
, "\n");
1697 error
= TA_add_hints_record(&hints_records
,
1699 bufp
, recorder
.hints_record
);
1705 if (num_hints_records
== 1 && !hints_records
[0].num_actions
)
1707 /* since we only have a single empty record we just scale the glyph, */
1708 /* overwriting the data from `TA_sfnt_build_glyph_segments' */
1709 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1712 error
= FT_Err_Out_Of_Memory
;
1716 /* clear the rest of the temporarily used part of `ins_buf' */
1718 while (*p
!= INS_A0
)
1724 /* in most cases, the output of `TA_sfnt_build_glyph_segments' */
1725 /* is shorter than the previously stored data, */
1726 /* so clear the rest of the temporarily used part of `ins_buf' */
1727 /* before appending the hints records */
1729 while (*p
!= INS_A0
)
1732 bufp
= TA_sfnt_emit_hints_records(sfnt
,
1733 hints_records
, num_hints_records
,
1737 TA_free_hints_records(hints_records
, num_hints_records
);
1738 TA_free_recorder(&recorder
);
1740 /* we are done, so reallocate the instruction array to its real size */
1741 if (*bufp
== INS_A0
)
1743 /* search backwards */
1744 while (*bufp
== INS_A0
)
1750 /* search forwards */
1751 while (*bufp
!= INS_A0
)
1756 ins_len
= bufp
- ins_buf
;
1758 if (ins_len
> sfnt
->max_instructions
)
1759 sfnt
->max_instructions
= ins_len
;
1761 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
1762 glyph
->ins_len
= ins_len
;
1767 TA_free_hints_records(hints_records
, num_hints_records
);
1768 TA_free_recorder(&recorder
);
1775 /* end of tabytecode.c */