Change FcCharSetMerge API

To only work on writable charsets.  Also, return a bool indicating whether
the merge changed the charset.

Also changes the implementation of FcCharSetMerge and FcCharSetIsSubset
This commit is contained in:
Karl Tomlinson 2009-01-27 03:35:51 -05:00 committed by Behdad Esfahbod
parent b8860e2faf
commit 575ee6cddd
4 changed files with 113 additions and 128 deletions

View File

@ -98,17 +98,19 @@ Returns a set including only those chars found in either <parameter>a</parameter
Returns a set including only those chars found in <parameter>a</parameter> but not <parameter>b</parameter>.
@@
@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 <parameter>a</parameter> is NULL, returns a newly-created copy of <parameter>b</parameter>.
If <parameter>a</parameter> is an FcCharSet object owned by fontconfig that
cannot be modified, it returns the union of <parameter>a</parameter> and
<parameter>b</parameter> in a newly-created FcCharSet object.
Otherwise, adds all chars in <parameter>b</parameter> to <parameter>a</parameter> and returns <parameter>a</parameter>. In other words, this is an in-place versionof FcCharSetUnion.
Adds all chars in <parameter>b</parameter> to <parameter>a</parameter>.
In other words, this is an in-place version of FcCharSetUnion.
If <parameter>changed</parameter> is not NULL, then it returns whether any new
chars from <parameter>b</parameter> were added to <parameter>a</parameter>.
Returns FcFalse on failure, either when <parameter>a</parameter> is a constant
set or from running out of memory.
@@
@RET@ FcBool

View File

@ -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);

View File

@ -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;
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);
if (changed) {
*changed = !FcCharSetIsSubset(b, a);
if (!*changed)
return FcTrue;
}
else if (bi.ucs4 < ai.ucs4)
{
if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
goto bail;
FcCharSetIterNext (b, &bi);
while (bi < b->num)
{
an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
bn = FcCharSetNumbers(b)[bi];
if (an < bn)
{
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;
}
}
/*

View File

@ -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);