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(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
,
59 const char* s
= *string_p
;
65 font_idx
= strtol(s
, &endptr
, 0);
70 return TA_Err_Deltas_Invalid_Font_Index
;
73 /* there must be a whitespace character after the number */
74 if (errno
|| !isspace(*endptr
))
77 return TA_Err_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_Err_Deltas_Invalid_Font_Index
;
89 *font_idx_p
= font_idx
;
96 get_glyph_idx(FONT
* font
,
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_Err_Deltas_Invalid_Glyph_Index
;
121 /* there must be a whitespace character after the number */
122 if (errno
|| !isspace(*endptr
))
125 return TA_Err_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_Err_Deltas_Invalid_Glyph_Index
;
136 else if (isnamestart(*s
))
144 s
= get_token(&endptr
);
146 token
= strndup(s
, endptr
- s
);
150 return TA_Err_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_Err_Deltas_Invalid_Glyph_Name
;
178 return TA_Err_Deltas_Syntax_Error
;
182 *glyph_idx_p
= glyph_idx
;
189 get_range(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
= (char*)(s
+ s_len
);
209 return TA_Err_Deltas_Syntax_Error
;
212 token
= strndup(s
, s_len
);
216 return TA_Err_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_Err_Deltas_Allocation_Error
;
233 if (number_set
== NUMBERSET_INVALID_CHARACTER
)
234 return TA_Err_Deltas_Invalid_Character
;
235 else if (number_set
== NUMBERSET_OVERFLOW
)
236 return TA_Err_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_Err_Deltas_Invalid_Point_Range
;
240 else if (number_set
== NUMBERSET_OVERLAPPING_RANGES
)
241 return TA_Err_Deltas_Overlapping_Ranges
;
242 else if (number_set
== NUMBERSET_NOT_ASCENDING
)
243 return TA_Err_Deltas_Ranges_Not_Ascending
;
245 *number_set_p
= number_set
;
252 get_shift(char** string_p
,
255 const char* s
= *string_p
;
261 shift
= strtod(s
, &endptr
);
266 /* this error code should be adjusted by the caller if necessary */
267 return TA_Err_Deltas_Invalid_X_Range
;
270 /* there must be a whitespace character after the number */
271 if (errno
|| !isspace(*endptr
))
274 return TA_Err_Deltas_Syntax_Error
;
277 if (shift
< DELTA_SHIFT_MIN
|| shift
> DELTA_SHIFT_MAX
)
280 return TA_Err_Deltas_Invalid_X_Range
;
285 /* we round the value to a multiple of 1/(2^DELTA_SHIFT) */
286 *shift_p
= (char)(shift
* DELTA_FACTOR
+ (shift
> 0 ? 0.5 : -0.5));
293 TA_deltas_parse(FONT
* font
,
297 int ppem_min
, int ppem_max
)
319 Deltas
* deltas
= NULL
;
320 char* pos
= (char*)s
;
332 deltas
= (Deltas
*)malloc(sizeof (Deltas
));
337 return TA_Err_Deltas_Allocation_Error
;
340 deltas
->font_idx
= 0;
341 deltas
->glyph_idx
= -1;
342 deltas
->points
= NULL
;
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
);
386 /* possibility 1: <font idx> <glyph name> `p' */
388 && (isdigit(*token2
) || isnamestart(*token2
))
389 && (c
== 'p' && next_is_space
))
391 if (!(error
= get_font_idx(font
, &pos
, &deltas
->font_idx
)))
392 state
= HAD_FONT_IDX
;
394 /* possibility 2: <glyph name> `p' */
395 else if ((isdigit(*token1
) || isnamestart(*token1
))
396 && (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_Err_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
)))
480 if (!(error
= get_shift(&pos
, &deltas
->y_shift
)))
482 if (error
== TA_Err_Deltas_Invalid_X_Range
)
483 error
= TA_Err_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_Err_Deltas_Invalid_Point_Range
)
501 error
= TA_Err_Deltas_Invalid_Ppem_Range
;
505 /* to make compiler happy */
509 if (old_state
== state
)
513 if (state
== HAD_PPEMS
)
519 TA_deltas_free(deltas
);
523 TA_deltas_free(deltas
);
526 if (!error
&& state
!= START
)
527 error
= TA_Err_Deltas_Syntax_Error
;
537 TA_deltas_free(Deltas
* deltas
)
542 number_set_free(deltas
->points
);
543 number_set_free(deltas
->ppems
);
550 TA_deltas_show(FONT
* font
,
554 char glyph_name_buf
[64];
555 char* points_buf
= NULL
;
556 char* ppems_buf
= NULL
;
557 char* deltas_buf
= NULL
;
565 if (deltas
->font_idx
>= font
->num_sfnts
)
568 face
= font
->sfnts
[deltas
->font_idx
].face
;
569 glyph_name_buf
[0] = '\0';
570 if (FT_HAS_GLYPH_NAMES(face
))
571 FT_Get_Glyph_Name(face
, deltas
->glyph_idx
, glyph_name_buf
, 64);
573 points_buf
= number_set_show(deltas
->points
, -1, -1);
576 ppems_buf
= number_set_show(deltas
->ppems
, -1, -1);
580 /* display glyph index if we don't have a glyph name */
582 ret
= asprintf(&deltas_buf
, "%ld %s p %s x %.20g y %.20g @ %s",
586 (double)deltas
->x_shift
/ DELTA_FACTOR
,
587 (double)deltas
->y_shift
/ DELTA_FACTOR
,
590 ret
= asprintf(&deltas_buf
, "%ld %ld p %s x %.20g y %.20g @ %s",
594 (double)deltas
->x_shift
/ DELTA_FACTOR
,
595 (double)deltas
->y_shift
/ DELTA_FACTOR
,
608 /* end of tadeltas.c */