]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcpat.c
Make FcCompareString and FcCompareFamily less expensive. Only add a value
[fontconfig.git] / src / fcpat.c
index 0714dc76306f9bc2546d100d9c15ec22f01f1c77..c37936f397133993fbaac14eb38382461551b9cb 100644 (file)
@@ -34,9 +34,18 @@ static int fcpatternelt_ptr, fcpatternelt_count;
 static FcValueList ** fcvaluelists = 0;
 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
 
+static const char *
+FcPatternFindFullFname (const FcPattern *p);
 static FcPatternEltPtr
 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
 
+/* If you are trying to duplicate an FcPattern which will be used for
+ * rendering, be aware that (internally) you also have to use
+ * FcPatternTransferFullFname to transfer the associated filename.  If
+ * you are copying the font (externally) using FcPatternGetString,
+ * then everything's fine; this caveat only applies if you're copying
+ * the bits individually.  */
+
 FcPattern *
 FcPatternCreate (void)
 {
@@ -298,6 +307,12 @@ FcPatternDestroy (FcPattern *p)
     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
        return;
 
+    if (FcPatternFindFullFname (p))
+    {
+       FcStrFree ((FcChar8 *)FcPatternFindFullFname (p));
+       FcPatternAddFullFname (p, 0);
+    }
+
     for (i = 0; i < p->num; i++)
        FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
 
@@ -577,6 +592,9 @@ FcPatternBaseFreeze (FcPattern *b)
            (FcPatternEltU(b->elts)+i)->object;
     }
 
+    if (FcPatternFindElt (b, FC_FILE))
+       FcPatternTransferFullFname (ep, b);
+
     ent->hash = hash;
     ent->next = *bucket;
     *bucket = ent;
@@ -644,6 +662,10 @@ FcPatternFreeze (FcPattern *p)
        if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
            goto bail;
     }
+
+    if (FcPatternFindElt (p, FC_FILE))
+       FcPatternTransferFullFname (b, p);
+
     /*
      * Freeze base
      */
@@ -850,6 +872,13 @@ FcPatternAddWithBinding  (FcPattern            *p,
     if (value.type == FcTypeVoid)
        goto bail1;
 
+    /* quick and dirty hack to enable FcCompareFamily speedup:
+     * only allow strings to be added under the FC_FAMILY key.
+     * a better hack would use FcBaseObjectTypes to check all objects. */
+    if (FcObjectToPtr(object) == FcObjectToPtr(FC_FAMILY) &&
+        value.type != FcTypeString)
+        goto bail1;
+
     FcValueListPtrU(new)->value = value;
     FcValueListPtrU(new)->binding = binding;
     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
@@ -1115,6 +1144,42 @@ FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s
        return r;
     if (v.type != FcTypeString)
         return FcResultTypeMismatch;
+
+    if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
+    {
+       const char *fn, *fpath;
+       FcChar8 *fname;
+       int size;
+
+       fn = FcPatternFindFullFname(p);
+       if (fn)
+       {
+           *s = (FcChar8 *) fn;
+           return FcResultMatch;
+       }
+
+       if (!p->bank)
+       {
+           *s = (FcChar8 *) v.u.s;
+           return FcResultMatch;
+       }
+
+       fpath = FcCacheFindBankDir (p->bank);
+       size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
+       fname = malloc (size);
+       if (!fname)
+           return FcResultOutOfMemory;
+
+       FcMemAlloc (FC_MEM_STRING, size);
+       strcpy ((char *)fname, (char *)fpath);
+       strcat ((char *)fname, "/");
+       strcat ((char *)fname, (char *)v.u.s);
+       
+       FcPatternAddFullFname (p, (const char *)fname);
+       *s = (FcChar8 *)fname;
+       return FcResultMatch;
+    }
+
     *s = (FcChar8 *) v.u.s;
     return FcResultMatch;
 }
@@ -1219,6 +1284,7 @@ FcPatternDuplicate (const FcPattern *orig)
                               FcTrue))
                goto bail1;
     }
+    FcPatternTransferFullFname (new, orig);
 
     return new;
 
@@ -1371,6 +1437,8 @@ static void
 FcStrNewBank (void);
 static int
 FcStrNeededBytes (const FcChar8 * s);
+static int
+FcStrNeededBytesAlign (void);
 static void *
 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
 static const FcChar8 *
@@ -1382,6 +1450,8 @@ static void
 FcValueListNewBank (void);
 static int
 FcValueListNeededBytes (FcValueList * vl);
+static int
+FcValueListNeededBytesAlign (void);
 static void *
 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
 static FcValueListPtr
@@ -1420,6 +1490,13 @@ FcPatternNeededBytes (FcPattern * p)
     return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
 }
 
+int
+FcPatternNeededBytesAlign (void)
+{
+    return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) + 
+       FcValueListNeededBytesAlign ();
+}
+
 static FcBool
 FcPatternEnsureBank (int bi)
 {
@@ -1466,12 +1543,14 @@ FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
        return 0;
 
     fcpattern_ptr = 0;
+    block_ptr = ALIGN(block_ptr, FcPattern);
     fcpatterns[bi] = (FcPattern *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPattern) * fcpattern_count));
     
     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
     fcpatternelt_ptr = 0;
+    block_ptr = ALIGN(block_ptr, FcPatternElt);
     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPatternElt) * fcpatternelt_count));
