4 * Copyright (C) 2011-2015 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 y delta exceptions before IUP_y, this code gets inserted */
185 FT_Byte ins_extra_buf
[4] =
188 /* tell bci_{scale,scale_composite,hint}_glyph to not call IUP_y */
198 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
199 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
200 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
205 TA_build_push(FT_Byte
* bufp
,
217 for (i
= 0; i
< num_args
; i
+= 255)
219 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
221 if (optimize
&& nargs
<= 8)
222 BCI(PUSHW_1
- 1 + nargs
);
228 for (j
= 0; j
< nargs
; j
++)
238 for (i
= 0; i
< num_args
; i
+= 255)
240 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
242 if (optimize
&& nargs
<= 8)
243 BCI(PUSHB_1
- 1 + nargs
);
249 for (j
= 0; j
< nargs
; j
++)
262 * We optimize two common cases, replacing
264 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
268 * NPUSHB (A+B[+C]) ... CALL
274 TA_optimize_push(FT_Byte
* buf
,
289 /* XXX improve handling of NPUSHW */
290 if (*(pos
[0]) == NPUSHW
291 || *(pos
[1]) == NPUSHW
292 || *(pos
[2]) == NPUSHW
)
295 /* the point hints records block can be missing */
296 if (pos
[0] == pos
[1])
302 /* there are at least two NPUSHB instructions */
303 /* (one of them directly at the start) */
304 sizes
[0] = *(pos
[0] + 1);
305 sizes
[1] = *(pos
[1] + 1);
306 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
308 sum
= sizes
[0] + sizes
[1] + sizes
[2];
311 return buf
; /* nothing to do since we need three NPUSHB */
312 else if (!sizes
[2] && (sum
> 0xFF))
313 return buf
; /* nothing to do since we need two NPUSHB */
317 /* reduce three NPUSHB to two */
319 new_size2
= sum
- 0xFF;
323 /* reduce two or three NPUSHB to one */
334 BCI(PUSHB_1
- 1 + new_size1
);
340 for (i
= 0; i
< new_size1
; i
++)
342 if (p
== pos
[pos_idx
])
345 p
+= 2; /* skip old NPUSHB */
353 BCI(PUSHB_1
- 1 + new_size2
);
359 for (i
= 0; i
< new_size2
; i
++)
361 if (p
== pos
[pos_idx
])
376 /* We add a subglyph for each composite glyph. */
377 /* Since subglyphs must contain at least one point, */
378 /* we have to adjust all point indices accordingly. */
379 /* Using the `pointsums' array of the `GLYPH' structure */
380 /* it is straightforward to do that: */
381 /* Assuming that point with index x is in the interval */
382 /* pointsums[n] <= x < pointsums[n + 1], */
383 /* the new point index is x + n. */
386 TA_adjust_point_index(Recorder
* recorder
,
389 FONT
* font
= recorder
->font
;
390 GLYPH
* glyph
= recorder
->glyph
;
394 if (!glyph
->num_components
|| !font
->hint_composites
)
395 return idx
; /* not a composite glyph */
397 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
398 if (idx
< glyph
->pointsums
[i
])
405 /* we store the segments in the storage area; */
406 /* each segment record consists of the first and last point */
409 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
414 FONT
* font
= recorder
->font
;
415 TA_GlyphHints hints
= &font
->loader
->hints
;
416 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
417 TA_Point points
= hints
->points
;
418 TA_Segment segments
= axis
->segments
;
420 TA_Segment seg_limit
;
422 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
423 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
425 FT_UInt style_id
= data
->style_ids
426 [font
->loader
->metrics
->style_class
->style
];
428 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
433 FT_UShort num_segments
;
435 FT_Bool need_words
= 0;
439 FT_UShort num_packed_segments
;
440 FT_UShort num_storage
;
441 FT_UShort num_stack_elements
;
442 FT_UShort num_twilight_points
;
445 seg_limit
= segments
+ axis
->num_segments
;
446 num_segments
= axis
->num_segments
;
448 /* to pack the data in the bytecode more tightly, */
449 /* we store up to the first nine segments in nibbles if possible, */
450 /* using delta values */
452 num_packed_segments
= 0;
453 for (seg
= segments
; seg
< seg_limit
; seg
++)
455 FT_UInt first
= seg
->first
- points
;
456 FT_UInt last
= seg
->last
- points
;
459 first
= TA_adjust_point_index(recorder
, first
);
460 last
= TA_adjust_point_index(recorder
, last
);
462 if (first
- base
>= 16)
464 if (first
> last
|| last
- first
>= 16)
466 if (num_packed_segments
== 9)
468 num_packed_segments
++;
472 /* also handle wrap-around segments */
473 num_segments
+= recorder
->num_wrap_around_segments
;
475 /* wrap-around segments are pushed with four arguments; */
476 /* a segment stored in nibbles needs only one byte instead of two */
477 num_args
= num_packed_segments
478 + 2 * (num_segments
- num_packed_segments
)
479 + 2 * recorder
->num_wrap_around_segments
482 /* collect all arguments temporarily in an array (in reverse order) */
483 /* so that we can easily split into chunks of 255 args */
484 /* as needed by NPUSHB and NPUSHW, respectively */
485 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
489 arg
= args
+ num_args
- 1;
491 if (num_segments
> 0xFF)
494 /* the number of packed segments is indicated by the function number */
495 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
496 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
498 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
500 *(arg
--) = CVT_SCALING_VALUE_OFFSET(style_id
);
501 *(arg
--) = num_segments
;
504 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
506 FT_UInt first
= seg
->first
- points
;
507 FT_UInt last
= seg
->last
- points
;
512 first
= TA_adjust_point_index(recorder
, first
);
513 last
= TA_adjust_point_index(recorder
, last
);
515 low_nibble
= first
- base
;
516 high_nibble
= last
- first
;
518 *(arg
--) = 16 * high_nibble
+ low_nibble
;
523 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
525 FT_UInt first
= seg
->first
- points
;
526 FT_UInt last
= seg
->last
- points
;
529 *(arg
--) = TA_adjust_point_index(recorder
, first
);
530 *(arg
--) = TA_adjust_point_index(recorder
, last
);
532 /* we push the last and first contour point */
533 /* as a third and fourth argument in wrap-around segments */
536 for (n
= 0; n
< outline
.n_contours
; n
++)
538 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
543 *(arg
--) = TA_adjust_point_index(recorder
, end
);
548 *(arg
--) = TA_adjust_point_index(recorder
, 0);
550 *(arg
--) = TA_adjust_point_index(recorder
,
551 (FT_UInt
)outline
.contours
[n
- 1] + 1);
561 /* emit the second part of wrap-around segments as separate segments */
562 /* so that edges can easily link to them */
563 for (seg
= segments
; seg
< seg_limit
; seg
++)
565 FT_UInt first
= seg
->first
- points
;
566 FT_UInt last
= seg
->last
- points
;
571 for (n
= 0; n
< outline
.n_contours
; n
++)
573 if (first
<= (FT_UInt
)outline
.contours
[n
])
576 *(arg
--) = TA_adjust_point_index(recorder
, 0);
578 *(arg
--) = TA_adjust_point_index(recorder
,
579 (FT_UInt
)outline
.contours
[n
- 1] + 1);
584 *(arg
--) = TA_adjust_point_index(recorder
, last
);
588 /* with most fonts it is very rare */
589 /* that any of the pushed arguments is larger than 0xFF, */
590 /* thus we refrain from further optimizing this case */
591 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
595 num_storage
= sal_segment_offset
+ num_segments
* 2;
596 if (num_storage
> sfnt
->max_storage
)
597 sfnt
->max_storage
= num_storage
;
599 num_twilight_points
= num_segments
* 2;
600 if (num_twilight_points
> sfnt
->max_twilight_points
)
601 sfnt
->max_twilight_points
= num_twilight_points
;
603 /* both this function and `TA_emit_hints_record' */
604 /* push data onto the stack */
605 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
606 + recorder
->num_stack_elements
+ num_args
;
607 if (num_stack_elements
> sfnt
->max_stack_elements
)
608 sfnt
->max_stack_elements
= num_stack_elements
;
617 build_delta_exception(const Ctrl
* ctrl
,
618 FT_UInt
** delta_args
,
627 ppem
= ctrl
->ppem
- CONTROL_DELTA_PPEM_MIN
;
643 * the possible shift values in the instructions are indexed as follows:
654 * (note that there is no index for a zero shift).
657 if (ctrl
->x_shift
< 0)
658 x_shift
= ctrl
->x_shift
+ 8;
660 x_shift
= ctrl
->x_shift
+ 7;
662 if (ctrl
->y_shift
< 0)
663 y_shift
= ctrl
->y_shift
+ 8;
665 y_shift
= ctrl
->y_shift
+ 7;
667 /* add point index and exception specification to appropriate stack */
670 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
671 (ppem
<< 4) + x_shift
;
672 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
679 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
680 (ppem
<< 4) + y_shift
;
681 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
688 TA_sfnt_build_delta_exceptions(SFNT
* sfnt
,
693 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
694 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
695 GLYPH
* glyph
= &data
->glyphs
[idx
];
697 FT_Face face
= font
->loader
->face
;
702 FT_UShort num_before_IUP_stack_elements
;
703 FT_UShort num_after_IUP_stack_elements
;
705 /* DELTAP[1-3] stacks for both x and y directions */
706 FT_UInt
* delta_before_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
707 FT_UInt
* delta_after_IUP_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
708 int num_delta_before_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
709 int num_delta_after_IUP_args
[6] = {0, 0, 0, 0, 0, 0};
710 FT_UInt
* args
= NULL
;
712 FT_Bool need_before_IUP_words
= 0;
713 FT_Bool need_after_IUP_words
= 0;
714 FT_Bool need_before_IUP_word_counts
= 0;
715 FT_Bool need_after_IUP_word_counts
= 0;
716 FT_Bool allocated_before_IUP
= 0;
717 FT_Bool allocated_after_IUP
= 0;
720 num_points
= font
->loader
->gloader
->base
.outline
.n_points
;
722 /* loop over all fitting control instructions */
725 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
732 if (!(ctrl
->type
== Control_Delta_before_IUP
733 || ctrl
->type
== Control_Delta_after_IUP
))
736 /* too large values of font and glyph indices in `ctrl' */
737 /* are handled by later calls of this function */
738 if (face
->face_index
< ctrl
->font_idx
739 || idx
< ctrl
->glyph_idx
)
742 if (ctrl
->type
== Control_Delta_before_IUP
743 && !allocated_before_IUP
)
745 for (i
= 0; i
< 6; i
++)
747 /* see the comment on allocating `ins_buf' in function */
748 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
749 /* we have to increase by 2 to push the number of argument pairs */
750 /* and the function for a LOOPCALL instruction */
751 delta_before_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 2)
753 if (!delta_before_IUP_args
[i
])
760 allocated_before_IUP
= 1;
763 if (ctrl
->type
== Control_Delta_after_IUP
764 && !allocated_after_IUP
)
766 for (i
= 0; i
< 6; i
++)
768 /* we have to increase by 1 for the number of argument pairs */
769 /* as needed by the DELTA instructions */
770 delta_after_IUP_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 1)
772 if (!delta_after_IUP_args
[i
])
779 allocated_after_IUP
= 1;
782 /* since we walk sequentially over all glyphs (with points), */
783 /* and the control instruction entries have the same order, */
784 /* we don't need to test for equality of font and glyph indices: */
785 /* at this very point in the code we certainly have a hit */
786 if (ctrl
->type
== Control_Delta_before_IUP
)
788 build_delta_exception(ctrl
,
789 delta_before_IUP_args
,
790 num_delta_before_IUP_args
);
792 if (ctrl
->point_idx
> 255)
793 need_before_IUP_words
= 1;
797 build_delta_exception(ctrl
,
798 delta_after_IUP_args
,
799 num_delta_after_IUP_args
);
801 if (ctrl
->point_idx
> 255)
802 need_after_IUP_words
= 1;
805 TA_control_get_next(font
);
808 /* nothing to do if no control instructions */
809 if (!(allocated_before_IUP
|| allocated_after_IUP
))
812 /* add number of argument pairs and function number to the stacks */
813 for (i
= 0; i
< 6; i
++)
815 if (num_delta_before_IUP_args
[i
])
817 int n
= num_delta_before_IUP_args
[i
] >> 1;
821 need_before_IUP_word_counts
= 1;
823 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) = n
;
824 num_delta_before_IUP_args
[i
]++;
826 *(delta_before_IUP_args
[i
] + num_delta_before_IUP_args
[i
]) =
827 bci_deltap1
+ (i
% 3);
828 num_delta_before_IUP_args
[i
]++;
832 /* add number of argument pairs to the stacks */
833 for (i
= 0; i
< 6; i
++)
835 if (num_delta_after_IUP_args
[i
])
837 int n
= num_delta_after_IUP_args
[i
] >> 1;
841 need_after_IUP_word_counts
= 1;
843 *(delta_after_IUP_args
[i
] + num_delta_after_IUP_args
[i
]) = n
;
844 num_delta_after_IUP_args
[i
]++;
848 /* merge `before IUP' delta stacks into a single one */
849 if (need_before_IUP_words
850 || (!need_before_IUP_words
&& !need_before_IUP_word_counts
))
852 FT_UInt num_args
= 0;
855 for (i
= 0; i
< 6; i
++)
858 FT_UInt num_args_new
;
861 if (!num_delta_before_IUP_args
[i
])
864 num_args_new
= num_args
+ num_delta_before_IUP_args
[i
];
865 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
872 memcpy(args_new
+ num_args
,
873 delta_before_IUP_args
[i
],
874 num_delta_before_IUP_args
[i
] * sizeof (FT_UInt
));
877 num_args
= num_args_new
;
880 num_before_IUP_stack_elements
= num_args
;
882 bufp
= TA_build_push(bufp
, args
, num_args
, need_before_IUP_words
, 1);
886 num_before_IUP_stack_elements
= 0;
888 /* stack elements are bytes, but counts need words */
889 for (i
= 0; i
< 6; i
++)
894 if (!num_delta_before_IUP_args
[i
])
897 num_delta_arg
= num_delta_before_IUP_args
[i
] - 2;
899 bufp
= TA_build_push(bufp
,
900 delta_before_IUP_args
[i
],
902 need_before_IUP_words
,
905 num_before_IUP_stack_elements
+= num_delta_arg
+ 2;
909 BCI(HIGH(num_delta_arg
));
910 BCI(LOW(num_delta_arg
));
912 /* the function number */
914 BCI(delta_before_IUP_args
[i
][num_delta_before_IUP_args
[i
] - 1]);
918 /* emit y DELTA opcodes (via `bci_deltap[1-3]' functions) */
919 if (num_delta_before_IUP_args
[5])
921 if (num_delta_before_IUP_args
[4])
923 if (num_delta_before_IUP_args
[3])
926 if (num_delta_before_IUP_args
[2]
927 || num_delta_before_IUP_args
[1]
928 || num_delta_before_IUP_args
[0])
931 /* emit x DELTA opcodes */
932 if (num_delta_before_IUP_args
[2])
934 if (num_delta_before_IUP_args
[1])
936 if (num_delta_before_IUP_args
[0])
939 if (num_delta_before_IUP_args
[2]
940 || num_delta_before_IUP_args
[1]
941 || num_delta_before_IUP_args
[0])
944 if (num_delta_before_IUP_args
[5]
945 || num_delta_before_IUP_args
[4]
946 || num_delta_before_IUP_args
[3])
949 /* merge `after IUP' delta stacks into a single one */
950 if (need_after_IUP_words
951 || (!need_after_IUP_words
&& !need_after_IUP_word_counts
))
953 FT_UInt num_args
= 0;
956 for (i
= 0; i
< 6; i
++)
959 FT_UInt num_args_new
;
962 if (!num_delta_after_IUP_args
[i
])
965 num_args_new
= num_args
+ num_delta_after_IUP_args
[i
];
966 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
973 memcpy(args_new
+ num_args
,
974 delta_after_IUP_args
[i
],
975 num_delta_after_IUP_args
[i
] * sizeof (FT_UInt
));
978 num_args
= num_args_new
;
981 num_after_IUP_stack_elements
= num_args
;
983 bufp
= TA_build_push(bufp
, args
, num_args
, need_after_IUP_words
, 1);
987 num_after_IUP_stack_elements
= 0;
989 /* stack elements are bytes, but counts need words */
990 for (i
= 0; i
< 6; i
++)
995 if (!num_delta_after_IUP_args
[i
])
998 num_delta_arg
= num_delta_after_IUP_args
[i
] - 1;
1000 bufp
= TA_build_push(bufp
,
1001 delta_after_IUP_args
[i
],
1003 need_after_IUP_words
,
1006 num_after_IUP_stack_elements
+= num_delta_arg
+ 1;
1008 num_delta_arg
>>= 1;
1010 BCI(HIGH(num_delta_arg
));
1011 BCI(LOW(num_delta_arg
));
1015 /* emit y DELTA opcodes */
1016 if (num_delta_after_IUP_args
[5])
1018 if (num_delta_after_IUP_args
[4])
1020 if (num_delta_after_IUP_args
[3])
1023 if (num_delta_after_IUP_args
[2]
1024 || num_delta_after_IUP_args
[1]
1025 || num_delta_after_IUP_args
[0])
1028 /* emit x DELTA opcodes */
1029 if (num_delta_after_IUP_args
[2])
1031 if (num_delta_after_IUP_args
[1])
1033 if (num_delta_after_IUP_args
[0])
1036 /* we need to insert a few extra bytecode instructions */
1037 /* if we have y delta exceptions before IUP */
1038 if (num_delta_before_IUP_args
[5]
1039 || num_delta_before_IUP_args
[4]
1040 || num_delta_before_IUP_args
[3])
1042 /* set `cvtl_do_iup_y' to zero at the beginning of the bytecode */
1043 /* by activating `ins_extra_buf' */
1044 glyph
->ins_extra_len
= sizeof (ins_extra_buf
) / sizeof (FT_Byte
);
1046 /* reset `cvtl_do_iup_y' for next glyph */
1054 for (i
= 0; i
< 6; i
++)
1056 free(delta_before_IUP_args
[i
]);
1057 free(delta_after_IUP_args
[i
]);
1061 if (num_before_IUP_stack_elements
> sfnt
->max_stack_elements
)
1062 sfnt
->max_stack_elements
= num_before_IUP_stack_elements
;
1063 if (num_after_IUP_stack_elements
> sfnt
->max_stack_elements
)
1064 sfnt
->max_stack_elements
= num_after_IUP_stack_elements
;
1071 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
1075 FONT
* font
= recorder
->font
;
1076 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
1077 FT_Vector
* points
= glyph
->outline
.points
;
1078 FT_Int num_contours
= glyph
->outline
.n_contours
;
1084 FT_Bool need_words
= 0;
1087 FT_UShort num_storage
;
1088 FT_UShort num_stack_elements
;
1091 num_args
= 2 * num_contours
+ 2;
1093 /* collect all arguments temporarily in an array (in reverse order) */
1094 /* so that we can easily split into chunks of 255 args */
1095 /* as needed by NPUSHB and NPUSHW, respectively */
1096 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
1100 arg
= args
+ num_args
- 1;
1102 if (num_args
> 0xFF)
1105 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
1106 *(arg
--) = bci_scale_composite_glyph
;
1108 *(arg
--) = bci_scale_glyph
;
1109 *(arg
--) = num_contours
;
1114 for (p
= 0; p
< num_contours
; p
++)
1120 end
= glyph
->outline
.contours
[p
];
1122 for (q
= start
; q
<= end
; q
++)
1124 if (points
[q
].y
< points
[min
].y
)
1126 if (points
[q
].y
> points
[max
].y
)
1132 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1133 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1137 *(arg
--) = TA_adjust_point_index(recorder
, min
);
1138 *(arg
--) = TA_adjust_point_index(recorder
, max
);
1147 /* with most fonts it is very rare */
1148 /* that any of the pushed arguments is larger than 0xFF, */
1149 /* thus we refrain from further optimizing this case */
1150 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
1154 num_storage
= sal_segment_offset
;
1155 if (num_storage
> sfnt
->max_storage
)
1156 sfnt
->max_storage
= num_storage
;
1158 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
1159 if (num_stack_elements
> sfnt
->max_stack_elements
)
1160 sfnt
->max_stack_elements
= num_stack_elements
;
1169 TA_font_build_subglyph_shifter(FONT
* font
,
1172 FT_Face face
= font
->loader
->face
;
1173 FT_GlyphSlot glyph
= face
->glyph
;
1175 TA_GlyphLoader gloader
= font
->loader
->gloader
;
1177 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
1178 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
1179 TA_SubGlyph subglyph
;
1181 FT_Int curr_contour
= 0;
1184 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
1188 FT_UShort flags
= subglyph
->flags
;
1189 FT_Pos y_offset
= subglyph
->arg2
;
1191 FT_Int num_contours
;
1194 /* load subglyph to get the number of contours */
1195 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
1198 num_contours
= glyph
->outline
.n_contours
;
1200 /* nothing to do if there is a point-to-point alignment */
1201 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
1204 /* nothing to do if y offset is zero */
1208 /* nothing to do if there are no contours */
1212 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1213 /* ensures that composite subglyphs are represented as simple glyphs */
1215 if (num_contours
> 0xFF
1216 || curr_contour
> 0xFF)
1219 BCI(HIGH(curr_contour
));
1220 BCI(LOW(curr_contour
));
1221 BCI(HIGH(num_contours
));
1222 BCI(LOW(num_contours
));
1231 /* there are high chances that this value needs PUSHW, */
1232 /* thus we handle it separately */
1233 if (y_offset
> 0xFF || y_offset
< 0)
1236 BCI(HIGH(y_offset
));
1246 BCI(bci_shift_subglyph
);
1250 curr_contour
+= num_contours
;
1258 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1259 * data in four arrays (which are simple but waste a lot of memory). The
1260 * function below converts them into bytecode.
1262 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1263 * together with the edge they correspond to.
1265 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1266 * loop over the edge or edge pairs, respectively, and each edge or edge
1267 * pair contains an inner loop to emit the correponding points.
1271 TA_build_point_hints(Recorder
* recorder
,
1272 TA_GlyphHints hints
)
1274 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1275 TA_Segment segments
= axis
->segments
;
1276 TA_Edge edges
= axis
->edges
;
1278 FT_Byte
* p
= recorder
->hints_record
.buf
;
1283 FT_UShort prev_edge
;
1284 FT_UShort prev_before_edge
;
1285 FT_UShort prev_after_edge
;
1290 Node3
* between_node
;
1293 /* we store everything as 16bit numbers; */
1294 /* the function numbers (`ta_ip_before', etc.) */
1295 /* reflect the order in the TA_Action enumeration */
1297 /* ip_before_points */
1300 for (before_node
= LLRB_MIN(ip_before_points
,
1301 &recorder
->ip_before_points_head
);
1303 before_node
= LLRB_NEXT(ip_before_points
,
1304 &recorder
->ip_before_points_head
,
1316 recorder
->hints_record
.num_actions
++;
1321 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1322 *(p
++) = HIGH(edge
->first
- segments
);
1323 *(p
++) = LOW(edge
->first
- segments
);
1327 for (before_node
= LLRB_MIN(ip_before_points
,
1328 &recorder
->ip_before_points_head
);
1330 before_node
= LLRB_NEXT(ip_before_points
,
1331 &recorder
->ip_before_points_head
,
1337 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1338 *(p
++) = HIGH(point
);
1339 *(p
++) = LOW(point
);
1343 /* ip_after_points */
1346 for (after_node
= LLRB_MIN(ip_after_points
,
1347 &recorder
->ip_after_points_head
);
1349 after_node
= LLRB_NEXT(ip_after_points
,
1350 &recorder
->ip_after_points_head
,
1362 recorder
->hints_record
.num_actions
++;
1364 edge
= edges
+ axis
->num_edges
- 1;
1367 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1368 *(p
++) = HIGH(edge
->first
- segments
);
1369 *(p
++) = LOW(edge
->first
- segments
);
1373 for (after_node
= LLRB_MIN(ip_after_points
,
1374 &recorder
->ip_after_points_head
);
1376 after_node
= LLRB_NEXT(ip_after_points
,
1377 &recorder
->ip_after_points_head
,
1383 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1384 *(p
++) = HIGH(point
);
1385 *(p
++) = LOW(point
);
1389 /* ip_on_point_array */
1393 for (on_node
= LLRB_MIN(ip_on_points
,
1394 &recorder
->ip_on_points_head
);
1396 on_node
= LLRB_NEXT(ip_on_points
,
1397 &recorder
->ip_on_points_head
,
1401 if (on_node
->edge
!= prev_edge
)
1404 prev_edge
= on_node
->edge
;
1410 recorder
->hints_record
.num_actions
++;
1413 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1417 for (on_node
= LLRB_MIN(ip_on_points
,
1418 &recorder
->ip_on_points_head
);
1420 on_node
= LLRB_NEXT(ip_on_points
,
1421 &recorder
->ip_on_points_head
,
1428 edge
= edges
+ on_node
->edge
;
1430 *(p
++) = HIGH(edge
->first
- segments
);
1431 *(p
++) = LOW(edge
->first
- segments
);
1433 /* save current position */
1434 edge_node
= on_node
;
1438 on_node
= LLRB_NEXT(ip_on_points
,
1439 &recorder
->ip_on_points_head
,
1442 /* count points on current edge */
1443 if (on_node
->edge
!= edge_node
->edge
)
1451 /* restore current position */
1452 on_node
= edge_node
;
1455 on_node
= LLRB_NEXT(ip_on_points
,
1456 &recorder
->ip_on_points_head
,
1462 if (on_node
->edge
!= edge_node
->edge
)
1465 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1466 *(p
++) = HIGH(point
);
1467 *(p
++) = LOW(point
);
1469 /* keep track of previous node */
1470 edge_node
= on_node
;
1473 /* reset loop iterator by one element, then continue */
1474 on_node
= edge_node
;
1478 /* ip_between_point_array */
1480 prev_before_edge
= 0xFFFF;
1481 prev_after_edge
= 0xFFFF;
1483 for (between_node
= LLRB_MIN(ip_between_points
,
1484 &recorder
->ip_between_points_head
);
1486 between_node
= LLRB_NEXT(ip_between_points
,
1487 &recorder
->ip_between_points_head
,
1490 /* count `(before,after)' edge pairs */
1491 if (between_node
->before_edge
!= prev_before_edge
1492 || between_node
->after_edge
!= prev_after_edge
)
1495 prev_before_edge
= between_node
->before_edge
;
1496 prev_after_edge
= between_node
->after_edge
;
1502 recorder
->hints_record
.num_actions
++;
1505 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1509 for (between_node
= LLRB_MIN(ip_between_points
,
1510 &recorder
->ip_between_points_head
);
1512 between_node
= LLRB_NEXT(ip_between_points
,
1513 &recorder
->ip_between_points_head
,
1516 Node3
* edge_pair_node
;
1521 before
= edges
+ between_node
->before_edge
;
1522 after
= edges
+ between_node
->after_edge
;
1524 *(p
++) = HIGH(after
->first
- segments
);
1525 *(p
++) = LOW(after
->first
- segments
);
1526 *(p
++) = HIGH(before
->first
- segments
);
1527 *(p
++) = LOW(before
->first
- segments
);
1529 /* save current position */
1530 edge_pair_node
= between_node
;
1534 between_node
= LLRB_NEXT(ip_between_points
,
1535 &recorder
->ip_between_points_head
,
1538 /* count points associated with current edge pair */
1539 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1540 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1548 /* restore current position */
1549 between_node
= edge_pair_node
;
1552 between_node
= LLRB_NEXT(ip_between_points
,
1553 &recorder
->ip_between_points_head
,
1559 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1560 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1563 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1564 *(p
++) = HIGH(point
);
1565 *(p
++) = LOW(point
);
1567 /* keep track of previous node */
1568 edge_pair_node
= between_node
;
1571 /* reset loop iterator by one element, then continue */
1572 between_node
= edge_pair_node
;
1576 recorder
->hints_record
.buf
= p
;
1581 TA_hints_record_is_different(Hints_Record
* hints_records
,
1582 FT_UInt num_hints_records
,
1586 Hints_Record last_hints_record
;
1592 /* we only need to compare with the last hints record */
1593 last_hints_record
= hints_records
[num_hints_records
- 1];
1595 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1598 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1606 TA_add_hints_record(Hints_Record
** hints_records
,
1607 FT_UInt
* num_hints_records
,
1609 Hints_Record hints_record
)
1611 Hints_Record
* hints_records_new
;
1613 /* at this point, `hints_record.buf' still points into `ins_buf' */
1614 FT_Byte
* end
= hints_record
.buf
;
1617 buf_len
= (FT_UInt
)(end
- start
);
1619 /* now fill the structure completely */
1620 hints_record
.buf_len
= buf_len
;
1621 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1622 if (!hints_record
.buf
)
1623 return FT_Err_Out_Of_Memory
;
1625 memcpy(hints_record
.buf
, start
, buf_len
);
1627 (*num_hints_records
)++;
1629 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1630 * sizeof (Hints_Record
));
1631 if (!hints_records_new
)
1633 free(hints_record
.buf
);
1634 (*num_hints_records
)--;
1635 return FT_Err_Out_Of_Memory
;
1638 *hints_records
= hints_records_new
;
1640 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1647 TA_emit_hints_record(Recorder
* recorder
,
1648 Hints_Record
* hints_record
,
1654 FT_Bool need_words
= 0;
1657 FT_UInt num_arguments
;
1661 /* check whether any argument is larger than 0xFF */
1662 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1663 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1670 /* with most fonts it is very rare */
1671 /* that any of the pushed arguments is larger than 0xFF, */
1672 /* thus we refrain from further optimizing this case */
1674 num_arguments
= hints_record
->buf_len
/ 2;
1679 for (i
= 0; i
< num_arguments
; i
+= 255)
1681 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1683 if (optimize
&& num_args
<= 8)
1684 BCI(PUSHW_1
- 1 + num_args
);
1690 for (j
= 0; j
< num_args
; j
++)
1700 /* we only need the lower bytes */
1703 for (i
= 0; i
< num_arguments
; i
+= 255)
1705 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1707 if (optimize
&& num_args
<= 8)
1708 BCI(PUSHB_1
- 1 + num_args
);
1714 for (j
= 0; j
< num_args
; j
++)
1722 /* collect stack depth data */
1723 if (num_arguments
> recorder
->num_stack_elements
)
1724 recorder
->num_stack_elements
= num_arguments
;
1731 TA_emit_hints_records(Recorder
* recorder
,
1732 Hints_Record
* hints_records
,
1733 FT_UInt num_hints_records
,
1738 Hints_Record
* hints_record
;
1741 hints_record
= hints_records
;
1743 /* emit hints records in `if' clauses, */
1744 /* with the ppem size as the condition */
1745 for (i
= 0; i
< num_hints_records
- 1; i
++)
1748 if (hints_record
->size
> 0xFF)
1751 BCI(HIGH((hints_record
+ 1)->size
));
1752 BCI(LOW((hints_record
+ 1)->size
));
1757 BCI((hints_record
+ 1)->size
);
1761 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1767 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1769 for (i
= 0; i
< num_hints_records
- 1; i
++)
1777 TA_free_hints_records(Hints_Record
* hints_records
,
1778 FT_UInt num_hints_records
)
1783 for (i
= 0; i
< num_hints_records
; i
++)
1784 free(hints_records
[i
].buf
);
1786 free(hints_records
);
1791 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1796 TA_Segment segments
= axis
->segments
;
1799 FT_UShort num_segs
= 0;
1803 seg_idx
= edge
->first
- segments
;
1805 /* we store everything as 16bit numbers */
1806 *(bufp
++) = HIGH(seg_idx
);
1807 *(bufp
++) = LOW(seg_idx
);
1809 /* wrap-around segments are stored as two segments */
1810 if (edge
->first
->first
> edge
->first
->last
)
1813 seg
= edge
->first
->edge_next
;
1814 while (seg
!= edge
->first
)
1818 if (seg
->first
> seg
->last
)
1821 seg
= seg
->edge_next
;
1824 *(bufp
++) = HIGH(num_segs
);
1825 *(bufp
++) = LOW(num_segs
);
1827 if (edge
->first
->first
> edge
->first
->last
)
1829 /* emit second part of wrap-around segment; */
1830 /* the bytecode positions such segments after `normal' ones */
1834 if (seg_idx
== *wrap
)
1839 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1840 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1843 seg
= edge
->first
->edge_next
;
1844 while (seg
!= edge
->first
)
1846 seg_idx
= seg
- segments
;
1848 *(bufp
++) = HIGH(seg_idx
);
1849 *(bufp
++) = LOW(seg_idx
);
1851 if (seg
->first
> seg
->last
)
1856 if (seg_idx
== *wrap
)
1861 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1862 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1865 seg
= seg
->edge_next
;
1873 TA_hints_recorder(TA_Action action
,
1874 TA_GlyphHints hints
,
1879 TA_Edge lower_bound
,
1880 TA_Edge upper_bound
)
1882 TA_AxisHints axis
= &hints
->axis
[dim
];
1883 TA_Edge edges
= axis
->edges
;
1884 TA_Segment segments
= axis
->segments
;
1885 TA_Point points
= hints
->points
;
1887 Recorder
* recorder
= (Recorder
*)hints
->user
;
1888 SFNT
* sfnt
= recorder
->sfnt
;
1889 FONT
* font
= recorder
->font
;
1890 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1891 FT_Byte
* p
= recorder
->hints_record
.buf
;
1893 FT_UInt style
= font
->loader
->metrics
->style_class
->style
;
1896 if (dim
== TA_DIMENSION_HORZ
)
1899 /* we collect point hints for later processing */
1905 TA_Point point
= (TA_Point
)arg1
;
1908 before_node
= (Node1
*)malloc(sizeof (Node1
));
1911 before_node
->point
= point
- points
;
1913 LLRB_INSERT(ip_before_points
,
1914 &recorder
->ip_before_points_head
,
1922 TA_Point point
= (TA_Point
)arg1
;
1925 after_node
= (Node1
*)malloc(sizeof (Node1
));
1928 after_node
->point
= point
- points
;
1930 LLRB_INSERT(ip_after_points
,
1931 &recorder
->ip_after_points_head
,
1939 TA_Point point
= (TA_Point
)arg1
;
1940 TA_Edge edge
= arg2
;
1943 on_node
= (Node2
*)malloc(sizeof (Node2
));
1946 on_node
->edge
= edge
- edges
;
1947 on_node
->point
= point
- points
;
1949 LLRB_INSERT(ip_on_points
,
1950 &recorder
->ip_on_points_head
,
1957 Node3
* between_node
;
1958 TA_Point point
= (TA_Point
)arg1
;
1959 TA_Edge before
= arg2
;
1960 TA_Edge after
= arg3
;
1963 between_node
= (Node3
*)malloc(sizeof (Node3
));
1966 between_node
->before_edge
= before
- edges
;
1967 between_node
->after_edge
= after
- edges
;
1968 between_node
->point
= point
- points
;
1970 LLRB_INSERT(ip_between_points
,
1971 &recorder
->ip_between_points_head
,
1977 /* we ignore the BOUND action since we signal this information */
1978 /* with the proper function number */
1985 /* some enum values correspond to four or eight bytecode functions; */
1986 /* if the value is n, the function numbers are n, ..., n+7, */
1987 /* to be differentiated with flags */
1993 TA_Edge base_edge
= (TA_Edge
)arg1
;
1994 TA_Edge stem_edge
= arg2
;
1998 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1999 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
2000 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
2002 *(p
++) = HIGH(base_edge
->first
- segments
);
2003 *(p
++) = LOW(base_edge
->first
- segments
);
2004 *(p
++) = HIGH(stem_edge
->first
- segments
);
2005 *(p
++) = LOW(stem_edge
->first
- segments
);
2007 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
2013 TA_Edge edge
= (TA_Edge
)arg1
;
2014 TA_Edge edge2
= arg2
;
2018 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2019 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2020 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
2022 *(p
++) = HIGH(edge
->first
- segments
);
2023 *(p
++) = LOW(edge
->first
- segments
);
2024 *(p
++) = HIGH(edge2
->first
- segments
);
2025 *(p
++) = LOW(edge2
->first
- segments
);
2027 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2033 TA_Edge edge
= (TA_Edge
)arg1
;
2034 TA_Edge edge2
= arg2
;
2035 TA_Edge edge_minus_one
= lower_bound
;
2039 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2040 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2041 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2042 + 4 * (edge_minus_one
!= NULL
);
2044 *(p
++) = HIGH(edge
->first
- segments
);
2045 *(p
++) = LOW(edge
->first
- segments
);
2046 *(p
++) = HIGH(edge2
->first
- segments
);
2047 *(p
++) = LOW(edge2
->first
- segments
);
2051 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
2052 *(p
++) = LOW(edge_minus_one
->first
- segments
);
2055 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2059 case ta_blue_anchor
:
2061 TA_Edge edge
= (TA_Edge
)arg1
;
2062 TA_Edge blue
= arg2
;
2066 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2068 *(p
++) = HIGH(blue
->first
- segments
);
2069 *(p
++) = LOW(blue
->first
- segments
);
2071 if (edge
->best_blue_is_shoot
)
2073 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2074 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2078 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2079 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2082 *(p
++) = HIGH(edge
->first
- segments
);
2083 *(p
++) = LOW(edge
->first
- segments
);
2085 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2091 TA_Edge edge
= (TA_Edge
)arg1
;
2092 TA_Edge edge2
= arg2
;
2093 TA_Edge edge_minus_one
= lower_bound
;
2097 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2098 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
2099 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
2100 + 4 * (edge_minus_one
!= NULL
);
2102 *(p
++) = HIGH(edge
->first
- segments
);
2103 *(p
++) = LOW(edge
->first
- segments
);
2104 *(p
++) = HIGH(edge2
->first
- segments
);
2105 *(p
++) = LOW(edge2
->first
- segments
);
2109 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
2110 *(p
++) = LOW(edge_minus_one
->first
- segments
);
2113 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2114 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
2120 TA_Edge edge
= (TA_Edge
)arg1
;
2124 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
2126 if (edge
->best_blue_is_shoot
)
2128 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2129 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
2133 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2134 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
2137 *(p
++) = HIGH(edge
->first
- segments
);
2138 *(p
++) = LOW(edge
->first
- segments
);
2140 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2146 TA_Edge serif
= (TA_Edge
)arg1
;
2147 TA_Edge base
= serif
->serif
;
2151 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2152 + (lower_bound
!= NULL
)
2153 + 2 * (upper_bound
!= NULL
);
2155 *(p
++) = HIGH(serif
->first
- segments
);
2156 *(p
++) = LOW(serif
->first
- segments
);
2157 *(p
++) = HIGH(base
->first
- segments
);
2158 *(p
++) = LOW(base
->first
- segments
);
2162 *(p
++) = HIGH(lower_bound
->first
- segments
);
2163 *(p
++) = LOW(lower_bound
->first
- segments
);
2167 *(p
++) = HIGH(upper_bound
->first
- segments
);
2168 *(p
++) = LOW(upper_bound
->first
- segments
);
2171 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
2175 case ta_serif_anchor
:
2176 case ta_serif_link2
:
2178 TA_Edge edge
= (TA_Edge
)arg1
;
2182 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2183 + (lower_bound
!= NULL
)
2184 + 2 * (upper_bound
!= NULL
);
2186 *(p
++) = HIGH(edge
->first
- segments
);
2187 *(p
++) = LOW(edge
->first
- segments
);
2191 *(p
++) = HIGH(lower_bound
->first
- segments
);
2192 *(p
++) = LOW(lower_bound
->first
- segments
);
2196 *(p
++) = HIGH(upper_bound
->first
- segments
);
2197 *(p
++) = LOW(upper_bound
->first
- segments
);
2200 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2204 case ta_serif_link1
:
2206 TA_Edge edge
= (TA_Edge
)arg1
;
2207 TA_Edge before
= arg2
;
2208 TA_Edge after
= arg3
;
2212 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2213 + (lower_bound
!= NULL
)
2214 + 2 * (upper_bound
!= NULL
);
2216 *(p
++) = HIGH(before
->first
- segments
);
2217 *(p
++) = LOW(before
->first
- segments
);
2218 *(p
++) = HIGH(edge
->first
- segments
);
2219 *(p
++) = LOW(edge
->first
- segments
);
2220 *(p
++) = HIGH(after
->first
- segments
);
2221 *(p
++) = LOW(after
->first
- segments
);
2225 *(p
++) = HIGH(lower_bound
->first
- segments
);
2226 *(p
++) = LOW(lower_bound
->first
- segments
);
2230 *(p
++) = HIGH(upper_bound
->first
- segments
);
2231 *(p
++) = LOW(upper_bound
->first
- segments
);
2234 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2239 /* there are more cases in the enumeration */
2240 /* which are handled with flags */
2244 recorder
->hints_record
.num_actions
++;
2245 recorder
->hints_record
.buf
= p
;
2250 TA_init_recorder(Recorder
* recorder
,
2254 TA_GlyphHints hints
)
2256 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2257 TA_Point points
= hints
->points
;
2258 TA_Point point_limit
= points
+ hints
->num_points
;
2261 TA_Segment segments
= axis
->segments
;
2262 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2265 FT_UShort num_strong_points
= 0;
2266 FT_UShort
* wrap_around_segment
;
2268 recorder
->sfnt
= sfnt
;
2269 recorder
->font
= font
;
2270 recorder
->glyph
= glyph
;
2271 recorder
->num_segments
= axis
->num_segments
;
2273 LLRB_INIT(&recorder
->ip_before_points_head
);
2274 LLRB_INIT(&recorder
->ip_after_points_head
);
2275 LLRB_INIT(&recorder
->ip_on_points_head
);
2276 LLRB_INIT(&recorder
->ip_between_points_head
);
2278 recorder
->num_stack_elements
= 0;
2280 /* no need to clean up allocated arrays in case of error; */
2281 /* this is handled later by `TA_free_recorder' */
2283 recorder
->num_wrap_around_segments
= 0;
2284 for (seg
= segments
; seg
< seg_limit
; seg
++)
2285 if (seg
->first
> seg
->last
)
2286 recorder
->num_wrap_around_segments
++;
2288 recorder
->wrap_around_segments
=
2289 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2290 * sizeof (FT_UShort
));
2291 if (!recorder
->wrap_around_segments
)
2292 return FT_Err_Out_Of_Memory
;
2294 wrap_around_segment
= recorder
->wrap_around_segments
;
2295 for (seg
= segments
; seg
< seg_limit
; seg
++)
2296 if (seg
->first
> seg
->last
)
2297 *(wrap_around_segment
++) = seg
- segments
;
2299 /* get number of strong points */
2300 for (point
= points
; point
< point_limit
; point
++)
2302 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2303 /* however, this value isn't known yet */
2304 /* (or rather, it can vary between different pixel sizes) */
2305 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
2308 num_strong_points
++;
2311 recorder
->num_strong_points
= num_strong_points
;
2318 TA_reset_recorder(Recorder
* recorder
,
2321 recorder
->hints_record
.buf
= bufp
;
2322 recorder
->hints_record
.num_actions
= 0;
2327 TA_rewind_recorder(Recorder
* recorder
,
2334 Node3
* between_node
;
2336 Node1
* next_before_node
;
2337 Node1
* next_after_node
;
2338 Node2
* next_on_node
;
2339 Node3
* next_between_node
;
2342 TA_reset_recorder(recorder
, bufp
);
2344 recorder
->hints_record
.size
= size
;
2346 /* deallocate our red-black trees */
2348 for (before_node
= LLRB_MIN(ip_before_points
,
2349 &recorder
->ip_before_points_head
);
2351 before_node
= next_before_node
)
2353 next_before_node
= LLRB_NEXT(ip_before_points
,
2354 &recorder
->ip_before_points_head
,
2356 LLRB_REMOVE(ip_before_points
,
2357 &recorder
->ip_before_points_head
,
2362 for (after_node
= LLRB_MIN(ip_after_points
,
2363 &recorder
->ip_after_points_head
);
2365 after_node
= next_after_node
)
2367 next_after_node
= LLRB_NEXT(ip_after_points
,
2368 &recorder
->ip_after_points_head
,
2370 LLRB_REMOVE(ip_after_points
,
2371 &recorder
->ip_after_points_head
,
2376 for (on_node
= LLRB_MIN(ip_on_points
,
2377 &recorder
->ip_on_points_head
);
2379 on_node
= next_on_node
)
2381 next_on_node
= LLRB_NEXT(ip_on_points
,
2382 &recorder
->ip_on_points_head
,
2384 LLRB_REMOVE(ip_on_points
,
2385 &recorder
->ip_on_points_head
,
2390 for (between_node
= LLRB_MIN(ip_between_points
,
2391 &recorder
->ip_between_points_head
);
2393 between_node
= next_between_node
)
2395 next_between_node
= LLRB_NEXT(ip_between_points
,
2396 &recorder
->ip_between_points_head
,
2398 LLRB_REMOVE(ip_between_points
,
2399 &recorder
->ip_between_points_head
,
2407 TA_free_recorder(Recorder
* recorder
)
2409 free(recorder
->wrap_around_segments
);
2411 TA_rewind_recorder(recorder
, NULL
, 0);
2416 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2420 FT_Face face
= sfnt
->face
;
2428 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2429 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2430 /* `idx' is never negative */
2431 GLYPH
* glyph
= &data
->glyphs
[idx
];
2433 TA_GlyphHints hints
;
2435 FT_UInt num_action_hints_records
= 0;
2436 FT_UInt num_point_hints_records
= 0;
2437 Hints_Record
* action_hints_records
= NULL
;
2438 Hints_Record
* point_hints_records
= NULL
;
2441 FT_UShort num_stack_elements
;
2442 FT_Bool optimize
= 0;
2444 FT_Int32 load_flags
;
2454 /* XXX: right now, we abuse this flag to control */
2455 /* the global behaviour of the auto-hinter */
2456 load_flags
= 1 << 29; /* vertical hinting only */
2457 if (!font
->adjust_subglyphs
)
2459 if (font
->hint_composites
)
2460 load_flags
|= FT_LOAD_NO_SCALE
;
2462 load_flags
|= FT_LOAD_NO_RECURSE
;
2465 /* computing the segments is resolution independent, */
2466 /* thus the pixel size in this call is arbitrary -- */
2467 /* however, we avoid unnecessary debugging output */
2468 /* if we use the lowest value of the hinting range */
2469 error
= FT_Set_Pixel_Sizes(face
,
2470 font
->hinting_range_min
,
2471 font
->hinting_range_min
);
2475 /* this data is needed for `ta_glyph_hints_reload' (in file `tahints.c') */
2476 /* to modify `out' directions of points at the user's request */
2477 /* (which will eventually become single-point segments) */
2478 error
= TA_control_segment_dir_collect(font
, face
->face_index
, idx
);
2483 /* temporarily disable some debugging output */
2484 /* to avoid getting the information twice */
2485 _ta_debug_save
= _ta_debug
;
2489 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2490 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2493 _ta_debug
= _ta_debug_save
;
2499 /* do nothing if we have an empty glyph */
2500 if (!face
->glyph
->outline
.n_contours
)
2503 hints
= &font
->loader
->hints
;
2505 /* do nothing if the setup delivered the `none_dflt' style only */
2506 if (!hints
->num_points
)
2510 * We allocate a buffer which is certainly large enough
2511 * to hold all of the created bytecode instructions;
2512 * later on it gets reallocated to its real size.
2514 * The value `1000' is a very rough guess, not tested well.
2516 * For delta exceptions, we have three DELTA commands,
2517 * covering 3*16 ppem values.
2518 * Since a point index can be larger than 255,
2519 * we assume two bytes everywhere for the necessary PUSH calls.
2520 * This value must be doubled for the other arguments of DELTA.
2521 * Additionally, we have both x and y deltas,
2522 * which need to be handled separately in the bytecode.
2523 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2524 * adding some bytes for the necessary overhead.
2526 ins_len
= hints
->num_points
2527 * (1000 + ((font
->control_data_head
!= NULL
) ? 400 : 0));
2528 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2530 return FT_Err_Out_Of_Memory
;
2532 /* handle composite glyph */
2533 if (font
->loader
->gloader
->base
.num_subglyphs
)
2535 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2538 error
= FT_Err_Out_Of_Memory
;
2545 /* only scale the glyph if the `none_dflt' style has been used */
2546 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
2548 /* since `TA_init_recorder' hasn't been called yet, */
2549 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2550 recorder
.sfnt
= sfnt
;
2551 recorder
.font
= font
;
2552 recorder
.glyph
= glyph
;
2554 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2557 error
= FT_Err_Out_Of_Memory
;
2564 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2568 /* loop over a large range of pixel sizes */
2569 /* to find hints records which get pushed onto the bytecode stack */
2578 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
2580 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2582 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2583 fprintf(stderr
, "\n");
2584 for (i
= 0; i
< num_chars
; i
++)
2586 fprintf(stderr
, "\n\n");
2591 /* we temporarily use `ins_buf' to record the current glyph hints */
2592 ta_loader_register_hints_recorder(font
->loader
,
2596 for (size
= font
->hinting_range_min
;
2597 size
<= font
->hinting_range_max
;
2605 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2607 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2617 num_chars
= fprintf(stderr
, "size %d\n", size
);
2618 for (i
= 0; i
< num_chars
- 1; i
++)
2620 fprintf(stderr
, "\n\n");
2624 /* calling `ta_loader_load_glyph' uses the */
2625 /* `TA_hints_recorder' function as a callback, */
2626 /* modifying `hints_record' */
2627 error
= ta_loader_load_glyph(font
, face
, idx
, load_flags
);
2631 if (TA_hints_record_is_different(action_hints_records
,
2632 num_action_hints_records
,
2633 ins_buf
, recorder
.hints_record
.buf
))
2640 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2641 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2642 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2644 fprintf(stderr
, "action hints record:\n");
2645 if (ins_buf
== recorder
.hints_record
.buf
)
2646 fprintf(stderr
, " (none)");
2649 fprintf(stderr
, " ");
2650 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2651 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2653 fprintf(stderr
, "\n");
2657 error
= TA_add_hints_record(&action_hints_records
,
2658 &num_action_hints_records
,
2659 ins_buf
, recorder
.hints_record
);
2664 /* now handle point records */
2666 TA_reset_recorder(&recorder
, ins_buf
);
2668 /* use the point hints data collected in `TA_hints_recorder' */
2669 TA_build_point_hints(&recorder
, hints
);
2671 if (TA_hints_record_is_different(point_hints_records
,
2672 num_point_hints_records
,
2673 ins_buf
, recorder
.hints_record
.buf
))
2683 num_chars
= fprintf(stderr
, "size %d\n", size
);
2684 for (i
= 0; i
< num_chars
- 1; i
++)
2686 fprintf(stderr
, "\n\n");
2688 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2689 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2690 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2693 fprintf(stderr
, "point hints record:\n");
2694 if (ins_buf
== recorder
.hints_record
.buf
)
2695 fprintf(stderr
, " (none)");
2698 fprintf(stderr
, " ");
2699 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2700 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2702 fprintf(stderr
, "\n\n");
2706 error
= TA_add_hints_record(&point_hints_records
,
2707 &num_point_hints_records
,
2708 ins_buf
, recorder
.hints_record
);
2714 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2716 /* since we only have a single empty record we just scale the glyph */
2717 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2720 error
= FT_Err_Out_Of_Memory
;
2727 /* if there is only a single record, */
2728 /* we do a global optimization later on */
2729 if (num_action_hints_records
> 1)
2732 /* store the hints records and handle stack depth */
2734 bufp
= TA_emit_hints_records(&recorder
,
2735 point_hints_records
,
2736 num_point_hints_records
,
2740 num_stack_elements
= recorder
.num_stack_elements
;
2741 recorder
.num_stack_elements
= 0;
2744 bufp
= TA_emit_hints_records(&recorder
,
2745 action_hints_records
,
2746 num_action_hints_records
,
2750 recorder
.num_stack_elements
+= num_stack_elements
;
2753 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
2756 error
= FT_Err_Out_Of_Memory
;
2760 if (num_action_hints_records
== 1)
2761 bufp
= TA_optimize_push(ins_buf
, pos
);
2764 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2765 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2766 TA_free_recorder(&recorder
);
2769 /* handle delta exceptions */
2770 if (font
->control_data_head
)
2772 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
2775 error
= FT_Err_Out_Of_Memory
;
2780 ins_len
= bufp
- ins_buf
;
2782 if (ins_len
> sfnt
->max_instructions
)
2783 sfnt
->max_instructions
= ins_len
;
2785 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2786 glyph
->ins_len
= ins_len
;
2791 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2792 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2793 TA_free_recorder(&recorder
);
2800 /* end of tabytecode.c */