fontconfig/src/fccharset.c

1404 lines
29 KiB
C
Raw Normal View History

2002-02-15 00:34:13 +01:00
/*
2008-08-12 22:34:24 +02:00
* fontconfig/src/fccharset.c
2002-02-15 00:34:13 +01:00
*
2004-12-07 02:14:46 +01:00
* Copyright © 2001 Keith Packard
2002-02-15 00:34:13 +01:00
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the author(s) not be used in
2002-02-15 00:34:13 +01:00
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The authors make no
2002-02-15 00:34:13 +01:00
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2002-02-15 00:34:13 +01:00
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2002-02-15 00:34:13 +01:00
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "fcint.h"
#include <stdlib.h>
2002-02-15 00:34:13 +01:00
/* #define CHECK */
FcCharSet *
FcCharSetCreate (void)
{
FcCharSet *fcs;
fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
if (!fcs)
return 0;
FcRefInit (&fcs->ref, 1);
fcs->num = 0;
fcs->leaves_offset = 0;
fcs->numbers_offset = 0;
2002-02-15 00:34:13 +01:00
return fcs;
}
FcCharSet *
FcCharSetPromote (FcValuePromotionBuffer *vbuf)
{
FcCharSet *fcs = (FcCharSet *) vbuf;
FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer));
FcRefSetConst (&fcs->ref);
fcs->num = 0;
fcs->leaves_offset = 0;
fcs->numbers_offset = 0;
return fcs;
}
2002-02-15 00:34:13 +01:00
FcCharSet *
FcCharSetNew (void)
{
return FcCharSetCreate ();
}
void
FcCharSetDestroy (FcCharSet *fcs)
{
int i;
2010-04-12 18:18:50 +02:00
if (fcs)
{
if (FcRefIsConst (&fcs->ref))
{
FcCacheObjectDereference (fcs);
return;
}
if (FcRefDec (&fcs->ref) != 1)
return;
for (i = 0; i < fcs->num; i++)
free (FcCharSetLeaf (fcs, i));
if (fcs->num)
{
free (FcCharSetLeaves (fcs));
free (FcCharSetNumbers (fcs));
}
free (fcs);
}
2002-02-15 00:34:13 +01:00
}
/*
* 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
2002-02-15 00:34:13 +01:00
*/
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
* the (position + 1) where it should be inserted
*/
static int
FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
{
return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
}
2002-02-15 00:34:13 +01:00
static FcCharLeaf *
FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
{
int pos = FcCharSetFindLeafPos (fcs, ucs4);
if (pos >= 0)
return FcCharSetLeaf(fcs, pos);
return 0;
}
2002-02-15 00:34:13 +01:00
#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
static FcBool
2010-04-12 18:18:50 +02:00
FcCharSetPutLeaf (FcCharSet *fcs,
FcChar32 ucs4,
2010-04-12 18:18:50 +02:00
FcCharLeaf *leaf,
int pos)
{
intptr_t *leaves = FcCharSetLeaves (fcs);
FcChar16 *numbers = FcCharSetNumbers (fcs);
ucs4 >>= 8;
if (ucs4 >= 0x10000)
return FcFalse;
2009-06-05 22:57:35 +02:00
if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
{
if (!fcs->num)
{
unsigned int alloced = 8;
leaves = malloc (alloced * sizeof (*leaves));
numbers = malloc (alloced * sizeof (*numbers));
if (!leaves || !numbers)
{
if (leaves)
free (leaves);
if (numbers)
free (numbers);
return FcFalse;
}
}
else
{
int i;
unsigned int alloced = fcs->num;
intptr_t *new_leaves;
ptrdiff_t distance;
alloced *= 2;
numbers = realloc (numbers, alloced * sizeof (*numbers));
if (!numbers)
return FcFalse;
new_leaves = realloc (leaves, alloced * sizeof (*leaves));
if (!new_leaves)
{
/*
* Revert the reallocation of numbers. We update numbers_offset
* first in case realloc() fails.
*/
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
numbers = realloc (numbers, (alloced / 2) * sizeof (*numbers));
/* unlikely to fail though */
if (!numbers)
return FcFalse;
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
return FcFalse;
}
distance = (char *) new_leaves - (char *) leaves;
for (i = 0; i < fcs->num; i++) {
new_leaves[i] -= distance;
}
leaves = new_leaves;
}
fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
}
2010-04-12 18:18:50 +02:00
memmove (leaves + pos + 1, leaves + pos,
(fcs->num - pos) * sizeof (*leaves));
memmove (numbers + pos + 1, numbers + pos,
(fcs->num - pos) * sizeof (*numbers));
numbers[pos] = (FcChar16) ucs4;
leaves[pos] = FcPtrToOffset (leaves, leaf);
fcs->num++;
return FcTrue;
2002-02-15 00:34:13 +01:00
}
/*
* Locate the leaf containing the specified char, creating it
* if desired
*/
FcCharLeaf *
2002-02-15 00:34:13 +01:00
FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
{
int pos;
FcCharLeaf *leaf;
2002-02-15 00:34:13 +01:00
pos = FcCharSetFindLeafPos (fcs, ucs4);
if (pos >= 0)
return FcCharSetLeaf(fcs, pos);
2010-04-12 18:18:50 +02:00
leaf = calloc (1, sizeof (FcCharLeaf));
if (!leaf)
return 0;
2010-04-12 18:18:50 +02:00
pos = -pos - 1;
if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
2002-02-15 00:34:13 +01:00
{
free (leaf);
return 0;
2002-02-15 00:34:13 +01:00
}
return leaf;
}
static FcBool
FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
{
int pos;
pos = FcCharSetFindLeafPos (fcs, ucs4);
if (pos >= 0)
2002-02-15 00:34:13 +01:00
{
free (FcCharSetLeaf (fcs, pos));
FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
leaf);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
pos = -pos - 1;
return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
2002-02-15 00:34:13 +01:00
}
FcBool
FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
{
FcCharLeaf *leaf;
FcChar32 *b;
2010-04-12 18:18:50 +02:00
if (fcs == NULL || FcRefIsConst (&fcs->ref))
2002-02-15 00:34:13 +01:00
return FcFalse;
leaf = FcCharSetFindLeafCreate (fcs, ucs4);
if (!leaf)
return FcFalse;
b = &leaf->map[(ucs4 & 0xff) >> 5];
2018-01-09 10:54:55 +01:00
*b |= (1U << (ucs4 & 0x1f));
2002-02-15 00:34:13 +01:00
return FcTrue;
}
2010-09-21 19:14:41 +02:00
FcBool
FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
{
FcCharLeaf *leaf;
FcChar32 *b;
if (fcs == NULL || FcRefIsConst (&fcs->ref))
2010-09-21 19:14:41 +02:00
return FcFalse;
leaf = FcCharSetFindLeaf (fcs, ucs4);
if (!leaf)
return FcTrue;
b = &leaf->map[(ucs4 & 0xff) >> 5];
2018-01-09 10:54:55 +01:00
*b &= ~(1U << (ucs4 & 0x1f));
2010-09-21 19:14:41 +02:00
/* We don't bother removing the leaf if it's empty */
return FcTrue;
}
2002-02-15 00:34:13 +01:00
/*
* An iterator for the leaves of a charset
*/
typedef struct _fcCharSetIter {
FcCharLeaf *leaf;
FcChar32 ucs4;
int pos;
2002-02-15 00:34:13 +01:00
} FcCharSetIter;
/*
* Set iter->leaf to the leaf containing iter->ucs4 or higher
2002-02-15 00:34:13 +01:00
*/
static void
FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
{
int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
if (pos < 0)
{
pos = -pos - 1;
if (pos == fcs->num)
{
iter->ucs4 = ~0;
iter->leaf = 0;
return;
}
iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
}
iter->leaf = FcCharSetLeaf(fcs, pos);
iter->pos = pos;
2002-02-15 00:34:13 +01:00
}
static void
FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
{
int pos = iter->pos + 1;
if (pos >= fcs->num)
{
iter->ucs4 = ~0;
iter->leaf = 0;
}
else
{
iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
iter->leaf = FcCharSetLeaf(fcs, pos);
iter->pos = pos;
}
}
2002-02-15 00:34:13 +01:00
static void
FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
{
iter->ucs4 = 0;
iter->pos = 0;
2002-02-15 00:34:13 +01:00
FcCharSetIterSet (fcs, iter);
}
FcCharSet *
FcCharSetCopy (FcCharSet *src)
{
if (src)
{
if (!FcRefIsConst (&src->ref))
FcRefInc (&src->ref);
else
FcCacheObjectReference (src);
}
2002-02-15 00:34:13 +01:00
return src;
}
FcBool
FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
{
FcCharSetIter ai, bi;
int i;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (a == b)
return FcTrue;
if (!a || !b)
return FcFalse;
2002-02-15 00:34:13 +01:00
for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
ai.leaf && bi.leaf;
FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
{
if (ai.ucs4 != bi.ucs4)
return FcFalse;
for (i = 0; i < 256/32; i++)
if (ai.leaf->map[i] != bi.leaf->map[i])
return FcFalse;
}
return ai.leaf == bi.leaf;
}
static FcBool
FcCharSetAddLeaf (FcCharSet *fcs,
FcChar32 ucs4,
FcCharLeaf *leaf)
{
FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4);
if (!new)
return FcFalse;
*new = *leaf;
return FcTrue;
}
static FcCharSet *
FcCharSetOperate (const FcCharSet *a,
const FcCharSet *b,
FcBool (*overlap) (FcCharLeaf *result,
const FcCharLeaf *al,
const FcCharLeaf *bl),
FcBool aonly,
FcBool bonly)
{
FcCharSet *fcs;
FcCharSetIter ai, bi;
if (!a || !b)
goto bail0;
2002-02-15 00:34:13 +01:00
fcs = FcCharSetCreate ();
if (!fcs)
goto bail0;
FcCharSetIterStart (a, &ai);
FcCharSetIterStart (b, &bi);
while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
2002-02-15 00:34:13 +01:00
{
if (ai.ucs4 < bi.ucs4)
{
if (aonly)
{
if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
goto bail1;
FcCharSetIterNext (a, &ai);
}
else
{
ai.ucs4 = bi.ucs4;
FcCharSetIterSet (a, &ai);
}
}
else if (bi.ucs4 < ai.ucs4 )
{
if (bonly)
{
if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
goto bail1;
FcCharSetIterNext (b, &bi);
}
else
{
bi.ucs4 = ai.ucs4;
FcCharSetIterSet (b, &bi);
}
}
else
{
FcCharLeaf leaf;
if ((*overlap) (&leaf, ai.leaf, bi.leaf))
{
if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
goto bail1;
}
FcCharSetIterNext (a, &ai);
FcCharSetIterNext (b, &bi);
}
}
return fcs;
bail1:
FcCharSetDestroy (fcs);
bail0:
return 0;
}
static FcBool
FcCharSetIntersectLeaf (FcCharLeaf *result,
const FcCharLeaf *al,
const FcCharLeaf *bl)
{
int i;
FcBool nonempty = FcFalse;
for (i = 0; i < 256/32; i++)
if ((result->map[i] = al->map[i] & bl->map[i]))
nonempty = FcTrue;
return nonempty;
}
FcCharSet *
FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
{
return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
}
static FcBool
FcCharSetUnionLeaf (FcCharLeaf *result,
const FcCharLeaf *al,
const FcCharLeaf *bl)
{
int i;
for (i = 0; i < 256/32; i++)
result->map[i] = al->map[i] | bl->map[i];
return FcTrue;
}
FcCharSet *
FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
{
return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
}
FcBool
FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
{
int ai = 0, bi = 0;
FcChar16 an, bn;
if (!a || !b)
return FcFalse;
if (FcRefIsConst (&a->ref)) {
2009-06-05 23:15:53 +02:00
if (changed)
*changed = FcFalse;
return FcFalse;
2009-06-05 23:15:53 +02:00
}
if (changed) {
*changed = !FcCharSetIsSubset(b, a);
if (!*changed)
return FcTrue;
}
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 *bl = FcCharSetLeaf(b, bi);
if (bn < an)
{
if (!FcCharSetAddLeaf (a, bn << 8, bl))
return FcFalse;
}
else
{
FcCharLeaf *al = FcCharSetLeaf(a, ai);
FcCharSetUnionLeaf (al, al, bl);
}
ai++;
bi++;
}
}
return FcTrue;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcCharSetSubtractLeaf (FcCharLeaf *result,
const FcCharLeaf *al,
const FcCharLeaf *bl)
{
int i;
FcBool nonempty = FcFalse;
for (i = 0; i < 256/32; i++)
if ((result->map[i] = al->map[i] & ~bl->map[i]))
nonempty = FcTrue;
return nonempty;
}
FcCharSet *
FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
{
return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
}
FcBool
FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
{
FcCharLeaf *leaf;
if (!fcs)
return FcFalse;
leaf = FcCharSetFindLeaf (fcs, ucs4);
2002-02-15 00:34:13 +01:00
if (!leaf)
return FcFalse;
2018-01-09 10:54:55 +01:00
return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
2002-02-15 00:34:13 +01:00
}
static FcChar32
FcCharSetPopCount (FcChar32 c1)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
return __builtin_popcount (c1);
#else
2002-02-15 00:34:13 +01:00
/* hackmem 169 */
FcChar32 c2 = (c1 >> 1) & 033333333333;
c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
return (((c2 + (c2 >> 3)) & 030707070707) % 077);
#endif
2002-02-15 00:34:13 +01:00
}
FcChar32
FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
{
FcCharSetIter ai, bi;
FcChar32 count = 0;
2010-04-12 18:18:50 +02:00
if (a && b)
2002-02-15 00:34:13 +01:00
{
FcCharSetIterStart (a, &ai);
FcCharSetIterStart (b, &bi);
while (ai.leaf && bi.leaf)
2002-02-15 00:34:13 +01:00
{
if (ai.ucs4 == bi.ucs4)
{
FcChar32 *am = ai.leaf->map;
FcChar32 *bm = bi.leaf->map;
int i = 256/32;
while (i--)
count += FcCharSetPopCount (*am++ & *bm++);
FcCharSetIterNext (a, &ai);
}
else if (ai.ucs4 < bi.ucs4)
{
ai.ucs4 = bi.ucs4;
FcCharSetIterSet (a, &ai);
}
if (bi.ucs4 < ai.ucs4)
{
bi.ucs4 = ai.ucs4;
FcCharSetIterSet (b, &bi);
}
2002-02-15 00:34:13 +01:00
}
}
return count;
}
FcChar32
FcCharSetCount (const FcCharSet *a)
{
FcCharSetIter ai;
FcChar32 count = 0;
2010-04-12 18:18:50 +02:00
if (a)
2002-02-15 00:34:13 +01:00
{
for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
{
int i = 256/32;
FcChar32 *am = ai.leaf->map;
2002-02-15 00:34:13 +01:00
while (i--)
count += FcCharSetPopCount (*am++);
}
2002-02-15 00:34:13 +01:00
}
return count;
}
FcChar32
FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
{
FcCharSetIter ai, bi;
FcChar32 count = 0;
2010-04-12 18:18:50 +02:00
if (a && b)
2002-02-15 00:34:13 +01:00
{
FcCharSetIterStart (a, &ai);
FcCharSetIterStart (b, &bi);
while (ai.leaf)
2002-02-15 00:34:13 +01:00
{
if (ai.ucs4 <= bi.ucs4)
2002-02-15 00:34:13 +01:00
{
FcChar32 *am = ai.leaf->map;
int i = 256/32;
if (ai.ucs4 == bi.ucs4)
{
FcChar32 *bm = bi.leaf->map;
while (i--)
count += FcCharSetPopCount (*am++ & ~*bm++);
}
else
{
while (i--)
count += FcCharSetPopCount (*am++);
}
FcCharSetIterNext (a, &ai);
2002-02-15 00:34:13 +01:00
}
else if (bi.leaf)
2002-02-15 00:34:13 +01:00
{
bi.ucs4 = ai.ucs4;
FcCharSetIterSet (b, &bi);
2002-02-15 00:34:13 +01:00
}
}
}
return count;
}
/*
* return FcTrue iff a is a subset of b
*/
FcBool
FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
{
int ai, bi;
FcChar16 an, bn;
2010-04-12 18:18:50 +02:00
if (a == b)
return FcTrue;
if (!a || !b)
return FcFalse;
bi = 0;
ai = 0;
while (ai < a->num && bi < b->num)
{
an = FcCharSetNumbers(a)[ai];
bn = FcCharSetNumbers(b)[bi];
/*
* Check matching pages
*/
if (an == bn)
{
FcChar32 *am = FcCharSetLeaf(a, ai)->map;
FcChar32 *bm = FcCharSetLeaf(b, bi)->map;
2010-04-12 18:18:50 +02:00
if (am != bm)
{
int i = 256/32;
/*
* Does am have any bits not in bm?
*/
while (i--)
if (*am++ & ~*bm++)
return FcFalse;
}
ai++;
bi++;
}
/*
* Does a have any pages not in b?
*/
else if (an < bn)
return FcFalse;
else
{
bi = FcCharSetFindLeafForward (b, bi + 1, an);
if (bi < 0)
bi = -bi - 1;
}
}
/*
* did we look at every page?
*/
return ai >= a->num;
}
/*
* These two functions efficiently walk the entire charmap for
* other software (like pango) that want their own copy
*/
FcChar32
2010-04-12 18:18:50 +02:00
FcCharSetNextPage (const FcCharSet *a,
FcChar32 map[FC_CHARSET_MAP_SIZE],
FcChar32 *next)
{
FcCharSetIter ai;
FcChar32 page;
if (!a)
return FC_CHARSET_DONE;
ai.ucs4 = *next;
FcCharSetIterSet (a, &ai);
if (!ai.leaf)
return FC_CHARSET_DONE;
2010-04-12 18:18:50 +02:00
/*
* Save current information
*/
page = ai.ucs4;
memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
/*
* Step to next page
*/
FcCharSetIterNext (a, &ai);
*next = ai.ucs4;
return page;
}
FcChar32
2010-04-12 18:18:50 +02:00
FcCharSetFirstPage (const FcCharSet *a,
FcChar32 map[FC_CHARSET_MAP_SIZE],
FcChar32 *next)
{
*next = 0;
return FcCharSetNextPage (a, map, next);
}
/*
* old coverage API, rather hard to use correctly
*/
2010-04-12 18:18:50 +02:00
FcChar32
FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
{
FcCharSetIter ai;
ai.ucs4 = page;
FcCharSetIterSet (a, &ai);
if (!ai.leaf)
{
memset (result, '\0', 256 / 8);
page = 0;
}
else
{
memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
FcCharSetIterNext (a, &ai);
page = ai.ucs4;
}
return page;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast)
{
char *s = (char *) *string;
char *t;
long first, last;
while (isspace((unsigned char) *s))
s++;
t = s;
errno = 0;
first = last = strtol (s, &s, 16);
if (errno)
return FcFalse;
while (isspace((unsigned char) *s))
s++;
if (*s == '-')
2002-02-15 00:34:13 +01:00
{
s++;
errno = 0;
last = strtol (s, &s, 16);
if (errno)
2002-02-15 00:34:13 +01:00
return FcFalse;
}
if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff)
return FcFalse;
*string = (FcChar8 *) s;
*pfirst = first;
*plast = last;
return FcTrue;
2002-02-15 00:34:13 +01:00
}
FcCharSet *
FcNameParseCharSet (FcChar8 *string)
{
FcCharSet *c;
FcChar32 first, last;
c = FcCharSetCreate ();
if (!c)
goto bail0;
while (*string)
{
FcChar32 u;
if (!FcNameParseRange (&string, &first, &last))
goto bail1;
for (u = first; u < last + 1; u++)
FcCharSetAddChar (c, u);
}
return c;
bail1:
FcCharSetDestroy (c);
bail0:
return NULL;
}
static void
FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u)
{
FcChar8 buf_static[64];
snprintf ((char *) buf_static, sizeof (buf_static), "%x", u);
FcStrBufString (buf, buf_static);
}
FcBool
FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
{
FcCharSetIter ci;
FcChar32 first, last;
int i;
#ifdef CHECK
int len = buf->len;
#endif
first = last = 0x7FFFFFFF;
for (FcCharSetIterStart (c, &ci);
ci.leaf;
FcCharSetIterNext (c, &ci))
{
for (i = 0; i < 256/32; i++)
{
FcChar32 bits = ci.leaf->map[i];
FcChar32 u = ci.ucs4 + i * 32;
while (bits)
{
if (bits & 1)
{
if (u != last + 1)
{
if (last != first)
{
FcStrBufChar (buf, '-');
FcNameUnparseUnicode (buf, last);
}
if (last != 0x7FFFFFFF)
FcStrBufChar (buf, ' ');
/* Start new range. */
first = u;
FcNameUnparseUnicode (buf, u);
}
last = u;
}
bits >>= 1;
u++;
}
}
}
if (last != first)
{
FcStrBufChar (buf, '-');
FcNameUnparseUnicode (buf, last);
}
#ifdef CHECK
{
FcCharSet *check;
FcChar32 missing;
FcCharSetIter ci, checki;
/* null terminate for parser */
FcStrBufChar (buf, '\0');
/* step back over null for life after test */
buf->len--;
check = FcNameParseCharSet (buf->buf + len);
FcCharSetIterStart (c, &ci);
FcCharSetIterStart (check, &checki);
while (ci.leaf || checki.leaf)
{
if (ci.ucs4 < checki.ucs4)
{
printf ("Missing leaf node at 0x%x\n", ci.ucs4);
FcCharSetIterNext (c, &ci);
}
else if (checki.ucs4 < ci.ucs4)
{
printf ("Extra leaf node at 0x%x\n", checki.ucs4);
FcCharSetIterNext (check, &checki);
}
else
{
int i = 256/32;
FcChar32 *cm = ci.leaf->map;
FcChar32 *checkm = checki.leaf->map;
for (i = 0; i < 256; i += 32)
{
if (*cm != *checkm)
printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
ci.ucs4 + i, *cm, *checkm);
cm++;
checkm++;
}
FcCharSetIterNext (c, &ci);
FcCharSetIterNext (check, &checki);
}
}
if ((missing = FcCharSetSubtractCount (c, check)))
printf ("%d missing in reparsed result\n", missing);
if ((missing = FcCharSetSubtractCount (check, c)))
printf ("%d extra in reparsed result\n", missing);
FcCharSetDestroy (check);
}
#endif
2010-04-12 18:18:50 +02:00
return FcTrue;
}
typedef struct _FcCharLeafEnt FcCharLeafEnt;
struct _FcCharLeafEnt {
FcCharLeafEnt *next;
FcChar32 hash;
FcCharLeaf leaf;
};
#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
#define FC_CHAR_LEAF_HASH_SIZE 257
typedef struct _FcCharSetEnt FcCharSetEnt;
struct _FcCharSetEnt {
FcCharSetEnt *next;
FcChar32 hash;
FcCharSet set;
};
typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
struct _FcCharSetOrigEnt {
FcCharSetOrigEnt *next;
const FcCharSet *orig;
const FcCharSet *frozen;
};
#define FC_CHAR_SET_HASH_SIZE 67
struct _FcCharSetFreezer {
FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
FcCharLeafEnt **leaf_blocks;
int leaf_block_count;
FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE];
FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE];
FcCharLeafEnt *current_block;
int leaf_remain;
int leaves_seen;
int charsets_seen;
int leaves_allocated;
int charsets_allocated;
};
static FcCharLeafEnt *
FcCharLeafEntCreate (FcCharSetFreezer *freezer)
{
if (!freezer->leaf_remain)
{
FcCharLeafEnt **newBlocks;
freezer->leaf_block_count++;
newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
if (!newBlocks)
return 0;
freezer->leaf_blocks = newBlocks;
freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
if (!freezer->current_block)
return 0;
freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
}
freezer->leaf_remain--;
freezer->leaves_allocated++;
return freezer->current_block++;
}
static FcChar32
FcCharLeafHash (FcCharLeaf *leaf)
{
FcChar32 hash = 0;
int i;
for (i = 0; i < 256/32; i++)
hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
return hash;
}
static FcCharLeaf *
FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
{
FcChar32 hash = FcCharLeafHash (leaf);
FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
FcCharLeafEnt *ent;
2010-04-12 18:18:50 +02:00
for (ent = *bucket; ent; ent = ent->next)
{
if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
return &ent->leaf;
}
ent = FcCharLeafEntCreate(freezer);
if (!ent)
return 0;
ent->leaf = *leaf;
ent->hash = hash;
ent->next = *bucket;
*bucket = ent;
return &ent->leaf;
}
static FcChar32
FcCharSetHash (FcCharSet *fcs)
{
FcChar32 hash = 0;
int i;
/* hash in leaves */
for (i = 0; i < fcs->num; i++)
hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i));
/* hash in numbers */
for (i = 0; i < fcs->num; i++)
hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers(fcs)[i];
return hash;
}
static FcBool
FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
{
FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
FcCharSetOrigEnt *ent;
2010-04-12 18:18:50 +02:00
ent = malloc (sizeof (FcCharSetOrigEnt));
if (!ent)
return FcFalse;
ent->orig = orig;
ent->frozen = frozen;
ent->next = *bucket;
*bucket = ent;
return FcTrue;
}
static FcCharSet *
2012-12-30 04:32:56 +01:00
FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
{
FcChar32 hash = FcCharSetHash (fcs);
FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
FcCharSetEnt *ent;
int size;
int i;
for (ent = *bucket; ent; ent = ent->next)
{
if (ent->hash == hash &&
ent->set.num == fcs->num &&
2010-04-12 18:18:50 +02:00
!memcmp (FcCharSetNumbers(&ent->set),
FcCharSetNumbers(fcs),
fcs->num * sizeof (FcChar16)))
{
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcBool ok = FcTrue;
int i;
for (i = 0; i < fcs->num; i++)
if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
ok = FcFalse;
if (ok)
return &ent->set;
}
}
size = (sizeof (FcCharSetEnt) +
fcs->num * sizeof (FcCharLeaf *) +
fcs->num * sizeof (FcChar16));
ent = malloc (size);
if (!ent)
return 0;
2010-04-12 18:18:50 +02:00
freezer->charsets_allocated++;
2010-04-12 18:18:50 +02:00
FcRefSetConst (&ent->set.ref);
ent->set.num = fcs->num;
if (fcs->num)
{
intptr_t *ent_leaves;
ent->set.leaves_offset = sizeof (ent->set);
ent->set.numbers_offset = (ent->set.leaves_offset +
fcs->num * sizeof (intptr_t));
2010-04-12 18:18:50 +02:00
ent_leaves = FcCharSetLeaves (&ent->set);
for (i = 0; i < fcs->num; i++)
ent_leaves[i] = FcPtrToOffset (ent_leaves,
FcCharSetLeaf (fcs, i));
2010-04-12 18:18:50 +02:00
memcpy (FcCharSetNumbers (&ent->set),
FcCharSetNumbers (fcs),
fcs->num * sizeof (FcChar16));
}
else
{
ent->set.leaves_offset = 0;
ent->set.numbers_offset = 0;
}
ent->hash = hash;
ent->next = *bucket;
*bucket = ent;
return &ent->set;
}
static const FcCharSet *
FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
{
FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
FcCharSetOrigEnt *ent;
2010-04-12 18:18:50 +02:00
for (ent = *bucket; ent; ent = ent->next)
if (ent->orig == orig)
return ent->frozen;
return NULL;
}
const FcCharSet *
FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
{
FcCharSet *b;
const FcCharSet *n = 0;
FcCharLeaf *l;
int i;
b = FcCharSetCreate ();
if (!b)
goto bail0;
for (i = 0; i < fcs->num; i++)
{
l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
if (!l)
goto bail1;
if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
goto bail1;
}
2012-12-30 04:32:56 +01:00
n = FcCharSetFreezeBase (freezer, b);
if (!FcCharSetFreezeOrig (freezer, fcs, n))
{
n = NULL;
goto bail1;
}
freezer->charsets_seen++;
freezer->leaves_seen += fcs->num;
bail1:
if (b->num)
free (FcCharSetLeaves (b));
if (b->num)
free (FcCharSetNumbers (b));
free (b);
bail0:
return n;
}
FcCharSetFreezer *
FcCharSetFreezerCreate (void)
2002-02-15 00:34:13 +01:00
{
FcCharSetFreezer *freezer;
2002-02-15 00:34:13 +01:00
freezer = calloc (1, sizeof (FcCharSetFreezer));
return freezer;
2002-02-15 00:34:13 +01:00
}
void
FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
2002-02-15 00:34:13 +01:00
{
int i;
2002-02-15 00:34:13 +01:00
if (FcDebug() & FC_DBG_CACHE)
2002-02-15 00:34:13 +01:00
{
printf ("\ncharsets %d -> %d leaves %d -> %d\n",
freezer->charsets_seen, freezer->charsets_allocated,
freezer->leaves_seen, freezer->leaves_allocated);
2002-02-15 00:34:13 +01:00
}
for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
2002-02-15 00:34:13 +01:00
{
FcCharSetEnt *ent, *next;
for (ent = freezer->set_hash_table[i]; ent; ent = next)
2002-02-15 00:34:13 +01:00
{
next = ent->next;
free (ent);
}
}
2002-02-15 00:34:13 +01:00
for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
{
FcCharSetOrigEnt *ent, *next;
for (ent = freezer->orig_hash_table[i]; ent; ent = next)
{
next = ent->next;
free (ent);
2002-02-15 00:34:13 +01:00
}
}
for (i = 0; i < freezer->leaf_block_count; i++)
free (freezer->leaf_blocks[i]);
free (freezer->leaf_blocks);
free (freezer);
2002-02-15 00:34:13 +01:00
}
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcBool
FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
{
intptr_t *leaves;
FcChar16 *numbers;
int i;
2010-04-12 18:18:50 +02:00
if (!FcRefIsConst (&cs->ref))
{
if (!serialize->cs_freezer)
{
serialize->cs_freezer = FcCharSetFreezerCreate ();
if (!serialize->cs_freezer)
return FcFalse;
}
if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
return FcTrue;
2010-04-12 18:18:50 +02:00
cs = FcCharSetFreeze (serialize->cs_freezer, cs);
}
2010-04-12 18:18:50 +02:00
leaves = FcCharSetLeaves (cs);
numbers = FcCharSetNumbers (cs);
2010-04-12 18:18:50 +02:00
if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
return FcFalse;
if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
return FcFalse;
if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
return FcFalse;
for (i = 0; i < cs->num; i++)
if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
sizeof (FcCharLeaf)))
return FcFalse;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
return FcTrue;
}
2010-04-12 18:18:50 +02:00
FcCharSet *
FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
{
FcCharSet *cs_serialized;
intptr_t *leaves, *leaves_serialized;
FcChar16 *numbers, *numbers_serialized;
FcCharLeaf *leaf, *leaf_serialized;
int i;
if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer)
{
cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
if (!cs)
return NULL;
}
2010-04-12 18:18:50 +02:00
cs_serialized = FcSerializePtr (serialize, cs);
if (!cs_serialized)
return NULL;
2010-04-12 18:18:50 +02:00
FcRefSetConst (&cs_serialized->ref);
cs_serialized->num = cs->num;
if (cs->num)
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
{
leaves = FcCharSetLeaves (cs);
leaves_serialized = FcSerializePtr (serialize, leaves);
if (!leaves_serialized)
return NULL;
2010-04-12 18:18:50 +02:00
cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
leaves_serialized);
numbers = FcCharSetNumbers (cs);
numbers_serialized = FcSerializePtr (serialize, numbers);
if (!numbers)
return NULL;
2010-04-12 18:18:50 +02:00
cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
numbers_serialized);
2010-04-12 18:18:50 +02:00
for (i = 0; i < cs->num; i++)
{
leaf = FcCharSetLeaf (cs, i);
leaf_serialized = FcSerializePtr (serialize, leaf);
if (!leaf_serialized)
return NULL;
*leaf_serialized = *leaf;
2010-04-12 18:18:50 +02:00
leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
leaf_serialized);
numbers_serialized[i] = numbers[i];
}
}
else
{
cs_serialized->leaves_offset = 0;
cs_serialized->numbers_offset = 0;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
}
2010-04-12 18:18:50 +02:00
return cs_serialized;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
}
#define __fccharset__
#include "fcaliastail.h"
#undef __fccharset__