4 * Copyright (C) 2011-2014 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
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
;
153 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
155 /* data necessary for strong point interpolation */
156 ip_before_points ip_before_points_head
;
157 ip_after_points ip_after_points_head
;
158 ip_on_points ip_on_points_head
;
159 ip_between_points ip_between_points_head
;
161 FT_UShort num_strong_points
;
162 FT_UShort num_segments
;
166 /* this is the bytecode of the `.ttfautohint' glyph */
168 FT_Byte ttfautohint_glyph_bytecode
[7] =
171 /* increment `cvtl_is_subglyph' counter */
183 /* if we have delta exceptions before IUP, this code gets inserted */
185 FT_Byte ins_extra_buf
[4] =
197 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
198 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
199 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
204 TA_build_push(FT_Byte
* bufp
,
216 for (i
= 0; i
< num_args
; i
+= 255)
218 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
220 if (optimize
&& nargs
<= 8)
221 BCI(PUSHW_1
- 1 + nargs
);
227 for (j
= 0; j
< nargs
; j
++)
237 for (i
= 0; i
< num_args
; i
+= 255)
239 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
241 if (optimize
&& nargs
<= 8)
242 BCI(PUSHB_1
- 1 + nargs
);
248 for (j
= 0; j
< nargs
; j
++)
261 * We optimize two common cases, replacing
263 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
267 * NPUSHB (A+B[+C]) ... CALL
273 TA_optimize_push(FT_Byte
* buf
,
288 /* XXX improve handling of NPUSHW */
289 if (*(pos
[0]) == NPUSHW
290 || *(pos
[1]) == NPUSHW
291 || *(pos
[2]) == NPUSHW
)
294 /* the point hints records block can be missing */
295 if (pos
[0] == pos
[1])
301 /* there are at least two NPUSHB instructions */
302 /* (one of them directly at the start) */
303 sizes
[0] = *(pos
[0] + 1);
304 sizes
[1] = *(pos
[1] + 1);
305 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
307 sum
= sizes
[0] + sizes
[1] + sizes
[2];
310 return buf
; /* nothing to do since we need three NPUSHB */
311 else if (!sizes
[2] && (sum
> 0xFF))
312 return buf
; /* nothing to do since we need two NPUSHB */
316 /* reduce three NPUSHB to two */
318 new_size2
= sum
- 0xFF;
322 /* reduce two or three NPUSHB to one */
333 BCI(PUSHB_1
- 1 + new_size1
);
339 for (i
= 0; i
< new_size1
; i
++)
341 if (p
== pos
[pos_idx
])
344 p
+= 2; /* skip old NPUSHB */
352 BCI(PUSHB_1
- 1 + new_size2
);
358 for (i
= 0; i
< new_size2
; i
++)
360 if (p
== pos
[pos_idx
])
375 /* We add a subglyph for each composite glyph. */
376 /* Since subglyphs must contain at least one point, */
377 /* we have to adjust all point indices accordingly. */
378 /* Using the `pointsums' array of the `GLYPH' structure */
379 /* it is straightforward to do that: */
380 /* Assuming that point with index x is in the interval */
381 /* pointsums[n] <= x < pointsums[n + 1], */
382 /* the new point index is x + n. */
385 TA_adjust_point_index(Recorder
* recorder
,
388 FONT
* font
= recorder
->font
;
389 GLYPH
* glyph
= recorder
->glyph
;
393 if (!glyph
->num_components
|| !font
->hint_composites
)
394 return idx
; /* not a composite glyph */
396 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
397 if (idx
< glyph
->pointsums
[i
])
404 /* we store the segments in the storage area; */
405 /* each segment record consists of the first and last point */
408 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
413 FONT
* font
= recorder
->font
;
414 TA_GlyphHints hints
= &font
->loader
->hints
;
415 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
416 TA_Point points
= hints
->points
;
417 TA_Segment segments
= axis
->segments
;
419 TA_Segment seg_limit
;
421 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
422 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
424 FT_UInt style_id
= data
->style_ids
425 [font
->loader
->metrics
->style_class
->style
];
427 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
432 FT_UShort num_segments
;
434 FT_Bool need_words
= 0;
438 FT_UShort num_packed_segments
;
439 FT_UShort num_storage
;
440 FT_UShort num_stack_elements
;
441 FT_UShort num_twilight_points
;
444 seg_limit
= segments
+ axis
->num_segments
;
445 num_segments
= axis
->num_segments
;
447 /* to pack the data in the bytecode more tightly, */
448 /* we store up to the first nine segments in nibbles if possible, */
449 /* using delta values */
451 num_packed_segments
= 0;
452 for (seg
= segments
; seg
< seg_limit
; seg
++)
454 FT_UInt first
= seg
->first
- points
;
455 FT_UInt last
= seg
->last
- points
;
458 first
= TA_adjust_point_index(recorder
, first
);
459 last
= TA_adjust_point_index(recorder
, last
);
461 if (first
- base
>= 16)
463 if (first
> last
|| last
- first
>= 16)
465 if (num_packed_segments
== 9)
467 num_packed_segments
++;
471 /* also handle wrap-around segments */
472 num_segments
+= recorder
->num_wrap_around_segments
;
474 /* wrap-around segments are pushed with four arguments; */
475 /* a segment stored in nibbles needs only one byte instead of two */
476 num_args
= num_packed_segments
477 + 2 * (num_segments
- num_packed_segments
)
478 + 2 * recorder
->num_wrap_around_segments
481 /* collect all arguments temporarily in an array (in reverse order) */
482 /* so that we can easily split into chunks of 255 args */
483 /* as needed by NPUSHB and NPUSHW, respectively */
484 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
488 arg
= args
+ num_args
- 1;
490 if (num_segments
> 0xFF)
493 /* the number of packed segments is indicated by the function number */
494 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
495 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
497 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
499 *(arg
--) = CVT_SCALING_VALUE_OFFSET(style_id
);
500 *(arg
--) = num_segments
;
503 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
505 FT_UInt first
= seg
->first
- points
;
506 FT_UInt last
= seg
->last
- points
;
511 first
= TA_adjust_point_index(recorder
, first
);
512 last
= TA_adjust_point_index(recorder
, last
);
514 low_nibble
= first
- base
;
515 high_nibble
= last
- first
;
517 *(arg
--) = 16 * high_nibble
+ low_nibble
;
522 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
524 FT_UInt first
= seg
->first
- points
;
525 FT_UInt last
= seg
->last
- points
;
528 *(arg
--) = TA_adjust_point_index(recorder
, first
);
529 *(arg
--) = TA_adjust_point_index(recorder
, last
);
531 /* we push the last and first contour point */
532 /* as a third and fourth argument in wrap-around segments */
535 for (n
= 0; n
< outline
.n_contours
; n
++)
537 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
542 *(arg
--) = TA_adjust_point_index(recorder
, end
);
547 *(arg
--) = TA_adjust_point_index(recorder
, 0);
549 *(arg
--) = TA_adjust_point_index(recorder
,
550 (FT_UInt
)outline
.contours
[n
- 1] + 1);
560 /* emit the second part of wrap-around segments as separate segments */
561 /* so that edges can easily link to them */
562 for (seg
= segments
; seg
< seg_limit
; seg
++)
564 FT_UInt first
= seg
->first
- points
;
565 FT_UInt last
= seg
->last
- points
;
570 for (n
= 0; n
< outline
.n_contours
; n
++)
572 if (first
<= (FT_UInt
)outline
.contours
[n
])
575 *(arg
--) = TA_adjust_point_index(recorder
, 0);
577 *(arg
--) = TA_adjust_point_index(recorder
,
578 (FT_UInt
)outline
.contours
[n
- 1] + 1);
583 *(arg
--) = TA_adjust_point_index(recorder
, last
);
587 /* with most fonts it is very rare */
588 /* that any of the pushed arguments is larger than 0xFF, */
589 /* thus we refrain from further optimizing this case */
590 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
594 num_storage
= sal_segment_offset
+ num_segments
* 2;
595 if (num_storage
> sfnt
->max_storage
)
596 sfnt
->max_storage
= num_storage
;
598 num_twilight_points
= num_segments
* 2;
599 if (num_twilight_points
> sfnt
->max_twilight_points
)
600 sfnt
->max_twilight_points
= num_twilight_points
;
602 /* both this function and `TA_emit_hints_record' */
603 /* push data onto the stack */
604 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
605 + recorder
->num_stack_elements
+ num_args
;
606 if (num_stack_elements
> sfnt
->max_stack_elements
)
607 sfnt
->max_stack_elements
= num_stack_elements
;
616 build_delta_exception(const Ctrl
* ctrl
,
617 FT_UInt
** delta_args
,
626 ppem
= ctrl
->ppem
- CONTROL_DELTA_PPEM_MIN
;
642 * the possible shift values in the instructions are indexed as follows:
653 * (note that there is no index for a zero shift).
656 if (ctrl
->x_shift
< 0)
657 x_shift
= ctrl
->x_shift
+ 8;
659 x_shift
= ctrl
->x_shift
+ 7;
661 if (ctrl
->y_shift
< 0)
662 y_shift
= ctrl
->y_shift
+ 8;
664 y_shift
= ctrl
->y_shift
+ 7;
666 /* add point index and exception specification to appropriate stack */
669 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
670 (ppem
<< 4) + x_shift
;
671 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
678 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
679 (ppem
<< 4) + y_shift
;
680 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
687 TA_sfnt_build_delta_exceptions(SFNT
* sfnt
,
692 FT_Face face
= font
->loader
->face
;
697 FT_UShort num_stack_elements
;
699 /* DELTAP[1-3] stacks for both x and y directions */
700 FT_UInt
* delta_after_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
701 int num_delta_after_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
702 FT_UInt
* args
= NULL
;
704 FT_Bool need_words
= 0;
705 FT_Bool need_word_counts
= 0;
706 FT_Bool allocated
= 0;
709 num_points
= font
->loader
->gloader
->base
.outline
.n_points
;
711 /* loop over all fitting control instructions */
714 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
721 if (!(ctrl
->type
== Control_Delta_before_IUP
722 || ctrl
->type
== Control_Delta_after_IUP
))
725 /* too large values of font and glyph indices in `ctrl' */
726 /* are handled by later calls of this function */
727 if (face
->face_index
< ctrl
->font_idx
728 || idx
< ctrl
->glyph_idx
)
733 for (i
= 0; i
< 6; i
++)
735 /* see the comment on allocating `ins_buf' in function */
736 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
737 /* we have to increase by 1 for the number of argument pairs */
738 delta_after_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 1)
740 if (!delta_after_IUP_args
[i
])
750 /* since we walk sequentially over all glyphs (with points), */
751 /* and the control instruction entries have the same order, */
752 /* we don't need to test for equality of font and glyph indices: */
753 /* at this very point in the code we certainly have a hit */
754 build_delta_exception(ctrl
,
755 delta_after_IUP_args
,
756 num_delta_after_IUP_args
);
758 if (ctrl
->point_idx
> 255)
761 TA_control_get_next(font
);
764 /* nothing to do if no control instructions */
768 /* add number of argument pairs to the stacks */
769 for (i
= 0; i
< 6; i
++)
771 if (num_delta_after_IUP_args
[i
])
773 int n
= num_delta_after_IUP_args
[i
] >> 1;
777 need_word_counts
= 1;
779 *(delta_after_IUP_args
[i
] + num_delta_after_IUP_args
[i
]) = n
;
780 num_delta_after_IUP_args
[i
]++;
784 /* merge delta stacks into a single one */
786 || (!need_words
&& !need_word_counts
))
788 FT_UInt num_args
= 0;
791 for (i
= 0; i
< 6; i
++)
794 FT_UInt num_args_new
;
797 if (!num_delta_after_IUP_args
[i
])
800 num_args_new
= num_args
+ num_delta_after_IUP_args
[i
];
801 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
808 memcpy(args_new
+ num_args
,
809 delta_after_IUP_args
[i
],
810 num_delta_after_IUP_args
[i
] * sizeof (FT_UInt
));
813 num_args
= num_args_new
;
816 num_stack_elements
= num_args
;
818 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
822 num_stack_elements
= 0;
824 /* stack elements are bytes, but counts need words */
825 for (i
= 0; i
< 6; i
++)
830 if (!num_delta_after_IUP_args
[i
])
833 num_delta_arg
= num_delta_after_IUP_args
[i
] - 1;
835 bufp
= TA_build_push(bufp
,
836 delta_after_IUP_args
[i
],
841 num_stack_elements
+= num_delta_arg
+ 1;
845 BCI(HIGH(num_delta_arg
));
846 BCI(LOW(num_delta_arg
));
850 /* emit the DELTA opcodes */
851 if (num_delta_after_IUP_args
[5])
853 if (num_delta_after_IUP_args
[4])
855 if (num_delta_after_IUP_args
[3])
858 if (num_delta_after_IUP_args
[2]
859 || num_delta_after_IUP_args
[1]
860 || num_delta_after_IUP_args
[0])
863 if (num_delta_after_IUP_args
[2])
865 if (num_delta_after_IUP_args
[1])
867 if (num_delta_after_IUP_args
[0])
871 for (i
= 0; i
< 6; i
++)
872 free(delta_after_IUP_args
[i
]);
875 if (num_stack_elements
> sfnt
->max_stack_elements
)
876 sfnt
->max_stack_elements
= num_stack_elements
;
882 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
886 FONT
* font
= recorder
->font
;
887 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
888 FT_Vector
* points
= glyph
->outline
.points
;
889 FT_Int num_contours
= glyph
->outline
.n_contours
;
895 FT_Bool need_words
= 0;
898 FT_UShort num_storage
;
899 FT_UShort num_stack_elements
;
902 num_args
= 2 * num_contours
+ 2;
904 /* collect all arguments temporarily in an array (in reverse order) */
905 /* so that we can easily split into chunks of 255 args */
906 /* as needed by NPUSHB and NPUSHW, respectively */
907 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
911 arg
= args
+ num_args
- 1;
916 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
917 *(arg
--) = bci_scale_composite_glyph
;
919 *(arg
--) = bci_scale_glyph
;
920 *(arg
--) = num_contours
;
925 for (p
= 0; p
< num_contours
; p
++)
931 end
= glyph
->outline
.contours
[p
];
933 for (q
= start
; q
<= end
; q
++)
935 if (points
[q
].y
< points
[min
].y
)
937 if (points
[q
].y
> points
[max
].y
)
943 *(arg
--) = TA_adjust_point_index(recorder
, max
);
944 *(arg
--) = TA_adjust_point_index(recorder
, min
);
948 *(arg
--) = TA_adjust_point_index(recorder
, min
);
949 *(arg
--) = TA_adjust_point_index(recorder
, max
);
958 /* with most fonts it is very rare */
959 /* that any of the pushed arguments is larger than 0xFF, */
960 /* thus we refrain from further optimizing this case */
961 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
965 num_storage
= sal_segment_offset
;
966 if (num_storage
> sfnt
->max_storage
)
967 sfnt
->max_storage
= num_storage
;
969 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
970 if (num_stack_elements
> sfnt
->max_stack_elements
)
971 sfnt
->max_stack_elements
= num_stack_elements
;
980 TA_font_build_subglyph_shifter(FONT
* font
,
983 FT_Face face
= font
->loader
->face
;
984 FT_GlyphSlot glyph
= face
->glyph
;
986 TA_GlyphLoader gloader
= font
->loader
->gloader
;
988 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
989 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
990 TA_SubGlyph subglyph
;
992 FT_Int curr_contour
= 0;
995 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
999 FT_UShort flags
= subglyph
->flags
;
1000 FT_Pos y_offset
= subglyph
->arg2
;
1002 FT_Int num_contours
;
1005 /* load subglyph to get the number of contours */
1006 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
1009 num_contours
= glyph
->outline
.n_contours
;
1011 /* nothing to do if there is a point-to-point alignment */
1012 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
1015 /* nothing to do if y offset is zero */
1019 /* nothing to do if there are no contours */
1023 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1024 /* ensures that composite subglyphs are represented as simple glyphs */
1026 if (num_contours
> 0xFF
1027 || curr_contour
> 0xFF)
1030 BCI(HIGH(curr_contour
));
1031 BCI(LOW(curr_contour
));
1032 BCI(HIGH(num_contours
));
1033 BCI(LOW(num_contours
));
1042 /* there are high chances that this value needs PUSHW, */
1043 /* thus we handle it separately */
1044 if (y_offset
> 0xFF || y_offset
< 0)
1047 BCI(HIGH(y_offset
));
1057 BCI(bci_shift_subglyph
);
1061 curr_contour
+= num_contours
;
1069 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1070 * data in four arrays (which are simple but waste a lot of memory). The
1071 * function below converts them into bytecode.
1073 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1074 * together with the edge they correspond to.
1076 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1077 * loop over the edge or edge pairs, respectively, and each edge or edge
1078 * pair contains an inner loop to emit the correponding points.
1082 TA_build_point_hints(Recorder
* recorder
,
1083 TA_GlyphHints hints
)
1085 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1086 TA_Segment segments
= axis
->segments
;
1087 TA_Edge edges
= axis
->edges
;
1089 FT_Byte
* p
= recorder
->hints_record
.buf
;
1094 FT_UShort prev_edge
;
1095 FT_UShort prev_before_edge
;
1096 FT_UShort prev_after_edge
;
1101 Node3
* between_node
;
1104 /* we store everything as 16bit numbers; */
1105 /* the function numbers (`ta_ip_before', etc.) */
1106 /* reflect the order in the TA_Action enumeration */
1108 /* ip_before_points */
1111 for (before_node
= LLRB_MIN(ip_before_points
,
1112 &recorder
->ip_before_points_head
);
1114 before_node
= LLRB_NEXT(ip_before_points
,
1115 &recorder
->ip_before_points_head
,
1127 recorder
->hints_record
.num_actions
++;
1132 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1133 *(p
++) = HIGH(edge
->first
- segments
);
1134 *(p
++) = LOW(edge
->first
- segments
);
1138 for (before_node
= LLRB_MIN(ip_before_points
,
1139 &recorder
->ip_before_points_head
);
1141 before_node
= LLRB_NEXT(ip_before_points
,
1142 &recorder
->ip_before_points_head
,
1148 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1149 *(p
++) = HIGH(point
);
1150 *(p
++) = LOW(point
);
1154 /* ip_after_points */
1157 for (after_node
= LLRB_MIN(ip_after_points
,
1158 &recorder
->ip_after_points_head
);
1160 after_node
= LLRB_NEXT(ip_after_points
,
1161 &recorder
->ip_after_points_head
,
1173 recorder
->hints_record
.num_actions
++;
1175 edge
= edges
+ axis
->num_edges
- 1;
1178 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1179 *(p
++) = HIGH(edge
->first
- segments
);
1180 *(p
++) = LOW(edge
->first
- segments
);
1184 for (after_node
= LLRB_MIN(ip_after_points
,
1185 &recorder
->ip_after_points_head
);
1187 after_node
= LLRB_NEXT(ip_after_points
,
1188 &recorder
->ip_after_points_head
,
1194 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1195 *(p
++) = HIGH(point
);
1196 *(p
++) = LOW(point
);
1200 /* ip_on_point_array */
1204 for (on_node
= LLRB_MIN(ip_on_points
,
1205 &recorder
->ip_on_points_head
);
1207 on_node
= LLRB_NEXT(ip_on_points
,
1208 &recorder
->ip_on_points_head
,
1212 if (on_node
->edge
!= prev_edge
)
1215 prev_edge
= on_node
->edge
;
1221 recorder
->hints_record
.num_actions
++;
1224 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1228 for (on_node
= LLRB_MIN(ip_on_points
,
1229 &recorder
->ip_on_points_head
);
1231 on_node
= LLRB_NEXT(ip_on_points
,
1232 &recorder
->ip_on_points_head
,
1239 edge
= edges
+ on_node
->edge
;
1241 *(p
++) = HIGH(edge
->first
- segments
);
1242 *(p
++) = LOW(edge
->first
- segments
);
1244 /* save current position */
1245 edge_node
= on_node
;
1249 on_node
= LLRB_NEXT(ip_on_points
,
1250 &recorder
->ip_on_points_head
,
1253 /* count points on current edge */
1254 if (on_node
->edge
!= edge_node
->edge
)
1262 /* restore current position */
1263 on_node
= edge_node
;
1266 on_node
= LLRB_NEXT(ip_on_points
,
1267 &recorder
->ip_on_points_head
,
1273 if (on_node
->edge
!= edge_node
->edge
)
1276 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1277 *(p
++) = HIGH(point
);
1278 *(p
++) = LOW(point
);
1280 /* keep track of previous node */
1281 edge_node
= on_node
;
1284 /* reset loop iterator by one element, then continue */
1285 on_node
= edge_node
;
1289 /* ip_between_point_array */
1291 prev_before_edge
= 0xFFFF;
1292 prev_after_edge
= 0xFFFF;
1294 for (between_node
= LLRB_MIN(ip_between_points
,
1295 &recorder
->ip_between_points_head
);
1297 between_node
= LLRB_NEXT(ip_between_points
,
1298 &recorder
->ip_between_points_head
,
1301 /* count `(before,after)' edge pairs */
1302 if (between_node
->before_edge
!= prev_before_edge
1303 || between_node
->after_edge
!= prev_after_edge
)
1306 prev_before_edge
= between_node
->before_edge
;
1307 prev_after_edge
= between_node
->after_edge
;
1313 recorder
->hints_record
.num_actions
++;
1316 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1320 for (between_node
= LLRB_MIN(ip_between_points
,
1321 &recorder
->ip_between_points_head
);
1323 between_node
= LLRB_NEXT(ip_between_points
,
1324 &recorder
->ip_between_points_head
,
1327 Node3
* edge_pair_node
;
1332 before
= edges
+ between_node
->before_edge
;
1333 after
= edges
+ between_node
->after_edge
;
1335 *(p
++) = HIGH(after
->first
- segments
);
1336 *(p
++) = LOW(after
->first
- segments
);
1337 *(p
++) = HIGH(before
->first
- segments
);
1338 *(p
++) = LOW(before
->first
- segments
);
1340 /* save current position */
1341 edge_pair_node
= between_node
;
1345 between_node
= LLRB_NEXT(ip_between_points
,
1346 &recorder
->ip_between_points_head
,
1349 /* count points associated with current edge pair */
1350 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1351 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1359 /* restore current position */
1360 between_node
= edge_pair_node
;
1363 between_node
= LLRB_NEXT(ip_between_points
,
1364 &recorder
->ip_between_points_head
,
1370 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1371 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1374 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1375 *(p
++) = HIGH(point
);
1376 *(p
++) = LOW(point
);
1378 /* keep track of previous node */
1379 edge_pair_node
= between_node
;
1382 /* reset loop iterator by one element, then continue */
1383 between_node
= edge_pair_node
;
1387 recorder
->hints_record
.buf
= p
;
1392 TA_hints_record_is_different(Hints_Record
* hints_records
,
1393 FT_UInt num_hints_records
,
1397 Hints_Record last_hints_record
;
1403 /* we only need to compare with the last hints record */
1404 last_hints_record
= hints_records
[num_hints_records
- 1];
1406 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1409 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1417 TA_add_hints_record(Hints_Record
** hints_records
,
1418 FT_UInt
* num_hints_records
,
1420 Hints_Record hints_record
)
1422 Hints_Record
* hints_records_new
;
1424 /* at this point, `hints_record.buf' still points into `ins_buf' */
1425 FT_Byte
* end
= hints_record
.buf
;
1428 buf_len
= (FT_UInt
)(end
- start
);
1430 /* now fill the structure completely */
1431 hints_record
.buf_len
= buf_len
;
1432 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1433 if (!hints_record
.buf
)
1434 return FT_Err_Out_Of_Memory
;
1436 memcpy(hints_record
.buf
, start
, buf_len
);
1438 (*num_hints_records
)++;
1440 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1441 * sizeof (Hints_Record
));
1442 if (!hints_records_new
)
1444 free(hints_record
.buf
);
1445 (*num_hints_records
)--;
1446 return FT_Err_Out_Of_Memory
;
1449 *hints_records
= hints_records_new
;
1451 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1458 TA_emit_hints_record(Recorder
* recorder
,
1459 Hints_Record
* hints_record
,
1465 FT_Bool need_words
= 0;
1468 FT_UInt num_arguments
;
1472 /* check whether any argument is larger than 0xFF */
1473 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1474 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1481 /* with most fonts it is very rare */
1482 /* that any of the pushed arguments is larger than 0xFF, */
1483 /* thus we refrain from further optimizing this case */
1485 num_arguments
= hints_record
->buf_len
/ 2;
1490 for (i
= 0; i
< num_arguments
; i
+= 255)
1492 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1494 if (optimize
&& num_args
<= 8)
1495 BCI(PUSHW_1
- 1 + num_args
);
1501 for (j
= 0; j
< num_args
; j
++)
1511 /* we only need the lower bytes */
1514 for (i
= 0; i
< num_arguments
; i
+= 255)
1516 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1518 if (optimize
&& num_args
<= 8)
1519 BCI(PUSHB_1
- 1 + num_args
);
1525 for (j
= 0; j
< num_args
; j
++)
1533 /* collect stack depth data */
1534 if (num_arguments
> recorder
->num_stack_elements
)
1535 recorder
->num_stack_elements
= num_arguments
;
1542 TA_emit_hints_records(Recorder
* recorder
,
1543 Hints_Record
* hints_records
,
1544 FT_UInt num_hints_records
,
1549 Hints_Record
* hints_record
;
1552 hints_record
= hints_records
;
1554 /* emit hints records in `if' clauses, */
1555 /* with the ppem size as the condition */
1556 for (i
= 0; i
< num_hints_records
- 1; i
++)
1559 if (hints_record
->size
> 0xFF)
1562 BCI(HIGH((hints_record
+ 1)->size
));
1563 BCI(LOW((hints_record
+ 1)->size
));
1568 BCI((hints_record
+ 1)->size
);
1572 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1578 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1580 for (i
= 0; i
< num_hints_records
- 1; i
++)
1588 TA_free_hints_records(Hints_Record
* hints_records
,
1589 FT_UInt num_hints_records
)
1594 for (i
= 0; i
< num_hints_records
; i
++)
1595 free(hints_records
[i
].buf
);
1597 free(hints_records
);
1602 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1607 TA_Segment segments
= axis
->segments
;
1610 FT_UShort num_segs
= 0;
1614 seg_idx
= edge
->first
- segments
;
1616 /* we store everything as 16bit numbers */
1617 *(bufp
++) = HIGH(seg_idx
);
1618 *(bufp
++) = LOW(seg_idx
);
1620 /* wrap-around segments are stored as two segments */
1621 if (edge
->first
->first
> edge
->first
->last
)
1624 seg
= edge
->first
->edge_next
;
1625 while (seg
!= edge
->first
)
1629 if (seg
->first
> seg
->last
)
1632 seg
= seg
->edge_next
;
1635 *(bufp
++) = HIGH(num_segs
);
1636 *(bufp
++) = LOW(num_segs
);
1638 if (edge
->first
->first
> edge
->first
->last
)
1640 /* emit second part of wrap-around segment; */
1641 /* the bytecode positions such segments after `normal' ones */
1645 if (seg_idx
== *wrap
)
1650 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1651 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1654 seg
= edge
->first
->edge_next
;
1655 while (seg
!= edge
->first
)
1657 seg_idx
= seg
- segments
;
1659 *(bufp
++) = HIGH(seg_idx
);
1660 *(bufp
++) = LOW(seg_idx
);
1662 if (seg
->first
> seg
->last
)
1667 if (seg_idx
== *wrap
)
1672 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1673 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1676 seg
= seg
->edge_next
;
1684 TA_hints_recorder(TA_Action action
,
1685 TA_GlyphHints hints
,
1690 TA_Edge lower_bound
,
1691 TA_Edge upper_bound
)
1693 TA_AxisHints axis
= &hints
->axis
[dim
];
1694 TA_Edge edges
= axis
->edges
;
1695 TA_Segment segments
= axis
->segments
;
1696 TA_Point points
= hints
->points
;
1698 Recorder
* recorder
= (Recorder
*)hints
->user
;
1699 SFNT
* sfnt
= recorder
->sfnt
;
1700 FONT
* font
= recorder
->font
;
1701 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1702 FT_Byte
* p
= recorder
->hints_record
.buf
;
1704 FT_UInt style
= font
->loader
->metrics
->style_class
->style
;
1707 if (dim
== TA_DIMENSION_HORZ
)
1710 /* we collect point hints for later processing */
1716 TA_Point point
= (TA_Point
)arg1
;
1719 before_node
= (Node1
*)malloc(sizeof (Node1
));
1722 before_node
->point
= point
- points
;
1724 LLRB_INSERT(ip_before_points
,
1725 &recorder
->ip_before_points_head
,
1733 TA_Point point
= (TA_Point
)arg1
;
1736 after_node
= (Node1
*)malloc(sizeof (Node1
));
1739 after_node
->point
= point
- points
;
1741 LLRB_INSERT(ip_after_points
,
1742 &recorder
->ip_after_points_head
,
1750 TA_Point point
= (TA_Point
)arg1
;
1751 TA_Edge edge
= arg2
;
1754 on_node
= (Node2
*)malloc(sizeof (Node2
));
1757 on_node
->edge
= edge
- edges
;
1758 on_node
->point
= point
- points
;
1760 LLRB_INSERT(ip_on_points
,
1761 &recorder
->ip_on_points_head
,
1768 Node3
* between_node
;
1769 TA_Point point
= (TA_Point
)arg1
;
1770 TA_Edge before
= arg2
;
1771 TA_Edge after
= arg3
;
1774 between_node
= (Node3
*)malloc(sizeof (Node3
));
1777 between_node
->before_edge
= before
- edges
;
1778 between_node
->after_edge
= after
- edges
;
1779 between_node
->point
= point
- points
;
1781 LLRB_INSERT(ip_between_points
,
1782 &recorder
->ip_between_points_head
,
1788 /* we ignore the BOUND action since we signal this information */
1789 /* with the proper function number */
1796 /* some enum values correspond to four or eight bytecode functions; */
1797 /* if the value is n, the function numbers are n, ..., n+7, */
1798 /* to be differentiated with flags */
1804 TA_Edge base_edge
= (TA_Edge
)arg1
;
1805 TA_Edge stem_edge
= arg2
;
1809 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1810 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1811 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1813 *(p
++) = HIGH(base_edge
->first
- segments
);
1814 *(p
++) = LOW(base_edge
->first
- segments
);
1815 *(p
++) = HIGH(stem_edge
->first
- segments
);
1816 *(p
++) = LOW(stem_edge
->first
- segments
);
1818 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1824 TA_Edge edge
= (TA_Edge
)arg1
;
1825 TA_Edge edge2
= arg2
;
1829 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1830 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1831 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1833 *(p
++) = HIGH(edge
->first
- segments
);
1834 *(p
++) = LOW(edge
->first
- segments
);
1835 *(p
++) = HIGH(edge2
->first
- segments
);
1836 *(p
++) = LOW(edge2
->first
- segments
);
1838 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1844 TA_Edge edge
= (TA_Edge
)arg1
;
1845 TA_Edge edge2
= arg2
;
1846 TA_Edge edge_minus_one
= lower_bound
;
1850 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1851 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1852 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1853 + 4 * (edge_minus_one
!= NULL
);
1855 *(p
++) = HIGH(edge
->first
- segments
);
1856 *(p
++) = LOW(edge
->first
- segments
);
1857 *(p
++) = HIGH(edge2
->first
- segments
);
1858 *(p
++) = LOW(edge2
->first
- segments
);
1862 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1863 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1866 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1870 case ta_blue_anchor
:
1872 TA_Edge edge
= (TA_Edge
)arg1
;
1873 TA_Edge blue
= arg2
;
1877 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1879 *(p
++) = HIGH(blue
->first
- segments
);
1880 *(p
++) = LOW(blue
->first
- segments
);
1882 if (edge
->best_blue_is_shoot
)
1884 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1885 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1889 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1890 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1893 *(p
++) = HIGH(edge
->first
- segments
);
1894 *(p
++) = LOW(edge
->first
- segments
);
1896 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1902 TA_Edge edge
= (TA_Edge
)arg1
;
1903 TA_Edge edge2
= arg2
;
1904 TA_Edge edge_minus_one
= lower_bound
;
1908 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1909 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1910 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1911 + 4 * (edge_minus_one
!= NULL
);
1913 *(p
++) = HIGH(edge
->first
- segments
);
1914 *(p
++) = LOW(edge
->first
- segments
);
1915 *(p
++) = HIGH(edge2
->first
- segments
);
1916 *(p
++) = LOW(edge2
->first
- segments
);
1920 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1921 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1924 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1925 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1931 TA_Edge edge
= (TA_Edge
)arg1
;
1935 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1937 if (edge
->best_blue_is_shoot
)
1939 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1940 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1944 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1945 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1948 *(p
++) = HIGH(edge
->first
- segments
);
1949 *(p
++) = LOW(edge
->first
- segments
);
1951 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1957 TA_Edge serif
= (TA_Edge
)arg1
;
1958 TA_Edge base
= serif
->serif
;
1962 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1963 + (lower_bound
!= NULL
)
1964 + 2 * (upper_bound
!= NULL
);
1966 *(p
++) = HIGH(serif
->first
- segments
);
1967 *(p
++) = LOW(serif
->first
- segments
);
1968 *(p
++) = HIGH(base
->first
- segments
);
1969 *(p
++) = LOW(base
->first
- segments
);
1973 *(p
++) = HIGH(lower_bound
->first
- segments
);
1974 *(p
++) = LOW(lower_bound
->first
- segments
);
1978 *(p
++) = HIGH(upper_bound
->first
- segments
);
1979 *(p
++) = LOW(upper_bound
->first
- segments
);
1982 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1986 case ta_serif_anchor
:
1987 case ta_serif_link2
:
1989 TA_Edge edge
= (TA_Edge
)arg1
;
1993 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1994 + (lower_bound
!= NULL
)
1995 + 2 * (upper_bound
!= NULL
);
1997 *(p
++) = HIGH(edge
->first
- segments
);
1998 *(p
++) = LOW(edge
->first
- segments
);
2002 *(p
++) = HIGH(lower_bound
->first
- segments
);
2003 *(p
++) = LOW(lower_bound
->first
- segments
);
2007 *(p
++) = HIGH(upper_bound
->first
- segments
);
2008 *(p
++) = LOW(upper_bound
->first
- segments
);
2011 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2015 case ta_serif_link1
:
2017 TA_Edge edge
= (TA_Edge
)arg1
;
2018 TA_Edge before
= arg2
;
2019 TA_Edge after
= arg3
;
2023 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2024 + (lower_bound
!= NULL
)
2025 + 2 * (upper_bound
!= NULL
);
2027 *(p
++) = HIGH(before
->first
- segments
);
2028 *(p
++) = LOW(before
->first
- segments
);
2029 *(p
++) = HIGH(edge
->first
- segments
);
2030 *(p
++) = LOW(edge
->first
- segments
);
2031 *(p
++) = HIGH(after
->first
- segments
);
2032 *(p
++) = LOW(after
->first
- segments
);
2036 *(p
++) = HIGH(lower_bound
->first
- segments
);
2037 *(p
++) = LOW(lower_bound
->first
- segments
);
2041 *(p
++) = HIGH(upper_bound
->first
- segments
);
2042 *(p
++) = LOW(upper_bound
->first
- segments
);
2045 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2050 /* there are more cases in the enumeration */
2051 /* which are handled with flags */
2055 recorder
->hints_record
.num_actions
++;
2056 recorder
->hints_record
.buf
= p
;
2061 TA_init_recorder(Recorder
* recorder
,
2065 TA_GlyphHints hints
)
2067 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2068 TA_Point points
= hints
->points
;
2069 TA_Point point_limit
= points
+ hints
->num_points
;
2072 TA_Segment segments
= axis
->segments
;
2073 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2076 FT_UShort num_strong_points
= 0;
2077 FT_UShort
* wrap_around_segment
;
2079 recorder
->sfnt
= sfnt
;
2080 recorder
->font
= font
;
2081 recorder
->glyph
= glyph
;
2082 recorder
->num_segments
= axis
->num_segments
;
2084 LLRB_INIT(&recorder
->ip_before_points_head
);
2085 LLRB_INIT(&recorder
->ip_after_points_head
);
2086 LLRB_INIT(&recorder
->ip_on_points_head
);
2087 LLRB_INIT(&recorder
->ip_between_points_head
);
2089 recorder
->num_stack_elements
= 0;
2091 /* no need to clean up allocated arrays in case of error; */
2092 /* this is handled later by `TA_free_recorder' */
2094 recorder
->num_wrap_around_segments
= 0;
2095 for (seg
= segments
; seg
< seg_limit
; seg
++)
2096 if (seg
->first
> seg
->last
)
2097 recorder
->num_wrap_around_segments
++;
2099 recorder
->wrap_around_segments
=
2100 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2101 * sizeof (FT_UShort
));
2102 if (!recorder
->wrap_around_segments
)
2103 return FT_Err_Out_Of_Memory
;
2105 wrap_around_segment
= recorder
->wrap_around_segments
;
2106 for (seg
= segments
; seg
< seg_limit
; seg
++)
2107 if (seg
->first
> seg
->last
)
2108 *(wrap_around_segment
++) = seg
- segments
;
2110 /* get number of strong points */
2111 for (point
= points
; point
< point_limit
; point
++)
2113 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2114 /* however, this value isn't known yet */
2115 /* (or rather, it can vary between different pixel sizes) */
2116 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
2119 num_strong_points
++;
2122 recorder
->num_strong_points
= num_strong_points
;
2129 TA_reset_recorder(Recorder
* recorder
,
2132 recorder
->hints_record
.buf
= bufp
;
2133 recorder
->hints_record
.num_actions
= 0;
2138 TA_rewind_recorder(Recorder
* recorder
,
2145 Node3
* between_node
;
2147 Node1
* next_before_node
;
2148 Node1
* next_after_node
;
2149 Node2
* next_on_node
;
2150 Node3
* next_between_node
;
2153 TA_reset_recorder(recorder
, bufp
);
2155 recorder
->hints_record
.size
= size
;
2157 /* deallocate our red-black trees */
2159 for (before_node
= LLRB_MIN(ip_before_points
,
2160 &recorder
->ip_before_points_head
);
2162 before_node
= next_before_node
)
2164 next_before_node
= LLRB_NEXT(ip_before_points
,
2165 &recorder
->ip_before_points_head
,
2167 LLRB_REMOVE(ip_before_points
,
2168 &recorder
->ip_before_points_head
,
2173 for (after_node
= LLRB_MIN(ip_after_points
,
2174 &recorder
->ip_after_points_head
);
2176 after_node
= next_after_node
)
2178 next_after_node
= LLRB_NEXT(ip_after_points
,
2179 &recorder
->ip_after_points_head
,
2181 LLRB_REMOVE(ip_after_points
,
2182 &recorder
->ip_after_points_head
,
2187 for (on_node
= LLRB_MIN(ip_on_points
,
2188 &recorder
->ip_on_points_head
);
2190 on_node
= next_on_node
)
2192 next_on_node
= LLRB_NEXT(ip_on_points
,
2193 &recorder
->ip_on_points_head
,
2195 LLRB_REMOVE(ip_on_points
,
2196 &recorder
->ip_on_points_head
,
2201 for (between_node
= LLRB_MIN(ip_between_points
,
2202 &recorder
->ip_between_points_head
);
2204 between_node
= next_between_node
)
2206 next_between_node
= LLRB_NEXT(ip_between_points
,
2207 &recorder
->ip_between_points_head
,
2209 LLRB_REMOVE(ip_between_points
,
2210 &recorder
->ip_between_points_head
,
2218 TA_free_recorder(Recorder
* recorder
)
2220 free(recorder
->wrap_around_segments
);
2222 TA_rewind_recorder(recorder
, NULL
, 0);
2227 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2231 FT_Face face
= sfnt
->face
;
2239 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2240 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2241 /* `idx' is never negative */
2242 GLYPH
* glyph
= &data
->glyphs
[idx
];
2244 TA_GlyphHints hints
;
2246 FT_UInt num_action_hints_records
= 0;
2247 FT_UInt num_point_hints_records
= 0;
2248 Hints_Record
* action_hints_records
= NULL
;
2249 Hints_Record
* point_hints_records
= NULL
;
2252 FT_UShort num_stack_elements
;
2253 FT_Bool optimize
= 0;
2255 FT_Int32 load_flags
;
2265 /* XXX: right now, we abuse this flag to control */
2266 /* the global behaviour of the auto-hinter */
2267 load_flags
= 1 << 29; /* vertical hinting only */
2268 if (!font
->adjust_subglyphs
)
2270 if (font
->hint_composites
)
2271 load_flags
|= FT_LOAD_NO_SCALE
;
2273 load_flags
|= FT_LOAD_NO_RECURSE
;
2276 /* computing the segments is resolution independent, */
2277 /* thus the pixel size in this call is arbitrary -- */
2278 /* however, we avoid unnecessary debugging output */
2279 /* if we use the lowest value of the hinting range */
2280 error
= FT_Set_Pixel_Sizes(face
,
2281 font
->hinting_range_min
,
2282 font
->hinting_range_min
);
2286 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2287 /* to modify `out' directions of points at the user's request */
2288 /* (which will eventually become single-point segments) */
2289 error
= TA_control_segment_dir_collect(font
, face
->face_index
, idx
);
2294 /* temporarily disable some debugging output */
2295 /* to avoid getting the information twice */
2296 _ta_debug_save
= _ta_debug
;
2300 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2301 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2304 _ta_debug
= _ta_debug_save
;
2310 /* do nothing if we have an empty glyph */
2311 if (!face
->glyph
->outline
.n_contours
)
2314 hints
= &font
->loader
->hints
;
2316 /* do nothing if the setup delivered the `none_dflt' style only */
2317 if (!hints
->num_points
)
2321 * We allocate a buffer which is certainly large enough
2322 * to hold all of the created bytecode instructions;
2323 * later on it gets reallocated to its real size.
2325 * The value `1000' is a very rough guess, not tested well.
2327 * For delta exceptions, we have three DELTA commands,
2328 * covering 3*16 ppem values.
2329 * Since a point index can be larger than 255,
2330 * we assume two bytes everywhere for the necessary PUSH calls.
2331 * This value must be doubled for the other arguments of DELTA.
2332 * Additionally, we have both x and y deltas,
2333 * which need to be handled separately in the bytecode.
2334 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2335 * adding some bytes for the necessary overhead.
2337 ins_len
= hints
->num_points
2338 * (1000 + ((font
->control_data_head
!= NULL
) ? 400 : 0));
2339 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2341 return FT_Err_Out_Of_Memory
;
2343 /* handle composite glyph */
2344 if (font
->loader
->gloader
->base
.num_subglyphs
)
2346 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2349 error
= FT_Err_Out_Of_Memory
;
2356 /* only scale the glyph if the `none_dflt' style has been used */
2357 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
2359 /* since `TA_init_recorder' hasn't been called yet, */
2360 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2361 recorder
.sfnt
= sfnt
;
2362 recorder
.font
= font
;
2363 recorder
.glyph
= glyph
;
2365 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2368 error
= FT_Err_Out_Of_Memory
;
2375 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2379 /* loop over a large range of pixel sizes */
2380 /* to find hints records which get pushed onto the bytecode stack */
2389 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
2391 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2393 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2394 fprintf(stderr
, "\n");
2395 for (i
= 0; i
< num_chars
; i
++)
2397 fprintf(stderr
, "\n\n");
2402 /* we temporarily use `ins_buf' to record the current glyph hints */
2403 ta_loader_register_hints_recorder(font
->loader
,
2407 for (size
= font
->hinting_range_min
;
2408 size
<= font
->hinting_range_max
;
2416 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2418 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2428 num_chars
= fprintf(stderr
, "size %d\n", size
);
2429 for (i
= 0; i
< num_chars
- 1; i
++)
2431 fprintf(stderr
, "\n\n");
2435 /* calling `ta_loader_load_glyph' uses the */
2436 /* `TA_hints_recorder' function as a callback, */
2437 /* modifying `hints_record' */
2438 error
= ta_loader_load_glyph(font
, face
, idx
, load_flags
);
2442 if (TA_hints_record_is_different(action_hints_records
,
2443 num_action_hints_records
,
2444 ins_buf
, recorder
.hints_record
.buf
))
2451 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2452 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2453 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2455 fprintf(stderr
, "action hints record:\n");
2456 if (ins_buf
== recorder
.hints_record
.buf
)
2457 fprintf(stderr
, " (none)");
2460 fprintf(stderr
, " ");
2461 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2462 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2464 fprintf(stderr
, "\n");
2468 error
= TA_add_hints_record(&action_hints_records
,
2469 &num_action_hints_records
,
2470 ins_buf
, recorder
.hints_record
);
2475 /* now handle point records */
2477 TA_reset_recorder(&recorder
, ins_buf
);
2479 /* use the point hints data collected in `TA_hints_recorder' */
2480 TA_build_point_hints(&recorder
, hints
);
2482 if (TA_hints_record_is_different(point_hints_records
,
2483 num_point_hints_records
,
2484 ins_buf
, recorder
.hints_record
.buf
))
2494 num_chars
= fprintf(stderr
, "size %d\n", size
);
2495 for (i
= 0; i
< num_chars
- 1; i
++)
2497 fprintf(stderr
, "\n\n");
2499 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2500 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2501 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2504 fprintf(stderr
, "point hints record:\n");
2505 if (ins_buf
== recorder
.hints_record
.buf
)
2506 fprintf(stderr
, " (none)");
2509 fprintf(stderr
, " ");
2510 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2511 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2513 fprintf(stderr
, "\n\n");
2517 error
= TA_add_hints_record(&point_hints_records
,
2518 &num_point_hints_records
,
2519 ins_buf
, recorder
.hints_record
);
2525 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2527 /* since we only have a single empty record we just scale the glyph */
2528 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2531 error
= FT_Err_Out_Of_Memory
;
2538 /* if there is only a single record, */
2539 /* we do a global optimization later on */
2540 if (num_action_hints_records
> 1)
2543 /* store the hints records and handle stack depth */
2545 bufp
= TA_emit_hints_records(&recorder
,
2546 point_hints_records
,
2547 num_point_hints_records
,
2551 num_stack_elements
= recorder
.num_stack_elements
;
2552 recorder
.num_stack_elements
= 0;
2555 bufp
= TA_emit_hints_records(&recorder
,
2556 action_hints_records
,
2557 num_action_hints_records
,
2561 recorder
.num_stack_elements
+= num_stack_elements
;
2564 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
2567 error
= FT_Err_Out_Of_Memory
;
2571 if (num_action_hints_records
== 1)
2572 bufp
= TA_optimize_push(ins_buf
, pos
);
2575 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2576 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2577 TA_free_recorder(&recorder
);
2580 /* handle delta exceptions */
2581 if (font
->control_data_head
)
2583 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
2586 error
= FT_Err_Out_Of_Memory
;
2591 ins_len
= bufp
- ins_buf
;
2593 if (ins_len
> sfnt
->max_instructions
)
2594 sfnt
->max_instructions
= ins_len
;
2596 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2597 glyph
->ins_len
= ins_len
;
2602 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2603 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2604 TA_free_recorder(&recorder
);
2611 /* end of tabytecode.c */