4 * Copyright (C) 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.
22 #include "llrb.h" /* a red-black tree implementation */
26 TA_deltas_new(long font_idx
,
28 number_range
* point_set
,
31 number_range
* ppem_set
)
36 deltas
= (Deltas
*)malloc(sizeof (Deltas
));
40 deltas
->font_idx
= font_idx
;
41 deltas
->glyph_idx
= glyph_idx
;
42 deltas
->points
= number_set_reverse(point_set
);
44 /* we round shift values to multiples of 1/(2^DELTA_SHIFT) */
45 deltas
->x_shift
= (char)(x_shift
* DELTA_FACTOR
46 + (x_shift
> 0 ? 0.5 : -0.5));
47 deltas
->y_shift
= (char)(y_shift
* DELTA_FACTOR
48 + (y_shift
> 0 ? 0.5 : -0.5));
50 deltas
->ppems
= number_set_reverse(ppem_set
);
58 TA_deltas_prepend(Deltas
* list
,
70 /* a test to check the validity of the first character */
71 /* in a PostScript glyph name -- for simplicity, we include `.' also */
73 const char* namestart_chars
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
74 "abcdefghijklmnopqrstuvwxyz"
80 return strchr(namestart_chars
, c
) != NULL
;
85 get_token(char** string_p
)
87 const char* s
= *string_p
;
88 const char* p
= *string_p
;
91 while (*p
&& !isspace(*p
))
99 /* in the following functions, `*string_p' is never '\0'; */
100 /* in case of error, `*string_p' should be set to a meaningful position */
103 get_font_idx(FONT
* font
,
107 const char* s
= *string_p
;
115 saved_locale
= setlocale(LC_NUMERIC
, "C");
117 font_idx
= strtol(s
, &endptr
, 0);
119 setlocale(LC_NUMERIC
, saved_locale
);
121 if (saved_errno
== ERANGE
)
124 return TA_Err_Deltas_Invalid_Font_Index
;
127 /* there must be a whitespace character after the number */
128 if (saved_errno
|| !isspace(*endptr
))
131 return TA_Err_Deltas_Syntax_Error
;
134 /* we have already tested that the first character in `s' is a digit, */
135 /* so `font_idx' can't be negative */
136 if (font_idx
>= font
->num_sfnts
)
139 return TA_Err_Deltas_Invalid_Font_Index
;
143 *font_idx_p
= font_idx
;
150 get_glyph_idx(FONT
* font
,
155 const char* s
= *string_p
;
159 FT_Face face
= font
->sfnts
[font_idx
].face
;
170 saved_locale
= setlocale(LC_NUMERIC
, "C");
172 glyph_idx
= strtol(s
, &endptr
, 0);
174 setlocale(LC_NUMERIC
, saved_locale
);
176 if (saved_errno
== ERANGE
)
179 return TA_Err_Deltas_Invalid_Glyph_Index
;
182 /* there must be a whitespace character after the number */
183 if (saved_errno
|| !isspace(*endptr
))
186 return TA_Err_Deltas_Syntax_Error
;
189 /* we have already tested that the first character in `s' is a digit, */
190 /* so `glyph_idx' can't be negative */
191 if (glyph_idx
>= face
->num_glyphs
)
194 return TA_Err_Deltas_Invalid_Glyph_Index
;
197 else if (isnamestart(*s
))
205 s
= get_token(&endptr
);
207 token
= strndup(s
, endptr
- s
);
211 return TA_Err_Deltas_Allocation_Error
;
214 /* explicitly compare with `.notdef' */
215 /* since `FT_Get_Name_Index' returns glyph index 0 */
216 /* for both this glyph name and invalid ones */
217 if (!strcmp(token
, ".notdef"))
221 glyph_idx
= FT_Get_Name_Index(face
, token
);
231 return TA_Err_Deltas_Invalid_Glyph_Name
;
239 return TA_Err_Deltas_Syntax_Error
;
243 *glyph_idx_p
= glyph_idx
;
250 get_range(char** string_p
,
251 number_range
** number_set_p
,
256 const char* s
= *string_p
;
257 number_range
* number_set
= *number_set_p
;
259 size_t s_len
= strcspn(s
, delims
);
264 /* there must be a whitespace character before the delimiter */
265 /* if it is not \0 */
267 && (!s_len
|| !isspace(s
[s_len
- 1])))
269 *string_p
= (char*)(s
+ s_len
);
270 return TA_Err_Deltas_Syntax_Error
;
273 token
= strndup(s
, s_len
);
277 return TA_Err_Deltas_Allocation_Error
;
280 endptr
= (char*)number_set_parse(token
, &number_set
, min
, max
);
282 /* use offset relative to `s' */
283 endptr
= (char*)s
+ (endptr
- token
);
286 if (number_set
== NUMBERSET_ALLOCATION_ERROR
)
289 return TA_Err_Deltas_Allocation_Error
;
294 if (number_set
== NUMBERSET_INVALID_CHARACTER
)
295 return TA_Err_Deltas_Invalid_Character
;
296 else if (number_set
== NUMBERSET_OVERFLOW
)
297 return TA_Err_Deltas_Overflow
;
298 else if (number_set
== NUMBERSET_INVALID_RANGE
)
299 /* this error code should be adjusted by the caller if necessary */
300 return TA_Err_Deltas_Invalid_Point_Range
;
301 else if (number_set
== NUMBERSET_OVERLAPPING_RANGES
)
302 return TA_Err_Deltas_Overlapping_Ranges
;
303 else if (number_set
== NUMBERSET_NOT_ASCENDING
)
304 return TA_Err_Deltas_Ranges_Not_Ascending
;
306 *number_set_p
= number_set
;
313 get_shift(char** string_p
,
316 const char* s
= *string_p
;
324 saved_locale
= setlocale(LC_NUMERIC
, "C");
326 shift
= strtod(s
, &endptr
);
328 setlocale(LC_NUMERIC
, saved_locale
);
330 if (saved_errno
== ERANGE
)
333 /* this error code should be adjusted by the caller if necessary */
334 return TA_Err_Deltas_Invalid_X_Range
;
337 /* there must be a whitespace character after the number */
338 if (saved_errno
|| !isspace(*endptr
))
341 return TA_Err_Deltas_Syntax_Error
;
344 if (shift
< DELTA_SHIFT_MIN
|| shift
> DELTA_SHIFT_MAX
)
347 return TA_Err_Deltas_Invalid_X_Range
;
352 /* we round the value to a multiple of 1/(2^DELTA_SHIFT) */
353 *shift_p
= (char)(shift
* DELTA_FACTOR
+ (shift
> 0 ? 0.5 : -0.5));
360 * Parse a delta exceptions line.
362 * In case of success (this is, the delta exceptions description in `s' is
363 * valid), `pos' is a pointer to the final zero byte in string `s'. In case
364 * of an error, it points to the offending character in string `s'.
366 * If s is NULL, the function exits immediately, with NULL as the value of
369 * If the user provides a non-NULL `deltas' value, `deltas_parse' stores the
370 * parsed result in `*deltas', allocating the necessary memory. If there is
371 * no data (for example, an empty string or whitespace only) nothing gets
372 * allocated, and `*deltas' is set to NULL.
377 deltas_parse_line(FONT
* font
,
381 int ppem_min
, int ppem_max
)
403 char* pos
= (char*)s
;
410 number_range
* points
= NULL
;
413 number_range
* ppems
= NULL
;
426 State old_state
= state
;
431 while (isspace(*pos
))
444 next_is_space
= isspace(*(pos
+ 1));
449 token1
= get_token(&pos
);
454 token2
= get_token(&pos
);
461 /* possibility 1: <font idx> <glyph name> `p' */
463 && (isdigit(*token2
) || isnamestart(*token2
))
464 && (c
== 'p' && next_is_space
))
466 if (!(error
= get_font_idx(font
, &pos
, &font_idx
)))
467 state
= HAD_FONT_IDX
;
469 /* possibility 2: <glyph name> `p' */
470 else if ((isdigit(*token1
) || isnamestart(*token1
))
471 && (*token2
== 'p' && isspace(*(token2
+ 1))))
473 if (!(error
= get_glyph_idx(font
, font_idx
,
475 state
= HAD_GLYPH_IDX
;
481 if (!(error
= get_glyph_idx(font
, font_idx
,
483 state
= HAD_GLYPH_IDX
;
488 if (c
== 'p' && next_is_space
)
499 FT_Face face
= font
->sfnts
[font_idx
].face
;
503 ft_error
= FT_Load_Glyph(face
, glyph_idx
, FT_LOAD_NO_SCALE
);
506 error
= TA_Err_Deltas_Invalid_Glyph
;
510 num_points
= face
->glyph
->outline
.n_points
;
511 if (!(error
= get_range(&pos
, deltas_p
? &points
: NULL
,
512 0, num_points
- 1, "xy@")))
518 /* `x' or `y' or `@' */
535 if (!(error
= get_shift(&pos
, &x_shift
)))
555 if (!(error
= get_shift(&pos
, &y_shift
)))
557 if (error
== TA_Err_Deltas_Invalid_X_Range
)
558 error
= TA_Err_Deltas_Invalid_Y_Range
;
563 if (c
== '@' && next_is_space
)
572 if (!(error
= get_range(&pos
, deltas_p
? &ppems
: NULL
,
573 ppem_min
, ppem_max
, "")))
575 if (error
== TA_Err_Deltas_Invalid_Point_Range
)
576 error
= TA_Err_Deltas_Invalid_Ppem_Range
;
580 /* to make compiler happy */
584 if (old_state
== state
)
588 if (state
== HAD_PPEMS
)
593 Deltas
* deltas
= (Deltas
*)malloc(sizeof (Deltas
));
598 number_set_free(points
);
599 number_set_free(ppems
);
603 return TA_Err_Deltas_Allocation_Error
;
606 deltas
->font_idx
= font_idx
;
607 deltas
->glyph_idx
= glyph_idx
;
608 deltas
->points
= points
;
609 deltas
->x_shift
= x_shift
;
610 deltas
->y_shift
= y_shift
;
611 deltas
->ppems
= ppems
;
621 number_set_free(points
);
622 number_set_free(ppems
);
627 if (!error
&& state
!= START
)
628 error
= TA_Err_Deltas_Syntax_Error
;
638 TA_deltas_free(Deltas
* deltas
)
645 number_set_free(deltas
->points
);
646 number_set_free(deltas
->ppems
);
649 deltas
= deltas
->next
;
655 /* `len' is the length of the returned string */
658 deltas_show_line(FONT
* font
,
663 char glyph_name_buf
[64];
664 char* points_buf
= NULL
;
665 char* ppems_buf
= NULL
;
666 char* deltas_buf
= NULL
;
674 if (deltas
->font_idx
>= font
->num_sfnts
)
677 face
= font
->sfnts
[deltas
->font_idx
].face
;
678 glyph_name_buf
[0] = '\0';
679 if (FT_HAS_GLYPH_NAMES(face
))
680 FT_Get_Glyph_Name(face
, deltas
->glyph_idx
, glyph_name_buf
, 64);
682 points_buf
= number_set_show(deltas
->points
, -1, -1);
685 ppems_buf
= number_set_show(deltas
->ppems
, -1, -1);
689 /* display glyph index if we don't have a glyph name */
691 ret
= asprintf(&deltas_buf
, "%ld %s p %s x %.20g y %.20g @ %s",
695 (double)deltas
->x_shift
/ DELTA_FACTOR
,
696 (double)deltas
->y_shift
/ DELTA_FACTOR
,
699 ret
= asprintf(&deltas_buf
, "%ld %ld p %s x %.20g y %.20g @ %s",
703 (double)deltas
->x_shift
/ DELTA_FACTOR
,
704 (double)deltas
->y_shift
/ DELTA_FACTOR
,
721 TA_deltas_show(FONT
* font
,
728 /* we return an empty string if there is no data */
729 s
= (char*)malloc(1);
744 tmp
= deltas_show_line(font
, &tmp_len
, deltas
);
751 /* append current line to buffer, followed by a newline character */
752 s_len_new
= s_len
+ tmp_len
+ 1;
753 s_new
= (char*)realloc(s
, s_len_new
);
761 strcpy(s_new
+ s_len
- 1, tmp
);
762 s_new
[s_len_new
- 2] = '\n';
763 s_new
[s_len_new
- 1] = '\0';
770 deltas
= deltas
->next
;
777 /* Get a line from a buffer, starting at `pos'. The final EOL */
778 /* character (or character pair) of the line (if existing) gets removed. */
779 /* After the call, `pos' points to the position right after the line in */
780 /* the buffer. The line is allocated with `malloc'; it returns NULL for */
781 /* end of data and allocation errors; the latter can be recognized by a */
782 /* changed value of `pos'. */
787 const char* start
= *pos
;
788 const char* p
= start
;
798 if (*p
== '\n' || *p
== '\r')
822 s
= (char*)malloc(len
+ 1);
827 strncpy(s
, start
, len
);
835 TA_deltas_parse(FONT
* font
,
837 unsigned int* errlinenum_p
,
848 unsigned int linenum
;
854 /* nothing to do if no data */
855 if (!font
->deltas_buf
)
861 bufpos
= font
->deltas_buf
;
867 /* parse line by line */
874 line
= get_line(&bufpos
);
877 if (bufpos
== bufpos_old
) /* end of data */
880 *errlinenum_p
= linenum
;
884 return FT_Err_Out_Of_Memory
;
887 error
= deltas_parse_line(font
,
890 deltas
? &new_deltas
: NULL
,
891 DELTA_PPEM_MIN
, DELTA_PPEM_MAX
);
894 *errlinenum_p
= linenum
;
903 if (deltas
&& new_deltas
)
905 new_deltas
->next
= cur
;
914 /* success; now reverse list to have elements in original order */
932 /* node structure for delta exception data */
934 typedef struct Node Node
;
937 LLRB_ENTRY(Node
) entry
;
942 /* comparison function for our red-black tree */
951 /* sort by font index ... */
952 diff
= e1
->delta
.font_idx
- e2
->delta
.font_idx
;
956 /* ... then by glyph index ... */
957 diff
= e1
->delta
.glyph_idx
- e2
->delta
.glyph_idx
;
961 /* ... then by ppem ... */
962 diff
= e1
->delta
.ppem
- e2
->delta
.ppem
;
966 /* ... then by point index */
967 diff
= e1
->delta
.point_idx
- e2
->delta
.point_idx
;
970 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
971 return (diff
> 0) - (diff
< 0);
975 /* the red-black tree function body */
976 typedef struct deltas_data deltas_data
;
978 LLRB_HEAD(deltas_data
, Node
);
980 /* no trailing semicolon in the next line */
981 LLRB_GENERATE_STATIC(deltas_data
, Node
, entry
, nodecmp
)
985 TA_deltas_free_tree(FONT
* font
)
987 deltas_data
* deltas_data_head
= (deltas_data
*)font
->deltas_data_head
;
993 if (!deltas_data_head
)
996 for (node
= LLRB_MIN(deltas_data
, deltas_data_head
);
1000 next_node
= LLRB_NEXT(deltas_data
, deltas_data_head
, node
);
1001 LLRB_REMOVE(deltas_data
, deltas_data_head
, node
);
1005 free(deltas_data_head
);
1010 TA_deltas_build_tree(FONT
* font
,
1013 deltas_data
* deltas_data_head
;
1014 int emit_newline
= 0;
1017 /* nothing to do if no data */
1020 font
->deltas_data_head
= NULL
;
1024 deltas_data_head
= (deltas_data
*)malloc(sizeof (deltas_data
));
1025 if (!deltas_data_head
)
1026 return FT_Err_Out_Of_Memory
;
1028 LLRB_INIT(deltas_data_head
);
1032 long font_idx
= deltas
->font_idx
;
1033 long glyph_idx
= deltas
->glyph_idx
;
1034 char x_shift
= deltas
->x_shift
;
1035 char y_shift
= deltas
->y_shift
;
1037 number_set_iter ppems_iter
;
1041 ppems_iter
.range
= deltas
->ppems
;
1042 ppem
= number_set_get_first(&ppems_iter
);
1044 while (ppems_iter
.range
)
1046 number_set_iter points_iter
;
1050 points_iter
.range
= deltas
->points
;
1051 point_idx
= number_set_get_first(&points_iter
);
1053 while (points_iter
.range
)
1059 node
= (Node
*)malloc(sizeof (Node
));
1061 return FT_Err_Out_Of_Memory
;
1063 node
->delta
.font_idx
= font_idx
;
1064 node
->delta
.glyph_idx
= glyph_idx
;
1065 node
->delta
.ppem
= ppem
;
1066 node
->delta
.point_idx
= point_idx
;
1067 node
->delta
.x_shift
= x_shift
;
1068 node
->delta
.y_shift
= y_shift
;
1070 val
= LLRB_INSERT(deltas_data
, deltas_data_head
, node
);
1073 if (val
&& font
->debug
)
1075 /* entry is already present; we ignore it */
1078 number_range points
;
1084 /* construct Deltas entry for debugging output */
1088 points
.start
= point_idx
;
1089 points
.end
= point_idx
;
1092 deltas
.font_idx
= font_idx
;
1093 deltas
.glyph_idx
= glyph_idx
;
1094 deltas
.points
= &points
;
1095 deltas
.x_shift
= x_shift
;
1096 deltas
.y_shift
= y_shift
;
1097 deltas
.ppems
= &ppems
;
1100 s
= deltas_show_line(font
, &s_len
, &deltas
);
1103 fprintf(stderr
, "Delta exception %s ignored.\n", s
);
1110 point_idx
= number_set_get_next(&points_iter
);
1113 ppem
= number_set_get_next(&ppems_iter
);
1116 deltas
= deltas
->next
;
1119 if (font
->debug
&& emit_newline
)
1120 fprintf(stderr
, "\n");
1122 font
->deltas_data_head
= deltas_data_head
;
1123 font
->deltas_data_cur
= LLRB_MIN(deltas_data
, deltas_data_head
);
1129 /* the next functions are intended to restrict the use of LLRB stuff */
1130 /* related to delta exceptions to this file, */
1131 /* providing a means to access the data sequentially */
1134 TA_deltas_get_next(FONT
* font
)
1136 Node
* node
= (Node
*)font
->deltas_data_cur
;
1142 node
= LLRB_NEXT(deltas_data
, /* unused */, node
);
1144 font
->deltas_data_cur
= node
;
1149 TA_deltas_get_delta(FONT
* font
)
1151 Node
* node
= (Node
*)font
->deltas_data_cur
;
1154 return node
? &node
->delta
: NULL
;
1157 /* end of tadeltas.c */