X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=src%2Ffcpat.c;h=c37936f397133993fbaac14eb38382461551b9cb;hb=4f8b266fd97e36961639c40d93225265c0f849c7;hp=bffaca3cc47c4712885f15e06e87d41d0304c6bc;hpb=07b3e5766332ad1b2ec0ae613476a123ec9c5453;p=fontconfig.git diff --git a/src/fcpat.c b/src/fcpat.c index bffaca3..c37936f 100644 --- a/src/fcpat.c +++ b/src/fcpat.c @@ -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); @@ -331,7 +346,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 +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 */ @@ -792,7 +814,7 @@ FcPatternHash (const FcPattern *p) for (i = 0; i < p->num; i++) { h = (((h << 1) | (h >> 31)) ^ - FcStringHash (FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^ + FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^ FcValueListHash ((FcPatternEltU(p->elts)+i)->values)); } return h; @@ -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; } @@ -1215,9 +1280,11 @@ 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; } + FcPatternTransferFullFname (new, orig); return new; @@ -1280,34 +1347,33 @@ FcPatternAppend (FcPattern *p, FcPattern *s) } #define OBJECT_HASH_SIZE 31 -struct objectBucket { +static struct objectBucket { struct objectBucket *next; FcChar32 hash; -}; -static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE]; - -const char * -FcStrStaticName (const char *name) -{ - FcChar32 hash = FcStringHash ((const FcChar8 *) name); - struct objectBucket **p; - struct objectBucket *b; - int size; - - for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next) -) - if (b->hash == hash && !strcmp (name, (char *) (b + 1))) - return (char *) (b + 1); - size = sizeof (struct objectBucket) + strlen (name) + 1; - b = malloc (size); - FcMemAlloc (FC_MEM_STATICSTR, size); +} *FcObjectBuckets[OBJECT_HASH_SIZE]; + +const FcChar8 * +FcStrStaticName (const FcChar8 *name) +{ + FcChar32 hash = FcStringHash (name); + struct objectBucket **p; + struct objectBucket *b; + int size; + + for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + 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 + 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; b->hash = hash; - strcpy ((char *) (b + 1), name); + strcpy ((char *) (b + 1), (char *)name); *p = b; - return (char *) (b + 1); + return (FcChar8 *) (b + 1); } static void @@ -1370,11 +1436,13 @@ FcPatternEltPtrCreateStatic (int bank, int i) static void FcStrNewBank (void); static int -FcStrNeededBytes (const char * s); +FcStrNeededBytes (const FcChar8 * s); +static int +FcStrNeededBytesAlign (void); static void * FcStrDistributeBytes (FcCache * metadata, void * block_ptr); -static const char * -FcStrSerialize (int bank, const char * s); +static const FcChar8 * +FcStrSerialize (int bank, const FcChar8 * s); static void * FcStrUnserialize (FcCache metadata, void *block_ptr); @@ -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,16 +1752,17 @@ 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) { case FcTypeString: if (v->u.s) { - const char * s = FcStrSerialize(bank, v->u.s); + const FcChar8 * s = FcStrSerialize(bank, v->u.s); if (!s) return FcValueListPtrCreateDynamic(pi); - v->u.s_off = s - (const char *)v; + v->u.s_off = s - (const FcChar8 *)v; v->type |= FC_STORAGE_STATIC; } break; @@ -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)); @@ -1743,7 +1834,7 @@ FcValueListPtrCreateDynamic(FcValueList * p) return r; } -static char ** static_strs; +static FcChar8 ** static_strs; static int static_str_bank_count = 0, fcstr_ptr, fcstr_count; static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE]; @@ -1772,7 +1863,7 @@ FcStrNewBank (void) } static int -FcStrNeededBytes (const char * s) +FcStrNeededBytes (const FcChar8 * s) { FcChar32 hash = FcStringHash ((const FcChar8 *) s); struct objectBucket **p; @@ -1780,27 +1871,38 @@ FcStrNeededBytes (const char * s) int size; for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) - if (b->hash == hash && !strcmp (s, (char *) (b + 1))) + if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1))) return 0; - size = sizeof (struct objectBucket) + strlen (s) + 1 + sizeof(char *); + size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *); b = malloc (size); FcMemAlloc (FC_MEM_STATICSTR, size); if (!b) return -1; b->next = 0; b->hash = hash; - strcpy ((char *) (b + 1), s); - *(char **)((char *) (b + 1) + strlen(s) + 1) = 0; + 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; - fcstr_count += strlen(s) + 1; - return strlen(s) + 1; + fcstr_count += strlen((char *)s) + 1; + return strlen((char *)s) + 1; +} + +static int +FcStrNeededBytesAlign (void) +{ + return __alignof__ (char); } static FcBool FcStrEnsureBank (int bi) { - char ** ss; + FcChar8 ** ss; if (!static_strs || static_str_bank_count <= bi) { @@ -1827,7 +1929,8 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr) return 0; FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count); - static_strs[bi] = (char *)block_ptr; + 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; fcstr_ptr = 0; @@ -1835,8 +1938,8 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr) return block_ptr; } -static const char * -FcStrSerialize (int bank, const char * s) +static const FcChar8 * +FcStrSerialize (int bank, const FcChar8 * s) { FcChar32 hash = FcStringHash ((const FcChar8 *) s); struct objectBucket **p; @@ -1844,15 +1947,15 @@ FcStrSerialize (int bank, const char * s) int bi = FcCacheBankToIndex(bank); for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) - if (b->hash == hash && !strcmp (s, (char *) (b + 1))) + if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1))) { - char * t = *(char **)(((char *)(b + 1)) + strlen (s) + 1); + FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1); if (!t) { - strcpy(static_strs[bi] + fcstr_ptr, s); - *(char **)((char *) (b + 1) + strlen(s) + 1) = (static_strs[bi] + fcstr_ptr); - fcstr_ptr += strlen(s) + 1; - t = *(char **)(((char *)(b + 1)) + strlen (s) + 1); + strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s); + *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr); + fcstr_ptr += strlen((char *)s) + 1; + t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1); } return t; } @@ -1867,10 +1970,78 @@ FcStrUnserialize (FcCache metadata, void *block_ptr) return 0; FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count); - static_strs[bi] = (char *)block_ptr; + block_ptr = ALIGN (block_ptr, FcChar8); + static_strs[bi] = (FcChar8 *)block_ptr; block_ptr = (void *)((char *)block_ptr + (sizeof (char) * metadata.str_count)); 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))); +}