711bb9b24664f019d765af194663e92366de7f7e
[platform/upstream/fontconfig.git] / src / fcname.c
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 *
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
48 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
49 {
50     /* Deprecated. */
51     return FcFalse;
52 }
53
54 FcBool
55 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
56 {
57     /* Deprecated. */
58     return FcFalse;
59 }
60
61 const FcObjectType *
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
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         case FcTypeRange:
91             if (type == FcTypeRange ||
92                 type == FcTypeDouble ||
93                 type == FcTypeInteger)
94                 return FcTrue;
95             break;
96         default:
97             if (type == t->type)
98                 return FcTrue;
99             break;
100         }
101         return FcFalse;
102     }
103     return FcTrue;
104 }
105
106 FcObject
107 FcObjectFromName (const char * name)
108 {
109     return FcObjectLookupIdByName (name);
110 }
111
112 FcObjectSet *
113 FcObjectGetSet (void)
114 {
115     int         i;
116     FcObjectSet *os = NULL;
117
118
119     os = FcObjectSetCreate ();
120     for (i = 0; i < NUM_OBJECT_TYPES; i++)
121         FcObjectSetAdd (os, FcObjects[i].object);
122
123     return os;
124 }
125
126 const char *
127 FcObjectName (FcObject object)
128 {
129     const FcObjectType   *o = FcObjectFindById (object);
130
131     if (o)
132         return o->object;
133
134     return FcObjectLookupOtherNameById (object);
135 }
136
137 static const FcConstant _FcBaseConstants[] = {
138     { (FcChar8 *) "thin",           "weight",   FC_WEIGHT_THIN, },
139     { (FcChar8 *) "extralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
140     { (FcChar8 *) "ultralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
141     { (FcChar8 *) "demilight",      "weight",   FC_WEIGHT_DEMILIGHT, },
142     { (FcChar8 *) "semilight",      "weight",   FC_WEIGHT_DEMILIGHT, },
143     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
144     { (FcChar8 *) "book",           "weight",   FC_WEIGHT_BOOK, },
145     { (FcChar8 *) "regular",        "weight",   FC_WEIGHT_REGULAR, },
146     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
147     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
148     { (FcChar8 *) "semibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
149     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
150     { (FcChar8 *) "extrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
151     { (FcChar8 *) "ultrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
152     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
153     { (FcChar8 *) "heavy",          "weight",   FC_WEIGHT_HEAVY, },
154
155     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
156     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
157     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
158
159     { (FcChar8 *) "ultracondensed", "width",    FC_WIDTH_ULTRACONDENSED },
160     { (FcChar8 *) "extracondensed", "width",    FC_WIDTH_EXTRACONDENSED },
161     { (FcChar8 *) "condensed",      "width",    FC_WIDTH_CONDENSED },
162     { (FcChar8 *) "semicondensed",  "width",    FC_WIDTH_SEMICONDENSED },
163     { (FcChar8 *) "normal",         "width",    FC_WIDTH_NORMAL },
164     { (FcChar8 *) "semiexpanded",   "width",    FC_WIDTH_SEMIEXPANDED },
165     { (FcChar8 *) "expanded",       "width",    FC_WIDTH_EXPANDED },
166     { (FcChar8 *) "extraexpanded",  "width",    FC_WIDTH_EXTRAEXPANDED },
167     { (FcChar8 *) "ultraexpanded",  "width",    FC_WIDTH_ULTRAEXPANDED },
168
169     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
170     { (FcChar8 *) "dual",           "spacing",  FC_DUAL, },
171     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
172     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
173
174     { (FcChar8 *) "unknown",        "rgba",         FC_RGBA_UNKNOWN },
175     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
176     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
177     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
178     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
179     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
180
181     { (FcChar8 *) "hintnone",       "hintstyle",   FC_HINT_NONE },
182     { (FcChar8 *) "hintslight",     "hintstyle",   FC_HINT_SLIGHT },
183     { (FcChar8 *) "hintmedium",     "hintstyle",   FC_HINT_MEDIUM },
184     { (FcChar8 *) "hintfull",       "hintstyle",   FC_HINT_FULL },
185
186     { (FcChar8 *) "antialias",      "antialias",    FcTrue },
187     { (FcChar8 *) "hinting",        "hinting",      FcTrue },
188     { (FcChar8 *) "verticallayout", "verticallayout",   FcTrue },
189     { (FcChar8 *) "autohint",       "autohint",     FcTrue },
190     { (FcChar8 *) "globaladvance",  "globaladvance",    FcTrue }, /* deprecated */
191     { (FcChar8 *) "outline",        "outline",      FcTrue },
192     { (FcChar8 *) "scalable",       "scalable",     FcTrue },
193     { (FcChar8 *) "minspace",       "minspace",     FcTrue },
194     { (FcChar8 *) "embolden",       "embolden",     FcTrue },
195     { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",   FcTrue },
196     { (FcChar8 *) "decorative",     "decorative",   FcTrue },
197     { (FcChar8 *) "lcdnone",        "lcdfilter",    FC_LCD_NONE },
198     { (FcChar8 *) "lcddefault",     "lcdfilter",    FC_LCD_DEFAULT },
199     { (FcChar8 *) "lcdlight",       "lcdfilter",    FC_LCD_LIGHT },
200     { (FcChar8 *) "lcdlegacy",      "lcdfilter",    FC_LCD_LEGACY },
201 };
202
203 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
204
205 FcBool
206 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
207 {
208     /* Deprecated. */
209     return FcFalse;
210 }
211
212 FcBool
213 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
214 {
215     /* Deprecated. */
216     return FcFalse;
217 }
218
219 const FcConstant *
220 FcNameGetConstant (const FcChar8 *string)
221 {
222     unsigned int            i;
223
224     for (i = 0; i < NUM_FC_CONSTANTS; i++)
225         if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
226             return &_FcBaseConstants[i];
227
228     return 0;
229 }
230
231 FcBool
232 FcNameConstant (const FcChar8 *string, int *result)
233 {
234     const FcConstant    *c;
235
236     if ((c = FcNameGetConstant(string)))
237     {
238         *result = c->value;
239         return FcTrue;
240     }
241     return FcFalse;
242 }
243
244 FcBool
245 FcNameBool (const FcChar8 *v, FcBool *result)
246 {
247     char    c0, c1;
248
249     c0 = *v;
250     c0 = FcToLower (c0);
251     if (c0 == 't' || c0 == 'y' || c0 == '1')
252     {
253         *result = FcTrue;
254         return FcTrue;
255     }
256     if (c0 == 'f' || c0 == 'n' || c0 == '0')
257     {
258         *result = FcFalse;
259         return FcTrue;
260     }
261     if (c0 == 'd' || c0 == 'x' || c0 == '2')
262     {
263         *result = FcDontCare;
264         return FcTrue;
265     }
266     if (c0 == 'o')
267     {
268         c1 = v[1];
269         c1 = FcToLower (c1);
270         if (c1 == 'n')
271         {
272             *result = FcTrue;
273             return FcTrue;
274         }
275         if (c1 == 'f')
276         {
277             *result = FcFalse;
278             return FcTrue;
279         }
280         if (c1 == 'r')
281         {
282             *result = FcDontCare;
283             return FcTrue;
284         }
285     }
286     return FcFalse;
287 }
288
289 static FcValue
290 FcNameConvert (FcType type, FcChar8 *string)
291 {
292     FcValue     v;
293     FcMatrix    m;
294     double      b, e;
295     char        *p;
296
297     v.type = type;
298     switch ((int) v.type) {
299     case FcTypeInteger:
300         if (!FcNameConstant (string, &v.u.i))
301             v.u.i = atoi ((char *) string);
302         break;
303     case FcTypeString:
304         v.u.s = FcStrdup (string);
305         if (!v.u.s)
306             v.type = FcTypeVoid;
307         break;
308     case FcTypeBool:
309         if (!FcNameBool (string, &v.u.b))
310             v.u.b = FcFalse;
311         break;
312     case FcTypeDouble:
313         v.u.d = strtod ((char *) string, 0);
314         break;
315     case FcTypeMatrix:
316         FcMatrixInit (&m);
317         sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
318         v.u.m = FcMatrixCopy (&m);
319         break;
320     case FcTypeCharSet:
321         v.u.c = FcNameParseCharSet (string);
322         if (!v.u.c)
323             v.type = FcTypeVoid;
324         break;
325     case FcTypeLangSet:
326         v.u.l = FcNameParseLangSet (string);
327         if (!v.u.l)
328             v.type = FcTypeVoid;
329         break;
330     case FcTypeRange:
331         if (sscanf ((char *) string, "[%lg %lg]", &b, &e) != 2)
332         {
333             char *sc, *ec;
334             size_t len = strlen ((const char *) string);
335             int si, ei;
336
337             sc = malloc (len + 1);
338             ec = malloc (len + 1);
339             if (sc && ec && sscanf ((char *) string, "[%s %[^]]]", sc, ec) == 2)
340             {
341                 if (FcNameConstant ((const FcChar8 *) sc, &si) &&
342                     FcNameConstant ((const FcChar8 *) ec, &ei))
343                     v.u.r =  FcRangeCreateDouble (si, ei);
344                 else
345                     goto bail1;
346             }
347             else
348             {
349             bail1:
350                 v.type = FcTypeDouble;
351                 if (FcNameConstant (string, &si))
352                 {
353                     v.u.d = (double) si;
354                 } else {
355                     v.u.d = strtod ((char *) string, &p);
356                     if (p != NULL && p[0] != 0)
357                         v.type = FcTypeVoid;
358                 }
359             }
360             if (sc)
361                 free (sc);
362             if (ec)
363                 free (ec);
364         }
365         else
366             v.u.r = FcRangeCreateDouble (b, e);
367         break;
368     default:
369         break;
370     }
371     return v;
372 }
373
374 static const FcChar8 *
375 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
376 {
377     FcChar8    c;
378
379     while ((c = *cur))
380     {
381         if (!isspace (c))
382             break;
383         ++cur;
384     }
385     while ((c = *cur))
386     {
387         if (c == '\\')
388         {
389             ++cur;
390             if (!(c = *cur))
391                 break;
392         }
393         else if (strchr (delim, c))
394             break;
395         ++cur;
396         *save++ = c;
397     }
398     *save = 0;
399     *last = *cur;
400     if (*cur)
401         cur++;
402     return cur;
403 }
404
405 FcPattern *
406 FcNameParse (const FcChar8 *name)
407 {
408     FcChar8             *save;
409     FcPattern           *pat;
410     double              d;
411     FcChar8             *e;
412     FcChar8             delim;
413     FcValue             v;
414     const FcObjectType  *t;
415     const FcConstant    *c;
416
417     /* freed below */
418     save = malloc (strlen ((char *) name) + 1);
419     if (!save)
420         goto bail0;
421     pat = FcPatternCreate ();
422     if (!pat)
423         goto bail1;
424
425     for (;;)
426     {
427         name = FcNameFindNext (name, "-,:", save, &delim);
428         if (save[0])
429         {
430             if (!FcPatternAddString (pat, FC_FAMILY, save))
431                 goto bail2;
432         }
433         if (delim != ',')
434             break;
435     }
436     if (delim == '-')
437     {
438         for (;;)
439         {
440             name = FcNameFindNext (name, "-,:", save, &delim);
441             d = strtod ((char *) save, (char **) &e);
442             if (e != save)
443             {
444                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
445                     goto bail2;
446             }
447             if (delim != ',')
448                 break;
449         }
450     }
451     while (delim == ':')
452     {
453         name = FcNameFindNext (name, "=_:", save, &delim);
454         if (save[0])
455         {
456             if (delim == '=' || delim == '_')
457             {
458                 t = FcNameGetObjectType ((char *) save);
459                 for (;;)
460                 {
461                     name = FcNameFindNext (name, ":,", save, &delim);
462                     if (t)
463                     {
464                         v = FcNameConvert (t->type, save);
465                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
466                         {
467                             FcValueDestroy (v);
468                             goto bail2;
469                         }
470                         FcValueDestroy (v);
471                     }
472                     if (delim != ',')
473                         break;
474                 }
475             }
476             else
477             {
478                 if ((c = FcNameGetConstant (save)))
479                 {
480                     t = FcNameGetObjectType ((char *) c->object);
481                     if (t == NULL)
482                         goto bail2;
483                     switch ((int) t->type) {
484                     case FcTypeInteger:
485                     case FcTypeDouble:
486                         if (!FcPatternAddInteger (pat, c->object, c->value))
487                             goto bail2;
488                         break;
489                     case FcTypeBool:
490                         if (!FcPatternAddBool (pat, c->object, c->value))
491                             goto bail2;
492                         break;
493                     case FcTypeRange:
494                         if (!FcPatternAddInteger (pat, c->object, c->value))
495                             goto bail2;
496                         break;
497                     default:
498                         break;
499                     }
500                 }
501             }
502         }
503     }
504
505     free (save);
506     return pat;
507
508 bail2:
509     FcPatternDestroy (pat);
510 bail1:
511     free (save);
512 bail0:
513     return 0;
514 }
515 static FcBool
516 FcNameUnparseString (FcStrBuf       *buf,
517                      const FcChar8  *string,
518                      const FcChar8  *escape)
519 {
520     FcChar8 c;
521     while ((c = *string++))
522     {
523         if (escape && strchr ((char *) escape, (char) c))
524         {
525             if (!FcStrBufChar (buf, escape[0]))
526                 return FcFalse;
527         }
528         if (!FcStrBufChar (buf, c))
529             return FcFalse;
530     }
531     return FcTrue;
532 }
533
534 FcBool
535 FcNameUnparseValue (FcStrBuf    *buf,
536                     FcValue     *v0,
537                     FcChar8     *escape)
538 {
539     FcChar8     temp[1024];
540     FcValue v = FcValueCanonicalize(v0);
541
542     switch (v.type) {
543     case FcTypeUnknown:
544     case FcTypeVoid:
545         return FcTrue;
546     case FcTypeInteger:
547         sprintf ((char *) temp, "%d", v.u.i);
548         return FcNameUnparseString (buf, temp, 0);
549     case FcTypeDouble:
550         sprintf ((char *) temp, "%g", v.u.d);
551         return FcNameUnparseString (buf, temp, 0);
552     case FcTypeString:
553         return FcNameUnparseString (buf, v.u.s, escape);
554     case FcTypeBool:
555         return FcNameUnparseString (buf,
556                                     v.u.b == FcTrue  ? (FcChar8 *) "True" :
557                                     v.u.b == FcFalse ? (FcChar8 *) "False" :
558                                                        (FcChar8 *) "DontCare", 0);
559     case FcTypeMatrix:
560         sprintf ((char *) temp, "%g %g %g %g",
561                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
562         return FcNameUnparseString (buf, temp, 0);
563     case FcTypeCharSet:
564         return FcNameUnparseCharSet (buf, v.u.c);
565     case FcTypeLangSet:
566         return FcNameUnparseLangSet (buf, v.u.l);
567     case FcTypeFTFace:
568         return FcTrue;
569     case FcTypeRange:
570         sprintf ((char *) temp, "[%g %g]", v.u.r->begin, v.u.r->end);
571         return FcNameUnparseString (buf, temp, 0);
572     }
573     return FcFalse;
574 }
575
576 FcBool
577 FcNameUnparseValueList (FcStrBuf        *buf,
578                         FcValueListPtr  v,
579                         FcChar8         *escape)
580 {
581     while (v)
582     {
583         if (!FcNameUnparseValue (buf, &v->value, escape))
584             return FcFalse;
585         if ((v = FcValueListNext(v)) != NULL)
586             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
587                 return FcFalse;
588     }
589     return FcTrue;
590 }
591
592 #define FC_ESCAPE_FIXED    "\\-:,"
593 #define FC_ESCAPE_VARIABLE "\\=_:,"
594
595 FcChar8 *
596 FcNameUnparse (FcPattern *pat)
597 {
598     return FcNameUnparseEscaped (pat, FcTrue);
599 }
600
601 FcChar8 *
602 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
603 {
604     FcStrBuf                buf, buf2;
605     FcChar8                 buf_static[8192], buf2_static[256];
606     int                     i;
607     FcPatternElt            *e;
608
609     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
610     FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static));
611     e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
612     if (e)
613     {
614         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
615             goto bail0;
616     }
617     e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
618     if (e)
619     {
620         FcChar8 *p;
621
622         if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0))
623             goto bail0;
624         if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
625             goto bail0;
626         p = FcStrBufDoneStatic (&buf2);
627         FcStrBufDestroy (&buf2);
628         if (strlen ((const char *)p) > 1)
629             if (!FcStrBufString (&buf, p))
630                 goto bail0;
631     }
632     for (i = 0; i < NUM_OBJECT_TYPES; i++)
633     {
634         FcObject id = i + 1;
635         const FcObjectType          *o;
636         o = &FcObjects[i];
637         if (!strcmp (o->object, FC_FAMILY) ||
638             !strcmp (o->object, FC_SIZE))
639             continue;
640     
641         e = FcPatternObjectFindElt (pat, id);
642         if (e)
643         {
644             if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
645                 goto bail0;
646             if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
647                 goto bail0;
648             if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
649                 goto bail0;
650             if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
651                                          (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
652                 goto bail0;
653         }
654     }
655     return FcStrBufDone (&buf);
656 bail0:
657     FcStrBufDestroy (&buf);
658     return 0;
659 }
660 #define __fcname__
661 #include "fcaliastail.h"
662 #undef __fcname__