Add FC_EMBEDDED_BITMAP object type to tell Xft/Cairo whether to load
[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 /* Please do not revoke any of these bindings. */
32 static const FcObjectType _FcBaseObjectTypes[] = {
33     { "__DUMMY__",      FcTypeVoid, },
34     { FC_FAMILY,        FcTypeString, },
35     { FC_FAMILYLANG,    FcTypeString, },
36     { FC_STYLE,         FcTypeString, },
37     { FC_STYLELANG,     FcTypeString, },
38     { FC_FULLNAME,      FcTypeString, },
39     { FC_FULLNAMELANG,  FcTypeString, },
40     { FC_SLANT,         FcTypeInteger, },
41     { FC_WEIGHT,        FcTypeInteger, },
42     { FC_WIDTH,         FcTypeInteger, },
43     { FC_SIZE,          FcTypeDouble, },
44     { FC_ASPECT,        FcTypeDouble, },
45     { FC_PIXEL_SIZE,    FcTypeDouble, },
46     { FC_SPACING,       FcTypeInteger, },
47     { FC_FOUNDRY,       FcTypeString, },
48 /*    { FC_CORE,                FcTypeBool, }, */
49     { FC_ANTIALIAS,     FcTypeBool, },
50     { FC_HINT_STYLE,    FcTypeInteger, },
51     { FC_HINTING,       FcTypeBool, },
52     { FC_VERTICAL_LAYOUT,   FcTypeBool, },
53     { FC_AUTOHINT,      FcTypeBool, },
54     { FC_GLOBAL_ADVANCE,    FcTypeBool, },
55 /*    { FC_XLFD,                FcTypeString, }, */
56     { FC_FILE,          FcTypeString, },
57     { FC_INDEX,         FcTypeInteger, },
58     { FC_RASTERIZER,    FcTypeString, },
59     { FC_OUTLINE,       FcTypeBool, },
60     { FC_SCALABLE,      FcTypeBool, },
61     { FC_DPI,           FcTypeDouble },
62     { FC_RGBA,          FcTypeInteger, },
63     { FC_SCALE,         FcTypeDouble, },
64     { FC_MINSPACE,      FcTypeBool, },
65 /*    { FC_RENDER,      FcTypeBool, },*/
66     { FC_CHAR_WIDTH,    FcTypeInteger },
67     { FC_CHAR_HEIGHT,   FcTypeInteger },
68     { FC_MATRIX,        FcTypeMatrix },
69     { FC_CHARSET,       FcTypeCharSet },
70     { FC_LANG,          FcTypeLangSet },
71     { FC_FONTVERSION,   FcTypeInteger },
72     { FC_CAPABILITY,    FcTypeString },
73     { FC_FONTFORMAT,    FcTypeString },
74     { FC_EMBOLDEN,      FcTypeBool },
75     { FC_EMBEDDED_BITMAP,   FcTypeBool },
76 };
77
78 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
79
80 static FcObjectType * _FcUserObjectNames = 0;
81 static int user_obj_alloc = 0;
82 static int next_basic_offset = NUM_OBJECT_TYPES;
83
84 typedef struct _FcObjectTypeList    FcObjectTypeList;
85
86 struct _FcObjectTypeList {
87     const FcObjectTypeList  *next;
88     const FcObjectType      *types;
89     int                     ntypes;
90     int                     basic_offset;
91 };
92
93 static const FcObjectTypeList _FcBaseObjectTypesList = {
94     0,
95     _FcBaseObjectTypes,
96     NUM_OBJECT_TYPES
97 };
98
99 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
100
101 FcBool
102 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
103 {
104     FcObjectTypeList    *l;
105
106     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
107     if (!l)
108         return FcFalse;
109     FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
110     l->types = types;
111     l->ntypes = ntypes;
112     l->next = _FcObjectTypes;
113     l->basic_offset = next_basic_offset;
114     next_basic_offset += ntypes;
115     _FcObjectTypes = l;
116     return FcTrue;
117 }
118
119 static FcBool
120 FcNameUnregisterObjectTypesFree (const FcObjectType *types, int ntypes, 
121                                  FcBool do_free)
122 {
123     const FcObjectTypeList      *l, **prev;
124
125     for (prev = &_FcObjectTypes; 
126          (l = *prev); 
127          prev = (const FcObjectTypeList **) &(l->next))
128     {
129         if (l->types == types && l->ntypes == ntypes)
130         {
131             *prev = l->next;
132             if (do_free) {
133                 FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
134                 free ((void *) l);
135             }
136             return FcTrue;
137         }
138     }
139     return FcFalse;
140 }
141
142 FcBool
143 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
144 {
145     return FcNameUnregisterObjectTypesFree (types, ntypes, FcTrue);
146 }
147
148 const FcObjectType *
149 FcNameGetObjectType (const char *object)
150 {
151     int                     i;
152     const FcObjectTypeList  *l;
153     const FcObjectType      *t;
154     
155     for (l = _FcObjectTypes; l; l = l->next)
156     {
157         for (i = 0; i < l->ntypes; i++)
158         {
159             t = &l->types[i];
160             if (!strcmp (object, t->object))
161                 return t;
162         }
163     }
164     return 0;
165 }
166
167 #define OBJECT_HASH_SIZE    31
168 struct objectBucket {
169     struct objectBucket *next;
170     FcChar32            hash;
171     int                 id;
172 };
173 static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
174
175 /* Design constraint: biggest_known_ntypes must never change
176  * after any call to FcNameRegisterObjectTypes. */
177 static const FcObjectType *biggest_known_types = _FcBaseObjectTypes; 
178 static FcBool allocated_biggest_known_types;
179 static int biggest_known_ntypes = NUM_OBJECT_TYPES;
180 static int biggest_known_count = 0;
181 static char * biggest_ptr;
182
183
184 static FcObjectPtr
185 FcObjectToPtrLookup (const char * object)
186 {
187     FcObjectPtr             i = 0, n;
188     const FcObjectTypeList  *l;
189     FcObjectType            *t = _FcUserObjectNames;
190
191     for (l = _FcObjectTypes; l; l = l->next)
192     {
193         for (i = 0; i < l->ntypes; i++)
194         {
195             t = (FcObjectType *)&l->types[i];
196             if (!strcmp (object, t->object))
197             {
198                 if (l == (FcObjectTypeList*)_FcUserObjectNames)
199                     return -i;
200                 else
201                     return l->basic_offset + i;
202             }
203         }
204     }
205
206     /* We didn't match.  Look for the correct FcObjectTypeList
207      * to replace it in-place. */
208     for (l = _FcObjectTypes; l; l = l->next)
209     {
210         if (l->types == _FcUserObjectNames)
211             break;
212     }
213
214     if (!_FcUserObjectNames || 
215         (l && l->types == _FcUserObjectNames && user_obj_alloc < l->ntypes))
216     {
217         int nt = user_obj_alloc + 4;
218         FcObjectType * t = realloc (_FcUserObjectNames, 
219                                     nt * sizeof (FcObjectType));
220         if (!t)
221             return 0;
222         _FcUserObjectNames = t;
223         user_obj_alloc = nt;
224     }
225
226     if (l && l->types == _FcUserObjectNames)
227     {
228         n = l->ntypes;
229         FcNameUnregisterObjectTypesFree (l->types, l->ntypes, FcFalse);
230     }
231     else
232         n = 0;
233
234     FcNameRegisterObjectTypes (_FcUserObjectNames, n+1);
235
236     for (l = _FcObjectTypes; l; l = l->next)
237     {
238         if (l->types == _FcUserObjectNames)
239         {
240             t = (FcObjectType *)l->types;
241             break;
242         }
243     }
244
245     if (!t)
246         return 0;
247
248     t[n].object = object;
249     t[n].type = FcTypeVoid;
250
251     return -n;
252 }
253
254 FcObjectPtr
255 FcObjectToPtr (const char * name)
256 {
257     FcChar32            hash = FcStringHash ((const FcChar8 *) name);
258     struct objectBucket **p;
259     struct objectBucket *b;
260     int                 size;
261
262     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)
263 )
264         if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
265             return b->id;
266     size = sizeof (struct objectBucket) + strlen (name) + 1;
267     /* workaround glibc bug which reads strlen in groups of 4 */
268     b = malloc (size + sizeof (int));
269     FcMemAlloc (FC_MEM_STATICSTR, size + sizeof(int));
270     if (!b)
271         return 0;
272     b->next = 0;
273     b->hash = hash;
274     b->id = FcObjectToPtrLookup (name);
275     strcpy ((char *) (b + 1), name);
276     *p = b;
277     return b->id;
278 }
279
280 void
281 FcObjectStaticNameFini (void)
282 {
283     int i, size;
284     struct objectBucket *b, *next;
285     char *name;
286
287     for (i = 0; i < OBJECT_HASH_SIZE; i++)
288     {
289         for (b = FcObjectBuckets[i]; b; b = next)
290         {
291             next = b->next;
292             name = (char *) (b + 1);
293             size = sizeof (struct objectBucket) + strlen (name) + 1;
294             FcMemFree (FC_MEM_STATICSTR, size);
295             free (b);
296         }
297         FcObjectBuckets[i] = 0;
298     }
299 }
300
301 const char *
302 FcObjectPtrU (FcObjectPtr si)
303 {
304     const FcObjectTypeList  *l;
305     int i, j;
306
307     if (si > 0)
308     {
309         if (si < biggest_known_ntypes)
310             return biggest_known_types[si].object;
311
312         j = 0;
313         for (l = _FcObjectTypes; l; l = l->next)
314             for (i = 0; i < l->ntypes; i++, j++)
315                 if (j == si)
316                     return l->types[i].object;
317     }
318
319     return _FcUserObjectNames[-si].object;
320 }
321
322 int
323 FcObjectNeededBytes ()
324 {
325     int num = 0, i;
326     for (i = 0; i < biggest_known_ntypes; i++)
327     {
328         const char * t = biggest_known_types[i].object;
329         num = num + strlen(t) + 1;
330     }
331     biggest_known_count = num;
332     return num + sizeof(int);
333 }
334
335 void *
336 FcObjectDistributeBytes (FcCache * metadata, void * block_ptr)
337 {
338     *(int *)block_ptr = biggest_known_ntypes;
339     block_ptr = (int *) block_ptr + 1;
340     biggest_ptr = block_ptr;
341     block_ptr = (char *) block_ptr + biggest_known_count;
342     return block_ptr;
343 }
344
345 void
346 FcObjectSerialize ()
347 {
348     int i;
349     for (i = 0; i < biggest_known_ntypes; i++)
350     {
351         const char * t = biggest_known_types[i].object;
352         strcpy (biggest_ptr, t);
353         biggest_ptr = biggest_ptr + strlen(t) + 1;
354     }
355 }
356
357 void *
358 FcObjectUnserialize (FcCache metadata, void *block_ptr)
359 {
360     int new_biggest;
361     new_biggest = *(int *)block_ptr;
362     block_ptr = (int *) block_ptr + 1;
363     if (biggest_known_ntypes < new_biggest)
364     {
365         int i;
366         char * bp = (char *)block_ptr;
367         FcObjectType * bn;
368         FcObjectTypeList * bnl;
369
370         bn = malloc (sizeof (const FcObjectType) * (new_biggest + 1));
371         if (!bn)
372             return 0;
373
374         bnl = malloc (sizeof (FcObjectTypeList));
375         if (!bnl)
376         {
377             free (bn);
378             return 0;
379         }
380
381         for (i = 0; i < new_biggest; i++)
382         {
383             const FcObjectType * t = FcNameGetObjectType(bp);
384             if (t)
385                 bn[i].type = t->type;
386             else
387                 bn[i].type = FcTypeVoid;
388             bn[i].object = bp;
389             bp = bp + strlen(bp) + 1;
390         }
391
392         FcNameUnregisterObjectTypesFree (biggest_known_types, biggest_known_ntypes, FcFalse);
393         if (allocated_biggest_known_types)
394         {
395             free ((FcObjectTypeList *)biggest_known_types);
396         }
397         else
398             allocated_biggest_known_types = FcTrue;
399
400         FcNameRegisterObjectTypes (bn, new_biggest);
401         biggest_known_ntypes = new_biggest;
402         biggest_known_types = (const FcObjectType *)bn;
403     }
404     block_ptr = (char *) block_ptr + biggest_known_count;
405     return block_ptr;
406 }
407
408 int
409 FcObjectPtrCompare (const FcObjectPtr a, const FcObjectPtr b)
410 {
411     return a - b;
412 }
413
414 static const FcConstant _FcBaseConstants[] = {
415     { (FcChar8 *) "thin",           "weight",   FC_WEIGHT_THIN, },
416     { (FcChar8 *) "extralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
417     { (FcChar8 *) "ultralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
418     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
419     { (FcChar8 *) "book",           "weight",   FC_WEIGHT_BOOK, },
420     { (FcChar8 *) "regular",        "weight",   FC_WEIGHT_REGULAR, },
421     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
422     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
423     { (FcChar8 *) "semibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
424     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
425     { (FcChar8 *) "extrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
426     { (FcChar8 *) "ultrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
427     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
428
429     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
430     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
431     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
432
433     { (FcChar8 *) "ultracondensed", "width",    FC_WIDTH_ULTRACONDENSED },
434     { (FcChar8 *) "extracondensed", "width",    FC_WIDTH_EXTRACONDENSED },
435     { (FcChar8 *) "condensed",      "width",    FC_WIDTH_CONDENSED },
436     { (FcChar8 *) "semicondensed", "width",     FC_WIDTH_SEMICONDENSED },
437     { (FcChar8 *) "normal",         "width",    FC_WIDTH_NORMAL },
438     { (FcChar8 *) "semiexpanded",   "width",    FC_WIDTH_SEMIEXPANDED },
439     { (FcChar8 *) "expanded",       "width",    FC_WIDTH_EXPANDED },
440     { (FcChar8 *) "extraexpanded",  "width",    FC_WIDTH_EXTRAEXPANDED },
441     { (FcChar8 *) "ultraexpanded",  "width",    FC_WIDTH_ULTRAEXPANDED },
442     
443     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
444     { (FcChar8 *) "dual",           "spacing",  FC_DUAL, },
445     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
446     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
447
448     { (FcChar8 *) "unknown",        "rgba",         FC_RGBA_UNKNOWN },
449     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
450     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
451     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
452     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
453     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
454
455     { (FcChar8 *) "hintnone",       "hintstyle",   FC_HINT_NONE },
456     { (FcChar8 *) "hintslight",     "hintstyle",   FC_HINT_SLIGHT },
457     { (FcChar8 *) "hintmedium",     "hintstyle",   FC_HINT_MEDIUM },
458     { (FcChar8 *) "hintfull",       "hintstyle",   FC_HINT_FULL },
459 };
460
461 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
462
463 typedef struct _FcConstantList FcConstantList;
464
465 struct _FcConstantList {
466     const FcConstantList    *next;
467     const FcConstant        *consts;
468     int                     nconsts;
469 };
470
471 static const FcConstantList _FcBaseConstantList = {
472     0,
473     _FcBaseConstants,
474     NUM_FC_CONSTANTS
475 };
476
477 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
478
479 FcBool
480 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
481 {
482     FcConstantList      *l;
483
484     l = (FcConstantList *) malloc (sizeof (FcConstantList));
485     if (!l)
486         return FcFalse;
487     FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
488     l->consts = consts;
489     l->nconsts = nconsts;
490     l->next = _FcConstants;
491     _FcConstants = l;
492     return FcTrue;
493 }
494
495 FcBool
496 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
497 {
498     const FcConstantList        *l, **prev;
499
500     for (prev = &_FcConstants; 
501          (l = *prev); 
502          prev = (const FcConstantList **) &(l->next))
503     {
504         if (l->consts == consts && l->nconsts == nconsts)
505         {
506             *prev = l->next;
507             FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
508             free ((void *) l);
509             return FcTrue;
510         }
511     }
512     return FcFalse;
513 }
514
515 const FcConstant *
516 FcNameGetConstant (FcChar8 *string)
517 {
518     const FcConstantList    *l;
519     int                     i;
520
521     for (l = _FcConstants; l; l = l->next)
522     {
523         for (i = 0; i < l->nconsts; i++)
524             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
525                 return &l->consts[i];
526     }
527     return 0;
528 }
529
530 FcBool
531 FcNameConstant (FcChar8 *string, int *result)
532 {
533     const FcConstant    *c;
534
535     if ((c = FcNameGetConstant(string)))
536     {
537         *result = c->value;
538         return FcTrue;
539     }
540     return FcFalse;
541 }
542
543 FcBool
544 FcNameBool (const FcChar8 *v, FcBool *result)
545 {
546     char    c0, c1;
547
548     c0 = *v;
549     c0 = FcToLower (c0);
550     if (c0 == 't' || c0 == 'y' || c0 == '1')
551     {
552         *result = FcTrue;
553         return FcTrue;
554     }
555     if (c0 == 'f' || c0 == 'n' || c0 == '0')
556     {
557         *result = FcFalse;
558         return FcTrue;
559     }
560     if (c0 == 'o')
561     {
562         c1 = v[1];
563         c1 = FcToLower (c1);
564         if (c1 == 'n')
565         {
566             *result = FcTrue;
567             return FcTrue;
568         }
569         if (c1 == 'f')
570         {
571             *result = FcFalse;
572             return FcTrue;
573         }
574     }
575     return FcFalse;
576 }
577
578 static FcValue
579 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
580 {
581     FcValue     v;
582
583     v.type = type;
584     switch (v.type) {
585     case FcTypeInteger:
586         if (!FcNameConstant (string, &v.u.i))
587             v.u.i = atoi ((char *) string);
588         break;
589     case FcTypeString:
590         v.u.s = FcStrStaticName(string);
591         break;
592     case FcTypeBool:
593         if (!FcNameBool (string, &v.u.b))
594             v.u.b = FcFalse;
595         break;
596     case FcTypeDouble:
597         v.u.d = strtod ((char *) string, 0);
598         break;
599     case FcTypeMatrix:
600         v.u.m = m;
601         sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
602         break;
603     case FcTypeCharSet:
604         v.u.c = FcNameParseCharSet (string);
605         break;
606     case FcTypeLangSet:
607         v.u.l = FcNameParseLangSet (string);
608         break;
609     default:
610         break;
611     }
612     return v;
613 }
614
615 static const FcChar8 *
616 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
617 {
618     FcChar8    c;
619     
620     while ((c = *cur))
621     {
622         if (c == '\\')
623         {
624             ++cur;
625             if (!(c = *cur))
626                 break;
627         }
628         else if (strchr (delim, c))
629             break;
630         ++cur;
631         *save++ = c;
632     }
633     *save = 0;
634     *last = *cur;
635     if (*cur)
636         cur++;
637     return cur;
638 }
639
640 FcPattern *
641 FcNameParse (const FcChar8 *name)
642 {
643     FcChar8             *save;
644     FcPattern           *pat;
645     double              d;
646     FcChar8             *e;
647     FcChar8             delim;
648     FcValue             v;
649     FcMatrix            m;
650     const FcObjectType  *t;
651     const FcConstant    *c;
652
653     /* freed below */
654     save = malloc (strlen ((char *) name) + 1);
655     if (!save)
656         goto bail0;
657     pat = FcPatternCreate ();
658     if (!pat)
659         goto bail1;
660
661     for (;;)
662     {
663         name = FcNameFindNext (name, "-,:", save, &delim);
664         if (save[0])
665         {
666             if (!FcPatternAddString (pat, FC_FAMILY, save))
667                 goto bail2;
668         }
669         if (delim != ',')
670             break;
671     }
672     if (delim == '-')
673     {
674         for (;;)
675         {
676             name = FcNameFindNext (name, "-,:", save, &delim);
677             d = strtod ((char *) save, (char **) &e);
678             if (e != save)
679             {
680                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
681                     goto bail2;
682             }
683             if (delim != ',')
684                 break;
685         }
686     }
687     while (delim == ':')
688     {
689         name = FcNameFindNext (name, "=_:", save, &delim);
690         if (save[0])
691         {
692             if (delim == '=' || delim == '_')
693             {
694                 t = FcNameGetObjectType ((char *) save);
695                 for (;;)
696                 {
697                     name = FcNameFindNext (name, ":,", save, &delim);
698                     if (t)
699                     {
700                         v = FcNameConvert (t->type, save, &m);
701                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
702                         {
703                             switch (v.type) {
704                             case FcTypeCharSet:
705                                 FcCharSetDestroy ((FcCharSet *) v.u.c);
706                                 break;
707                             case FcTypeLangSet:
708                                 FcLangSetDestroy ((FcLangSet *) v.u.l);
709                                 break;
710                             default:
711                                 break;
712                             }
713                             goto bail2;
714                         }
715                         switch (v.type) {
716                         case FcTypeCharSet:
717                             FcCharSetDestroy ((FcCharSet *) v.u.c);
718                             break;
719                         case FcTypeLangSet:
720                             FcLangSetDestroy ((FcLangSet *) v.u.l);
721                             break;
722                         default:
723                             break;
724                         }
725                     }
726                     if (delim != ',')
727                         break;
728                 }
729             }
730             else
731             {
732                 if ((c = FcNameGetConstant (save)))
733                 {
734                     if (!FcPatternAddInteger (pat, c->object, c->value))
735                         goto bail2;
736                 }
737             }
738         }
739     }
740
741     free (save);
742     return pat;
743
744 bail2:
745     FcPatternDestroy (pat);
746 bail1:
747     free (save);
748 bail0:
749     return 0;
750 }
751 static FcBool
752 FcNameUnparseString (FcStrBuf       *buf, 
753                      const FcChar8  *string,
754                      const FcChar8  *escape)
755 {
756     FcChar8 c;
757     while ((c = *string++))
758     {
759         if (escape && strchr ((char *) escape, (char) c))
760         {
761             if (!FcStrBufChar (buf, escape[0]))
762                 return FcFalse;
763         }
764         if (!FcStrBufChar (buf, c))
765             return FcFalse;
766     }
767     return FcTrue;
768 }
769
770 static FcBool
771 FcNameUnparseValue (FcStrBuf    *buf,
772                     int         bank,
773                     FcValue     *v0,
774                     FcChar8     *escape)
775 {
776     FcChar8     temp[1024];
777     FcValue v = FcValueCanonicalize(v0);
778     
779     switch (v.type) {
780     case FcTypeVoid:
781         return FcTrue;
782     case FcTypeInteger:
783         sprintf ((char *) temp, "%d", v.u.i);
784         return FcNameUnparseString (buf, temp, 0);
785     case FcTypeDouble:
786         sprintf ((char *) temp, "%g", v.u.d);
787         return FcNameUnparseString (buf, temp, 0);
788     case FcTypeString:
789         return FcNameUnparseString (buf, v.u.s, escape);
790     case FcTypeBool:
791         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
792     case FcTypeMatrix:
793         sprintf ((char *) temp, "%g %g %g %g", 
794                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
795         return FcNameUnparseString (buf, temp, 0);
796     case FcTypeCharSet:
797         return FcNameUnparseCharSet (buf, v.u.c);
798     case FcTypeLangSet:
799         return FcNameUnparseLangSet (buf, v.u.l);
800     case FcTypeFTFace:
801         return FcTrue;
802     }
803     return FcFalse;
804 }
805
806 static FcBool
807 FcNameUnparseValueList (FcStrBuf        *buf,
808                         FcValueListPtr  v,
809                         FcChar8         *escape)
810 {
811     while (FcValueListPtrU(v))
812     {
813         if (!FcNameUnparseValue (buf, v.bank, &FcValueListPtrU(v)->value, escape))
814             return FcFalse;
815         if (FcValueListPtrU(v = FcValueListPtrU(v)->next))
816             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
817                 return FcFalse;
818     }
819     return FcTrue;
820 }
821
822 #define FC_ESCAPE_FIXED    "\\-:,"
823 #define FC_ESCAPE_VARIABLE "\\=_:,"
824
825 FcChar8 *
826 FcNameUnparse (FcPattern *pat)
827 {
828     return FcNameUnparseEscaped (pat, FcTrue);
829 }
830
831 FcChar8 *
832 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
833 {
834     FcStrBuf                buf;
835     FcChar8                 buf_static[8192];
836     int                     i;
837     FcPatternElt            *e;
838     const FcObjectTypeList  *l;
839     const FcObjectType      *o;
840
841     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
842     e = FcPatternFindElt (pat, FC_FAMILY);
843     if (e)
844     {
845         if (!FcNameUnparseValueList (&buf, e->values, escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
846             goto bail0;
847     }
848     e = FcPatternFindElt (pat, FC_SIZE);
849     if (e)
850     {
851         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
852             goto bail0;
853         if (!FcNameUnparseValueList (&buf, e->values, escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
854             goto bail0;
855     }
856     for (l = _FcObjectTypes; l; l = l->next)
857     {
858         for (i = 0; i < l->ntypes; i++)
859         {
860             o = &l->types[i];
861             if (!strcmp (o->object, FC_FAMILY) || 
862                 !strcmp (o->object, FC_SIZE) ||
863                 !strcmp (o->object, FC_FILE))
864                 continue;
865             
866             e = FcPatternFindElt (pat, o->object);
867             if (e)
868             {
869                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
870                     goto bail0;
871                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
872                     goto bail0;
873                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
874                     goto bail0;
875                 if (!FcNameUnparseValueList (&buf, e->values, escape ? 
876                                              (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
877                     goto bail0;
878             }
879         }
880     }
881     return FcStrBufDone (&buf);
882 bail0:
883     FcStrBufDestroy (&buf);
884     return 0;
885 }