(root)/
fontconfig-2.14.2/
src/
fcpat.c
       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__