Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2000 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of the author(s) not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  The authors make no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 #include "fcint.h"
     24 #include "fcftint.h"
     25 
     26 /* Objects MT-safe for readonly access. */
     27 
     28 FcPattern *
     29 FcPatternCreate (void)
     30 {
     31     FcPattern	*p;
     32 
     33     p = (FcPattern *) malloc (sizeof (FcPattern));
     34     if (!p)
     35 	return 0;
     36     memset (p, 0, sizeof (FcPattern));
     37     p->num = 0;
     38     p->size = 0;
     39     p->elts_offset = FcPtrToOffset (p, NULL);
     40     FcRefInit (&p->ref, 1);
     41     return p;
     42 }
     43 
     44 void
     45 FcValueDestroy (FcValue v)
     46 {
     47     switch ((int) v.type) {
     48     case FcTypeString:
     49 	FcFree (v.u.s);
     50 	break;
     51     case FcTypeMatrix:
     52 	FcMatrixFree ((FcMatrix *) v.u.m);
     53 	break;
     54     case FcTypeCharSet:
     55 	FcCharSetDestroy ((FcCharSet *) v.u.c);
     56 	break;
     57     case FcTypeLangSet:
     58 	FcLangSetDestroy ((FcLangSet *) v.u.l);
     59 	break;
     60     case FcTypeRange:
     61 	FcRangeDestroy ((FcRange *) v.u.r);
     62 	break;
     63     default:
     64 	break;
     65     }
     66 }
     67 
     68 FcValue
     69 FcValueCanonicalize (const FcValue *v)
     70 {
     71     FcValue new;
     72 
     73     switch ((int) v->type)
     74     {
     75     case FcTypeString:
     76 	new.u.s = FcValueString(v);
     77 	new.type = FcTypeString;
     78 	break;
     79     case FcTypeCharSet:
     80 	new.u.c = FcValueCharSet(v);
     81 	new.type = FcTypeCharSet;
     82 	break;
     83     case FcTypeLangSet:
     84 	new.u.l = FcValueLangSet(v);
     85 	new.type = FcTypeLangSet;
     86 	break;
     87     case FcTypeRange:
     88 	new.u.r = FcValueRange(v);
     89 	new.type = FcTypeRange;
     90 	break;
     91     default:
     92 	new = *v;
     93 	break;
     94     }
     95     return new;
     96 }
     97 
     98 FcValue
     99 FcValueSave (FcValue v)
    100 {
    101     switch ((int) v.type) {
    102     case FcTypeString:
    103 	v.u.s = FcStrdup (v.u.s);
    104 	if (!v.u.s)
    105 	    v.type = FcTypeVoid;
    106 	break;
    107     case FcTypeMatrix:
    108 	v.u.m = FcMatrixCopy (v.u.m);
    109 	if (!v.u.m)
    110 	    v.type = FcTypeVoid;
    111 	break;
    112     case FcTypeCharSet:
    113 	v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
    114 	if (!v.u.c)
    115 	    v.type = FcTypeVoid;
    116 	break;
    117     case FcTypeLangSet:
    118 	v.u.l = FcLangSetCopy (v.u.l);
    119 	if (!v.u.l)
    120 	    v.type = FcTypeVoid;
    121 	break;
    122     case FcTypeRange:
    123 	v.u.r = FcRangeCopy (v.u.r);
    124 	if (!v.u.r)
    125 	    v.type = FcTypeVoid;
    126 	break;
    127     default:
    128 	break;
    129     }
    130     return v;
    131 }
    132 
    133 FcValueListPtr
    134 FcValueListCreate (void)
    135 {
    136     return calloc (1, sizeof (FcValueList));
    137 }
    138 
    139 void
    140 FcValueListDestroy (FcValueListPtr l)
    141 {
    142     FcValueListPtr next;
    143     for (; l; l = next)
    144     {
    145 	FcValueDestroy (l->value);
    146 	next = FcValueListNext(l);
    147 	free(l);
    148     }
    149 }
    150 
    151 FcValueListPtr
    152 FcValueListPrepend (FcValueListPtr vallist,
    153 		    FcValue        value,
    154 		    FcValueBinding binding)
    155 {
    156     FcValueListPtr new;
    157 
    158     if (value.type == FcTypeVoid)
    159 	return vallist;
    160     new = FcValueListCreate ();
    161     if (!new)
    162 	return vallist;
    163 
    164     new->value = FcValueSave (value);
    165     new->binding = binding;
    166     new->next = vallist;
    167 
    168     return new;
    169 }
    170 
    171 FcValueListPtr
    172 FcValueListAppend (FcValueListPtr vallist,
    173 		   FcValue        value,
    174 		   FcValueBinding binding)
    175 {
    176     FcValueListPtr new, last;
    177 
    178     if (value.type == FcTypeVoid)
    179 	return vallist;
    180     new = FcValueListCreate ();
    181     if (!new)
    182 	return vallist;
    183 
    184     new->value = FcValueSave (value);
    185     new->binding = binding;
    186     new->next = NULL;
    187 
    188     if (vallist)
    189     {
    190 	for (last = vallist; FcValueListNext (last); last = FcValueListNext (last));
    191 
    192 	last->next = new;
    193     }
    194     else
    195 	vallist = new;
    196 
    197     return vallist;
    198 }
    199 
    200 FcValueListPtr
    201 FcValueListDuplicate(FcValueListPtr orig)
    202 {
    203     FcValueListPtr new = NULL, l, t = NULL;
    204     FcValue v;
    205 
    206     for (l = orig; l != NULL; l = FcValueListNext (l))
    207     {
    208 	if (!new)
    209 	{
    210 	    t = new = FcValueListCreate();
    211 	}
    212 	else
    213 	{
    214 	    t->next = FcValueListCreate();
    215 	    t = FcValueListNext (t);
    216 	}
    217 	v = FcValueCanonicalize (&l->value);
    218 	t->value = FcValueSave (v);
    219 	t->binding = l->binding;
    220 	t->next = NULL;
    221     }
    222 
    223     return new;
    224 }
    225 
    226 FcBool
    227 FcValueEqual (FcValue va, FcValue vb)
    228 {
    229     if (va.type != vb.type)
    230     {
    231 	if (va.type == FcTypeInteger)
    232 	{
    233 	    va.type = FcTypeDouble;
    234 	    va.u.d = va.u.i;
    235 	}
    236 	if (vb.type == FcTypeInteger)
    237 	{
    238 	    vb.type = FcTypeDouble;
    239 	    vb.u.d = vb.u.i;
    240 	}
    241 	if (va.type != vb.type)
    242 	    return FcFalse;
    243     }
    244     switch (va.type) {
    245     case FcTypeUnknown:
    246 	return FcFalse;	/* don't know how to compare this object */
    247     case FcTypeVoid:
    248 	return FcTrue;
    249     case FcTypeInteger:
    250 	return va.u.i == vb.u.i;
    251     case FcTypeDouble:
    252 	return va.u.d == vb.u.d;
    253     case FcTypeString:
    254 	return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
    255     case FcTypeBool:
    256 	return va.u.b == vb.u.b;
    257     case FcTypeMatrix:
    258 	return FcMatrixEqual (va.u.m, vb.u.m);
    259     case FcTypeCharSet:
    260 	return FcCharSetEqual (va.u.c, vb.u.c);
    261     case FcTypeFTFace:
    262 	return va.u.f == vb.u.f;
    263     case FcTypeLangSet:
    264 	return FcLangSetEqual (va.u.l, vb.u.l);
    265     case FcTypeRange:
    266 	return FcRangeIsInRange (va.u.r, vb.u.r);
    267     }
    268     return FcFalse;
    269 }
    270 
    271 static FcChar32
    272 FcDoubleHash (double d)
    273 {
    274     if (d < 0)
    275 	d = -d;
    276     if (d > 0xffffffff)
    277 	d = 0xffffffff;
    278     return (FcChar32) d;
    279 }
    280 
    281 FcChar32
    282 FcStringHash (const FcChar8 *s)
    283 {
    284     FcChar8	c;
    285     FcChar32	h = 0;
    286 
    287     if (s)
    288 	while ((c = *s++))
    289 	    h = ((h << 1) | (h >> 31)) ^ c;
    290     return h;
    291 }
    292 
    293 static FcChar32
    294 FcValueHash (const FcValue *v)
    295 {
    296     switch (v->type) {
    297     case FcTypeUnknown:
    298     case FcTypeVoid:
    299 	return 0;
    300     case FcTypeInteger:
    301 	return (FcChar32) v->u.i;
    302     case FcTypeDouble:
    303 	return FcDoubleHash (v->u.d);
    304     case FcTypeString:
    305 	return FcStringHash (FcValueString(v));
    306     case FcTypeBool:
    307 	return (FcChar32) v->u.b;
    308     case FcTypeMatrix:
    309 	return (FcDoubleHash (v->u.m->xx) ^
    310 		FcDoubleHash (v->u.m->xy) ^
    311 		FcDoubleHash (v->u.m->yx) ^
    312 		FcDoubleHash (v->u.m->yy));
    313     case FcTypeCharSet:
    314 	return (FcChar32) FcValueCharSet(v)->num;
    315     case FcTypeFTFace:
    316 	return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
    317 	       FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
    318     case FcTypeLangSet:
    319 	return FcLangSetHash (FcValueLangSet(v));
    320     case FcTypeRange:
    321 	return FcRangeHash (FcValueRange (v));
    322     }
    323     return 0;
    324 }
    325 
    326 static FcBool
    327 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
    328 {
    329     if (la == lb)
    330 	return FcTrue;
    331 
    332     while (la && lb)
    333     {
    334 	if (!FcValueEqual (la->value, lb->value))
    335 	    return FcFalse;
    336 	la = FcValueListNext(la);
    337 	lb = FcValueListNext(lb);
    338     }
    339     if (la || lb)
    340 	return FcFalse;
    341     return FcTrue;
    342 }
    343 
    344 static FcChar32
    345 FcValueListHash (FcValueListPtr l)
    346 {
    347     FcChar32	hash = 0;
    348 
    349     for (; l; l = FcValueListNext(l))
    350     {
    351 	hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
    352     }
    353     return hash;
    354 }
    355 
    356 static void *
    357 FcPatternGetCacheObject (FcPattern *p)
    358 {
    359   /* We use a value to find the cache, instead of the FcPattern object
    360    * because the pattern itself may be a cache allocation if we rewrote the path,
    361    * so the p may not be in the cached region. */
    362   return FcPatternEltValues(&FcPatternElts (p)[0]);
    363 }
    364 
    365 FcPattern *
    366 FcPatternCacheRewriteFile (const FcPattern *p,
    367                            FcCache *cache,
    368                            const FcChar8 *relocated_font_file)
    369 {
    370     FcPatternElt *elts = FcPatternElts (p);
    371     size_t i,j;
    372     FcChar8 *data;
    373     FcPattern *new_p;
    374     FcPatternElt *new_elts;
    375     FcValueList *new_value_list;
    376     size_t new_path_len = strlen ((char *)relocated_font_file);
    377     FcChar8 *new_path;
    378 
    379     /* Allocate space for the patter, the PatternElt headers and
    380      * the FC_FILE FcValueList and path that will be freed with the
    381      * cache */
    382     data = FcCacheAllocate (cache,
    383 			    sizeof (FcPattern) +
    384 			    p->num * sizeof (FcPatternElt) +
    385 			    sizeof (FcValueList) +
    386 			    new_path_len + 1);
    387 
    388     new_p = (FcPattern *)data;
    389     data += sizeof (FcPattern);
    390     new_elts = (FcPatternElt *)(data);
    391     data += p->num * sizeof (FcPatternElt);
    392     new_value_list = (FcValueList *)data;
    393     data += sizeof (FcValueList);
    394     new_path = data;
    395 
    396     *new_p = *p;
    397     new_p->elts_offset = FcPtrToOffset (new_p, new_elts);
    398 
    399     /* Copy all but the FILE values from the cache */
    400     for (i = 0, j = 0; i < p->num; i++)
    401     {
    402 	FcPatternElt *elt = &elts[i];
    403 	new_elts[j].object = elt->object;
    404 	if (elt->object != FC_FILE_OBJECT)
    405 	    new_elts[j++].values = FcPatternEltValues(elt);
    406 	else
    407 	    new_elts[j++].values = new_value_list;
    408     }
    409 
    410     new_value_list->next = NULL;
    411     new_value_list->value.type = FcTypeString;
    412     new_value_list->value.u.s = new_path;
    413     new_value_list->binding = FcValueBindingWeak;
    414 
    415     /* Add rewritten path at the end */
    416     strcpy ((char *)new_path, (char *)relocated_font_file);
    417 
    418     return new_p;
    419 }
    420 
    421 void
    422 FcPatternDestroy (FcPattern *p)
    423 {
    424     int		    i;
    425     FcPatternElt    *elts;
    426 
    427     if (!p)
    428 	return;
    429 
    430     if (FcRefIsConst (&p->ref))
    431     {
    432 	FcCacheObjectDereference (FcPatternGetCacheObject(p));
    433 	return;
    434     }
    435 
    436     if (FcRefDec (&p->ref) != 1)
    437 	return;
    438 
    439     elts = FcPatternElts (p);
    440     for (i = 0; i < FcPatternObjectCount (p); i++)
    441 	FcValueListDestroy (FcPatternEltValues(&elts[i]));
    442 
    443     free (elts);
    444     free (p);
    445 }
    446 
    447 int
    448 FcPatternObjectCount (const FcPattern *pat)
    449 {
    450     if (pat)
    451 	return pat->num;
    452 
    453     return 0;
    454 }
    455 
    456 
    457 static int
    458 FcPatternObjectPosition (const FcPattern *p, FcObject object)
    459 {
    460     int	    low, high, mid, c;
    461     FcPatternElt    *elts = FcPatternElts(p);
    462 
    463     low = 0;
    464     high = FcPatternObjectCount (p) - 1;
    465     c = 1;
    466     mid = 0;
    467     while (low <= high)
    468     {
    469 	mid = (low + high) >> 1;
    470 	c = elts[mid].object - object;
    471 	if (c == 0)
    472 	    return mid;
    473 	if (c < 0)
    474 	    low = mid + 1;
    475 	else
    476 	    high = mid - 1;
    477     }
    478     if (c < 0)
    479 	mid++;
    480     return -(mid + 1);
    481 }
    482 
    483 int
    484 FcPatternPosition (const FcPattern *p, const char *object)
    485 {
    486     return FcPatternObjectPosition (p, FcObjectFromName (object));
    487 }
    488 
    489 FcPatternElt *
    490 FcPatternObjectFindElt (const FcPattern *p, FcObject object)
    491 {
    492     int	    i = FcPatternObjectPosition (p, object);
    493     if (i < 0)
    494 	return 0;
    495     return &FcPatternElts(p)[i];
    496 }
    497 
    498 FcPatternElt *
    499 FcPatternObjectInsertElt (FcPattern *p, FcObject object)
    500 {
    501     int		    i;
    502     FcPatternElt   *e;
    503 
    504     i = FcPatternObjectPosition (p, object);
    505     if (i < 0)
    506     {
    507 	i = -i - 1;
    508 
    509 	/* reallocate array */
    510 	if (FcPatternObjectCount (p) + 1 >= p->size)
    511 	{
    512 	    int s = p->size + 16;
    513 	    if (p->size)
    514 	    {
    515 		FcPatternElt *e0 = FcPatternElts(p);
    516 		e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
    517 		if (!e) /* maybe it was mmapped */
    518 		{
    519 		    e = malloc(s * sizeof (FcPatternElt));
    520 		    if (e)
    521 			memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt));
    522 		}
    523 	    }
    524 	    else
    525 		e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
    526 	    if (!e)
    527 		return FcFalse;
    528 	    p->elts_offset = FcPtrToOffset (p, e);
    529 	    while (p->size < s)
    530 	    {
    531 		e[p->size].object = 0;
    532 		e[p->size].values = NULL;
    533 		p->size++;
    534 	    }
    535 	}
    536 
    537 	e = FcPatternElts(p);
    538 	/* move elts up */
    539 	memmove (e + i + 1,
    540 		 e + i,
    541 		 sizeof (FcPatternElt) *
    542 		 (FcPatternObjectCount (p) - i));
    543 
    544 	/* bump count */
    545 	p->num++;
    546 
    547 	e[i].object = object;
    548 	e[i].values = NULL;
    549     }
    550 
    551     return FcPatternElts(p) + i;
    552 }
    553 
    554 FcBool
    555 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
    556 {
    557     FcPatternIter ia, ib;
    558 
    559     if (pa == pb)
    560 	return FcTrue;
    561 
    562     if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb))
    563 	return FcFalse;
    564     FcPatternIterStart (pa, &ia);
    565     FcPatternIterStart (pb, &ib);
    566     do {
    567 	FcBool ra, rb;
    568 
    569 	if (!FcPatternIterEqual (pa, &ia, pb, &ib))
    570 	    return FcFalse;
    571 	ra = FcPatternIterNext (pa, &ia);
    572 	rb = FcPatternIterNext (pb, &ib);
    573 	if (!ra && !rb)
    574 	    break;
    575     } while (1);
    576 
    577     return FcTrue;
    578 }
    579 
    580 FcChar32
    581 FcPatternHash (const FcPattern *p)
    582 {
    583     int		i;
    584     FcChar32	h = 0;
    585     FcPatternElt    *pe = FcPatternElts(p);
    586 
    587     for (i = 0; i < FcPatternObjectCount (p); i++)
    588     {
    589 	h = (((h << 1) | (h >> 31)) ^
    590 	     pe[i].object ^
    591 	     FcValueListHash (FcPatternEltValues(&pe[i])));
    592     }
    593     return h;
    594 }
    595 
    596 FcBool
    597 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
    598 {
    599     FcPatternElt    *ea, *eb;
    600     int		    i;
    601 
    602     for (i = 0; i < os->nobject; i++)
    603     {
    604 	FcObject    object = FcObjectFromName (os->objects[i]);
    605 	ea = FcPatternObjectFindElt (pai, object);
    606 	eb = FcPatternObjectFindElt (pbi, object);
    607 	if (ea)
    608 	{
    609 	    if (!eb)
    610 		return FcFalse;
    611 	    if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
    612 		return FcFalse;
    613 	}
    614 	else
    615 	{
    616 	    if (eb)
    617 		return FcFalse;
    618 	}
    619     }
    620     return FcTrue;
    621 }
    622 
    623 FcBool
    624 FcPatternObjectListAdd (FcPattern	*p,
    625 			FcObject	object,
    626 			FcValueListPtr	list,
    627 			FcBool		append)
    628 {
    629     FcPatternElt   *e;
    630     FcValueListPtr l, *prev;
    631 
    632     if (FcRefIsConst (&p->ref))
    633 	goto bail0;
    634 
    635     /*
    636      * Make sure the stored type is valid for built-in objects
    637      */
    638     for (l = list; l != NULL; l = FcValueListNext (l))
    639     {
    640 	if (!FcObjectValidType (object, l->value.type))
    641 	{
    642 	    fprintf (stderr,
    643 		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
    644 	    FcValuePrintFile (stderr, l->value);
    645 	    fprintf (stderr, "\n");
    646 	    goto bail0;
    647 	}
    648     }
    649 
    650     e = FcPatternObjectInsertElt (p, object);
    651     if (!e)
    652 	goto bail0;
    653 
    654     if (append)
    655     {
    656 	for (prev = &e->values; *prev; prev = &(*prev)->next)
    657 	    ;
    658 	*prev = list;
    659     }
    660     else
    661     {
    662 	for (prev = &list; *prev; prev = &(*prev)->next)
    663 	    ;
    664 	*prev = e->values;
    665 	e->values = list;
    666     }
    667 
    668     return FcTrue;
    669 
    670 bail0:
    671     return FcFalse;
    672 }
    673 
    674 FcBool
    675 FcPatternObjectAddWithBinding  (FcPattern	*p,
    676 				FcObject	object,
    677 				FcValue		value,
    678 				FcValueBinding  binding,
    679 				FcBool		append)
    680 {
    681     FcPatternElt   *e;
    682     FcValueListPtr new, *prev;
    683 
    684     if (FcRefIsConst (&p->ref))
    685 	goto bail0;
    686 
    687     new = FcValueListCreate ();
    688     if (!new)
    689 	goto bail0;
    690 
    691     new->value = FcValueSave (value);
    692     new->binding = binding;
    693     new->next = NULL;
    694 
    695     if (new->value.type == FcTypeVoid)
    696 	goto bail1;
    697 
    698     /*
    699      * Make sure the stored type is valid for built-in objects
    700      */
    701     if (!FcObjectValidType (object, new->value.type))
    702     {
    703 	fprintf (stderr,
    704 		 "Fontconfig warning: FcPattern object %s does not accept value",
    705 		 FcObjectName (object));
    706 	FcValuePrintFile (stderr, new->value);
    707 	fprintf (stderr, "\n");
    708 	goto bail1;
    709     }
    710 
    711     e = FcPatternObjectInsertElt (p, object);
    712     if (!e)
    713 	goto bail1;
    714 
    715     if (append)
    716     {
    717 	for (prev = &e->values; *prev; prev = &(*prev)->next)
    718 	    ;
    719 	*prev = new;
    720     }
    721     else
    722     {
    723 	new->next = e->values;
    724 	e->values = new;
    725     }
    726 
    727     return FcTrue;
    728 
    729 bail1:
    730     FcValueListDestroy (new);
    731 bail0:
    732     return FcFalse;
    733 }
    734 
    735 FcBool
    736 FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
    737 {
    738     return FcPatternObjectAddWithBinding (p, object,
    739 					  value, FcValueBindingStrong, append);
    740 }
    741 
    742 FcBool
    743 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
    744 {
    745     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
    746 					  value, FcValueBindingStrong, append);
    747 }
    748 
    749 FcBool
    750 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
    751 {
    752     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
    753 					  value, FcValueBindingWeak, append);
    754 }
    755 
    756 FcBool
    757 FcPatternObjectDel (FcPattern *p, FcObject object)
    758 {
    759     FcPatternElt   *e;
    760 
    761     e = FcPatternObjectFindElt (p, object);
    762     if (!e)
    763 	return FcFalse;
    764 
    765     /* destroy value */
    766     FcValueListDestroy (e->values);
    767 
    768     /* shuffle existing ones down */
    769     memmove (e, e+1,
    770 	     (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) *
    771 	     sizeof (FcPatternElt));
    772     p->num--;
    773     e = FcPatternElts(p) + FcPatternObjectCount (p);
    774     e->object = 0;
    775     e->values = NULL;
    776     return FcTrue;
    777 }
    778 
    779 FcBool
    780 FcPatternDel (FcPattern *p, const char *object)
    781 {
    782     return FcPatternObjectDel (p, FcObjectFromName (object));
    783 }
    784 
    785 FcBool
    786 FcPatternRemove (FcPattern *p, const char *object, int id)
    787 {
    788     FcPatternElt    *e;
    789     FcValueListPtr  *prev, l;
    790 
    791     e = FcPatternObjectFindElt (p, FcObjectFromName (object));
    792     if (!e)
    793 	return FcFalse;
    794     for (prev = &e->values; (l = *prev); prev = &l->next)
    795     {
    796 	if (!id)
    797 	{
    798 	    *prev = l->next;
    799 	    l->next = NULL;
    800 	    FcValueListDestroy (l);
    801 	    if (!e->values)
    802 		FcPatternDel (p, object);
    803 	    return FcTrue;
    804 	}
    805 	id--;
    806     }
    807     return FcFalse;
    808 }
    809 
    810 FcBool
    811 FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
    812 {
    813     FcValue	v;
    814 
    815     v.type = FcTypeInteger;
    816     v.u.i = i;
    817     return FcPatternObjectAdd (p, object, v, FcTrue);
    818 }
    819 
    820 FcBool
    821 FcPatternAddInteger (FcPattern *p, const char *object, int i)
    822 {
    823     return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
    824 }
    825 
    826 FcBool
    827 FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
    828 {
    829     FcValue	v;
    830 
    831     v.type = FcTypeDouble;
    832     v.u.d = d;
    833     return FcPatternObjectAdd (p, object, v, FcTrue);
    834 }
    835 
    836 
    837 FcBool
    838 FcPatternAddDouble (FcPattern *p, const char *object, double d)
    839 {
    840     return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
    841 }
    842 
    843 FcBool
    844 FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
    845 {
    846     FcValue	v;
    847 
    848     if (!s)
    849     {
    850 	v.type = FcTypeVoid;
    851 	v.u.s = 0;
    852 	return FcPatternObjectAdd (p, object, v, FcTrue);
    853     }
    854 
    855     v.type = FcTypeString;
    856     v.u.s = s;
    857     return FcPatternObjectAdd (p, object, v, FcTrue);
    858 }
    859 
    860 FcBool
    861 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
    862 {
    863     return FcPatternObjectAddString (p, FcObjectFromName (object), s);
    864 }
    865 
    866 FcBool
    867 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
    868 {
    869     FcValue	v;
    870 
    871     v.type = FcTypeMatrix;
    872     v.u.m = s;
    873     return FcPatternAdd (p, object, v, FcTrue);
    874 }
    875 
    876 
    877 FcBool
    878 FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
    879 {
    880     FcValue	v;
    881 
    882     v.type = FcTypeBool;
    883     v.u.b = b;
    884     return FcPatternObjectAdd (p, object, v, FcTrue);
    885 }
    886 
    887 FcBool
    888 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
    889 {
    890     return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
    891 }
    892 
    893 FcBool
    894 FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c)
    895 {
    896     FcValue	v;
    897 
    898     v.type = FcTypeCharSet;
    899     v.u.c = (FcCharSet *)c;
    900     return FcPatternObjectAdd (p, object, v, FcTrue);
    901 }
    902 
    903 FcBool
    904 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
    905 {
    906     return FcPatternObjectAddCharSet (p, FcObjectFromName (object), c);
    907 }
    908 
    909 FcBool
    910 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
    911 {
    912     FcValue	v;
    913 
    914     v.type = FcTypeFTFace;
    915     v.u.f = (void *) f;
    916     return FcPatternAdd (p, object, v, FcTrue);
    917 }
    918 
    919 FcBool
    920 FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls)
    921 {
    922     FcValue	v;
    923 
    924     v.type = FcTypeLangSet;
    925     v.u.l = (FcLangSet *)ls;
    926     return FcPatternObjectAdd (p, object, v, FcTrue);
    927 }
    928 
    929 FcBool
    930 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
    931 {
    932     return FcPatternObjectAddLangSet (p, FcObjectFromName (object), ls);
    933 }
    934 
    935 FcBool
    936 FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r)
    937 {
    938     FcValue v;
    939 
    940     v.type = FcTypeRange;
    941     v.u.r = (FcRange *)r;
    942     return FcPatternObjectAdd (p, object, v, FcTrue);
    943 }
    944 
    945 FcBool
    946 FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r)
    947 {
    948     return FcPatternObjectAddRange (p, FcObjectFromName (object), r);
    949 }
    950 
    951 FcResult
    952 FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b)
    953 {
    954     FcPatternElt   *e;
    955     FcValueListPtr l;
    956 
    957     if (!p)
    958 	return FcResultNoMatch;
    959     e = FcPatternObjectFindElt (p, object);
    960     if (!e)
    961 	return FcResultNoMatch;
    962     for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
    963     {
    964 	if (!id)
    965 	{
    966 	    *v = FcValueCanonicalize(&l->value);
    967 	    if (b)
    968 		*b = l->binding;
    969 	    return FcResultMatch;
    970 	}
    971 	id--;
    972     }
    973     return FcResultNoId;
    974 }
    975 
    976 FcResult
    977 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
    978 {
    979     return FcPatternObjectGetWithBinding (p, object, id, v, NULL);
    980 }
    981 
    982 FcResult
    983 FcPatternGetWithBinding (const FcPattern *p, const char *object, int id, FcValue *v, FcValueBinding *b)
    984 {
    985     return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, b);
    986 }
    987 
    988 FcResult
    989 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
    990 {
    991     return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, NULL);
    992 }
    993 
    994 FcResult
    995 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
    996 {
    997     FcValue	v;
    998     FcResult	r;
    999 
   1000     r = FcPatternObjectGet (p, object, id, &v);
   1001     if (r != FcResultMatch)
   1002 	return r;
   1003     switch ((int) v.type) {
   1004     case FcTypeDouble:
   1005 	*i = (int) v.u.d;
   1006 	break;
   1007     case FcTypeInteger:
   1008 	*i = v.u.i;
   1009 	break;
   1010     default:
   1011         return FcResultTypeMismatch;
   1012     }
   1013     return FcResultMatch;
   1014 }
   1015 
   1016 FcResult
   1017 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
   1018 {
   1019     return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
   1020 }
   1021 
   1022 
   1023 FcResult
   1024 FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
   1025 {
   1026     FcValue	v;
   1027     FcResult	r;
   1028 
   1029     r = FcPatternObjectGet (p, object, id, &v);
   1030     if (r != FcResultMatch)
   1031 	return r;
   1032     switch ((int) v.type) {
   1033     case FcTypeDouble:
   1034 	*d = v.u.d;
   1035 	break;
   1036     case FcTypeInteger:
   1037 	*d = (double) v.u.i;
   1038 	break;
   1039     default:
   1040         return FcResultTypeMismatch;
   1041     }
   1042     return FcResultMatch;
   1043 }
   1044 
   1045 FcResult
   1046 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
   1047 {
   1048     return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
   1049 }
   1050 
   1051 FcResult
   1052 FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
   1053 {
   1054     FcValue	v;
   1055     FcResult	r;
   1056 
   1057     r = FcPatternObjectGet (p, object, id, &v);
   1058     if (r != FcResultMatch)
   1059 	return r;
   1060     if (v.type != FcTypeString)
   1061         return FcResultTypeMismatch;
   1062 
   1063     *s = (FcChar8 *) v.u.s;
   1064     return FcResultMatch;
   1065 }
   1066 
   1067 FcResult
   1068 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
   1069 {
   1070     return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
   1071 }
   1072 
   1073 FcResult
   1074 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
   1075 {
   1076     FcValue	v;
   1077     FcResult	r;
   1078 
   1079     r = FcPatternGet (p, object, id, &v);
   1080     if (r != FcResultMatch)
   1081 	return r;
   1082     if (v.type != FcTypeMatrix)
   1083         return FcResultTypeMismatch;
   1084     *m = (FcMatrix *)v.u.m;
   1085     return FcResultMatch;
   1086 }
   1087 
   1088 
   1089 FcResult
   1090 FcPatternObjectGetBool (const FcPattern *p, FcObject object, int id, FcBool *b)
   1091 {
   1092     FcValue	v;
   1093     FcResult	r;
   1094 
   1095     r = FcPatternObjectGet (p, object, id, &v);
   1096     if (r != FcResultMatch)
   1097 	return r;
   1098     if (v.type != FcTypeBool)
   1099         return FcResultTypeMismatch;
   1100     *b = v.u.b;
   1101     return FcResultMatch;
   1102 }
   1103 
   1104 FcResult
   1105 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
   1106 {
   1107     return FcPatternObjectGetBool (p, FcObjectFromName (object), id, b);
   1108 }
   1109 
   1110 FcResult
   1111 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
   1112 {
   1113     FcValue	v;
   1114     FcResult	r;
   1115 
   1116     r = FcPatternGet (p, object, id, &v);
   1117     if (r != FcResultMatch)
   1118 	return r;
   1119     if (v.type != FcTypeCharSet)
   1120         return FcResultTypeMismatch;
   1121     *c = (FcCharSet *)v.u.c;
   1122     return FcResultMatch;
   1123 }
   1124 
   1125 FcResult
   1126 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
   1127 {
   1128     FcValue	v;
   1129     FcResult	r;
   1130 
   1131     r = FcPatternGet (p, object, id, &v);
   1132     if (r != FcResultMatch)
   1133 	return r;
   1134     if (v.type != FcTypeFTFace)
   1135 	return FcResultTypeMismatch;
   1136     *f = (FT_Face) v.u.f;
   1137     return FcResultMatch;
   1138 }
   1139 
   1140 FcResult
   1141 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
   1142 {
   1143     FcValue	v;
   1144     FcResult	r;
   1145 
   1146     r = FcPatternGet (p, object, id, &v);
   1147     if (r != FcResultMatch)
   1148 	return r;
   1149     if (v.type != FcTypeLangSet)
   1150         return FcResultTypeMismatch;
   1151     *ls = (FcLangSet *)v.u.l;
   1152     return FcResultMatch;
   1153 }
   1154 
   1155 FcResult
   1156 FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r)
   1157 {
   1158     FcValue	v;
   1159     FcResult	res;
   1160 
   1161     res = FcPatternObjectGet (p, object, id, &v);
   1162     if (res != FcResultMatch)
   1163 	return res;
   1164     switch ((int)v.type) {
   1165     case FcTypeRange:
   1166 	*r = (FcRange *)v.u.r;
   1167 	break;
   1168     default:
   1169 	return FcResultTypeMismatch;
   1170     }
   1171     return FcResultMatch;
   1172 }
   1173 
   1174 FcResult
   1175 FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r)
   1176 {
   1177     return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r);
   1178 }
   1179 
   1180 FcPattern *
   1181 FcPatternDuplicate (const FcPattern *orig)
   1182 {
   1183     FcPattern	    *new;
   1184     FcPatternIter   iter;
   1185     FcValueListPtr  l;
   1186 
   1187     if (!orig)
   1188 	return NULL;
   1189 
   1190     new = FcPatternCreate ();
   1191     if (!new)
   1192 	goto bail0;
   1193 
   1194     FcPatternIterStart (orig, &iter);
   1195     do
   1196     {
   1197 	for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l))
   1198 	{
   1199 	    if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter),
   1200 						FcValueCanonicalize(&l->value),
   1201 						l->binding,
   1202 						FcTrue))
   1203 		goto bail1;
   1204 	}
   1205     } while (FcPatternIterNext (orig, &iter));
   1206 
   1207     return new;
   1208 
   1209 bail1:
   1210     FcPatternDestroy (new);
   1211 bail0:
   1212     return 0;
   1213 }
   1214 
   1215 void
   1216 FcPatternReference (FcPattern *p)
   1217 {
   1218     if (!FcRefIsConst (&p->ref))
   1219 	FcRefInc (&p->ref);
   1220     else
   1221 	FcCacheObjectReference (FcPatternGetCacheObject(p));
   1222 }
   1223 
   1224 FcPattern *
   1225 FcPatternVaBuild (FcPattern *p, va_list va)
   1226 {
   1227     FcPattern	*ret;
   1228 
   1229     FcPatternVapBuild (ret, p, va);
   1230     return ret;
   1231 }
   1232 
   1233 FcPattern *
   1234 FcPatternBuild (FcPattern *p, ...)
   1235 {
   1236     va_list	va;
   1237 
   1238     va_start (va, p);
   1239     FcPatternVapBuild (p, p, va);
   1240     va_end (va);
   1241     return p;
   1242 }
   1243 
   1244 /*
   1245  * Add all of the elements in 's' to 'p'
   1246  */
   1247 FcBool
   1248 FcPatternAppend (FcPattern *p, FcPattern *s)
   1249 {
   1250     FcPatternIter  iter;
   1251     FcValueListPtr v;
   1252 
   1253     FcPatternIterStart (s, &iter);
   1254     do
   1255     {
   1256 	for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v))
   1257 	{
   1258 	    if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter),
   1259 						FcValueCanonicalize(&v->value),
   1260 						v->binding, FcTrue))
   1261 		return FcFalse;
   1262 	}
   1263     } while (FcPatternIterNext (s, &iter));
   1264 
   1265     return FcTrue;
   1266 }
   1267 
   1268 FcPattern *
   1269 FcPatternFilter (FcPattern *p, const FcObjectSet *os)
   1270 {
   1271     int		    i;
   1272     FcPattern	    *ret;
   1273     FcPatternElt    *e;
   1274     FcValueListPtr  v;
   1275 
   1276     if (!os)
   1277 	return FcPatternDuplicate (p);
   1278 
   1279     ret = FcPatternCreate ();
   1280     if (!ret)
   1281 	return NULL;
   1282 
   1283     for (i = 0; i < os->nobject; i++)
   1284     {
   1285 	FcObject object = FcObjectFromName (os->objects[i]);
   1286 	e = FcPatternObjectFindElt (p, object);
   1287 	if (e)
   1288 	{
   1289 	    for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
   1290 	    {
   1291 		if (!FcPatternObjectAddWithBinding (ret, e->object,
   1292 						    FcValueCanonicalize(&v->value),
   1293 						    v->binding, FcTrue))
   1294 		    goto bail0;
   1295 	    }
   1296 	}
   1297     }
   1298     return ret;
   1299 
   1300 bail0:
   1301     FcPatternDestroy (ret);
   1302     return NULL;
   1303 }
   1304 
   1305 typedef struct _FcPatternPrivateIter {
   1306     FcPatternElt *elt;
   1307     int           pos;
   1308 } FcPatternPrivateIter;
   1309 
   1310 static void
   1311 FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter)
   1312 {
   1313     iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL;
   1314 }
   1315 
   1316 void
   1317 FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter)
   1318 {
   1319     FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
   1320 
   1321     priv->pos = 0;
   1322     FcPatternIterSet (pat, priv);
   1323 }
   1324 
   1325 FcBool
   1326 FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter)
   1327 {
   1328     FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
   1329 
   1330     priv->pos++;
   1331     if (priv->pos >= FcPatternObjectCount (pat))
   1332 	return FcFalse;
   1333     FcPatternIterSet (pat, priv);
   1334 
   1335     return FcTrue;
   1336 }
   1337 
   1338 FcBool
   1339 FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1,
   1340 		    const FcPattern *p2, FcPatternIter *i2)
   1341 {
   1342     FcBool b1 = FcPatternIterIsValid (p1, i1);
   1343     FcBool b2 = FcPatternIterIsValid (p2, i2);
   1344 
   1345     if (!i1 && !i2)
   1346 	return FcTrue;
   1347     if (!b1 || !b2)
   1348 	return FcFalse;
   1349     if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2))
   1350 	return FcFalse;
   1351 
   1352     return FcValueListEqual (FcPatternIterGetValues (p1, i1),
   1353 			     FcPatternIterGetValues (p2, i2));
   1354 }
   1355 
   1356 FcBool
   1357 FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object)
   1358 {
   1359     FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
   1360     int i = FcPatternObjectPosition (pat, object);
   1361 
   1362     priv->elt = NULL;
   1363     if (i < 0)
   1364 	return FcFalse;
   1365 
   1366     priv->pos = i;
   1367     FcPatternIterSet (pat, priv);
   1368 
   1369     return FcTrue;
   1370 }
   1371 
   1372 FcBool
   1373 FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object)
   1374 {
   1375     return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object));
   1376 }
   1377 
   1378 FcBool
   1379 FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter)
   1380 {
   1381     FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter;
   1382 
   1383     if (priv && priv->elt)
   1384 	return FcTrue;
   1385 
   1386     return FcFalse;
   1387 }
   1388 
   1389 FcObject
   1390 FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter)
   1391 {
   1392     FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
   1393 
   1394     if (priv && priv->elt)
   1395 	return priv->elt->object;
   1396 
   1397     return 0;
   1398 }
   1399 
   1400 const char *
   1401 FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter)
   1402 {
   1403     return FcObjectName (FcPatternIterGetObjectId (pat, iter));
   1404 }
   1405 
   1406 FcValueListPtr
   1407 FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter)
   1408 {
   1409     FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
   1410 
   1411     if (priv && priv->elt)
   1412 	return FcPatternEltValues (priv->elt);
   1413 
   1414     return NULL;
   1415 }
   1416 
   1417 int
   1418 FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter)
   1419 {
   1420     int count = 0;
   1421     FcValueListPtr l;
   1422 
   1423     for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
   1424 	count++;
   1425 
   1426     return count;
   1427 }
   1428 
   1429 FcResult
   1430 FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b)
   1431 {
   1432     FcValueListPtr l;
   1433 
   1434     for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
   1435     {
   1436 	if (id == 0)
   1437 	{
   1438 	    *v = FcValueCanonicalize (&l->value);
   1439 	    if (b)
   1440 		*b = l->binding;
   1441 	    return FcResultMatch;
   1442 	}
   1443 	id--;
   1444     }
   1445     return FcResultNoId;
   1446 }
   1447 
   1448 FcBool
   1449 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
   1450 {
   1451     int	i;
   1452     FcPatternElt    *elts = FcPatternElts(pat);
   1453 
   1454     if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
   1455 	return FcFalse;
   1456     if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt)))
   1457 	return FcFalse;
   1458     for (i = 0; i < FcPatternObjectCount (pat); i++)
   1459 	if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
   1460 	    return FcFalse;
   1461     return FcTrue;
   1462 }
   1463 
   1464 FcPattern *
   1465 FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
   1466 {
   1467     FcPattern	    *pat_serialized;
   1468     FcPatternElt    *elts = FcPatternElts (pat);
   1469     FcPatternElt    *elts_serialized;
   1470     FcValueList	    *values_serialized;
   1471     int		    i;
   1472 
   1473     pat_serialized = FcSerializePtr (serialize, pat);
   1474     if (!pat_serialized)
   1475 	return NULL;
   1476     *pat_serialized = *pat;
   1477     pat_serialized->size = FcPatternObjectCount (pat);
   1478     FcRefSetConst (&pat_serialized->ref);
   1479 
   1480     elts_serialized = FcSerializePtr (serialize, elts);
   1481     if (!elts_serialized)
   1482 	return NULL;
   1483 
   1484     pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
   1485 						 elts_serialized);
   1486 
   1487     for (i = 0; i < FcPatternObjectCount (pat); i++)
   1488     {
   1489 	values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
   1490 	if (!values_serialized)
   1491 	    return NULL;
   1492 	elts_serialized[i].object = elts[i].object;
   1493 	elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
   1494 							  values_serialized,
   1495 							  FcValueList);
   1496     }
   1497     if (FcDebug() & FC_DBG_CACHEV) {
   1498 	printf ("Raw pattern:\n");
   1499 	FcPatternPrint (pat);
   1500 	printf ("Serialized pattern:\n");
   1501 	FcPatternPrint (pat_serialized);
   1502 	printf ("\n");
   1503     }
   1504     return pat_serialized;
   1505 }
   1506 
   1507 FcBool
   1508 FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
   1509 {
   1510     while (vl)
   1511     {
   1512 	if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
   1513 	    return FcFalse;
   1514 	switch ((int) vl->value.type) {
   1515 	case FcTypeString:
   1516 	    if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
   1517 		return FcFalse;
   1518 	    break;
   1519 	case FcTypeCharSet:
   1520 	    if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
   1521 		return FcFalse;
   1522 	    break;
   1523 	case FcTypeLangSet:
   1524 	    if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
   1525 		return FcFalse;
   1526 	    break;
   1527 	case FcTypeRange:
   1528 	    if (!FcRangeSerializeAlloc (serialize, vl->value.u.r))
   1529 		return FcFalse;
   1530 	    break;
   1531 	default:
   1532 	    break;
   1533 	}
   1534 	vl = vl->next;
   1535     }
   1536     return FcTrue;
   1537 }
   1538 
   1539 FcValueList *
   1540 FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
   1541 {
   1542     FcValueList	*vl_serialized;
   1543     FcChar8	*s_serialized;
   1544     FcCharSet	*c_serialized;
   1545     FcLangSet	*l_serialized;
   1546     FcRange	*r_serialized;
   1547     FcValueList	*head_serialized = NULL;
   1548     FcValueList	*prev_serialized = NULL;
   1549 
   1550     while (vl)
   1551     {
   1552 	vl_serialized = FcSerializePtr (serialize, vl);
   1553 	if (!vl_serialized)
   1554 	    return NULL;
   1555 
   1556 	if (prev_serialized)
   1557 	    prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
   1558 							  vl_serialized,
   1559 							  FcValueList);
   1560 	else
   1561 	    head_serialized = vl_serialized;
   1562 
   1563 	vl_serialized->next = NULL;
   1564 	vl_serialized->value.type = vl->value.type;
   1565 	switch ((int) vl->value.type) {
   1566 	case FcTypeInteger:
   1567 	    vl_serialized->value.u.i = vl->value.u.i;
   1568 	    break;
   1569 	case FcTypeDouble:
   1570 	    vl_serialized->value.u.d = vl->value.u.d;
   1571 	    break;
   1572 	case FcTypeString:
   1573 	    s_serialized = FcStrSerialize (serialize, vl->value.u.s);
   1574 	    if (!s_serialized)
   1575 		return NULL;
   1576 	    vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
   1577 							     s_serialized,
   1578 							     FcChar8);
   1579 	    break;
   1580 	case FcTypeBool:
   1581 	    vl_serialized->value.u.b = vl->value.u.b;
   1582 	    break;
   1583 	case FcTypeMatrix:
   1584 	    /* can't happen */
   1585 	    break;
   1586 	case FcTypeCharSet:
   1587 	    c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
   1588 	    if (!c_serialized)
   1589 		return NULL;
   1590 	    vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
   1591 							     c_serialized,
   1592 							     FcCharSet);
   1593 	    break;
   1594 	case FcTypeFTFace:
   1595 	    /* can't happen */
   1596 	    break;
   1597 	case FcTypeLangSet:
   1598 	    l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
   1599 	    if (!l_serialized)
   1600 		return NULL;
   1601 	    vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
   1602 							     l_serialized,
   1603 							     FcLangSet);
   1604 	    break;
   1605 	case FcTypeRange:
   1606 	    r_serialized = FcRangeSerialize (serialize, vl->value.u.r);
   1607 	    if (!r_serialized)
   1608 		return NULL;
   1609 	    vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value,
   1610 							     r_serialized,
   1611 							     FcRange);
   1612 	    break;
   1613 	default:
   1614 	    break;
   1615 	}
   1616 	prev_serialized = vl_serialized;
   1617 	vl = vl->next;
   1618     }
   1619     return head_serialized;
   1620 }
   1621 
   1622 #define __fcpat__
   1623 #include "fcaliastail.h"
   1624 #include "fcftaliastail.h"
   1625 #undef __fcpat__
   1626