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
,
71 TA_deltas_reverse(Deltas
* list
)
94 /* a test to check the validity of the first character */
95 /* in a PostScript glyph name -- for simplicity, we include `.' also */
97 const char* namestart_chars
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
98 "abcdefghijklmnopqrstuvwxyz"
104 return strchr(namestart_chars
, c
) != NULL
;
109 get_token(char** string_p
)
111 const char* s
= *string_p
;
112 const char* p
= *string_p
;
115 while (*p
&& !isspace(*p
))
118 *string_p
= (char*)p
;
123 /* in the following functions, `*string_p' is never '\0'; */
124 /* in case of error, `*string_p' should be set to a meaningful position */
127 get_font_idx(FONT
* font
,
131 const char* s
= *string_p
;
139 saved_locale
= setlocale(LC_NUMERIC
, "C");
141 font_idx
= strtol(s
, &endptr
, 0);
143 setlocale(LC_NUMERIC
, saved_locale
);
145 if (saved_errno
== ERANGE
)
148 return TA_Err_Deltas_Invalid_Font_Index
;
151 /* there must be a whitespace character after the number */
152 if (saved_errno
|| !isspace(*endptr
))
155 return TA_Err_Deltas_Syntax_Error
;
158 /* we have already tested that the first character in `s' is a digit, */
159 /* so `font_idx' can't be negative */
160 if (font_idx
>= font
->num_sfnts
)
163 return TA_Err_Deltas_Invalid_Font_Index
;
167 *font_idx_p
= font_idx
;
174 get_glyph_idx(FONT
* font
,
179 const char* s
= *string_p
;
183 FT_Face face
= font
->sfnts
[font_idx
].face
;
194 saved_locale
= setlocale(LC_NUMERIC
, "C");
196 glyph_idx
= strtol(s
, &endptr
, 0);
198 setlocale(LC_NUMERIC
, saved_locale
);
200 if (saved_errno
== ERANGE
)
203 return TA_Err_Deltas_Invalid_Glyph_Index
;
206 /* there must be a whitespace character after the number */
207 if (saved_errno
|| !isspace(*endptr
))
210 return TA_Err_Deltas_Syntax_Error
;
213 /* we have already tested that the first character in `s' is a digit, */
214 /* so `glyph_idx' can't be negative */
215 if (glyph_idx
>= face
->num_glyphs
)
218 return TA_Err_Deltas_Invalid_Glyph_Index
;
221 else if (isnamestart(*s
))
229 s
= get_token(&endptr
);
231 token
= strndup(s
, endptr
- s
);
235 return TA_Err_Deltas_Allocation_Error
;
238 /* explicitly compare with `.notdef' */
239 /* since `FT_Get_Name_Index' returns glyph index 0 */
240 /* for both this glyph name and invalid ones */
241 if (!strcmp(token
, ".notdef"))
245 glyph_idx
= FT_Get_Name_Index(face
, token
);
255 return TA_Err_Deltas_Invalid_Glyph_Name
;
263 return TA_Err_Deltas_Syntax_Error
;
267 *glyph_idx_p
= glyph_idx
;
274 get_range(char** string_p
,
275 number_range
** number_set_p
,
280 const char* s
= *string_p
;
281 number_range
* number_set
= *number_set_p
;
283 size_t s_len
= strcspn(s
, delims
);
288 /* there must be a whitespace character before the delimiter */
289 /* if it is not \0 */
291 && (!s_len
|| !isspace(s
[s_len
- 1])))
293 *string_p
= (char*)(s
+ s_len
);
294 return TA_Err_Deltas_Syntax_Error
;
297 token
= strndup(s
, s_len
);
301 return TA_Err_Deltas_Allocation_Error
;
304 endptr
= (char*)number_set_parse(token
, &number_set
, min
, max
);
306 /* use offset relative to `s' */
307 endptr
= (char*)s
+ (endptr
- token
);
310 if (number_set
== NUMBERSET_ALLOCATION_ERROR
)
313 return TA_Err_Deltas_Allocation_Error
;
318 if (number_set
== NUMBERSET_INVALID_CHARACTER
)
319 return TA_Err_Deltas_Invalid_Character
;
320 else if (number_set
== NUMBERSET_OVERFLOW
)
321 return TA_Err_Deltas_Overflow
;
322 else if (number_set
== NUMBERSET_INVALID_RANGE
)
323 return TA_Err_Deltas_Invalid_Range
;
324 else if (number_set
== NUMBERSET_OVERLAPPING_RANGES
)
325 return TA_Err_Deltas_Overlapping_Ranges
;
326 else if (number_set
== NUMBERSET_NOT_ASCENDING
)
327 return TA_Err_Deltas_Ranges_Not_Ascending
;
329 *number_set_p
= number_set
;
336 get_shift(char** string_p
,
339 const char* s
= *string_p
;
347 saved_locale
= setlocale(LC_NUMERIC
, "C");
349 shift
= strtod(s
, &endptr
);
351 setlocale(LC_NUMERIC
, saved_locale
);
353 if (saved_errno
== ERANGE
)
356 return TA_Err_Deltas_Invalid_Shift
;
359 /* there must be a whitespace character after the number */
360 if (saved_errno
|| !isspace(*endptr
))
363 return TA_Err_Deltas_Syntax_Error
;
366 if (shift
< DELTA_SHIFT_MIN
|| shift
> DELTA_SHIFT_MAX
)
369 return TA_Err_Deltas_Invalid_Shift
;
374 /* we round the value to a multiple of 1/(2^DELTA_SHIFT) */
375 *shift_p
= (char)(shift
* DELTA_FACTOR
+ (shift
> 0 ? 0.5 : -0.5));
382 * Parse a delta exceptions line.
384 * In case of success (this is, the delta exceptions description in `s' is
385 * valid), `pos' is a pointer to the final zero byte in string `s'. In case
386 * of an error, it points to the offending character in string `s'.
388 * If s is NULL, the function exits immediately, with NULL as the value of
391 * If the user provides a non-NULL `deltas' value, `deltas_parse' stores the
392 * parsed result in `*deltas', allocating the necessary memory. If there is
393 * no data (for example, an empty string or whitespace only) nothing gets
394 * allocated, and `*deltas' is set to NULL.
399 deltas_parse_line(FONT
* font
,
403 int ppem_min
, int ppem_max
)
425 char* pos
= (char*)s
;
432 number_range
* points
= NULL
;
435 number_range
* ppems
= NULL
;
448 State old_state
= state
;
453 while (isspace(*pos
))
466 next_is_space
= isspace(*(pos
+ 1));
471 token1
= get_token(&pos
);
476 token2
= get_token(&pos
);
483 /* possibility 1: <font idx> <glyph name> `p' */
485 && (isdigit(*token2
) || isnamestart(*token2
))
486 && (c
== 'p' && next_is_space
))
488 if (!(error
= get_font_idx(font
, &pos
, &font_idx
)))
489 state
= HAD_FONT_IDX
;
491 /* possibility 2: <glyph name> `p' */
492 else if ((isdigit(*token1
) || isnamestart(*token1
))
493 && (*token2
== 'p' && isspace(*(token2
+ 1))))
495 if (!(error
= get_glyph_idx(font
, font_idx
,
497 state
= HAD_GLYPH_IDX
;
503 if (!(error
= get_glyph_idx(font
, font_idx
,
505 state
= HAD_GLYPH_IDX
;
510 if (c
== 'p' && next_is_space
)
521 FT_Face face
= font
->sfnts
[font_idx
].face
;
525 ft_error
= FT_Load_Glyph(face
, glyph_idx
, FT_LOAD_NO_SCALE
);
528 error
= TA_Err_Deltas_Invalid_Glyph
;
532 num_points
= face
->glyph
->outline
.n_points
;
533 if (!(error
= get_range(&pos
, deltas_p
? &points
: NULL
,
534 0, num_points
- 1, "xy@")))
540 /* `x' or `y' or `@' */
557 if (!(error
= get_shift(&pos
, &x_shift
)))
577 if (!(error
= get_shift(&pos
, &y_shift
)))
583 if (c
== '@' && next_is_space
)
592 if (!(error
= get_range(&pos
, deltas_p
? &ppems
: NULL
,
593 ppem_min
, ppem_max
, "")))
598 /* to make compiler happy */
602 if (old_state
== state
)
606 if (state
== HAD_PPEMS
)
611 Deltas
* deltas
= (Deltas
*)malloc(sizeof (Deltas
));
616 number_set_free(points
);
617 number_set_free(ppems
);
621 return TA_Err_Deltas_Allocation_Error
;
624 deltas
->font_idx
= font_idx
;
625 deltas
->glyph_idx
= glyph_idx
;
626 deltas
->points
= points
;
627 deltas
->x_shift
= x_shift
;
628 deltas
->y_shift
= y_shift
;
629 deltas
->ppems
= ppems
;
639 number_set_free(points
);
640 number_set_free(ppems
);
645 if (!error
&& state
!= START
)
646 error
= TA_Err_Deltas_Syntax_Error
;
656 TA_deltas_free(Deltas
* deltas
)
663 number_set_free(deltas
->points
);
664 number_set_free(deltas
->ppems
);
667 deltas
= deltas
->next
;
673 /* `len' is the length of the returned string */
676 deltas_show_line(FONT
* font
,
681 char glyph_name_buf
[64];
682 char* points_buf
= NULL
;
683 char* ppems_buf
= NULL
;
684 char* deltas_buf
= NULL
;
692 if (deltas
->font_idx
>= font
->num_sfnts
)
695 face
= font
->sfnts
[deltas
->font_idx
].face
;
696 glyph_name_buf
[0] = '\0';
697 if (FT_HAS_GLYPH_NAMES(face
))
698 FT_Get_Glyph_Name(face
, deltas
->glyph_idx
, glyph_name_buf
, 64);
700 points_buf
= number_set_show(deltas
->points
, -1, -1);
703 ppems_buf
= number_set_show(deltas
->ppems
, -1, -1);
707 /* display glyph index if we don't have a glyph name */
709 ret
= asprintf(&deltas_buf
, "%ld %s p %s x %.20g y %.20g @ %s",
713 (double)deltas
->x_shift
/ DELTA_FACTOR
,
714 (double)deltas
->y_shift
/ DELTA_FACTOR
,
717 ret
= asprintf(&deltas_buf
, "%ld %ld p %s x %.20g y %.20g @ %s",
721 (double)deltas
->x_shift
/ DELTA_FACTOR
,
722 (double)deltas
->y_shift
/ DELTA_FACTOR
,
739 TA_deltas_show(FONT
* font
,
746 /* we return an empty string if there is no data */
747 s
= (char*)malloc(1);
762 tmp
= deltas_show_line(font
, &tmp_len
, deltas
);
769 /* append current line to buffer, followed by a newline character */
770 s_len_new
= s_len
+ tmp_len
+ 1;
771 s_new
= (char*)realloc(s
, s_len_new
);
779 strcpy(s_new
+ s_len
- 1, tmp
);
780 s_new
[s_len_new
- 2] = '\n';
781 s_new
[s_len_new
- 1] = '\0';
788 deltas
= deltas
->next
;
795 /* Get a line from a buffer, starting at `pos'. The final EOL */
796 /* character (or character pair) of the line (if existing) gets removed. */
797 /* After the call, `pos' points to the position right after the line in */
798 /* the buffer. The line is allocated with `malloc'; it returns NULL for */
799 /* end of data and allocation errors; the latter can be recognized by a */
800 /* changed value of `pos'. */
805 const char* start
= *pos
;
806 const char* p
= start
;
816 if (*p
== '\n' || *p
== '\r')
840 s
= (char*)malloc(len
+ 1);
845 strncpy(s
, start
, len
);
853 TA_deltas_parse_buffer(FONT
* font
,
855 unsigned int* errlinenum_p
,
866 unsigned int linenum
;
872 /* nothing to do if no data */
873 if (!font
->deltas_buf
)
879 bufpos
= font
->deltas_buf
;
885 /* parse line by line */
892 line
= get_line(&bufpos
);
895 if (bufpos
== bufpos_old
) /* end of data */
898 *errlinenum_p
= linenum
;
902 return FT_Err_Out_Of_Memory
;
905 error
= deltas_parse_line(font
,
908 deltas
? &new_deltas
: NULL
,
909 DELTA_PPEM_MIN
, DELTA_PPEM_MAX
);
912 *errlinenum_p
= linenum
;
921 if (deltas
&& new_deltas
)
923 new_deltas
->next
= cur
;
932 /* success; now reverse list to have elements in original order */
950 /* node structure for delta exception data */
952 typedef struct Node Node
;
955 LLRB_ENTRY(Node
) entry
;
960 /* comparison function for our red-black tree */
969 /* sort by font index ... */
970 diff
= e1
->delta
.font_idx
- e2
->delta
.font_idx
;
974 /* ... then by glyph index ... */
975 diff
= e1
->delta
.glyph_idx
- e2
->delta
.glyph_idx
;
979 /* ... then by ppem ... */
980 diff
= e1
->delta
.ppem
- e2
->delta
.ppem
;
984 /* ... then by point index */
985 diff
= e1
->delta
.point_idx
- e2
->delta
.point_idx
;
988 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
989 return (diff
> 0) - (diff
< 0);
993 /* the red-black tree function body */
994 typedef struct deltas_data deltas_data
;
996 LLRB_HEAD(deltas_data
, Node
);
998 /* no trailing semicolon in the next line */
999 LLRB_GENERATE_STATIC(deltas_data
, Node
, entry
, nodecmp
)
1003 TA_deltas_free_tree(FONT
* font
)
1005 deltas_data
* deltas_data_head
= (deltas_data
*)font
->deltas_data_head
;
1011 if (!deltas_data_head
)
1014 for (node
= LLRB_MIN(deltas_data
, deltas_data_head
);
1018 next_node
= LLRB_NEXT(deltas_data
, deltas_data_head
, node
);
1019 LLRB_REMOVE(deltas_data
, deltas_data_head
, node
);
1023 free(deltas_data_head
);
1028 TA_deltas_build_tree(FONT
* font
,
1031 deltas_data
* deltas_data_head
;
1032 int emit_newline
= 0;
1035 /* nothing to do if no data */
1038 font
->deltas_data_head
= NULL
;
1042 deltas_data_head
= (deltas_data
*)malloc(sizeof (deltas_data
));
1043 if (!deltas_data_head
)
1044 return FT_Err_Out_Of_Memory
;
1046 LLRB_INIT(deltas_data_head
);
1050 long font_idx
= deltas
->font_idx
;
1051 long glyph_idx
= deltas
->glyph_idx
;
1052 char x_shift
= deltas
->x_shift
;
1053 char y_shift
= deltas
->y_shift
;
1055 number_set_iter ppems_iter
;
1059 ppems_iter
.range
= deltas
->ppems
;
1060 ppem
= number_set_get_first(&ppems_iter
);
1062 while (ppems_iter
.range
)
1064 number_set_iter points_iter
;
1068 points_iter
.range
= deltas
->points
;
1069 point_idx
= number_set_get_first(&points_iter
);
1071 while (points_iter
.range
)
1077 node
= (Node
*)malloc(sizeof (Node
));
1079 return FT_Err_Out_Of_Memory
;
1081 node
->delta
.font_idx
= font_idx
;
1082 node
->delta
.glyph_idx
= glyph_idx
;
1083 node
->delta
.ppem
= ppem
;
1084 node
->delta
.point_idx
= point_idx
;
1085 node
->delta
.x_shift
= x_shift
;
1086 node
->delta
.y_shift
= y_shift
;
1088 val
= LLRB_INSERT(deltas_data
, deltas_data_head
, node
);
1091 if (val
&& font
->debug
)
1093 /* entry is already present; we ignore it */
1096 number_range points
;
1102 /* construct Deltas entry for debugging output */
1106 points
.start
= point_idx
;
1107 points
.end
= point_idx
;
1110 deltas
.font_idx
= font_idx
;
1111 deltas
.glyph_idx
= glyph_idx
;
1112 deltas
.points
= &points
;
1113 deltas
.x_shift
= x_shift
;
1114 deltas
.y_shift
= y_shift
;
1115 deltas
.ppems
= &ppems
;
1118 s
= deltas_show_line(font
, &s_len
, &deltas
);
1121 fprintf(stderr
, "Delta exception %s ignored.\n", s
);
1128 point_idx
= number_set_get_next(&points_iter
);
1131 ppem
= number_set_get_next(&ppems_iter
);
1134 deltas
= deltas
->next
;
1137 if (font
->debug
&& emit_newline
)
1138 fprintf(stderr
, "\n");
1140 font
->deltas_data_head
= deltas_data_head
;
1141 font
->deltas_data_cur
= LLRB_MIN(deltas_data
, deltas_data_head
);
1147 /* the next functions are intended to restrict the use of LLRB stuff */
1148 /* related to delta exceptions to this file, */
1149 /* providing a means to access the data sequentially */
1152 TA_deltas_get_next(FONT
* font
)
1154 Node
* node
= (Node
*)font
->deltas_data_cur
;
1160 node
= LLRB_NEXT(deltas_data
, /* unused */, node
);
1162 font
->deltas_data_cur
= node
;
1167 TA_deltas_get_delta(FONT
* font
)
1169 Node
* node
= (Node
*)font
->deltas_data_cur
;
1172 return node
? &node
->delta
: NULL
;
1175 /* end of tadeltas.c */