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