1 /*
2 * fontconfig/src/fcname.c
3 *
4 * Copyright © 2000 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include "fcint.h"
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 static const FcObjectType FcObjects[] = {
32 #define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type },
33 #include "fcobjs.h"
34 #undef FC_OBJECT
35 };
36
37 #define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0]))
38
39 static const FcObjectType *
FcObjectFindById(FcObject object)40 FcObjectFindById (FcObject object)
41 {
42 if (1 <= object && object <= NUM_OBJECT_TYPES)
43 return &FcObjects[object - 1];
44 return FcObjectLookupOtherTypeById (object);
45 }
46
47 FcBool
FcNameRegisterObjectTypes(const FcObjectType * types,int ntypes)48 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
49 {
50 /* Deprecated. */
51 return FcFalse;
52 }
53
54 FcBool
FcNameUnregisterObjectTypes(const FcObjectType * types,int ntypes)55 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
56 {
57 /* Deprecated. */
58 return FcFalse;
59 }
60
61 const FcObjectType *
FcNameGetObjectType(const char * object)62 FcNameGetObjectType (const char *object)
63 {
64 int id = FcObjectLookupBuiltinIdByName (object);
65
66 if (!id)
67 return FcObjectLookupOtherTypeByName (object);
68
69 return &FcObjects[id - 1];
70 }
71
72 FcBool
FcObjectValidType(FcObject object,FcType type)73 FcObjectValidType (FcObject object, FcType type)
74 {
75 const FcObjectType *t = FcObjectFindById (object);
76
77 if (t) {
78 switch ((int) t->type) {
79 case FcTypeUnknown:
80 return FcTrue;
81 case FcTypeDouble:
82 case FcTypeInteger:
83 if (type == FcTypeDouble || type == FcTypeInteger)
84 return FcTrue;
85 break;
86 case FcTypeLangSet:
87 if (type == FcTypeLangSet || type == FcTypeString)
88 return FcTrue;
89 break;
90 default:
91 if (type == t->type)
92 return FcTrue;
93 break;
94 }
95 return FcFalse;
96 }
97 return FcTrue;
98 }
99
100 FcObject
FcObjectFromName(const char * name)101 FcObjectFromName (const char * name)
102 {
103 return FcObjectLookupIdByName (name);
104 }
105
106 FcObjectSet *
FcObjectGetSet(void)107 FcObjectGetSet (void)
108 {
109 int i;
110 FcObjectSet *os = NULL;
111
112
113 os = FcObjectSetCreate ();
114 for (i = 0; i < NUM_OBJECT_TYPES; i++)
115 FcObjectSetAdd (os, FcObjects[i].object);
116
117 return os;
118 }
119
120 const char *
FcObjectName(FcObject object)121 FcObjectName (FcObject object)
122 {
123 const FcObjectType *o = FcObjectFindById (object);
124
125 if (o)
126 return o->object;
127
128 return FcObjectLookupOtherNameById (object);
129 }
130
131 static const FcConstant _FcBaseConstants[] = {
132 { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, },
133 { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, },
134 { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, },
135 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, },
136 { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, },
137 { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, },
138 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, },
139 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
140 { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, },
141 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, },
142 { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, },
143 { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, },
144 { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, },
145 { (FcChar8 *) "heavy", "weight", FC_WEIGHT_HEAVY, },
146
147 { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, },
148 { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, },
149 { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, },
150
151 { (FcChar8 *) "ultracondensed", "width", FC_WIDTH_ULTRACONDENSED },
152 { (FcChar8 *) "extracondensed", "width", FC_WIDTH_EXTRACONDENSED },
153 { (FcChar8 *) "condensed", "width", FC_WIDTH_CONDENSED },
154 { (FcChar8 *) "semicondensed", "width", FC_WIDTH_SEMICONDENSED },
155 { (FcChar8 *) "normal", "width", FC_WIDTH_NORMAL },
156 { (FcChar8 *) "semiexpanded", "width", FC_WIDTH_SEMIEXPANDED },
157 { (FcChar8 *) "expanded", "width", FC_WIDTH_EXPANDED },
158 { (FcChar8 *) "extraexpanded", "width", FC_WIDTH_EXTRAEXPANDED },
159 { (FcChar8 *) "ultraexpanded", "width", FC_WIDTH_ULTRAEXPANDED },
160
161 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, },
162 { (FcChar8 *) "dual", "spacing", FC_DUAL, },
163 { (FcChar8 *) "mono", "spacing", FC_MONO, },
164 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, },
165
166 { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN },
167 { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, },
168 { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, },
169 { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB },
170 { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR },
171 { (FcChar8 *) "none", "rgba", FC_RGBA_NONE },
172
173 { (FcChar8 *) "hintnone", "hintstyle", FC_HINT_NONE },
174 { (FcChar8 *) "hintslight", "hintstyle", FC_HINT_SLIGHT },
175 { (FcChar8 *) "hintmedium", "hintstyle", FC_HINT_MEDIUM },
176 { (FcChar8 *) "hintfull", "hintstyle", FC_HINT_FULL },
177
178 { (FcChar8 *) "antialias", "antialias", FcTrue },
179 { (FcChar8 *) "hinting", "hinting", FcTrue },
180 { (FcChar8 *) "verticallayout", "verticallayout", FcTrue },
181 { (FcChar8 *) "autohint", "autohint", FcTrue },
182 { (FcChar8 *) "globaladvance", "globaladvance", FcTrue }, /* deprecated */
183 { (FcChar8 *) "outline", "outline", FcTrue },
184 { (FcChar8 *) "scalable", "scalable", FcTrue },
185 { (FcChar8 *) "minspace", "minspace", FcTrue },
186 { (FcChar8 *) "embolden", "embolden", FcTrue },
187 { (FcChar8 *) "embeddedbitmap", "embeddedbitmap", FcTrue },
188 { (FcChar8 *) "decorative", "decorative", FcTrue },
189 { (FcChar8 *) "lcdnone", "lcdfilter", FC_LCD_NONE },
190 { (FcChar8 *) "lcddefault", "lcdfilter", FC_LCD_DEFAULT },
191 { (FcChar8 *) "lcdlight", "lcdfilter", FC_LCD_LIGHT },
192 { (FcChar8 *) "lcdlegacy", "lcdfilter", FC_LCD_LEGACY },
193 };
194
195 #define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
196
197 FcBool
FcNameRegisterConstants(const FcConstant * consts,int nconsts)198 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
199 {
200 /* Deprecated. */
201 return FcFalse;
202 }
203
204 FcBool
FcNameUnregisterConstants(const FcConstant * consts,int nconsts)205 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
206 {
207 /* Deprecated. */
208 return FcFalse;
209 }
210
211 const FcConstant *
FcNameGetConstant(const FcChar8 * string)212 FcNameGetConstant (const FcChar8 *string)
213 {
214 unsigned int i;
215
216 for (i = 0; i < NUM_FC_CONSTANTS; i++)
217 if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
218 return &_FcBaseConstants[i];
219
220 return 0;
221 }
222
223 FcBool
FcNameConstant(const FcChar8 * string,int * result)224 FcNameConstant (const FcChar8 *string, int *result)
225 {
226 const FcConstant *c;
227
228 if ((c = FcNameGetConstant(string)))
229 {
230 *result = c->value;
231 return FcTrue;
232 }
233 return FcFalse;
234 }
235
236 FcBool
FcNameBool(const FcChar8 * v,FcBool * result)237 FcNameBool (const FcChar8 *v, FcBool *result)
238 {
239 char c0, c1;
240
241 c0 = *v;
242 c0 = FcToLower (c0);
243 if (c0 == 't' || c0 == 'y' || c0 == '1')
244 {
245 *result = FcTrue;
246 return FcTrue;
247 }
248 if (c0 == 'f' || c0 == 'n' || c0 == '0')
249 {
250 *result = FcFalse;
251 return FcTrue;
252 }
253 if (c0 == 'o')
254 {
255 c1 = v[1];
256 c1 = FcToLower (c1);
257 if (c1 == 'n')
258 {
259 *result = FcTrue;
260 return FcTrue;
261 }
262 if (c1 == 'f')
263 {
264 *result = FcFalse;
265 return FcTrue;
266 }
267 }
268 return FcFalse;
269 }
270
271 static FcValue
FcNameConvert(FcType type,FcChar8 * string)272 FcNameConvert (FcType type, FcChar8 *string)
273 {
274 FcValue v;
275 FcMatrix m;
276
277 v.type = type;
278 switch ((int) v.type) {
279 case FcTypeInteger:
280 if (!FcNameConstant (string, &v.u.i))
281 v.u.i = atoi ((char *) string);
282 break;
283 case FcTypeString:
284 v.u.s = FcStrdup (string);
285 if (!v.u.s)
286 v.type = FcTypeVoid;
287 break;
288 case FcTypeBool:
289 if (!FcNameBool (string, &v.u.b))
290 v.u.b = FcFalse;
291 break;
292 case FcTypeDouble:
293 v.u.d = strtod ((char *) string, 0);
294 break;
295 case FcTypeMatrix:
296 FcMatrixInit (&m);
297 sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
298 v.u.m = FcMatrixCopy (&m);
299 break;
300 case FcTypeCharSet:
301 v.u.c = FcNameParseCharSet (string);
302 if (!v.u.c)
303 v.type = FcTypeVoid;
304 break;
305 case FcTypeLangSet:
306 v.u.l = FcNameParseLangSet (string);
307 if (!v.u.l)
308 v.type = FcTypeVoid;
309 break;
310 default:
311 break;
312 }
313 return v;
314 }
315
316 static const FcChar8 *
FcNameFindNext(const FcChar8 * cur,const char * delim,FcChar8 * save,FcChar8 * last)317 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
318 {
319 FcChar8 c;
320
321 while ((c = *cur))
322 {
323 if (!isspace (c))
324 break;
325 ++cur;
326 }
327 while ((c = *cur))
328 {
329 if (c == '\\')
330 {
331 ++cur;
332 if (!(c = *cur))
333 break;
334 }
335 else if (strchr (delim, c))
336 break;
337 ++cur;
338 *save++ = c;
339 }
340 *save = 0;
341 *last = *cur;
342 if (*cur)
343 cur++;
344 return cur;
345 }
346
347 FcPattern *
FcNameParse(const FcChar8 * name)348 FcNameParse (const FcChar8 *name)
349 {
350 FcChar8 *save;
351 FcPattern *pat;
352 double d;
353 FcChar8 *e;
354 FcChar8 delim;
355 FcValue v;
356 const FcObjectType *t;
357 const FcConstant *c;
358
359 /* freed below */
360 save = malloc (strlen ((char *) name) + 1);
361 if (!save)
362 goto bail0;
363 pat = FcPatternCreate ();
364 if (!pat)
365 goto bail1;
366
367 for (;;)
368 {
369 name = FcNameFindNext (name, "-,:", save, &delim);
370 if (save[0])
371 {
372 if (!FcPatternAddString (pat, FC_FAMILY, save))
373 goto bail2;
374 }
375 if (delim != ',')
376 break;
377 }
378 if (delim == '-')
379 {
380 for (;;)
381 {
382 name = FcNameFindNext (name, "-,:", save, &delim);
383 d = strtod ((char *) save, (char **) &e);
384 if (e != save)
385 {
386 if (!FcPatternAddDouble (pat, FC_SIZE, d))
387 goto bail2;
388 }
389 if (delim != ',')
390 break;
391 }
392 }
393 while (delim == ':')
394 {
395 name = FcNameFindNext (name, "=_:", save, &delim);
396 if (save[0])
397 {
398 if (delim == '=' || delim == '_')
399 {
400 t = FcNameGetObjectType ((char *) save);
401 for (;;)
402 {
403 name = FcNameFindNext (name, ":,", save, &delim);
404 if (t)
405 {
406 v = FcNameConvert (t->type, save);
407 if (!FcPatternAdd (pat, t->object, v, FcTrue))
408 {
409 FcValueDestroy (v);
410 goto bail2;
411 }
412 FcValueDestroy (v);
413 }
414 if (delim != ',')
415 break;
416 }
417 }
418 else
419 {
420 if ((c = FcNameGetConstant (save)))
421 {
422 t = FcNameGetObjectType ((char *) c->object);
423 if (t == NULL)
424 goto bail2;
425 switch ((int) t->type) {
426 case FcTypeInteger:
427 case FcTypeDouble:
428 if (!FcPatternAddInteger (pat, c->object, c->value))
429 goto bail2;
430 break;
431 case FcTypeBool:
432 if (!FcPatternAddBool (pat, c->object, c->value))
433 goto bail2;
434 break;
435 default:
436 break;
437 }
438 }
439 }
440 }
441 }
442
443 free (save);
444 return pat;
445
446 bail2:
447 FcPatternDestroy (pat);
448 bail1:
449 free (save);
450 bail0:
451 return 0;
452 }
453 static FcBool
FcNameUnparseString(FcStrBuf * buf,const FcChar8 * string,const FcChar8 * escape)454 FcNameUnparseString (FcStrBuf *buf,
455 const FcChar8 *string,
456 const FcChar8 *escape)
457 {
458 FcChar8 c;
459 while ((c = *string++))
460 {
461 if (escape && strchr ((char *) escape, (char) c))
462 {
463 if (!FcStrBufChar (buf, escape[0]))
464 return FcFalse;
465 }
466 if (!FcStrBufChar (buf, c))
467 return FcFalse;
468 }
469 return FcTrue;
470 }
471
472 FcBool
FcNameUnparseValue(FcStrBuf * buf,FcValue * v0,FcChar8 * escape)473 FcNameUnparseValue (FcStrBuf *buf,
474 FcValue *v0,
475 FcChar8 *escape)
476 {
477 FcChar8 temp[1024];
478 FcValue v = FcValueCanonicalize(v0);
479
480 switch (v.type) {
481 case FcTypeUnknown:
482 case FcTypeVoid:
483 return FcTrue;
484 case FcTypeInteger:
485 sprintf ((char *) temp, "%d", v.u.i);
486 return FcNameUnparseString (buf, temp, 0);
487 case FcTypeDouble:
488 sprintf ((char *) temp, "%g", v.u.d);
489 return FcNameUnparseString (buf, temp, 0);
490 case FcTypeString:
491 return FcNameUnparseString (buf, v.u.s, escape);
492 case FcTypeBool:
493 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
494 case FcTypeMatrix:
495 sprintf ((char *) temp, "%g %g %g %g",
496 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
497 return FcNameUnparseString (buf, temp, 0);
498 case FcTypeCharSet:
499 return FcNameUnparseCharSet (buf, v.u.c);
500 case FcTypeLangSet:
501 return FcNameUnparseLangSet (buf, v.u.l);
502 case FcTypeFTFace:
503 return FcTrue;
504 }
505 return FcFalse;
506 }
507
508 FcBool
FcNameUnparseValueList(FcStrBuf * buf,FcValueListPtr v,FcChar8 * escape)509 FcNameUnparseValueList (FcStrBuf *buf,
510 FcValueListPtr v,
511 FcChar8 *escape)
512 {
513 while (v)
514 {
515 if (!FcNameUnparseValue (buf, &v->value, escape))
516 return FcFalse;
517 if ((v = FcValueListNext(v)) != NULL)
518 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
519 return FcFalse;
520 }
521 return FcTrue;
522 }
523
524 #define FC_ESCAPE_FIXED "\\-:,"
525 #define FC_ESCAPE_VARIABLE "\\=_:,"
526
527 FcChar8 *
FcNameUnparse(FcPattern * pat)528 FcNameUnparse (FcPattern *pat)
529 {
530 return FcNameUnparseEscaped (pat, FcTrue);
531 }
532
533 FcChar8 *
FcNameUnparseEscaped(FcPattern * pat,FcBool escape)534 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
535 {
536 FcStrBuf buf;
537 FcChar8 buf_static[8192];
538 int i;
539 FcPatternElt *e;
540
541 FcStrBufInit (&buf, buf_static, sizeof (buf_static));
542 e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
543 if (e)
544 {
545 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
546 goto bail0;
547 }
548 e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
549 if (e)
550 {
551 if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
552 goto bail0;
553 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
554 goto bail0;
555 }
556 for (i = 0; i < NUM_OBJECT_TYPES; i++)
557 {
558 FcObject id = i + 1;
559 const FcObjectType *o;
560 o = &FcObjects[i];
561 if (!strcmp (o->object, FC_FAMILY) ||
562 !strcmp (o->object, FC_SIZE))
563 continue;
564
565 e = FcPatternObjectFindElt (pat, id);
566 if (e)
567 {
568 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
569 goto bail0;
570 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
571 goto bail0;
572 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
573 goto bail0;
574 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
575 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
576 goto bail0;
577 }
578 }
579 return FcStrBufDone (&buf);
580 bail0:
581 FcStrBufDestroy (&buf);
582 return 0;
583 }
584 #define __fcname__
585 #include "fcaliastail.h"
586 #undef __fcname__
587