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