4 * Copyright (C) 2011-2017 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.
18 #include <stdbool.h> /* for llrb.h */
20 #include "llrb.h" /* a red-black tree implementation */
29 int _ta_debug_global
= 0;
30 int _ta_debug_disable_horz_hints
;
31 int _ta_debug_disable_vert_hints
;
32 int _ta_debug_disable_blue_hints
;
33 void* _ta_debug_hints
;
37 /* node structures for point hints */
39 typedef struct Node1 Node1
;
42 LLRB_ENTRY(Node1
) entry1
;
46 typedef struct Node2 Node2
;
49 LLRB_ENTRY(Node2
) entry2
;
54 typedef struct Node3 Node3
;
57 LLRB_ENTRY(Node3
) entry3
;
58 FT_UShort before_edge
;
64 /* comparison functions for our red-black trees */
71 return e1
->point
- e2
->point
;
81 /* sort by edges ... */
82 delta
= (FT_Int
)e1
->edge
- (FT_Int
)e2
->edge
;
86 /* ... then by points */
87 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
97 /* sort by `before' edges ... */
98 delta
= (FT_Int
)e1
->before_edge
- (FT_Int
)e2
->before_edge
;
102 /* ... then by `after' edges ... */
103 delta
= (FT_Int
)e1
->after_edge
- (FT_Int
)e2
->after_edge
;
107 /* ... then by points */
108 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
112 /* the red-black tree function bodies */
113 typedef struct ip_before_points ip_before_points
;
114 typedef struct ip_after_points ip_after_points
;
115 typedef struct ip_on_points ip_on_points
;
116 typedef struct ip_between_points ip_between_points
;
118 LLRB_HEAD(ip_before_points
, Node1
);
119 LLRB_HEAD(ip_after_points
, Node1
);
120 LLRB_HEAD(ip_on_points
, Node2
);
121 LLRB_HEAD(ip_between_points
, Node3
);
123 /* no trailing semicolon in the next four lines */
124 LLRB_GENERATE_STATIC(ip_before_points
, Node1
, entry1
, node1cmp
)
125 LLRB_GENERATE_STATIC(ip_after_points
, Node1
, entry1
, node1cmp
)
126 LLRB_GENERATE_STATIC(ip_on_points
, Node2
, entry2
, node2cmp
)
127 LLRB_GENERATE_STATIC(ip_between_points
, Node3
, entry3
, node3cmp
)
130 typedef struct Hints_Record_
138 typedef struct Recorder_
142 GLYPH
* glyph
; /* the current glyph */
143 Hints_Record hints_record
;
145 /* some segments can `wrap around' */
146 /* a contour's start point like 24-25-26-0-1-2 */
147 /* (there can be at most one such segment per contour); */
148 /* later on we append additional records */
149 /* to split them into 24-26 and 0-2 */
150 FT_UShort
* wrap_around_segments
;
151 FT_UShort num_wrap_around_segments
;
152 FT_Bool wrap_around_segments_initialized
;
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 /* we omit one-point segments not part of an edge, */
163 /* thus we have to adjust indices into the `segments' array */
164 FT_UShort
* segment_map
;
165 FT_Bool segment_map_initialized
;
169 /* this is the bytecode of the `.ttfautohint' glyph */
171 FT_Byte ttfautohint_glyph_bytecode
[7] =
174 /* increment `cvtl_is_subglyph' counter */
186 /* if we have y delta exceptions before IUP_y, this code gets inserted */
187 static FT_Byte ins_extra_delta_exceptions
[4] =
190 /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
199 /* if we have a non-base glyph, this code gets inserted */
200 static FT_Byte ins_extra_ignore_std_width
[4] =
203 /* tell bci_{smooth,strong}_stem_width to ignore std_width */
205 cvtl_ignore_std_width
,
213 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
214 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
215 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
220 TA_build_push(FT_Byte
* bufp
,
232 for (i
= 0; i
< num_args
; i
+= 255)
234 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
236 if (optimize
&& nargs
<= 8)
237 BCI(PUSHW_1
- 1 + nargs
);
243 for (j
= 0; j
< nargs
; j
++)
253 for (i
= 0; i
< num_args
; i
+= 255)
255 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
257 if (optimize
&& nargs
<= 8)
258 BCI(PUSHB_1
- 1 + nargs
);
264 for (j
= 0; j
< nargs
; j
++)
277 * We optimize two common cases, replacing
279 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
283 * NPUSHB (A+B[+C]) ... CALL
289 TA_optimize_push(FT_Byte
* buf
,
304 /* XXX improve handling of NPUSHW */
305 if (*(pos
[0]) == NPUSHW
306 || *(pos
[1]) == NPUSHW
307 || *(pos
[2]) == NPUSHW
)
310 /* the point hints records block can be missing */
311 if (pos
[0] == pos
[1])
317 /* only needed for the algorithm loops below */
320 /* there are at least two NPUSHB instructions */
321 /* (one of them directly at the start) */
322 sizes
[0] = *(pos
[0] + 1);
323 sizes
[1] = *(pos
[1] + 1);
324 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
326 sum
= sizes
[0] + sizes
[1] + sizes
[2];
329 return buf
; /* nothing to do since we need three NPUSHB */
330 else if (!sizes
[2] && (sum
> 0xFF))
331 return buf
; /* nothing to do since we need two NPUSHB */
335 /* reduce three NPUSHB to two */
337 new_size2
= (FT_Byte
)(sum
- 0xFF);
341 /* reduce two or three NPUSHB to one */
342 new_size1
= (FT_Byte
)sum
;
352 BCI(PUSHB_1
- 1 + new_size1
);
358 for (i
= 0; i
< new_size1
; i
++)
360 if (p
== pos
[pos_idx
])
363 p
+= 2; /* skip old NPUSHB */
371 BCI(PUSHB_1
- 1 + new_size2
);
377 for (i
= 0; i
< new_size2
; i
++)
379 if (p
== pos
[pos_idx
])
394 /* We add a subglyph for each composite glyph. */
395 /* Since subglyphs must contain at least one point, */
396 /* we have to adjust all point indices accordingly. */
397 /* Using the `pointsums' array of the `GLYPH' structure */
398 /* it is straightforward to do that: */
399 /* Assuming that point with index x is in the interval */
400 /* pointsums[n] <= x < pointsums[n + 1], */
401 /* the new point index is x + n. */
404 TA_adjust_point_index(Recorder
* recorder
,
407 FONT
* font
= recorder
->font
;
408 GLYPH
* glyph
= recorder
->glyph
;
412 if (!glyph
->num_components
|| !font
->hint_composites
)
413 return idx
; /* not a composite glyph */
415 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
416 if (idx
< glyph
->pointsums
[i
])
423 /* We omit one-point segments not part of an edge, */
424 /* thus we have to adjust indices into the `segments' array. */
425 /* If `segment' is NULL, the number of all segments */
426 /* without non-edge one-point segments is returned. */
429 TA_get_segment_index(TA_Segment segment
,
432 FONT
* font
= recorder
->font
;
433 TA_GlyphHints hints
= &font
->loader
->hints
;
434 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
437 return segment
? recorder
->segment_map
[segment
- axis
->segments
]
438 : recorder
->segment_map
[axis
->num_segments
];
442 /* we store the segments in the storage area; */
443 /* each segment record consists of the first and last point */
446 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
451 FONT
* font
= recorder
->font
;
452 TA_GlyphHints hints
= &font
->loader
->hints
;
453 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
454 TA_Point points
= hints
->points
;
455 TA_Segment segments
= axis
->segments
;
457 TA_Segment seg_limit
;
459 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
460 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
462 FT_UInt style_id
= data
->style_ids
463 [font
->loader
->metrics
->style_class
->style
];
465 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
470 FT_UShort num_segments
;
472 FT_Bool need_words
= 0;
476 FT_UShort num_packed_segments
;
477 FT_UShort num_storage
;
478 FT_UShort num_stack_elements
;
479 FT_UShort num_twilight_points
;
482 seg_limit
= segments
+ axis
->num_segments
;
483 num_segments
= TA_get_segment_index(NULL
, recorder
);
485 /* to pack the data in the bytecode more tightly, */
486 /* we store up to the first nine segments in nibbles if possible, */
487 /* using delta values */
489 num_packed_segments
= 0;
490 for (seg
= segments
; seg
< seg_limit
; seg
++)
492 FT_UInt first
= (FT_UInt
)(seg
->first
- points
);
493 FT_UInt last
= (FT_UInt
)(seg
->last
- points
);
496 if (TA_get_segment_index(seg
, recorder
) == 0xFFFF)
499 first
= TA_adjust_point_index(recorder
, first
);
500 last
= TA_adjust_point_index(recorder
, last
);
502 if (first
- base
>= 16)
504 if (first
> last
|| last
- first
>= 16)
506 if (num_packed_segments
== 9)
508 num_packed_segments
++;
512 /* also handle wrap-around segments */
513 num_segments
+= recorder
->num_wrap_around_segments
;
515 /* wrap-around segments are pushed with four arguments; */
516 /* a segment stored in nibbles needs only one byte instead of two */
517 num_args
= num_packed_segments
518 + 2 * (num_segments
- num_packed_segments
)
519 + 2 * recorder
->num_wrap_around_segments
522 /* collect all arguments temporarily in an array (in reverse order) */
523 /* so that we can easily split into chunks of 255 args */
524 /* as needed by NPUSHB and NPUSHW, respectively */
525 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
529 arg
= args
+ num_args
- 1;
531 if (num_segments
> 0xFF)
534 /* the number of packed segments is indicated by the function number */
535 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
536 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
538 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
540 *(arg
--) = CVT_SCALING_VALUE_OFFSET(style_id
);
541 *(arg
--) = num_segments
;
545 for (seg
= segments
; seg
< seg_limit
; seg
++)
547 FT_UInt first
= (FT_UInt
)(seg
->first
- points
);
548 FT_UInt last
= (FT_UInt
)(seg
->last
- points
);
553 if (TA_get_segment_index(seg
, recorder
) == 0xFFFF)
555 if (n
>= num_packed_segments
)
558 first
= TA_adjust_point_index(recorder
, first
);
559 last
= TA_adjust_point_index(recorder
, last
);
561 low_nibble
= first
- base
;
562 high_nibble
= last
- first
;
564 *(arg
--) = 16 * high_nibble
+ low_nibble
;
570 for (; seg
< seg_limit
; seg
++)
572 FT_UInt first
= (FT_UInt
)(seg
->first
- points
);
573 FT_UInt last
= (FT_UInt
)(seg
->last
- points
);
576 if (TA_get_segment_index(seg
, recorder
) == 0xFFFF)
579 *(arg
--) = TA_adjust_point_index(recorder
, first
);
580 *(arg
--) = TA_adjust_point_index(recorder
, last
);
582 /* we push the last and first contour point */
583 /* as a third and fourth argument in wrap-around segments */
586 for (n
= 0; n
< outline
.n_contours
; n
++)
588 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
593 *(arg
--) = TA_adjust_point_index(recorder
, end
);
598 *(arg
--) = TA_adjust_point_index(recorder
, 0);
600 *(arg
--) = TA_adjust_point_index(recorder
,
601 (FT_UInt
)outline
.contours
[n
- 1] + 1);
611 /* emit the second part of wrap-around segments as separate segments */
612 /* so that edges can easily link to them */
613 for (seg
= segments
; seg
< seg_limit
; seg
++)
615 FT_UInt first
= (FT_UInt
)(seg
->first
- points
);
616 FT_UInt last
= (FT_UInt
)(seg
->last
- points
);
619 if (TA_get_segment_index(seg
, recorder
) == 0xFFFF)
624 for (n
= 0; n
< outline
.n_contours
; n
++)
626 if (first
<= (FT_UInt
)outline
.contours
[n
])
629 *(arg
--) = TA_adjust_point_index(recorder
, 0);
631 *(arg
--) = TA_adjust_point_index(recorder
,
632 (FT_UInt
)outline
.contours
[n
- 1] + 1);
637 *(arg
--) = TA_adjust_point_index(recorder
, last
);
641 /* with most fonts it is very rare */
642 /* that any of the pushed arguments is larger than 0xFF, */
643 /* thus we refrain from further optimizing this case */
644 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
648 num_storage
= sal_segment_offset
+ num_segments
* 2;
649 if (num_storage
> sfnt
->max_storage
)
650 sfnt
->max_storage
= num_storage
;
652 num_twilight_points
= num_segments
* 2;
653 if (num_twilight_points
> sfnt
->max_twilight_points
)
654 sfnt
->max_twilight_points
= num_twilight_points
;
656 /* both this function and `TA_emit_hints_record' */
657 /* push data onto the stack */
658 num_stack_elements
= (FT_UShort
)(ADDITIONAL_STACK_ELEMENTS
659 + recorder
->num_stack_elements
661 if (num_stack_elements
> sfnt
->max_stack_elements
)
662 sfnt
->max_stack_elements
= num_stack_elements
;
671 build_delta_exception(const Ctrl
* ctrl
,
672 FT_UInt
** delta_args
,
673 unsigned int* num_delta_args
)
681 ppem
= ctrl
->ppem
- CONTROL_DELTA_PPEM_MIN
;
697 * the possible shift values in the instructions are indexed as follows:
708 * (note that there is no index for a zero shift).
711 if (ctrl
->x_shift
< 0)
712 x_shift
= ctrl
->x_shift
+ 8;
714 x_shift
= ctrl
->x_shift
+ 7;
716 if (ctrl
->y_shift
< 0)
717 y_shift
= ctrl
->y_shift
+ 8;
719 y_shift
= ctrl
->y_shift
+ 7;
721 /* add point index and exception specification to appropriate stack */
724 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
725 (FT_UInt
)((ppem
<< 4) + x_shift
);
726 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
727 (FT_UInt
)ctrl
->point_idx
;
733 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
734 (FT_UInt
)((ppem
<< 4) + y_shift
);
735 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
736 (FT_UInt
)ctrl
->point_idx
;
742 TA_sfnt_build_delta_exceptions(SFNT
* sfnt
,
747 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
748 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
749 GLYPH
* glyph
= &data
->glyphs
[idx
];
751 FT_Face face
= font
->loader
->face
;
753 unsigned int num_points
;
756 FT_UShort num_before_IUP_stack_elements
= 0;
757 FT_UShort num_after_IUP_stack_elements
= 0;
759 /* DELTAP[1-3] stacks for both x and y directions */
760 FT_UInt
* delta_before_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
761 FT_UInt
* delta_after_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
762 unsigned int num_delta_before_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
763 unsigned int num_delta_after_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
764 FT_UInt
* args
= NULL
;
766 FT_Bool need_before_IUP_words
= 0;
767 FT_Bool need_after_IUP_words
= 0;
768 FT_Bool need_before_IUP_word_counts
= 0;
769 FT_Bool need_after_IUP_word_counts
= 0;
770 FT_Bool allocated_before_IUP
= 0;
771 FT_Bool allocated_after_IUP
= 0;
774 num_points
= (unsigned int)font
->loader
->gloader
->base
.outline
.n_points
;
776 /* loop over all fitting control instructions */
779 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
786 if (!(ctrl
->type
== Control_Delta_before_IUP
787 || ctrl
->type
== Control_Delta_after_IUP
))
790 /* too large values of font and glyph indices in `ctrl' */
791 /* are handled by later calls of this function */
792 if (face
->face_index
< ctrl
->font_idx
793 || idx
< ctrl
->glyph_idx
)
796 if (ctrl
->type
== Control_Delta_before_IUP
797 && !allocated_before_IUP
)
799 for (i
= 0; i
< 6; i
++)
801 /* see the comment on allocating `ins_buf' in function */
802 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
803 /* we have to increase by 2 to push the number of argument pairs */
804 /* and the function for a LOOPCALL instruction */
805 delta_before_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 2)
807 if (!delta_before_IUP_args
[i
])
814 allocated_before_IUP
= 1;
817 if (ctrl
->type
== Control_Delta_after_IUP
818 && !allocated_after_IUP
)
820 for (i
= 0; i
< 6; i
++)
822 /* we have to increase by 1 for the number of argument pairs */
823 /* as needed by the DELTA instructions */
824 delta_after_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 1)
826 if (!delta_after_IUP_args
[i
])
833 allocated_after_IUP
= 1;
836 /* since we walk sequentially over all glyphs (with points), */
837 /* and the control instruction entries have the same order, */
838 /* we don't need to test for equality of font and glyph indices: */
839 /* at this very point in the code we certainly have a hit */
840 if (ctrl
->type
== Control_Delta_before_IUP
)
842 build_delta_exception(ctrl
,
843 delta_before_IUP_args
,
844 num_delta_before_IUP_args
);
846 if (ctrl
->point_idx
> 255)
847 need_before_IUP_words
= 1;
851 build_delta_exception(ctrl
,
852 delta_after_IUP_args
,
853 num_delta_after_IUP_args
);
855 if (ctrl
->point_idx
> 255)
856 need_after_IUP_words
= 1;
859 TA_control_get_next(font
);
862 /* nothing to do if no control instructions */
863 if (!(allocated_before_IUP
|| allocated_after_IUP
))
866 /* add number of argument pairs and function number to the stacks */
867 for (i
= 0; i
< 6; i
++)
869 if (num_delta_before_IUP_args
[i
])
871 unsigned int n
= num_delta_before_IUP_args
[i
] >> 1;
875 need_before_IUP_word_counts
= 1;
877 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) = n
;
878 num_delta_before_IUP_args
[i
]++;
880 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) =
881 bci_deltap1
+ (i
% 3);
882 num_delta_before_IUP_args
[i
]++;
886 /* add number of argument pairs to the stacks */
887 for (i
= 0; i
< 6; i
++)
889 if (num_delta_after_IUP_args
[i
])
891 unsigned int n
= num_delta_after_IUP_args
[i
] >> 1;
895 need_after_IUP_word_counts
= 1;
897 *(delta_after_IUP_args
[i
] + num_delta_after_IUP_args
[i
]) = n
;
898 num_delta_after_IUP_args
[i
]++;
902 /* merge `before IUP' delta stacks into a single one */
903 if (need_before_IUP_words
904 || (!need_before_IUP_words
&& !need_before_IUP_word_counts
))
906 FT_UInt num_args
= 0;
909 for (i
= 0; i
< 6; i
++)
912 FT_UInt num_args_new
;
915 if (!num_delta_before_IUP_args
[i
])
918 num_args_new
= num_args
+ num_delta_before_IUP_args
[i
];
919 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
926 memcpy(args_new
+ num_args
,
927 delta_before_IUP_args
[i
],
928 num_delta_before_IUP_args
[i
] * sizeof (FT_UInt
));
931 num_args
= num_args_new
;
934 num_before_IUP_stack_elements
= (FT_UShort
)num_args
;
936 bufp
= TA_build_push(bufp
, args
, num_args
, need_before_IUP_words
, 1);
940 num_before_IUP_stack_elements
= 0;
942 /* stack elements are bytes, but counts need words */
943 for (i
= 0; i
< 6; i
++)
945 FT_UInt num_delta_arg
;
948 if (!num_delta_before_IUP_args
[i
])
951 num_delta_arg
= num_delta_before_IUP_args
[i
] - 2;
953 bufp
= TA_build_push(bufp
,
954 delta_before_IUP_args
[i
],
956 need_before_IUP_words
,
959 num_before_IUP_stack_elements
+= num_delta_arg
+ 2;
963 BCI(HIGH(num_delta_arg
));
964 BCI(LOW(num_delta_arg
));
966 /* the function number */
968 BCI(delta_before_IUP_args
[i
][num_delta_before_IUP_args
[i
] - 1]);
972 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
973 if (num_delta_before_IUP_args
[5])
975 if (num_delta_before_IUP_args
[4])
977 if (num_delta_before_IUP_args
[3])
980 if (num_delta_before_IUP_args
[2]
981 || num_delta_before_IUP_args
[1]
982 || num_delta_before_IUP_args
[0])
985 /* emit x DELTA opcodes */
986 if (num_delta_before_IUP_args
[2])
988 if (num_delta_before_IUP_args
[1])
990 if (num_delta_before_IUP_args
[0])
993 if (num_delta_before_IUP_args
[2]
994 || num_delta_before_IUP_args
[1]
995 || num_delta_before_IUP_args
[0])
998 if (num_delta_before_IUP_args
[5]
999 || num_delta_before_IUP_args
[4]
1000 || num_delta_before_IUP_args
[3])
1003 /* merge `after IUP' delta stacks into a single one */
1004 if (need_after_IUP_words
1005 || (!need_after_IUP_words
&& !need_after_IUP_word_counts
))
1007 FT_UInt num_args
= 0;
1010 for (i
= 0; i
< 6; i
++)
1013 FT_UInt num_args_new
;
1016 if (!num_delta_after_IUP_args
[i
])
1019 num_args_new
= num_args
+ num_delta_after_IUP_args
[i
];
1020 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
1027 memcpy(args_new
+ num_args
,
1028 delta_after_IUP_args
[i
],
1029 num_delta_after_IUP_args
[i
] * sizeof (FT_UInt
));
1032 num_args
= num_args_new
;
1035 num_after_IUP_stack_elements
= (FT_UShort
)num_args
;
1037 bufp
= TA_build_push(bufp
, args
, num_args
, need_after_IUP_words
, 1);
1041 num_after_IUP_stack_elements
= 0;
1043 /* stack elements are bytes, but counts need words */
1044 for (i
= 0; i
< 6; i
++)
1046 FT_UInt num_delta_arg
;
1049 if (!num_delta_after_IUP_args
[i
])
1052 num_delta_arg
= num_delta_after_IUP_args
[i
] - 1;
1054 bufp
= TA_build_push(bufp
,
1055 delta_after_IUP_args
[i
],
1057 need_after_IUP_words
,
1060 num_after_IUP_stack_elements
+= num_delta_arg
+ 1;
1062 num_delta_arg
>>= 1;
1064 BCI(HIGH(num_delta_arg
));
1065 BCI(LOW(num_delta_arg
));
1069 /* emit y DELTA opcodes */
1070 if (num_delta_after_IUP_args
[5])
1072 if (num_delta_after_IUP_args
[4])
1074 if (num_delta_after_IUP_args
[3])
1077 if (num_delta_after_IUP_args
[2]
1078 || num_delta_after_IUP_args
[1]
1079 || num_delta_after_IUP_args
[0])
1082 /* emit x DELTA opcodes */
1083 if (num_delta_after_IUP_args
[2])
1085 if (num_delta_after_IUP_args
[1])
1087 if (num_delta_after_IUP_args
[0])
1090 /* we need to insert a few extra bytecode instructions */
1091 /* if we have y delta exceptions before IUP */
1092 if (num_delta_before_IUP_args
[5]
1093 || num_delta_before_IUP_args
[4]
1094 || num_delta_before_IUP_args
[3])
1096 FT_Byte
* ins_extra_buf_new
;
1097 FT_Byte ins_extra_len_new
;
1100 ins_extra_len_new
= glyph
->ins_extra_len
1101 + sizeof (ins_extra_delta_exceptions
);
1102 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
1104 if (!ins_extra_buf_new
)
1110 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1111 /* by activating `ins_extra_delta_exceptions' */
1112 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
1113 ins_extra_delta_exceptions
,
1114 sizeof (ins_extra_delta_exceptions
));
1116 glyph
->ins_extra_buf
= ins_extra_buf_new
;
1117 glyph
->ins_extra_len
= ins_extra_len_new
;
1119 /* reset `cvtl_do_iup_y' for next glyph */
1127 for (i
= 0; i
< 6; i
++)
1129 free(delta_before_IUP_args
[i
]);
1130 free(delta_after_IUP_args
[i
]);
1134 if (num_before_IUP_stack_elements
> sfnt
->max_stack_elements
)
1135 sfnt
->max_stack_elements
= num_before_IUP_stack_elements
;
1136 if (num_after_IUP_stack_elements
> sfnt
->max_stack_elements
)
1137 sfnt
->max_stack_elements
= num_after_IUP_stack_elements
;
1144 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
1148 FONT
* font
= recorder
->font
;
1149 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
1150 FT_Vector
* points
= glyph
->outline
.points
;
1151 FT_UInt num_contours
= (FT_UInt
)glyph
->outline
.n_contours
;
1157 FT_Bool need_words
= 0;
1160 FT_UShort num_storage
;
1161 FT_UShort num_stack_elements
;
1164 num_args
= 2 * num_contours
+ 2;
1166 /* collect all arguments temporarily in an array (in reverse order) */
1167 /* so that we can easily split into chunks of 255 args */
1168 /* as needed by NPUSHB and NPUSHW, respectively */
1169 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1173 arg
= args
+ num_args
- 1;
1175 if (num_args
> 0xFF)
1178 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
1179 *(arg
--) = bci_scale_composite_glyph
;
1181 *(arg
--) = bci_scale_glyph
;
1182 *(arg
--) = num_contours
;
1187 for (p
= 0; p
< num_contours
; p
++)
1189 FT_UInt max
= start
;
1190 FT_UInt min
= start
;
1193 end
= (FT_UInt
)glyph
->outline
.contours
[p
];
1195 for (q
= start
; q
<= end
; q
++)
1197 if (points
[q
].y
< points
[min
].y
)
1199 if (points
[q
].y
> points
[max
].y
)
1205 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1206 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1210 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1211 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1220 /* with most fonts it is very rare */
1221 /* that any of the pushed arguments is larger than 0xFF, */
1222 /* thus we refrain from further optimizing this case */
1223 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
1227 num_storage
= sal_segment_offset
;
1228 if (num_storage
> sfnt
->max_storage
)
1229 sfnt
->max_storage
= num_storage
;
1231 num_stack_elements
= (FT_UShort
)(ADDITIONAL_STACK_ELEMENTS
+ num_args
);
1232 if (num_stack_elements
> sfnt
->max_stack_elements
)
1233 sfnt
->max_stack_elements
= num_stack_elements
;
1242 TA_font_build_subglyph_shifter(FONT
* font
,
1245 FT_Face face
= font
->loader
->face
;
1246 FT_GlyphSlot glyph
= face
->glyph
;
1248 TA_GlyphLoader gloader
= font
->loader
->gloader
;
1250 TA_SubGlyph subglyphs
= gloader
->current
.subglyphs
;
1251 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->current
.num_subglyphs
;
1252 TA_SubGlyph subglyph
;
1254 FT_Int curr_contour
= 0;
1257 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
1261 FT_UShort flags
= subglyph
->flags
;
1262 FT_Pos y_offset
= subglyph
->arg2
;
1264 FT_Int num_contours
;
1267 /* load subglyph to get the number of contours */
1268 error
= FT_Load_Glyph(face
, (FT_UInt
)subglyph
->index
, FT_LOAD_NO_SCALE
);
1271 num_contours
= glyph
->outline
.n_contours
;
1273 /* nothing to do if there is a point-to-point alignment */
1274 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
1277 /* nothing to do if y offset is zero */
1281 /* nothing to do if there are no contours */
1285 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1286 /* ensures that composite subglyphs are represented as simple glyphs */
1288 if (num_contours
> 0xFF
1289 || curr_contour
> 0xFF)
1292 BCI(HIGH(curr_contour
));
1293 BCI(LOW(curr_contour
));
1294 BCI(HIGH(num_contours
));
1295 BCI(LOW(num_contours
));
1304 /* there are high chances that this value needs PUSHW, */
1305 /* thus we handle it separately */
1306 if (y_offset
> 0xFF || y_offset
< 0)
1309 BCI(HIGH(y_offset
));
1319 BCI(bci_shift_subglyph
);
1323 curr_contour
+= num_contours
;
1331 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1332 * data in four arrays (which are simple but waste a lot of memory). The
1333 * function below converts them into bytecode.
1335 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1336 * together with the edge they correspond to.
1338 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1339 * loop over the edge or edge pairs, respectively, and each edge or edge
1340 * pair contains an inner loop to emit the correponding points.
1344 TA_build_point_hints(Recorder
* recorder
,
1345 TA_GlyphHints hints
)
1347 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1348 TA_Edge edges
= axis
->edges
;
1350 FT_Byte
* p
= recorder
->hints_record
.buf
;
1355 FT_UShort prev_edge
;
1356 FT_UShort prev_before_edge
;
1357 FT_UShort prev_after_edge
;
1362 Node3
* between_node
;
1365 /* we store everything as 16bit numbers; */
1366 /* the function numbers (`ta_ip_before', etc.) */
1367 /* reflect the order in the TA_Action enumeration */
1369 /* ip_before_points */
1372 for (before_node
= LLRB_MIN(ip_before_points
,
1373 &recorder
->ip_before_points_head
);
1375 before_node
= LLRB_NEXT(ip_before_points
,
1376 &recorder
->ip_before_points_head
,
1386 FT_UShort edge_first_idx
;
1389 recorder
->hints_record
.num_actions
++;
1392 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1395 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1396 *(p
++) = HIGH(edge_first_idx
);
1397 *(p
++) = LOW(edge_first_idx
);
1401 for (before_node
= LLRB_MIN(ip_before_points
,
1402 &recorder
->ip_before_points_head
);
1404 before_node
= LLRB_NEXT(ip_before_points
,
1405 &recorder
->ip_before_points_head
,
1411 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1412 *(p
++) = HIGH(point
);
1413 *(p
++) = LOW(point
);
1417 /* ip_after_points */
1420 for (after_node
= LLRB_MIN(ip_after_points
,
1421 &recorder
->ip_after_points_head
);
1423 after_node
= LLRB_NEXT(ip_after_points
,
1424 &recorder
->ip_after_points_head
,
1434 FT_UShort edge_first_idx
;
1437 recorder
->hints_record
.num_actions
++;
1439 edge
= edges
+ axis
->num_edges
- 1;
1440 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1443 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1444 *(p
++) = HIGH(edge_first_idx
);
1445 *(p
++) = LOW(edge_first_idx
);
1449 for (after_node
= LLRB_MIN(ip_after_points
,
1450 &recorder
->ip_after_points_head
);
1452 after_node
= LLRB_NEXT(ip_after_points
,
1453 &recorder
->ip_after_points_head
,
1459 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1460 *(p
++) = HIGH(point
);
1461 *(p
++) = LOW(point
);
1465 /* ip_on_point_array */
1469 for (on_node
= LLRB_MIN(ip_on_points
,
1470 &recorder
->ip_on_points_head
);
1472 on_node
= LLRB_NEXT(ip_on_points
,
1473 &recorder
->ip_on_points_head
,
1477 if (on_node
->edge
!= prev_edge
)
1480 prev_edge
= on_node
->edge
;
1486 recorder
->hints_record
.num_actions
++;
1489 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1493 for (on_node
= LLRB_MIN(ip_on_points
,
1494 &recorder
->ip_on_points_head
);
1496 on_node
= LLRB_NEXT(ip_on_points
,
1497 &recorder
->ip_on_points_head
,
1502 FT_UShort edge_first_idx
;
1505 edge
= edges
+ on_node
->edge
;
1506 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1508 *(p
++) = HIGH(edge_first_idx
);
1509 *(p
++) = LOW(edge_first_idx
);
1511 /* save current position */
1512 edge_node
= on_node
;
1516 on_node
= LLRB_NEXT(ip_on_points
,
1517 &recorder
->ip_on_points_head
,
1520 /* count points on current edge */
1521 if (on_node
->edge
!= edge_node
->edge
)
1529 /* restore current position */
1530 on_node
= edge_node
;
1533 on_node
= LLRB_NEXT(ip_on_points
,
1534 &recorder
->ip_on_points_head
,
1540 if (on_node
->edge
!= edge_node
->edge
)
1543 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1544 *(p
++) = HIGH(point
);
1545 *(p
++) = LOW(point
);
1547 /* keep track of previous node */
1548 edge_node
= on_node
;
1551 /* reset loop iterator by one element, then continue */
1552 on_node
= edge_node
;
1556 /* ip_between_point_array */
1558 prev_before_edge
= 0xFFFF;
1559 prev_after_edge
= 0xFFFF;
1561 for (between_node
= LLRB_MIN(ip_between_points
,
1562 &recorder
->ip_between_points_head
);
1564 between_node
= LLRB_NEXT(ip_between_points
,
1565 &recorder
->ip_between_points_head
,
1568 /* count `(before,after)' edge pairs */
1569 if (between_node
->before_edge
!= prev_before_edge
1570 || between_node
->after_edge
!= prev_after_edge
)
1573 prev_before_edge
= between_node
->before_edge
;
1574 prev_after_edge
= between_node
->after_edge
;
1580 recorder
->hints_record
.num_actions
++;
1583 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1587 for (between_node
= LLRB_MIN(ip_between_points
,
1588 &recorder
->ip_between_points_head
);
1590 between_node
= LLRB_NEXT(ip_between_points
,
1591 &recorder
->ip_between_points_head
,
1594 Node3
* edge_pair_node
;
1597 FT_UShort before_first_idx
;
1598 FT_UShort after_first_idx
;
1601 before
= edges
+ between_node
->before_edge
;
1602 after
= edges
+ between_node
->after_edge
;
1603 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
1604 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
1606 *(p
++) = HIGH(after_first_idx
);
1607 *(p
++) = LOW(after_first_idx
);
1608 *(p
++) = HIGH(before_first_idx
);
1609 *(p
++) = LOW(before_first_idx
);
1611 /* save current position */
1612 edge_pair_node
= between_node
;
1616 between_node
= LLRB_NEXT(ip_between_points
,
1617 &recorder
->ip_between_points_head
,
1620 /* count points associated with current edge pair */
1621 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1622 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1630 /* restore current position */
1631 between_node
= edge_pair_node
;
1634 between_node
= LLRB_NEXT(ip_between_points
,
1635 &recorder
->ip_between_points_head
,
1641 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1642 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1645 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1646 *(p
++) = HIGH(point
);
1647 *(p
++) = LOW(point
);
1649 /* keep track of previous node */
1650 edge_pair_node
= between_node
;
1653 /* reset loop iterator by one element, then continue */
1654 between_node
= edge_pair_node
;
1658 recorder
->hints_record
.buf
= p
;
1663 TA_hints_record_is_different(Hints_Record
* hints_records
,
1664 FT_UInt num_hints_records
,
1668 Hints_Record last_hints_record
;
1674 /* we only need to compare with the last hints record */
1675 last_hints_record
= hints_records
[num_hints_records
- 1];
1677 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1680 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1688 TA_add_hints_record(Hints_Record
** hints_records
,
1689 FT_UInt
* num_hints_records
,
1691 Hints_Record hints_record
)
1693 Hints_Record
* hints_records_new
;
1695 /* at this point, `hints_record.buf' still points into `ins_buf' */
1696 FT_Byte
* end
= hints_record
.buf
;
1699 buf_len
= (FT_UInt
)(end
- start
);
1701 /* now fill the structure completely */
1702 hints_record
.buf_len
= buf_len
;
1703 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1704 if (!hints_record
.buf
)
1705 return FT_Err_Out_Of_Memory
;
1707 memcpy(hints_record
.buf
, start
, buf_len
);
1709 (*num_hints_records
)++;
1711 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1712 * sizeof (Hints_Record
));
1713 if (!hints_records_new
)
1715 free(hints_record
.buf
);
1716 (*num_hints_records
)--;
1717 return FT_Err_Out_Of_Memory
;
1720 *hints_records
= hints_records_new
;
1722 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1729 TA_emit_hints_record(Recorder
* recorder
,
1730 Hints_Record
* hints_record
,
1736 FT_Bool need_words
= 0;
1739 FT_UInt num_arguments
;
1743 /* check whether any argument is larger than 0xFF */
1744 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1745 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1752 /* with most fonts it is very rare */
1753 /* that any of the pushed arguments is larger than 0xFF, */
1754 /* thus we refrain from further optimizing this case */
1756 num_arguments
= hints_record
->buf_len
/ 2;
1761 for (i
= 0; i
< num_arguments
; i
+= 255)
1763 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1765 if (optimize
&& num_args
<= 8)
1766 BCI(PUSHW_1
- 1 + num_args
);
1772 for (j
= 0; j
< num_args
; j
++)
1782 /* we only need the lower bytes */
1785 for (i
= 0; i
< num_arguments
; i
+= 255)
1787 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1789 if (optimize
&& num_args
<= 8)
1790 BCI(PUSHB_1
- 1 + num_args
);
1796 for (j
= 0; j
< num_args
; j
++)
1804 /* collect stack depth data */
1805 if (num_arguments
> recorder
->num_stack_elements
)
1806 recorder
->num_stack_elements
= (FT_UShort
)num_arguments
;
1813 TA_emit_hints_records(Recorder
* recorder
,
1814 Hints_Record
* hints_records
,
1815 FT_UInt num_hints_records
,
1820 Hints_Record
* hints_record
;
1823 hints_record
= hints_records
;
1825 /* emit hints records in `if' clauses, */
1826 /* with the ppem size as the condition */
1827 for (i
= 0; i
< num_hints_records
- 1; i
++)
1830 if (hints_record
->size
> 0xFF)
1833 BCI(HIGH((hints_record
+ 1)->size
));
1834 BCI(LOW((hints_record
+ 1)->size
));
1839 BCI((hints_record
+ 1)->size
);
1843 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1849 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1851 for (i
= 0; i
< num_hints_records
- 1; i
++)
1859 TA_free_hints_records(Hints_Record
* hints_records
,
1860 FT_UInt num_hints_records
)
1865 for (i
= 0; i
< num_hints_records
; i
++)
1866 free(hints_records
[i
].buf
);
1868 free(hints_records
);
1873 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1880 FT_UShort num_segs
= 0;
1882 FT_UShort num_segments
;
1885 seg_idx
= TA_get_segment_index(edge
->first
, recorder
);
1886 num_segments
= TA_get_segment_index(NULL
, recorder
);
1888 /* we store everything as 16bit numbers */
1889 *(bufp
++) = HIGH(seg_idx
);
1890 *(bufp
++) = LOW(seg_idx
);
1892 /* wrap-around segments are stored as two segments */
1893 if (edge
->first
->first
> edge
->first
->last
)
1896 seg
= edge
->first
->edge_next
;
1897 while (seg
!= edge
->first
)
1901 if (seg
->first
> seg
->last
)
1904 seg
= seg
->edge_next
;
1907 *(bufp
++) = HIGH(num_segs
);
1908 *(bufp
++) = LOW(num_segs
);
1910 if (edge
->first
->first
> edge
->first
->last
)
1912 /* emit second part of wrap-around segment; */
1913 /* the bytecode positions such segments after `normal' ones */
1917 if (seg_idx
== *wrap
)
1922 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1923 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1926 seg
= edge
->first
->edge_next
;
1927 while (seg
!= edge
->first
)
1929 seg_idx
= TA_get_segment_index(seg
, recorder
);
1931 *(bufp
++) = HIGH(seg_idx
);
1932 *(bufp
++) = LOW(seg_idx
);
1934 if (seg
->first
> seg
->last
)
1939 if (seg_idx
== *wrap
)
1944 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1945 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1948 seg
= seg
->edge_next
;
1956 TA_hints_recorder(TA_Action action
,
1957 TA_GlyphHints hints
,
1962 TA_Edge lower_bound
,
1963 TA_Edge upper_bound
)
1965 TA_AxisHints axis
= &hints
->axis
[dim
];
1966 TA_Edge edges
= axis
->edges
;
1967 TA_Point points
= hints
->points
;
1969 TA_Segment segments
= axis
->segments
;
1970 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1973 Recorder
* recorder
= (Recorder
*)hints
->user
;
1974 SFNT
* sfnt
= recorder
->sfnt
;
1975 FONT
* font
= recorder
->font
;
1976 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1977 FT_Byte
* p
= recorder
->hints_record
.buf
;
1979 TA_StyleClass style_class
= font
->loader
->metrics
->style_class
;
1980 TA_ScriptClass script_class
= ta_script_classes
[style_class
->script
];
1982 FT_UInt style
= style_class
->style
;
1983 FT_Bool top_to_bottom_hinting
= script_class
->top_to_bottom_hinting
;
1986 if (dim
== TA_DIMENSION_HORZ
)
1989 if (!recorder
->segment_map_initialized
)
1991 FT_UShort
* segment_map
= recorder
->segment_map
;
1996 for (seg
= segments
; seg
< seg_limit
; seg
++)
1999 *segment_map
= idx
++;
2001 *segment_map
= 0xFFFF;
2007 recorder
->segment_map_initialized
= 1;
2010 if (!recorder
->wrap_around_segments_initialized
)
2012 FT_UShort
* wrap_around_segment
;
2015 wrap_around_segment
= recorder
->wrap_around_segments
;
2016 for (seg
= segments
; seg
< seg_limit
; seg
++)
2017 if (seg
->first
> seg
->last
)
2018 *(wrap_around_segment
++) = TA_get_segment_index(seg
, recorder
);
2020 recorder
->wrap_around_segments_initialized
= 1;
2023 /* we collect point hints for later processing */
2029 TA_Point point
= (TA_Point
)arg1
;
2032 before_node
= (Node1
*)malloc(sizeof (Node1
));
2035 before_node
->point
= (FT_UShort
)(point
- points
);
2037 LLRB_INSERT(ip_before_points
,
2038 &recorder
->ip_before_points_head
,
2046 TA_Point point
= (TA_Point
)arg1
;
2049 after_node
= (Node1
*)malloc(sizeof (Node1
));
2052 after_node
->point
= (FT_UShort
)(point
- points
);
2054 LLRB_INSERT(ip_after_points
,
2055 &recorder
->ip_after_points_head
,
2063 TA_Point point
= (TA_Point
)arg1
;
2064 TA_Edge edge
= arg2
;
2067 on_node
= (Node2
*)malloc(sizeof (Node2
));
2070 on_node
->edge
= (FT_UShort
)(edge
- edges
);
2071 on_node
->point
= (FT_UShort
)(point
- points
);
2073 LLRB_INSERT(ip_on_points
,
2074 &recorder
->ip_on_points_head
,
2081 Node3
* between_node
;
2082 TA_Point point
= (TA_Point
)arg1
;
2083 TA_Edge before
= arg2
;
2084 TA_Edge after
= arg3
;
2087 between_node
= (Node3
*)malloc(sizeof (Node3
));
2090 between_node
->before_edge
= (FT_UShort
)(before
- edges
);
2091 between_node
->after_edge
= (FT_UShort
)(after
- edges
);
2092 between_node
->point
= (FT_UShort
)(point
- points
);
2094 LLRB_INSERT(ip_between_points
,
2095 &recorder
->ip_between_points_head
,
2101 /* we ignore the BOUND action since we signal this information */
2102 /* with the proper function number */
2109 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2110 /* if the value is n, the function numbers are n, ..., n+11, */
2111 /* to be differentiated with flags */
2117 TA_Edge base_edge
= (TA_Edge
)arg1
;
2118 TA_Edge stem_edge
= arg2
;
2119 FT_UShort base_first_idx
;
2120 FT_UShort stem_first_idx
;
2123 base_first_idx
= TA_get_segment_index(base_edge
->first
, recorder
);
2124 stem_first_idx
= TA_get_segment_index(stem_edge
->first
, recorder
);
2127 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2128 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
2129 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
2131 *(p
++) = HIGH(base_first_idx
);
2132 *(p
++) = LOW(base_first_idx
);
2133 *(p
++) = HIGH(stem_first_idx
);
2134 *(p
++) = LOW(stem_first_idx
);
2136 p
= TA_hints_recorder_handle_segments(p
, recorder
, stem_edge
, wraps
);
2142 TA_Edge edge
= (TA_Edge
)arg1
;
2143 TA_Edge edge2
= arg2
;
2144 FT_UShort edge_first_idx
;
2145 FT_UShort edge2_first_idx
;
2148 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2149 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2152 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2153 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2154 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
2156 *(p
++) = HIGH(edge_first_idx
);
2157 *(p
++) = LOW(edge_first_idx
);
2158 *(p
++) = HIGH(edge2_first_idx
);
2159 *(p
++) = LOW(edge2_first_idx
);
2161 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2167 TA_Edge edge
= (TA_Edge
)arg1
;
2168 TA_Edge edge2
= arg2
;
2169 TA_Edge edge_minus_one
= lower_bound
;
2170 FT_UShort edge_first_idx
;
2171 FT_UShort edge2_first_idx
;
2174 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2175 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2178 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2179 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2180 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2181 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2182 + 4 * (edge_minus_one
!= NULL
2183 && top_to_bottom_hinting
); /* `down' */
2185 *(p
++) = HIGH(edge_first_idx
);
2186 *(p
++) = LOW(edge_first_idx
);
2187 *(p
++) = HIGH(edge2_first_idx
);
2188 *(p
++) = LOW(edge2_first_idx
);
2192 FT_UShort edge_minus_one_first_idx
;
2195 edge_minus_one_first_idx
= TA_get_segment_index(
2196 edge_minus_one
->first
, recorder
);
2198 *(p
++) = HIGH(edge_minus_one_first_idx
);
2199 *(p
++) = LOW(edge_minus_one_first_idx
);
2202 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2206 case ta_blue_anchor
:
2208 TA_Edge edge
= (TA_Edge
)arg1
;
2209 TA_Edge blue
= arg2
;
2210 FT_UShort blue_first_idx
;
2211 FT_UShort edge_first_idx
;
2214 blue_first_idx
= TA_get_segment_index(blue
->first
, recorder
);
2215 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2218 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2220 *(p
++) = HIGH(blue_first_idx
);
2221 *(p
++) = LOW(blue_first_idx
);
2223 if (edge
->best_blue_is_shoot
)
2225 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2226 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2230 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2231 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2234 *(p
++) = HIGH(edge_first_idx
);
2235 *(p
++) = LOW(edge_first_idx
);
2237 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2243 TA_Edge edge
= (TA_Edge
)arg1
;
2244 TA_Edge edge2
= arg2
;
2245 TA_Edge edge_minus_one
= lower_bound
;
2246 FT_UShort edge_first_idx
;
2247 FT_UShort edge2_first_idx
;
2250 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2251 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2254 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2255 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2256 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2257 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2258 + 4 * (edge_minus_one
!= NULL
2259 && top_to_bottom_hinting
); /* `down' */
2261 *(p
++) = HIGH(edge_first_idx
);
2262 *(p
++) = LOW(edge_first_idx
);
2263 *(p
++) = HIGH(edge2_first_idx
);
2264 *(p
++) = LOW(edge2_first_idx
);
2268 FT_UShort edge_minus_one_first_idx
;
2271 edge_minus_one_first_idx
= TA_get_segment_index(
2272 edge_minus_one
->first
, recorder
);
2274 *(p
++) = HIGH(edge_minus_one_first_idx
);
2275 *(p
++) = LOW(edge_minus_one_first_idx
);
2278 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2279 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge2
, wraps
);
2285 TA_Edge edge
= (TA_Edge
)arg1
;
2286 FT_UShort edge_first_idx
;
2289 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2292 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2294 if (edge
->best_blue_is_shoot
)
2296 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2297 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2301 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2302 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2305 *(p
++) = HIGH(edge_first_idx
);
2306 *(p
++) = LOW(edge_first_idx
);
2308 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2314 TA_Edge serif
= (TA_Edge
)arg1
;
2315 TA_Edge base
= serif
->serif
;
2316 FT_UShort serif_first_idx
;
2317 FT_UShort base_first_idx
;
2320 serif_first_idx
= TA_get_segment_index(serif
->first
, recorder
);
2321 base_first_idx
= TA_get_segment_index(base
->first
, recorder
);
2324 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2325 + (lower_bound
!= NULL
)
2326 + 2 * (upper_bound
!= NULL
)
2327 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2328 && top_to_bottom_hinting
); /* `down' */
2330 *(p
++) = HIGH(serif_first_idx
);
2331 *(p
++) = LOW(serif_first_idx
);
2332 *(p
++) = HIGH(base_first_idx
);
2333 *(p
++) = LOW(base_first_idx
);
2337 FT_UShort lower_bound_first_idx
;
2340 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2343 *(p
++) = HIGH(lower_bound_first_idx
);
2344 *(p
++) = LOW(lower_bound_first_idx
);
2348 FT_UShort upper_bound_first_idx
;
2351 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2354 *(p
++) = HIGH(upper_bound_first_idx
);
2355 *(p
++) = LOW(upper_bound_first_idx
);
2358 p
= TA_hints_recorder_handle_segments(p
, recorder
, serif
, wraps
);
2362 case ta_serif_anchor
:
2363 case ta_serif_link2
:
2365 TA_Edge edge
= (TA_Edge
)arg1
;
2366 FT_UShort edge_first_idx
;
2369 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2372 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2373 + (lower_bound
!= NULL
)
2374 + 2 * (upper_bound
!= NULL
)
2375 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2376 && top_to_bottom_hinting
); /* `down' */
2378 *(p
++) = HIGH(edge_first_idx
);
2379 *(p
++) = LOW(edge_first_idx
);
2383 FT_UShort lower_bound_first_idx
;
2386 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2389 *(p
++) = HIGH(lower_bound_first_idx
);
2390 *(p
++) = LOW(lower_bound_first_idx
);
2394 FT_UShort upper_bound_first_idx
;
2397 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2400 *(p
++) = HIGH(upper_bound_first_idx
);
2401 *(p
++) = LOW(upper_bound_first_idx
);
2404 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2408 case ta_serif_link1
:
2410 TA_Edge edge
= (TA_Edge
)arg1
;
2411 TA_Edge before
= arg2
;
2412 TA_Edge after
= arg3
;
2413 FT_UShort before_first_idx
;
2414 FT_UShort edge_first_idx
;
2415 FT_UShort after_first_idx
;
2418 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
2419 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2420 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
2423 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2424 + (lower_bound
!= NULL
)
2425 + 2 * (upper_bound
!= NULL
)
2426 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2427 && top_to_bottom_hinting
); /* `down' */
2429 *(p
++) = HIGH(before_first_idx
);
2430 *(p
++) = LOW(before_first_idx
);
2431 *(p
++) = HIGH(edge_first_idx
);
2432 *(p
++) = LOW(edge_first_idx
);
2433 *(p
++) = HIGH(after_first_idx
);
2434 *(p
++) = LOW(after_first_idx
);
2438 FT_UShort lower_bound_first_idx
;
2441 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2444 *(p
++) = HIGH(lower_bound_first_idx
);
2445 *(p
++) = LOW(lower_bound_first_idx
);
2449 FT_UShort upper_bound_first_idx
;
2452 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2455 *(p
++) = HIGH(upper_bound_first_idx
);
2456 *(p
++) = LOW(upper_bound_first_idx
);
2459 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2464 /* there are more cases in the enumeration */
2465 /* which are handled with flags */
2469 recorder
->hints_record
.num_actions
++;
2470 recorder
->hints_record
.buf
= p
;
2475 TA_init_recorder(Recorder
* recorder
,
2479 TA_GlyphHints hints
)
2481 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2483 TA_Segment segments
= axis
->segments
;
2484 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2488 recorder
->sfnt
= sfnt
;
2489 recorder
->font
= font
;
2490 recorder
->glyph
= glyph
;
2492 LLRB_INIT(&recorder
->ip_before_points_head
);
2493 LLRB_INIT(&recorder
->ip_after_points_head
);
2494 LLRB_INIT(&recorder
->ip_on_points_head
);
2495 LLRB_INIT(&recorder
->ip_between_points_head
);
2497 recorder
->num_stack_elements
= 0;
2499 /* no need to clean up allocated arrays in case of error; */
2500 /* this is handled later by `TA_free_recorder' */
2502 /* we use segment_map[axis->num_segments] */
2503 /* as the total number of mapped segments, so allocate one more element */
2504 recorder
->segment_map
=
2505 (FT_UShort
*)malloc((size_t)(axis
->num_segments
+ 1) * sizeof (FT_UShort
));
2506 if (!recorder
->segment_map
)
2507 return FT_Err_Out_Of_Memory
;
2509 /* `segment_map' gets initialized later on, */
2510 /* after the first call of `ta_loader_load_glyph' */
2511 recorder
->segment_map_initialized
= 0;
2513 recorder
->num_wrap_around_segments
= 0;
2514 for (seg
= segments
; seg
< seg_limit
; seg
++)
2515 if (seg
->first
> seg
->last
)
2516 recorder
->num_wrap_around_segments
++;
2518 recorder
->wrap_around_segments
=
2519 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2520 * sizeof (FT_UShort
));
2521 if (!recorder
->wrap_around_segments
)
2522 return FT_Err_Out_Of_Memory
;
2524 /* `wrap_around_segments' gets initialized later on; */
2525 /* it needs function `TA_get_segment_index' which uses data */
2526 /* that hasn't been initialized yet either */
2527 recorder
->wrap_around_segments_initialized
= 0;
2534 TA_reset_recorder(Recorder
* recorder
,
2537 recorder
->hints_record
.buf
= bufp
;
2538 recorder
->hints_record
.num_actions
= 0;
2543 TA_rewind_recorder(Recorder
* recorder
,
2550 Node3
* between_node
;
2552 Node1
* next_before_node
;
2553 Node1
* next_after_node
;
2554 Node2
* next_on_node
;
2555 Node3
* next_between_node
;
2558 TA_reset_recorder(recorder
, bufp
);
2560 recorder
->hints_record
.size
= size
;
2562 /* deallocate our red-black trees */
2564 for (before_node
= LLRB_MIN(ip_before_points
,
2565 &recorder
->ip_before_points_head
);
2567 before_node
= next_before_node
)
2569 next_before_node
= LLRB_NEXT(ip_before_points
,
2570 &recorder
->ip_before_points_head
,
2572 LLRB_REMOVE(ip_before_points
,
2573 &recorder
->ip_before_points_head
,
2578 for (after_node
= LLRB_MIN(ip_after_points
,
2579 &recorder
->ip_after_points_head
);
2581 after_node
= next_after_node
)
2583 next_after_node
= LLRB_NEXT(ip_after_points
,
2584 &recorder
->ip_after_points_head
,
2586 LLRB_REMOVE(ip_after_points
,
2587 &recorder
->ip_after_points_head
,
2592 for (on_node
= LLRB_MIN(ip_on_points
,
2593 &recorder
->ip_on_points_head
);
2595 on_node
= next_on_node
)
2597 next_on_node
= LLRB_NEXT(ip_on_points
,
2598 &recorder
->ip_on_points_head
,
2600 LLRB_REMOVE(ip_on_points
,
2601 &recorder
->ip_on_points_head
,
2606 for (between_node
= LLRB_MIN(ip_between_points
,
2607 &recorder
->ip_between_points_head
);
2609 between_node
= next_between_node
)
2611 next_between_node
= LLRB_NEXT(ip_between_points
,
2612 &recorder
->ip_between_points_head
,
2614 LLRB_REMOVE(ip_between_points
,
2615 &recorder
->ip_between_points_head
,
2623 TA_free_recorder(Recorder
* recorder
)
2625 free(recorder
->segment_map
);
2626 free(recorder
->wrap_around_segments
);
2628 TA_rewind_recorder(recorder
, NULL
, 0);
2633 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2637 FT_Face face
= sfnt
->face
;
2645 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2646 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2647 /* `idx' is never negative */
2648 GLYPH
* glyph
= &data
->glyphs
[idx
];
2650 TA_FaceGlobals globals
= (TA_FaceGlobals
)sfnt
->face
->autohint
.data
;
2651 FT_UShort
* gstyles
= globals
->glyph_styles
;
2652 FT_Bool use_gstyle_data
= 1;
2654 TA_GlyphHints hints
;
2656 FT_UInt num_action_hints_records
= 0;
2657 FT_UInt num_point_hints_records
= 0;
2658 Hints_Record
* action_hints_records
= NULL
;
2659 Hints_Record
* point_hints_records
= NULL
;
2662 FT_UShort num_stack_elements
;
2663 FT_Bool optimize
= 0;
2665 FT_Int32 load_flags
;
2668 /* we store only three positions, but it simplifies the algorithm in */
2669 /* `TA_optimize_push' if we have one additional element */
2677 /* XXX: right now, we abuse this flag to control */
2678 /* the global behaviour of the auto-hinter */
2679 load_flags
= 1 << 29; /* vertical hinting only */
2680 if (!font
->adjust_subglyphs
)
2682 if (font
->hint_composites
)
2683 load_flags
|= FT_LOAD_NO_SCALE
;
2685 load_flags
|= FT_LOAD_NO_RECURSE
;
2688 /* computing the segments is resolution independent, */
2689 /* thus the pixel size in this call is arbitrary -- */
2690 /* however, we avoid unnecessary debugging output */
2691 /* if we use the lowest value of the hinting range */
2692 error
= FT_Set_Pixel_Sizes(face
,
2693 font
->hinting_range_min
,
2694 font
->hinting_range_min
);
2698 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2699 /* to modify `out' directions of points at the user's request */
2700 /* (which will eventually become single-point segments) */
2701 error
= TA_control_segment_dir_collect(font
, face
->face_index
, idx
);
2706 /* temporarily disable some debugging output */
2707 /* to avoid getting the information twice */
2708 _ta_debug_save
= _ta_debug
;
2712 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2713 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2716 _ta_debug
= _ta_debug_save
;
2722 /* do nothing if we have an empty glyph */
2723 if (!(font
->loader
->gloader
->current
.num_subglyphs
2724 || face
->glyph
->outline
.n_contours
))
2727 hints
= &font
->loader
->hints
;
2730 * We allocate a buffer which is certainly large enough
2731 * to hold all of the created bytecode instructions;
2732 * later on it gets reallocated to its real size.
2734 * The value `1000' is a very rough guess, not tested well.
2736 * For delta exceptions, we have three DELTA commands,
2737 * covering 3*16 ppem values.
2738 * Since a point index can be larger than 255,
2739 * we assume two bytes everywhere for the necessary PUSH calls.
2740 * This value must be doubled for the other arguments of DELTA.
2741 * Additionally, we have both x and y deltas,
2742 * which need to be handled separately in the bytecode.
2743 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2744 * adding some bytes for the necessary overhead.
2746 ins_len
= (FT_UInt
)(hints
->num_points
2748 + ((font
->control_data_head
!= NULL
) ? 400 : 0)));
2749 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2751 return FT_Err_Out_Of_Memory
;
2753 /* handle composite glyph */
2754 if (font
->loader
->gloader
->current
.num_subglyphs
)
2756 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2759 error
= FT_Err_Out_Of_Memory
;
2763 use_gstyle_data
= 0;
2769 if (font
->fallback_scaling
)
2771 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
2773 /* the scaling value of `none_dflt' */
2774 /* (this is, hinting without script-specific blue zones) */
2775 /* is always 1, which corresponds to a no-op */
2780 /* since `TA_init_recorder' hasn't been called yet, */
2781 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2782 recorder
.sfnt
= sfnt
;
2783 recorder
.font
= font
;
2784 recorder
.glyph
= glyph
;
2786 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2789 error
= FT_Err_Out_Of_Memory
;
2794 use_gstyle_data
= 0;
2799 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2803 /* loop over a large range of pixel sizes */
2804 /* to find hints records which get pushed onto the bytecode stack */
2813 (void)FT_Get_Glyph_Name(face
, (FT_UInt
)idx
, buf
, 256);
2815 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2817 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2818 fprintf(stderr
, "\n");
2819 for (i
= 0; i
< num_chars
; i
++)
2821 fprintf(stderr
, "\n\n");
2826 /* we temporarily use `ins_buf' to record the current glyph hints */
2827 ta_loader_register_hints_recorder(font
->loader
,
2832 * It is important that we start the loop with the smallest PPEM value
2833 * used for hinting, since the number of segments that form an edge can
2834 * become smaller for larger PPEM values. For efficiency, we skip
2835 * non-edge one-point segments, and `TA_get_segment_index' would return
2836 * wrong indices otherwise.
2838 for (size
= font
->hinting_range_min
;
2839 size
<= font
->hinting_range_max
;
2847 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2849 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2859 num_chars
= fprintf(stderr
, "size %d\n", size
);
2860 for (i
= 0; i
< num_chars
- 1; i
++)
2862 fprintf(stderr
, "\n\n");
2866 /* calling `ta_loader_load_glyph' uses the */
2867 /* `TA_hints_recorder' function as a callback, */
2868 /* modifying `hints_record' */
2869 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2873 if (TA_hints_record_is_different(action_hints_records
,
2874 num_action_hints_records
,
2875 ins_buf
, recorder
.hints_record
.buf
))
2882 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2883 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2884 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2886 fprintf(stderr
, "action hints record:\n");
2887 if (ins_buf
== recorder
.hints_record
.buf
)
2888 fprintf(stderr
, " (none)");
2891 fprintf(stderr
, " ");
2892 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2893 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2895 fprintf(stderr
, "\n");
2899 error
= TA_add_hints_record(&action_hints_records
,
2900 &num_action_hints_records
,
2901 ins_buf
, recorder
.hints_record
);
2906 /* now handle point records */
2908 TA_reset_recorder(&recorder
, ins_buf
);
2910 /* use the point hints data collected in `TA_hints_recorder' */
2911 TA_build_point_hints(&recorder
, hints
);
2913 if (TA_hints_record_is_different(point_hints_records
,
2914 num_point_hints_records
,
2915 ins_buf
, recorder
.hints_record
.buf
))
2925 num_chars
= fprintf(stderr
, "size %d\n", size
);
2926 for (i
= 0; i
< num_chars
- 1; i
++)
2928 fprintf(stderr
, "\n\n");
2930 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2931 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2932 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2935 fprintf(stderr
, "point hints record:\n");
2936 if (ins_buf
== recorder
.hints_record
.buf
)
2937 fprintf(stderr
, " (none)");
2940 fprintf(stderr
, " ");
2941 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2942 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2944 fprintf(stderr
, "\n\n");
2948 error
= TA_add_hints_record(&point_hints_records
,
2949 &num_point_hints_records
,
2950 ins_buf
, recorder
.hints_record
);
2956 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2958 /* since we only have a single empty record we just scale the glyph */
2959 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2962 error
= FT_Err_Out_Of_Memory
;
2966 use_gstyle_data
= 0;
2971 /* if there is only a single record, */
2972 /* we do a global optimization later on */
2973 if (num_action_hints_records
> 1)
2976 /* store the hints records and handle stack depth */
2978 bufp
= TA_emit_hints_records(&recorder
,
2979 point_hints_records
,
2980 num_point_hints_records
,
2984 num_stack_elements
= recorder
.num_stack_elements
;
2985 recorder
.num_stack_elements
= 0;
2988 bufp
= TA_emit_hints_records(&recorder
,
2989 action_hints_records
,
2990 num_action_hints_records
,
2994 recorder
.num_stack_elements
+= num_stack_elements
;
2997 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
3000 error
= FT_Err_Out_Of_Memory
;
3004 if (num_action_hints_records
== 1)
3005 bufp
= TA_optimize_push(ins_buf
, pos
);
3008 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3009 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3010 TA_free_recorder(&recorder
);
3013 /* handle delta exceptions */
3014 if (font
->control_data_head
)
3016 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
3019 error
= FT_Err_Out_Of_Memory
;
3024 /* we need to insert a few extra bytecode instructions */
3025 /* for non-base glyphs */
3026 if (use_gstyle_data
&& (gstyles
[idx
] & TA_NONBASE
))
3028 FT_Byte
* ins_extra_buf_new
;
3029 FT_Byte ins_extra_len_new
;
3032 ins_extra_len_new
= glyph
->ins_extra_len
3033 + sizeof (ins_extra_ignore_std_width
);
3034 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
3036 if (!ins_extra_buf_new
)
3042 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3043 /* by activating `ins_extra_ignore_std_width' */
3044 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
3045 ins_extra_ignore_std_width
,
3046 sizeof (ins_extra_ignore_std_width
));
3048 glyph
->ins_extra_buf
= ins_extra_buf_new
;
3049 glyph
->ins_extra_len
= ins_extra_len_new
;
3051 /* reset `cvtl_ignore_std_width' for next glyph */
3053 BCI(cvtl_ignore_std_width
);
3058 ins_len
= (FT_UInt
)(bufp
- ins_buf
);
3060 if (ins_len
> sfnt
->max_instructions
)
3061 sfnt
->max_instructions
= (FT_UShort
)ins_len
;
3063 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
3064 glyph
->ins_len
= ins_len
;
3069 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3070 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3071 TA_free_recorder(&recorder
);
3078 /* end of tabytecode.c */