]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcpat.c
Add ref counting to font config patterns so that FcFontSort return values
[fontconfig.git] / src / fcpat.c
index 55b1e71abe02008bd2930c0d249d0b695a8ef3d7..3e19732a4e47b879543a6e3a27869f923d0afd23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.2 2002/02/15 06:01:28 keithp Exp $
+ * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.7 2002/06/03 08:31:15 keithp Exp $
  *
  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
  *
@@ -38,6 +38,7 @@ FcPatternCreate (void)
     p->num = 0;
     p->size = 0;
     p->elts = 0;
+    p->ref = 1;
     return p;
 }
 
@@ -109,11 +110,131 @@ FcValueListDestroy (FcValueList *l)
     }
 }
 
+FcBool
+FcValueEqual (FcValue va, FcValue vb)
+{
+    if (va.type != vb.type)
+    {
+       if (va.type == FcTypeInteger)
+       {
+           va.type = FcTypeDouble;
+           va.u.d = va.u.i;
+       }
+       if (vb.type == FcTypeInteger)
+       {
+           vb.type = FcTypeDouble;
+           vb.u.d = vb.u.i;
+       }
+       if (va.type != vb.type)
+           return FcFalse;
+    }
+    switch (va.type) {
+    case FcTypeVoid:
+       return FcTrue;
+    case FcTypeInteger:
+       return va.u.i == vb.u.i;
+    case FcTypeDouble:
+       return va.u.d == vb.u.d;
+    case FcTypeString:
+       return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
+    case FcTypeBool:
+       return va.u.b == vb.u.b;
+    case FcTypeMatrix:
+       return FcMatrixEqual (va.u.m, vb.u.m);
+    case FcTypeCharSet:
+       return FcCharSetEqual (va.u.c, vb.u.c);
+    case FcTypeFTFace:
+       return va.u.f == vb.u.f;
+    }
+    return FcFalse;
+}
+
+static FcChar32
+FcDoubleHash (double d)
+{
+    if (d < 0)
+       d = -d;
+    if (d > 0xffffffff)
+       d = 0xffffffff;
+    return (FcChar32) d;
+}
+
+static FcChar32
+FcStringHash (const FcChar8 *s)
+{
+    FcChar8    c;
+    FcChar32   h = 0;
+    
+    if (s)
+       while ((c = *s++))
+           h = ((h << 1) | (h >> 31)) ^ c;
+    return h;
+}
+
+static FcChar32
+FcValueHash (FcValue v)
+{
+    switch (v.type) {
+    case FcTypeVoid:
+       return 0;
+    case FcTypeInteger:
+       return (FcChar32) v.u.i;
+    case FcTypeDouble:
+       return FcDoubleHash (v.u.d);
+    case FcTypeString:
+       return FcStringHash (v.u.s);
+    case FcTypeBool:
+       return (FcChar32) v.u.b;
+    case FcTypeMatrix:
+       return (FcDoubleHash (v.u.m->xx) ^ 
+               FcDoubleHash (v.u.m->xy) ^ 
+               FcDoubleHash (v.u.m->yx) ^ 
+               FcDoubleHash (v.u.m->yy));
+    case FcTypeCharSet:
+       return (FcChar32) v.u.c->num;
+    case FcTypeFTFace:
+       return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
+              FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
+    }
+    return FcFalse;
+}
+
+static FcBool
+FcValueListEqual (FcValueList *la, FcValueList *lb)
+{
+    while (la && lb)
+    {
+       if (!FcValueEqual (la->value, lb->value))
+           return FcFalse;
+       la = la->next;
+       lb = lb->next;
+    }
+    if (la || lb)
+       return FcFalse;
+    return FcTrue;
+}
+
+static FcChar32
+FcValueListHash (FcValueList *l)
+{
+    FcChar32   hash = 0;
+    
+    while (l)
+    {
+       hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
+       l = l->next;
+    }
+    return hash;
+}
+
 void
 FcPatternDestroy (FcPattern *p)
 {
     int                    i;
     
+    if (--p->ref > 0)
+       return;
+
     for (i = 0; i < p->num; i++)
        FcValueListDestroy (p->elts[i].values);
 
@@ -129,51 +250,145 @@ FcPatternDestroy (FcPattern *p)
     free (p);
 }
 
+static int
+FcPatternPosition (const FcPattern *p, const char *object)
+{
+    int            low, high, mid, c;
+
+    low = 0;
+    high = p->num - 1;
+    c = 1;
+    mid = 0;
+    while (low <= high)
+    {
+       mid = (low + high) >> 1;
+       c = strcmp (p->elts[mid].object, object);
+       if (c == 0)
+           return mid;
+       if (c < 0)
+           low = mid + 1;
+       else
+           high = mid - 1;
+    }
+    if (c < 0)
+       mid++;
+    return -(mid + 1);
+}
+
+FcPatternElt *
+FcPatternFindElt (const FcPattern *p, const char *object)
+{
+    int            i = FcPatternPosition (p, object);
+    if (i < 0)
+       return 0;
+    return &p->elts[i];
+}
+
 FcPatternElt *
