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