summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2008-04-23 09:07:28 +0100
committerBehdad Esfahbod <behdad@behdad.org>2009-02-13 16:54:00 -0800
commit311da2316f5d40d9b8c72c9965f7d70330f3c498 (patch)
tree834083347339d6932c5bc34b8a03f75cc9429259 /src
parent8072f4b1304efc59fee5e61efc4c4b0fc05bb8fb (diff)
Reduce number of allocations during FcSortWalk().
The current behaviour of FcSortWalk() is to create a new FcCharSet on each iteration that is the union of the previous iteration with the next FcCharSet in the font set. This causes the existing FcCharSet to be reproduced in its entirety and then allocates fresh leaves for the new FcCharSet. In essence the number of allocations is quadratic wrt the number of fonts required. By introducing a new method for merging a new FcCharSet with an existing one we can change the behaviour to be effectively linear with the number of fonts - allocating no more leaves than necessary to cover all the fonts in the set. For example, profiling 'gedit UTF-8-demo.txt' Allocator nAllocs nBytes Before: FcCharSetFindLeafCreate 62886 2012352 FcCharSetPutLeaf 9361 11441108 After: FcCharSetFindLeafCreate 1940 62080 FcCharSetPutLeaf 281 190336 The savings are even more significant for applications like firefox-3.0b5 which need to switch between large number of fonts. Before: FcCharSetFindLeafCreate 4461192 142758144 FcCharSetPutLeaf 1124536 451574172 After: FcCharSetFindLeafCreate 80359 2571488 FcCharSetPutLeaf 18940 9720522 Out of interest, the next most frequent allocations are FcPatternObjectAddWithBinding 526029 10520580 tt_face_load_eblc 42103 2529892
Diffstat (limited to 'src')
-rw-r--r--src/fccharset.c62
-rw-r--r--src/fcint.h3
-rw-r--r--src/fcmatch.c13
3 files changed, 68 insertions, 10 deletions
diff --git a/src/fccharset.c b/src/fccharset.c
index d42d78f3..98ced278 100644
--- a/src/fccharset.c
+++ b/src/fccharset.c
@@ -452,6 +452,68 @@ FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
}
+FcCharSet *
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSet *fcs;
+ FcCharSetIter ai, bi;
+
+ if (a == NULL) {
+ return FcCharSetCopy ((FcCharSet *) b);
+ } else if (a->ref == FC_REF_CONSTANT) {
+ fcs = FcCharSetCreate ();
+ if (fcs == NULL)
+ return NULL;
+ } else
+ fcs = a;
+
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while (ai.leaf || bi.leaf)
+ {
+ if (ai.ucs4 < bi.ucs4)
+ {
+ if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
+ goto bail;
+
+ FcCharSetIterNext (a, &ai);
+ }
+ else if (bi.ucs4 < ai.ucs4)
+ {
+ if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
+ goto bail;
+
+ FcCharSetIterNext (b, &bi);
+ }
+ else
+ {
+ FcCharLeaf leaf;
+
+ if (FcCharSetUnionLeaf (&leaf, ai.leaf, bi.leaf))
+ {
+ if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
+ goto bail;
+ }
+
+ FcCharSetIterNext (a, &ai);
+ FcCharSetIterNext (b, &bi);
+ }
+ }
+
+ if (fcs != a)
+ FcCharSetDestroy (a);
+
+ return fcs;
+
+bail:
+ FcCharSetDestroy (fcs);
+
+ if (fcs != a)
+ FcCharSetDestroy (a);
+
+ return NULL;
+}
+
static FcBool
FcCharSetSubtractLeaf (FcCharLeaf *result,
const FcCharLeaf *al,
diff --git a/src/fcint.h b/src/fcint.h
index 370dd7e8..9a768c24 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -641,6 +641,9 @@ FcNameParseCharSet (FcChar8 *string);
FcPrivate FcCharLeaf *
FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4);
+FcPrivate FcCharSet *
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b);
+
FcPrivate FcBool
FcCharSetSerializeAlloc(FcSerialize *serialize, const FcCharSet *cs);
diff --git a/src/fcmatch.c b/src/fcmatch.c
index b3ee5c12..77b49cf1 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -601,16 +601,9 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri
{
if (trim || build_cs)
{
- if (*cs)
- {
- ncs = FcCharSetUnion (ncs, *cs);
- if (!ncs)
- return FcFalse;
- FcCharSetDestroy (*cs);
- }
- else
- ncs = FcCharSetCopy (ncs);
- *cs = ncs;
+ *cs = FcCharSetMerge (*cs, ncs);
+ if (*cs == NULL)
+ return FcFalse;
}
FcPatternReference (node->pattern);