712b2fad36c24f62e49e32f85cd55482a642a6f3
[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         default:
91             if (type == t->type)
92                 return FcTrue;
93             break;
94         }
95         return FcFalse;
96     }
97     return FcTrue;
98 }
99
100 FcObject
101 FcObjectFromName (const char * name)
102 {
103     return FcObjectLookupIdByName (name);
104 }
105
106 FcObjectSet *
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 *
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
198 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
199 {
200     /* Deprecated. */
201     return FcFalse;
202 }
203
204 FcBool
205 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
206 {
207     /* Deprecated. */
208     return FcFalse;
209 }
210
211 const FcConstant *
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
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
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
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 *
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 *
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                     switch ((int) t->type) {
424                     case FcTypeInteger:
425                     case FcTypeDouble:
426                         if (!FcPatternAddInteger (pat, c->object, c->value))
427                             goto bail2;
428                         break;
429                     case FcTypeBool:
430                         if (!FcPatternAddBool (pat, c->object, c->value))
431                             goto bail2;
432                         break;
433                     default:
434                         break;
435                     }
436                 }
437             }
438         }
439     }
440
441     free (save);
442     return pat;
443
444 bail2:
445     FcPatternDestroy (pat);
446 bail1:
447     free (save);
448 bail0:
449     return 0;
450 }
451 static FcBool
452 FcNameUnparseString (FcStrBuf       *buf,
453                      const FcChar8  *string,
454                      const FcChar8  *escape)
455 {
456     FcChar8 c;
457     while ((c = *string++))
458     {
459         if (escape && strchr ((char *) escape, (char) c))
460         {
461             if (!FcStrBufChar (buf, escape[0]))
462                 return FcFalse;
463         }
464         if (!FcStrBufChar (buf, c))
465             return FcFalse;
466     }
467     return FcTrue;
468 }
469
470 FcBool
471 FcNameUnparseValue (FcStrBuf    *buf,
472                     FcValue     *v0,
473                     FcChar8     *escape)
474 {
475     FcChar8     temp[1024];
476     FcValue v = FcValueCanonicalize(v0);
477
478     switch (v.type) {
479     case FcTypeUnknown:
480     case FcTypeVoid:
481         return FcTrue;
482     case FcTypeInteger:
483         sprintf ((char *) temp, "%d", v.u.i);
484         return FcNameUnparseString (buf, temp, 0);
485     case FcTypeDouble:
486         sprintf ((char *) temp, "%g", v.u.d);
487         return FcNameUnparseString (buf, temp, 0);
488     case FcTypeString:
489         return FcNameUnparseString (buf, v.u.s, escape);
490     case FcTypeBool:
491         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
492     case FcTypeMatrix:
493         sprintf ((char *) temp, "%g %g %g %g",
494                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
495         return FcNameUnparseString (buf, temp, 0);
496     case FcTypeCharSet:
497         return FcNameUnparseCharSet (buf, v.u.c);
498     case FcTypeLangSet:
499         return FcNameUnparseLangSet (buf, v.u.l);
500     case FcTypeFTFace:
501         return FcTrue;
502     }
503     return FcFalse;
504 }
505
506 FcBool
507 FcNameUnparseValueList (FcStrBuf        *buf,
508                         FcValueListPtr  v,
509                         FcChar8         *escape)
510 {
511     while (v)
512     {
513         if (!FcNameUnparseValue (buf, &v->value, escape))
514             return FcFalse;
515         if ((v = FcValueListNext(v)) != NULL)
516             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
517                 return FcFalse;
518     }
519     return FcTrue;
520 }
521
522 #define FC_ESCAPE_FIXED    "\\-:,"
523 #define FC_ESCAPE_VARIABLE "\\=_:,"
524
525 FcChar8 *
526 FcNameUnparse (FcPattern *pat)
527 {
528     return FcNameUnparseEscaped (pat, FcTrue);
529 }
530
531 FcChar8 *
532 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
533 {
534     FcStrBuf                buf;
535     FcChar8                 buf_static[8192];
536     int                     i;
537     FcPatternElt            *e;
538
539     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
540     e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
541     if (e)
542     {
543         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
544             goto bail0;
545     }
546     e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
547     if (e)
548     {
549         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
550             goto bail0;
551         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
552             goto bail0;
553     }
554     for (i = 0; i < NUM_OBJECT_TYPES; i++)
555     {
556         FcObject id = i + 1;
557         const FcObjectType          *o;
558         o = &FcObjects[i];
559         if (!strcmp (o->object, FC_FAMILY) ||
560             !strcmp (o->object, FC_SIZE))
561             continue;
562     
563         e = FcPatternObjectFindElt (pat, id);
564         if (e)
565         {
566             if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
567                 goto bail0;
568             if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
569                 goto bail0;
570             if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
571                 goto bail0;
572             if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
573                                          (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
574                 goto bail0;
575         }
576     }
577     return FcStrBufDone (&buf);
578 bail0:
579     FcStrBufDestroy (&buf);
580     return 0;
581 }
582 #define __fcname__
583 #include "fcaliastail.h"
584 #undef __fcname__