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 /* see storage area layout description in `tabytecode.h' */
649 num_storage
= sal_segment_offset
+ num_segments
* 3;
650 if (num_storage
> sfnt
->max_storage
)
651 sfnt
->max_storage
= num_storage
;
653 num_twilight_points
= num_segments
* 2;
654 if (num_twilight_points
> sfnt
->max_twilight_points
)
655 sfnt
->max_twilight_points
= num_twilight_points
;
657 /* both this function and `TA_emit_hints_record' */
658 /* push data onto the stack */
659 num_stack_elements
= (FT_UShort
)(ADDITIONAL_STACK_ELEMENTS
660 + recorder
->num_stack_elements
662 if (num_stack_elements
> sfnt
->max_stack_elements
)
663 sfnt
->max_stack_elements
= num_stack_elements
;
672 build_delta_exception(const Ctrl
* ctrl
,
673 FT_UInt
** delta_args
,
674 unsigned int* num_delta_args
)
682 ppem
= ctrl
->ppem
- CONTROL_DELTA_PPEM_MIN
;
698 * the possible shift values in the instructions are indexed as follows:
709 * (note that there is no index for a zero shift).
712 if (ctrl
->x_shift
< 0)
713 x_shift
= ctrl
->x_shift
+ 8;
715 x_shift
= ctrl
->x_shift
+ 7;
717 if (ctrl
->y_shift
< 0)
718 y_shift
= ctrl
->y_shift
+ 8;
720 y_shift
= ctrl
->y_shift
+ 7;
722 /* add point index and exception specification to appropriate stack */
725 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
726 (FT_UInt
)((ppem
<< 4) + x_shift
);
727 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
728 (FT_UInt
)ctrl
->point_idx
;
734 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
735 (FT_UInt
)((ppem
<< 4) + y_shift
);
736 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
737 (FT_UInt
)ctrl
->point_idx
;
743 TA_sfnt_build_delta_exceptions(SFNT
* sfnt
,
748 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
749 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
750 GLYPH
* glyph
= &data
->glyphs
[idx
];
752 FT_Face face
= font
->loader
->face
;
754 unsigned int num_points
;
757 FT_UShort num_before_IUP_stack_elements
= 0;
758 FT_UShort num_after_IUP_stack_elements
= 0;
760 /* DELTAP[1-3] stacks for both x and y directions */
761 FT_UInt
* delta_before_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
762 FT_UInt
* delta_after_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
763 unsigned int num_delta_before_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
764 unsigned int num_delta_after_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
765 FT_UInt
* args
= NULL
;
767 FT_Bool need_before_IUP_words
= 0;
768 FT_Bool need_after_IUP_words
= 0;
769 FT_Bool need_before_IUP_word_counts
= 0;
770 FT_Bool need_after_IUP_word_counts
= 0;
771 FT_Bool allocated_before_IUP
= 0;
772 FT_Bool allocated_after_IUP
= 0;
775 num_points
= (unsigned int)font
->loader
->gloader
->base
.outline
.n_points
;
777 /* loop over all fitting control instructions */
780 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
787 if (!(ctrl
->type
== Control_Delta_before_IUP
788 || ctrl
->type
== Control_Delta_after_IUP
))
791 /* too large values of font and glyph indices in `ctrl' */
792 /* are handled by later calls of this function */
793 if (face
->face_index
< ctrl
->font_idx
794 || idx
< ctrl
->glyph_idx
)
797 if (ctrl
->type
== Control_Delta_before_IUP
798 && !allocated_before_IUP
)
800 for (i
= 0; i
< 6; i
++)
802 /* see the comment on allocating `ins_buf' in function */
803 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
804 /* we have to increase by 2 to push the number of argument pairs */
805 /* and the function for a LOOPCALL instruction */
806 delta_before_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 2)
808 if (!delta_before_IUP_args
[i
])
815 allocated_before_IUP
= 1;
818 if (ctrl
->type
== Control_Delta_after_IUP
819 && !allocated_after_IUP
)
821 for (i
= 0; i
< 6; i
++)
823 /* we have to increase by 1 for the number of argument pairs */
824 /* as needed by the DELTA instructions */
825 delta_after_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 1)
827 if (!delta_after_IUP_args
[i
])
834 allocated_after_IUP
= 1;
837 /* since we walk sequentially over all glyphs (with points), */
838 /* and the control instruction entries have the same order, */
839 /* we don't need to test for equality of font and glyph indices: */
840 /* at this very point in the code we certainly have a hit */
841 if (ctrl
->type
== Control_Delta_before_IUP
)
843 build_delta_exception(ctrl
,
844 delta_before_IUP_args
,
845 num_delta_before_IUP_args
);
847 if (ctrl
->point_idx
> 255)
848 need_before_IUP_words
= 1;
852 build_delta_exception(ctrl
,
853 delta_after_IUP_args
,
854 num_delta_after_IUP_args
);
856 if (ctrl
->point_idx
> 255)
857 need_after_IUP_words
= 1;
860 TA_control_get_next(font
);
863 /* nothing to do if no control instructions */
864 if (!(allocated_before_IUP
|| allocated_after_IUP
))
867 /* add number of argument pairs and function number to the stacks */
868 for (i
= 0; i
< 6; i
++)
870 if (num_delta_before_IUP_args
[i
])
872 unsigned int n
= num_delta_before_IUP_args
[i
] >> 1;
876 need_before_IUP_word_counts
= 1;
878 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) = n
;
879 num_delta_before_IUP_args
[i
]++;
881 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) =
882 bci_deltap1
+ (i
% 3);
883 num_delta_before_IUP_args
[i
]++;
887 /* add number of argument pairs to the stacks */
888 for (i
= 0; i
< 6; i
++)
890 if (num_delta_after_IUP_args
[i
])
892 unsigned int n
= num_delta_after_IUP_args
[i
] >> 1;
896 need_after_IUP_word_counts
= 1;
898 *(delta_after_IUP_args
[i
] + num_delta_after_IUP_args
[i
]) = n
;
899 num_delta_after_IUP_args
[i
]++;
903 /* merge `before IUP' delta stacks into a single one */
904 if (need_before_IUP_words
905 || (!need_before_IUP_words
&& !need_before_IUP_word_counts
))
907 FT_UInt num_args
= 0;
910 for (i
= 0; i
< 6; i
++)
913 FT_UInt num_args_new
;
916 if (!num_delta_before_IUP_args
[i
])
919 num_args_new
= num_args
+ num_delta_before_IUP_args
[i
];
920 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
927 memcpy(args_new
+ num_args
,
928 delta_before_IUP_args
[i
],
929 num_delta_before_IUP_args
[i
] * sizeof (FT_UInt
));
932 num_args
= num_args_new
;
935 num_before_IUP_stack_elements
= (FT_UShort
)num_args
;
937 bufp
= TA_build_push(bufp
, args
, num_args
, need_before_IUP_words
, 1);
941 num_before_IUP_stack_elements
= 0;
943 /* stack elements are bytes, but counts need words */
944 for (i
= 0; i
< 6; i
++)
946 FT_UInt num_delta_arg
;
949 if (!num_delta_before_IUP_args
[i
])
952 num_delta_arg
= num_delta_before_IUP_args
[i
] - 2;
954 bufp
= TA_build_push(bufp
,
955 delta_before_IUP_args
[i
],
957 need_before_IUP_words
,
960 num_before_IUP_stack_elements
+= num_delta_arg
+ 2;
964 BCI(HIGH(num_delta_arg
));
965 BCI(LOW(num_delta_arg
));
967 /* the function number */
969 BCI(delta_before_IUP_args
[i
][num_delta_before_IUP_args
[i
] - 1]);
973 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
974 if (num_delta_before_IUP_args
[5])
976 if (num_delta_before_IUP_args
[4])
978 if (num_delta_before_IUP_args
[3])
981 if (num_delta_before_IUP_args
[2]
982 || num_delta_before_IUP_args
[1]
983 || num_delta_before_IUP_args
[0])
986 /* emit x DELTA opcodes */
987 if (num_delta_before_IUP_args
[2])
989 if (num_delta_before_IUP_args
[1])
991 if (num_delta_before_IUP_args
[0])
994 if (num_delta_before_IUP_args
[2]
995 || num_delta_before_IUP_args
[1]
996 || num_delta_before_IUP_args
[0])
999 if (num_delta_before_IUP_args
[5]
1000 || num_delta_before_IUP_args
[4]
1001 || num_delta_before_IUP_args
[3])
1004 /* merge `after IUP' delta stacks into a single one */
1005 if (need_after_IUP_words
1006 || (!need_after_IUP_words
&& !need_after_IUP_word_counts
))
1008 FT_UInt num_args
= 0;
1011 for (i
= 0; i
< 6; i
++)
1014 FT_UInt num_args_new
;
1017 if (!num_delta_after_IUP_args
[i
])
1020 num_args_new
= num_args
+ num_delta_after_IUP_args
[i
];
1021 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
1028 memcpy(args_new
+ num_args
,
1029 delta_after_IUP_args
[i
],
1030 num_delta_after_IUP_args
[i
] * sizeof (FT_UInt
));
1033 num_args
= num_args_new
;
1036 num_after_IUP_stack_elements
= (FT_UShort
)num_args
;
1038 bufp
= TA_build_push(bufp
, args
, num_args
, need_after_IUP_words
, 1);
1042 num_after_IUP_stack_elements
= 0;
1044 /* stack elements are bytes, but counts need words */
1045 for (i
= 0; i
< 6; i
++)
1047 FT_UInt num_delta_arg
;
1050 if (!num_delta_after_IUP_args
[i
])
1053 num_delta_arg
= num_delta_after_IUP_args
[i
] - 1;
1055 bufp
= TA_build_push(bufp
,
1056 delta_after_IUP_args
[i
],
1058 need_after_IUP_words
,
1061 num_after_IUP_stack_elements
+= num_delta_arg
+ 1;
1063 num_delta_arg
>>= 1;
1065 BCI(HIGH(num_delta_arg
));
1066 BCI(LOW(num_delta_arg
));
1070 /* emit y DELTA opcodes */
1071 if (num_delta_after_IUP_args
[5])
1073 if (num_delta_after_IUP_args
[4])
1075 if (num_delta_after_IUP_args
[3])
1078 if (num_delta_after_IUP_args
[2]
1079 || num_delta_after_IUP_args
[1]
1080 || num_delta_after_IUP_args
[0])
1083 /* emit x DELTA opcodes */
1084 if (num_delta_after_IUP_args
[2])
1086 if (num_delta_after_IUP_args
[1])
1088 if (num_delta_after_IUP_args
[0])
1091 /* we need to insert a few extra bytecode instructions */
1092 /* if we have y delta exceptions before IUP */
1093 if (num_delta_before_IUP_args
[5]
1094 || num_delta_before_IUP_args
[4]
1095 || num_delta_before_IUP_args
[3])
1097 FT_Byte
* ins_extra_buf_new
;
1098 FT_Byte ins_extra_len_new
;
1101 ins_extra_len_new
= glyph
->ins_extra_len
1102 + sizeof (ins_extra_delta_exceptions
);
1103 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
1105 if (!ins_extra_buf_new
)
1111 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1112 /* by activating `ins_extra_delta_exceptions' */
1113 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
1114 ins_extra_delta_exceptions
,
1115 sizeof (ins_extra_delta_exceptions
));
1117 glyph
->ins_extra_buf
= ins_extra_buf_new
;
1118 glyph
->ins_extra_len
= ins_extra_len_new
;
1120 /* reset `cvtl_do_iup_y' for next glyph */
1128 for (i
= 0; i
< 6; i
++)
1130 free(delta_before_IUP_args
[i
]);
1131 free(delta_after_IUP_args
[i
]);
1135 if (num_before_IUP_stack_elements
> sfnt
->max_stack_elements
)
1136 sfnt
->max_stack_elements
= num_before_IUP_stack_elements
;
1137 if (num_after_IUP_stack_elements
> sfnt
->max_stack_elements
)
1138 sfnt
->max_stack_elements
= num_after_IUP_stack_elements
;
1145 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
1149 FONT
* font
= recorder
->font
;
1150 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
1151 FT_Vector
* points
= glyph
->outline
.points
;
1152 FT_UInt num_contours
= (FT_UInt
)glyph
->outline
.n_contours
;
1158 FT_Bool need_words
= 0;
1161 FT_UShort num_storage
;
1162 FT_UShort num_stack_elements
;
1165 num_args
= 2 * num_contours
+ 2;
1167 /* collect all arguments temporarily in an array (in reverse order) */
1168 /* so that we can easily split into chunks of 255 args */
1169 /* as needed by NPUSHB and NPUSHW, respectively */
1170 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1174 arg
= args
+ num_args
- 1;
1176 if (num_args
> 0xFF)
1179 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
1180 *(arg
--) = bci_scale_composite_glyph
;
1182 *(arg
--) = bci_scale_glyph
;
1183 *(arg
--) = num_contours
;
1188 for (p
= 0; p
< num_contours
; p
++)
1190 FT_UInt max
= start
;
1191 FT_UInt min
= start
;
1194 end
= (FT_UInt
)glyph
->outline
.contours
[p
];
1196 for (q
= start
; q
<= end
; q
++)
1198 if (points
[q
].y
< points
[min
].y
)
1200 if (points
[q
].y
> points
[max
].y
)
1206 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1207 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1211 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1212 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1221 /* with most fonts it is very rare */
1222 /* that any of the pushed arguments is larger than 0xFF, */
1223 /* thus we refrain from further optimizing this case */
1224 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
1228 num_storage
= sal_segment_offset
;
1229 if (num_storage
> sfnt
->max_storage
)
1230 sfnt
->max_storage
= num_storage
;
1232 num_stack_elements
= (FT_UShort
)(ADDITIONAL_STACK_ELEMENTS
+ num_args
);
1233 if (num_stack_elements
> sfnt
->max_stack_elements
)
1234 sfnt
->max_stack_elements
= num_stack_elements
;
1243 TA_font_build_subglyph_shifter(FONT
* font
,
1246 FT_Face face
= font
->loader
->face
;
1247 FT_GlyphSlot glyph
= face
->glyph
;
1249 TA_GlyphLoader gloader
= font
->loader
->gloader
;
1251 TA_SubGlyph subglyphs
= gloader
->current
.subglyphs
;
1252 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->current
.num_subglyphs
;
1253 TA_SubGlyph subglyph
;
1255 FT_Int curr_contour
= 0;
1258 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
1262 FT_UShort flags
= subglyph
->flags
;
1263 FT_Pos y_offset
= subglyph
->arg2
;
1265 FT_Int num_contours
;
1268 /* load subglyph to get the number of contours */
1269 error
= FT_Load_Glyph(face
, (FT_UInt
)subglyph
->index
, FT_LOAD_NO_SCALE
);
1272 num_contours
= glyph
->outline
.n_contours
;
1274 /* nothing to do if there is a point-to-point alignment */
1275 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
1278 /* nothing to do if y offset is zero */
1282 /* nothing to do if there are no contours */
1286 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1287 /* ensures that composite subglyphs are represented as simple glyphs */
1289 if (num_contours
> 0xFF
1290 || curr_contour
> 0xFF)
1293 BCI(HIGH(curr_contour
));
1294 BCI(LOW(curr_contour
));
1295 BCI(HIGH(num_contours
));
1296 BCI(LOW(num_contours
));
1305 /* there are high chances that this value needs PUSHW, */
1306 /* thus we handle it separately */
1307 if (y_offset
> 0xFF || y_offset
< 0)
1310 BCI(HIGH(y_offset
));
1320 BCI(bci_shift_subglyph
);
1324 curr_contour
+= num_contours
;
1332 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1333 * data in four arrays (which are simple but waste a lot of memory). The
1334 * function below converts them into bytecode.
1336 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1337 * together with the edge they correspond to.
1339 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1340 * loop over the edge or edge pairs, respectively, and each edge or edge
1341 * pair contains an inner loop to emit the correponding points.
1345 TA_build_point_hints(Recorder
* recorder
,
1346 TA_GlyphHints hints
)
1348 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1349 TA_Edge edges
= axis
->edges
;
1351 FT_Byte
* p
= recorder
->hints_record
.buf
;
1356 FT_UShort prev_edge
;
1357 FT_UShort prev_before_edge
;
1358 FT_UShort prev_after_edge
;
1363 Node3
* between_node
;
1366 /* we store everything as 16bit numbers; */
1367 /* the function numbers (`ta_ip_before', etc.) */
1368 /* reflect the order in the TA_Action enumeration */
1370 /* ip_before_points */
1373 for (before_node
= LLRB_MIN(ip_before_points
,
1374 &recorder
->ip_before_points_head
);
1376 before_node
= LLRB_NEXT(ip_before_points
,
1377 &recorder
->ip_before_points_head
,
1387 FT_UShort edge_first_idx
;
1390 recorder
->hints_record
.num_actions
++;
1393 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1396 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1397 *(p
++) = HIGH(edge_first_idx
);
1398 *(p
++) = LOW(edge_first_idx
);
1402 for (before_node
= LLRB_MIN(ip_before_points
,
1403 &recorder
->ip_before_points_head
);
1405 before_node
= LLRB_NEXT(ip_before_points
,
1406 &recorder
->ip_before_points_head
,
1412 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1413 *(p
++) = HIGH(point
);
1414 *(p
++) = LOW(point
);
1418 /* ip_after_points */
1421 for (after_node
= LLRB_MIN(ip_after_points
,
1422 &recorder
->ip_after_points_head
);
1424 after_node
= LLRB_NEXT(ip_after_points
,
1425 &recorder
->ip_after_points_head
,
1435 FT_UShort edge_first_idx
;
1438 recorder
->hints_record
.num_actions
++;
1440 edge
= edges
+ axis
->num_edges
- 1;
1441 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1444 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1445 *(p
++) = HIGH(edge_first_idx
);
1446 *(p
++) = LOW(edge_first_idx
);
1450 for (after_node
= LLRB_MIN(ip_after_points
,
1451 &recorder
->ip_after_points_head
);
1453 after_node
= LLRB_NEXT(ip_after_points
,
1454 &recorder
->ip_after_points_head
,
1460 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1461 *(p
++) = HIGH(point
);
1462 *(p
++) = LOW(point
);
1466 /* ip_on_point_array */
1470 for (on_node
= LLRB_MIN(ip_on_points
,
1471 &recorder
->ip_on_points_head
);
1473 on_node
= LLRB_NEXT(ip_on_points
,
1474 &recorder
->ip_on_points_head
,
1478 if (on_node
->edge
!= prev_edge
)
1481 prev_edge
= on_node
->edge
;
1487 recorder
->hints_record
.num_actions
++;
1490 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1494 for (on_node
= LLRB_MIN(ip_on_points
,
1495 &recorder
->ip_on_points_head
);
1497 on_node
= LLRB_NEXT(ip_on_points
,
1498 &recorder
->ip_on_points_head
,
1503 FT_UShort edge_first_idx
;
1506 edge
= edges
+ on_node
->edge
;
1507 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1509 *(p
++) = HIGH(edge_first_idx
);
1510 *(p
++) = LOW(edge_first_idx
);
1512 /* save current position */
1513 edge_node
= on_node
;
1517 on_node
= LLRB_NEXT(ip_on_points
,
1518 &recorder
->ip_on_points_head
,
1521 /* count points on current edge */
1522 if (on_node
->edge
!= edge_node
->edge
)
1530 /* restore current position */
1531 on_node
= edge_node
;
1534 on_node
= LLRB_NEXT(ip_on_points
,
1535 &recorder
->ip_on_points_head
,
1541 if (on_node
->edge
!= edge_node
->edge
)
1544 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1545 *(p
++) = HIGH(point
);
1546 *(p
++) = LOW(point
);
1548 /* keep track of previous node */
1549 edge_node
= on_node
;
1552 /* reset loop iterator by one element, then continue */
1553 on_node
= edge_node
;
1557 /* ip_between_point_array */
1559 prev_before_edge
= 0xFFFF;
1560 prev_after_edge
= 0xFFFF;
1562 for (between_node
= LLRB_MIN(ip_between_points
,
1563 &recorder
->ip_between_points_head
);
1565 between_node
= LLRB_NEXT(ip_between_points
,
1566 &recorder
->ip_between_points_head
,
1569 /* count `(before,after)' edge pairs */
1570 if (between_node
->before_edge
!= prev_before_edge
1571 || between_node
->after_edge
!= prev_after_edge
)
1574 prev_before_edge
= between_node
->before_edge
;
1575 prev_after_edge
= between_node
->after_edge
;
1581 recorder
->hints_record
.num_actions
++;
1584 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1588 for (between_node
= LLRB_MIN(ip_between_points
,
1589 &recorder
->ip_between_points_head
);
1591 between_node
= LLRB_NEXT(ip_between_points
,
1592 &recorder
->ip_between_points_head
,
1595 Node3
* edge_pair_node
;
1598 FT_UShort before_first_idx
;
1599 FT_UShort after_first_idx
;
1602 before
= edges
+ between_node
->before_edge
;
1603 after
= edges
+ between_node
->after_edge
;
1604 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
1605 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
1607 *(p
++) = HIGH(after_first_idx
);
1608 *(p
++) = LOW(after_first_idx
);
1609 *(p
++) = HIGH(before_first_idx
);
1610 *(p
++) = LOW(before_first_idx
);
1612 /* save current position */
1613 edge_pair_node
= between_node
;
1617 between_node
= LLRB_NEXT(ip_between_points
,
1618 &recorder
->ip_between_points_head
,
1621 /* count points associated with current edge pair */
1622 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1623 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1631 /* restore current position */
1632 between_node
= edge_pair_node
;
1635 between_node
= LLRB_NEXT(ip_between_points
,
1636 &recorder
->ip_between_points_head
,
1642 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1643 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1646 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1647 *(p
++) = HIGH(point
);
1648 *(p
++) = LOW(point
);
1650 /* keep track of previous node */
1651 edge_pair_node
= between_node
;
1654 /* reset loop iterator by one element, then continue */
1655 between_node
= edge_pair_node
;
1659 recorder
->hints_record
.buf
= p
;
1664 TA_hints_record_is_different(Hints_Record
* hints_records
,
1665 FT_UInt num_hints_records
,
1669 Hints_Record last_hints_record
;
1675 /* we only need to compare with the last hints record */
1676 last_hints_record
= hints_records
[num_hints_records
- 1];
1678 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1681 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1689 TA_add_hints_record(Hints_Record
** hints_records
,
1690 FT_UInt
* num_hints_records
,
1692 Hints_Record hints_record
)
1694 Hints_Record
* hints_records_new
;
1696 /* at this point, `hints_record.buf' still points into `ins_buf' */
1697 FT_Byte
* end
= hints_record
.buf
;
1700 buf_len
= (FT_UInt
)(end
- start
);
1702 /* now fill the structure completely */
1703 hints_record
.buf_len
= buf_len
;
1704 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1705 if (!hints_record
.buf
)
1706 return FT_Err_Out_Of_Memory
;
1708 memcpy(hints_record
.buf
, start
, buf_len
);
1710 (*num_hints_records
)++;
1712 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1713 * sizeof (Hints_Record
));
1714 if (!hints_records_new
)
1716 free(hints_record
.buf
);
1717 (*num_hints_records
)--;
1718 return FT_Err_Out_Of_Memory
;
1721 *hints_records
= hints_records_new
;
1723 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1730 TA_emit_hints_record(Recorder
* recorder
,
1731 Hints_Record
* hints_record
,
1737 FT_Bool need_words
= 0;
1740 FT_UInt num_arguments
;
1744 /* check whether any argument is larger than 0xFF */
1745 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1746 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1753 /* with most fonts it is very rare */
1754 /* that any of the pushed arguments is larger than 0xFF, */
1755 /* thus we refrain from further optimizing this case */
1757 num_arguments
= hints_record
->buf_len
/ 2;
1762 for (i
= 0; i
< num_arguments
; i
+= 255)
1764 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1766 if (optimize
&& num_args
<= 8)
1767 BCI(PUSHW_1
- 1 + num_args
);
1773 for (j
= 0; j
< num_args
; j
++)
1783 /* we only need the lower bytes */
1786 for (i
= 0; i
< num_arguments
; i
+= 255)
1788 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1790 if (optimize
&& num_args
<= 8)
1791 BCI(PUSHB_1
- 1 + num_args
);
1797 for (j
= 0; j
< num_args
; j
++)
1805 /* collect stack depth data */
1806 if (num_arguments
> recorder
->num_stack_elements
)
1807 recorder
->num_stack_elements
= (FT_UShort
)num_arguments
;
1814 TA_emit_hints_records(Recorder
* recorder
,
1815 Hints_Record
* hints_records
,
1816 FT_UInt num_hints_records
,
1821 Hints_Record
* hints_record
;
1824 hints_record
= hints_records
;
1826 /* emit hints records in `if' clauses, */
1827 /* with the ppem size as the condition */
1828 for (i
= 0; i
< num_hints_records
- 1; i
++)
1831 if (hints_record
->size
> 0xFF)
1834 BCI(HIGH((hints_record
+ 1)->size
));
1835 BCI(LOW((hints_record
+ 1)->size
));
1840 BCI((hints_record
+ 1)->size
);
1844 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1850 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1852 for (i
= 0; i
< num_hints_records
- 1; i
++)
1860 TA_free_hints_records(Hints_Record
* hints_records
,
1861 FT_UInt num_hints_records
)
1866 for (i
= 0; i
< num_hints_records
; i
++)
1867 free(hints_records
[i
].buf
);
1869 free(hints_records
);
1874 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1881 FT_UShort num_segs
= 0;
1883 FT_UShort num_segments
;
1886 seg_idx
= TA_get_segment_index(edge
->first
, recorder
);
1887 num_segments
= TA_get_segment_index(NULL
, recorder
);
1889 /* we store everything as 16bit numbers */
1890 *(bufp
++) = HIGH(seg_idx
);
1891 *(bufp
++) = LOW(seg_idx
);
1893 /* wrap-around segments are stored as two segments */
1894 if (edge
->first
->first
> edge
->first
->last
)
1897 seg
= edge
->first
->edge_next
;
1898 while (seg
!= edge
->first
)
1902 if (seg
->first
> seg
->last
)
1905 seg
= seg
->edge_next
;
1908 *(bufp
++) = HIGH(num_segs
);
1909 *(bufp
++) = LOW(num_segs
);
1911 if (edge
->first
->first
> edge
->first
->last
)
1913 /* emit second part of wrap-around segment; */
1914 /* the bytecode positions such segments after `normal' ones */
1918 if (seg_idx
== *wrap
)
1923 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1924 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1927 seg
= edge
->first
->edge_next
;
1928 while (seg
!= edge
->first
)
1930 seg_idx
= TA_get_segment_index(seg
, recorder
);
1932 *(bufp
++) = HIGH(seg_idx
);
1933 *(bufp
++) = LOW(seg_idx
);
1935 if (seg
->first
> seg
->last
)
1940 if (seg_idx
== *wrap
)
1945 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1946 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1949 seg
= seg
->edge_next
;
1957 TA_hints_recorder(TA_Action action
,
1958 TA_GlyphHints hints
,
1963 TA_Edge lower_bound
,
1964 TA_Edge upper_bound
)
1966 TA_AxisHints axis
= &hints
->axis
[dim
];
1967 TA_Edge edges
= axis
->edges
;
1968 TA_Point points
= hints
->points
;
1970 TA_Segment segments
= axis
->segments
;
1971 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1974 Recorder
* recorder
= (Recorder
*)hints
->user
;
1975 SFNT
* sfnt
= recorder
->sfnt
;
1976 FONT
* font
= recorder
->font
;
1977 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1978 FT_Byte
* p
= recorder
->hints_record
.buf
;
1980 TA_StyleClass style_class
= font
->loader
->metrics
->style_class
;
1981 TA_ScriptClass script_class
= ta_script_classes
[style_class
->script
];
1983 FT_UInt style
= style_class
->style
;
1984 FT_Bool top_to_bottom_hinting
= script_class
->top_to_bottom_hinting
;
1987 if (dim
== TA_DIMENSION_HORZ
)
1990 if (!recorder
->segment_map_initialized
)
1992 FT_UShort
* segment_map
= recorder
->segment_map
;
1997 for (seg
= segments
; seg
< seg_limit
; seg
++)
2000 *segment_map
= idx
++;
2002 *segment_map
= 0xFFFF;
2008 recorder
->segment_map_initialized
= 1;
2011 if (!recorder
->wrap_around_segments_initialized
)
2013 FT_UShort
* wrap_around_segment
;
2016 wrap_around_segment
= recorder
->wrap_around_segments
;
2017 for (seg
= segments
; seg
< seg_limit
; seg
++)
2018 if (seg
->first
> seg
->last
)
2019 *(wrap_around_segment
++) = TA_get_segment_index(seg
, recorder
);
2021 recorder
->wrap_around_segments_initialized
= 1;
2024 /* we collect point hints for later processing */
2030 TA_Point point
= (TA_Point
)arg1
;
2033 before_node
= (Node1
*)malloc(sizeof (Node1
));
2036 before_node
->point
= (FT_UShort
)(point
- points
);
2038 LLRB_INSERT(ip_before_points
,
2039 &recorder
->ip_before_points_head
,
2047 TA_Point point
= (TA_Point
)arg1
;
2050 after_node
= (Node1
*)malloc(sizeof (Node1
));
2053 after_node
->point
= (FT_UShort
)(point
- points
);
2055 LLRB_INSERT(ip_after_points
,
2056 &recorder
->ip_after_points_head
,
2064 TA_Point point
= (TA_Point
)arg1
;
2065 TA_Edge edge
= arg2
;
2068 on_node
= (Node2
*)malloc(sizeof (Node2
));
2071 on_node
->edge
= (FT_UShort
)(edge
- edges
);
2072 on_node
->point
= (FT_UShort
)(point
- points
);
2074 LLRB_INSERT(ip_on_points
,
2075 &recorder
->ip_on_points_head
,
2082 Node3
* between_node
;
2083 TA_Point point
= (TA_Point
)arg1
;
2084 TA_Edge before
= arg2
;
2085 TA_Edge after
= arg3
;
2088 between_node
= (Node3
*)malloc(sizeof (Node3
));
2091 between_node
->before_edge
= (FT_UShort
)(before
- edges
);
2092 between_node
->after_edge
= (FT_UShort
)(after
- edges
);
2093 between_node
->point
= (FT_UShort
)(point
- points
);
2095 LLRB_INSERT(ip_between_points
,
2096 &recorder
->ip_between_points_head
,
2102 /* we ignore the BOUND action since we signal this information */
2103 /* with the proper function number */
2110 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2111 /* if the value is n, the function numbers are n, ..., n+11, */
2112 /* to be differentiated with flags */
2118 TA_Edge base_edge
= (TA_Edge
)arg1
;
2119 TA_Edge stem_edge
= arg2
;
2120 FT_UShort base_first_idx
;
2121 FT_UShort stem_first_idx
;
2124 base_first_idx
= TA_get_segment_index(base_edge
->first
, recorder
);
2125 stem_first_idx
= TA_get_segment_index(stem_edge
->first
, recorder
);
2128 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2129 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
2130 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
2132 *(p
++) = HIGH(base_first_idx
);
2133 *(p
++) = LOW(base_first_idx
);
2134 *(p
++) = HIGH(stem_first_idx
);
2135 *(p
++) = LOW(stem_first_idx
);
2137 p
= TA_hints_recorder_handle_segments(p
, recorder
, stem_edge
, wraps
);
2143 TA_Edge edge
= (TA_Edge
)arg1
;
2144 TA_Edge edge2
= arg2
;
2145 FT_UShort edge_first_idx
;
2146 FT_UShort edge2_first_idx
;
2149 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2150 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2153 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2154 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2155 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
2157 *(p
++) = HIGH(edge_first_idx
);
2158 *(p
++) = LOW(edge_first_idx
);
2159 *(p
++) = HIGH(edge2_first_idx
);
2160 *(p
++) = LOW(edge2_first_idx
);
2162 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2168 TA_Edge edge
= (TA_Edge
)arg1
;
2169 TA_Edge edge2
= arg2
;
2170 TA_Edge edge_minus_one
= lower_bound
;
2171 FT_UShort edge_first_idx
;
2172 FT_UShort edge2_first_idx
;
2175 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2176 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2179 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2180 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2181 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2182 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2183 + 4 * (edge_minus_one
!= NULL
2184 && top_to_bottom_hinting
); /* `down' */
2186 *(p
++) = HIGH(edge_first_idx
);
2187 *(p
++) = LOW(edge_first_idx
);
2188 *(p
++) = HIGH(edge2_first_idx
);
2189 *(p
++) = LOW(edge2_first_idx
);
2193 FT_UShort edge_minus_one_first_idx
;
2196 edge_minus_one_first_idx
= TA_get_segment_index(
2197 edge_minus_one
->first
, recorder
);
2199 *(p
++) = HIGH(edge_minus_one_first_idx
);
2200 *(p
++) = LOW(edge_minus_one_first_idx
);
2203 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2207 case ta_blue_anchor
:
2209 TA_Edge edge
= (TA_Edge
)arg1
;
2210 TA_Edge blue
= arg2
;
2211 FT_UShort blue_first_idx
;
2212 FT_UShort edge_first_idx
;
2215 blue_first_idx
= TA_get_segment_index(blue
->first
, recorder
);
2216 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2219 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2221 *(p
++) = HIGH(blue_first_idx
);
2222 *(p
++) = LOW(blue_first_idx
);
2224 if (edge
->best_blue_is_shoot
)
2226 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2227 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2231 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2232 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2235 *(p
++) = HIGH(edge_first_idx
);
2236 *(p
++) = LOW(edge_first_idx
);
2238 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2244 TA_Edge edge
= (TA_Edge
)arg1
;
2245 TA_Edge edge2
= arg2
;
2246 TA_Edge edge_minus_one
= lower_bound
;
2247 FT_UShort edge_first_idx
;
2248 FT_UShort edge2_first_idx
;
2251 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2252 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2255 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2256 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2257 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2258 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2259 + 4 * (edge_minus_one
!= NULL
2260 && top_to_bottom_hinting
); /* `down' */
2262 *(p
++) = HIGH(edge_first_idx
);
2263 *(p
++) = LOW(edge_first_idx
);
2264 *(p
++) = HIGH(edge2_first_idx
);
2265 *(p
++) = LOW(edge2_first_idx
);
2269 FT_UShort edge_minus_one_first_idx
;
2272 edge_minus_one_first_idx
= TA_get_segment_index(
2273 edge_minus_one
->first
, recorder
);
2275 *(p
++) = HIGH(edge_minus_one_first_idx
);
2276 *(p
++) = LOW(edge_minus_one_first_idx
);
2279 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2280 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge2
, wraps
);
2286 TA_Edge edge
= (TA_Edge
)arg1
;
2287 FT_UShort edge_first_idx
;
2290 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2293 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2295 if (edge
->best_blue_is_shoot
)
2297 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2298 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2302 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2303 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2306 *(p
++) = HIGH(edge_first_idx
);
2307 *(p
++) = LOW(edge_first_idx
);
2309 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2315 TA_Edge serif
= (TA_Edge
)arg1
;
2316 TA_Edge base
= serif
->serif
;
2317 FT_UShort serif_first_idx
;
2318 FT_UShort base_first_idx
;
2321 serif_first_idx
= TA_get_segment_index(serif
->first
, recorder
);
2322 base_first_idx
= TA_get_segment_index(base
->first
, recorder
);
2325 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2326 + (lower_bound
!= NULL
)
2327 + 2 * (upper_bound
!= NULL
)
2328 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2329 && top_to_bottom_hinting
); /* `down' */
2331 *(p
++) = HIGH(serif_first_idx
);
2332 *(p
++) = LOW(serif_first_idx
);
2333 *(p
++) = HIGH(base_first_idx
);
2334 *(p
++) = LOW(base_first_idx
);
2338 FT_UShort lower_bound_first_idx
;
2341 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2344 *(p
++) = HIGH(lower_bound_first_idx
);
2345 *(p
++) = LOW(lower_bound_first_idx
);
2349 FT_UShort upper_bound_first_idx
;
2352 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2355 *(p
++) = HIGH(upper_bound_first_idx
);
2356 *(p
++) = LOW(upper_bound_first_idx
);
2359 p
= TA_hints_recorder_handle_segments(p
, recorder
, serif
, wraps
);
2363 case ta_serif_anchor
:
2364 case ta_serif_link2
:
2366 TA_Edge edge
= (TA_Edge
)arg1
;
2367 FT_UShort edge_first_idx
;
2370 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2373 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2374 + (lower_bound
!= NULL
)
2375 + 2 * (upper_bound
!= NULL
)
2376 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2377 && top_to_bottom_hinting
); /* `down' */
2379 *(p
++) = HIGH(edge_first_idx
);
2380 *(p
++) = LOW(edge_first_idx
);
2384 FT_UShort lower_bound_first_idx
;
2387 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2390 *(p
++) = HIGH(lower_bound_first_idx
);
2391 *(p
++) = LOW(lower_bound_first_idx
);
2395 FT_UShort upper_bound_first_idx
;
2398 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2401 *(p
++) = HIGH(upper_bound_first_idx
);
2402 *(p
++) = LOW(upper_bound_first_idx
);
2405 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2409 case ta_serif_link1
:
2411 TA_Edge edge
= (TA_Edge
)arg1
;
2412 TA_Edge before
= arg2
;
2413 TA_Edge after
= arg3
;
2414 FT_UShort before_first_idx
;
2415 FT_UShort edge_first_idx
;
2416 FT_UShort after_first_idx
;
2419 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
2420 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2421 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
2424 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2425 + (lower_bound
!= NULL
)
2426 + 2 * (upper_bound
!= NULL
)
2427 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2428 && top_to_bottom_hinting
); /* `down' */
2430 *(p
++) = HIGH(before_first_idx
);
2431 *(p
++) = LOW(before_first_idx
);
2432 *(p
++) = HIGH(edge_first_idx
);
2433 *(p
++) = LOW(edge_first_idx
);
2434 *(p
++) = HIGH(after_first_idx
);
2435 *(p
++) = LOW(after_first_idx
);
2439 FT_UShort lower_bound_first_idx
;
2442 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2445 *(p
++) = HIGH(lower_bound_first_idx
);
2446 *(p
++) = LOW(lower_bound_first_idx
);
2450 FT_UShort upper_bound_first_idx
;
2453 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2456 *(p
++) = HIGH(upper_bound_first_idx
);
2457 *(p
++) = LOW(upper_bound_first_idx
);
2460 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2465 /* there are more cases in the enumeration */
2466 /* which are handled with flags */
2470 recorder
->hints_record
.num_actions
++;
2471 recorder
->hints_record
.buf
= p
;
2476 TA_init_recorder(Recorder
* recorder
,
2480 TA_GlyphHints hints
)
2482 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2484 TA_Segment segments
= axis
->segments
;
2485 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2489 recorder
->sfnt
= sfnt
;
2490 recorder
->font
= font
;
2491 recorder
->glyph
= glyph
;
2493 LLRB_INIT(&recorder
->ip_before_points_head
);
2494 LLRB_INIT(&recorder
->ip_after_points_head
);
2495 LLRB_INIT(&recorder
->ip_on_points_head
);
2496 LLRB_INIT(&recorder
->ip_between_points_head
);
2498 recorder
->num_stack_elements
= 0;
2500 /* no need to clean up allocated arrays in case of error; */
2501 /* this is handled later by `TA_free_recorder' */
2503 /* we use segment_map[axis->num_segments] */
2504 /* as the total number of mapped segments, so allocate one more element */
2505 recorder
->segment_map
=
2506 (FT_UShort
*)malloc((size_t)(axis
->num_segments
+ 1) * sizeof (FT_UShort
));
2507 if (!recorder
->segment_map
)
2508 return FT_Err_Out_Of_Memory
;
2510 /* `segment_map' gets initialized later on, */
2511 /* after the first call of `ta_loader_load_glyph' */
2512 recorder
->segment_map_initialized
= 0;
2514 recorder
->num_wrap_around_segments
= 0;
2515 for (seg
= segments
; seg
< seg_limit
; seg
++)
2516 if (seg
->first
> seg
->last
)
2517 recorder
->num_wrap_around_segments
++;
2519 recorder
->wrap_around_segments
=
2520 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2521 * sizeof (FT_UShort
));
2522 if (!recorder
->wrap_around_segments
)
2523 return FT_Err_Out_Of_Memory
;
2525 /* `wrap_around_segments' gets initialized later on; */
2526 /* it needs function `TA_get_segment_index' which uses data */
2527 /* that hasn't been initialized yet either */
2528 recorder
->wrap_around_segments_initialized
= 0;
2535 TA_reset_recorder(Recorder
* recorder
,
2538 recorder
->hints_record
.buf
= bufp
;
2539 recorder
->hints_record
.num_actions
= 0;
2544 TA_rewind_recorder(Recorder
* recorder
,
2551 Node3
* between_node
;
2553 Node1
* next_before_node
;
2554 Node1
* next_after_node
;
2555 Node2
* next_on_node
;
2556 Node3
* next_between_node
;
2559 TA_reset_recorder(recorder
, bufp
);
2561 recorder
->hints_record
.size
= size
;
2563 /* deallocate our red-black trees */
2565 for (before_node
= LLRB_MIN(ip_before_points
,
2566 &recorder
->ip_before_points_head
);
2568 before_node
= next_before_node
)
2570 next_before_node
= LLRB_NEXT(ip_before_points
,
2571 &recorder
->ip_before_points_head
,
2573 LLRB_REMOVE(ip_before_points
,
2574 &recorder
->ip_before_points_head
,
2579 for (after_node
= LLRB_MIN(ip_after_points
,
2580 &recorder
->ip_after_points_head
);
2582 after_node
= next_after_node
)
2584 next_after_node
= LLRB_NEXT(ip_after_points
,
2585 &recorder
->ip_after_points_head
,
2587 LLRB_REMOVE(ip_after_points
,
2588 &recorder
->ip_after_points_head
,
2593 for (on_node
= LLRB_MIN(ip_on_points
,
2594 &recorder
->ip_on_points_head
);
2596 on_node
= next_on_node
)
2598 next_on_node
= LLRB_NEXT(ip_on_points
,
2599 &recorder
->ip_on_points_head
,
2601 LLRB_REMOVE(ip_on_points
,
2602 &recorder
->ip_on_points_head
,
2607 for (between_node
= LLRB_MIN(ip_between_points
,
2608 &recorder
->ip_between_points_head
);
2610 between_node
= next_between_node
)
2612 next_between_node
= LLRB_NEXT(ip_between_points
,
2613 &recorder
->ip_between_points_head
,
2615 LLRB_REMOVE(ip_between_points
,
2616 &recorder
->ip_between_points_head
,
2624 TA_free_recorder(Recorder
* recorder
)
2626 free(recorder
->segment_map
);
2627 free(recorder
->wrap_around_segments
);
2629 TA_rewind_recorder(recorder
, NULL
, 0);
2634 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2638 FT_Face face
= sfnt
->face
;
2646 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2647 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2648 /* `idx' is never negative */
2649 GLYPH
* glyph
= &data
->glyphs
[idx
];
2651 TA_FaceGlobals globals
= (TA_FaceGlobals
)sfnt
->face
->autohint
.data
;
2652 FT_UShort
* gstyles
= globals
->glyph_styles
;
2653 FT_Bool use_gstyle_data
= 1;
2655 TA_GlyphHints hints
;
2657 FT_UInt num_action_hints_records
= 0;
2658 FT_UInt num_point_hints_records
= 0;
2659 Hints_Record
* action_hints_records
= NULL
;
2660 Hints_Record
* point_hints_records
= NULL
;
2663 FT_UShort num_stack_elements
;
2664 FT_Bool optimize
= 0;
2666 FT_Int32 load_flags
;
2669 /* we store only three positions, but it simplifies the algorithm in */
2670 /* `TA_optimize_push' if we have one additional element */
2678 /* XXX: right now, we abuse this flag to control */
2679 /* the global behaviour of the auto-hinter */
2680 load_flags
= 1 << 29; /* vertical hinting only */
2681 if (!font
->adjust_subglyphs
)
2683 if (font
->hint_composites
)
2684 load_flags
|= FT_LOAD_NO_SCALE
;
2686 load_flags
|= FT_LOAD_NO_RECURSE
;
2689 /* computing the segments is resolution independent, */
2690 /* thus the pixel size in this call is arbitrary -- */
2691 /* however, we avoid unnecessary debugging output */
2692 /* if we use the lowest value of the hinting range */
2693 error
= FT_Set_Pixel_Sizes(face
,
2694 font
->hinting_range_min
,
2695 font
->hinting_range_min
);
2699 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2700 /* to modify `out' directions of points at the user's request */
2701 /* (which will eventually become single-point segments) */
2702 error
= TA_control_segment_dir_collect(font
, face
->face_index
, idx
);
2707 /* temporarily disable some debugging output */
2708 /* to avoid getting the information twice */
2709 _ta_debug_save
= _ta_debug
;
2713 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2714 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2717 _ta_debug
= _ta_debug_save
;
2723 /* do nothing if we have an empty glyph */
2724 if (!(font
->loader
->gloader
->current
.num_subglyphs
2725 || face
->glyph
->outline
.n_contours
))
2728 hints
= &font
->loader
->hints
;
2731 * We allocate a buffer which is certainly large enough
2732 * to hold all of the created bytecode instructions;
2733 * later on it gets reallocated to its real size.
2735 * The value `1000' is a very rough guess, not tested well.
2737 * For delta exceptions, we have three DELTA commands,
2738 * covering 3*16 ppem values.
2739 * Since a point index can be larger than 255,
2740 * we assume two bytes everywhere for the necessary PUSH calls.
2741 * This value must be doubled for the other arguments of DELTA.
2742 * Additionally, we have both x and y deltas,
2743 * which need to be handled separately in the bytecode.
2744 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2745 * adding some bytes for the necessary overhead.
2747 ins_len
= (FT_UInt
)(hints
->num_points
2749 + ((font
->control_data_head
!= NULL
) ? 400 : 0)));
2750 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2752 return FT_Err_Out_Of_Memory
;
2754 /* handle composite glyph */
2755 if (font
->loader
->gloader
->current
.num_subglyphs
)
2757 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2760 error
= FT_Err_Out_Of_Memory
;
2764 use_gstyle_data
= 0;
2770 if (font
->fallback_scaling
)
2772 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
2774 /* the scaling value of `none_dflt' */
2775 /* (this is, hinting without script-specific blue zones) */
2776 /* is always 1, which corresponds to a no-op */
2781 /* since `TA_init_recorder' hasn't been called yet, */
2782 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2783 recorder
.sfnt
= sfnt
;
2784 recorder
.font
= font
;
2785 recorder
.glyph
= glyph
;
2787 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2790 error
= FT_Err_Out_Of_Memory
;
2795 use_gstyle_data
= 0;
2800 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2804 /* loop over a large range of pixel sizes */
2805 /* to find hints records which get pushed onto the bytecode stack */
2814 (void)FT_Get_Glyph_Name(face
, (FT_UInt
)idx
, buf
, 256);
2816 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2818 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2819 fprintf(stderr
, "\n");
2820 for (i
= 0; i
< num_chars
; i
++)
2822 fprintf(stderr
, "\n\n");
2827 /* we temporarily use `ins_buf' to record the current glyph hints */
2828 ta_loader_register_hints_recorder(font
->loader
,
2833 * It is important that we start the loop with the smallest PPEM value
2834 * used for hinting, since the number of segments that form an edge can
2835 * become smaller for larger PPEM values. For efficiency, we skip
2836 * non-edge one-point segments, and `TA_get_segment_index' would return
2837 * wrong indices otherwise.
2839 for (size
= font
->hinting_range_min
;
2840 size
<= font
->hinting_range_max
;
2848 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2850 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2860 num_chars
= fprintf(stderr
, "size %d\n", size
);
2861 for (i
= 0; i
< num_chars
- 1; i
++)
2863 fprintf(stderr
, "\n\n");
2867 /* calling `ta_loader_load_glyph' uses the */
2868 /* `TA_hints_recorder' function as a callback, */
2869 /* modifying `hints_record' */
2870 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2874 if (TA_hints_record_is_different(action_hints_records
,
2875 num_action_hints_records
,
2876 ins_buf
, recorder
.hints_record
.buf
))
2883 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2884 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2885 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2887 fprintf(stderr
, "action hints record:\n");
2888 if (ins_buf
== recorder
.hints_record
.buf
)
2889 fprintf(stderr
, " (none)");
2892 fprintf(stderr
, " ");
2893 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2894 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2896 fprintf(stderr
, "\n");
2900 error
= TA_add_hints_record(&action_hints_records
,
2901 &num_action_hints_records
,
2902 ins_buf
, recorder
.hints_record
);
2907 /* now handle point records */
2909 TA_reset_recorder(&recorder
, ins_buf
);
2911 /* use the point hints data collected in `TA_hints_recorder' */
2912 TA_build_point_hints(&recorder
, hints
);
2914 if (TA_hints_record_is_different(point_hints_records
,
2915 num_point_hints_records
,
2916 ins_buf
, recorder
.hints_record
.buf
))
2926 num_chars
= fprintf(stderr
, "size %d\n", size
);
2927 for (i
= 0; i
< num_chars
- 1; i
++)
2929 fprintf(stderr
, "\n\n");
2931 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2932 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2933 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2936 fprintf(stderr
, "point hints record:\n");
2937 if (ins_buf
== recorder
.hints_record
.buf
)
2938 fprintf(stderr
, " (none)");
2941 fprintf(stderr
, " ");
2942 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2943 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2945 fprintf(stderr
, "\n\n");
2949 error
= TA_add_hints_record(&point_hints_records
,
2950 &num_point_hints_records
,
2951 ins_buf
, recorder
.hints_record
);
2957 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2959 /* since we only have a single empty record we just scale the glyph */
2960 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2963 error
= FT_Err_Out_Of_Memory
;
2967 use_gstyle_data
= 0;
2972 /* if there is only a single record, */
2973 /* we do a global optimization later on */
2974 if (num_action_hints_records
> 1)
2977 /* store the hints records and handle stack depth */
2979 bufp
= TA_emit_hints_records(&recorder
,
2980 point_hints_records
,
2981 num_point_hints_records
,
2985 num_stack_elements
= recorder
.num_stack_elements
;
2986 recorder
.num_stack_elements
= 0;
2989 bufp
= TA_emit_hints_records(&recorder
,
2990 action_hints_records
,
2991 num_action_hints_records
,
2995 recorder
.num_stack_elements
+= num_stack_elements
;
2998 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
3001 error
= FT_Err_Out_Of_Memory
;
3005 if (num_action_hints_records
== 1)
3006 bufp
= TA_optimize_push(ins_buf
, pos
);
3009 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3010 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3011 TA_free_recorder(&recorder
);
3014 /* handle delta exceptions */
3015 if (font
->control_data_head
)
3017 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
3020 error
= FT_Err_Out_Of_Memory
;
3025 /* we need to insert a few extra bytecode instructions */
3026 /* for non-base glyphs */
3027 if (use_gstyle_data
&& (gstyles
[idx
] & TA_NONBASE
))
3029 FT_Byte
* ins_extra_buf_new
;
3030 FT_Byte ins_extra_len_new
;
3033 ins_extra_len_new
= glyph
->ins_extra_len
3034 + sizeof (ins_extra_ignore_std_width
);
3035 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
3037 if (!ins_extra_buf_new
)
3043 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3044 /* by activating `ins_extra_ignore_std_width' */
3045 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
3046 ins_extra_ignore_std_width
,
3047 sizeof (ins_extra_ignore_std_width
));
3049 glyph
->ins_extra_buf
= ins_extra_buf_new
;
3050 glyph
->ins_extra_len
= ins_extra_len_new
;
3052 /* reset `cvtl_ignore_std_width' for next glyph */
3054 BCI(cvtl_ignore_std_width
);
3059 ins_len
= (FT_UInt
)(bufp
- ins_buf
);
3061 if (ins_len
> sfnt
->max_instructions
)
3062 sfnt
->max_instructions
= (FT_UShort
)ins_len
;
3064 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
3065 glyph
->ins_len
= ins_len
;
3070 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3071 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3072 TA_free_recorder(&recorder
);
3079 /* end of tabytecode.c */