4 * Copyright (C) 2014-2022 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
24 #include <stdbool.h> /* for llrb.h */
26 #include "llrb.h" /* a red-black tree implementation */
27 #include "tacontrol-bison.h"
31 TA_control_new(Control_Type type
,
34 number_range
* point_set
,
37 number_range
* ppem_set
,
43 control
= (Control
*)malloc(sizeof (Control
));
48 control
->font_idx
= font_idx
;
49 control
->glyph_idx
= glyph_idx
;
50 control
->points
= number_set_reverse(point_set
);
52 switch (control
->type
)
54 case Control_Delta_before_IUP
:
55 case Control_Delta_after_IUP
:
56 /* we round shift values to multiples of 1/(2^CONTROL_DELTA_SHIFT) */
57 control
->x_shift
= (int)(x_shift
* CONTROL_DELTA_FACTOR
58 + (x_shift
> 0 ? 0.5 : -0.5));
59 control
->y_shift
= (int)(y_shift
* CONTROL_DELTA_FACTOR
60 + (y_shift
> 0 ? 0.5 : -0.5));
63 case Control_Single_Point_Segment_Left
:
64 case Control_Single_Point_Segment_Right
:
66 control
->x_shift
= (int)x_shift
;
67 control
->y_shift
= (int)y_shift
;
70 case Control_Single_Point_Segment_None
:
75 case Control_Script_Feature_Glyphs
:
76 /* the `glyph_idx' field holds the style; */
77 /* the `points' field holds the glyph index set */
80 case Control_Script_Feature_Widths
:
81 /* the `glyph_idx' field holds the style */
82 /* (or a feature for all scripts); */
83 /* the `points' field holds the width set; */
87 control
->ppems
= number_set_reverse(ppem_set
);
90 control
->line_number
= line_number
;
97 TA_control_prepend(Control
* list
,
103 element
->next
= list
;
110 TA_control_reverse(Control
* list
)
134 TA_control_free(Control
* control
)
141 number_set_free(control
->points
);
142 number_set_free(control
->ppems
);
145 control
= control
->next
;
152 control_show_line(FONT
* font
,
155 char glyph_name_buf
[64];
156 char* points_buf
= NULL
;
157 char* ppems_buf
= NULL
;
169 if (control
->font_idx
>= font
->num_sfnts
)
172 face
= font
->sfnts
[control
->font_idx
].face
;
173 glyph_name_buf
[0] = '\0';
174 if (!(control
->type
== Control_Script_Feature_Glyphs
175 || control
->type
== Control_Script_Feature_Widths
)
176 && FT_HAS_GLYPH_NAMES(face
))
177 FT_Get_Glyph_Name(face
, (FT_UInt
)control
->glyph_idx
, glyph_name_buf
, 64);
179 points_buf
= number_set_show(control
->points
, -1, -1);
182 ppems_buf
= number_set_show(control
->ppems
, -1, -1);
186 switch (control
->type
)
188 case Control_Delta_before_IUP
:
189 case Control_Delta_after_IUP
:
190 /* display glyph index if we don't have a glyph name */
192 s
= sdscatprintf(s
, "%ld %s %s %s xshift %.20g yshift %.20g @ %s",
195 control
->type
== Control_Delta_before_IUP
? "touch"
198 (double)control
->x_shift
/ CONTROL_DELTA_FACTOR
,
199 (double)control
->y_shift
/ CONTROL_DELTA_FACTOR
,
202 s
= sdscatprintf(s
, "%ld %ld point %s xshift %.20g yshift %.20g @ %s",
206 (double)control
->x_shift
/ CONTROL_DELTA_FACTOR
,
207 (double)control
->y_shift
/ CONTROL_DELTA_FACTOR
,
211 case Control_Single_Point_Segment_Left
:
212 case Control_Single_Point_Segment_Right
:
213 /* display glyph index if we don't have a glyph name */
215 s
= sdscatprintf(s
, "%ld %s %s %s",
218 control
->type
== Control_Single_Point_Segment_Left
222 s
= sdscatprintf(s
, "%ld %ld %s %s",
225 control
->type
== Control_Single_Point_Segment_Left
229 if (control
->x_shift
|| control
->y_shift
)
230 s
= sdscatprintf(s
, " (%d,%d)", control
->x_shift
, control
->y_shift
);
233 case Control_Single_Point_Segment_None
:
234 /* display glyph index if we don't have a glyph name */
236 s
= sdscatprintf(s
, "%ld %s nodir %s",
241 s
= sdscatprintf(s
, "%ld %ld nodir %s",
247 case Control_Script_Feature_Glyphs
:
249 TA_StyleClass style_class
= ta_style_classes
[control
->glyph_idx
];
250 char feature_name
[5];
253 feature_name
[4] = '\0';
254 hb_tag_to_string(feature_tags
[style_class
->coverage
], feature_name
);
256 s
= sdscatprintf(s
, "%ld %s %s @ %s",
258 script_names
[style_class
->script
],
264 case Control_Script_Feature_Widths
:
266 char feature_name
[5];
267 const char* script_name
;
270 feature_name
[4] = '\0';
272 if (control
->glyph_idx
> 0)
274 TA_StyleClass style_class
= ta_style_classes
[control
->glyph_idx
];
277 script_name
= script_names
[style_class
->script
];
278 hb_tag_to_string(feature_tags
[style_class
->coverage
], feature_name
);
283 hb_tag_to_string(feature_tags
[-control
->glyph_idx
], feature_name
);
286 s
= sdscatprintf(s
, "%ld %s %s width %s",
303 TA_control_show(FONT
* font
)
309 Control
* control
= font
->control
;
319 /* append current line to buffer, followed by a newline character */
320 d
= control_show_line(font
, control
);
330 control
= control
->next
;
336 /* we return an empty string if there is no data */
338 res
= (char*)malloc(len
);
348 /* Parse control instructions in `font->control_buf'. */
351 TA_control_parse_buffer(FONT
* font
,
352 char** error_string_p
,
353 unsigned int* errlinenum_p
,
359 Control_Context context
;
362 /* nothing to do if no data */
363 if (!font
->control_buf
)
365 font
->control
= NULL
;
369 TA_control_scanner_init(&context
, font
);
372 /* this is `yyparse' in disguise */
373 bison_error
= TA_control_parse(&context
);
374 TA_control_scanner_done(&context
);
378 if (bison_error
== 2)
379 context
.error
= TA_Err_Control_Allocation_Error
;
382 font
->control
= NULL
;
384 if (context
.error
== TA_Err_Control_Allocation_Error
385 || context
.error
== TA_Err_Control_Flex_Error
)
391 *error_string_p
= strdup(context
.errmsg
);
393 *error_string_p
= strdup(TA_get_error_message(context
.error
));
405 /* construct data for `errline_p' */
406 buf_end
= font
->control_buf
+ font
->control_len
;
408 p_start
= font
->control_buf
;
409 if (context
.errline_num
> 1)
412 while (p_start
< buf_end
)
414 if (*p_start
++ == '\n')
417 if (i
== context
.errline_num
)
424 while (p_end
< buf_end
)
430 *errline_p
= strndup(p_start
, (size_t)(p_end
- p_start
));
432 /* construct data for `error_string_p' */
433 if (context
.error
== TA_Err_Control_Invalid_Font_Index
)
434 sprintf(auxbuf
, " (valid range is [%ld;%ld])",
437 else if (context
.error
== TA_Err_Control_Invalid_Glyph_Index
)
438 sprintf(auxbuf
, " (valid range is [%ld;%ld])",
440 font
->sfnts
[context
.font_idx
].face
->num_glyphs
);
441 else if (context
.error
== TA_Err_Control_Invalid_Shift
)
442 sprintf(auxbuf
, " (valid interval is [%g;%g])",
443 CONTROL_DELTA_SHIFT_MIN
,
444 CONTROL_DELTA_SHIFT_MAX
);
445 else if (context
.error
== TA_Err_Control_Invalid_Offset
)
446 sprintf(auxbuf
, " (valid interval is [%d;%d])",
449 else if (context
.error
== TA_Err_Control_Invalid_Range
)
450 sprintf(auxbuf
, " (values must be within [%d;%d])",
451 context
.number_set_min
,
452 context
.number_set_max
);
456 ret
= asprintf(error_string_p
, "%s%s",
457 *context
.errmsg
? context
.errmsg
458 : TA_get_error_message(context
.error
),
461 *error_string_p
= NULL
;
464 *errpos_p
= *errline_p
+ context
.errline_pos_left
- 1;
468 *errlinenum_p
= (unsigned int)context
.errline_num
;
472 font
->control
= context
.result
;
474 return context
.error
;
478 /* apply coverage data from the control instructions file */
481 TA_control_apply_coverage(SFNT
* sfnt
,
484 Control
* control
= font
->control
;
485 TA_FaceGlobals globals
= (TA_FaceGlobals
)sfnt
->face
->autohint
.data
;
486 FT_UShort
* gstyles
= globals
->glyph_styles
;
491 number_set_iter glyph_idx_iter
;
496 if (control
->type
!= Control_Script_Feature_Glyphs
)
498 if (control
->font_idx
!= sfnt
->face
->face_index
)
501 /* `control->glyph_idx' holds the style; */
502 /* `control->points' holds the glyph index set */
503 style
= (int)control
->glyph_idx
;
504 glyph_idx_iter
.range
= control
->points
;
505 glyph_idx
= number_set_get_first(&glyph_idx_iter
);
507 while (glyph_idx
>= 0)
509 /* assign new style but retain digit property */
510 gstyles
[glyph_idx
] &= TA_DIGIT
;
511 gstyles
[glyph_idx
] |= style
;
513 glyph_idx
= number_set_get_next(&glyph_idx_iter
);
517 control
= control
->next
;
522 /* handle stem width data from the control instructions file; */
525 TA_control_set_stem_widths(TA_LatinMetrics metrics
,
528 Control
* control
= font
->control
;
529 FT_Face face
= font
->loader
->face
;
530 TA_WidthRec
* widths
= metrics
->axis
[TA_DIMENSION_VERT
].widths
;
535 TA_StyleClass style_class
= metrics
->root
.style_class
;
537 number_set_iter width_iter
;
542 if (control
->type
!= Control_Script_Feature_Widths
)
544 if (control
->font_idx
!= face
->face_index
)
546 /* `control->glyph_idx' holds either a style */
547 /* or a feature for all scripts */
548 if (!(control
->glyph_idx
== style_class
->style
549 || -control
->glyph_idx
== style_class
->coverage
))
552 /* `control->points' holds the width set */
553 width_iter
.range
= control
->points
;
554 width
= number_set_get_first(&width_iter
);
559 widths
[i
++].org
= width
;
560 width
= number_set_get_next(&width_iter
);
562 metrics
->axis
[TA_DIMENSION_VERT
].width_count
= i
;
565 control
= control
->next
;
570 /* node structure for control instruction data */
572 typedef struct Node Node
;
575 LLRB_ENTRY(Node
) entry
;
580 /* comparison function for our red-black tree */
589 /* sort by font index ... */
590 diff
= e1
->ctrl
.font_idx
- e2
->ctrl
.font_idx
;
594 /* ... then by glyph index ... */
595 diff
= e1
->ctrl
.glyph_idx
- e2
->ctrl
.glyph_idx
;
599 /* ... then by ppem ... */
600 diff
= e1
->ctrl
.ppem
- e2
->ctrl
.ppem
;
604 /* ... then by point index */
605 diff
= e1
->ctrl
.point_idx
- e2
->ctrl
.point_idx
;
608 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
609 return (diff
> 0) - (diff
< 0);
613 /* the red-black tree function body */
614 typedef struct control_data control_data
;
616 LLRB_HEAD(control_data
, Node
);
618 /* no trailing semicolon in the next line */
619 LLRB_GENERATE_STATIC(control_data
, Node
, entry
, nodecmp
)
623 TA_control_free_tree(FONT
* font
)
625 control_data
* control_data_head
= (control_data
*)font
->control_data_head
;
626 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
632 if (!control_data_head
)
635 for (node
= LLRB_MIN(control_data
, control_data_head
);
639 next_node
= LLRB_NEXT(control_data
, control_data_head
, node
);
640 LLRB_REMOVE(control_data
, control_data_head
, node
);
644 free(control_data_head
);
645 TA_control_free(control_segment_dirs_head
);
650 TA_control_build_tree(FONT
* font
)
652 Control
* control
= font
->control
;
653 control_data
* control_data_head
;
654 int emit_newline
= 0;
657 font
->control_segment_dirs_head
= NULL
;
658 font
->control_segment_dirs_cur
= NULL
;
660 /* nothing to do if no data */
663 font
->control_data_head
= NULL
;
664 font
->control_data_cur
= NULL
;
668 control_data_head
= (control_data
*)malloc(sizeof (control_data
));
669 if (!control_data_head
)
670 return FT_Err_Out_Of_Memory
;
672 LLRB_INIT(control_data_head
);
676 Control_Type type
= control
->type
;
677 long font_idx
= control
->font_idx
;
678 long glyph_idx
= control
->glyph_idx
;
679 int x_shift
= control
->x_shift
;
680 int y_shift
= control
->y_shift
;
681 int line_number
= control
->line_number
;
683 number_set_iter ppems_iter
;
687 /* we don't store style information in the tree */
688 if (type
== Control_Script_Feature_Glyphs
)
690 control
= control
->next
;
694 ppems_iter
.range
= control
->ppems
;
695 ppem
= number_set_get_first(&ppems_iter
);
697 /* ppem is always zero for one-point segments */
698 if (type
== Control_Single_Point_Segment_Left
699 || type
== Control_Single_Point_Segment_Right
700 || type
== Control_Single_Point_Segment_None
)
705 number_set_iter points_iter
;
710 points_iter
.range
= control
->points
;
711 point_idx
= number_set_get_first(&points_iter
);
713 while (point_idx
>= 0)
719 node
= (Node
*)malloc(sizeof (Node
));
721 return FT_Err_Out_Of_Memory
;
723 node
->ctrl
.type
= type
;
724 node
->ctrl
.font_idx
= font_idx
;
725 node
->ctrl
.glyph_idx
= glyph_idx
;
726 node
->ctrl
.ppem
= ppem
;
727 node
->ctrl
.point_idx
= point_idx
;
728 node
->ctrl
.x_shift
= x_shift
;
729 node
->ctrl
.y_shift
= y_shift
;
730 node
->ctrl
.line_number
= line_number
;
732 val
= LLRB_INSERT(control_data
, control_data_head
, node
);
733 if (val
&& font
->debug
)
735 /* entry is already present; we overwrite it */
743 /* construct Control entry for debugging output */
747 points
.start
= point_idx
;
748 points
.end
= point_idx
;
752 d
.font_idx
= font_idx
;
753 d
.glyph_idx
= glyph_idx
;
760 s
= control_show_line(font
, &d
);
763 fprintf(stderr
, "Control instruction `%s' (line %d)"
764 " overwrites data from line %d.\n",
765 s
, line_number
, val
->ctrl
.line_number
);
773 val
->ctrl
.type
= type
;
774 val
->ctrl
.font_idx
= font_idx
;
775 val
->ctrl
.glyph_idx
= glyph_idx
;
776 val
->ctrl
.ppem
= ppem
;
777 val
->ctrl
.point_idx
= point_idx
;
778 val
->ctrl
.x_shift
= x_shift
;
779 val
->ctrl
.y_shift
= y_shift
;
780 val
->ctrl
.line_number
= line_number
;
785 point_idx
= number_set_get_next(&points_iter
);
788 ppem
= number_set_get_next(&ppems_iter
);
791 control
= control
->next
;
794 if (font
->debug
&& emit_newline
)
795 fprintf(stderr
, "\n");
797 font
->control_data_head
= control_data_head
;
798 font
->control_data_cur
= LLRB_MIN(control_data
, control_data_head
);
804 /* the next functions are intended to restrict the use of LLRB stuff */
805 /* related to control instructions to this file, */
806 /* providing a means to access the data sequentially */
809 TA_control_get_next(FONT
* font
)
811 Node
* node
= (Node
*)font
->control_data_cur
;
817 node
= LLRB_NEXT(control_data
, /* unused */, node
);
819 font
->control_data_cur
= node
;
824 TA_control_get_ctrl(FONT
* font
)
826 Node
* node
= (Node
*)font
->control_data_cur
;
829 return node
? &node
->ctrl
: NULL
;
834 TA_control_segment_dir_collect(FONT
* font
,
838 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
841 /* nothing to do if no data */
842 if (!font
->control_data_head
)
845 if (control_segment_dirs_head
)
847 TA_control_free(control_segment_dirs_head
);
848 control_segment_dirs_head
= NULL
;
852 * The PPEM value for one-point segments is always zero; such control
853 * instructions are thus sorted before other control instructions for the
854 * same glyph index -- this fits nicely with the call to
855 * `TA_control_get_next' in the loop of `TA_sfnt_build_delta_exceptions',
856 * assuring proper sequential access to the red-black tree.
860 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
868 if (!(ctrl
->type
== Control_Single_Point_Segment_Left
869 || ctrl
->type
== Control_Single_Point_Segment_Right
870 || ctrl
->type
== Control_Single_Point_Segment_None
))
873 /* too large values of font and glyph indices in `ctrl' */
874 /* are handled by later calls of this function */
875 if (font_idx
< ctrl
->font_idx
876 || glyph_idx
< ctrl
->glyph_idx
)
879 /* we simply use the `Control' structure again, */
880 /* abusing the `glyph_idx' field for the point index */
881 elem
= TA_control_new(ctrl
->type
,
891 TA_control_free(control_segment_dirs_head
);
892 return TA_Err_Control_Allocation_Error
;
894 control_segment_dirs_head
= TA_control_prepend(control_segment_dirs_head
,
897 TA_control_get_next(font
);
900 font
->control_segment_dirs_head
= TA_control_reverse(control_segment_dirs_head
);
901 font
->control_segment_dirs_cur
= font
->control_segment_dirs_head
;
908 TA_control_segment_dir_get_next(FONT
* font
,
914 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
915 Control
* control_segment_dirs_cur
= (Control
*)font
->control_segment_dirs_cur
;
918 /* nothing to do if no data */
919 if (!control_segment_dirs_head
)
922 if (!control_segment_dirs_cur
)
924 font
->control_segment_dirs_cur
= control_segment_dirs_head
;
928 /* the `glyph_idx' field gets abused for `point_idx' */
929 *point_idx
= (int)control_segment_dirs_cur
->glyph_idx
;
930 *dir
= control_segment_dirs_cur
->type
== Control_Single_Point_Segment_Left
932 : control_segment_dirs_cur
->type
== Control_Single_Point_Segment_Right
935 *left_offset
= control_segment_dirs_cur
->x_shift
;
936 *right_offset
= control_segment_dirs_cur
->y_shift
;
938 font
->control_segment_dirs_cur
= control_segment_dirs_cur
->next
;
943 /* end of tacontrol.c */