[css] Use https for connection to google's font API.
[ttfautohint.git] / lib / tacontrol.c
blobb6e2447400a1c2fd106646806e56e3a03766c38e
1 /* tacontrol.c */
3 /*
4 * Copyright (C) 2014-2017 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)
39 Control* control;
42 control = (Control*)malloc(sizeof (Control));
43 if (!control)
44 return NULL;
46 control->type = type;
48 control->font_idx = font_idx;
49 control->glyph_idx = glyph_idx;
50 control->points = number_set_normalize(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_Segment_Left:
64 case Control_Segment_Right:
65 /* offsets */
66 control->x_shift = (int)x_shift;
67 control->y_shift = (int)y_shift;
68 break;
70 case Control_Segment_None:
71 control->x_shift = 0;
72 control->y_shift = 0;
73 break;
75 case Control_Script_Feature:
76 /* the `glyph_idx' field holds the style; */
77 /* the `points' field holds the glyph index set */
78 break;
81 control->ppems = number_set_normalize(number_set_reverse(ppem_set));
82 control->next = NULL;
84 return control;
88 Control*
89 TA_control_prepend(Control* list,
90 Control* element)
92 if (!element)
93 return list;
95 element->next = list;
97 return element;
101 Control*
102 TA_control_reverse(Control* list)
104 Control* cur;
107 cur = list;
108 list = NULL;
110 while (cur)
112 Control* tmp;
115 tmp = cur;
116 cur = cur->next;
117 tmp->next = list;
118 list = tmp;
121 return list;
125 void
126 TA_control_free(Control* control)
128 while (control)
130 Control* tmp;
133 number_set_free(control->points);
134 number_set_free(control->ppems);
136 tmp = control;
137 control = control->next;
138 free(tmp);
143 static sds
144 control_show_line(FONT* font,
145 Control* control)
147 char glyph_name_buf[64];
148 char* points_buf = NULL;
149 char* ppems_buf = NULL;
151 sds s;
153 FT_Face face;
156 s = sdsempty();
158 if (!control)
159 goto Exit;
161 if (control->font_idx >= font->num_sfnts)
162 goto Exit;
164 face = font->sfnts[control->font_idx].face;
165 glyph_name_buf[0] = '\0';
166 if (control->type != Control_Script_Feature
167 && FT_HAS_GLYPH_NAMES(face))
168 FT_Get_Glyph_Name(face, (FT_UInt)control->glyph_idx, glyph_name_buf, 64);
170 points_buf = number_set_show(control->points, -1, -1);
171 if (!points_buf)
172 goto Exit;
173 ppems_buf = number_set_show(control->ppems, -1, -1);
174 if (!ppems_buf)
175 goto Exit;
177 switch (control->type)
179 case Control_Delta_before_IUP:
180 case Control_Delta_after_IUP:
181 /* display glyph index if we don't have a glyph name */
182 if (*glyph_name_buf)
183 s = sdscatprintf(s, "%ld %s %s %s xshift %.20g yshift %.20g @ %s",
184 control->font_idx,
185 glyph_name_buf,
186 control->type == Control_Delta_before_IUP ? "touch"
187 : "point",
188 points_buf,
189 (double)control->x_shift / CONTROL_DELTA_FACTOR,
190 (double)control->y_shift / CONTROL_DELTA_FACTOR,
191 ppems_buf);
192 else
193 s = sdscatprintf(s, "%ld %ld point %s xshift %.20g yshift %.20g @ %s",
194 control->font_idx,
195 control->glyph_idx,
196 points_buf,
197 (double)control->x_shift / CONTROL_DELTA_FACTOR,
198 (double)control->y_shift / CONTROL_DELTA_FACTOR,
199 ppems_buf);
200 break;
202 case Control_Segment_Left:
203 case Control_Segment_Right:
204 /* display glyph index if we don't have a glyph name */
205 if (*glyph_name_buf)
206 s = sdscatprintf(s, "%ld %s %s %s",
207 control->font_idx,
208 glyph_name_buf,
209 control->type == Control_Segment_Left ? "left"
210 : "right",
211 points_buf);
212 else
213 s = sdscatprintf(s, "%ld %ld %s %s",
214 control->font_idx,
215 control->glyph_idx,
216 control->type == Control_Segment_Left ? "left"
217 : "right",
218 points_buf);
220 if (control->x_shift || control->y_shift)
221 s = sdscatprintf(s, " (%d,%d)", control->x_shift, control->y_shift);
222 break;
224 case Control_Segment_None:
225 /* display glyph index if we don't have a glyph name */
226 if (*glyph_name_buf)
227 s = sdscatprintf(s, "%ld %s nodir %s",
228 control->font_idx,
229 glyph_name_buf,
230 points_buf);
231 else
232 s = sdscatprintf(s, "%ld %ld nodir %s",
233 control->font_idx,
234 control->glyph_idx,
235 points_buf);
236 break;
238 case Control_Script_Feature:
240 TA_StyleClass style_class = ta_style_classes[control->glyph_idx];
241 char feature_name[5];
244 feature_name[4] = '\0';
245 hb_tag_to_string(feature_tags[style_class->coverage], feature_name);
247 s = sdscatprintf(s, "%ld %s %s @ %s",
248 control->font_idx,
249 script_names[style_class->script],
250 feature_name,
251 points_buf);
253 break;
256 Exit:
257 free(points_buf);
258 free(ppems_buf);
260 return s;
264 char*
265 TA_control_show(FONT* font)
267 sds s;
268 size_t len;
269 char* res;
271 Control* control = font->control;
274 s = sdsempty();
276 while (control)
278 sds d;
281 /* append current line to buffer, followed by a newline character */
282 d = control_show_line(font, control);
283 if (!d)
285 sdsfree(s);
286 return NULL;
288 s = sdscatsds(s, d);
289 sdsfree(d);
290 s = sdscat(s, "\n");
292 control = control->next;
295 if (!s)
296 return NULL;
298 /* we return an empty string if there is no data */
299 len = sdslen(s) + 1;
300 res = (char*)malloc(len);
301 if (res)
302 memcpy(res, s, len);
304 sdsfree(s);
306 return res;
310 /* Parse control instructions in `font->control_buf'. */
312 TA_Error
313 TA_control_parse_buffer(FONT* font,
314 char** error_string_p,
315 unsigned int* errlinenum_p,
316 char** errline_p,
317 char** errpos_p)
319 int bison_error;
321 Control_Context context;
324 /* nothing to do if no data */
325 if (!font->control_buf)
327 font->control = NULL;
328 return TA_Err_Ok;
331 TA_control_scanner_init(&context, font);
332 if (context.error)
333 goto Fail;
334 /* this is `yyparse' in disguise */
335 bison_error = TA_control_parse(&context);
336 TA_control_scanner_done(&context);
338 if (bison_error)
340 if (bison_error == 2)
341 context.error = TA_Err_Control_Allocation_Error;
343 Fail:
344 font->control = NULL;
346 if (context.error == TA_Err_Control_Allocation_Error
347 || context.error == TA_Err_Control_Flex_Error)
349 *errlinenum_p = 0;
350 *errline_p = NULL;
351 *errpos_p = NULL;
352 if (*context.errmsg)
353 *error_string_p = strdup(context.errmsg);
354 else
355 *error_string_p = strdup(TA_get_error_message(context.error));
357 else
359 int i, ret;
360 char auxbuf[128];
362 char* buf_end;
363 char* p_start;
364 char* p_end;
367 /* construct data for `errline_p' */
368 buf_end = font->control_buf + font->control_len;
370 p_start = font->control_buf;
371 if (context.errline_num > 1)
373 i = 1;
374 while (p_start < buf_end)
376 if (*p_start++ == '\n')
378 i++;
379 if (i == context.errline_num)
380 break;
385 p_end = p_start;
386 while (p_end < buf_end)
388 if (*p_end == '\n')
389 break;
390 p_end++;
392 *errline_p = strndup(p_start, (size_t)(p_end - p_start));
394 /* construct data for `error_string_p' */
395 if (context.error == TA_Err_Control_Invalid_Font_Index)
396 sprintf(auxbuf, " (valid range is [%ld;%ld])",
398 font->num_sfnts);
399 else if (context.error == TA_Err_Control_Invalid_Glyph_Index)
400 sprintf(auxbuf, " (valid range is [%ld;%ld])",
402 font->sfnts[context.font_idx].face->num_glyphs);
403 else if (context.error == TA_Err_Control_Invalid_Shift)
404 sprintf(auxbuf, " (valid interval is [%g;%g])",
405 CONTROL_DELTA_SHIFT_MIN,
406 CONTROL_DELTA_SHIFT_MAX);
407 else if (context.error == TA_Err_Control_Invalid_Offset)
408 sprintf(auxbuf, " (valid interval is [%d;%d])",
409 SHRT_MIN,
410 SHRT_MAX);
411 else if (context.error == TA_Err_Control_Invalid_Range)
412 sprintf(auxbuf, " (values must be within [%d;%d])",
413 context.number_set_min,
414 context.number_set_max);
415 else
416 auxbuf[0] = '\0';
418 ret = asprintf(error_string_p, "%s%s",
419 *context.errmsg ? context.errmsg
420 : TA_get_error_message(context.error),
421 auxbuf);
422 if (ret == -1)
423 *error_string_p = NULL;
425 if (errline_p)
426 *errpos_p = *errline_p + context.errline_pos_left - 1;
427 else
428 *errpos_p = NULL;
430 *errlinenum_p = (unsigned int)context.errline_num;
433 else
434 font->control = context.result;
436 return context.error;
440 /* apply coverage data from the control instructions file */
442 void
443 TA_control_apply_coverage(SFNT* sfnt,
444 FONT* font)
446 Control* control = font->control;
447 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
448 FT_UShort* gstyles = globals->glyph_styles;
451 while (control)
453 number_set_iter glyph_idx_iter;
454 int glyph_idx;
455 int style;
458 if (control->type != Control_Script_Feature)
459 goto Skip;
460 if (control->font_idx != sfnt->face->face_index)
461 goto Skip;
463 /* `control->glyph_idx' holds the style; */
464 /* `control->points' holds the glyph index set */
465 style = (int)control->glyph_idx;
466 glyph_idx_iter.range = control->points;
467 glyph_idx = number_set_get_first(&glyph_idx_iter);
469 while (glyph_idx_iter.range)
471 /* assign new style but retain digit property */
472 gstyles[glyph_idx] &= TA_DIGIT;
473 gstyles[glyph_idx] |= style;
475 glyph_idx = number_set_get_next(&glyph_idx_iter);
478 Skip:
479 control = control->next;
484 /* node structure for control instruction data */
486 typedef struct Node Node;
487 struct Node
489 LLRB_ENTRY(Node) entry;
490 Ctrl ctrl;
494 /* comparison function for our red-black tree */
496 static int
497 nodecmp(Node* e1,
498 Node* e2)
500 long diff;
503 /* sort by font index ... */
504 diff = e1->ctrl.font_idx - e2->ctrl.font_idx;
505 if (diff)
506 goto Exit;
508 /* ... then by glyph index ... */
509 diff = e1->ctrl.glyph_idx - e2->ctrl.glyph_idx;
510 if (diff)
511 goto Exit;
513 /* ... then by ppem ... */
514 diff = e1->ctrl.ppem - e2->ctrl.ppem;
515 if (diff)
516 goto Exit;
518 /* ... then by point index */
519 diff = e1->ctrl.point_idx - e2->ctrl.point_idx;
521 Exit:
522 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
523 return (diff > 0) - (diff < 0);
527 /* the red-black tree function body */
528 typedef struct control_data control_data;
530 LLRB_HEAD(control_data, Node);
532 /* no trailing semicolon in the next line */
533 LLRB_GENERATE_STATIC(control_data, Node, entry, nodecmp)
536 void
537 TA_control_free_tree(FONT* font)
539 control_data* control_data_head = (control_data*)font->control_data_head;
540 Control* control_segment_dirs_head = (Control*)font->control_segment_dirs_head;
542 Node* node;
543 Node* next_node;
546 if (!control_data_head)
547 return;
549 for (node = LLRB_MIN(control_data, control_data_head);
550 node;
551 node = next_node)
553 next_node = LLRB_NEXT(control_data, control_data_head, node);
554 LLRB_REMOVE(control_data, control_data_head, node);
555 free(node);
558 free(control_data_head);
559 TA_control_free(control_segment_dirs_head);
563 TA_Error
564 TA_control_build_tree(FONT* font)
566 Control* control = font->control;
567 control_data* control_data_head;
568 int emit_newline = 0;
571 font->control_segment_dirs_head = NULL;
572 font->control_segment_dirs_cur = NULL;
574 /* nothing to do if no data */
575 if (!control)
577 font->control_data_head = NULL;
578 font->control_data_cur = NULL;
579 return TA_Err_Ok;
582 control_data_head = (control_data*)malloc(sizeof (control_data));
583 if (!control_data_head)
584 return FT_Err_Out_Of_Memory;
586 LLRB_INIT(control_data_head);
588 while (control)
590 Control_Type type = control->type;
591 long font_idx = control->font_idx;
592 long glyph_idx = control->glyph_idx;
593 int x_shift = control->x_shift;
594 int y_shift = control->y_shift;
596 number_set_iter ppems_iter;
597 int ppem;
600 /* we don't store style information in the tree */
601 if (type == Control_Script_Feature)
603 control = control->next;
604 continue;
607 ppems_iter.range = control->ppems;
608 ppem = number_set_get_first(&ppems_iter);
610 /* ppem is always zero for one-point segments */
611 if (type == Control_Segment_Left
612 || type == Control_Segment_Right
613 || type == Control_Segment_None)
614 goto Points_Loop;
616 while (ppems_iter.range)
618 number_set_iter points_iter;
619 int point_idx;
622 Points_Loop:
623 points_iter.range = control->points;
624 point_idx = number_set_get_first(&points_iter);
626 while (points_iter.range)
628 Node* node;
629 Node* val;
632 node = (Node*)malloc(sizeof (Node));
633 if (!node)
634 return FT_Err_Out_Of_Memory;
636 node->ctrl.type = type;
637 node->ctrl.font_idx = font_idx;
638 node->ctrl.glyph_idx = glyph_idx;
639 node->ctrl.ppem = ppem;
640 node->ctrl.point_idx = point_idx;
641 node->ctrl.x_shift = x_shift;
642 node->ctrl.y_shift = y_shift;
644 val = LLRB_INSERT(control_data, control_data_head, node);
645 if (val)
646 free(node);
647 if (val && font->debug)
649 /* entry is already present; we ignore it */
650 Control d;
651 number_range ppems;
652 number_range points;
654 sds s;
657 /* construct Control entry for debugging output */
658 ppems.start = ppem;
659 ppems.end = ppem;
660 ppems.next = NULL;
661 points.start = point_idx;
662 points.end = point_idx;
663 points.next = NULL;
665 d.type = type;
666 d.font_idx = font_idx;
667 d.glyph_idx = glyph_idx;
668 d.points = &points;
669 d.x_shift = x_shift;
670 d.y_shift = y_shift;
671 d.ppems = &ppems;
672 d.next = NULL;
674 s = control_show_line(font, &d);
675 if (s)
677 fprintf(stderr, "Control instruction `%s' ignored.\n", s);
678 sdsfree(s);
681 emit_newline = 1;
684 point_idx = number_set_get_next(&points_iter);
687 ppem = number_set_get_next(&ppems_iter);
690 control = control->next;
693 if (font->debug && emit_newline)
694 fprintf(stderr, "\n");
696 font->control_data_head = control_data_head;
697 font->control_data_cur = LLRB_MIN(control_data, control_data_head);
699 return TA_Err_Ok;
703 /* the next functions are intended to restrict the use of LLRB stuff */
704 /* related to control instructions to this file, */
705 /* providing a means to access the data sequentially */
707 void
708 TA_control_get_next(FONT* font)
710 Node* node = (Node*)font->control_data_cur;
713 if (!node)
714 return;
716 node = LLRB_NEXT(control_data, /* unused */, node);
718 font->control_data_cur = node;
722 const Ctrl*
723 TA_control_get_ctrl(FONT* font)
725 Node* node = (Node*)font->control_data_cur;
728 return node ? &node->ctrl : NULL;
732 TA_Error
733 TA_control_segment_dir_collect(FONT* font,
734 long font_idx,
735 long glyph_idx)
737 Control* control_segment_dirs_head = (Control*)font->control_segment_dirs_head;
740 /* nothing to do if no data */
741 if (!font->control_data_head)
742 return TA_Err_Ok;
744 if (control_segment_dirs_head)
746 TA_control_free(control_segment_dirs_head);
747 control_segment_dirs_head = NULL;
751 * The PPEM value for one-point segments is always zero; such control
752 * instructions are thus sorted before other control instructions for the
753 * same glyph index -- this fits nicely with the call to
754 * `TA_control_get_next' in the loop of `TA_sfnt_build_delta_exceptions',
755 * assuring proper sequential access to the red-black tree.
757 for (;;)
759 const Ctrl* ctrl = TA_control_get_ctrl(font);
760 Control* elem;
763 if (!ctrl)
764 break;
766 /* check type */
767 if (!(ctrl->type == Control_Segment_Left
768 || ctrl->type == Control_Segment_Right
769 || ctrl->type == Control_Segment_None))
770 break;
772 /* too large values of font and glyph indices in `ctrl' */
773 /* are handled by later calls of this function */
774 if (font_idx < ctrl->font_idx
775 || glyph_idx < ctrl->glyph_idx)
776 break;
778 /* we simply use the `Control' structure again, */
779 /* abusing the `glyph_idx' field for the point index */
780 elem = TA_control_new(ctrl->type,
782 ctrl->point_idx,
783 NULL,
784 ctrl->x_shift,
785 ctrl->y_shift,
786 NULL);
787 if (!elem)
789 TA_control_free(control_segment_dirs_head);
790 return TA_Err_Control_Allocation_Error;
792 control_segment_dirs_head = TA_control_prepend(control_segment_dirs_head,
793 elem);
795 TA_control_get_next(font);
798 font->control_segment_dirs_head = TA_control_reverse(control_segment_dirs_head);
799 font->control_segment_dirs_cur = font->control_segment_dirs_head;
801 return TA_Err_Ok;
806 TA_control_segment_dir_get_next(FONT* font,
807 int* point_idx,
808 TA_Direction* dir,
809 int* left_offset,
810 int* right_offset)
812 Control* control_segment_dirs_head = (Control*)font->control_segment_dirs_head;
813 Control* control_segment_dirs_cur = (Control*)font->control_segment_dirs_cur;
816 /* nothing to do if no data */
817 if (!control_segment_dirs_head)
818 return 0;
820 if (!control_segment_dirs_cur)
822 font->control_segment_dirs_cur = control_segment_dirs_head;
823 return 0;
826 /* the `glyph_idx' field gets abused for `point_idx' */
827 *point_idx = (int)control_segment_dirs_cur->glyph_idx;
828 *dir = control_segment_dirs_cur->type == Control_Segment_Left
829 ? TA_DIR_LEFT
830 : control_segment_dirs_cur->type == Control_Segment_Right
831 ? TA_DIR_RIGHT
832 : TA_DIR_NONE;
833 *left_offset = control_segment_dirs_cur->x_shift;
834 *right_offset = control_segment_dirs_cur->y_shift;
836 font->control_segment_dirs_cur = control_segment_dirs_cur->next;
838 return control_segment_dirs_cur != NULL;
841 /* end of tacontrol.c */