Fix OTS warning about `maxp.maxSizeOfInstructions`.
[ttfautohint.git] / lib / tacontrol.c
blob291e8550fd917af21daaab9e6e2dd3e48b6d7cfa
1 /* tacontrol.c */
3 /*
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.
15 #include "ta.h"
16 #include "tashaper.h"
18 #include <locale.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <math.h>
24 #include <stdbool.h> /* for llrb.h */
26 #include "llrb.h" /* a red-black tree implementation */
27 #include "tacontrol-bison.h"
30 Control*
31 TA_control_new(Control_Type type,
32 long font_idx,
33 long glyph_idx,
34 number_range* point_set,
35 double x_shift,
36 double y_shift,
37 number_range* ppem_set,
38 int line_number)
40 Control* control;
43 control = (Control*)malloc(sizeof (Control));
44 if (!control)
45 return NULL;
47 control->type = type;
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));
61 break;
63 case Control_Single_Point_Segment_Left:
64 case Control_Single_Point_Segment_Right:
65 /* offsets */
66 control->x_shift = (int)x_shift;
67 control->y_shift = (int)y_shift;
68 break;
70 case Control_Single_Point_Segment_None:
71 control->x_shift = 0;
72 control->y_shift = 0;
73 break;
75 case Control_Script_Feature_Glyphs:
76 /* the `glyph_idx' field holds the style; */
77 /* the `points' field holds the glyph index set */
78 break;
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; */
84 break;
87 control->ppems = number_set_reverse(ppem_set);
88 control->next = NULL;
90 control->line_number = line_number;
92 return control;
96 Control*
97 TA_control_prepend(Control* list,
98 Control* element)
100 if (!element)
101 return list;
103 element->next = list;
105 return element;
109 Control*
110 TA_control_reverse(Control* list)
112 Control* cur;
115 cur = list;
116 list = NULL;
118 while (cur)
120 Control* tmp;
123 tmp = cur;
124 cur = cur->next;
125 tmp->next = list;
126 list = tmp;
129 return list;
133 void
134 TA_control_free(Control* control)
136 while (control)
138 Control* tmp;
141 number_set_free(control->points);
142 number_set_free(control->ppems);
144 tmp = control;
145 control = control->next;
146 free(tmp);
151 static sds
152 control_show_line(FONT* font,
153 Control* control)
155 char glyph_name_buf[64];
156 char* points_buf = NULL;
157 char* ppems_buf = NULL;
159 sds s;
161 FT_Face face;
164 s = sdsempty();
166 if (!control)
167 goto Exit;
169 if (control->font_idx >= font->num_sfnts)
170 goto Exit;
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);
180 if (!points_buf)
181 goto Exit;
182 ppems_buf = number_set_show(control->ppems, -1, -1);
183 if (!ppems_buf)
184 goto Exit;
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 */
191 if (*glyph_name_buf)
192 s = sdscatprintf(s, "%ld %s %s %s xshift %.20g yshift %.20g @ %s",
193 control->font_idx,
194 glyph_name_buf,
195 control->type == Control_Delta_before_IUP ? "touch"
196 : "point",
197 points_buf,
198 (double)control->x_shift / CONTROL_DELTA_FACTOR,
199 (double)control->y_shift / CONTROL_DELTA_FACTOR,
200 ppems_buf);
201 else
202 s = sdscatprintf(s, "%ld %ld point %s xshift %.20g yshift %.20g @ %s",
203 control->font_idx,
204 control->glyph_idx,
205 points_buf,
206 (double)control->x_shift / CONTROL_DELTA_FACTOR,
207 (double)control->y_shift / CONTROL_DELTA_FACTOR,
208 ppems_buf);
209 break;
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 */
214 if (*glyph_name_buf)
215 s = sdscatprintf(s, "%ld %s %s %s",
216 control->font_idx,
217 glyph_name_buf,
218 control->type == Control_Single_Point_Segment_Left
219 ? "left" : "right",
220 points_buf);
221 else
222 s = sdscatprintf(s, "%ld %ld %s %s",
223 control->font_idx,
224 control->glyph_idx,
225 control->type == Control_Single_Point_Segment_Left
226 ? "left" : "right",
227 points_buf);
229 if (control->x_shift || control->y_shift)
230 s = sdscatprintf(s, " (%d,%d)", control->x_shift, control->y_shift);
231 break;
233 case Control_Single_Point_Segment_None:
234 /* display glyph index if we don't have a glyph name */
235 if (*glyph_name_buf)
236 s = sdscatprintf(s, "%ld %s nodir %s",
237 control->font_idx,
238 glyph_name_buf,
239 points_buf);
240 else
241 s = sdscatprintf(s, "%ld %ld nodir %s",
242 control->font_idx,
243 control->glyph_idx,
244 points_buf);
245 break;
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",
257 control->font_idx,
258 script_names[style_class->script],
259 feature_name,
260 points_buf);
262 break;
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);
280 else
282 script_name = "*";
283 hb_tag_to_string(feature_tags[-control->glyph_idx], feature_name);
286 s = sdscatprintf(s, "%ld %s %s width %s",
287 control->font_idx,
288 script_name,
289 feature_name,
290 points_buf);
294 Exit:
295 free(points_buf);
296 free(ppems_buf);
298 return s;
302 char*
303 TA_control_show(FONT* font)
305 sds s;
306 size_t len;
307 char* res;
309 Control* control = font->control;
312 s = sdsempty();
314 while (control)
316 sds d;
319 /* append current line to buffer, followed by a newline character */
320 d = control_show_line(font, control);
321 if (!d)
323 sdsfree(s);
324 return NULL;
326 s = sdscatsds(s, d);
327 sdsfree(d);
328 s = sdscat(s, "\n");
330 control = control->next;
333 if (!s)
334 return NULL;
336 /* we return an empty string if there is no data */
337 len = sdslen(s) + 1;
338 res = (char*)malloc(len);
339 if (res)
340 memcpy(res, s, len);
342 sdsfree(s);
344 return res;
348 /* Parse control instructions in `font->control_buf'. */
350 TA_Error
351 TA_control_parse_buffer(FONT* font,
352 char** error_string_p,
353 unsigned int* errlinenum_p,
354 char** errline_p,
355 char** errpos_p)
357 int bison_error;
359 Control_Context context;
362 /* nothing to do if no data */
363 if (!font->control_buf)
365 font->control = NULL;
366 return TA_Err_Ok;
369 TA_control_scanner_init(&context, font);
370 if (context.error)
371 goto Fail;
372 /* this is `yyparse' in disguise */
373 bison_error = TA_control_parse(&context);
374 TA_control_scanner_done(&context);
376 if (bison_error)
378 if (bison_error == 2)
379 context.error = TA_Err_Control_Allocation_Error;
381 Fail:
382 font->control = NULL;
384 if (context.error == TA_Err_Control_Allocation_Error
385 || context.error == TA_Err_Control_Flex_Error)
387 *errlinenum_p = 0;
388 *errline_p = NULL;
389 *errpos_p = NULL;
390 if (*context.errmsg)
391 *error_string_p = strdup(context.errmsg);
392 else
393 *error_string_p = strdup(TA_get_error_message(context.error));
395 else
397 int ret;
398 char auxbuf[128];
400 char* buf_end;
401 char* p_start;
402 char* p_end;
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)
411 int i = 1;
412 while (p_start < buf_end)
414 if (*p_start++ == '\n')
416 i++;
417 if (i == context.errline_num)
418 break;
423 p_end = p_start;
424 while (p_end < buf_end)
426 if (*p_end == '\n')
427 break;
428 p_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])",
436 font->num_sfnts);
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])",
447 SHRT_MIN,
448 SHRT_MAX);
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);
453 else
454 auxbuf[0] = '\0';
456 ret = asprintf(error_string_p, "%s%s",
457 *context.errmsg ? context.errmsg
458 : TA_get_error_message(context.error),
459 auxbuf);
460 if (ret == -1)
461 *error_string_p = NULL;
463 if (*errline_p)
464 *errpos_p = *errline_p + context.errline_pos_left - 1;
465 else
466 *errpos_p = NULL;
468 *errlinenum_p = (unsigned int)context.errline_num;
471 else
472 font->control = context.result;
474 return context.error;
478 /* apply coverage data from the control instructions file */
480 void
481 TA_control_apply_coverage(SFNT* sfnt,
482 FONT* font)
484 Control* control = font->control;
485 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
486 FT_UShort* gstyles = globals->glyph_styles;
489 while (control)
491 number_set_iter glyph_idx_iter;
492 int glyph_idx;
493 int style;
496 if (control->type != Control_Script_Feature_Glyphs)
497 goto Skip;
498 if (control->font_idx != sfnt->face->face_index)
499 goto Skip;
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);
516 Skip:
517 control = control->next;
522 /* handle stem width data from the control instructions file; */
524 void
525 TA_control_set_stem_widths(TA_LatinMetrics metrics,
526 FONT* font)
528 Control* control = font->control;
529 FT_Face face = font->loader->face;
530 TA_WidthRec* widths = metrics->axis[TA_DIMENSION_VERT].widths;
533 while (control)
535 TA_StyleClass style_class = metrics->root.style_class;
537 number_set_iter width_iter;
538 int width;
539 int i;
542 if (control->type != Control_Script_Feature_Widths)
543 goto Skip;
544 if (control->font_idx != face->face_index)
545 goto Skip;
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))
550 goto Skip;
552 /* `control->points' holds the width set */
553 width_iter.range = control->points;
554 width = number_set_get_first(&width_iter);
556 i = 0;
557 while (width >= 0)
559 widths[i++].org = width;
560 width = number_set_get_next(&width_iter);
562 metrics->axis[TA_DIMENSION_VERT].width_count = i;
564 Skip:
565 control = control->next;
570 /* node structure for control instruction data */
572 typedef struct Node Node;
573 struct Node
575 LLRB_ENTRY(Node) entry;
576 Ctrl ctrl;
580 /* comparison function for our red-black tree */
582 static int
583 nodecmp(Node* e1,
584 Node* e2)
586 long diff;
589 /* sort by font index ... */
590 diff = e1->ctrl.font_idx - e2->ctrl.font_idx;
591 if (diff)
592 goto Exit;
594 /* ... then by glyph index ... */
595 diff = e1->ctrl.glyph_idx - e2->ctrl.glyph_idx;
596 if (diff)
597 goto Exit;
599 /* ... then by ppem ... */
600 diff = e1->ctrl.ppem - e2->ctrl.ppem;
601 if (diff)
602 goto Exit;
604 /* ... then by point index */
605 diff = e1->ctrl.point_idx - e2->ctrl.point_idx;
607 Exit:
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)
622 void
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;
628 Node* node;
629 Node* next_node;
632 if (!control_data_head)
633 return;
635 for (node = LLRB_MIN(control_data, control_data_head);
636 node;
637 node = next_node)
639 next_node = LLRB_NEXT(control_data, control_data_head, node);
640 LLRB_REMOVE(control_data, control_data_head, node);
641 free(node);
644 free(control_data_head);
645 TA_control_free(control_segment_dirs_head);
649 TA_Error
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 */
661 if (!control)
663 font->control_data_head = NULL;
664 font->control_data_cur = NULL;
665 return TA_Err_Ok;
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);
674 while (control)
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;
684 int ppem;
687 /* we don't store style information in the tree */
688 if (type == Control_Script_Feature_Glyphs)
690 control = control->next;
691 continue;
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)
701 goto Points_Loop;
703 while (ppem >= 0)
705 number_set_iter points_iter;
706 int point_idx;
709 Points_Loop:
710 points_iter.range = control->points;
711 point_idx = number_set_get_first(&points_iter);
713 while (point_idx >= 0)
715 Node* node;
716 Node* val;
719 node = (Node*)malloc(sizeof (Node));
720 if (!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 */
736 Control d;
737 number_range ppems;
738 number_range points;
740 sds s;
743 /* construct Control entry for debugging output */
744 ppems.start = ppem;
745 ppems.end = ppem;
746 ppems.next = NULL;
747 points.start = point_idx;
748 points.end = point_idx;
749 points.next = NULL;
751 d.type = type;
752 d.font_idx = font_idx;
753 d.glyph_idx = glyph_idx;
754 d.points = &points;
755 d.x_shift = x_shift;
756 d.y_shift = y_shift;
757 d.ppems = &ppems;
758 d.next = NULL;
760 s = control_show_line(font, &d);
761 if (s)
763 fprintf(stderr, "Control instruction `%s' (line %d)"
764 " overwrites data from line %d.\n",
765 s, line_number, val->ctrl.line_number);
766 sdsfree(s);
769 emit_newline = 1;
771 if (val)
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;
782 free(node);
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);
800 return TA_Err_Ok;
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 */
808 void
809 TA_control_get_next(FONT* font)
811 Node* node = (Node*)font->control_data_cur;
814 if (!node)
815 return;
817 node = LLRB_NEXT(control_data, /* unused */, node);
819 font->control_data_cur = node;
823 const Ctrl*
824 TA_control_get_ctrl(FONT* font)
826 Node* node = (Node*)font->control_data_cur;
829 return node ? &node->ctrl : NULL;
833 TA_Error
834 TA_control_segment_dir_collect(FONT* font,
835 long font_idx,
836 long glyph_idx)
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)
843 return TA_Err_Ok;
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.
858 for (;;)
860 const Ctrl* ctrl = TA_control_get_ctrl(font);
861 Control* elem;
864 if (!ctrl)
865 break;
867 /* check type */
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))
871 break;
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)
877 break;
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,
883 ctrl->point_idx,
884 NULL,
885 ctrl->x_shift,
886 ctrl->y_shift,
887 NULL,
888 ctrl->line_number);
889 if (!elem)
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,
895 elem);
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;
903 return TA_Err_Ok;
908 TA_control_segment_dir_get_next(FONT* font,
909 int* point_idx,
910 TA_Direction* dir,
911 int* left_offset,
912 int* right_offset)
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)
920 return 0;
922 if (!control_segment_dirs_cur)
924 font->control_segment_dirs_cur = control_segment_dirs_head;
925 return 0;
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
931 ? TA_DIR_LEFT
932 : control_segment_dirs_cur->type == Control_Single_Point_Segment_Right
933 ? TA_DIR_RIGHT
934 : TA_DIR_NONE;
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;
940 return 1;
943 /* end of tacontrol.c */