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.
17 #include <stdbool.h> /* for llrb.h */
19 #include "llrb.h" /* a red-black tree implementation */
30 int _ta_debug_global
= 0;
31 int _ta_debug_disable_horz_hints
;
32 int _ta_debug_disable_vert_hints
;
33 int _ta_debug_disable_blue_hints
;
34 void* _ta_debug_hints
;
38 /* node structures for point hints */
40 typedef struct Node1 Node1
;
43 LLRB_ENTRY(Node1
) entry1
;
47 typedef struct Node2 Node2
;
50 LLRB_ENTRY(Node2
) entry2
;
55 typedef struct Node3 Node3
;
58 LLRB_ENTRY(Node3
) entry3
;
59 FT_UShort before_edge
;
65 /* comparison functions for our red-black trees */
72 return e1
->point
- e2
->point
;
82 /* sort by edges ... */
83 delta
= (FT_Int
)e1
->edge
- (FT_Int
)e2
->edge
;
87 /* ... then by points */
88 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
98 /* sort by `before' edges ... */
99 delta
= (FT_Int
)e1
->before_edge
- (FT_Int
)e2
->before_edge
;
103 /* ... then by `after' edges ... */
104 delta
= (FT_Int
)e1
->after_edge
- (FT_Int
)e2
->after_edge
;
108 /* ... then by points */
109 return (FT_Int
)e1
->point
- (FT_Int
)e2
->point
;
113 /* the red-black tree function bodies */
114 typedef struct ip_before_points ip_before_points
;
115 typedef struct ip_after_points ip_after_points
;
116 typedef struct ip_on_points ip_on_points
;
117 typedef struct ip_between_points ip_between_points
;
119 LLRB_HEAD(ip_before_points
, Node1
);
120 LLRB_HEAD(ip_after_points
, Node1
);
121 LLRB_HEAD(ip_on_points
, Node2
);
122 LLRB_HEAD(ip_between_points
, Node3
);
124 /* no trailing semicolon in the next four lines */
125 LLRB_GENERATE_STATIC(ip_before_points
, Node1
, entry1
, node1cmp
)
126 LLRB_GENERATE_STATIC(ip_after_points
, Node1
, entry1
, node1cmp
)
127 LLRB_GENERATE_STATIC(ip_on_points
, Node2
, entry2
, node2cmp
)
128 LLRB_GENERATE_STATIC(ip_between_points
, Node3
, entry3
, node3cmp
)
131 typedef struct Hints_Record_
139 typedef struct Recorder_
143 GLYPH
* glyph
; /* the current glyph */
144 Hints_Record hints_record
;
146 /* some segments can `wrap around' */
147 /* a contour's start point like 24-25-26-0-1-2 */
148 /* (there can be at most one such segment per contour); */
149 /* later on we append additional records */
150 /* to split them into 24-26 and 0-2 */
151 FT_UShort
* wrap_around_segments
;
152 FT_UShort num_wrap_around_segments
;
154 FT_UShort num_stack_elements
; /* the necessary stack depth so far */
156 /* data necessary for strong point interpolation */
157 ip_before_points ip_before_points_head
;
158 ip_after_points ip_after_points_head
;
159 ip_on_points ip_on_points_head
;
160 ip_between_points ip_between_points_head
;
162 FT_UShort num_strong_points
;
163 FT_UShort num_segments
;
167 /* this is the bytecode of the `.ttfautohint' glyph */
169 FT_Byte ttfautohint_glyph_bytecode
[7] =
172 /* increment `cvtl_is_subglyph' counter */
185 * convert array `args' into a sequence of NPUSHB, NPUSHW, PUSHB_X, and
186 * PUSHW_X instructions to be stored in `bufp' (the latter two instructions
187 * only if `optimize' is not set); if `need_words' is set, NPUSHW and
192 TA_build_push(FT_Byte
* bufp
,
204 for (i
= 0; i
< num_args
; i
+= 255)
206 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
208 if (optimize
&& nargs
<= 8)
209 BCI(PUSHW_1
- 1 + nargs
);
215 for (j
= 0; j
< nargs
; j
++)
225 for (i
= 0; i
< num_args
; i
+= 255)
227 nargs
= (num_args
- i
> 255) ? 255 : num_args
- i
;
229 if (optimize
&& nargs
<= 8)
230 BCI(PUSHB_1
- 1 + nargs
);
236 for (j
= 0; j
< nargs
; j
++)
249 * We optimize two common cases, replacing
251 * NPUSHB A ... NPUSHB B [... NPUSHB C] ... CALL
255 * NPUSHB (A+B[+C]) ... CALL
261 TA_optimize_push(FT_Byte
* buf
,
276 /* XXX improve handling of NPUSHW */
277 if (*(pos
[0]) == NPUSHW
278 || *(pos
[1]) == NPUSHW
279 || *(pos
[2]) == NPUSHW
)
282 /* the point hints records block can be missing */
283 if (pos
[0] == pos
[1])
289 /* there are at least two NPUSHB instructions */
290 /* (one of them directly at the start) */
291 sizes
[0] = *(pos
[0] + 1);
292 sizes
[1] = *(pos
[1] + 1);
293 sizes
[2] = pos
[2] ? *(pos
[2] + 1) : 0;
295 sum
= sizes
[0] + sizes
[1] + sizes
[2];
298 return buf
; /* nothing to do since we need three NPUSHB */
299 else if (!sizes
[2] && (sum
> 0xFF))
300 return buf
; /* nothing to do since we need two NPUSHB */
304 /* reduce three NPUSHB to two */
306 new_size2
= sum
- 0xFF;
310 /* reduce two or three NPUSHB to one */
321 BCI(PUSHB_1
- 1 + new_size1
);
327 for (i
= 0; i
< new_size1
; i
++)
329 if (p
== pos
[pos_idx
])
332 p
+= 2; /* skip old NPUSHB */
340 BCI(PUSHB_1
- 1 + new_size2
);
346 for (i
= 0; i
< new_size2
; i
++)
348 if (p
== pos
[pos_idx
])
363 /* We add a subglyph for each composite glyph. */
364 /* Since subglyphs must contain at least one point, */
365 /* we have to adjust all point indices accordingly. */
366 /* Using the `pointsums' array of the `GLYPH' structure */
367 /* it is straightforward to do that: */
368 /* Assuming that point with index x is in the interval */
369 /* pointsums[n] <= x < pointsums[n + 1], */
370 /* the new point index is x + n. */
373 TA_adjust_point_index(Recorder
* recorder
,
376 FONT
* font
= recorder
->font
;
377 GLYPH
* glyph
= recorder
->glyph
;
381 if (!glyph
->num_components
|| !font
->hint_composites
)
382 return idx
; /* not a composite glyph */
384 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
385 if (idx
< glyph
->pointsums
[i
])
392 /* we store the segments in the storage area; */
393 /* each segment record consists of the first and last point */
396 TA_sfnt_build_glyph_segments(SFNT
* sfnt
,
401 FONT
* font
= recorder
->font
;
402 TA_GlyphHints hints
= &font
->loader
->hints
;
403 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
404 TA_Point points
= hints
->points
;
405 TA_Segment segments
= axis
->segments
;
407 TA_Segment seg_limit
;
409 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
410 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
412 FT_UInt style_id
= data
->style_ids
413 [font
->loader
->metrics
->style_class
->style
];
415 FT_Outline outline
= font
->loader
->gloader
->base
.outline
;
420 FT_UShort num_segments
;
422 FT_Bool need_words
= 0;
426 FT_UShort num_packed_segments
;
427 FT_UShort num_storage
;
428 FT_UShort num_stack_elements
;
429 FT_UShort num_twilight_points
;
432 seg_limit
= segments
+ axis
->num_segments
;
433 num_segments
= axis
->num_segments
;
435 /* to pack the data in the bytecode more tightly, */
436 /* we store up to the first nine segments in nibbles if possible, */
437 /* using delta values */
439 num_packed_segments
= 0;
440 for (seg
= segments
; seg
< seg_limit
; seg
++)
442 FT_UInt first
= seg
->first
- points
;
443 FT_UInt last
= seg
->last
- points
;
446 first
= TA_adjust_point_index(recorder
, first
);
447 last
= TA_adjust_point_index(recorder
, last
);
449 if (first
- base
>= 16)
451 if (first
> last
|| last
- first
>= 16)
453 if (num_packed_segments
== 9)
455 num_packed_segments
++;
459 /* also handle wrap-around segments */
460 num_segments
+= recorder
->num_wrap_around_segments
;
462 /* wrap-around segments are pushed with four arguments; */
463 /* a segment stored in nibbles needs only one byte instead of two */
464 num_args
= num_packed_segments
465 + 2 * (num_segments
- num_packed_segments
)
466 + 2 * recorder
->num_wrap_around_segments
469 /* collect all arguments temporarily in an array (in reverse order) */
470 /* so that we can easily split into chunks of 255 args */
471 /* as needed by NPUSHB and NPUSHW, respectively */
472 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
476 arg
= args
+ num_args
- 1;
478 if (num_segments
> 0xFF)
481 /* the number of packed segments is indicated by the function number */
482 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
483 *(arg
--) = bci_create_segments_composite_0
+ num_packed_segments
;
485 *(arg
--) = bci_create_segments_0
+ num_packed_segments
;
487 *(arg
--) = CVT_SCALING_VALUE_OFFSET(style_id
);
488 *(arg
--) = num_segments
;
491 for (seg
= segments
; seg
< segments
+ num_packed_segments
; seg
++)
493 FT_UInt first
= seg
->first
- points
;
494 FT_UInt last
= seg
->last
- points
;
499 first
= TA_adjust_point_index(recorder
, first
);
500 last
= TA_adjust_point_index(recorder
, last
);
502 low_nibble
= first
- base
;
503 high_nibble
= last
- first
;
505 *(arg
--) = 16 * high_nibble
+ low_nibble
;
510 for (seg
= segments
+ num_packed_segments
; seg
< seg_limit
; seg
++)
512 FT_UInt first
= seg
->first
- points
;
513 FT_UInt last
= seg
->last
- points
;
516 *(arg
--) = TA_adjust_point_index(recorder
, first
);
517 *(arg
--) = TA_adjust_point_index(recorder
, last
);
519 /* we push the last and first contour point */
520 /* as a third and fourth argument in wrap-around segments */
523 for (n
= 0; n
< outline
.n_contours
; n
++)
525 FT_UInt end
= (FT_UInt
)outline
.contours
[n
];
530 *(arg
--) = TA_adjust_point_index(recorder
, end
);
535 *(arg
--) = TA_adjust_point_index(recorder
, 0);
537 *(arg
--) = TA_adjust_point_index(recorder
,
538 (FT_UInt
)outline
.contours
[n
- 1] + 1);
548 /* emit the second part of wrap-around segments as separate segments */
549 /* so that edges can easily link to them */
550 for (seg
= segments
; seg
< seg_limit
; seg
++)
552 FT_UInt first
= seg
->first
- points
;
553 FT_UInt last
= seg
->last
- points
;
558 for (n
= 0; n
< outline
.n_contours
; n
++)
560 if (first
<= (FT_UInt
)outline
.contours
[n
])
563 *(arg
--) = TA_adjust_point_index(recorder
, 0);
565 *(arg
--) = TA_adjust_point_index(recorder
,
566 (FT_UInt
)outline
.contours
[n
- 1] + 1);
571 *(arg
--) = TA_adjust_point_index(recorder
, last
);
575 /* with most fonts it is very rare */
576 /* that any of the pushed arguments is larger than 0xFF, */
577 /* thus we refrain from further optimizing this case */
578 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, optimize
);
582 num_storage
= sal_segment_offset
+ num_segments
* 2;
583 if (num_storage
> sfnt
->max_storage
)
584 sfnt
->max_storage
= num_storage
;
586 num_twilight_points
= num_segments
* 2;
587 if (num_twilight_points
> sfnt
->max_twilight_points
)
588 sfnt
->max_twilight_points
= num_twilight_points
;
590 /* both this function and `TA_emit_hints_record' */
591 /* push data onto the stack */
592 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
593 + recorder
->num_stack_elements
+ num_args
;
594 if (num_stack_elements
> sfnt
->max_stack_elements
)
595 sfnt
->max_stack_elements
= num_stack_elements
;
604 build_delta_exception(const Delta
* delta
,
605 FT_UInt
** delta_args
,
614 ppem
= delta
->ppem
- DELTA_PPEM_MIN
;
630 * the possible shift values in the instructions are indexed as follows:
641 * (note that there is no index for a zero shift).
644 if (delta
->x_shift
< 0)
645 x_shift
= delta
->x_shift
+ 8;
647 x_shift
= delta
->x_shift
+ 7;
649 if (delta
->y_shift
< 0)
650 y_shift
= delta
->y_shift
+ 8;
652 y_shift
= delta
->y_shift
+ 7;
654 /* add point index and exception specification to appropriate stack */
657 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
658 (ppem
<< 4) + x_shift
;
659 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
666 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
667 (ppem
<< 4) + y_shift
;
668 *(delta_args
[offset
] + num_delta_args
[offset
]++) =
675 TA_sfnt_build_delta_exceptions(SFNT
* sfnt
,
680 FT_Face face
= font
->loader
->face
;
685 FT_UShort num_stack_elements
;
687 /* DELTAP[1-3] stacks for both x and y directions */
688 FT_UInt
* delta_args
[6] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
689 int num_delta_args
[6] = {0, 0, 0, 0, 0, 0};
690 FT_UInt
* args
= NULL
;
692 FT_Bool need_words
= 0;
693 FT_Bool need_word_counts
= 0;
694 FT_Bool allocated
= 0;
699 num_points
= font
->loader
->gloader
->base
.outline
.n_points
;
701 /* loop over all fitting delta exceptions */
704 delta
= TA_deltas_get_delta(font
);
706 /* too large values of font and glyph indices in `delta' */
707 /* are handled by later calls of this function */
709 || face
->face_index
< delta
->font_idx
710 || idx
< delta
->glyph_idx
)
715 for (i
= 0; i
< 6; i
++)
717 /* see the comment on allocating `ins_buf' in function */
718 /* `TA_sfnt_build_glyph_instructions' for more on the array sizes; */
719 /* we have to increase by 1 for the number of argument pairs */
720 delta_args
[i
] = (FT_UInt
*)malloc((16 * 2 * num_points
+ 1)
732 /* since we walk sequentially over all glyphs (with points), */
733 /* and the delta entries have the same order, */
734 /* we don't need to test for equality of font and glyph indices: */
735 /* at this very point in the code we certainly have a hit */
736 build_delta_exception(delta
, delta_args
, num_delta_args
);
738 if (delta
->point_idx
> 255)
741 TA_deltas_get_next(font
);
744 /* nothing to do if no delta data */
748 /* add number of argument pairs to the stacks */
749 for (i
= 0; i
< 6; i
++)
751 if (num_delta_args
[i
])
753 int n
= num_delta_args
[i
] >> 1;
757 need_word_counts
= 1;
759 *(delta_args
[i
] + num_delta_args
[i
]) = n
;
764 /* merge delta stacks into a single one */
766 || (!need_words
&& !need_word_counts
))
768 FT_UInt num_args
= 0;
771 for (i
= 0; i
< 6; i
++)
774 FT_UInt num_args_new
;
777 if (!num_delta_args
[i
])
780 num_args_new
= num_args
+ num_delta_args
[i
];
781 args_new
= (FT_UInt
*)realloc(args
, num_args_new
* sizeof (FT_UInt
));
788 memcpy(args_new
+ num_args
,
790 num_delta_args
[i
] * sizeof (FT_UInt
));
793 num_args
= num_args_new
;
796 num_stack_elements
= num_args
;
798 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
802 num_stack_elements
= 0;
804 /* stack elements are bytes, but counts need words */
805 for (i
= 0; i
< 6; i
++)
810 if (!num_delta_args
[i
])
813 num_delta_arg
= num_delta_args
[i
] - 1;
815 bufp
= TA_build_push(bufp
,
821 num_stack_elements
+= num_delta_arg
+ 1;
825 BCI(HIGH(num_delta_arg
));
826 BCI(LOW(num_delta_arg
));
830 /* emit the DELTA opcodes */
831 if (num_delta_args
[5])
833 if (num_delta_args
[4])
835 if (num_delta_args
[3])
838 if (num_delta_args
[2] || num_delta_args
[1] || num_delta_args
[0])
841 if (num_delta_args
[2])
843 if (num_delta_args
[1])
845 if (num_delta_args
[0])
849 for (i
= 0; i
< 6; i
++)
853 if (num_stack_elements
> sfnt
->max_stack_elements
)
854 sfnt
->max_stack_elements
= num_stack_elements
;
860 TA_sfnt_build_glyph_scaler(SFNT
* sfnt
,
864 FONT
* font
= recorder
->font
;
865 FT_GlyphSlot glyph
= sfnt
->face
->glyph
;
866 FT_Vector
* points
= glyph
->outline
.points
;
867 FT_Int num_contours
= glyph
->outline
.n_contours
;
873 FT_Bool need_words
= 0;
876 FT_UShort num_storage
;
877 FT_UShort num_stack_elements
;
880 num_args
= 2 * num_contours
+ 2;
882 /* collect all arguments temporarily in an array (in reverse order) */
883 /* so that we can easily split into chunks of 255 args */
884 /* as needed by NPUSHB and NPUSHW, respectively */
885 args
= (FT_UInt
*)malloc(num_args
* sizeof (FT_UInt
));
889 arg
= args
+ num_args
- 1;
894 if (recorder
->glyph
->num_components
&& font
->hint_composites
)
895 *(arg
--) = bci_scale_composite_glyph
;
897 *(arg
--) = bci_scale_glyph
;
898 *(arg
--) = num_contours
;
903 for (p
= 0; p
< num_contours
; p
++)
909 end
= glyph
->outline
.contours
[p
];
911 for (q
= start
; q
<= end
; q
++)
913 if (points
[q
].y
< points
[min
].y
)
915 if (points
[q
].y
> points
[max
].y
)
921 *(arg
--) = TA_adjust_point_index(recorder
, max
);
922 *(arg
--) = TA_adjust_point_index(recorder
, min
);
926 *(arg
--) = TA_adjust_point_index(recorder
, min
);
927 *(arg
--) = TA_adjust_point_index(recorder
, max
);
936 /* with most fonts it is very rare */
937 /* that any of the pushed arguments is larger than 0xFF, */
938 /* thus we refrain from further optimizing this case */
939 bufp
= TA_build_push(bufp
, args
, num_args
, need_words
, 1);
943 num_storage
= sal_segment_offset
;
944 if (num_storage
> sfnt
->max_storage
)
945 sfnt
->max_storage
= num_storage
;
947 num_stack_elements
= ADDITIONAL_STACK_ELEMENTS
+ num_args
;
948 if (num_stack_elements
> sfnt
->max_stack_elements
)
949 sfnt
->max_stack_elements
= num_stack_elements
;
958 TA_font_build_subglyph_shifter(FONT
* font
,
961 FT_Face face
= font
->loader
->face
;
962 FT_GlyphSlot glyph
= face
->glyph
;
964 TA_GlyphLoader gloader
= font
->loader
->gloader
;
966 TA_SubGlyph subglyphs
= gloader
->base
.subglyphs
;
967 TA_SubGlyph subglyph_limit
= subglyphs
+ gloader
->base
.num_subglyphs
;
968 TA_SubGlyph subglyph
;
970 FT_Int curr_contour
= 0;
973 for (subglyph
= subglyphs
; subglyph
< subglyph_limit
; subglyph
++)
977 FT_UShort flags
= subglyph
->flags
;
978 FT_Pos y_offset
= subglyph
->arg2
;
983 /* load subglyph to get the number of contours */
984 error
= FT_Load_Glyph(face
, subglyph
->index
, FT_LOAD_NO_SCALE
);
987 num_contours
= glyph
->outline
.n_contours
;
989 /* nothing to do if there is a point-to-point alignment */
990 if (!(flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
993 /* nothing to do if y offset is zero */
997 /* nothing to do if there are no contours */
1001 /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */
1002 /* ensures that composite subglyphs are represented as simple glyphs */
1004 if (num_contours
> 0xFF
1005 || curr_contour
> 0xFF)
1008 BCI(HIGH(curr_contour
));
1009 BCI(LOW(curr_contour
));
1010 BCI(HIGH(num_contours
));
1011 BCI(LOW(num_contours
));
1020 /* there are high chances that this value needs PUSHW, */
1021 /* thus we handle it separately */
1022 if (y_offset
> 0xFF || y_offset
< 0)
1025 BCI(HIGH(y_offset
));
1035 BCI(bci_shift_subglyph
);
1039 curr_contour
+= num_contours
;
1047 * The four `ta_ip_*' actions in the `TA_hints_recorder' callback store its
1048 * data in four arrays (which are simple but waste a lot of memory). The
1049 * function below converts them into bytecode.
1051 * For `ta_ip_before' and `ta_ip_after', the collected points are emitted
1052 * together with the edge they correspond to.
1054 * For both `ta_ip_on' and `ta_ip_between', an outer loop is constructed to
1055 * loop over the edge or edge pairs, respectively, and each edge or edge
1056 * pair contains an inner loop to emit the correponding points.
1060 TA_build_point_hints(Recorder
* recorder
,
1061 TA_GlyphHints hints
)
1063 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
1064 TA_Segment segments
= axis
->segments
;
1065 TA_Edge edges
= axis
->edges
;
1067 FT_Byte
* p
= recorder
->hints_record
.buf
;
1072 FT_UShort prev_edge
;
1073 FT_UShort prev_before_edge
;
1074 FT_UShort prev_after_edge
;
1079 Node3
* between_node
;
1082 /* we store everything as 16bit numbers; */
1083 /* the function numbers (`ta_ip_before', etc.) */
1084 /* reflect the order in the TA_Action enumeration */
1086 /* ip_before_points */
1089 for (before_node
= LLRB_MIN(ip_before_points
,
1090 &recorder
->ip_before_points_head
);
1092 before_node
= LLRB_NEXT(ip_before_points
,
1093 &recorder
->ip_before_points_head
,
1105 recorder
->hints_record
.num_actions
++;
1110 *(p
++) = (FT_Byte
)ta_ip_before
+ ACTION_OFFSET
;
1111 *(p
++) = HIGH(edge
->first
- segments
);
1112 *(p
++) = LOW(edge
->first
- segments
);
1116 for (before_node
= LLRB_MIN(ip_before_points
,
1117 &recorder
->ip_before_points_head
);
1119 before_node
= LLRB_NEXT(ip_before_points
,
1120 &recorder
->ip_before_points_head
,
1126 point
= TA_adjust_point_index(recorder
, before_node
->point
);
1127 *(p
++) = HIGH(point
);
1128 *(p
++) = LOW(point
);
1132 /* ip_after_points */
1135 for (after_node
= LLRB_MIN(ip_after_points
,
1136 &recorder
->ip_after_points_head
);
1138 after_node
= LLRB_NEXT(ip_after_points
,
1139 &recorder
->ip_after_points_head
,
1151 recorder
->hints_record
.num_actions
++;
1153 edge
= edges
+ axis
->num_edges
- 1;
1156 *(p
++) = (FT_Byte
)ta_ip_after
+ ACTION_OFFSET
;
1157 *(p
++) = HIGH(edge
->first
- segments
);
1158 *(p
++) = LOW(edge
->first
- segments
);
1162 for (after_node
= LLRB_MIN(ip_after_points
,
1163 &recorder
->ip_after_points_head
);
1165 after_node
= LLRB_NEXT(ip_after_points
,
1166 &recorder
->ip_after_points_head
,
1172 point
= TA_adjust_point_index(recorder
, after_node
->point
);
1173 *(p
++) = HIGH(point
);
1174 *(p
++) = LOW(point
);
1178 /* ip_on_point_array */
1182 for (on_node
= LLRB_MIN(ip_on_points
,
1183 &recorder
->ip_on_points_head
);
1185 on_node
= LLRB_NEXT(ip_on_points
,
1186 &recorder
->ip_on_points_head
,
1190 if (on_node
->edge
!= prev_edge
)
1193 prev_edge
= on_node
->edge
;
1199 recorder
->hints_record
.num_actions
++;
1202 *(p
++) = (FT_Byte
)ta_ip_on
+ ACTION_OFFSET
;
1206 for (on_node
= LLRB_MIN(ip_on_points
,
1207 &recorder
->ip_on_points_head
);
1209 on_node
= LLRB_NEXT(ip_on_points
,
1210 &recorder
->ip_on_points_head
,
1217 edge
= edges
+ on_node
->edge
;
1219 *(p
++) = HIGH(edge
->first
- segments
);
1220 *(p
++) = LOW(edge
->first
- segments
);
1222 /* save current position */
1223 edge_node
= on_node
;
1227 on_node
= LLRB_NEXT(ip_on_points
,
1228 &recorder
->ip_on_points_head
,
1231 /* count points on current edge */
1232 if (on_node
->edge
!= edge_node
->edge
)
1240 /* restore current position */
1241 on_node
= edge_node
;
1244 on_node
= LLRB_NEXT(ip_on_points
,
1245 &recorder
->ip_on_points_head
,
1251 if (on_node
->edge
!= edge_node
->edge
)
1254 point
= TA_adjust_point_index(recorder
, on_node
->point
);
1255 *(p
++) = HIGH(point
);
1256 *(p
++) = LOW(point
);
1258 /* keep track of previous node */
1259 edge_node
= on_node
;
1262 /* reset loop iterator by one element, then continue */
1263 on_node
= edge_node
;
1267 /* ip_between_point_array */
1269 prev_before_edge
= 0xFFFF;
1270 prev_after_edge
= 0xFFFF;
1272 for (between_node
= LLRB_MIN(ip_between_points
,
1273 &recorder
->ip_between_points_head
);
1275 between_node
= LLRB_NEXT(ip_between_points
,
1276 &recorder
->ip_between_points_head
,
1279 /* count `(before,after)' edge pairs */
1280 if (between_node
->before_edge
!= prev_before_edge
1281 || between_node
->after_edge
!= prev_after_edge
)
1284 prev_before_edge
= between_node
->before_edge
;
1285 prev_after_edge
= between_node
->after_edge
;
1291 recorder
->hints_record
.num_actions
++;
1294 *(p
++) = (FT_Byte
)ta_ip_between
+ ACTION_OFFSET
;
1298 for (between_node
= LLRB_MIN(ip_between_points
,
1299 &recorder
->ip_between_points_head
);
1301 between_node
= LLRB_NEXT(ip_between_points
,
1302 &recorder
->ip_between_points_head
,
1305 Node3
* edge_pair_node
;
1310 before
= edges
+ between_node
->before_edge
;
1311 after
= edges
+ between_node
->after_edge
;
1313 *(p
++) = HIGH(after
->first
- segments
);
1314 *(p
++) = LOW(after
->first
- segments
);
1315 *(p
++) = HIGH(before
->first
- segments
);
1316 *(p
++) = LOW(before
->first
- segments
);
1318 /* save current position */
1319 edge_pair_node
= between_node
;
1323 between_node
= LLRB_NEXT(ip_between_points
,
1324 &recorder
->ip_between_points_head
,
1327 /* count points associated with current edge pair */
1328 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1329 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1337 /* restore current position */
1338 between_node
= edge_pair_node
;
1341 between_node
= LLRB_NEXT(ip_between_points
,
1342 &recorder
->ip_between_points_head
,
1348 if (between_node
->before_edge
!= edge_pair_node
->before_edge
1349 || between_node
->after_edge
!= edge_pair_node
->after_edge
)
1352 point
= TA_adjust_point_index(recorder
, between_node
->point
);
1353 *(p
++) = HIGH(point
);
1354 *(p
++) = LOW(point
);
1356 /* keep track of previous node */
1357 edge_pair_node
= between_node
;
1360 /* reset loop iterator by one element, then continue */
1361 between_node
= edge_pair_node
;
1365 recorder
->hints_record
.buf
= p
;
1370 TA_hints_record_is_different(Hints_Record
* hints_records
,
1371 FT_UInt num_hints_records
,
1375 Hints_Record last_hints_record
;
1381 /* we only need to compare with the last hints record */
1382 last_hints_record
= hints_records
[num_hints_records
- 1];
1384 if ((FT_UInt
)(end
- start
) != last_hints_record
.buf_len
)
1387 if (memcmp(start
, last_hints_record
.buf
, last_hints_record
.buf_len
))
1395 TA_add_hints_record(Hints_Record
** hints_records
,
1396 FT_UInt
* num_hints_records
,
1398 Hints_Record hints_record
)
1400 Hints_Record
* hints_records_new
;
1402 /* at this point, `hints_record.buf' still points into `ins_buf' */
1403 FT_Byte
* end
= hints_record
.buf
;
1406 buf_len
= (FT_UInt
)(end
- start
);
1408 /* now fill the structure completely */
1409 hints_record
.buf_len
= buf_len
;
1410 hints_record
.buf
= (FT_Byte
*)malloc(buf_len
);
1411 if (!hints_record
.buf
)
1412 return FT_Err_Out_Of_Memory
;
1414 memcpy(hints_record
.buf
, start
, buf_len
);
1416 (*num_hints_records
)++;
1418 (Hints_Record
*)realloc(*hints_records
, *num_hints_records
1419 * sizeof (Hints_Record
));
1420 if (!hints_records_new
)
1422 free(hints_record
.buf
);
1423 (*num_hints_records
)--;
1424 return FT_Err_Out_Of_Memory
;
1427 *hints_records
= hints_records_new
;
1429 (*hints_records
)[*num_hints_records
- 1] = hints_record
;
1436 TA_emit_hints_record(Recorder
* recorder
,
1437 Hints_Record
* hints_record
,
1443 FT_Bool need_words
= 0;
1446 FT_UInt num_arguments
;
1450 /* check whether any argument is larger than 0xFF */
1451 endp
= hints_record
->buf
+ hints_record
->buf_len
;
1452 for (p
= hints_record
->buf
; p
< endp
; p
+= 2)
1459 /* with most fonts it is very rare */
1460 /* that any of the pushed arguments is larger than 0xFF, */
1461 /* thus we refrain from further optimizing this case */
1463 num_arguments
= hints_record
->buf_len
/ 2;
1468 for (i
= 0; i
< num_arguments
; i
+= 255)
1470 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1472 if (optimize
&& num_args
<= 8)
1473 BCI(PUSHW_1
- 1 + num_args
);
1479 for (j
= 0; j
< num_args
; j
++)
1489 /* we only need the lower bytes */
1492 for (i
= 0; i
< num_arguments
; i
+= 255)
1494 num_args
= (num_arguments
- i
> 255) ? 255 : (num_arguments
- i
);
1496 if (optimize
&& num_args
<= 8)
1497 BCI(PUSHB_1
- 1 + num_args
);
1503 for (j
= 0; j
< num_args
; j
++)
1511 /* collect stack depth data */
1512 if (num_arguments
> recorder
->num_stack_elements
)
1513 recorder
->num_stack_elements
= num_arguments
;
1520 TA_emit_hints_records(Recorder
* recorder
,
1521 Hints_Record
* hints_records
,
1522 FT_UInt num_hints_records
,
1527 Hints_Record
* hints_record
;
1530 hints_record
= hints_records
;
1532 /* emit hints records in `if' clauses, */
1533 /* with the ppem size as the condition */
1534 for (i
= 0; i
< num_hints_records
- 1; i
++)
1537 if (hints_record
->size
> 0xFF)
1540 BCI(HIGH((hints_record
+ 1)->size
));
1541 BCI(LOW((hints_record
+ 1)->size
));
1546 BCI((hints_record
+ 1)->size
);
1550 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1556 bufp
= TA_emit_hints_record(recorder
, hints_record
, bufp
, optimize
);
1558 for (i
= 0; i
< num_hints_records
- 1; i
++)
1566 TA_free_hints_records(Hints_Record
* hints_records
,
1567 FT_UInt num_hints_records
)
1572 for (i
= 0; i
< num_hints_records
; i
++)
1573 free(hints_records
[i
].buf
);
1575 free(hints_records
);
1580 TA_hints_recorder_handle_segments(FT_Byte
* bufp
,
1585 TA_Segment segments
= axis
->segments
;
1588 FT_UShort num_segs
= 0;
1592 seg_idx
= edge
->first
- segments
;
1594 /* we store everything as 16bit numbers */
1595 *(bufp
++) = HIGH(seg_idx
);
1596 *(bufp
++) = LOW(seg_idx
);
1598 /* wrap-around segments are stored as two segments */
1599 if (edge
->first
->first
> edge
->first
->last
)
1602 seg
= edge
->first
->edge_next
;
1603 while (seg
!= edge
->first
)
1607 if (seg
->first
> seg
->last
)
1610 seg
= seg
->edge_next
;
1613 *(bufp
++) = HIGH(num_segs
);
1614 *(bufp
++) = LOW(num_segs
);
1616 if (edge
->first
->first
> edge
->first
->last
)
1618 /* emit second part of wrap-around segment; */
1619 /* the bytecode positions such segments after `normal' ones */
1623 if (seg_idx
== *wrap
)
1628 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1629 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1632 seg
= edge
->first
->edge_next
;
1633 while (seg
!= edge
->first
)
1635 seg_idx
= seg
- segments
;
1637 *(bufp
++) = HIGH(seg_idx
);
1638 *(bufp
++) = LOW(seg_idx
);
1640 if (seg
->first
> seg
->last
)
1645 if (seg_idx
== *wrap
)
1650 *(bufp
++) = HIGH(axis
->num_segments
+ (wrap
- wraps
));
1651 *(bufp
++) = LOW(axis
->num_segments
+ (wrap
- wraps
));
1654 seg
= seg
->edge_next
;
1662 TA_hints_recorder(TA_Action action
,
1663 TA_GlyphHints hints
,
1668 TA_Edge lower_bound
,
1669 TA_Edge upper_bound
)
1671 TA_AxisHints axis
= &hints
->axis
[dim
];
1672 TA_Edge edges
= axis
->edges
;
1673 TA_Segment segments
= axis
->segments
;
1674 TA_Point points
= hints
->points
;
1676 Recorder
* recorder
= (Recorder
*)hints
->user
;
1677 SFNT
* sfnt
= recorder
->sfnt
;
1678 FONT
* font
= recorder
->font
;
1679 FT_UShort
* wraps
= recorder
->wrap_around_segments
;
1680 FT_Byte
* p
= recorder
->hints_record
.buf
;
1682 FT_UInt style
= font
->loader
->metrics
->style_class
->style
;
1685 if (dim
== TA_DIMENSION_HORZ
)
1688 /* we collect point hints for later processing */
1694 TA_Point point
= (TA_Point
)arg1
;
1697 before_node
= (Node1
*)malloc(sizeof (Node1
));
1700 before_node
->point
= point
- points
;
1702 LLRB_INSERT(ip_before_points
,
1703 &recorder
->ip_before_points_head
,
1711 TA_Point point
= (TA_Point
)arg1
;
1714 after_node
= (Node1
*)malloc(sizeof (Node1
));
1717 after_node
->point
= point
- points
;
1719 LLRB_INSERT(ip_after_points
,
1720 &recorder
->ip_after_points_head
,
1728 TA_Point point
= (TA_Point
)arg1
;
1729 TA_Edge edge
= arg2
;
1732 on_node
= (Node2
*)malloc(sizeof (Node2
));
1735 on_node
->edge
= edge
- edges
;
1736 on_node
->point
= point
- points
;
1738 LLRB_INSERT(ip_on_points
,
1739 &recorder
->ip_on_points_head
,
1746 Node3
* between_node
;
1747 TA_Point point
= (TA_Point
)arg1
;
1748 TA_Edge before
= arg2
;
1749 TA_Edge after
= arg3
;
1752 between_node
= (Node3
*)malloc(sizeof (Node3
));
1755 between_node
->before_edge
= before
- edges
;
1756 between_node
->after_edge
= after
- edges
;
1757 between_node
->point
= point
- points
;
1759 LLRB_INSERT(ip_between_points
,
1760 &recorder
->ip_between_points_head
,
1766 /* we ignore the BOUND action since we signal this information */
1767 /* with the proper function number */
1774 /* some enum values correspond to four or eight bytecode functions; */
1775 /* if the value is n, the function numbers are n, ..., n+7, */
1776 /* to be differentiated with flags */
1782 TA_Edge base_edge
= (TA_Edge
)arg1
;
1783 TA_Edge stem_edge
= arg2
;
1787 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1788 + ((stem_edge
->flags
& TA_EDGE_SERIF
) != 0)
1789 + 2 * ((base_edge
->flags
& TA_EDGE_ROUND
) != 0);
1791 *(p
++) = HIGH(base_edge
->first
- segments
);
1792 *(p
++) = LOW(base_edge
->first
- segments
);
1793 *(p
++) = HIGH(stem_edge
->first
- segments
);
1794 *(p
++) = LOW(stem_edge
->first
- segments
);
1796 p
= TA_hints_recorder_handle_segments(p
, axis
, stem_edge
, wraps
);
1802 TA_Edge edge
= (TA_Edge
)arg1
;
1803 TA_Edge edge2
= arg2
;
1807 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1808 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1809 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0);
1811 *(p
++) = HIGH(edge
->first
- segments
);
1812 *(p
++) = LOW(edge
->first
- segments
);
1813 *(p
++) = HIGH(edge2
->first
- segments
);
1814 *(p
++) = LOW(edge2
->first
- segments
);
1816 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1822 TA_Edge edge
= (TA_Edge
)arg1
;
1823 TA_Edge edge2
= arg2
;
1824 TA_Edge edge_minus_one
= lower_bound
;
1828 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1829 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1830 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1831 + 4 * (edge_minus_one
!= NULL
);
1833 *(p
++) = HIGH(edge
->first
- segments
);
1834 *(p
++) = LOW(edge
->first
- segments
);
1835 *(p
++) = HIGH(edge2
->first
- segments
);
1836 *(p
++) = LOW(edge2
->first
- segments
);
1840 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1841 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1844 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1848 case ta_blue_anchor
:
1850 TA_Edge edge
= (TA_Edge
)arg1
;
1851 TA_Edge blue
= arg2
;
1855 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1857 *(p
++) = HIGH(blue
->first
- segments
);
1858 *(p
++) = LOW(blue
->first
- segments
);
1860 if (edge
->best_blue_is_shoot
)
1862 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1863 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1867 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1868 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1871 *(p
++) = HIGH(edge
->first
- segments
);
1872 *(p
++) = LOW(edge
->first
- segments
);
1874 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1880 TA_Edge edge
= (TA_Edge
)arg1
;
1881 TA_Edge edge2
= arg2
;
1882 TA_Edge edge_minus_one
= lower_bound
;
1886 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1887 + ((edge2
->flags
& TA_EDGE_SERIF
) != 0)
1888 + 2 * ((edge
->flags
& TA_EDGE_ROUND
) != 0)
1889 + 4 * (edge_minus_one
!= NULL
);
1891 *(p
++) = HIGH(edge
->first
- segments
);
1892 *(p
++) = LOW(edge
->first
- segments
);
1893 *(p
++) = HIGH(edge2
->first
- segments
);
1894 *(p
++) = LOW(edge2
->first
- segments
);
1898 *(p
++) = HIGH(edge_minus_one
->first
- segments
);
1899 *(p
++) = LOW(edge_minus_one
->first
- segments
);
1902 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1903 p
= TA_hints_recorder_handle_segments(p
, axis
, edge2
, wraps
);
1909 TA_Edge edge
= (TA_Edge
)arg1
;
1913 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
;
1915 if (edge
->best_blue_is_shoot
)
1917 *(p
++) = HIGH(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1918 *(p
++) = LOW(CVT_BLUE_SHOOTS_OFFSET(style
) + edge
->best_blue_idx
);
1922 *(p
++) = HIGH(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1923 *(p
++) = LOW(CVT_BLUE_REFS_OFFSET(style
) + edge
->best_blue_idx
);
1926 *(p
++) = HIGH(edge
->first
- segments
);
1927 *(p
++) = LOW(edge
->first
- segments
);
1929 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1935 TA_Edge serif
= (TA_Edge
)arg1
;
1936 TA_Edge base
= serif
->serif
;
1940 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1941 + (lower_bound
!= NULL
)
1942 + 2 * (upper_bound
!= NULL
);
1944 *(p
++) = HIGH(serif
->first
- segments
);
1945 *(p
++) = LOW(serif
->first
- segments
);
1946 *(p
++) = HIGH(base
->first
- segments
);
1947 *(p
++) = LOW(base
->first
- segments
);
1951 *(p
++) = HIGH(lower_bound
->first
- segments
);
1952 *(p
++) = LOW(lower_bound
->first
- segments
);
1956 *(p
++) = HIGH(upper_bound
->first
- segments
);
1957 *(p
++) = LOW(upper_bound
->first
- segments
);
1960 p
= TA_hints_recorder_handle_segments(p
, axis
, serif
, wraps
);
1964 case ta_serif_anchor
:
1965 case ta_serif_link2
:
1967 TA_Edge edge
= (TA_Edge
)arg1
;
1971 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
1972 + (lower_bound
!= NULL
)
1973 + 2 * (upper_bound
!= NULL
);
1975 *(p
++) = HIGH(edge
->first
- segments
);
1976 *(p
++) = LOW(edge
->first
- segments
);
1980 *(p
++) = HIGH(lower_bound
->first
- segments
);
1981 *(p
++) = LOW(lower_bound
->first
- segments
);
1985 *(p
++) = HIGH(upper_bound
->first
- segments
);
1986 *(p
++) = LOW(upper_bound
->first
- segments
);
1989 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
1993 case ta_serif_link1
:
1995 TA_Edge edge
= (TA_Edge
)arg1
;
1996 TA_Edge before
= arg2
;
1997 TA_Edge after
= arg3
;
2001 *(p
++) = (FT_Byte
)action
+ ACTION_OFFSET
2002 + (lower_bound
!= NULL
)
2003 + 2 * (upper_bound
!= NULL
);
2005 *(p
++) = HIGH(before
->first
- segments
);
2006 *(p
++) = LOW(before
->first
- segments
);
2007 *(p
++) = HIGH(edge
->first
- segments
);
2008 *(p
++) = LOW(edge
->first
- segments
);
2009 *(p
++) = HIGH(after
->first
- segments
);
2010 *(p
++) = LOW(after
->first
- segments
);
2014 *(p
++) = HIGH(lower_bound
->first
- segments
);
2015 *(p
++) = LOW(lower_bound
->first
- segments
);
2019 *(p
++) = HIGH(upper_bound
->first
- segments
);
2020 *(p
++) = LOW(upper_bound
->first
- segments
);
2023 p
= TA_hints_recorder_handle_segments(p
, axis
, edge
, wraps
);
2028 /* there are more cases in the enumeration */
2029 /* which are handled with flags */
2033 recorder
->hints_record
.num_actions
++;
2034 recorder
->hints_record
.buf
= p
;
2039 TA_init_recorder(Recorder
* recorder
,
2043 TA_GlyphHints hints
)
2045 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_VERT
];
2046 TA_Point points
= hints
->points
;
2047 TA_Point point_limit
= points
+ hints
->num_points
;
2050 TA_Segment segments
= axis
->segments
;
2051 TA_Segment seg_limit
= segments
+ axis
->num_segments
;
2054 FT_UShort num_strong_points
= 0;
2055 FT_UShort
* wrap_around_segment
;
2057 recorder
->sfnt
= sfnt
;
2058 recorder
->font
= font
;
2059 recorder
->glyph
= glyph
;
2060 recorder
->num_segments
= axis
->num_segments
;
2062 LLRB_INIT(&recorder
->ip_before_points_head
);
2063 LLRB_INIT(&recorder
->ip_after_points_head
);
2064 LLRB_INIT(&recorder
->ip_on_points_head
);
2065 LLRB_INIT(&recorder
->ip_between_points_head
);
2067 recorder
->num_stack_elements
= 0;
2069 /* no need to clean up allocated arrays in case of error; */
2070 /* this is handled later by `TA_free_recorder' */
2072 recorder
->num_wrap_around_segments
= 0;
2073 for (seg
= segments
; seg
< seg_limit
; seg
++)
2074 if (seg
->first
> seg
->last
)
2075 recorder
->num_wrap_around_segments
++;
2077 recorder
->wrap_around_segments
=
2078 (FT_UShort
*)malloc(recorder
->num_wrap_around_segments
2079 * sizeof (FT_UShort
));
2080 if (!recorder
->wrap_around_segments
)
2081 return FT_Err_Out_Of_Memory
;
2083 wrap_around_segment
= recorder
->wrap_around_segments
;
2084 for (seg
= segments
; seg
< seg_limit
; seg
++)
2085 if (seg
->first
> seg
->last
)
2086 *(wrap_around_segment
++) = seg
- segments
;
2088 /* get number of strong points */
2089 for (point
= points
; point
< point_limit
; point
++)
2091 /* actually, we need to test `TA_FLAG_TOUCH_Y' also; */
2092 /* however, this value isn't known yet */
2093 /* (or rather, it can vary between different pixel sizes) */
2094 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
2097 num_strong_points
++;
2100 recorder
->num_strong_points
= num_strong_points
;
2107 TA_reset_recorder(Recorder
* recorder
,
2110 recorder
->hints_record
.buf
= bufp
;
2111 recorder
->hints_record
.num_actions
= 0;
2116 TA_rewind_recorder(Recorder
* recorder
,
2123 Node3
* between_node
;
2125 Node1
* next_before_node
;
2126 Node1
* next_after_node
;
2127 Node2
* next_on_node
;
2128 Node3
* next_between_node
;
2131 TA_reset_recorder(recorder
, bufp
);
2133 recorder
->hints_record
.size
= size
;
2135 /* deallocate our red-black trees */
2137 for (before_node
= LLRB_MIN(ip_before_points
,
2138 &recorder
->ip_before_points_head
);
2140 before_node
= next_before_node
)
2142 next_before_node
= LLRB_NEXT(ip_before_points
,
2143 &recorder
->ip_before_points_head
,
2145 LLRB_REMOVE(ip_before_points
,
2146 &recorder
->ip_before_points_head
,
2151 for (after_node
= LLRB_MIN(ip_after_points
,
2152 &recorder
->ip_after_points_head
);
2154 after_node
= next_after_node
)
2156 next_after_node
= LLRB_NEXT(ip_after_points
,
2157 &recorder
->ip_after_points_head
,
2159 LLRB_REMOVE(ip_after_points
,
2160 &recorder
->ip_after_points_head
,
2165 for (on_node
= LLRB_MIN(ip_on_points
,
2166 &recorder
->ip_on_points_head
);
2168 on_node
= next_on_node
)
2170 next_on_node
= LLRB_NEXT(ip_on_points
,
2171 &recorder
->ip_on_points_head
,
2173 LLRB_REMOVE(ip_on_points
,
2174 &recorder
->ip_on_points_head
,
2179 for (between_node
= LLRB_MIN(ip_between_points
,
2180 &recorder
->ip_between_points_head
);
2182 between_node
= next_between_node
)
2184 next_between_node
= LLRB_NEXT(ip_between_points
,
2185 &recorder
->ip_between_points_head
,
2187 LLRB_REMOVE(ip_between_points
,
2188 &recorder
->ip_between_points_head
,
2196 TA_free_recorder(Recorder
* recorder
)
2198 free(recorder
->wrap_around_segments
);
2200 TA_rewind_recorder(recorder
, NULL
, 0);
2205 TA_sfnt_build_glyph_instructions(SFNT
* sfnt
,
2209 FT_Face face
= sfnt
->face
;
2217 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
2218 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
2219 /* `idx' is never negative */
2220 GLYPH
* glyph
= &data
->glyphs
[idx
];
2222 TA_GlyphHints hints
;
2224 FT_UInt num_action_hints_records
= 0;
2225 FT_UInt num_point_hints_records
= 0;
2226 Hints_Record
* action_hints_records
= NULL
;
2227 Hints_Record
* point_hints_records
= NULL
;
2230 FT_UShort num_stack_elements
;
2231 FT_Bool optimize
= 0;
2233 FT_Int32 load_flags
;
2243 /* XXX: right now, we abuse this flag to control */
2244 /* the global behaviour of the auto-hinter */
2245 load_flags
= 1 << 29; /* vertical hinting only */
2246 if (!font
->adjust_subglyphs
)
2248 if (font
->hint_composites
)
2249 load_flags
|= FT_LOAD_NO_SCALE
;
2251 load_flags
|= FT_LOAD_NO_RECURSE
;
2254 /* computing the segments is resolution independent, */
2255 /* thus the pixel size in this call is arbitrary -- */
2256 /* however, we avoid unnecessary debugging output */
2257 /* if we use the lowest value of the hinting range */
2258 error
= FT_Set_Pixel_Sizes(face
,
2259 font
->hinting_range_min
,
2260 font
->hinting_range_min
);
2265 /* temporarily disable some debugging output */
2266 /* to avoid getting the information twice */
2267 _ta_debug_save
= _ta_debug
;
2271 ta_loader_register_hints_recorder(font
->loader
, NULL
, NULL
);
2272 error
= ta_loader_load_glyph(font
, face
, (FT_UInt
)idx
, load_flags
);
2275 _ta_debug
= _ta_debug_save
;
2281 /* do nothing if we have an empty glyph */
2282 if (!face
->glyph
->outline
.n_contours
)
2285 hints
= &font
->loader
->hints
;
2287 /* do nothing if the setup delivered the `none_dflt' style only */
2288 if (!hints
->num_points
)
2292 * We allocate a buffer which is certainly large enough
2293 * to hold all of the created bytecode instructions;
2294 * later on it gets reallocated to its real size.
2296 * The value `1000' is a very rough guess, not tested well.
2298 * For delta exceptions, we have three DELTA commands,
2299 * covering 3*16 ppem values.
2300 * Since a point index can be larger than 255,
2301 * we assume two bytes everywhere for the necessary PUSH calls.
2302 * This value must be doubled for the other arguments of DELTA.
2303 * Additionally, we have both x and y deltas,
2304 * which need to be handled separately in the bytecode.
2305 * In summary, this is approx. 3*16 * 2*2 * 2 = 400 bytes per point,
2306 * adding some bytes for the necessary overhead.
2308 ins_len
= hints
->num_points
2309 * (1000 + ((font
->deltas_data_head
!= NULL
) ? 400 : 0));
2310 ins_buf
= (FT_Byte
*)malloc(ins_len
);
2312 return FT_Err_Out_Of_Memory
;
2314 /* handle composite glyph */
2315 if (font
->loader
->gloader
->base
.num_subglyphs
)
2317 bufp
= TA_font_build_subglyph_shifter(font
, ins_buf
);
2320 error
= FT_Err_Out_Of_Memory
;
2327 /* only scale the glyph if the `none_dflt' style has been used */
2328 if (font
->loader
->metrics
->style_class
== &ta_none_dflt_style_class
)
2330 /* since `TA_init_recorder' hasn't been called yet, */
2331 /* we manually initialize the `sfnt', `font', and `glyph' fields */
2332 recorder
.sfnt
= sfnt
;
2333 recorder
.font
= font
;
2334 recorder
.glyph
= glyph
;
2336 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2339 error
= FT_Err_Out_Of_Memory
;
2346 error
= TA_init_recorder(&recorder
, sfnt
, font
, glyph
, hints
);
2350 /* loop over a large range of pixel sizes */
2351 /* to find hints records which get pushed onto the bytecode stack */
2360 (void)FT_Get_Glyph_Name(face
, idx
, buf
, 256);
2362 num_chars
= fprintf(stderr
, "glyph %ld", idx
);
2364 num_chars
+= fprintf(stderr
, " (%s)", buf
);
2365 fprintf(stderr
, "\n");
2366 for (i
= 0; i
< num_chars
; i
++)
2368 fprintf(stderr
, "\n\n");
2373 /* we temporarily use `ins_buf' to record the current glyph hints */
2374 ta_loader_register_hints_recorder(font
->loader
,
2378 for (size
= font
->hinting_range_min
;
2379 size
<= font
->hinting_range_max
;
2387 TA_rewind_recorder(&recorder
, ins_buf
, size
);
2389 error
= FT_Set_Pixel_Sizes(face
, size
, size
);
2399 num_chars
= fprintf(stderr
, "size %d\n", size
);
2400 for (i
= 0; i
< num_chars
- 1; i
++)
2402 fprintf(stderr
, "\n\n");
2406 /* calling `ta_loader_load_glyph' uses the */
2407 /* `TA_hints_recorder' function as a callback, */
2408 /* modifying `hints_record' */
2409 error
= ta_loader_load_glyph(font
, face
, idx
, load_flags
);
2413 if (TA_hints_record_is_different(action_hints_records
,
2414 num_action_hints_records
,
2415 ins_buf
, recorder
.hints_record
.buf
))
2422 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2423 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2424 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2426 fprintf(stderr
, "action hints record:\n");
2427 if (ins_buf
== recorder
.hints_record
.buf
)
2428 fprintf(stderr
, " (none)");
2431 fprintf(stderr
, " ");
2432 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2433 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2435 fprintf(stderr
, "\n");
2439 error
= TA_add_hints_record(&action_hints_records
,
2440 &num_action_hints_records
,
2441 ins_buf
, recorder
.hints_record
);
2446 /* now handle point records */
2448 TA_reset_recorder(&recorder
, ins_buf
);
2450 /* use the point hints data collected in `TA_hints_recorder' */
2451 TA_build_point_hints(&recorder
, hints
);
2453 if (TA_hints_record_is_different(point_hints_records
,
2454 num_point_hints_records
,
2455 ins_buf
, recorder
.hints_record
.buf
))
2465 num_chars
= fprintf(stderr
, "size %d\n", size
);
2466 for (i
= 0; i
< num_chars
- 1; i
++)
2468 fprintf(stderr
, "\n\n");
2470 ta_glyph_hints_dump_edges((TA_GlyphHints
)_ta_debug_hints
);
2471 ta_glyph_hints_dump_segments((TA_GlyphHints
)_ta_debug_hints
);
2472 ta_glyph_hints_dump_points((TA_GlyphHints
)_ta_debug_hints
);
2475 fprintf(stderr
, "point hints record:\n");
2476 if (ins_buf
== recorder
.hints_record
.buf
)
2477 fprintf(stderr
, " (none)");
2480 fprintf(stderr
, " ");
2481 for (p
= ins_buf
; p
< recorder
.hints_record
.buf
; p
+= 2)
2482 fprintf(stderr
, " %2d", *p
* 256 + *(p
+ 1));
2484 fprintf(stderr
, "\n\n");
2488 error
= TA_add_hints_record(&point_hints_records
,
2489 &num_point_hints_records
,
2490 ins_buf
, recorder
.hints_record
);
2496 if (num_action_hints_records
== 1 && !action_hints_records
[0].num_actions
)
2498 /* since we only have a single empty record we just scale the glyph */
2499 bufp
= TA_sfnt_build_glyph_scaler(sfnt
, &recorder
, ins_buf
);
2502 error
= FT_Err_Out_Of_Memory
;
2509 /* if there is only a single record, */
2510 /* we do a global optimization later on */
2511 if (num_action_hints_records
> 1)
2514 /* store the hints records and handle stack depth */
2516 bufp
= TA_emit_hints_records(&recorder
,
2517 point_hints_records
,
2518 num_point_hints_records
,
2522 num_stack_elements
= recorder
.num_stack_elements
;
2523 recorder
.num_stack_elements
= 0;
2526 bufp
= TA_emit_hints_records(&recorder
,
2527 action_hints_records
,
2528 num_action_hints_records
,
2532 recorder
.num_stack_elements
+= num_stack_elements
;
2535 bufp
= TA_sfnt_build_glyph_segments(sfnt
, &recorder
, bufp
, optimize
);
2538 error
= FT_Err_Out_Of_Memory
;
2542 if (num_action_hints_records
== 1)
2543 bufp
= TA_optimize_push(ins_buf
, pos
);
2546 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2547 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2548 TA_free_recorder(&recorder
);
2551 /* handle delta exceptions */
2552 if (font
->deltas_data_head
)
2554 bufp
= TA_sfnt_build_delta_exceptions(sfnt
, font
, idx
, bufp
);
2557 error
= FT_Err_Out_Of_Memory
;
2562 ins_len
= bufp
- ins_buf
;
2564 if (ins_len
> sfnt
->max_instructions
)
2565 sfnt
->max_instructions
= ins_len
;
2567 glyph
->ins_buf
= (FT_Byte
*)realloc(ins_buf
, ins_len
);
2568 glyph
->ins_len
= ins_len
;
2573 TA_free_hints_records(action_hints_records
, num_action_hints_records
);
2574 TA_free_hints_records(point_hints_records
, num_point_hints_records
);
2575 TA_free_recorder(&recorder
);
2582 /* end of tabytecode.c */