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