4 * Copyright (C) 2011-2022 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
= glyph
->num_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
|| !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
|| !need_after_IUP_word_counts
)
1006 FT_UInt num_args
= 0;
1009 for (i
= 0; i
< 6; i
++)
1012 FT_UInt num_args_new
;
1015 if (!num_delta_after_IUP_args
[i
])
1018 num_args_new
= num_args
+ num_delta_after_IUP_args
[i
];
1019 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
1026 memcpy(args_new
+ num_args
,
1027 delta_after_IUP_args
[i
],
1028 num_delta_after_IUP_args
[i
] * sizeof (FT_UInt
));
1031 num_args
= num_args_new
;
1034 num_after_IUP_stack_elements
= (FT_UShort
)num_args
;
1036 bufp
= TA_build_push(bufp
, args
, num_args
, need_after_IUP_words
, 1);
1040 num_after_IUP_stack_elements
= 0;
1042 /* stack elements are bytes, but counts need words */
1043 for (i
= 0; i
< 6; i
++)
1045 FT_UInt num_delta_arg
;
1048 if (!num_delta_after_IUP_args
[i
])
1051 num_delta_arg
= num_delta_after_IUP_args
[i
] - 1;
1053 bufp
= TA_build_push(bufp
,
1054 delta_after_IUP_args
[i
],
1056 need_after_IUP_words
,
1059 num_after_IUP_stack_elements
+= num_delta_arg
+ 1;
1061 num_delta_arg
>>= 1;
1063 BCI(HIGH(num_delta_arg
));
1064 BCI(LOW(num_delta_arg
));
1068 /* emit y DELTA opcodes */
1069 if (num_delta_after_IUP_args
[5])
1071 if (num_delta_after_IUP_args
[4])
1073 if (num_delta_after_IUP_args
[3])
1076 if (num_delta_after_IUP_args
[2]
1077 || num_delta_after_IUP_args
[1]
1078 || num_delta_after_IUP_args
[0])
1081 /* emit x DELTA opcodes */
1082 if (num_delta_after_IUP_args
[2])
1084 if (num_delta_after_IUP_args
[1])
1086 if (num_delta_after_IUP_args
[0])
1089 /* we need to insert a few extra bytecode instructions */
1090 /* if we have y delta exceptions before IUP */
1091 if (num_delta_before_IUP_args
[5]
1092 || num_delta_before_IUP_args
[4]
1093 || num_delta_before_IUP_args
[3])
1095 FT_Byte
* ins_extra_buf_new
;
1096 FT_Byte ins_extra_len_new
;
1099 ins_extra_len_new
= glyph
->ins_extra_len
1100 + sizeof (ins_extra_delta_exceptions
);
1101 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
1103 if (!ins_extra_buf_new
)
1109 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1110 /* by activating `ins_extra_delta_exceptions' */
1111 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
1112 ins_extra_delta_exceptions
,
1113 sizeof (ins_extra_delta_exceptions
));
1115 glyph
->ins_extra_buf
= ins_extra_buf_new
;
1116 glyph
->ins_extra_len
= ins_extra_len_new
;
1118 /* reset `cvtl_do_iup_y' for next glyph */
1126 for (i
= 0; i
< 6; i
++)
1128 free(delta_before_IUP_args
[i
]);
1129 free(delta_after_IUP_args
[i
]);
1133 if (num_before_IUP_stack_elements
> sfnt
->max_stack_elements
)
1134 sfnt
->max_stack_elements
= num_before_IUP_stack_elements
;
1135 if (num_after_IUP_stack_elements
> sfnt
->max_stack_elements
)
1136 sfnt
->max_stack_elements
= num_after_IUP_stack_elements
;
1143 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
1147 FONT
* font
= recorder
->font
;
1148 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
1149 FT_Vector
* points
= glyph
->outline
.points
;
1150 FT_UInt num_contours
= (FT_UInt
)glyph
->outline
.n_contours
;
1156 FT_Bool need_words
= 0;
1159 FT_UShort num_storage
;
1160 FT_UShort num_stack_elements
;
1163 num_args
= 2 * num_contours
+ 2;
1165 /* collect all arguments temporarily in an array (in reverse order) */
1166 /* so that we can easily split into chunks of 255 args */
1167 /* as needed by NPUSHB and NPUSHW, respectively */
1168 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1172 arg
= args
+ num_args
- 1;
1174 if (num_args
> 0xFF)
1177 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
1178 *(arg
--) = bci_scale_composite_glyph
;
1180 *(arg
--) = bci_scale_glyph
;
1181 *(arg
--) = num_contours
;
1186 for (p
= 0; p
< num_contours
; p
++)
1188 FT_UInt max
= start
;
1189 FT_UInt min
= start
;
1192 end
= (FT_UInt
)glyph
->outline
.contours
[p
];
1194 for (q
= start
; q
<= end
; q
++)
1196 if (points
[q
].y
< points
[min
].y
)
1198 if (points
[q
].y
> points
[max
].y
)
1204 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1205 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1209 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1210 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1219 /* with most fonts it is very rare */
1220 /* that any of the pushed arguments is larger than 0xFF, */
1221 /* thus we refrain from further optimizing this case */
1222 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
1226 num_storage
= sal_segment_offset
;
1227 if (num_storage
> sfnt
->max_storage
)
1228 sfnt
->max_storage
= num_storage
;
1230 num_stack_elements
= (FT_UShort
)(ADDITIONAL_STACK_ELEMENTS
+ num_args
);
1231 if (num_stack_elements
> sfnt
->max_stack_elements
)
1232 sfnt
->max_stack_elements
= num_stack_elements
;
1241 TA_font_build_subglyph_shifter(FONT
* font
,
1244 FT_Face face
= font
->loader
->face
;
1245 FT_GlyphSlot glyph
= face
->glyph
;
1247 TA_GlyphLoader gloader
= font
->loader
->gloader
;
1249 TA_SubGlyph subglyphs
= gloader
->current
.subglyphs
;
1250 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->current
.num_subglyphs
;
1251 TA_SubGlyph subglyph
;
1253 FT_Int curr_contour
= 0;
1256 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
1260 FT_UShort flags
= subglyph
->flags
;
1261 FT_Pos y_offset
= subglyph
->arg2
;
1263 FT_Int num_contours
;
1266 /* load subglyph to get the number of contours */
1267 error
= FT_Load_Glyph(face
, (FT_UInt
)subglyph
->index
, FT_LOAD_NO_SCALE
);
1270 num_contours
= glyph
->outline
.n_contours
;
1272 /* nothing to do if there is a point-to-point alignment */
1273 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
1276 /* nothing to do if y offset is zero */
1280 /* nothing to do if there are no contours */
1284 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1285 /* ensures that composite subglyphs are represented as simple glyphs */
1287 if (num_contours
> 0xFF
1288 || curr_contour
> 0xFF)
1291 BCI(HIGH(curr_contour
));
1292 BCI(LOW(curr_contour
));
1293 BCI(HIGH(num_contours
));
1294 BCI(LOW(num_contours
));
1303 /* there are high chances that this value needs PUSHW, */
1304 /* thus we handle it separately */
1305 if (y_offset
> 0xFF || y_offset
< 0)
1308 BCI(HIGH(y_offset
));
1318 BCI(bci_shift_subglyph
);
1322 curr_contour
+= num_contours
;
1330 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1331 * data in four arrays (which are simple but waste a lot of memory). The
1332 * function below converts them into bytecode.
1334 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1335 * together with the edge they correspond to.
1337 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1338 * loop over the edge or edge pairs, respectively, and each edge or edge
1339 * pair contains an inner loop to emit the correponding points.
1343 TA_build_point_hints(Recorder
* recorder
,
1344 TA_GlyphHints hints
)
1346 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1347 TA_Edge edges
= axis
->edges
;
1349 FT_Byte
* p
= recorder
->hints_record
.buf
;
1354 FT_UShort prev_edge
;
1355 FT_UShort prev_before_edge
;
1356 FT_UShort prev_after_edge
;
1361 Node3
* between_node
;
1364 /* we store everything as 16bit numbers; */
1365 /* the function numbers (`ta_ip_before', etc.) */
1366 /* reflect the order in the TA_Action enumeration */
1368 /* ip_before_points */
1371 for (before_node
= LLRB_MIN(ip_before_points
,
1372 &recorder
->ip_before_points_head
);
1374 before_node
= LLRB_NEXT(ip_before_points
,
1375 &recorder
->ip_before_points_head
,
1385 FT_UShort edge_first_idx
;
1388 recorder
->hints_record
.num_actions
++;
1391 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1394 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1395 *(p
++) = HIGH(edge_first_idx
);
1396 *(p
++) = LOW(edge_first_idx
);
1400 for (before_node
= LLRB_MIN(ip_before_points
,
1401 &recorder
->ip_before_points_head
);
1403 before_node
= LLRB_NEXT(ip_before_points
,
1404 &recorder
->ip_before_points_head
,
1410 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1411 *(p
++) = HIGH(point
);
1412 *(p
++) = LOW(point
);
1416 /* ip_after_points */
1419 for (after_node
= LLRB_MIN(ip_after_points
,
1420 &recorder
->ip_after_points_head
);
1422 after_node
= LLRB_NEXT(ip_after_points
,
1423 &recorder
->ip_after_points_head
,
1433 FT_UShort edge_first_idx
;
1436 recorder
->hints_record
.num_actions
++;
1438 edge
= edges
+ axis
->num_edges
- 1;
1439 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1442 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1443 *(p
++) = HIGH(edge_first_idx
);
1444 *(p
++) = LOW(edge_first_idx
);
1448 for (after_node
= LLRB_MIN(ip_after_points
,
1449 &recorder
->ip_after_points_head
);
1451 after_node
= LLRB_NEXT(ip_after_points
,
1452 &recorder
->ip_after_points_head
,
1458 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1459 *(p
++) = HIGH(point
);
1460 *(p
++) = LOW(point
);
1464 /* ip_on_point_array */
1468 for (on_node
= LLRB_MIN(ip_on_points
,
1469 &recorder
->ip_on_points_head
);
1471 on_node
= LLRB_NEXT(ip_on_points
,
1472 &recorder
->ip_on_points_head
,
1476 if (on_node
->edge
!= prev_edge
)
1479 prev_edge
= on_node
->edge
;
1485 recorder
->hints_record
.num_actions
++;
1488 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1492 for (on_node
= LLRB_MIN(ip_on_points
,
1493 &recorder
->ip_on_points_head
);
1495 on_node
= LLRB_NEXT(ip_on_points
,
1496 &recorder
->ip_on_points_head
,
1501 FT_UShort edge_first_idx
;
1504 edge
= edges
+ on_node
->edge
;
1505 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
1507 *(p
++) = HIGH(edge_first_idx
);
1508 *(p
++) = LOW(edge_first_idx
);
1510 /* save current position */
1511 edge_node
= on_node
;
1515 on_node
= LLRB_NEXT(ip_on_points
,
1516 &recorder
->ip_on_points_head
,
1519 /* count points on current edge */
1520 if (on_node
->edge
!= edge_node
->edge
)
1528 /* restore current position */
1529 on_node
= edge_node
;
1532 on_node
= LLRB_NEXT(ip_on_points
,
1533 &recorder
->ip_on_points_head
,
1539 if (on_node
->edge
!= edge_node
->edge
)
1542 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1543 *(p
++) = HIGH(point
);
1544 *(p
++) = LOW(point
);
1546 /* keep track of previous node */
1547 edge_node
= on_node
;
1550 /* reset loop iterator by one element, then continue */
1551 on_node
= edge_node
;
1555 /* ip_between_point_array */
1557 prev_before_edge
= 0xFFFF;
1558 prev_after_edge
= 0xFFFF;
1560 for (between_node
= LLRB_MIN(ip_between_points
,
1561 &recorder
->ip_between_points_head
);
1563 between_node
= LLRB_NEXT(ip_between_points
,
1564 &recorder
->ip_between_points_head
,
1567 /* count `(before,after)' edge pairs */
1568 if (between_node
->before_edge
!= prev_before_edge
1569 || between_node
->after_edge
!= prev_after_edge
)
1572 prev_before_edge
= between_node
->before_edge
;
1573 prev_after_edge
= between_node
->after_edge
;
1579 recorder
->hints_record
.num_actions
++;
1582 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1586 for (between_node
= LLRB_MIN(ip_between_points
,
1587 &recorder
->ip_between_points_head
);
1589 between_node
= LLRB_NEXT(ip_between_points
,
1590 &recorder
->ip_between_points_head
,
1593 Node3
* edge_pair_node
;
1596 FT_UShort before_first_idx
;
1597 FT_UShort after_first_idx
;
1600 before
= edges
+ between_node
->before_edge
;
1601 after
= edges
+ between_node
->after_edge
;
1602 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
1603 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
1605 *(p
++) = HIGH(after_first_idx
);
1606 *(p
++) = LOW(after_first_idx
);
1607 *(p
++) = HIGH(before_first_idx
);
1608 *(p
++) = LOW(before_first_idx
);
1610 /* save current position */
1611 edge_pair_node
= between_node
;
1615 between_node
= LLRB_NEXT(ip_between_points
,
1616 &recorder
->ip_between_points_head
,
1619 /* count points associated with current edge pair */
1620 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1621 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1629 /* restore current position */
1630 between_node
= edge_pair_node
;
1633 between_node
= LLRB_NEXT(ip_between_points
,
1634 &recorder
->ip_between_points_head
,
1640 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1641 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1644 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1645 *(p
++) = HIGH(point
);
1646 *(p
++) = LOW(point
);
1648 /* keep track of previous node */
1649 edge_pair_node
= between_node
;
1652 /* reset loop iterator by one element, then continue */
1653 between_node
= edge_pair_node
;
1657 recorder
->hints_record
.buf
= p
;
1662 TA_hints_record_is_different(Hints_Record
* hints_records
,
1663 FT_UInt num_hints_records
,
1667 Hints_Record last_hints_record
;
1673 /* we only need to compare with the last hints record */
1674 last_hints_record
= hints_records
[num_hints_records
- 1];
1676 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1679 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1687 TA_add_hints_record(Hints_Record
** hints_records
,
1688 FT_UInt
* num_hints_records
,
1690 Hints_Record hints_record
)
1692 Hints_Record
* hints_records_new
;
1694 /* at this point, `hints_record.buf' still points into `ins_buf' */
1695 FT_Byte
* end
= hints_record
.buf
;
1698 buf_len
= (FT_UInt
)(end
- start
);
1700 /* now fill the structure completely */
1701 hints_record
.buf_len
= buf_len
;
1702 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1703 if (!hints_record
.buf
)
1704 return FT_Err_Out_Of_Memory
;
1706 memcpy(hints_record
.buf
, start
, buf_len
);
1708 (*num_hints_records
)++;
1710 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1711 * sizeof (Hints_Record
));
1712 if (!hints_records_new
)
1714 free(hints_record
.buf
);
1715 (*num_hints_records
)--;
1716 return FT_Err_Out_Of_Memory
;
1719 *hints_records
= hints_records_new
;
1721 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1728 TA_emit_hints_record(Recorder
* recorder
,
1729 Hints_Record
* hints_record
,
1735 FT_Bool need_words
= 0;
1738 FT_UInt num_arguments
;
1742 /* check whether any argument is larger than 0xFF */
1743 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1744 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1751 /* with most fonts it is very rare */
1752 /* that any of the pushed arguments is larger than 0xFF, */
1753 /* thus we refrain from further optimizing this case */
1755 num_arguments
= hints_record
->buf_len
/ 2;
1760 for (i
= 0; i
< num_arguments
; i
+= 255)
1762 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1764 if (optimize
&& num_args
<= 8)
1765 BCI(PUSHW_1
- 1 + num_args
);
1771 for (j
= 0; j
< num_args
; j
++)
1781 /* we only need the lower bytes */
1784 for (i
= 0; i
< num_arguments
; i
+= 255)
1786 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1788 if (optimize
&& num_args
<= 8)
1789 BCI(PUSHB_1
- 1 + num_args
);
1795 for (j
= 0; j
< num_args
; j
++)
1803 /* collect stack depth data */
1804 if (num_arguments
> recorder
->num_stack_elements
)
1805 recorder
->num_stack_elements
= (FT_UShort
)num_arguments
;
1812 TA_emit_hints_records(Recorder
* recorder
,
1813 Hints_Record
* hints_records
,
1814 FT_UInt num_hints_records
,
1819 Hints_Record
* hints_record
;
1822 hints_record
= hints_records
;
1824 /* emit hints records in `if' clauses, */
1825 /* with the ppem size as the condition */
1826 for (i
= 0; i
< num_hints_records
- 1; i
++)
1829 if (hints_record
->size
> 0xFF)
1832 BCI(HIGH((hints_record
+ 1)->size
));
1833 BCI(LOW((hints_record
+ 1)->size
));
1838 BCI((hints_record
+ 1)->size
);
1842 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1848 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1850 for (i
= 0; i
< num_hints_records
- 1; i
++)
1858 TA_free_hints_records(Hints_Record
* hints_records
,
1859 FT_UInt num_hints_records
)
1864 for (i
= 0; i
< num_hints_records
; i
++)
1865 free(hints_records
[i
].buf
);
1867 free(hints_records
);
1872 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1879 FT_UShort num_segs
= 0;
1881 FT_UShort num_segments
;
1884 seg_idx
= TA_get_segment_index(edge
->first
, recorder
);
1885 num_segments
= TA_get_segment_index(NULL
, recorder
);
1887 /* we store everything as 16bit numbers */
1888 *(bufp
++) = HIGH(seg_idx
);
1889 *(bufp
++) = LOW(seg_idx
);
1891 /* wrap-around segments are stored as two segments */
1892 if (edge
->first
->first
> edge
->first
->last
)
1895 seg
= edge
->first
->edge_next
;
1896 while (seg
!= edge
->first
)
1900 if (seg
->first
> seg
->last
)
1903 seg
= seg
->edge_next
;
1906 *(bufp
++) = HIGH(num_segs
);
1907 *(bufp
++) = LOW(num_segs
);
1909 if (edge
->first
->first
> edge
->first
->last
)
1911 /* emit second part of wrap-around segment; */
1912 /* the bytecode positions such segments after `normal' ones */
1916 if (seg_idx
== *wrap
)
1921 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1922 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1925 seg
= edge
->first
->edge_next
;
1926 while (seg
!= edge
->first
)
1928 seg_idx
= TA_get_segment_index(seg
, recorder
);
1930 *(bufp
++) = HIGH(seg_idx
);
1931 *(bufp
++) = LOW(seg_idx
);
1933 if (seg
->first
> seg
->last
)
1938 if (seg_idx
== *wrap
)
1943 *(bufp
++) = HIGH(num_segments
+ (wrap
- wraps
));
1944 *(bufp
++) = LOW(num_segments
+ (wrap
- wraps
));
1947 seg
= seg
->edge_next
;
1955 TA_hints_recorder(TA_Action action
,
1956 TA_GlyphHints hints
,
1961 TA_Edge lower_bound
,
1962 TA_Edge upper_bound
)
1964 TA_AxisHints axis
= &hints
->axis
[dim
];
1965 TA_Edge edges
= axis
->edges
;
1966 TA_Point points
= hints
->points
;
1968 TA_Segment segments
= axis
->segments
;
1969 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
1972 Recorder
* recorder
= (Recorder
*)hints
->user
;
1973 SFNT
* sfnt
= recorder
->sfnt
;
1974 FONT
* font
= recorder
->font
;
1975 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1976 FT_Byte
* p
= recorder
->hints_record
.buf
;
1978 TA_StyleClass style_class
= font
->loader
->metrics
->style_class
;
1979 TA_ScriptClass script_class
= ta_script_classes
[style_class
->script
];
1981 FT_UInt style
= style_class
->style
;
1982 FT_Bool top_to_bottom_hinting
= script_class
->top_to_bottom_hinting
;
1985 if (dim
== TA_DIMENSION_HORZ
)
1988 if (!recorder
->segment_map_initialized
)
1990 FT_UShort
* segment_map
= recorder
->segment_map
;
1995 for (seg
= segments
; seg
< seg_limit
; seg
++)
1998 *segment_map
= idx
++;
2000 *segment_map
= 0xFFFF;
2006 recorder
->segment_map_initialized
= 1;
2009 if (!recorder
->wrap_around_segments_initialized
)
2011 FT_UShort
* wrap_around_segment
;
2014 wrap_around_segment
= recorder
->wrap_around_segments
;
2015 for (seg
= segments
; seg
< seg_limit
; seg
++)
2016 if (seg
->first
> seg
->last
)
2017 *(wrap_around_segment
++) = TA_get_segment_index(seg
, recorder
);
2019 recorder
->wrap_around_segments_initialized
= 1;
2022 /* we collect point hints for later processing */
2028 TA_Point point
= (TA_Point
)arg1
;
2031 before_node
= (Node1
*)malloc(sizeof (Node1
));
2034 before_node
->point
= (FT_UShort
)(point
- points
);
2036 LLRB_INSERT(ip_before_points
,
2037 &recorder
->ip_before_points_head
,
2045 TA_Point point
= (TA_Point
)arg1
;
2048 after_node
= (Node1
*)malloc(sizeof (Node1
));
2051 after_node
->point
= (FT_UShort
)(point
- points
);
2053 LLRB_INSERT(ip_after_points
,
2054 &recorder
->ip_after_points_head
,
2062 TA_Point point
= (TA_Point
)arg1
;
2063 TA_Edge edge
= arg2
;
2066 on_node
= (Node2
*)malloc(sizeof (Node2
));
2069 on_node
->edge
= (FT_UShort
)(edge
- edges
);
2070 on_node
->point
= (FT_UShort
)(point
- points
);
2072 LLRB_INSERT(ip_on_points
,
2073 &recorder
->ip_on_points_head
,
2080 Node3
* between_node
;
2081 TA_Point point
= (TA_Point
)arg1
;
2082 TA_Edge before
= arg2
;
2083 TA_Edge after
= arg3
;
2086 between_node
= (Node3
*)malloc(sizeof (Node3
));
2089 between_node
->before_edge
= (FT_UShort
)(before
- edges
);
2090 between_node
->after_edge
= (FT_UShort
)(after
- edges
);
2091 between_node
->point
= (FT_UShort
)(point
- points
);
2093 LLRB_INSERT(ip_between_points
,
2094 &recorder
->ip_between_points_head
,
2100 /* we ignore the BOUND action since we signal this information */
2101 /* with the proper function number */
2108 /* some enum values correspond to 4, 7, 8, or 12 bytecode functions; */
2109 /* if the value is n, the function numbers are n, ..., n+11, */
2110 /* to be differentiated with flags */
2116 TA_Edge base_edge
= (TA_Edge
)arg1
;
2117 TA_Edge stem_edge
= arg2
;
2118 FT_UShort base_first_idx
;
2119 FT_UShort stem_first_idx
;
2122 base_first_idx
= TA_get_segment_index(base_edge
->first
, recorder
);
2123 stem_first_idx
= TA_get_segment_index(stem_edge
->first
, recorder
);
2126 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2127 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
2128 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
2130 *(p
++) = HIGH(base_first_idx
);
2131 *(p
++) = LOW(base_first_idx
);
2132 *(p
++) = HIGH(stem_first_idx
);
2133 *(p
++) = LOW(stem_first_idx
);
2135 p
= TA_hints_recorder_handle_segments(p
, recorder
, stem_edge
, wraps
);
2141 TA_Edge edge
= (TA_Edge
)arg1
;
2142 TA_Edge edge2
= arg2
;
2143 FT_UShort edge_first_idx
;
2144 FT_UShort edge2_first_idx
;
2147 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2148 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2151 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2152 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2153 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
2155 *(p
++) = HIGH(edge_first_idx
);
2156 *(p
++) = LOW(edge_first_idx
);
2157 *(p
++) = HIGH(edge2_first_idx
);
2158 *(p
++) = LOW(edge2_first_idx
);
2160 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2166 TA_Edge edge
= (TA_Edge
)arg1
;
2167 TA_Edge edge2
= arg2
;
2168 TA_Edge edge_minus_one
= lower_bound
;
2169 FT_UShort edge_first_idx
;
2170 FT_UShort edge2_first_idx
;
2173 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2174 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2177 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2178 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2179 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2180 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2181 + 4 * (edge_minus_one
!= NULL
2182 && top_to_bottom_hinting
); /* `down' */
2184 *(p
++) = HIGH(edge_first_idx
);
2185 *(p
++) = LOW(edge_first_idx
);
2186 *(p
++) = HIGH(edge2_first_idx
);
2187 *(p
++) = LOW(edge2_first_idx
);
2191 FT_UShort edge_minus_one_first_idx
;
2194 edge_minus_one_first_idx
= TA_get_segment_index(
2195 edge_minus_one
->first
, recorder
);
2197 *(p
++) = HIGH(edge_minus_one_first_idx
);
2198 *(p
++) = LOW(edge_minus_one_first_idx
);
2201 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2205 case ta_blue_anchor
:
2207 TA_Edge edge
= (TA_Edge
)arg1
;
2208 TA_Edge blue
= arg2
;
2209 FT_UShort blue_first_idx
;
2210 FT_UShort edge_first_idx
;
2213 blue_first_idx
= TA_get_segment_index(blue
->first
, recorder
);
2214 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2217 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2219 *(p
++) = HIGH(blue_first_idx
);
2220 *(p
++) = LOW(blue_first_idx
);
2222 if (edge
->best_blue_is_shoot
)
2224 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2225 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2229 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2230 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2233 *(p
++) = HIGH(edge_first_idx
);
2234 *(p
++) = LOW(edge_first_idx
);
2236 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2242 TA_Edge edge
= (TA_Edge
)arg1
;
2243 TA_Edge edge2
= arg2
;
2244 TA_Edge edge_minus_one
= lower_bound
;
2245 FT_UShort edge_first_idx
;
2246 FT_UShort edge2_first_idx
;
2249 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2250 edge2_first_idx
= TA_get_segment_index(edge2
->first
, recorder
);
2253 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2254 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2255 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2256 + 4 * (edge_minus_one
!= NULL
) /* `bound' */
2257 + 4 * (edge_minus_one
!= NULL
2258 && top_to_bottom_hinting
); /* `down' */
2260 *(p
++) = HIGH(edge_first_idx
);
2261 *(p
++) = LOW(edge_first_idx
);
2262 *(p
++) = HIGH(edge2_first_idx
);
2263 *(p
++) = LOW(edge2_first_idx
);
2267 FT_UShort edge_minus_one_first_idx
;
2270 edge_minus_one_first_idx
= TA_get_segment_index(
2271 edge_minus_one
->first
, recorder
);
2273 *(p
++) = HIGH(edge_minus_one_first_idx
);
2274 *(p
++) = LOW(edge_minus_one_first_idx
);
2277 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2278 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge2
, wraps
);
2284 TA_Edge edge
= (TA_Edge
)arg1
;
2285 FT_UShort edge_first_idx
;
2288 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2291 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2293 if (edge
->best_blue_is_shoot
)
2295 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2296 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2300 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2301 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2304 *(p
++) = HIGH(edge_first_idx
);
2305 *(p
++) = LOW(edge_first_idx
);
2307 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2313 TA_Edge serif
= (TA_Edge
)arg1
;
2314 TA_Edge base
= serif
->serif
;
2315 FT_UShort serif_first_idx
;
2316 FT_UShort base_first_idx
;
2319 serif_first_idx
= TA_get_segment_index(serif
->first
, recorder
);
2320 base_first_idx
= TA_get_segment_index(base
->first
, recorder
);
2323 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2324 + (lower_bound
!= NULL
)
2325 + 2 * (upper_bound
!= NULL
)
2326 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2327 && top_to_bottom_hinting
); /* `down' */
2329 *(p
++) = HIGH(serif_first_idx
);
2330 *(p
++) = LOW(serif_first_idx
);
2331 *(p
++) = HIGH(base_first_idx
);
2332 *(p
++) = LOW(base_first_idx
);
2336 FT_UShort lower_bound_first_idx
;
2339 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2342 *(p
++) = HIGH(lower_bound_first_idx
);
2343 *(p
++) = LOW(lower_bound_first_idx
);
2347 FT_UShort upper_bound_first_idx
;
2350 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2353 *(p
++) = HIGH(upper_bound_first_idx
);
2354 *(p
++) = LOW(upper_bound_first_idx
);
2357 p
= TA_hints_recorder_handle_segments(p
, recorder
, serif
, wraps
);
2361 case ta_serif_anchor
:
2362 case ta_serif_link2
:
2364 TA_Edge edge
= (TA_Edge
)arg1
;
2365 FT_UShort edge_first_idx
;
2368 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2371 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2372 + (lower_bound
!= NULL
)
2373 + 2 * (upper_bound
!= NULL
)
2374 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2375 && top_to_bottom_hinting
); /* `down' */
2377 *(p
++) = HIGH(edge_first_idx
);
2378 *(p
++) = LOW(edge_first_idx
);
2382 FT_UShort lower_bound_first_idx
;
2385 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2388 *(p
++) = HIGH(lower_bound_first_idx
);
2389 *(p
++) = LOW(lower_bound_first_idx
);
2393 FT_UShort upper_bound_first_idx
;
2396 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2399 *(p
++) = HIGH(upper_bound_first_idx
);
2400 *(p
++) = LOW(upper_bound_first_idx
);
2403 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2407 case ta_serif_link1
:
2409 TA_Edge edge
= (TA_Edge
)arg1
;
2410 TA_Edge before
= arg2
;
2411 TA_Edge after
= arg3
;
2412 FT_UShort before_first_idx
;
2413 FT_UShort edge_first_idx
;
2414 FT_UShort after_first_idx
;
2417 before_first_idx
= TA_get_segment_index(before
->first
, recorder
);
2418 edge_first_idx
= TA_get_segment_index(edge
->first
, recorder
);
2419 after_first_idx
= TA_get_segment_index(after
->first
, recorder
);
2422 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2423 + (lower_bound
!= NULL
)
2424 + 2 * (upper_bound
!= NULL
)
2425 + 3 * ((lower_bound
!= NULL
|| upper_bound
!= NULL
)
2426 && top_to_bottom_hinting
); /* `down' */
2428 *(p
++) = HIGH(before_first_idx
);
2429 *(p
++) = LOW(before_first_idx
);
2430 *(p
++) = HIGH(edge_first_idx
);
2431 *(p
++) = LOW(edge_first_idx
);
2432 *(p
++) = HIGH(after_first_idx
);
2433 *(p
++) = LOW(after_first_idx
);
2437 FT_UShort lower_bound_first_idx
;
2440 lower_bound_first_idx
= TA_get_segment_index(lower_bound
->first
,
2443 *(p
++) = HIGH(lower_bound_first_idx
);
2444 *(p
++) = LOW(lower_bound_first_idx
);
2448 FT_UShort upper_bound_first_idx
;
2451 upper_bound_first_idx
= TA_get_segment_index(upper_bound
->first
,
2454 *(p
++) = HIGH(upper_bound_first_idx
);
2455 *(p
++) = LOW(upper_bound_first_idx
);
2458 p
= TA_hints_recorder_handle_segments(p
, recorder
, edge
, wraps
);
2463 /* there are more cases in the enumeration */
2464 /* which are handled with flags */
2468 recorder
->hints_record
.num_actions
++;
2469 recorder
->hints_record
.buf
= p
;
2474 TA_init_recorder(Recorder
* recorder
,
2478 TA_GlyphHints hints
)
2480 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2482 TA_Segment segments
= axis
->segments
;
2483 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2487 recorder
->sfnt
= sfnt
;
2488 recorder
->font
= font
;
2489 recorder
->glyph
= glyph
;
2491 LLRB_INIT(&recorder
->ip_before_points_head
);
2492 LLRB_INIT(&recorder
->ip_after_points_head
);
2493 LLRB_INIT(&recorder
->ip_on_points_head
);
2494 LLRB_INIT(&recorder
->ip_between_points_head
);
2496 recorder
->num_stack_elements
= 0;
2498 /* no need to clean up allocated arrays in case of error; */
2499 /* this is handled later by `TA_free_recorder' */
2501 /* we use segment_map[axis->num_segments] */
2502 /* as the total number of mapped segments, so allocate one more element */
2503 recorder
->segment_map
=
2504 (FT_UShort
*)malloc((size_t)(axis
->num_segments
+ 1) * sizeof (FT_UShort
));
2505 if (!recorder
->segment_map
)
2506 return FT_Err_Out_Of_Memory
;
2508 /* `segment_map' gets initialized later on, */
2509 /* after the first call of `ta_loader_load_glyph' */
2510 recorder
->segment_map_initialized
= 0;
2512 recorder
->num_wrap_around_segments
= 0;
2513 for (seg
= segments
; seg
< seg_limit
; seg
++)
2514 if (seg
->first
> seg
->last
)
2515 recorder
->num_wrap_around_segments
++;
2517 recorder
->wrap_around_segments
=
2518 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2519 * sizeof (FT_UShort
));
2520 if (!recorder
->wrap_around_segments
)
2521 return FT_Err_Out_Of_Memory
;
2523 /* `wrap_around_segments' gets initialized later on; */
2524 /* it needs function `TA_get_segment_index' which uses data */
2525 /* that hasn't been initialized yet either */
2526 recorder
->wrap_around_segments_initialized
= 0;
2533 TA_reset_recorder(Recorder
* recorder
,
2536 recorder
->hints_record
.buf
= bufp
;
2537 recorder
->hints_record
.num_actions
= 0;
2542 TA_rewind_recorder(Recorder
* recorder
,
2549 Node3
* between_node
;
2551 Node1
* next_before_node
;
2552 Node1
* next_after_node
;
2553 Node2
* next_on_node
;
2554 Node3
* next_between_node
;
2557 TA_reset_recorder(recorder
, bufp
);
2559 recorder
->hints_record
.size
= size
;
2561 /* deallocate our red-black trees */
2563 for (before_node
= LLRB_MIN(ip_before_points
,
2564 &recorder
->ip_before_points_head
);
2566 before_node
= next_before_node
)
2568 next_before_node
= LLRB_NEXT(ip_before_points
,
2569 &recorder
->ip_before_points_head
,
2571 LLRB_REMOVE(ip_before_points
,
2572 &recorder
->ip_before_points_head
,
2577 for (after_node
= LLRB_MIN(ip_after_points
,
2578 &recorder
->ip_after_points_head
);
2580 after_node
= next_after_node
)
2582 next_after_node
= LLRB_NEXT(ip_after_points
,
2583 &recorder
->ip_after_points_head
,
2585 LLRB_REMOVE(ip_after_points
,
2586 &recorder
->ip_after_points_head
,
2591 for (on_node
= LLRB_MIN(ip_on_points
,
2592 &recorder
->ip_on_points_head
);
2594 on_node
= next_on_node
)
2596 next_on_node
= LLRB_NEXT(ip_on_points
,
2597 &recorder
->ip_on_points_head
,
2599 LLRB_REMOVE(ip_on_points
,
2600 &recorder
->ip_on_points_head
,
2605 for (between_node
= LLRB_MIN(ip_between_points
,
2606 &recorder
->ip_between_points_head
);
2608 between_node
= next_between_node
)
2610 next_between_node
= LLRB_NEXT(ip_between_points
,
2611 &recorder
->ip_between_points_head
,
2613 LLRB_REMOVE(ip_between_points
,
2614 &recorder
->ip_between_points_head
,
2622 TA_free_recorder(Recorder
* recorder
)
2624 free(recorder
->segment_map
);
2625 free(recorder
->wrap_around_segments
);
2627 TA_rewind_recorder(recorder
, NULL
, 0);
2632 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2636 FT_Face face
= sfnt
->face
;
2644 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2645 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2646 /* `idx' is never negative */
2647 GLYPH
* glyph
= &data
->glyphs
[idx
];
2649 TA_FaceGlobals globals
= (TA_FaceGlobals
)sfnt
->face
->autohint
.data
;
2650 FT_UShort
* gstyles
= globals
->glyph_styles
;
2651 FT_Bool use_gstyle_data
= 1;
2653 TA_GlyphHints hints
;
2655 FT_UInt num_action_hints_records
= 0;
2656 FT_UInt num_point_hints_records
= 0;
2657 Hints_Record
* action_hints_records
= NULL
;
2658 Hints_Record
* point_hints_records
= NULL
;
2661 FT_UShort num_stack_elements
;
2662 FT_Bool optimize
= 0;
2664 FT_Int32 load_flags
;
2667 /* we store only three positions, but it simplifies the algorithm in */
2668 /* `TA_optimize_push' if we have one additional element */
2676 /* XXX: right now, we abuse this flag to control */
2677 /* the global behaviour of the auto-hinter */
2678 load_flags
= 1 << 29; /* vertical hinting only */
2679 if (!font
->adjust_subglyphs
)
2681 if (font
->hint_composites
)
2682 load_flags
|= FT_LOAD_NO_SCALE
;
2684 load_flags
|= FT_LOAD_NO_RECURSE
;
2687 /* computing the segments is resolution independent, */
2688 /* thus the pixel size in this call is arbitrary -- */
2689 /* however, we avoid unnecessary debugging output */
2690 /* if we use the lowest value of the hinting range */
2691 error
= FT_Set_Pixel_Sizes(face
,
2692 font
->hinting_range_min
,
2693 font
->hinting_range_min
);
2697 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2698 /* to modify `out' directions of points at the user's request */
2699 /* (which will eventually become single-point segments) */
2700 error
= TA_control_segment_dir_collect(font
, face
->face_index
, idx
);
2705 /* temporarily disable some debugging output */
2706 /* to avoid getting the information twice */
2707 _ta_debug_save
= _ta_debug
;
2711 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2712 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2715 _ta_debug
= _ta_debug_save
;
2721 /* do nothing if we have an empty glyph */
2722 if (!(font
->loader
->gloader
->current
.num_subglyphs
2723 || face
->glyph
->outline
.n_contours
))
2726 hints
= &font
->loader
->hints
;
2729 * We allocate a buffer which is certainly large enough
2730 * to hold all of the created bytecode instructions;
2731 * later on it gets reallocated to its real size.
2733 * The value `1000' is a very rough guess, not tested well.
2735 * For delta exceptions, we have three DELTA commands,
2736 * covering 3*16 ppem values.
2737 * Since a point index can be larger than 255,
2738 * we assume two bytes everywhere for the necessary PUSH calls.
2739 * This value must be doubled for the other arguments of DELTA.
2740 * Additionally, we have both x and y deltas,
2741 * which need to be handled separately in the bytecode.
2742 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2743 * adding some bytes for the necessary overhead.
2745 ins_len
= (FT_UInt
)(hints
->num_points
2747 + ((font
->control_data_head
!= NULL
) ? 400 : 0)));
2748 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2750 return FT_Err_Out_Of_Memory
;
2752 /* handle composite glyph */
2753 if (font
->loader
->gloader
->current
.num_subglyphs
)
2755 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2758 error
= FT_Err_Out_Of_Memory
;
2762 use_gstyle_data
= 0;
2768 if (font
->fallback_scaling
)
2770 TA_StyleClass style_class
= font
->loader
->metrics
->style_class
;
2773 if (style_class
== &ta_none_dflt_style_class
)
2775 /* the scaling value of `none_dflt' */
2776 /* (this is, hinting without script-specific blue zones) */
2777 /* is always 1, which corresponds to a no-op */
2780 use_gstyle_data
= 0;
2784 else if (style_class
== ta_style_classes
[font
->fallback_style
])
2786 /* since `TA_init_recorder' hasn't been called yet, */
2787 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2788 recorder
.sfnt
= sfnt
;
2789 recorder
.font
= font
;
2790 recorder
.glyph
= glyph
;
2792 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2795 error
= FT_Err_Out_Of_Memory
;
2799 use_gstyle_data
= 0;
2805 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2809 /* loop over a large range of pixel sizes */
2810 /* to find hints records which get pushed onto the bytecode stack */
2819 (void)FT_Get_Glyph_Name(face
, (FT_UInt
)idx
, buf
, 256);
2821 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2823 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2824 fprintf(stderr
, "\n");
2825 for (i
= 0; i
< num_chars
; i
++)
2827 fprintf(stderr
, "\n\n");
2832 /* we temporarily use `ins_buf' to record the current glyph hints */
2833 ta_loader_register_hints_recorder(font
->loader
,
2838 * It is important that we start the loop with the smallest PPEM value
2839 * used for hinting, since the number of segments that form an edge can
2840 * become smaller for larger PPEM values. For efficiency, we skip
2841 * non-edge one-point segments, and `TA_get_segment_index' would return
2842 * wrong indices otherwise.
2844 for (size
= font
->hinting_range_min
;
2845 size
<= font
->hinting_range_max
;
2853 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2855 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2865 num_chars
= fprintf(stderr
, "size %d\n", size
);
2866 for (i
= 0; i
< num_chars
- 1; i
++)
2868 fprintf(stderr
, "\n\n");
2872 /* calling `ta_loader_load_glyph' uses the */
2873 /* `TA_hints_recorder' function as a callback, */
2874 /* modifying `hints_record' */
2875 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2879 if (TA_hints_record_is_different(action_hints_records
,
2880 num_action_hints_records
,
2881 ins_buf
, recorder
.hints_record
.buf
))
2888 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2889 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2890 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2892 fprintf(stderr
, "action hints record:\n");
2893 if (ins_buf
== recorder
.hints_record
.buf
)
2894 fprintf(stderr
, " (none)");
2897 fprintf(stderr
, " ");
2898 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2899 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2901 fprintf(stderr
, "\n");
2905 error
= TA_add_hints_record(&action_hints_records
,
2906 &num_action_hints_records
,
2907 ins_buf
, recorder
.hints_record
);
2912 /* now handle point records */
2914 TA_reset_recorder(&recorder
, ins_buf
);
2916 /* use the point hints data collected in `TA_hints_recorder' */
2917 TA_build_point_hints(&recorder
, hints
);
2919 if (TA_hints_record_is_different(point_hints_records
,
2920 num_point_hints_records
,
2921 ins_buf
, recorder
.hints_record
.buf
))
2931 num_chars
= fprintf(stderr
, "size %d\n", size
);
2932 for (i
= 0; i
< num_chars
- 1; i
++)
2934 fprintf(stderr
, "\n\n");
2936 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2937 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2938 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2941 fprintf(stderr
, "point hints record:\n");
2942 if (ins_buf
== recorder
.hints_record
.buf
)
2943 fprintf(stderr
, " (none)");
2946 fprintf(stderr
, " ");
2947 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2948 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2950 fprintf(stderr
, "\n\n");
2954 error
= TA_add_hints_record(&point_hints_records
,
2955 &num_point_hints_records
,
2956 ins_buf
, recorder
.hints_record
);
2962 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2964 /* since we only have a single empty record we just scale the glyph */
2965 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2968 error
= FT_Err_Out_Of_Memory
;
2972 use_gstyle_data
= 0;
2977 /* if there is only a single record, */
2978 /* we do a global optimization later on */
2979 if (num_action_hints_records
> 1)
2982 /* store the hints records and handle stack depth */
2984 bufp
= TA_emit_hints_records(&recorder
,
2985 point_hints_records
,
2986 num_point_hints_records
,
2990 num_stack_elements
= recorder
.num_stack_elements
;
2991 recorder
.num_stack_elements
= 0;
2994 bufp
= TA_emit_hints_records(&recorder
,
2995 action_hints_records
,
2996 num_action_hints_records
,
3000 recorder
.num_stack_elements
+= num_stack_elements
;
3003 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
3006 error
= FT_Err_Out_Of_Memory
;
3010 if (num_action_hints_records
== 1)
3011 bufp
= TA_optimize_push(ins_buf
, pos
);
3014 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3015 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3016 TA_free_recorder(&recorder
);
3019 /* handle delta exceptions */
3020 if (font
->control_data_head
)
3022 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
3025 error
= FT_Err_Out_Of_Memory
;
3030 /* we need to insert a few extra bytecode instructions */
3031 /* for non-base glyphs */
3032 if (use_gstyle_data
&& (gstyles
[idx
] & TA_NONBASE
))
3034 FT_Byte
* ins_extra_buf_new
;
3035 FT_Byte ins_extra_len_new
;
3038 ins_extra_len_new
= glyph
->ins_extra_len
3039 + sizeof (ins_extra_ignore_std_width
);
3040 ins_extra_buf_new
= (FT_Byte
*)realloc(glyph
->ins_extra_buf
,
3042 if (!ins_extra_buf_new
)
3048 /* set `cvtl_ignore_std_width' to 100 at the beginning of the bytecode */
3049 /* by activating `ins_extra_ignore_std_width' */
3050 memcpy(ins_extra_buf_new
+ glyph
->ins_extra_len
,
3051 ins_extra_ignore_std_width
,
3052 sizeof (ins_extra_ignore_std_width
));
3054 glyph
->ins_extra_buf
= ins_extra_buf_new
;
3055 glyph
->ins_extra_len
= ins_extra_len_new
;
3057 /* reset `cvtl_ignore_std_width' for next glyph */
3059 BCI(cvtl_ignore_std_width
);
3064 ins_len
= (FT_UInt
)(bufp
- ins_buf
);
3066 if ((ins_len
+ glyph
->ins_extra_len
) > sfnt
->max_instructions
)
3067 sfnt
->max_instructions
= (FT_UShort
)(ins_len
+ glyph
->ins_extra_len
);
3069 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
3070 glyph
->ins_len
= ins_len
;
3075 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
3076 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
3077 TA_free_recorder(&recorder
);
3084 /* end of tabytecode.c */