Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/harfbuzz/src/hb-common.cc
21318 views
1
/*
2
* Copyright © 2009,2010 Red Hat, Inc.
3
* Copyright © 2011,2012 Google, Inc.
4
*
5
* This is part of HarfBuzz, a text shaping library.
6
*
7
* Permission is hereby granted, without written agreement and without
8
* license or royalty fees, to use, copy, modify, and distribute this
9
* software and its documentation for any purpose, provided that the
10
* above copyright notice and the following two paragraphs appear in
11
* all copies of this software.
12
*
13
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
* DAMAGE.
18
*
19
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
*
25
* Red Hat Author(s): Behdad Esfahbod
26
* Google Author(s): Behdad Esfahbod
27
*/
28
29
#include "hb.hh"
30
#include "hb-machinery.hh"
31
32
33
/**
34
* SECTION:hb-common
35
* @title: hb-common
36
* @short_description: Common data types
37
* @include: hb.h
38
*
39
* Common data types used across HarfBuzz are defined here.
40
**/
41
42
43
/* hb_tag_t */
44
45
/**
46
* hb_tag_from_string:
47
* @str: (array length=len) (element-type uint8_t): String to convert
48
* @len: Length of @str, or -1 if it is `NULL`-terminated
49
*
50
* Converts a string into an #hb_tag_t. Valid tags
51
* are four characters. Shorter input strings will be
52
* padded with spaces. Longer input strings will be
53
* truncated.
54
*
55
* Return value: The #hb_tag_t corresponding to @str
56
*
57
* Since: 0.9.2
58
**/
59
hb_tag_t
60
hb_tag_from_string (const char *str, int len)
61
{
62
char tag[4];
63
unsigned int i;
64
65
if (!str || !len || !*str)
66
return HB_TAG_NONE;
67
68
if (len < 0 || len > 4)
69
len = 4;
70
for (i = 0; i < (unsigned) len && str[i]; i++)
71
tag[i] = str[i];
72
for (; i < 4; i++)
73
tag[i] = ' ';
74
75
return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
76
}
77
78
/**
79
* hb_tag_to_string:
80
* @tag: #hb_tag_t to convert
81
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
82
*
83
* Converts an #hb_tag_t to a string and returns it in @buf.
84
* Strings will be four characters long.
85
*
86
* Since: 0.9.5
87
**/
88
void
89
hb_tag_to_string (hb_tag_t tag, char *buf)
90
{
91
buf[0] = (char) (uint8_t) (tag >> 24);
92
buf[1] = (char) (uint8_t) (tag >> 16);
93
buf[2] = (char) (uint8_t) (tag >> 8);
94
buf[3] = (char) (uint8_t) (tag >> 0);
95
}
96
97
98
/* hb_direction_t */
99
100
static const char direction_strings[][4] = {
101
"ltr",
102
"rtl",
103
"ttb",
104
"btt"
105
};
106
107
/**
108
* hb_direction_from_string:
109
* @str: (array length=len) (element-type uint8_t): String to convert
110
* @len: Length of @str, or -1 if it is `NULL`-terminated
111
*
112
* Converts a string to an #hb_direction_t.
113
*
114
* Matching is loose and applies only to the first letter. For
115
* examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
116
*
117
* Unmatched strings will return #HB_DIRECTION_INVALID.
118
*
119
* Return value: The #hb_direction_t matching @str
120
*
121
* Since: 0.9.2
122
**/
123
hb_direction_t
124
hb_direction_from_string (const char *str, int len)
125
{
126
if (unlikely (!str || !len || !*str))
127
return HB_DIRECTION_INVALID;
128
129
/* Lets match loosely: just match the first letter, such that
130
* all of "ltr", "left-to-right", etc work!
131
*/
132
char c = TOLOWER (str[0]);
133
for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
134
if (c == direction_strings[i][0])
135
return (hb_direction_t) (HB_DIRECTION_LTR + i);
136
137
return HB_DIRECTION_INVALID;
138
}
139
140
/**
141
* hb_direction_to_string:
142
* @direction: The #hb_direction_t to convert
143
*
144
* Converts an #hb_direction_t to a string.
145
*
146
* Return value: (transfer none): The string corresponding to @direction
147
*
148
* Since: 0.9.2
149
**/
150
const char *
151
hb_direction_to_string (hb_direction_t direction)
152
{
153
if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
154
< ARRAY_LENGTH (direction_strings)))
155
return direction_strings[direction - HB_DIRECTION_LTR];
156
157
return "invalid";
158
}
159
160
161
/* hb_language_t */
162
163
struct hb_language_impl_t {
164
const char s[1];
165
};
166
167
static const char canon_map[256] = {
168
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
171
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
172
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
173
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
174
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
175
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
176
};
177
178
static bool
179
lang_equal (hb_language_t v1,
180
const void *v2)
181
{
182
const unsigned char *p1 = (const unsigned char *) v1;
183
const unsigned char *p2 = (const unsigned char *) v2;
184
185
while (*p1 && *p1 == canon_map[*p2]) {
186
p1++;
187
p2++;
188
}
189
190
return *p1 == canon_map[*p2];
191
}
192
193
#if 0
194
static unsigned int
195
lang_hash (const void *key)
196
{
197
const unsigned char *p = key;
198
unsigned int h = 0;
199
while (canon_map[*p])
200
{
201
h = (h << 5) - h + canon_map[*p];
202
p++;
203
}
204
205
return h;
206
}
207
#endif
208
209
210
struct hb_language_item_t {
211
212
struct hb_language_item_t *next;
213
hb_language_t lang;
214
215
bool operator == (const char *s) const
216
{ return lang_equal (lang, s); }
217
218
hb_language_item_t & operator = (const char *s)
219
{
220
/* We can't call strdup(), because we allow custom allocators. */
221
size_t len = strlen(s) + 1;
222
lang = (hb_language_t) hb_malloc(len);
223
if (likely (lang))
224
{
225
hb_memcpy((unsigned char *) lang, s, len);
226
for (unsigned char *p = (unsigned char *) lang; *p; p++)
227
*p = canon_map[*p];
228
}
229
230
return *this;
231
}
232
233
void fini () { hb_free ((void *) lang); }
234
};
235
236
237
/* Thread-safe lockfree language list */
238
239
static hb_atomic_t<hb_language_item_t *> langs;
240
241
static inline void
242
free_langs ()
243
{
244
retry:
245
hb_language_item_t *first_lang = langs;
246
if (unlikely (!langs.cmpexch (first_lang, nullptr)))
247
goto retry;
248
249
while (first_lang) {
250
hb_language_item_t *next = first_lang->next;
251
first_lang->fini ();
252
hb_free (first_lang);
253
first_lang = next;
254
}
255
}
256
257
static hb_language_item_t *
258
lang_find_or_insert (const char *key)
259
{
260
retry:
261
hb_language_item_t *first_lang = langs;
262
263
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
264
if (*lang == key)
265
return lang;
266
267
/* Not found; allocate one. */
268
hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
269
if (unlikely (!lang))
270
return nullptr;
271
lang->next = first_lang;
272
*lang = key;
273
if (unlikely (!lang->lang))
274
{
275
hb_free (lang);
276
return nullptr;
277
}
278
279
if (unlikely (!langs.cmpexch (first_lang, lang)))
280
{
281
lang->fini ();
282
hb_free (lang);
283
goto retry;
284
}
285
286
if (!first_lang)
287
hb_atexit (free_langs); /* First person registers atexit() callback. */
288
289
return lang;
290
}
291
292
293
/**
294
* hb_language_from_string:
295
* @str: (array length=len) (element-type uint8_t): a string representing
296
* a BCP 47 language tag
297
* @len: length of the @str, or -1 if it is `NULL`-terminated.
298
*
299
* Converts @str representing a BCP 47 language tag to the corresponding
300
* #hb_language_t.
301
*
302
* Return value: (transfer none):
303
* The #hb_language_t corresponding to the BCP 47 language tag.
304
*
305
* Since: 0.9.2
306
**/
307
hb_language_t
308
hb_language_from_string (const char *str, int len)
309
{
310
if (!str || !len || !*str)
311
return HB_LANGUAGE_INVALID;
312
313
hb_language_item_t *item = nullptr;
314
if (len >= 0)
315
{
316
/* NUL-terminate it. */
317
char strbuf[64];
318
len = hb_min (len, (int) sizeof (strbuf) - 1);
319
hb_memcpy (strbuf, str, len);
320
strbuf[len] = '\0';
321
item = lang_find_or_insert (strbuf);
322
}
323
else
324
item = lang_find_or_insert (str);
325
326
return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
327
}
328
329
/**
330
* hb_language_to_string:
331
* @language: The #hb_language_t to convert
332
*
333
* Converts an #hb_language_t to a string.
334
*
335
* Return value: (transfer none):
336
* A `NULL`-terminated string representing the @language. Must not be freed by
337
* the caller.
338
*
339
* Since: 0.9.2
340
**/
341
const char *
342
hb_language_to_string (hb_language_t language)
343
{
344
if (unlikely (!language)) return nullptr;
345
346
return language->s;
347
}
348
349
/**
350
* hb_language_get_default:
351
*
352
* Fetch the default language from current locale.
353
*
354
* <note>Note that the first time this function is called, it calls
355
* "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
356
* setlocale function is, in many implementations, NOT threadsafe. To avoid
357
* problems, call this function once before multiple threads can call it.
358
* This function is only used from hb_buffer_guess_segment_properties() by
359
* HarfBuzz itself.</note>
360
*
361
* Return value: (transfer none): The default language of the locale as
362
* an #hb_language_t
363
*
364
* Since: 0.9.2
365
**/
366
hb_language_t
367
hb_language_get_default ()
368
{
369
static hb_atomic_t<hb_language_t> default_language;
370
371
hb_language_t language = default_language;
372
if (unlikely (language == HB_LANGUAGE_INVALID))
373
{
374
language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
375
(void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
376
}
377
378
return language;
379
}
380
381
/**
382
* hb_language_matches:
383
* @language: The #hb_language_t to work on
384
* @specific: Another #hb_language_t
385
*
386
* Check whether a second language tag is the same or a more
387
* specific version of the provided language tag. For example,
388
* "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".
389
*
390
* Return value: `true` if languages match, `false` otherwise.
391
*
392
* Since: 5.0.0
393
**/
394
hb_bool_t
395
hb_language_matches (hb_language_t language,
396
hb_language_t specific)
397
{
398
if (language == specific) return true;
399
if (!language || !specific) return false;
400
401
const char *l = language->s;
402
const char *s = specific->s;
403
unsigned ll = strlen (l);
404
unsigned sl = strlen (s);
405
406
if (ll > sl)
407
return false;
408
409
return strncmp (l, s, ll) == 0 &&
410
(s[ll] == '\0' || s[ll] == '-');
411
}
412
413
414
/* hb_script_t */
415
416
/**
417
* hb_script_from_iso15924_tag:
418
* @tag: an #hb_tag_t representing an ISO 15924 tag.
419
*
420
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
421
*
422
* Return value:
423
* An #hb_script_t corresponding to the ISO 15924 tag.
424
*
425
* Since: 0.9.2
426
**/
427
hb_script_t
428
hb_script_from_iso15924_tag (hb_tag_t tag)
429
{
430
if (unlikely (tag == HB_TAG_NONE))
431
return HB_SCRIPT_INVALID;
432
433
/* Be lenient, adjust case (one capital letter followed by three small letters) */
434
tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
435
436
switch (tag) {
437
438
/* These graduated from the 'Q' private-area codes, but
439
* the old code is still aliased by Unicode, and the Qaai
440
* one in use by ICU. */
441
case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
442
case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
443
444
/* Script variants from https://unicode.org/iso15924/ */
445
case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
446
case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
447
case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
448
case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
449
case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
450
case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
451
case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
452
case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
453
case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
454
case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
455
case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
456
}
457
458
/* If it looks right, just use the tag as a script */
459
if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
460
return (hb_script_t) tag;
461
462
/* Otherwise, return unknown */
463
return HB_SCRIPT_UNKNOWN;
464
}
465
466
/**
467
* hb_script_from_string:
468
* @str: (array length=len) (element-type uint8_t): a string representing an
469
* ISO 15924 tag.
470
* @len: length of the @str, or -1 if it is `NULL`-terminated.
471
*
472
* Converts a string @str representing an ISO 15924 script tag to a
473
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
474
* hb_script_from_iso15924_tag().
475
*
476
* Return value:
477
* An #hb_script_t corresponding to the ISO 15924 tag.
478
*
479
* Since: 0.9.2
480
**/
481
hb_script_t
482
hb_script_from_string (const char *str, int len)
483
{
484
return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
485
}
486
487
/**
488
* hb_script_to_iso15924_tag:
489
* @script: an #hb_script_t to convert.
490
*
491
* Converts an #hb_script_t to a corresponding ISO 15924 script tag.
492
*
493
* Return value:
494
* An #hb_tag_t representing an ISO 15924 script tag.
495
*
496
* Since: 0.9.2
497
**/
498
hb_tag_t
499
hb_script_to_iso15924_tag (hb_script_t script)
500
{
501
return (hb_tag_t) script;
502
}
503
504
/**
505
* hb_script_get_horizontal_direction:
506
* @script: The #hb_script_t to query
507
*
508
* Fetches the #hb_direction_t of a script when it is
509
* set horizontally. All right-to-left scripts will return
510
* #HB_DIRECTION_RTL. All left-to-right scripts will return
511
* #HB_DIRECTION_LTR.
512
*
513
* Scripts that can be written either right-to-left or
514
* left-to-right will return #HB_DIRECTION_INVALID.
515
*
516
* Unknown scripts will return #HB_DIRECTION_LTR.
517
*
518
* Return value: The horizontal #hb_direction_t of @script
519
*
520
* Since: 0.9.2
521
**/
522
hb_direction_t
523
hb_script_get_horizontal_direction (hb_script_t script)
524
{
525
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
526
switch ((hb_tag_t) script)
527
{
528
/* Unicode-1.1 additions */
529
case HB_SCRIPT_ARABIC:
530
case HB_SCRIPT_HEBREW:
531
532
/* Unicode-3.0 additions */
533
case HB_SCRIPT_SYRIAC:
534
case HB_SCRIPT_THAANA:
535
536
/* Unicode-4.0 additions */
537
case HB_SCRIPT_CYPRIOT:
538
539
/* Unicode-4.1 additions */
540
case HB_SCRIPT_KHAROSHTHI:
541
542
/* Unicode-5.0 additions */
543
case HB_SCRIPT_PHOENICIAN:
544
case HB_SCRIPT_NKO:
545
546
/* Unicode-5.1 additions */
547
case HB_SCRIPT_LYDIAN:
548
549
/* Unicode-5.2 additions */
550
case HB_SCRIPT_AVESTAN:
551
case HB_SCRIPT_IMPERIAL_ARAMAIC:
552
case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
553
case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
554
case HB_SCRIPT_OLD_SOUTH_ARABIAN:
555
case HB_SCRIPT_OLD_TURKIC:
556
case HB_SCRIPT_SAMARITAN:
557
558
/* Unicode-6.0 additions */
559
case HB_SCRIPT_MANDAIC:
560
561
/* Unicode-6.1 additions */
562
case HB_SCRIPT_MEROITIC_CURSIVE:
563
case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
564
565
/* Unicode-7.0 additions */
566
case HB_SCRIPT_MANICHAEAN:
567
case HB_SCRIPT_MENDE_KIKAKUI:
568
case HB_SCRIPT_NABATAEAN:
569
case HB_SCRIPT_OLD_NORTH_ARABIAN:
570
case HB_SCRIPT_PALMYRENE:
571
case HB_SCRIPT_PSALTER_PAHLAVI:
572
573
/* Unicode-8.0 additions */
574
case HB_SCRIPT_HATRAN:
575
576
/* Unicode-9.0 additions */
577
case HB_SCRIPT_ADLAM:
578
579
/* Unicode-11.0 additions */
580
case HB_SCRIPT_HANIFI_ROHINGYA:
581
case HB_SCRIPT_OLD_SOGDIAN:
582
case HB_SCRIPT_SOGDIAN:
583
584
/* Unicode-12.0 additions */
585
case HB_SCRIPT_ELYMAIC:
586
587
/* Unicode-13.0 additions */
588
case HB_SCRIPT_CHORASMIAN:
589
case HB_SCRIPT_YEZIDI:
590
591
/* Unicode-14.0 additions */
592
case HB_SCRIPT_OLD_UYGHUR:
593
594
/* Unicode-16.0 additions */
595
case HB_SCRIPT_GARAY:
596
597
/* Unicode-17.0 additions */
598
case HB_SCRIPT_SIDETIC:
599
600
return HB_DIRECTION_RTL;
601
602
603
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
604
case HB_SCRIPT_OLD_HUNGARIAN:
605
case HB_SCRIPT_OLD_ITALIC:
606
case HB_SCRIPT_RUNIC:
607
case HB_SCRIPT_TIFINAGH:
608
609
return HB_DIRECTION_INVALID;
610
}
611
612
return HB_DIRECTION_LTR;
613
}
614
615
616
/* hb_version */
617
618
619
/**
620
* SECTION:hb-version
621
* @title: hb-version
622
* @short_description: Information about the version of HarfBuzz in use
623
* @include: hb.h
624
*
625
* These functions and macros allow accessing version of the HarfBuzz
626
* library used at compile- as well as run-time, and to direct code
627
* conditionally based on those versions, again, at compile- or run-time.
628
**/
629
630
631
/**
632
* hb_version:
633
* @major: (out): Library major version component
634
* @minor: (out): Library minor version component
635
* @micro: (out): Library micro version component
636
*
637
* Returns library version as three integer components.
638
*
639
* Since: 0.9.2
640
**/
641
void
642
hb_version (unsigned int *major,
643
unsigned int *minor,
644
unsigned int *micro)
645
{
646
*major = HB_VERSION_MAJOR;
647
*minor = HB_VERSION_MINOR;
648
*micro = HB_VERSION_MICRO;
649
}
650
651
/**
652
* hb_version_string:
653
*
654
* Returns library version as a string with three components.
655
*
656
* Return value: Library version string
657
*
658
* Since: 0.9.2
659
**/
660
const char *
661
hb_version_string ()
662
{
663
return HB_VERSION_STRING;
664
}
665
666
/**
667
* hb_version_atleast:
668
* @major: Library major version component
669
* @minor: Library minor version component
670
* @micro: Library micro version component
671
*
672
* Tests the library version against a minimum value,
673
* as three integer components.
674
*
675
* Return value: `true` if the library is equal to or greater than
676
* the test value, `false` otherwise
677
*
678
* Since: 0.9.30
679
**/
680
hb_bool_t
681
hb_version_atleast (unsigned int major,
682
unsigned int minor,
683
unsigned int micro)
684
{
685
return HB_VERSION_ATLEAST (major, minor, micro);
686
}
687
688
689
690
/* hb_feature_t and hb_variation_t */
691
692
static bool
693
parse_space (const char **pp, const char *end)
694
{
695
while (*pp < end && ISSPACE (**pp))
696
(*pp)++;
697
return true;
698
}
699
700
static bool
701
parse_char (const char **pp, const char *end, char c)
702
{
703
parse_space (pp, end);
704
705
if (*pp == end || **pp != c)
706
return false;
707
708
(*pp)++;
709
return true;
710
}
711
712
static bool
713
parse_uint (const char **pp, const char *end, unsigned int *pv)
714
{
715
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
716
* such that -1 turns into "big number"... */
717
int v;
718
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
719
720
*pv = v;
721
return true;
722
}
723
724
static bool
725
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
726
{
727
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
728
* such that -1 turns into "big number"... */
729
int v;
730
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
731
732
*pv = v;
733
return true;
734
}
735
736
static bool
737
parse_bool (const char **pp, const char *end, uint32_t *pv)
738
{
739
parse_space (pp, end);
740
741
const char *p = *pp;
742
while (*pp < end && ISALPHA(**pp))
743
(*pp)++;
744
745
/* CSS allows on/off as aliases 1/0. */
746
if (*pp - p == 2
747
&& TOLOWER (p[0]) == 'o'
748
&& TOLOWER (p[1]) == 'n')
749
*pv = 1;
750
else if (*pp - p == 3
751
&& TOLOWER (p[0]) == 'o'
752
&& TOLOWER (p[1]) == 'f'
753
&& TOLOWER (p[2]) == 'f')
754
*pv = 0;
755
else
756
return false;
757
758
return true;
759
}
760
761
/* hb_feature_t */
762
763
static bool
764
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
765
{
766
if (parse_char (pp, end, '-'))
767
feature->value = 0;
768
else {
769
parse_char (pp, end, '+');
770
feature->value = 1;
771
}
772
773
return true;
774
}
775
776
static bool
777
parse_tag (const char **pp, const char *end, hb_tag_t *tag)
778
{
779
parse_space (pp, end);
780
781
char quote = 0;
782
783
if (*pp < end && (**pp == '\'' || **pp == '"'))
784
{
785
quote = **pp;
786
(*pp)++;
787
}
788
789
const char *p = *pp;
790
while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote))
791
(*pp)++;
792
793
if (p == *pp || *pp - p > 4)
794
return false;
795
796
*tag = hb_tag_from_string (p, *pp - p);
797
798
if (quote)
799
{
800
/* CSS expects exactly four bytes. And we only allow quotations for
801
* CSS compatibility. So, enforce the length. */
802
if (*pp - p != 4)
803
return false;
804
if (*pp == end || **pp != quote)
805
return false;
806
(*pp)++;
807
}
808
809
return true;
810
}
811
812
static bool
813
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
814
{
815
parse_space (pp, end);
816
817
bool has_start;
818
819
feature->start = HB_FEATURE_GLOBAL_START;
820
feature->end = HB_FEATURE_GLOBAL_END;
821
822
if (!parse_char (pp, end, '['))
823
return true;
824
825
has_start = parse_uint (pp, end, &feature->start);
826
827
if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
828
parse_uint (pp, end, &feature->end);
829
} else {
830
if (has_start)
831
feature->end = feature->start + 1;
832
}
833
834
return parse_char (pp, end, ']');
835
}
836
837
static bool
838
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
839
{
840
bool had_equal = parse_char (pp, end, '=');
841
bool had_value = parse_uint32 (pp, end, &feature->value) ||
842
parse_bool (pp, end, &feature->value);
843
/* CSS doesn't use equal-sign between tag and value.
844
* If there was an equal-sign, then there *must* be a value.
845
* A value without an equal-sign is ok, but not required. */
846
return !had_equal || had_value;
847
}
848
849
static bool
850
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
851
{
852
return parse_feature_value_prefix (pp, end, feature) &&
853
parse_tag (pp, end, &feature->tag) &&
854
parse_feature_indices (pp, end, feature) &&
855
parse_feature_value_postfix (pp, end, feature) &&
856
parse_space (pp, end) &&
857
*pp == end;
858
}
859
860
/**
861
* hb_feature_from_string:
862
* @str: (array length=len) (element-type uint8_t): a string to parse
863
* @len: length of @str, or -1 if string is `NULL` terminated
864
* @feature: (out): the #hb_feature_t to initialize with the parsed values
865
*
866
* Parses a string into a #hb_feature_t.
867
*
868
* The format for specifying feature strings follows. All valid CSS
869
* font-feature-settings values other than 'normal' and the global values are
870
* also accepted, though not documented below. CSS string escapes are not
871
* supported.
872
*
873
* The range indices refer to the positions between Unicode characters. The
874
* position before the first character is always 0.
875
*
876
* The format is Python-esque. Here is how it all works:
877
*
878
* <informaltable pgwide='1' align='left' frame='none'>
879
* <tgroup cols='5'>
880
* <thead>
881
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
882
* </thead>
883
* <tbody>
884
* <row><entry>Setting value:</entry></row>
885
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
886
* <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
887
* <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
888
* <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
889
* <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
890
* <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry>∞</entry> <entry>Choose 2nd alternate</entry></row>
891
* <row><entry>Setting index:</entry></row>
892
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
893
* <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
894
* <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry>∞</entry> <entry>Turn feature on, partial</entry></row>
895
* <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
896
* <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
897
* <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
898
* <row><entry>Mixing it all:</entry></row>
899
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
900
* </tbody>
901
* </tgroup>
902
* </informaltable>
903
*
904
* Return value:
905
* `true` if @str is successfully parsed, `false` otherwise
906
*
907
* Since: 0.9.5
908
**/
909
hb_bool_t
910
hb_feature_from_string (const char *str, int len,
911
hb_feature_t *feature)
912
{
913
hb_feature_t feat;
914
915
if (len < 0)
916
len = strlen (str);
917
918
if (likely (parse_one_feature (&str, str + len, &feat)))
919
{
920
if (feature)
921
*feature = feat;
922
return true;
923
}
924
925
if (feature)
926
hb_memset (feature, 0, sizeof (*feature));
927
return false;
928
}
929
930
/**
931
* hb_feature_to_string:
932
* @feature: an #hb_feature_t to convert
933
* @buf: (array length=size) (out): output string
934
* @size: the allocated size of @buf
935
*
936
* Converts a #hb_feature_t into a `NULL`-terminated string in the format
937
* understood by hb_feature_from_string(). The client in responsible for
938
* allocating big enough size for @buf, 128 bytes is more than enough.
939
*
940
* Note that the feature value will be omitted if it is '1', but the
941
* string won't include any whitespace.
942
*
943
* Since: 0.9.5
944
**/
945
void
946
hb_feature_to_string (hb_feature_t *feature,
947
char *buf, unsigned int size)
948
{
949
if (unlikely (!size)) return;
950
951
char s[128];
952
unsigned int len = 0;
953
if (feature->value == 0)
954
s[len++] = '-';
955
hb_tag_to_string (feature->tag, s + len);
956
len += 4;
957
while (len && s[len - 1] == ' ')
958
len--;
959
if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
960
{
961
s[len++] = '[';
962
if (feature->start)
963
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
964
if (feature->end != feature->start + 1) {
965
s[len++] = ':';
966
if (feature->end != HB_FEATURE_GLOBAL_END)
967
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
968
}
969
s[len++] = ']';
970
}
971
if (feature->value > 1)
972
{
973
s[len++] = '=';
974
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
975
}
976
assert (len < ARRAY_LENGTH (s));
977
len = hb_min (len, size - 1);
978
hb_memcpy (buf, s, len);
979
buf[len] = '\0';
980
}
981
982
/* hb_variation_t */
983
984
static bool
985
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
986
{
987
parse_char (pp, end, '='); /* Optional. */
988
double v;
989
if (unlikely (!hb_parse_double (pp, end, &v))) return false;
990
991
variation->value = v;
992
return true;
993
}
994
995
static bool
996
parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
997
{
998
return parse_tag (pp, end, &variation->tag) &&
999
parse_variation_value (pp, end, variation) &&
1000
parse_space (pp, end) &&
1001
*pp == end;
1002
}
1003
1004
/**
1005
* hb_variation_from_string:
1006
* @str: (array length=len) (element-type uint8_t): a string to parse
1007
* @len: length of @str, or -1 if string is `NULL` terminated
1008
* @variation: (out): the #hb_variation_t to initialize with the parsed values
1009
*
1010
* Parses a string into a #hb_variation_t.
1011
*
1012
* The format for specifying variation settings follows. All valid CSS
1013
* font-variation-settings values other than 'normal' and 'inherited' are also
1014
* accepted, though, not documented below.
1015
*
1016
* The format is a tag, optionally followed by an equals sign, followed by a
1017
* number. For example `wght=500`, or `slnt=-7.5`.
1018
*
1019
* Return value:
1020
* `true` if @str is successfully parsed, `false` otherwise
1021
*
1022
* Since: 1.4.2
1023
*/
1024
hb_bool_t
1025
hb_variation_from_string (const char *str, int len,
1026
hb_variation_t *variation)
1027
{
1028
hb_variation_t var;
1029
1030
if (len < 0)
1031
len = strlen (str);
1032
1033
if (likely (parse_one_variation (&str, str + len, &var)))
1034
{
1035
if (variation)
1036
*variation = var;
1037
return true;
1038
}
1039
1040
if (variation)
1041
hb_memset (variation, 0, sizeof (*variation));
1042
return false;
1043
}
1044
1045
#ifndef HB_NO_SETLOCALE
1046
1047
static inline void free_static_C_locale ();
1048
1049
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
1050
hb_C_locale_lazy_loader_t>
1051
{
1052
static hb_locale_t create ()
1053
{
1054
hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
1055
if (!l)
1056
return l;
1057
1058
hb_atexit (free_static_C_locale);
1059
1060
return l;
1061
}
1062
static void destroy (hb_locale_t l)
1063
{
1064
freelocale (l);
1065
}
1066
static hb_locale_t get_null ()
1067
{
1068
return (hb_locale_t) 0;
1069
}
1070
} static_C_locale;
1071
1072
static inline
1073
void free_static_C_locale ()
1074
{
1075
static_C_locale.free_instance ();
1076
}
1077
1078
static hb_locale_t
1079
get_C_locale ()
1080
{
1081
return static_C_locale.get_unconst ();
1082
}
1083
1084
#endif
1085
1086
/**
1087
* hb_variation_to_string:
1088
* @variation: an #hb_variation_t to convert
1089
* @buf: (array length=size) (out caller-allocates): output string
1090
* @size: the allocated size of @buf
1091
*
1092
* Converts an #hb_variation_t into a `NULL`-terminated string in the format
1093
* understood by hb_variation_from_string(). The client in responsible for
1094
* allocating big enough size for @buf, 128 bytes is more than enough.
1095
*
1096
* Note that the string won't include any whitespace.
1097
*
1098
* Since: 1.4.2
1099
*/
1100
void
1101
hb_variation_to_string (hb_variation_t *variation,
1102
char *buf, unsigned int size)
1103
{
1104
if (unlikely (!size)) return;
1105
1106
char s[128];
1107
unsigned int len = 0;
1108
hb_tag_to_string (variation->tag, s + len);
1109
len += 4;
1110
while (len && s[len - 1] == ' ')
1111
len--;
1112
s[len++] = '=';
1113
1114
hb_locale_t oldlocale HB_UNUSED;
1115
oldlocale = hb_uselocale (get_C_locale ());
1116
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
1117
(void) hb_uselocale (oldlocale);
1118
1119
assert (len < ARRAY_LENGTH (s));
1120
len = hb_min (len, size - 1);
1121
hb_memcpy (buf, s, len);
1122
buf[len] = '\0';
1123
}
1124
1125
/**
1126
* hb_color_get_alpha:
1127
* @color: an #hb_color_t we are interested in its channels.
1128
*
1129
* Fetches the alpha channel of the given @color.
1130
*
1131
* Return value: Alpha channel value
1132
*
1133
* Since: 2.1.0
1134
*/
1135
uint8_t
1136
(hb_color_get_alpha) (hb_color_t color)
1137
{
1138
return hb_color_get_alpha (color);
1139
}
1140
1141
/**
1142
* hb_color_get_red:
1143
* @color: an #hb_color_t we are interested in its channels.
1144
*
1145
* Fetches the red channel of the given @color.
1146
*
1147
* Return value: Red channel value
1148
*
1149
* Since: 2.1.0
1150
*/
1151
uint8_t
1152
(hb_color_get_red) (hb_color_t color)
1153
{
1154
return hb_color_get_red (color);
1155
}
1156
1157
/**
1158
* hb_color_get_green:
1159
* @color: an #hb_color_t we are interested in its channels.
1160
*
1161
* Fetches the green channel of the given @color.
1162
*
1163
* Return value: Green channel value
1164
*
1165
* Since: 2.1.0
1166
*/
1167
uint8_t
1168
(hb_color_get_green) (hb_color_t color)
1169
{
1170
return hb_color_get_green (color);
1171
}
1172
1173
/**
1174
* hb_color_get_blue:
1175
* @color: an #hb_color_t we are interested in its channels.
1176
*
1177
* Fetches the blue channel of the given @color.
1178
*
1179
* Return value: Blue channel value
1180
*
1181
* Since: 2.1.0
1182
*/
1183
uint8_t
1184
(hb_color_get_blue) (hb_color_t color)
1185
{
1186
return hb_color_get_blue (color);
1187
}
1188
1189
/**
1190
* hb_malloc:
1191
* @size: The size of the memory to allocate.
1192
*
1193
* Allocates @size bytes of memory, using the allocator set at
1194
* compile-time. Typically just malloc().
1195
*
1196
* Return value: A pointer to the allocated memory.
1197
*
1198
* Since: 11.0.0
1199
**/
1200
void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
1201
1202
/**
1203
* hb_calloc:
1204
* @nmemb: The number of elements to allocate.
1205
* @size: The size of each element.
1206
*
1207
* Allocates @nmemb elements of @size bytes each, initialized to zero,
1208
* using the allocator set at compile-time. Typically just calloc().
1209
*
1210
* Return value: A pointer to the allocated memory.
1211
*
1212
* Since: 11.0.0
1213
**/
1214
void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
1215
1216
/**
1217
* hb_realloc:
1218
* @ptr: The pointer to the memory to reallocate.
1219
* @size: The new size of the memory.
1220
*
1221
* Reallocates the memory pointed to by @ptr to @size bytes, using the
1222
* allocator set at compile-time. Typically just realloc().
1223
*
1224
* Return value: A pointer to the reallocated memory.
1225
*
1226
* Since: 11.0.0
1227
**/
1228
void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
1229
1230
/**
1231
* hb_free:
1232
* @ptr: The pointer to the memory to free.
1233
*
1234
* Frees the memory pointed to by @ptr, using the allocator set at
1235
* compile-time. Typically just free().
1236
*
1237
* Since: 11.0.0
1238
**/
1239
void hb_free(void *ptr) { hb_free_impl (ptr); }
1240
1241
1242
/* If there is no visibility control, then hb-static.cc will NOT
1243
* define anything. Instead, we get it to define one set in here
1244
* only, so only libharfbuzz.so defines them, not other libs. */
1245
#ifdef HB_NO_VISIBILITY
1246
#undef HB_NO_VISIBILITY
1247
#include "hb-static.cc"
1248
#define HB_NO_VISIBILITY 1
1249
#endif
1250
1251