Add FC_RGBA_UNKNOWN
[platform/upstream/fontconfig.git] / src / fcname.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.15 2002/09/26 00:17:28 keithp Exp $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes 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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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 <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include "fcint.h"
30
31 static const FcObjectType _FcBaseObjectTypes[] = {
32     { FC_FAMILY,        FcTypeString, },
33     { FC_STYLE,         FcTypeString, },
34     { FC_SLANT,         FcTypeInteger, },
35     { FC_WEIGHT,        FcTypeInteger, },
36     { FC_SIZE,          FcTypeDouble, },
37     { FC_ASPECT,        FcTypeDouble, },
38     { FC_PIXEL_SIZE,    FcTypeDouble, },
39     { FC_SPACING,       FcTypeInteger, },
40     { FC_FOUNDRY,       FcTypeString, },
41 /*    { FC_CORE,                FcTypeBool, }, */
42     { FC_ANTIALIAS,     FcTypeBool, },
43     { FC_HINTING,       FcTypeBool, },
44     { FC_VERTICAL_LAYOUT,   FcTypeBool, },
45     { FC_AUTOHINT,      FcTypeBool, },
46     { FC_GLOBAL_ADVANCE,    FcTypeBool, },
47 /*    { FC_XLFD,                FcTypeString, }, */
48     { FC_FILE,          FcTypeString, },
49     { FC_INDEX,         FcTypeInteger, },
50     { FC_RASTERIZER,    FcTypeString, },
51     { FC_OUTLINE,       FcTypeBool, },
52     { FC_SCALABLE,      FcTypeBool, },
53     { FC_DPI,           FcTypeDouble },
54     { FC_RGBA,          FcTypeInteger, },
55     { FC_SCALE,         FcTypeDouble, },
56 /*    { FC_RENDER,      FcTypeBool, },*/
57     { FC_MINSPACE,      FcTypeBool, },
58     { FC_CHAR_WIDTH,    FcTypeInteger },
59     { FC_CHAR_HEIGHT,   FcTypeInteger },
60     { FC_MATRIX,        FcTypeMatrix },
61     { FC_CHARSET,       FcTypeCharSet },
62     { FC_LANG,          FcTypeLangSet },
63     { FC_FONTVERSION,   FcTypeInteger },
64 };
65
66 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
67
68 typedef struct _FcObjectTypeList    FcObjectTypeList;
69
70 struct _FcObjectTypeList {
71     const FcObjectTypeList  *next;
72     const FcObjectType      *types;
73     int                     ntypes;
74 };
75
76 static const FcObjectTypeList _FcBaseObjectTypesList = {
77     0,
78     _FcBaseObjectTypes,
79     NUM_OBJECT_TYPES
80 };
81
82 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
83
84 FcBool
85 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
86 {
87     FcObjectTypeList    *l;
88
89     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
90     if (!l)
91         return FcFalse;
92     FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
93     l->types = types;
94     l->ntypes = ntypes;
95     l->next = _FcObjectTypes;
96     _FcObjectTypes = l;
97     return FcTrue;
98 }
99
100 FcBool
101 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
102 {
103     const FcObjectTypeList      *l, **prev;
104
105     for (prev = &_FcObjectTypes; 
106          (l = *prev); 
107          prev = (const FcObjectTypeList **) &(l->next))
108     {
109         if (l->types == types && l->ntypes == ntypes)
110         {
111             *prev = l->next;
112             FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
113             free ((void *) l);
114             return FcTrue;
115         }
116     }
117     return FcFalse;
118 }
119
120 const FcObjectType *
121 FcNameGetObjectType (const char *object)
122 {
123     int                     i;
124     const FcObjectTypeList  *l;
125     const FcObjectType      *t;
126     
127     for (l = _FcObjectTypes; l; l = l->next)
128     {
129         for (i = 0; i < l->ntypes; i++)
130         {
131             t = &l->types[i];
132             if (!strcmp (object, t->object))
133                 return t;
134         }
135     }
136     return 0;
137 }
138
139 static const FcConstant _FcBaseConstants[] = {
140     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
141     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
142     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
143     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
144     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
145
146     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
147     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
148     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
149
150     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
151     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
152     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
153
154     { (FcChar8 *) "unknown",        "rgba",         FC_RGBA_UNKNOWN },
155     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
156     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
157     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
158     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
159     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
160 };
161
162 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
163
164 typedef struct _FcConstantList FcConstantList;
165
166 struct _FcConstantList {
167     const FcConstantList    *next;
168     const FcConstant        *consts;
169     int                     nconsts;
170 };
171
172 static const FcConstantList _FcBaseConstantList = {
173     0,
174     _FcBaseConstants,
175     NUM_FC_CONSTANTS
176 };
177
178 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
179
180 FcBool
181 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
182 {
183     FcConstantList      *l;
184
185     l = (FcConstantList *) malloc (sizeof (FcConstantList));
186     if (!l)
187         return FcFalse;
188     FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
189     l->consts = consts;
190     l->nconsts = nconsts;
191     l->next = _FcConstants;
192     _FcConstants = l;
193     return FcTrue;
194 }
195
196 FcBool
197 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
198 {
199     const FcConstantList        *l, **prev;
200
201     for (prev = &_FcConstants; 
202          (l = *prev); 
203          prev = (const FcConstantList **) &(l->next))
204     {
205         if (l->consts == consts && l->nconsts == nconsts)
206         {
207             *prev = l->next;
208             FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
209             free ((void *) l);
210             return FcTrue;
211         }
212     }
213     return FcFalse;
214 }
215
216 const FcConstant *
217 FcNameGetConstant (FcChar8 *string)
218 {
219     const FcConstantList    *l;
220     int                     i;
221     
222     for (l = _FcConstants; l; l = l->next)
223     {
224         for (i = 0; i < l->nconsts; i++)
225             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
226                 return &l->consts[i];
227     }
228     return 0;
229 }
230
231 FcBool
232 FcNameConstant (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 (FcChar8 *v, FcBool *result)
246 {
247     char    c0, c1;
248
249     c0 = *v;
250     if (isupper (c0))
251         c0 = tolower (c0);
252     if (c0 == 't' || c0 == 'y' || c0 == '1')
253     {
254         *result = FcTrue;
255         return FcTrue;
256     }
257     if (c0 == 'f' || c0 == 'n' || c0 == '0')
258     {
259         *result = FcFalse;
260         return FcTrue;
261     }
262     if (c0 == 'o')
263     {
264         c1 = v[1];
265         if (isupper (c1))
266             c1 = tolower (c1);
267         if (c1 == 'n')
268         {
269             *result = FcTrue;
270             return FcTrue;
271         }
272         if (c1 == 'f')
273         {
274             *result = FcFalse;
275             return FcTrue;
276         }
277     }
278     return FcFalse;
279 }
280
281 static FcValue
282 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
283 {
284     FcValue     v;
285
286     v.type = type;
287     switch (v.type) {
288     case FcTypeInteger:
289         if (!FcNameConstant (string, &v.u.i))
290             v.u.i = atoi ((char *) string);
291         break;
292     case FcTypeString:
293         v.u.s = string;
294         break;
295     case FcTypeBool:
296         if (!FcNameBool (string, &v.u.b))
297             v.u.b = FcFalse;
298         break;
299     case FcTypeDouble:
300         v.u.d = strtod ((char *) string, 0);
301         break;
302     case FcTypeMatrix:
303         v.u.m = m;
304         sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
305         break;
306     case FcTypeCharSet:
307         v.u.c = FcNameParseCharSet (string);
308         break;
309     case FcTypeLangSet:
310         v.u.l = FcNameParseLangSet (string);
311         break;
312     default:
313         break;
314     }
315     return v;
316 }
317
318 static const FcChar8 *
319 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
320 {
321     FcChar8    c;
322     
323     while ((c = *cur))
324     {
325         if (c == '\\')
326         {
327             ++cur;
328             if (!(c = *cur))
329                 break;
330         }
331         else if (strchr (delim, c))
332             break;
333         ++cur;
334         *save++ = c;
335     }
336     *save = 0;
337     *last = *cur;
338     if (*cur)
339         cur++;
340     return cur;
341 }
342
343 FcPattern *
344 FcNameParse (const FcChar8 *name)
345 {
346     FcChar8             *save;
347     FcPattern           *pat;
348     double              d;
349     FcChar8             *e;
350     FcChar8             delim;
351     FcValue             v;
352     FcMatrix            m;
353     const FcObjectType  *t;
354     const FcConstant    *c;
355
356     /* freed below */
357     save = malloc (strlen ((char *) name) + 1);
358     if (!save)
359         goto bail0;
360     pat = FcPatternCreate ();
361     if (!pat)
362         goto bail1;
363
364     for (;;)
365     {
366         name = FcNameFindNext (name, "-,:", save, &delim);
367         if (save[0])
368         {
369             if (!FcPatternAddString (pat, FC_FAMILY, save))
370                 goto bail2;
371         }
372         if (delim != ',')
373             break;
374     }
375     if (delim == '-')
376     {
377         for (;;)
378         {
379             name = FcNameFindNext (name, "-,:", save, &delim);
380             d = strtod ((char *) save, (char **) &e);
381             if (e != save)
382             {
383                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
384                     goto bail2;
385             }
386             if (delim != ',')
387                 break;
388         }
389     }
390     while (delim == ':')
391     {
392         name = FcNameFindNext (name, "=_:", save, &delim);
393         if (save[0])
394         {
395             if (delim == '=' || delim == '_')
396             {
397                 t = FcNameGetObjectType ((char *) save);
398                 for (;;)
399                 {
400                     name = FcNameFindNext (name, ":,", save, &delim);
401                     if (t)
402                     {
403                         v = FcNameConvert (t->type, save, &m);
404                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
405                         {
406                             switch (v.type) {
407                             case FcTypeCharSet:
408                                 FcCharSetDestroy ((FcCharSet *) v.u.c);
409                                 break;
410                             case FcTypeLangSet:
411                                 FcLangSetDestroy ((FcLangSet *) v.u.l);
412                                 break;
413                             default:
414                                 break;
415                             }
416                             goto bail2;
417                         }
418                         switch (v.type) {
419                         case FcTypeCharSet:
420                             FcCharSetDestroy ((FcCharSet *) v.u.c);
421                             break;
422                         case FcTypeLangSet:
423                             FcLangSetDestroy ((FcLangSet *) v.u.l);
424                             break;
425                         default:
426                             break;
427                         }
428                     }
429                     if (delim != ',')
430                         break;
431                 }
432             }
433             else
434             {
435                 if ((c = FcNameGetConstant (save)))
436                 {
437                     if (!FcPatternAddInteger (pat, c->object, c->value))
438                         goto bail2;
439                 }
440             }
441         }
442     }
443
444     free (save);
445     return pat;
446
447 bail2:
448     FcPatternDestroy (pat);
449 bail1:
450     free (save);
451 bail0:
452     return 0;
453 }
454 static FcBool
455 FcNameUnparseString (FcStrBuf       *buf, 
456                      const FcChar8  *string,
457                      const FcChar8  *escape)
458 {
459     FcChar8 c;
460     while ((c = *string++))
461     {
462         if (escape && strchr ((char *) escape, (char) c))
463         {
464             if (!FcStrBufChar (buf, escape[0]))
465                 return FcFalse;
466         }
467         if (!FcStrBufChar (buf, c))
468             return FcFalse;
469     }
470     return FcTrue;
471 }
472
473 static FcBool
474 FcNameUnparseValue (FcStrBuf    *buf,
475                     FcValue     v,
476                     FcChar8     *escape)
477 {
478     FcChar8     temp[1024];
479     
480     switch (v.type) {
481     case FcTypeVoid:
482         return FcTrue;
483     case FcTypeInteger:
484         sprintf ((char *) temp, "%d", v.u.i);
485         return FcNameUnparseString (buf, temp, 0);
486     case FcTypeDouble:
487         sprintf ((char *) temp, "%g", v.u.d);
488         return FcNameUnparseString (buf, temp, 0);
489     case FcTypeString:
490         return FcNameUnparseString (buf, v.u.s, escape);
491     case FcTypeBool:
492         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
493     case FcTypeMatrix:
494         sprintf ((char *) temp, "%g %g %g %g", 
495                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
496         return FcNameUnparseString (buf, temp, 0);
497     case FcTypeCharSet:
498         return FcNameUnparseCharSet (buf, v.u.c);
499     case FcTypeLangSet:
500         return FcNameUnparseLangSet (buf, v.u.l);
501     case FcTypeFTFace:
502         return FcTrue;
503     }
504     return FcFalse;
505 }
506
507 static FcBool
508 FcNameUnparseValueList (FcStrBuf        *buf,
509                         FcValueList     *v,
510                         FcChar8         *escape)
511 {
512     while (v)
513     {
514         if (!FcNameUnparseValue (buf, v->value, escape))
515             return FcFalse;
516         if ((v = v->next))
517             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
518                 return FcFalse;
519     }
520     return FcTrue;
521 }
522
523 #define FC_ESCAPE_FIXED    "\\-:,"
524 #define FC_ESCAPE_VARIABLE "\\=_:,"
525
526 FcChar8 *
527 FcNameUnparse (FcPattern *pat)
528 {
529     FcStrBuf                buf;
530     FcChar8                 buf_static[8192];
531     int                     i;
532     FcPatternElt            *e;
533     const FcObjectTypeList  *l;
534     const FcObjectType      *o;
535
536     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
537     e = FcPatternFindElt (pat, FC_FAMILY);
538     if (e)
539     {
540         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
541             goto bail0;
542     }
543     e = FcPatternFindElt (pat, FC_SIZE);
544     if (e)
545     {
546         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
547             goto bail0;
548         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
549             goto bail0;
550     }
551     for (l = _FcObjectTypes; l; l = l->next)
552     {
553         for (i = 0; i < l->ntypes; i++)
554         {
555             o = &l->types[i];
556             if (!strcmp (o->object, FC_FAMILY) || 
557                 !strcmp (o->object, FC_SIZE) ||
558                 !strcmp (o->object, FC_FILE))
559                 continue;
560             
561             e = FcPatternFindElt (pat, o->object);
562             if (e)
563             {
564                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
565                     goto bail0;
566                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
567                     goto bail0;
568                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
569                     goto bail0;
570                 if (!FcNameUnparseValueList (&buf, e->values, 
571                                              (FcChar8 *) FC_ESCAPE_VARIABLE))
572                     goto bail0;
573             }
574         }
575     }
576     return FcStrBufDone (&buf);
577 bail0:
578     FcStrBufDestroy (&buf);
579     return 0;
580 }