4 * Copyright (C) 2011-2014 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
17 #include <stdbool.h> /* for llrb.h */
19 #include "llrb.h" /* a red-black tree implementation */
30 int _ta_debug_global
= 0;
31 int _ta_debug_disable_horz_hints
;
32 int _ta_debug_disable_vert_hints
;
33 int _ta_debug_disable_blue_hints
;
34 void* _ta_debug_hints
;
38 /* node structures for point hints */
40 typedef struct Node1 Node1
;
43 LLRB_ENTRY(Node1
) entry1
;
47 typedef struct Node2 Node2
;
50 LLRB_ENTRY(Node2
) entry2
;
55 typedef struct Node3 Node3
;
58 LLRB_ENTRY(Node3
) entry3
;
59 FT_UShort before_edge
;
65 /* comparison functions for our red-black trees */
72 return e1
->point
- e2
->point
;
82 /* sort by edges ... */
83 delta
= (FT_Int
)e1
->edge
- (FT_Int
)e2
->edge
;
87 /* ... then by points */
88 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
98 /* sort by `before' edges ... */
99 delta
= (FT_Int
)e1
->before_edge
- (FT_Int
)e2
->before_edge
;
103 /* ... then by `after' edges ... */
104 delta
= (FT_Int
)e1
->after_edge
- (FT_Int
)e2
->after_edge
;
108 /* ... then by points */
109 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
113 /* the red-black tree function bodies */
114 typedef struct ip_before_points ip_before_points
;
115 typedef struct ip_after_points ip_after_points
;
116 typedef struct ip_on_points ip_on_points
;
117 typedef struct ip_between_points ip_between_points
;
119 LLRB_HEAD(ip_before_points
, Node1
);
120 LLRB_HEAD(ip_after_points
, Node1
);
121 LLRB_HEAD(ip_on_points
, Node2
);
122 LLRB_HEAD(ip_between_points
, Node3
);
124 /* no trailing semicolon in the next four lines */
125 LLRB_GENERATE_STATIC(ip_before_points
, Node1
, entry1
, node1cmp
)
126 LLRB_GENERATE_STATIC(ip_after_points
, Node1
, entry1
, node1cmp
)
127 LLRB_GENERATE_STATIC(ip_on_points
, Node2
, entry2
, node2cmp
)
128 LLRB_GENERATE_STATIC(ip_between_points
, Node3
, entry3
, node3cmp
)
131 typedef struct Hints_Record_
139 typedef struct Recorder_
143 GLYPH
* glyph
; /* the current glyph */
144 Hints_Record hints_record
;
146 /* some segments can `wrap around' */
147 /* a contour's start point like 24-25-26-0-1-2 */
148 /* (there can be at most one such segment per contour); */
149 /* later on we append additional records */
150 /* to split them into 24-26 and 0-2 */
151 FT_UShort
* wrap_around_segments
;
152 FT_UShort num_wrap_around_segments
;
154 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
156 /* data necessary for strong point interpolation */
157 ip_before_points ip_before_points_head
;
158 ip_after_points ip_after_points_head
;
159 ip_on_points ip_on_points_head
;
160 ip_between_points ip_between_points_head
;
162 FT_UShort num_strong_points
;
163 FT_UShort num_segments
;
167 /* this is the bytecode of the `.ttfautohint' glyph */
169 FT_Byte ttfautohint_glyph_bytecode
[7] =
172 /* increment `cvtl_is_subglyph' counter */
185 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
186 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
187 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
192 TA_build_push(FT_Byte
* bufp
,
204 for (i
= 0; i
< num_args
; i
+= 255)
206 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
208 if (optimize
&& nargs
<= 8)
209 BCI(PUSHW_1
- 1 + nargs
);
215 for (j
= 0; j
< nargs
; j
++)
225 for (i
= 0; i
< num_args
; i
+= 255)
227 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
229 if (optimize
&& nargs
<= 8)
230 BCI(PUSHB_1
- 1 + nargs
);
236 for (j
= 0; j
< nargs
; j
++)
248 /* We add a subglyph for each composite glyph. */
249 /* Since subglyphs must contain at least one point, */
250 /* we have to adjust all point indices accordingly. */
251 /* Using the `pointsums' array of the `GLYPH' structure */
252 /* it is straightforward to do that: */
253 /* Assuming that point with index x is in the interval */
254 /* pointsums[n] <= x < pointsums[n + 1], */
255 /* the new point index is x + n. */
258 TA_adjust_point_index(Recorder
* recorder
,
261 FONT
* font
= recorder
->font
;
262 GLYPH
* glyph
= recorder
->glyph
;
266 if (!glyph
->num_components
|| !font
->hint_composites
)
267 return idx
; /* not a composite glyph */
269 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
270 if (idx
< glyph
->pointsums
[i
])
277 /* we store the segments in the storage area; */
278 /* each segment record consists of the first and last point */
281 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
286 FONT
* font
= recorder
->font
;
287 TA_GlyphHints hints
= &font
->loader
->hints
;
288 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
289 TA_Point points
= hints
->points
;
290 TA_Segment segments
= axis
->segments
;
292 TA_Segment seg_limit
;
294 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
295 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
297 FT_UInt style_id
= data
->style_ids
298 [font
->loader
->metrics
->style_class
->style
];
300 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
305 FT_UShort num_segments
;
307 FT_Bool need_words
= 0;
311 FT_UShort num_packed_segments
;
312 FT_UShort num_storage
;
313 FT_UShort num_stack_elements
;
314 FT_UShort num_twilight_points
;
317 seg_limit
= segments
+ axis
->num_segments
;
318 num_segments
= axis
->num_segments
;
320 /* to pack the data in the bytecode more tightly, */
321 /* we store up to the first nine segments in nibbles if possible, */
322 /* using delta values */
324 num_packed_segments
= 0;
325 for (seg
= segments
; seg
< seg_limit
; seg
++)
327 FT_UInt first
= seg
->first
- points
;
328 FT_UInt last
= seg
->last
- points
;
331 first
= TA_adjust_point_index(recorder
, first
);
332 last
= TA_adjust_point_index(recorder
, last
);
334 if (first
- base
>= 16)
336 if (first
> last
|| last
- first
>= 16)
338 if (num_packed_segments
== 9)
340 num_packed_segments
++;
344 /* also handle wrap-around segments */
345 num_segments
+= recorder
->num_wrap_around_segments
;
347 /* wrap-around segments are pushed with four arguments; */
348 /* a segment stored in nibbles needs only one byte instead of two */
349 num_args
= num_packed_segments
350 + 2 * (num_segments
- num_packed_segments
)
351 + 2 * recorder
->num_wrap_around_segments
354 /* collect all arguments temporarily in an array (in reverse order) */
355 /* so that we can easily split into chunks of 255 args */
356 /* as needed by NPUSHB and NPUSHW, respectively */
357 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
361 arg
= args
+ num_args
- 1;
363 if (num_segments
> 0xFF)
366 /* the number of packed segments is indicated by the function number */
367 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
368 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
370 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
372 *(arg
--) = CVT_SCALING_VALUE_OFFSET(style_id
);
373 *(arg
--) = num_segments
;
376 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
378 FT_UInt first
= seg
->first
- points
;
379 FT_UInt last
= seg
->last
- points
;
384 first
= TA_adjust_point_index(recorder
, first
);
385 last
= TA_adjust_point_index(recorder
, last
);
387 low_nibble
= first
- base
;
388 high_nibble
= last
- first
;
390 *(arg
--) = 16 * high_nibble
+ low_nibble
;
395 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
397 FT_UInt first
= seg
->first
- points
;
398 FT_UInt last
= seg
->last
- points
;
401 *(arg
--) = TA_adjust_point_index(recorder
, first
);
402 *(arg
--) = TA_adjust_point_index(recorder
, last
);
404 /* we push the last and first contour point */
405 /* as a third and fourth argument in wrap-around segments */
408 for (n
= 0; n
< outline
.n_contours
; n
++)
410 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
415 *(arg
--) = TA_adjust_point_index(recorder
, end
);
420 *(arg
--) = TA_adjust_point_index(recorder
, 0);
422 *(arg
--) = TA_adjust_point_index(recorder
,
423 (FT_UInt
)outline
.contours
[n
- 1] + 1);
433 /* emit the second part of wrap-around segments as separate segments */
434 /* so that edges can easily link to them */
435 for (seg
= segments
; seg
< seg_limit
; seg
++)
437 FT_UInt first
= seg
->first
- points
;
438 FT_UInt last
= seg
->last
- points
;
443 for (n
= 0; n
< outline
.n_contours
; n
++)
445 if (first
<= (FT_UInt
)outline
.contours
[n
])
448 *(arg
--) = TA_adjust_point_index(recorder
, 0);
450 *(arg
--) = TA_adjust_point_index(recorder
,
451 (FT_UInt
)outline
.contours
[n
- 1] + 1);
456 *(arg
--) = TA_adjust_point_index(recorder
, last
);
460 /* with most fonts it is very rare */
461 /* that any of the pushed arguments is larger than 0xFF, */
462 /* thus we refrain from further optimizing this case */
463 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
467 num_storage
= sal_segment_offset
+ num_segments
* 2;
468 if (num_storage
> sfnt
->max_storage
)
469 sfnt
->max_storage
= num_storage
;
471 num_twilight_points
= num_segments
* 2;
472 if (num_twilight_points
> sfnt
->max_twilight_points
)
473 sfnt
->max_twilight_points
= num_twilight_points
;
475 /* both this function and `TA_emit_hints_record' */
476 /* push data onto the stack */
477 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
478 + recorder
->num_stack_elements
+ num_args
;
479 if (num_stack_elements
> sfnt
->max_stack_elements
)
480 sfnt
->max_stack_elements
= num_stack_elements
;
489 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
493 FONT
* font
= recorder
->font
;
494 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
495 FT_Vector
* points
= glyph
->outline
.points
;
496 FT_Int num_contours
= glyph
->outline
.n_contours
;
502 FT_Bool need_words
= 0;
505 FT_UShort num_stack_elements
;
508 num_args
= 2 * num_contours
+ 2;
510 /* collect all arguments temporarily in an array (in reverse order) */
511 /* so that we can easily split into chunks of 255 args */
512 /* as needed by NPUSHB and NPUSHW, respectively */
513 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
517 arg
= args
+ num_args
- 1;
522 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
523 *(arg
--) = bci_scale_composite_glyph
;
525 *(arg
--) = bci_scale_glyph
;
526 *(arg
--) = num_contours
;
531 for (p
= 0; p
< num_contours
; p
++)
537 end
= glyph
->outline
.contours
[p
];
539 for (q
= start
; q
<= end
; q
++)
541 if (points
[q
].y
< points
[min
].y
)
543 if (points
[q
].y
> points
[max
].y
)
549 *(arg
--) = TA_adjust_point_index(recorder
, max
);
550 *(arg
--) = TA_adjust_point_index(recorder
, min
);
554 *(arg
--) = TA_adjust_point_index(recorder
, min
);
555 *(arg
--) = TA_adjust_point_index(recorder
, max
);
564 /* with most fonts it is very rare */
565 /* that any of the pushed arguments is larger than 0xFF, */
566 /* thus we refrain from further optimizing this case */
567 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
571 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
572 if (num_stack_elements
> sfnt
->max_stack_elements
)
573 sfnt
->max_stack_elements
= num_stack_elements
;
582 TA_font_build_subglyph_shifter(FONT
* font
,
585 FT_Face face
= font
->loader
->face
;
586 FT_GlyphSlot glyph
= face
->glyph
;
588 TA_GlyphLoader gloader
= font
->loader
->gloader
;
590 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
591 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
592 TA_SubGlyph subglyph
;
594 FT_Int curr_contour
= 0;
597 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
601 FT_UShort flags
= subglyph
->flags
;
602 FT_Pos y_offset
= subglyph
->arg2
;
607 /* load subglyph to get the number of contours */
608 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
611 num_contours
= glyph
->outline
.n_contours
;
613 /* nothing to do if there is a point-to-point alignment */
614 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
617 /* nothing to do if y offset is zero */
621 /* nothing to do if there are no contours */
625 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
626 /* ensures that composite subglyphs are represented as simple glyphs */
628 if (num_contours
> 0xFF
629 || curr_contour
> 0xFF)
632 BCI(HIGH(curr_contour
));
633 BCI(LOW(curr_contour
));
634 BCI(HIGH(num_contours
));
635 BCI(LOW(num_contours
));
644 /* there are high chances that this value needs PUSHW, */
645 /* thus we handle it separately */
646 if (y_offset
> 0xFF || y_offset
< 0)
659 BCI(bci_shift_subglyph
);
663 curr_contour
+= num_contours
;
671 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
672 * data in four arrays (which are simple but waste a lot of memory). The
673 * function below converts them into bytecode.
675 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
676 * together with the edge they correspond to.
678 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
679 * loop over the edge or edge pairs, respectively, and each edge or edge
680 * pair contains an inner loop to emit the correponding points.
684 TA_build_point_hints(Recorder
* recorder
,
687 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
688 TA_Segment segments
= axis
->segments
;
689 TA_Edge edges
= axis
->edges
;
691 FT_Byte
* p
= recorder
->hints_record
.buf
;
697 FT_UShort prev_before_edge
;
698 FT_UShort prev_after_edge
;
706 /* we store everything as 16bit numbers; */
707 /* the function numbers (`ta_ip_before', etc.) */
708 /* reflect the order in the TA_Action enumeration */
710 /* ip_before_points */
713 for (before_node
= LLRB_MIN(ip_before_points
,
714 &recorder
->ip_before_points_head
);
716 before_node
= LLRB_NEXT(ip_before_points
,
717 &recorder
->ip_before_points_head
,
729 recorder
->hints_record
.num_actions
++;
734 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
735 *(p
++) = HIGH(edge
->first
- segments
);
736 *(p
++) = LOW(edge
->first
- segments
);
740 for (before_node
= LLRB_MIN(ip_before_points
,
741 &recorder
->ip_before_points_head
);
743 before_node
= LLRB_NEXT(ip_before_points
,
744 &recorder
->ip_before_points_head
,
750 point
= TA_adjust_point_index(recorder
, before_node
->point
);
751 *(p
++) = HIGH(point
);
756 /* ip_after_points */
759 for (after_node
= LLRB_MIN(ip_after_points
,
760 &recorder
->ip_after_points_head
);
762 after_node
= LLRB_NEXT(ip_after_points
,
763 &recorder
->ip_after_points_head
,
775 recorder
->hints_record
.num_actions
++;
777 edge
= edges
+ axis
->num_edges
- 1;
780 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
781 *(p
++) = HIGH(edge
->first
- segments
);
782 *(p
++) = LOW(edge
->first
- segments
);
786 for (after_node
= LLRB_MIN(ip_after_points
,
787 &recorder
->ip_after_points_head
);
789 after_node
= LLRB_NEXT(ip_after_points
,
790 &recorder
->ip_after_points_head
,
796 point
= TA_adjust_point_index(recorder
, after_node
->point
);
797 *(p
++) = HIGH(point
);
802 /* ip_on_point_array */
806 for (on_node
= LLRB_MIN(ip_on_points
,
807 &recorder
->ip_on_points_head
);
809 on_node
= LLRB_NEXT(ip_on_points
,
810 &recorder
->ip_on_points_head
,
814 if (on_node
->edge
!= prev_edge
)
817 prev_edge
= on_node
->edge
;
823 recorder
->hints_record
.num_actions
++;
826 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
830 for (on_node
= LLRB_MIN(ip_on_points
,
831 &recorder
->ip_on_points_head
);
833 on_node
= LLRB_NEXT(ip_on_points
,
834 &recorder
->ip_on_points_head
,
841 edge
= edges
+ on_node
->edge
;
843 *(p
++) = HIGH(edge
->first
- segments
);
844 *(p
++) = LOW(edge
->first
- segments
);
846 /* save current position */
851 on_node
= LLRB_NEXT(ip_on_points
,
852 &recorder
->ip_on_points_head
,
855 /* count points on current edge */
856 if (on_node
->edge
!= edge_node
->edge
)
864 /* restore current position */
868 on_node
= LLRB_NEXT(ip_on_points
,
869 &recorder
->ip_on_points_head
,
875 if (on_node
->edge
!= edge_node
->edge
)
878 point
= TA_adjust_point_index(recorder
, on_node
->point
);
879 *(p
++) = HIGH(point
);
882 /* keep track of previous node */
886 /* reset loop iterator by one element, then continue */
891 /* ip_between_point_array */
893 prev_before_edge
= 0xFFFF;
894 prev_after_edge
= 0xFFFF;
896 for (between_node
= LLRB_MIN(ip_between_points
,
897 &recorder
->ip_between_points_head
);
899 between_node
= LLRB_NEXT(ip_between_points
,
900 &recorder
->ip_between_points_head
,
903 /* count `(before,after)' edge pairs */
904 if (between_node
->before_edge
!= prev_before_edge
905 || between_node
->after_edge
!= prev_after_edge
)
908 prev_before_edge
= between_node
->before_edge
;
909 prev_after_edge
= between_node
->after_edge
;
915 recorder
->hints_record
.num_actions
++;
918 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
922 for (between_node
= LLRB_MIN(ip_between_points
,
923 &recorder
->ip_between_points_head
);
925 between_node
= LLRB_NEXT(ip_between_points
,
926 &recorder
->ip_between_points_head
,
929 Node3
* edge_pair_node
;
934 before
= edges
+ between_node
->before_edge
;
935 after
= edges
+ between_node
->after_edge
;
937 *(p
++) = HIGH(after
->first
- segments
);
938 *(p
++) = LOW(after
->first
- segments
);
939 *(p
++) = HIGH(before
->first
- segments
);
940 *(p
++) = LOW(before
->first
- segments
);
942 /* save current position */
943 edge_pair_node
= between_node
;
947 between_node
= LLRB_NEXT(ip_between_points
,
948 &recorder
->ip_between_points_head
,
951 /* count points associated with current edge pair */
952 if (between_node
->before_edge
!= edge_pair_node
->before_edge
953 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
961 /* restore current position */
962 between_node
= edge_pair_node
;
965 between_node
= LLRB_NEXT(ip_between_points
,
966 &recorder
->ip_between_points_head
,
972 if (between_node
->before_edge
!= edge_pair_node
->before_edge
973 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
976 point
= TA_adjust_point_index(recorder
, between_node
->point
);
977 *(p
++) = HIGH(point
);
980 /* keep track of previous node */
981 edge_pair_node
= between_node
;
984 /* reset loop iterator by one element, then continue */
985 between_node
= edge_pair_node
;
989 recorder
->hints_record
.buf
= p
;
994 TA_hints_record_is_different(Hints_Record
* hints_records
,
995 FT_UInt num_hints_records
,
999 Hints_Record last_hints_record
;
1005 /* we only need to compare with the last hints record */
1006 last_hints_record
= hints_records
[num_hints_records
- 1];
1008 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1011 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1019 TA_add_hints_record(Hints_Record
** hints_records
,
1020 FT_UInt
* num_hints_records
,
1022 Hints_Record hints_record
)
1024 Hints_Record
* hints_records_new
;
1026 /* at this point, `hints_record.buf' still points into `ins_buf' */
1027 FT_Byte
* end
= hints_record
.buf
;
1030 buf_len
= (FT_UInt
)(end
- start
);
1032 /* now fill the structure completely */
1033 hints_record
.buf_len
= buf_len
;
1034 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1035 if (!hints_record
.buf
)
1036 return FT_Err_Out_Of_Memory
;
1038 memcpy(hints_record
.buf
, start
, buf_len
);
1040 (*num_hints_records
)++;
1042 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1043 * sizeof (Hints_Record
));
1044 if (!hints_records_new
)
1046 free(hints_record
.buf
);
1047 (*num_hints_records
)--;
1048 return FT_Err_Out_Of_Memory
;
1051 *hints_records
= hints_records_new
;
1053 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1060 TA_emit_hints_record(Recorder
* recorder
,
1061 Hints_Record
* hints_record
,
1067 FT_Bool need_words
= 0;
1070 FT_UInt num_arguments
;
1074 /* check whether any argument is larger than 0xFF */
1075 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1076 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1083 /* with most fonts it is very rare */
1084 /* that any of the pushed arguments is larger than 0xFF, */
1085 /* thus we refrain from further optimizing this case */
1087 num_arguments
= hints_record
->buf_len
/ 2;
1092 for (i
= 0; i
< num_arguments
; i
+= 255)
1094 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1096 if (optimize
&& num_args
<= 8)
1097 BCI(PUSHW_1
- 1 + num_args
);
1103 for (j
= 0; j
< num_args
; j
++)
1113 /* we only need the lower bytes */
1116 for (i
= 0; i
< num_arguments
; i
+= 255)
1118 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1120 if (optimize
&& num_args
<= 8)
1121 BCI(PUSHB_1
- 1 + num_args
);
1127 for (j
= 0; j
< num_args
; j
++)
1135 /* collect stack depth data */
1136 if (num_arguments
> recorder
->num_stack_elements
)
1137 recorder
->num_stack_elements
= num_arguments
;
1144 TA_emit_hints_records(Recorder
* recorder
,
1145 Hints_Record
* hints_records
,
1146 FT_UInt num_hints_records
,
1151 Hints_Record
* hints_record
;
1154 hints_record
= hints_records
;
1156 /* emit hints records in `if' clauses, */
1157 /* with the ppem size as the condition */
1158 for (i
= 0; i
< num_hints_records
- 1; i
++)
1161 if (hints_record
->size
> 0xFF)
1164 BCI(HIGH((hints_record
+ 1)->size
));
1165 BCI(LOW((hints_record
+ 1)->size
));
1170 BCI((hints_record
+ 1)->size
);
1174 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1180 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1182 for (i
= 0; i
< num_hints_records
- 1; i
++)
1190 TA_free_hints_records(Hints_Record
* hints_records
,
1191 FT_UInt num_hints_records
)
1196 for (i
= 0; i
< num_hints_records
; i
++)
1197 free(hints_records
[i
].buf
);
1199 free(hints_records
);
1204 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1209 TA_Segment segments
= axis
->segments
;
1212 FT_UShort num_segs
= 0;
1216 seg_idx
= edge
->first
- segments
;
1218 /* we store everything as 16bit numbers */
1219 *(bufp
++) = HIGH(seg_idx
);
1220 *(bufp
++) = LOW(seg_idx
);
1222 /* wrap-around segments are stored as two segments */
1223 if (edge
->first
->first
> edge
->first
->last
)
1226 seg
= edge
->first
->edge_next
;
1227 while (seg
!= edge
->first
)
1231 if (seg
->first
> seg
->last
)
1234 seg
= seg
->edge_next
;
1237 *(bufp
++) = HIGH(num_segs
);
1238 *(bufp
++) = LOW(num_segs
);
1240 if (edge
->first
->first
> edge
->first
->last
)
1242 /* emit second part of wrap-around segment; */
1243 /* the bytecode positions such segments after `normal' ones */
1247 if (seg_idx
== *wrap
)
1252 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1253 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1256 seg
= edge
->first
->edge_next
;
1257 while (seg
!= edge
->first
)
1259 seg_idx
= seg
- segments
;
1261 *(bufp
++) = HIGH(seg_idx
);
1262 *(bufp
++) = LOW(seg_idx
);
1264 if (seg
->first
> seg
->last
)
1269 if (seg_idx
== *wrap
)
1274 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1275 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1278 seg
= seg
->edge_next
;
1286 TA_hints_recorder(TA_Action action
,
1287 TA_GlyphHints hints
,
1292 TA_Edge lower_bound
,
1293 TA_Edge upper_bound
)
1295 TA_AxisHints axis
= &hints
->axis
[dim
];
1296 TA_Edge edges
= axis
->edges
;
1297 TA_Segment segments
= axis
->segments
;
1298 TA_Point points
= hints
->points
;
1300 Recorder
* recorder
= (Recorder
*)hints
->user
;
1301 SFNT
* sfnt
= recorder
->sfnt
;
1302 FONT
* font
= recorder
->font
;
1303 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1304 FT_Byte
* p
= recorder
->hints_record
.buf
;
1306 FT_UInt style
= font
->loader
->metrics
->style_class
->style
;
1309 if (dim
== TA_DIMENSION_HORZ
)
1312 /* we collect point hints for later processing */
1318 TA_Point point
= (TA_Point
)arg1
;
1321 before_node
= (Node1
*)malloc(sizeof (Node1
));
1324 before_node
->point
= point
- points
;
1326 LLRB_INSERT(ip_before_points
,
1327 &recorder
->ip_before_points_head
,
1335 TA_Point point
= (TA_Point
)arg1
;
1338 after_node
= (Node1
*)malloc(sizeof (Node1
));
1341 after_node
->point
= point
- points
;
1343 LLRB_INSERT(ip_after_points
,
1344 &recorder
->ip_after_points_head
,
1352 TA_Point point
= (TA_Point
)arg1
;
1353 TA_Edge edge
= arg2
;
1356 on_node
= (Node2
*)malloc(sizeof (Node2
));
1359 on_node
->edge
= edge
- edges
;
1360 on_node
->point
= point
- points
;
1362 LLRB_INSERT(ip_on_points
,
1363 &recorder
->ip_on_points_head
,
1370 Node3
* between_node
;
1371 TA_Point point
= (TA_Point
)arg1
;
1372 TA_Edge before
= arg2
;
1373 TA_Edge after
= arg3
;
1376 between_node
= (Node3
*)malloc(sizeof (Node3
));
1379 between_node
->before_edge
= before
- edges
;
1380 between_node
->after_edge
= after
- edges
;
1381 between_node
->point
= point
- points
;
1383 LLRB_INSERT(ip_between_points
,
1384 &recorder
->ip_between_points_head
,
1390 /* we ignore the BOUND action since we signal this information */
1391 /* with the proper function number */
1398 /* some enum values correspond to four or eight bytecode functions; */
1399 /* if the value is n, the function numbers are n, ..., n+7, */
1400 /* to be differentiated with flags */
1406 TA_Edge base_edge
= (TA_Edge
)arg1
;
1407 TA_Edge stem_edge
= arg2
;
1411 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1412 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1413 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1415 *(p
++) = HIGH(base_edge
->first
- segments
);
1416 *(p
++) = LOW(base_edge
->first
- segments
);
1417 *(p
++) = HIGH(stem_edge
->first
- segments
);
1418 *(p
++) = LOW(stem_edge
->first
- segments
);
1420 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1426 TA_Edge edge
= (TA_Edge
)arg1
;
1427 TA_Edge edge2
= arg2
;
1431 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1432 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1433 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1435 *(p
++) = HIGH(edge
->first
- segments
);
1436 *(p
++) = LOW(edge
->first
- segments
);
1437 *(p
++) = HIGH(edge2
->first
- segments
);
1438 *(p
++) = LOW(edge2
->first
- segments
);
1440 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1446 TA_Edge edge
= (TA_Edge
)arg1
;
1447 TA_Edge edge2
= arg2
;
1448 TA_Edge edge_minus_one
= lower_bound
;
1452 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1453 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1454 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1455 + 4 * (edge_minus_one
!= NULL
);
1457 *(p
++) = HIGH(edge
->first
- segments
);
1458 *(p
++) = LOW(edge
->first
- segments
);
1459 *(p
++) = HIGH(edge2
->first
- segments
);
1460 *(p
++) = LOW(edge2
->first
- segments
);
1464 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1465 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1468 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1472 case ta_blue_anchor
:
1474 TA_Edge edge
= (TA_Edge
)arg1
;
1475 TA_Edge blue
= arg2
;
1479 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1481 *(p
++) = HIGH(blue
->first
- segments
);
1482 *(p
++) = LOW(blue
->first
- segments
);
1484 if (edge
->best_blue_is_shoot
)
1486 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1487 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1491 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1492 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1495 *(p
++) = HIGH(edge
->first
- segments
);
1496 *(p
++) = LOW(edge
->first
- segments
);
1498 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1504 TA_Edge edge
= (TA_Edge
)arg1
;
1505 TA_Edge edge2
= arg2
;
1506 TA_Edge edge_minus_one
= lower_bound
;
1510 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1511 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1512 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1513 + 4 * (edge_minus_one
!= NULL
);
1515 *(p
++) = HIGH(edge
->first
- segments
);
1516 *(p
++) = LOW(edge
->first
- segments
);
1517 *(p
++) = HIGH(edge2
->first
- segments
);
1518 *(p
++) = LOW(edge2
->first
- segments
);
1522 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1523 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1526 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1527 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1533 TA_Edge edge
= (TA_Edge
)arg1
;
1537 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1539 if (edge
->best_blue_is_shoot
)
1541 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1542 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1546 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1547 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1550 *(p
++) = HIGH(edge
->first
- segments
);
1551 *(p
++) = LOW(edge
->first
- segments
);
1553 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1559 TA_Edge serif
= (TA_Edge
)arg1
;
1560 TA_Edge base
= serif
->serif
;
1564 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1565 + (lower_bound
!= NULL
)
1566 + 2 * (upper_bound
!= NULL
);
1568 *(p
++) = HIGH(serif
->first
- segments
);
1569 *(p
++) = LOW(serif
->first
- segments
);
1570 *(p
++) = HIGH(base
->first
- segments
);
1571 *(p
++) = LOW(base
->first
- segments
);
1575 *(p
++) = HIGH(lower_bound
->first
- segments
);
1576 *(p
++) = LOW(lower_bound
->first
- segments
);
1580 *(p
++) = HIGH(upper_bound
->first
- segments
);
1581 *(p
++) = LOW(upper_bound
->first
- segments
);
1584 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1588 case ta_serif_anchor
:
1589 case ta_serif_link2
:
1591 TA_Edge edge
= (TA_Edge
)arg1
;
1595 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1596 + (lower_bound
!= NULL
)
1597 + 2 * (upper_bound
!= NULL
);
1599 *(p
++) = HIGH(edge
->first
- segments
);
1600 *(p
++) = LOW(edge
->first
- segments
);
1604 *(p
++) = HIGH(lower_bound
->first
- segments
);
1605 *(p
++) = LOW(lower_bound
->first
- segments
);
1609 *(p
++) = HIGH(upper_bound
->first
- segments
);
1610 *(p
++) = LOW(upper_bound
->first
- segments
);
1613 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1617 case ta_serif_link1
:
1619 TA_Edge edge
= (TA_Edge
)arg1
;
1620 TA_Edge before
= arg2
;
1621 TA_Edge after
= arg3
;
1625 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1626 + (lower_bound
!= NULL
)
1627 + 2 * (upper_bound
!= NULL
);
1629 *(p
++) = HIGH(before
->first
- segments
);
1630 *(p
++) = LOW(before
->first
- segments
);
1631 *(p
++) = HIGH(edge
->first
- segments
);
1632 *(p
++) = LOW(edge
->first
- segments
);
1633 *(p
++) = HIGH(after
->first
- segments
);
1634 *(p
++) = LOW(after
->first
- segments
);
1638 *(p
++) = HIGH(lower_bound
->first
- segments
);
1639 *(p
++) = LOW(lower_bound
->first
- segments
);
1643 *(p
++) = HIGH(upper_bound
->first
- segments
);
1644 *(p
++) = LOW(upper_bound
->first
- segments
);
1647 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1652 /* there are more cases in the enumeration */
1653 /* which are handled with flags */
1657 recorder
->hints_record
.num_actions
++;
1658 recorder
->hints_record
.buf
= p
;
1663 TA_init_recorder(Recorder
* recorder
,
1667 TA_GlyphHints hints
)
1669 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1670 TA_Point points
= hints
->points
;
1671 TA_Point point_limit
= points
+ hints
->num_points
;
1674 TA_Segment segments
= axis
->segments
;
1675 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1678 FT_UShort num_strong_points
= 0;
1679 FT_UShort
* wrap_around_segment
;
1681 recorder
->sfnt
= sfnt
;
1682 recorder
->font
= font
;
1683 recorder
->glyph
= glyph
;
1684 recorder
->num_segments
= axis
->num_segments
;
1686 LLRB_INIT(&recorder
->ip_before_points_head
);
1687 LLRB_INIT(&recorder
->ip_after_points_head
);
1688 LLRB_INIT(&recorder
->ip_on_points_head
);
1689 LLRB_INIT(&recorder
->ip_between_points_head
);
1691 recorder
->num_stack_elements
= 0;
1693 /* no need to clean up allocated arrays in case of error; */
1694 /* this is handled later by `TA_free_recorder' */
1696 recorder
->num_wrap_around_segments
= 0;
1697 for (seg
= segments
; seg
< seg_limit
; seg
++)
1698 if (seg
->first
> seg
->last
)
1699 recorder
->num_wrap_around_segments
++;
1701 recorder
->wrap_around_segments
=
1702 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
1703 * sizeof (FT_UShort
));
1704 if (!recorder
->wrap_around_segments
)
1705 return FT_Err_Out_Of_Memory
;
1707 wrap_around_segment
= recorder
->wrap_around_segments
;
1708 for (seg
= segments
; seg
< seg_limit
; seg
++)
1709 if (seg
->first
> seg
->last
)
1710 *(wrap_around_segment
++) = seg
- segments
;
1712 /* get number of strong points */
1713 for (point
= points
; point
< point_limit
; point
++)
1715 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
1716 /* however, this value isn't known yet */
1717 /* (or rather, it can vary between different pixel sizes) */
1718 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
1721 num_strong_points
++;
1724 recorder
->num_strong_points
= num_strong_points
;
1731 TA_reset_recorder(Recorder
* recorder
,
1734 recorder
->hints_record
.buf
= bufp
;
1735 recorder
->hints_record
.num_actions
= 0;
1740 TA_rewind_recorder(Recorder
* recorder
,
1747 Node3
* between_node
;
1749 Node1
* next_before_node
;
1750 Node1
* next_after_node
;
1751 Node2
* next_on_node
;
1752 Node3
* next_between_node
;
1755 TA_reset_recorder(recorder
, bufp
);
1757 recorder
->hints_record
.size
= size
;
1759 /* deallocate our red-black trees */
1761 for (before_node
= LLRB_MIN(ip_before_points
,
1762 &recorder
->ip_before_points_head
);
1764 before_node
= next_before_node
)
1766 next_before_node
= LLRB_NEXT(ip_before_points
,
1767 &recorder
->ip_before_points_head
,
1769 LLRB_REMOVE(ip_before_points
,
1770 &recorder
->ip_before_points_head
,
1775 for (after_node
= LLRB_MIN(ip_after_points
,
1776 &recorder
->ip_after_points_head
);
1778 after_node
= next_after_node
)
1780 next_after_node
= LLRB_NEXT(ip_after_points
,
1781 &recorder
->ip_after_points_head
,
1783 LLRB_REMOVE(ip_after_points
,
1784 &recorder
->ip_after_points_head
,
1789 for (on_node
= LLRB_MIN(ip_on_points
,
1790 &recorder
->ip_on_points_head
);
1792 on_node
= next_on_node
)
1794 next_on_node
= LLRB_NEXT(ip_on_points
,
1795 &recorder
->ip_on_points_head
,
1797 LLRB_REMOVE(ip_on_points
,
1798 &recorder
->ip_on_points_head
,
1803 for (between_node
= LLRB_MIN(ip_between_points
,
1804 &recorder
->ip_between_points_head
);
1806 between_node
= next_between_node
)
1808 next_between_node
= LLRB_NEXT(ip_between_points
,
1809 &recorder
->ip_between_points_head
,
1811 LLRB_REMOVE(ip_between_points
,
1812 &recorder
->ip_between_points_head
,
1820 TA_free_recorder(Recorder
* recorder
)
1822 free(recorder
->wrap_around_segments
);
1824 TA_rewind_recorder(recorder
, NULL
, 0);
1829 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
1833 FT_Face face
= sfnt
->face
;
1841 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1842 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
1843 /* `idx' is never negative */
1844 GLYPH
* glyph
= &data
->glyphs
[idx
];
1846 TA_GlyphHints hints
;
1848 FT_UInt num_action_hints_records
= 0;
1849 FT_UInt num_point_hints_records
= 0;
1850 Hints_Record
* action_hints_records
= NULL
;
1851 Hints_Record
* point_hints_records
= NULL
;
1854 FT_UShort num_stack_elements
;
1855 FT_Bool optimize
= 0;
1857 FT_Int32 load_flags
;
1867 /* XXX: right now, we abuse this flag to control */
1868 /* the global behaviour of the auto-hinter */
1869 load_flags
= 1 << 29; /* vertical hinting only */
1870 if (!font
->adjust_subglyphs
)
1872 if (font
->hint_composites
)
1873 load_flags
|= FT_LOAD_NO_SCALE
;
1875 load_flags
|= FT_LOAD_NO_RECURSE
;
1878 /* computing the segments is resolution independent, */
1879 /* thus the pixel size in this call is arbitrary -- */
1880 /* however, we avoid unnecessary debugging output */
1881 /* if we use the lowest value of the hinting range */
1882 error
= FT_Set_Pixel_Sizes(face
,
1883 font
->hinting_range_min
,
1884 font
->hinting_range_min
);
1889 /* temporarily disable some debugging output */
1890 /* to avoid getting the information twice */
1891 _ta_debug_save
= _ta_debug
;
1895 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
1896 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
1899 _ta_debug
= _ta_debug_save
;
1905 /* do nothing if we have an empty glyph */
1906 if (!face
->glyph
->outline
.n_contours
)
1909 hints
= &font
->loader
->hints
;
1911 /* do nothing if the setup delivered the `none_dflt' style only */
1912 if (!hints
->num_points
)
1915 /* we allocate a buffer which is certainly large enough */
1916 /* to hold all of the created bytecode instructions; */
1917 /* later on it gets reallocated to its real size */
1918 ins_len
= hints
->num_points
* 1000;
1919 ins_buf
= (FT_Byte
*)malloc(ins_len
);
1921 return FT_Err_Out_Of_Memory
;
1923 /* initialize array with an invalid bytecode */
1924 /* so that we can easily find the array length at reallocation time */
1925 memset(ins_buf
, INS_A0
, ins_len
);
1927 /* handle composite glyph */
1928 if (font
->loader
->gloader
->base
.num_subglyphs
)
1930 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
1933 error
= FT_Err_Out_Of_Memory
;
1940 /* only scale the glyph if the `none_dflt' style has been used */
1941 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
1943 /* since `TA_init_recorder' hasn't been called yet, */
1944 /* we manually initialize the `sfnt', `font', and `glyph' fields */
1945 recorder
.sfnt
= sfnt
;
1946 recorder
.font
= font
;
1947 recorder
.glyph
= glyph
;
1949 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
1952 error
= FT_Err_Out_Of_Memory
;
1959 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
1963 /* loop over a large range of pixel sizes */
1964 /* to find hints records which get pushed onto the bytecode stack */
1973 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
1975 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
1977 num_chars
+= fprintf(stderr
, " (%s)", buf
);
1978 fprintf(stderr
, "\n");
1979 for (i
= 0; i
< num_chars
; i
++)
1981 fprintf(stderr
, "\n\n");
1986 /* we temporarily use `ins_buf' to record the current glyph hints */
1987 ta_loader_register_hints_recorder(font
->loader
,
1991 for (size
= font
->hinting_range_min
;
1992 size
<= font
->hinting_range_max
;
2000 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2002 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2012 num_chars
= fprintf(stderr
, "size %d\n", size
);
2013 for (i
= 0; i
< num_chars
- 1; i
++)
2015 fprintf(stderr
, "\n\n");
2019 /* calling `ta_loader_load_glyph' uses the */
2020 /* `TA_hints_recorder' function as a callback, */
2021 /* modifying `hints_record' */
2022 error
= ta_loader_load_glyph(font
, face
, idx
, load_flags
);
2026 if (TA_hints_record_is_different(action_hints_records
,
2027 num_action_hints_records
,
2028 ins_buf
, recorder
.hints_record
.buf
))
2035 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2036 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2037 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2039 fprintf(stderr
, "action hints record:\n");
2040 if (ins_buf
== recorder
.hints_record
.buf
)
2041 fprintf(stderr
, " (none)");
2044 fprintf(stderr
, " ");
2045 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2046 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2048 fprintf(stderr
, "\n");
2052 error
= TA_add_hints_record(&action_hints_records
,
2053 &num_action_hints_records
,
2054 ins_buf
, recorder
.hints_record
);
2059 /* now handle point records */
2061 TA_reset_recorder(&recorder
, ins_buf
);
2063 /* use the point hints data collected in `TA_hints_recorder' */
2064 TA_build_point_hints(&recorder
, hints
);
2066 if (TA_hints_record_is_different(point_hints_records
,
2067 num_point_hints_records
,
2068 ins_buf
, recorder
.hints_record
.buf
))
2078 num_chars
= fprintf(stderr
, "size %d\n", size
);
2079 for (i
= 0; i
< num_chars
- 1; i
++)
2081 fprintf(stderr
, "\n\n");
2083 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2084 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2085 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2088 fprintf(stderr
, "point hints record:\n");
2089 if (ins_buf
== recorder
.hints_record
.buf
)
2090 fprintf(stderr
, " (none)");
2093 fprintf(stderr
, " ");
2094 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2095 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2097 fprintf(stderr
, "\n\n");
2101 error
= TA_add_hints_record(&point_hints_records
,
2102 &num_point_hints_records
,
2103 ins_buf
, recorder
.hints_record
);
2109 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2111 /* since we only have a single empty record we just scale the glyph */
2112 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2115 error
= FT_Err_Out_Of_Memory
;
2119 /* clear the rest of the temporarily used part of `ins_buf' */
2121 while (*p
!= INS_A0
)
2127 /* if there is only a single record, */
2128 /* we do a global optimization later on */
2129 if (num_action_hints_records
> 1)
2132 /* store the hints records and handle stack depth */
2134 bufp
= TA_emit_hints_records(&recorder
,
2135 point_hints_records
,
2136 num_point_hints_records
,
2140 num_stack_elements
= recorder
.num_stack_elements
;
2141 recorder
.num_stack_elements
= 0;
2144 bufp
= TA_emit_hints_records(&recorder
,
2145 action_hints_records
,
2146 num_action_hints_records
,
2150 recorder
.num_stack_elements
+= num_stack_elements
;
2153 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
2156 error
= FT_Err_Out_Of_Memory
;
2160 /* XXX improve handling of NPUSHW */
2161 if (num_action_hints_records
== 1
2162 && *(pos
[0]) != NPUSHW
&& *(pos
[1]) != NPUSHW
&& *(pos
[2]) != NPUSHW
)
2165 * we optimize two common cases, replacing
2167 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
2171 * NPUSHB (A+B[+C]) ... CALL
2184 /* the point hints records block can be missing */
2185 if (pos
[0] == pos
[1])
2191 /* there are at least two NPUSHB instructions */
2192 /* (one of them directly at the start) */
2193 sizes
[0] = *(pos
[0] + 1);
2194 sizes
[1] = *(pos
[1] + 1);
2195 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
2197 sum
= sizes
[0] + sizes
[1] + sizes
[2];
2200 goto Done2
; /* nothing to do since we need three NPUSHB */
2201 else if (!sizes
[2] && (sum
> 0xFF))
2202 goto Done2
; /* nothing to do since we need two NPUSHB */
2206 /* reduce three NPUSHB to two */
2208 new_size2
= sum
- 0xFF;
2212 /* reduce two or three NPUSHB to one */
2223 BCI(PUSHB_1
- 1 + new_size1
);
2229 for (i
= 0; i
< new_size1
; i
++)
2231 if (p
== pos
[pos_idx
])
2234 p
+= 2; /* skip old NPUSHB */
2242 BCI(PUSHB_1
- 1 + new_size2
);
2248 for (i
= 0; i
< new_size2
; i
++)
2250 if (p
== pos
[pos_idx
])
2263 /* clear the rest of the temporarily used part of `ins_buf' */
2265 while (*p
!= INS_A0
)
2269 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2270 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2271 TA_free_recorder(&recorder
);
2273 /* we are done, so reallocate the instruction array to its real size */
2274 if (*bufp
== INS_A0
)
2276 /* search backwards */
2277 while (*bufp
== INS_A0
)
2283 /* search forwards */
2284 while (*bufp
!= INS_A0
)
2289 ins_len
= bufp
- ins_buf
;
2291 if (ins_len
> sfnt
->max_instructions
)
2292 sfnt
->max_instructions
= ins_len
;
2294 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2295 glyph
->ins_len
= ins_len
;
2300 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2301 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2302 TA_free_recorder(&recorder
);
2309 /* end of tabytecode.c */