3 // Copyright (C) 2012-2015 by Werner Lemberg.
5 // This file is part of the ttfautohint library, and may only be used,
6 // modified, and distributed under the terms given in `COPYING'. By
7 // continuing to use, modify, or distribute this file you indicate that you
8 // have read `COPYING' and understand and accept it fully.
10 // The file `COPYING' mentioned in the previous paragraph is distributed
11 // with the ttfautohint library.
18 // the next header file is from gnulib defining function `base_name',
19 // which is a replacement for `basename' that works on Windows also
24 #include <numberset.h>
27 #define TTFAUTOHINT_STRING "; ttfautohint"
28 #define TTFAUTOHINT_STRING_WIDE "\0;\0 \0t\0t\0f\0a\0u\0t\0o\0h\0i\0n\0t"
33 const char invalid_ps_chars
[96] =
35 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, // 0x20 %, (, ), /
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, // 0x30 <, >
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 0x50 [, ]
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, // 0x70 {, }, DEL
45 check_family_suffix(const char* s
)
49 int c
= (signed char)*s
- 0x20;
51 // valid range is 0x20-0x7E minus characters %()/<>[]{}
52 // (well, the space character 0x20 is not valid within a PS name,
53 // but the validity test gets executed before constructing a PS name,
54 // which has all space characters removed)
55 if (c
< 0 || invalid_ps_chars
[c
])
65 // build string that gets appended to the `Version' field(s)
66 // return value 1 means allocation error, value 2 too long a string
68 build_version_string(Info_Data
* idata
)
70 // since we use `goto' we have to initialize variables before the jumps
71 unsigned char* info_string
;
72 unsigned char* info_string_wide
;
83 d
= sdscatprintf(d
, TTFAUTOHINT_STRING
" (v%s)", VERSION
);
84 if (!idata
->detailed_info
)
92 d
= sdscatprintf(d
, " -l %d", idata
->hinting_range_min
);
93 d
= sdscatprintf(d
, " -r %d", idata
->hinting_range_max
);
94 d
= sdscatprintf(d
, " -G %d", idata
->hinting_limit
);
95 d
= sdscatprintf(d
, " -x %d", idata
->increase_x_height
);
96 if (idata
->fallback_stem_width
)
97 d
= sdscatprintf(d
, " -H %d", idata
->fallback_stem_width
);
98 d
= sdscatprintf(d
, " -D %s", idata
->default_script
);
99 d
= sdscatprintf(d
, " -f %s", idata
->fallback_script
);
100 if (idata
->control_name
)
102 char* bn
= base_name(idata
->control_name
);
103 d
= sdscatprintf(d
, " -m \"%s\"", bn
? bn
: idata
->control_name
);
112 if (idata
->gray_strong_stem_width
)
113 strong
[count
++] = 'g';
114 if (idata
->gdi_cleartype_strong_stem_width
)
115 strong
[count
++] = 'G';
116 if (idata
->dw_cleartype_strong_stem_width
)
117 strong
[count
++] = 'D';
119 d
= sdscatprintf(d
, " -w %s", strong
);
121 d
= sdscat(d
, " -w \"\"");
123 if (idata
->windows_compatibility
)
124 d
= sdscat(d
, " -W");
125 if (idata
->adjust_subglyphs
)
126 d
= sdscat(d
, " -p");
127 if (idata
->hint_composites
)
128 d
= sdscat(d
, " -c");
130 d
= sdscat(d
, " -s");
131 if (idata
->TTFA_info
)
132 d
= sdscat(d
, " -t");
134 if (idata
->x_height_snapping_exceptions_string
)
136 // only set specific value of `ret' for an allocation error,
137 // since syntax errors are handled in TTF_autohint
138 number_range
* x_height_snapping_exceptions
;
139 const char* pos
= number_set_parse(
140 idata
->x_height_snapping_exceptions_string
,
141 &x_height_snapping_exceptions
,
145 if (x_height_snapping_exceptions
== NUMBERSET_ALLOCATION_ERROR
)
150 s
= number_set_show(x_height_snapping_exceptions
, 6, 0x7FFF);
151 number_set_free(x_height_snapping_exceptions
);
153 // ensure UTF16-BE version doesn't get too long
154 if (strlen(s
) > 0xFFFF / 2 - sdslen(d
))
160 d
= sdscatprintf(d
, " -X \"%s\"", s
);
170 info_string
= (unsigned char*)malloc(sdslen(d
) + 1);
176 memcpy(info_string
, d
, sdslen(d
) + 1);
178 idata
->info_string
= info_string
;
179 idata
->info_string_len
= (unsigned short)sdslen(d
);
181 // prepare UTF16-BE version data
182 idata
->info_string_wide_len
= 2 * idata
->info_string_len
;
183 info_string_wide
= (unsigned char*)realloc(idata
->info_string_wide
,
184 idata
->info_string_wide_len
);
185 if (!info_string_wide
)
190 idata
->info_string_wide
= info_string_wide
;
192 dt
= idata
->info_string
;
193 dtw
= idata
->info_string_wide
;
194 for (unsigned short i
= 0; i
< idata
->info_string_len
; i
++)
207 free(idata
->info_string
);
208 free(idata
->info_string_wide
);
210 idata
->info_string
= NULL
;
211 idata
->info_string_wide
= NULL
;
212 idata
->info_string_len
= 0;
213 idata
->info_string_wide_len
= 0;
220 info_name_id_5(unsigned short platform_id
,
221 unsigned short encoding_id
,
226 unsigned char ttfautohint_string
[] = TTFAUTOHINT_STRING
;
227 unsigned char ttfautohint_string_wide
[] = TTFAUTOHINT_STRING_WIDE
;
229 // we use memmem, so don't count the trailing \0 character
230 size_t ttfautohint_string_len
= sizeof (TTFAUTOHINT_STRING
) - 1;
231 size_t ttfautohint_string_wide_len
= sizeof (TTFAUTOHINT_STRING_WIDE
) - 1;
234 unsigned short v_len
;
240 || (platform_id
== 3 && !(encoding_id
== 1
241 || encoding_id
== 10)))
243 // one-byte or multi-byte encodings
244 v
= idata
->info_string
;
245 v_len
= idata
->info_string_len
;
246 s
= ttfautohint_string
;
247 s_len
= ttfautohint_string_len
;
252 // (two-byte) UTF-16BE for everything else
253 v
= idata
->info_string_wide
;
254 v_len
= idata
->info_string_wide_len
;
255 s
= ttfautohint_string_wide
;
256 s_len
= ttfautohint_string_wide_len
;
260 // if we already have an ttfautohint info string,
261 // remove it up to a following `;' character (or end of string)
262 unsigned char* s_start
= (unsigned char*)memmem(*str
, *len
, s
, s_len
);
265 unsigned char* s_end
= s_start
+ offset
;
266 unsigned char* limit
= *str
+ *len
;
268 while (s_end
< limit
)
276 if (*(s_end
- 1) == '\0') // UTF-16BE
287 while (s_end
< limit
)
288 *s_start
++ = *s_end
++;
290 *len
-= s_end
- s_start
;
293 // do nothing if the string would become too long
294 if (*len
> 0xFFFF - v_len
)
297 unsigned short len_new
= *len
+ v_len
;
298 unsigned char* str_new
= (unsigned char*)realloc(*str
, len_new
);
303 memcpy(*str
+ *len
, v
, v_len
);
310 // a structure to collect family data for a given
311 // (platform_id, encoding_id, language_id) triplet
313 typedef struct Family_
315 unsigned short platform_id
;
316 unsigned short encoding_id
;
317 unsigned short language_id
;
319 unsigned short* name_id_1_len
;
320 unsigned char** name_id_1_str
;
321 unsigned short* name_id_4_len
;
322 unsigned char** name_id_4_str
;
323 unsigned short* name_id_6_len
;
324 unsigned char** name_id_6_str
;
325 unsigned short* name_id_16_len
;
326 unsigned char** name_id_16_str
;
327 unsigned short* name_id_21_len
;
328 unsigned char** name_id_21_str
;
334 // node structure for collected family data
336 typedef struct Node Node
;
339 LLRB_ENTRY(Node
) entry
;
344 // comparison function for our red-black tree
352 // sort by platform ID ...
353 diff
= e1
->family
.platform_id
- e2
->family
.platform_id
;
357 // ... then by encoding ID ...
358 diff
= e1
->family
.encoding_id
- e2
->family
.encoding_id
;
362 // ... then by language ID
363 diff
= e1
->family
.language_id
- e2
->family
.language_id
;
366 // https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign
367 return (diff
> 0) - (diff
< 0);
371 // the red-black tree function body
372 typedef struct family_data family_data
;
374 LLRB_HEAD(family_data
, Node
);
376 // no trailing semicolon in the next line
377 LLRB_GENERATE_STATIC(family_data
, Node
, entry
, nodecmp
)
381 family_data_free(Info_Data
* idata
)
383 family_data
* family_data_head
= (family_data
*)idata
->family_data_head
;
388 if (!family_data_head
)
391 for (node
= LLRB_MIN(family_data
, family_data_head
);
395 next_node
= LLRB_NEXT(family_data
, family_data_head
, node
);
396 LLRB_REMOVE(family_data
, family_data_head
, node
);
397 sdsfree(node
->family
.family_name
);
401 free(family_data_head
);
406 collect_family_data(unsigned short platform_id
,
407 unsigned short encoding_id
,
408 unsigned short language_id
,
409 unsigned short name_id
,
414 family_data
* family_data_head
= (family_data
*)idata
->family_data_head
;
418 if (!family_data_head
)
420 // first-time initialization
421 family_data_head
= (family_data
*)malloc(sizeof (family_data
));
422 if (!family_data_head
)
425 LLRB_INIT(family_data_head
);
426 idata
->family_data_head
= family_data_head
;
429 node
= (Node
*)malloc(sizeof (Node
));
433 node
->family
.platform_id
= platform_id
;
434 node
->family
.encoding_id
= encoding_id
;
435 node
->family
.language_id
= language_id
;
437 val
= LLRB_INSERT(family_data
, family_data_head
, node
);
440 // we already have an entry in the tree for our triplet
446 // initialize remaining fields
447 node
->family
.name_id_1_len
= NULL
;
448 node
->family
.name_id_1_str
= NULL
;
449 node
->family
.name_id_4_len
= NULL
;
450 node
->family
.name_id_4_str
= NULL
;
451 node
->family
.name_id_6_len
= NULL
;
452 node
->family
.name_id_6_str
= NULL
;
453 node
->family
.name_id_16_len
= NULL
;
454 node
->family
.name_id_16_str
= NULL
;
455 node
->family
.name_id_21_len
= NULL
;
456 node
->family
.name_id_21_str
= NULL
;
458 node
->family
.family_name
= NULL
;
463 node
->family
.name_id_1_len
= len
;
464 node
->family
.name_id_1_str
= str
;
466 else if (name_id
== 4)
468 node
->family
.name_id_4_len
= len
;
469 node
->family
.name_id_4_str
= str
;
471 else if (name_id
== 6)
473 node
->family
.name_id_6_len
= len
;
474 node
->family
.name_id_6_str
= str
;
476 else if (name_id
== 16)
478 node
->family
.name_id_16_len
= len
;
479 node
->family
.name_id_16_str
= str
;
481 else if (name_id
== 21)
483 node
->family
.name_id_21_len
= len
;
484 node
->family
.name_id_21_str
= str
;
491 // `info-callback' function
494 info(unsigned short platform_id
,
495 unsigned short encoding_id
,
496 unsigned short language_id
,
497 unsigned short name_id
,
502 Info_Data
* idata
= (Info_Data
*)user
;
504 // if ID is a version string, append our data
505 if (!idata
->no_info
&& name_id
== 5)
506 return info_name_id_5(platform_id
, encoding_id
, len
, str
, idata
);
508 // if ID is related to a family name, collect the data
509 if (*idata
->family_suffix
515 return collect_family_data(platform_id
,
527 // Insert `suffix' to `str', right after substring `name'.
528 // If `name' isn't a substring of `str', append `suffix' to `str'.
529 // Do nothing in case of allocation error or if resulting string is too long.
532 insert_suffix(sds suffix
,
537 if (!len
|| !*len
|| !str
|| !*str
)
542 // check whether `name' is a substring of `str'
543 unsigned char* s_start
= (unsigned char*)memmem(*str
, *len
,
546 // construct new string
549 size_t substring_end
= s_start
- *str
+ sdslen(name
);
551 // everything up to the end of the substring
552 s
= sdscatlen(s
, *str
, substring_end
);
554 s
= sdscatsds(s
, suffix
);
556 s
= sdscatlen(s
, *str
+ substring_end
, *len
- substring_end
);
560 s
= sdscatlen(s
, *str
, *len
);
561 s
= sdscatsds(s
, suffix
);
567 if (sdslen(s
) <= 0xFFFF)
569 unsigned short len_new
= sdslen(s
);
570 unsigned char* str_new
= (unsigned char*)realloc(*str
, len_new
);
574 memcpy(*str
, s
, len_new
);
583 // `info-post-callback' function
586 info_post(void* user
)
588 Info_Data
* idata
= (Info_Data
*)user
;
589 family_data
* family_data_head
= (family_data
*)idata
->family_data_head
;
592 // family_suffix + family_suffix_wide
594 sds family_suffix
= sdsnew(idata
->family_suffix
);
595 size_t family_suffix_len
= sdslen(family_suffix
);
597 sds family_suffix_wide
= sdsempty();
598 size_t family_suffix_wide_len
= 2 * family_suffix_len
;
600 // create sds with given size but uninitialized string data
601 family_suffix_wide
= sdsMakeRoomFor(family_suffix_wide
,
602 family_suffix_wide_len
);
606 // construct `family_suffix_wide' by inserting '\0'
608 char *fsw
= family_suffix_wide
;
609 for (size_t i
= 0; i
< family_suffix_len
; i
++)
614 sdsIncrLen(family_suffix_wide
, family_suffix_wide_len
);
617 // family_ps_suffix + family_ps_suffix_wide
619 sds family_ps_suffix
= sdsempty();
621 // create sds with estimated size but uninitialized string data;
622 // we later set the size to the actual value
623 family_ps_suffix
= sdsMakeRoomFor(family_ps_suffix
,
626 // construct `family_ps_suffix' by removing all space characters
628 char *fps
= family_ps_suffix
;
629 for (size_t i
= 0; i
< family_suffix_len
; i
++)
636 sdsIncrLen(family_ps_suffix
, fps
- family_ps_suffix
);
638 size_t family_ps_suffix_len
= sdslen(family_ps_suffix
);
640 sds family_ps_suffix_wide
= sdsempty();
641 size_t family_ps_suffix_wide_len
= 2 * family_ps_suffix_len
;
643 // create sds with given size but uninitialized string data
644 family_ps_suffix_wide
= sdsMakeRoomFor(family_ps_suffix_wide
,
645 family_ps_suffix_wide_len
);
647 // construct `family_ps_suffix_wide' by inserting '\0'
648 fps
= family_ps_suffix
;
649 char* fpsw
= family_ps_suffix_wide
;
650 for (size_t i
= 0; i
< family_ps_suffix_len
; i
++)
653 *(fpsw
++) = *(fps
++);
655 sdsIncrLen(family_ps_suffix_wide
, family_ps_suffix_wide_len
);
657 // We try the following algorithm.
659 // 1. If we have a `Preferred Family' (ID 16), use it as the family name,
660 // otherwise use the `Font Family Name' (ID 1). If necessary, search
661 // other language IDs for the current (platform ID, encoding ID) pair
662 // to find a family name.
664 // 2. Append the family suffix to the family substring in the `Font Family
665 // Name' (ID 1), the `Full Font Name' (ID 4), the `Preferred Family'
666 // (ID 16), and the `WWS Family Name' (ID 21). In case the family name
667 // found in step 1 is not a substring, append the suffix to the whole
670 // 3. Remove spaces from the family name and locate this substring in the
671 // `PostScript Name' (ID 6), then append the family suffix, also with
672 // spaces removed. If we don't have a substring, append the stripped
673 // suffix to the whole string.
675 // determine family name for all triplets if available
676 for (Node
* node
= LLRB_MIN(family_data
, family_data_head
);
678 node
= LLRB_NEXT(family_data
, family_data_head
, node
))
680 Family
* family
= &node
->family
;
682 if (family
->name_id_16_len
&& *family
->name_id_16_len
683 && family
->name_id_16_str
&& *family
->name_id_16_str
)
684 family
->family_name
= sdsnewlen(*family
->name_id_16_str
,
685 *family
->name_id_16_len
);
686 else if (family
->name_id_1_len
&& *family
->name_id_1_len
687 && family
->name_id_1_str
&& *family
->name_id_1_str
)
688 family
->family_name
= sdsnewlen(*family
->name_id_1_str
,
689 *family
->name_id_1_len
);
692 sds family_name
= sdsempty();
693 sds family_ps_name
= sdsempty();
695 // process all name ID strings in triplets
696 for (Node
* node
= LLRB_MIN(family_data
, family_data_head
);
698 node
= LLRB_NEXT(family_data
, family_data_head
, node
))
700 Family family
= node
->family
;
703 sdsclear(family_name
);
704 sdsclear(family_ps_name
);
706 if (family
.family_name
)
707 family_name
= sdscatsds(family_name
, family
.family_name
);
712 // use family name from a triplet that actually has one
713 for (n
= LLRB_MIN(family_data
, family_data_head
);
715 n
= LLRB_NEXT(family_data
, family_data_head
, n
))
717 Family f
= n
->family
;
719 if (f
.platform_id
== family
.platform_id
720 && f
.encoding_id
== family
.encoding_id
723 family_name
= sdscatsds(family_name
, f
.family_name
);
729 continue; // no valid family name found
732 if (family
.platform_id
== 1
733 || (family
.platform_id
== 3 && !(family
.encoding_id
== 1
734 || family
.encoding_id
== 10)))
735 is_wide
= false; // one-byte or multi-byte encodings
737 is_wide
= true; // (two-byte) UTF-16BE
739 sds suffix
= is_wide
? family_suffix_wide
: family_suffix
;
740 insert_suffix(suffix
,
742 family
.name_id_1_len
,
743 family
.name_id_1_str
);
744 insert_suffix(suffix
,
746 family
.name_id_4_len
,
747 family
.name_id_4_str
);
748 insert_suffix(suffix
,
750 family
.name_id_16_len
,
751 family
.name_id_16_str
);
752 insert_suffix(suffix
,
754 family
.name_id_21_len
,
755 family
.name_id_21_str
);
757 size_t family_name_len
= sdslen(family_name
);
759 family_name_len
&= ~1; // ensure even value for the loop below
761 // set sds to estimated size;
762 // we later set the size to the actual value
763 family_ps_name
= sdsMakeRoomFor(family_ps_name
,
766 // construct `family_ps_name' by removing all space characters
767 char *fn
= family_name
;
768 char *fpn
= family_ps_name
;
771 for (size_t i
= 0; i
< family_name_len
; i
+= 2)
775 if (!(c1
== '\0' && c2
== ' '))
784 for (size_t i
= 0; i
< family_name_len
; i
++)
792 sdsIncrLen(family_ps_name
, fpn
- family_ps_name
);
794 sds ps_suffix
= is_wide
? family_ps_suffix_wide
: family_ps_suffix
;
795 insert_suffix(ps_suffix
,
797 family
.name_id_6_len
,
798 family
.name_id_6_str
);
801 sdsfree(family_suffix
);
802 sdsfree(family_suffix_wide
);
803 sdsfree(family_ps_suffix
);
804 sdsfree(family_ps_suffix_wide
);
805 sdsfree(family_name
);
806 sdsfree(family_ps_name
);
808 family_data_free(idata
);