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