4 * Copyright (C) 2014-2015 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
22 #include <stdbool.h> /* for llrb.h */
24 #include "llrb.h" /* a red-black tree implementation */
25 #include "tacontrol-bison.h"
28 TA_control_new(Control_Type type
,
31 number_range
* point_set
,
34 number_range
* ppem_set
)
39 control
= (Control
*)malloc(sizeof (Control
));
45 control
->font_idx
= font_idx
;
46 control
->glyph_idx
= glyph_idx
;
47 control
->points
= number_set_normalize(number_set_reverse(point_set
));
49 switch (control
->type
)
51 case Control_Delta_before_IUP
:
52 case Control_Delta_after_IUP
:
53 /* we round shift values to multiples of 1/(2^CONTROL_DELTA_SHIFT) */
54 control
->x_shift
= (int)(x_shift
* CONTROL_DELTA_FACTOR
55 + (x_shift
> 0 ? 0.5 : -0.5));
56 control
->y_shift
= (int)(y_shift
* CONTROL_DELTA_FACTOR
57 + (y_shift
> 0 ? 0.5 : -0.5));
60 case Control_Segment_Left
:
61 case Control_Segment_Right
:
63 control
->x_shift
= (int)x_shift
;
64 control
->y_shift
= (int)y_shift
;
67 case Control_Segment_None
:
73 control
->ppems
= number_set_normalize(number_set_reverse(ppem_set
));
81 TA_control_prepend(Control
* list
,
94 TA_control_reverse(Control
* list
)
118 TA_control_free(Control
* control
)
125 number_set_free(control
->points
);
126 number_set_free(control
->ppems
);
129 control
= control
->next
;
136 control_show_line(FONT
* font
,
139 char glyph_name_buf
[64];
140 char* points_buf
= NULL
;
141 char* ppems_buf
= NULL
;
153 if (control
->font_idx
>= font
->num_sfnts
)
156 face
= font
->sfnts
[control
->font_idx
].face
;
157 glyph_name_buf
[0] = '\0';
158 if (FT_HAS_GLYPH_NAMES(face
))
159 FT_Get_Glyph_Name(face
, (FT_UInt
)control
->glyph_idx
, glyph_name_buf
, 64);
161 points_buf
= number_set_show(control
->points
, -1, -1);
164 ppems_buf
= number_set_show(control
->ppems
, -1, -1);
168 switch (control
->type
)
170 case Control_Delta_before_IUP
:
171 case Control_Delta_after_IUP
:
172 /* display glyph index if we don't have a glyph name */
174 s
= sdscatprintf(s
, "%ld %s %s %s xshift %.20g yshift %.20g @ %s",
177 control
->type
== Control_Delta_before_IUP
? "touch"
180 (double)control
->x_shift
/ CONTROL_DELTA_FACTOR
,
181 (double)control
->y_shift
/ CONTROL_DELTA_FACTOR
,
184 s
= sdscatprintf(s
, "%ld %ld point %s xshift %.20g yshift %.20g @ %s",
188 (double)control
->x_shift
/ CONTROL_DELTA_FACTOR
,
189 (double)control
->y_shift
/ CONTROL_DELTA_FACTOR
,
193 case Control_Segment_Left
:
194 case Control_Segment_Right
:
195 /* display glyph index if we don't have a glyph name */
197 s
= sdscatprintf(s
, "%ld %s %s %s",
200 control
->type
== Control_Segment_Left
? "left"
204 s
= sdscatprintf(s
, "%ld %ld %s %s",
207 control
->type
== Control_Segment_Left
? "left"
211 if (control
->x_shift
|| control
->y_shift
)
212 s
= sdscatprintf(s
, " (%d,%d)", control
->x_shift
, control
->y_shift
);
215 case Control_Segment_None
:
216 /* display glyph index if we don't have a glyph name */
218 s
= sdscatprintf(s
, "%ld %s nodir %s",
223 s
= sdscatprintf(s
, "%ld %ld nodir %s",
239 TA_control_show(FONT
* font
)
245 Control
* control
= font
->control
;
255 /* append current line to buffer, followed by a newline character */
256 d
= control_show_line(font
, control
);
266 control
= control
->next
;
272 /* we return an empty string if there is no data */
274 res
= (char*)malloc(len
);
284 /* Parse control instructions in `font->control_buf'. */
287 TA_control_parse_buffer(FONT
* font
,
288 char** error_string_p
,
289 unsigned int* errlinenum_p
,
295 Control_Context context
;
298 /* nothing to do if no data */
299 if (!font
->control_buf
)
301 font
->control
= NULL
;
305 TA_control_scanner_init(&context
, font
);
308 /* this is `yyparse' in disguise */
309 bison_error
= TA_control_parse(&context
);
310 TA_control_scanner_done(&context
);
314 if (bison_error
== 2)
315 context
.error
= TA_Err_Control_Allocation_Error
;
318 font
->control
= NULL
;
320 if (context
.error
== TA_Err_Control_Allocation_Error
321 || context
.error
== TA_Err_Control_Flex_Error
)
327 *error_string_p
= strdup(context
.errmsg
);
329 *error_string_p
= strdup(TA_get_error_message(context
.error
));
341 /* construct data for `errline_p' */
342 buf_end
= font
->control_buf
+ font
->control_len
;
344 p_start
= font
->control_buf
;
345 if (context
.errline_num
> 1)
348 while (p_start
< buf_end
)
350 if (*p_start
++ == '\n')
353 if (i
== context
.errline_num
)
360 while (p_end
< buf_end
)
366 *errline_p
= strndup(p_start
, (size_t)(p_end
- p_start
));
368 /* construct data for `error_string_p' */
369 if (context
.error
== TA_Err_Control_Invalid_Font_Index
)
370 sprintf(auxbuf
, " (valid range is [%ld;%ld])",
373 else if (context
.error
== TA_Err_Control_Invalid_Glyph_Index
)
374 sprintf(auxbuf
, " (valid range is [%ld;%ld])",
376 font
->sfnts
[context
.font_idx
].face
->num_glyphs
);
377 else if (context
.error
== TA_Err_Control_Invalid_Shift
)
378 sprintf(auxbuf
, " (valid interval is [%g;%g])",
379 CONTROL_DELTA_SHIFT_MIN
,
380 CONTROL_DELTA_SHIFT_MAX
);
381 else if (context
.error
== TA_Err_Control_Invalid_Offset
)
382 sprintf(auxbuf
, " (valid interval is [%d;%d])",
385 else if (context
.error
== TA_Err_Control_Invalid_Range
)
386 sprintf(auxbuf
, " (values must be within [%ld;%ld])",
387 context
.number_set_min
,
388 context
.number_set_max
);
392 ret
= asprintf(error_string_p
, "%s%s",
393 *context
.errmsg
? context
.errmsg
394 : TA_get_error_message(context
.error
),
397 *error_string_p
= NULL
;
400 *errpos_p
= *errline_p
+ context
.errline_pos_left
- 1;
404 *errlinenum_p
= (unsigned int)context
.errline_num
;
408 font
->control
= context
.result
;
410 return context
.error
;
414 /* node structure for control instruction data */
416 typedef struct Node Node
;
419 LLRB_ENTRY(Node
) entry
;
424 /* comparison function for our red-black tree */
433 /* sort by font index ... */
434 diff
= e1
->ctrl
.font_idx
- e2
->ctrl
.font_idx
;
438 /* ... then by glyph index ... */
439 diff
= e1
->ctrl
.glyph_idx
- e2
->ctrl
.glyph_idx
;
443 /* ... then by ppem ... */
444 diff
= e1
->ctrl
.ppem
- e2
->ctrl
.ppem
;
448 /* ... then by point index */
449 diff
= e1
->ctrl
.point_idx
- e2
->ctrl
.point_idx
;
452 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
453 return (diff
> 0) - (diff
< 0);
457 /* the red-black tree function body */
458 typedef struct control_data control_data
;
460 LLRB_HEAD(control_data
, Node
);
462 /* no trailing semicolon in the next line */
463 LLRB_GENERATE_STATIC(control_data
, Node
, entry
, nodecmp
)
467 TA_control_free_tree(FONT
* font
)
469 control_data
* control_data_head
= (control_data
*)font
->control_data_head
;
470 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
476 if (!control_data_head
)
479 for (node
= LLRB_MIN(control_data
, control_data_head
);
483 next_node
= LLRB_NEXT(control_data
, control_data_head
, node
);
484 LLRB_REMOVE(control_data
, control_data_head
, node
);
488 free(control_data_head
);
489 TA_control_free(control_segment_dirs_head
);
494 TA_control_build_tree(FONT
* font
)
496 Control
* control
= font
->control
;
497 control_data
* control_data_head
;
498 int emit_newline
= 0;
501 font
->control_segment_dirs_head
= NULL
;
502 font
->control_segment_dirs_cur
= NULL
;
504 /* nothing to do if no data */
507 font
->control_data_head
= NULL
;
508 font
->control_data_cur
= NULL
;
512 control_data_head
= (control_data
*)malloc(sizeof (control_data
));
513 if (!control_data_head
)
514 return FT_Err_Out_Of_Memory
;
516 LLRB_INIT(control_data_head
);
520 Control_Type type
= control
->type
;
521 long font_idx
= control
->font_idx
;
522 long glyph_idx
= control
->glyph_idx
;
523 int x_shift
= control
->x_shift
;
524 int y_shift
= control
->y_shift
;
526 number_set_iter ppems_iter
;
530 ppems_iter
.range
= control
->ppems
;
531 ppem
= number_set_get_first(&ppems_iter
);
533 /* ppem is always zero for one-point segments */
534 if (type
== Control_Segment_Left
535 || type
== Control_Segment_Right
536 || type
== Control_Segment_None
)
539 while (ppems_iter
.range
)
541 number_set_iter points_iter
;
546 points_iter
.range
= control
->points
;
547 point_idx
= number_set_get_first(&points_iter
);
549 while (points_iter
.range
)
555 node
= (Node
*)malloc(sizeof (Node
));
557 return FT_Err_Out_Of_Memory
;
559 node
->ctrl
.type
= type
;
560 node
->ctrl
.font_idx
= font_idx
;
561 node
->ctrl
.glyph_idx
= glyph_idx
;
562 node
->ctrl
.ppem
= ppem
;
563 node
->ctrl
.point_idx
= point_idx
;
564 node
->ctrl
.x_shift
= x_shift
;
565 node
->ctrl
.y_shift
= y_shift
;
567 val
= LLRB_INSERT(control_data
, control_data_head
, node
);
570 if (val
&& font
->debug
)
572 /* entry is already present; we ignore it */
580 /* construct Control entry for debugging output */
584 points
.start
= point_idx
;
585 points
.end
= point_idx
;
589 d
.font_idx
= font_idx
;
590 d
.glyph_idx
= glyph_idx
;
597 s
= control_show_line(font
, &d
);
600 fprintf(stderr
, "Control instruction %s ignored.\n", s
);
607 point_idx
= number_set_get_next(&points_iter
);
610 ppem
= number_set_get_next(&ppems_iter
);
613 control
= control
->next
;
616 if (font
->debug
&& emit_newline
)
617 fprintf(stderr
, "\n");
619 font
->control_data_head
= control_data_head
;
620 font
->control_data_cur
= LLRB_MIN(control_data
, control_data_head
);
626 /* the next functions are intended to restrict the use of LLRB stuff */
627 /* related to control instructions to this file, */
628 /* providing a means to access the data sequentially */
631 TA_control_get_next(FONT
* font
)
633 Node
* node
= (Node
*)font
->control_data_cur
;
639 node
= LLRB_NEXT(control_data
, /* unused */, node
);
641 font
->control_data_cur
= node
;
646 TA_control_get_ctrl(FONT
* font
)
648 Node
* node
= (Node
*)font
->control_data_cur
;
651 return node
? &node
->ctrl
: NULL
;
656 TA_control_segment_dir_collect(FONT
* font
,
660 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
663 /* nothing to do if no data */
664 if (!font
->control_data_head
)
667 if (control_segment_dirs_head
)
669 TA_control_free(control_segment_dirs_head
);
670 control_segment_dirs_head
= NULL
;
674 * The PPEM value for one-point segments is always zero; such control
675 * instructions are thus sorted before other control instructions for the
676 * same glyph index -- this fits nicely with the call to
677 * `TA_control_get_next' in the loop of `TA_sfnt_build_delta_exceptions',
678 * assuring proper sequential access to the red-black tree.
682 const Ctrl
* ctrl
= TA_control_get_ctrl(font
);
690 if (!(ctrl
->type
== Control_Segment_Left
691 || ctrl
->type
== Control_Segment_Right
692 || ctrl
->type
== Control_Segment_None
))
695 /* too large values of font and glyph indices in `ctrl' */
696 /* are handled by later calls of this function */
697 if (font_idx
< ctrl
->font_idx
698 || glyph_idx
< ctrl
->glyph_idx
)
701 /* we simply use the `Control' structure again, */
702 /* abusing the `glyph_idx' field for the point index */
703 elem
= TA_control_new(ctrl
->type
,
712 TA_control_free(control_segment_dirs_head
);
713 return TA_Err_Control_Allocation_Error
;
715 control_segment_dirs_head
= TA_control_prepend(control_segment_dirs_head
,
718 TA_control_get_next(font
);
721 font
->control_segment_dirs_head
= TA_control_reverse(control_segment_dirs_head
);
722 font
->control_segment_dirs_cur
= font
->control_segment_dirs_head
;
729 TA_control_segment_dir_get_next(FONT
* font
,
735 Control
* control_segment_dirs_head
= (Control
*)font
->control_segment_dirs_head
;
736 Control
* control_segment_dirs_cur
= (Control
*)font
->control_segment_dirs_cur
;
739 /* nothing to do if no data */
740 if (!control_segment_dirs_head
)
743 if (!control_segment_dirs_cur
)
745 font
->control_segment_dirs_cur
= control_segment_dirs_head
;
749 /* the `glyph_idx' field gets abused for `point_idx' */
750 *point_idx
= control_segment_dirs_cur
->glyph_idx
;
751 *dir
= control_segment_dirs_cur
->type
== Control_Segment_Left
753 : control_segment_dirs_cur
->type
== Control_Segment_Right
756 *left_offset
= control_segment_dirs_cur
->x_shift
;
757 *right_offset
= control_segment_dirs_cur
->y_shift
;
759 font
->control_segment_dirs_cur
= control_segment_dirs_cur
->next
;
761 return control_segment_dirs_cur
!= NULL
;
764 /* end of tacontrol.c */