]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcpat.c
Copy the full pathname whenever duplicating an FcPattern; otherwise,
[fontconfig.git] / src / fcpat.c
index 9600d33a614564d2ebc1dae1c4539e6155aae772..b7f52793c6e63a0515038a53660e4a0776c037b8 100644 (file)
@@ -34,6 +34,8 @@ 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);
 
@@ -295,6 +297,9 @@ FcPatternDestroy (FcPattern *p)
 {
     int                    i;
     
+    if (FcPatternFindFullFname (p))
+       FcPatternAddFullFname (p, 0);
+
     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
        return;
 
@@ -331,7 +336,7 @@ typedef union _FcValueListAlign {
 
 static int         FcValueListFrozenCount[FcTypeLangSet + 1];
 static int         FcValueListFrozenBytes[FcTypeLangSet + 1];
-static char        *FcValueListFrozenName[] = {
+static char        FcValueListFrozenName[][8] = {
     "Void", 
     "Integer", 
     "Double", 
@@ -577,6 +582,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 +652,10 @@ FcPatternFreeze (FcPattern *p)
        if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
            goto bail;
     }
+
+    if (FcPatternFindElt (p, FC_FILE))
+       FcPatternTransferFullFname (b, p);
+
     /*
      * Freeze base
      */
@@ -1115,6 +1127,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;
 }
@@ -1215,8 +1263,16 @@ FcPatternDuplicate (const FcPattern *orig)
             FcValueListPtrU(l); 
             l = FcValueListPtrU(l)->next)
            if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
-                               FcValueListPtrU(l)->value, FcTrue))
+                               FcValueCanonicalize(&FcValueListPtrU(l)->value),
+                              FcTrue))
                goto bail1;
+
+       if (!strcmp ((char *)FcObjectPtrU((e + i)->object), FC_FILE))
+       {
+           FcChar8 * s;
+           FcPatternGetString (orig, FC_FILE, 0, &s);
+           FcPatternAddFullFname (new, FcPatternFindFullFname(orig));
+       }
     }
 
     return new;
@@ -1297,8 +1353,9 @@ FcStrStaticName (const FcChar8 *name)
        if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
            return (FcChar8 *) (b + 1);
     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
-    b = malloc (size);
-    FcMemAlloc (FC_MEM_STATICSTR, size);
+    b = malloc (size + sizeof (int));
+    /* workaround glibc bug which reads strlen in groups of 4 */
+    FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
     if (!b)
         return NULL;
     b->next = 0;
@@ -1872,3 +1929,68 @@ 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, FcPatternFindFullFname(orig));
+}