@@ -1544,12 +1623,14 @@ FcPatternUnserialize (FcCache metadata, void *block_ptr)
        return FcFalse;
 
     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata.pattern_count);
+    block_ptr = ALIGN(block_ptr, FcPattern);
     fcpatterns[bi] = (FcPattern *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPattern) * metadata.pattern_count));
     
     FcMemAlloc (FC_MEM_PATELT, 
                sizeof (FcPatternElt) * metadata.patternelt_count);
+    block_ptr = ALIGN(block_ptr, FcPatternElt);
     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPatternElt) * metadata.patternelt_count));
@@ -1601,6 +1682,13 @@ FcValueListNeededBytes (FcValueList *p)
     return cum;
 }
 
+static int
+FcValueListNeededBytesAlign (void)
+{
+    return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() + 
+       FcStrNeededBytesAlign() + __alignof__ (FcValueList);
+}
+
 static FcBool
 FcValueListEnsureBank (int bi)
 {
@@ -1635,6 +1723,7 @@ FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
 
     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
     fcvaluelist_ptr = 0;
+    block_ptr = ALIGN(block_ptr, FcValueList);
     fcvaluelists[bi] = (FcValueList *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcValueList) * fcvaluelist_count));
@@ -1663,6 +1752,7 @@ FcValueListSerialize(int bank, FcValueList *pi)
     fcvaluelists[bi][fcvaluelist_ptr] = *pi;
     new.bank = bank;
     new.u.stat = fcvaluelist_ptr++;
+    fcvaluelists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
     v = &fcvaluelists[bi][new.u.stat].value;
     switch (v->type)
     {
@@ -1714,6 +1804,7 @@ FcValueListUnserialize (FcCache metadata, void *block_ptr)
 
     FcMemAlloc (FC_MEM_VALLIST, 
                sizeof (FcValueList) * metadata.valuelist_count);
+    block_ptr = ALIGN(block_ptr, FcValueList);
     fcvaluelists[bi] = (FcValueList *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcValueList) * metadata.valuelist_count));
@@ -1790,6 +1881,11 @@ FcStrNeededBytes (const FcChar8 * s)
     b->next = 0;
     b->hash = hash;
     strcpy ((char *) (b + 1), (char *)s);
+
+    /* Yes, the following line is convoluted.  However, it is
+     * incorrect to replace the with a memset, because the C
+     * specification doesn't guarantee that the null pointer is
+     * the same as the zero bit pattern. */
     *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
     *p = b;
 
@@ -1797,6 +1893,12 @@ FcStrNeededBytes (const FcChar8 * s)
     return strlen((char *)s) + 1;
 }
 
+static int
+FcStrNeededBytesAlign (void)
+{
+    return __alignof__ (char);
+}
+
 static FcBool
 FcStrEnsureBank (int bi)
 {
@@ -1827,6 +1929,7 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
        return 0;
 
     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
+    block_ptr = ALIGN (block_ptr, FcChar8);
     static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
     metadata->str_count = fcstr_count;
@@ -1867,6 +1970,7 @@ FcStrUnserialize (FcCache metadata, void *block_ptr)
        return 0;
 
     FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
+    block_ptr = ALIGN (block_ptr, FcChar8);
     static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (char) * metadata.str_count));
@@ -1874,3 +1978,70 @@ FcStrUnserialize (FcCache metadata, void *block_ptr)
     return block_ptr;
 }
 
+/* we don't store these in the FcPattern itself because
+ * we don't want to serialize the directory names */
+
+/* I suppose this should be cleaned, too... */
+typedef struct _FcPatternDirMapping {
+    const FcPattern    *p;
+    const char *fname;
+} FcPatternDirMapping;
+
+#define PATTERNDIR_HASH_SIZE    31
+static struct patternDirBucket {
+    struct patternDirBucket    *next;
+    FcPatternDirMapping                m;
+} FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
+
+void
+FcPatternAddFullFname (const FcPattern *p, const char *fname)
+{
+    struct patternDirBucket    *pb;
+
+    /* N.B. FcPatternHash fails, since it's contents-based, not
+     * address-based, and we're in the process of mutating the FcPattern. */
+    for (pb = &FcPatternDirBuckets
+             [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
+         pb->m.p != p && pb->next; 
+         pb = pb->next)
+        ;
+
+    if (pb->m.p == p)
+    {
+        pb->m.fname = fname;
+        return;
+    }
+
+    pb->next = malloc (sizeof (struct patternDirBucket));
+    if (!pb->next)
+        return;
+    FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
+
+    pb->next->next = 0;
+    pb->next->m.p = p;
+    pb->next->m.fname = fname;
+}
+
+static const char *
+FcPatternFindFullFname (const FcPattern *p)
+{
+    struct patternDirBucket    *pb;
+
+    for (pb = &FcPatternDirBuckets
+             [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE]; 
+         pb; pb = pb->next)
+       if (pb->m.p == p)
+           return pb->m.fname;
+
+    return 0;
+}
+
+void
+FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
+{
+    FcChar8 * s;
+    FcPatternGetString (orig, FC_FILE, 0, &s);
+    FcPatternAddFullFname (new, 
+                          (char *)FcStrCopy 
+                          ((FcChar8 *)FcPatternFindFullFname(orig)));
+}