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 /* a test to check the validity of the first character */
23 /* in a PostScript glyph name -- for simplicity, we include `.' also */
25 const char* namestart_chars
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
26 "abcdefghijklmnopqrstuvwxyz"
32 return strchr(namestart_chars
, c
) != NULL
;
37 get_token(const char** string_p
)
39 const char* s
= *string_p
;
40 const char* p
= *string_p
;
43 while (*p
&& !isspace(*p
))
51 /* in the following functions, `*string_p' is never '\0'; */
52 /* in case of error, `*string_p' should be set to a meaningful position */
55 get_font_idx(FONT
* font
,
56 const char** string_p
,
59 const char* s
= *string_p
;
65 font_idx
= strtol(s
, &endptr
, 0);
70 return TA_DELTAS_INVALID_FONT_INDEX
;
73 /* there must be a whitespace character after the number */
74 if (errno
|| !isspace(*endptr
))
77 return TA_DELTAS_SYNTAX_ERROR
;
80 /* we have already tested that the first character in `s' is a digit, */
81 /* so `font_idx' can't be negative */
82 if (font_idx
>= font
->num_sfnts
)
85 return TA_DELTAS_INVALID_FONT_INDEX
;
89 *font_idx_p
= font_idx
;
96 get_glyph_idx(FONT
* font
,
98 const char** string_p
,
101 const char* s
= *string_p
;
105 FT_Face face
= font
->sfnts
[font_idx
].face
;
113 glyph_idx
= strtol(s
, &endptr
, 0);
118 return TA_DELTAS_INVALID_GLYPH_INDEX
;
121 /* there must be a whitespace character after the number */
122 if (errno
|| !isspace(*endptr
))
125 return TA_DELTAS_SYNTAX_ERROR
;
128 /* we have already tested that the first character in `s' is a digit, */
129 /* so `glyph_idx' can't be negative */
130 if (glyph_idx
>= face
->num_glyphs
)
133 return TA_DELTAS_INVALID_GLYPH_INDEX
;
136 else if (isnamestart(*s
))
144 s
= get_token((const char**)&endptr
);
146 token
= strndup(s
, endptr
- s
);
150 return TA_DELTAS_ALLOCATION_ERROR
;
153 /* explicitly compare with `.notdef' */
154 /* since `FT_Get_Name_Index' returns glyph index 0 */
155 /* for both this glyph name and invalid ones */
156 if (!strcmp(token
, ".notdef"))
160 glyph_idx
= FT_Get_Name_Index(face
, token
);
170 return TA_DELTAS_INVALID_GLYPH_NAME
;
178 return TA_DELTAS_SYNTAX_ERROR
;
182 *glyph_idx_p
= glyph_idx
;
189 get_range(const char** string_p
,
190 number_range
** number_set_p
,
195 const char* s
= *string_p
;
196 number_range
* number_set
= *number_set_p
;
198 size_t s_len
= strcspn(s
, delims
);
203 /* there must be a whitespace character before the delimiter */
204 /* if it is not \0 */
206 && (!s_len
|| !isspace(s
[s_len
- 1])))
208 *string_p
= s
+ s_len
;
209 return TA_DELTAS_SYNTAX_ERROR
;
212 token
= strndup(s
, s_len
);
216 return TA_DELTAS_ALLOCATION_ERROR
;
219 endptr
= (char*)number_set_parse(token
, &number_set
, min
, max
);
221 /* use offset relative to `s' */
222 endptr
= (char*)s
+ (endptr
- token
);
225 if (number_set
== NUMBERSET_ALLOCATION_ERROR
)
228 return TA_DELTAS_ALLOCATION_ERROR
;
233 if (number_set
== NUMBERSET_INVALID_CHARACTER
)
234 return TA_DELTAS_INVALID_CHARACTER
;
235 else if (number_set
== NUMBERSET_OVERFLOW
)
236 return TA_DELTAS_OVERFLOW
;
237 else if (number_set
== NUMBERSET_INVALID_RANGE
)
238 /* this error code should be adjusted by the caller if necessary */
239 return TA_DELTAS_INVALID_POINT_RANGE
;
240 else if (number_set
== NUMBERSET_OVERLAPPING_RANGES
)
241 return TA_DELTAS_OVERLAPPING_RANGES
;
242 else if (number_set
== NUMBERSET_NOT_ASCENDING
)
243 return TA_DELTAS_NOT_ASCENDING
;
245 *number_set_p
= number_set
;
252 get_shift(const char** string_p
,
257 const char* s
= *string_p
;
263 shift
= strtod(s
, &endptr
);
268 /* this error code should be adjusted by the caller if necessary */
269 return TA_DELTAS_INVALID_X_RANGE
;
272 /* there must be a whitespace character after the number */
273 if (errno
|| !isspace(*endptr
))
276 return TA_DELTAS_SYNTAX_ERROR
;
279 if (shift
< min
|| shift
> max
)
282 return TA_DELTAS_INVALID_X_RANGE
;
285 /* we round the value to a multiple of 1/(2^DELTA_SHIFT) */
286 shift
= floor(shift
* DELTA_FACTOR
+ 0.5) / DELTA_FACTOR
;
296 TA_deltas_parse(FONT
* font
,
299 int x_min
, int x_max
,
300 int y_min
, int y_max
,
301 int ppem_min
, int ppem_max
)
321 Deltas
* deltas
= NULL
;
332 deltas
= (Deltas
*)malloc(sizeof (Deltas
));
336 *deltas_p
= TA_DELTAS_ALLOCATION_ERROR
;
340 deltas
->font_idx
= 0;
341 deltas
->glyph_idx
= -1;
342 deltas
->points
= NULL
;
343 deltas
->x_shift
= 0.0;
344 deltas
->y_shift
= 0.0;
345 deltas
->ppems
= NULL
;
351 State old_state
= state
;
356 while (isspace(*pos
))
369 next_is_space
= isspace(*(pos
+ 1));
374 token1
= get_token(&pos
);
379 token2
= get_token(&pos
);
384 /* possibility 1: <font idx> <glyph name> `p' */
386 && (isdigit(*token2
) || isnamestart(*token2
))
387 && (c
== 'p' && next_is_space
))
390 if (!(error
= get_font_idx(font
, &pos
, &deltas
->font_idx
)))
391 state
= HAD_FONT_IDX
;
393 /* possibility 2: <glyph name> `p' */
394 else if ((isdigit(*token1
) || isnamestart(*token1
))
395 && (c
== 'p' && next_is_space
))
398 if (!(error
= get_glyph_idx(font
, deltas
->font_idx
,
399 &pos
, &deltas
->glyph_idx
)))
400 state
= HAD_GLYPH_IDX
;
406 if (!(error
= get_glyph_idx(font
, deltas
->font_idx
,
407 &pos
, &deltas
->glyph_idx
)))
408 state
= HAD_GLYPH_IDX
;
413 if (c
== 'p' && next_is_space
)
424 FT_Face face
= font
->sfnts
[deltas
->font_idx
].face
;
428 ft_error
= FT_Load_Glyph(face
, deltas
->glyph_idx
, FT_LOAD_NO_SCALE
);
431 error
= TA_DELTAS_INVALID_GLYPH
;
435 num_points
= face
->glyph
->outline
.n_points
;
436 if (!(error
= get_range(&pos
, &deltas
->points
,
437 0, num_points
- 1, "xy@")))
443 /* `x' or `y' or `@' */
460 if (!(error
= get_shift(&pos
, &deltas
->x_shift
, x_min
, x_max
)))
480 if (!(error
= get_shift(&pos
, &deltas
->y_shift
, y_min
, y_max
)))
482 if (error
== TA_DELTAS_INVALID_X_RANGE
)
483 error
= TA_DELTAS_INVALID_Y_RANGE
;
488 if (c
== '@' && next_is_space
)
497 if (!(error
= get_range(&pos
, &deltas
->ppems
,
498 ppem_min
, ppem_max
, "")))
500 if (error
== TA_DELTAS_INVALID_POINT_RANGE
)
501 error
= TA_DELTAS_INVALID_PPEM_RANGE
;
505 /* to make compiler happy */
509 if (old_state
== state
)
513 if (state
== HAD_PPEMS
)
520 TA_deltas_free(deltas
);
530 TA_deltas_free(Deltas
* deltas
)
535 number_set_free(deltas
->points
);
536 number_set_free(deltas
->ppems
);
541 /* end of tadeltas.c */