-FcPatternFind (FcPattern *p, const char *object, FcBool insert)
+FcPatternInsertElt (FcPattern *p, const char *object)
 {
     int                    i;
-    int                    s;
     FcPatternElt   *e;
     
-    /* match existing */
-    for (i = 0; i < p->num; i++)
+    i = FcPatternPosition (p, object);
+    if (i < 0)
     {
-       if (!FcStrCmpIgnoreCase ((FcChar8 *) object, (FcChar8 *) p->elts[i].object))
-           return &p->elts[i];
+       i = -i - 1;
+    
+       /* grow array */
+       if (p->num + 1 >= p->size)
+       {
+           int s = p->size + 16;
+           if (p->elts)
+               e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
+           else
+               e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
+           if (!e)
+               return FcFalse;
+           p->elts = e;
+           if (p->size)
+               FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
+           FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
+           while (p->size < s)
+           {
+               p->elts[p->size].object = 0;
+               p->elts[p->size].values = 0;
+               p->size++;
+           }
+       }
+       
+       /* move elts up */
+       memmove (p->elts + i + 1,
+                p->elts + i,
+                sizeof (FcPatternElt) *
+                (p->num - i));
+                
+       /* bump count */
+       p->num++;
+       
+       p->elts[i].object = object;
+       p->elts[i].values = 0;
     }
+    
+    return &p->elts[i];
+}
+
+FcBool
+FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
+{
+    int        i;
 
-    if (!insert)
+    if (pa->num != pb->num)
        return FcFalse;
+    for (i = 0; i < pa->num; i++)
+    {
+       if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
+           return FcFalse;
+       if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
+           return FcFalse;
+    }
+    return FcTrue;
+}
 
-    /* grow array */
-    if (i == p->size)
+FcChar32
+FcPatternHash (const FcPattern *p)
+{
+    int                i;
+    FcChar32   h = 0;
+
+    for (i = 0; i < p->num; i++)
+    {
+       h = (((h << 1) | (h >> 31)) ^ 
+            FcStringHash ((const FcChar8 *) p->elts[i].object) ^
+            FcValueListHash (p->elts[i].values));
+    }
+    return h;
+}
+
+FcBool
+FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
+{
+    FcPatternElt    *ea, *eb;
+    int                    i;
+    
+    for (i = 0; i < os->nobject; i++)
     {
-       s = p->size + 16;
-       if (p->elts)
-           e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
+       ea = FcPatternFindElt (pa, os->objects[i]);
+       eb = FcPatternFindElt (pb, os->objects[i]);
+       if (ea)
+       {
+           if (!eb)
+               return FcFalse;
+           if (!FcValueListEqual (ea->values, eb->values))
+               return FcFalse;
+       }
        else
-           e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
-       if (!e)
-           return FcFalse;
-       p->elts = e;
-       if (p->size)
-           FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
-       FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
-       while (p->size < s)
        {
-           p->elts[p->size].object = 0;
-           p->elts[p->size].values = 0;
-           p->size++;
+           if (eb)
+               return FcFalse;
        }
     }
-    
-    /* bump count */
-    p->num++;
-    
-    p->elts[i].object = object;
-    
-    return &p->elts[i];
+    return FcTrue;
 }
 
 FcBool
@@ -195,7 +410,7 @@ FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
     new->value = value;
     new->next = 0;
     
-    e = FcPatternFind (p, object, FcTrue);
+    e = FcPatternInsertElt (p, object);
     if (!e)
        goto bail2;
     
@@ -239,7 +454,7 @@ FcPatternDel (FcPattern *p, const char *object)
     FcPatternElt   *e;
     int                    i;
 
-    e = FcPatternFind (p, object, FcFalse);
+    e = FcPatternFindElt (p, object);
     if (!e)
        return FcFalse;
 
@@ -318,13 +533,23 @@ FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
     return FcPatternAdd (p, object, v, FcTrue);
 }
 
+FcBool
+FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
+{
+    FcValue    v;
+
+    v.type = FcTypeFTFace;
+    v.u.f = (void *) f;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
 FcResult
 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
 {
     FcPatternElt   *e;
     FcValueList    *l;
 
-    e = FcPatternFind (p, object, FcFalse);
+    e = FcPatternFindElt (p, object);
     if (!e)
        return FcResultNoMatch;
     for (l = e->values; l; l = l->next)
@@ -444,6 +669,21 @@ FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
     return FcResultMatch;
 }
 
+FcResult
+FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    if (v.type != FcTypeFTFace)
+       return FcResultTypeMismatch;
+    *f = (FT_Face) v.u.f;
+    return FcResultMatch;
+}
+
 FcPattern *
 FcPatternDuplicate (FcPattern *orig)
 {
@@ -470,6 +710,12 @@ bail0:
     return 0;
 }
 
+void
+FcPatternReference (FcPattern *p)
+{
+    p->ref++;
+}
+
 FcPattern *
 FcPatternVaBuild (FcPattern *orig, va_list va)
 {