diff --git a/doc/fccharset.fncs b/doc/fccharset.fncs
index 0dd7d1a..de06aa4 100644
--- a/doc/fccharset.fncs
+++ b/doc/fccharset.fncs
@@ -98,17 +98,19 @@ Returns a set including only those chars found in either aa but not b.
@@
-@RET@ FcCharSet *
+@RET@ FcBool
@FUNC@ FcCharSetMerge
-@TYPE1@ const FcCharSet * @ARG1@ a
+@TYPE1@ FcCharSet * @ARG1@ a
@TYPE2@ const FcCharSet * @ARG2@ b
+@TYPE3@ FcBool * @ARG3@ changed
@PURPOSE@ Merge charsets
@DESC@
-If a is NULL, returns a newly-created copy of b.
-If a is an FcCharSet object owned by fontconfig that
-cannot be modified, it returns the union of a and
-b in a newly-created FcCharSet object.
-Otherwise, adds all chars in b to a and returns a. In other words, this is an in-place versionof FcCharSetUnion.
+Adds all chars in b to a.
+In other words, this is an in-place version of FcCharSetUnion.
+If changed is not NULL, then it returns whether any new
+chars from b were added to a.
+Returns FcFalse on failure, either when a is a constant
+set or from running out of memory.
@@
@RET@ FcBool
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index 606580d..99e2f04 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -439,8 +439,8 @@ FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
FcPublic FcCharSet*
FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b);
-FcPublic FcCharSet *
-FcCharSetMerge (FcCharSet *a, const FcCharSet *b);
+FcPublic FcBool
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed);
FcPublic FcBool
FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4);
diff --git a/src/fccharset.c b/src/fccharset.c
index 2daa39d..1885c26 100644
--- a/src/fccharset.c
+++ b/src/fccharset.c
@@ -80,6 +80,39 @@ FcCharSetDestroy (FcCharSet *fcs)
free (fcs);
}
+/*
+ * Search for the leaf containing with the specified num.
+ * Return its index if it exists, otherwise return negative of
+ * the (position + 1) where it should be inserted
+ */
+
+
+static int
+FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
+{
+ FcChar16 *numbers = FcCharSetNumbers(fcs);
+ FcChar16 page;
+ int low = start;
+ int high = fcs->num - 1;
+
+ if (!numbers)
+ return -1;
+ while (low <= high)
+ {
+ int mid = (low + high) >> 1;
+ page = numbers[mid];
+ if (page == num)
+ return mid;
+ if (page < num)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+ if (high < 0 || (high < fcs->num && numbers[high] < num))
+ high++;
+ return -(high + 1);
+}
+
/*
* Locate the leaf containing the specified char, return
* its index if it exists, otherwise return negative of
@@ -89,28 +122,7 @@ FcCharSetDestroy (FcCharSet *fcs)
static int
FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
{
- FcChar16 *numbers = FcCharSetNumbers(fcs);
- FcChar16 page;
- int low = 0;
- int high = fcs->num - 1;
-
- if (!numbers)
- return -1;
- ucs4 >>= 8;
- while (low <= high)
- {
- int mid = (low + high) >> 1;
- page = numbers[mid];
- if (page == ucs4)
- return mid;
- if (page < ucs4)
- low = mid + 1;
- else
- high = mid - 1;
- }
- if (high < 0 || (high < fcs->num && numbers[high] < ucs4))
- high++;
- return -(high + 1);
+ return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
}
static FcCharLeaf *
@@ -452,67 +464,52 @@ FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
}
-FcCharSet *
-FcCharSetMerge (FcCharSet *a, const FcCharSet *b)
+FcBool
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
{
- FcCharSet *fcs;
- FcCharSetIter ai, bi;
+ int ai = 0, bi = 0;
+ FcChar16 an, bn;
- if (a == NULL) {
- fcs = a = FcCharSetCreate ();
- } else if (a->ref == FC_REF_CONSTANT) {
- fcs = FcCharSetCreate ();
- } else
- fcs = a;
+ if (a->ref == FC_REF_CONSTANT)
+ return FcFalse;
- if (fcs == NULL)
- return NULL;
+ if (changed) {
+ *changed = !FcCharSetIsSubset(b, a);
+ if (!*changed)
+ return FcTrue;
+ }
- FcCharSetIterStart (a, &ai);
- FcCharSetIterStart (b, &bi);
- while (ai.leaf || bi.leaf)
+ while (bi < b->num)
{
- if (ai.ucs4 < bi.ucs4)
- {
- if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
- goto bail;
+ an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
+ bn = FcCharSetNumbers(b)[bi];
- FcCharSetIterNext (a, &ai);
- }
- else if (bi.ucs4 < ai.ucs4)
+ if (an < bn)
{
- if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
- goto bail;
-
- FcCharSetIterNext (b, &bi);
+ ai = FcCharSetFindLeafForward (a, ai + 1, bn);
+ if (ai < 0)
+ ai = -ai - 1;
}
else
{
- FcCharLeaf leaf;
-
- if (FcCharSetUnionLeaf (&leaf, ai.leaf, bi.leaf))
+ FcCharLeaf *bl = FcCharSetLeaf(b, bi);
+ if (bn < an)
{
- if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
- goto bail;
+ if (!FcCharSetAddLeaf (a, bn << 8, bl))
+ return FcFalse;
+ }
+ else
+ {
+ FcCharLeaf *al = FcCharSetLeaf(a, ai);
+ FcCharSetUnionLeaf (al, al, bl);
}
- FcCharSetIterNext (a, &ai);
- FcCharSetIterNext (b, &bi);
+ ai++;
+ bi++;
}
}
- if (fcs != a)
- FcCharSetDestroy (a);
-
- return fcs;
-
-bail:
- FcCharSetDestroy (fcs);
-
- if (fcs != a)
- FcCharSetDestroy (a);
-
- return NULL;
+ return FcTrue;
}
static FcBool
@@ -687,29 +684,9 @@ FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
return FcFalse;
else
{
- int low = bi + 1;
- int high = b->num - 1;
-
- /*
- * Search for page 'an' in 'b'
- */
- while (low <= high)
- {
- int mid = (low + high) >> 1;
- bn = FcCharSetNumbers(b)[mid];
- if (bn == an)
- {
- high = mid;
- break;
- }
- if (bn < an)
- low = mid + 1;
- else
- high = mid - 1;
- }
- bi = high;
- while (bi < b->num && FcCharSetNumbers(b)[bi] < an)
- bi++;
+ bi = FcCharSetFindLeafForward (b, bi + 1, an);
+ if (bi < 0)
+ bi = -bi - 1;
}
}
/*
diff --git a/src/fcmatch.c b/src/fcmatch.c
index b86cbbc..e06444c 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -606,38 +606,45 @@ FcSortCompare (const void *aa, const void *ab)
}
static FcBool
-FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim, FcBool build_cs)
+FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
{
- FcCharSet *ncs;
- FcSortNode *node;
+ FcBool ret = FcFalse;
+ FcCharSet *cs;
+
+ cs = 0;
+ if (trim || csp)
+ {
+ cs = FcCharSetCreate ();
+ if (cs == NULL)
+ goto bail;
+ }
while (nnode--)
{
- node = *n++;
+ FcSortNode *node = *n++;
+ FcBool adds_chars = FcFalse;
/*
* Only fetch node charset if we'd need it
*/
- if (trim || build_cs)
+ if (cs)
{
+ FcCharSet *ncs;
+
if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
FcResultMatch)
continue;
+
+ if (!FcCharSetMerge (cs, ncs, &adds_chars))
+ goto bail;
}
/*
* If this font isn't a subset of the previous fonts,
* add it to the list
*/
- if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
+ if (!trim || adds_chars)
{
- if (trim || build_cs)
- {
- *cs = FcCharSetMerge (*cs, ncs);
- if (*cs == NULL)
- return FcFalse;
- }
-
FcPatternReference (node->pattern);
if (FcDebug () & FC_DBG_MATCHV)
{
@@ -647,11 +654,23 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri
if (!FcFontSetAdd (fs, node->pattern))
{
FcPatternDestroy (node->pattern);
- return FcFalse;
+ goto bail;
}
}
}
- return FcTrue;
+ if (csp)
+ {
+ *csp = cs;
+ cs = 0;
+ }
+
+ ret = FcTrue;
+
+bail:
+ if (cs)
+ FcCharSetDestroy (cs);
+
+ return ret;
}
void
@@ -675,7 +694,6 @@ FcFontSetSort (FcConfig *config,
FcSortNode **nodeps, **nodep;
int nnodes;
FcSortNode *new;
- FcCharSet *cs;
int set;
int f;
int i;
@@ -803,19 +821,9 @@ FcFontSetSort (FcConfig *config,
if (!ret)
goto bail1;
- cs = 0;
-
- if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim, (csp!=0)))
+ if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
goto bail2;
- if (csp)
- *csp = cs;
- else
- {
- if (cs)
- FcCharSetDestroy (cs);
- }
-
free (nodes);
if (FcDebug() & FC_DBG_MATCH)
@@ -826,8 +834,6 @@ FcFontSetSort (FcConfig *config,
return ret;
bail2:
- if (cs)
- FcCharSetDestroy (cs);
FcFontSetDestroy (ret);
bail1:
free (nodes);