aboutsummaryrefslogtreecommitdiff
path: root/fontconfig/src/fccharset.c
diff options
context:
space:
mode:
Diffstat (limited to 'fontconfig/src/fccharset.c')
-rw-r--r--fontconfig/src/fccharset.c2861
1 files changed, 1439 insertions, 1422 deletions
diff --git a/fontconfig/src/fccharset.c b/fontconfig/src/fccharset.c
index d30e1614a..54e396bce 100644
--- a/fontconfig/src/fccharset.c
+++ b/fontconfig/src/fccharset.c
@@ -1,1422 +1,1439 @@
-/*
- * fontconfig/src/fccharset.c
- *
- * Copyright © 2001 Keith Packard
- *
- * 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 Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * 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,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * 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>
-
-/* #define CHECK */
-
-FcCharSet *
-FcCharSetCreate (void)
-{
- FcCharSet *fcs;
-
- fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
- if (!fcs)
- return 0;
- FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
- fcs->ref = 1;
- fcs->num = 0;
- fcs->leaves_offset = 0;
- fcs->numbers_offset = 0;
- return fcs;
-}
-
-FcCharSet *
-FcCharSetNew (void)
-{
- return FcCharSetCreate ();
-}
-
-void
-FcCharSetDestroy (FcCharSet *fcs)
-{
- int i;
-
- if (fcs->ref == FC_REF_CONSTANT)
- {
- FcCacheObjectDereference (fcs);
- return;
- }
- if (--fcs->ref > 0)
- return;
- for (i = 0; i < fcs->num; i++)
- {
- FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- free (FcCharSetLeaf (fcs, i));
- }
- if (fcs->num)
- {
- /* the numbers here are estimates */
- FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
- free (FcCharSetLeaves (fcs));
- FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
- free (FcCharSetNumbers (fcs));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- 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
- * the (position + 1) where it should be inserted
- */
-
-static int
-FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
-{
- return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
-}
-
-static FcCharLeaf *
-FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
-{
- int pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- return FcCharSetLeaf(fcs, pos);
- return 0;
-}
-
-#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
-
-static FcBool
-FcCharSetPutLeaf (FcCharSet *fcs,
- FcChar32 ucs4,
- FcCharLeaf *leaf,
- int pos)
-{
- intptr_t *leaves = FcCharSetLeaves (fcs);
- FcChar16 *numbers = FcCharSetNumbers (fcs);
-
- ucs4 >>= 8;
- if (ucs4 >= 0x10000)
- return FcFalse;
-
- if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
- {
- if (!fcs->num)
- {
- unsigned int alloced = 8;
- leaves = malloc (alloced * sizeof (*leaves));
- numbers = malloc (alloced * sizeof (*numbers));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
- }
- else
- {
- unsigned int alloced = fcs->num;
- intptr_t *new_leaves, distance;
-
- FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers));
-
- alloced *= 2;
- new_leaves = realloc (leaves, alloced * sizeof (*leaves));
- numbers = realloc (numbers, alloced * sizeof (*numbers));
-
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
- FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
-
- distance = (intptr_t) new_leaves - (intptr_t) leaves;
- if (new_leaves && distance)
- {
- int i;
- for (i = 0; i < fcs->num; i++)
- new_leaves[i] -= distance;
- }
- leaves = new_leaves;
- }
-
- if (!leaves || !numbers)
- return FcFalse;
-
- fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
- fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
- }
-
- 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;
-}
-
-/*
- * Locate the leaf containing the specified char, creating it
- * if desired
- */
-
-FcCharLeaf *
-FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
-{
- int pos;
- FcCharLeaf *leaf;
-
- pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- return FcCharSetLeaf(fcs, pos);
-
- leaf = calloc (1, sizeof (FcCharLeaf));
- if (!leaf)
- return 0;
-
- pos = -pos - 1;
- if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
- {
- free (leaf);
- return 0;
- }
- FcMemAlloc (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- return leaf;
-}
-
-static FcBool
-FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
-{
- int pos;
-
- pos = FcCharSetFindLeafPos (fcs, ucs4);
- if (pos >= 0)
- {
- FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
- free (FcCharSetLeaf (fcs, pos));
- FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
- leaf);
- return FcTrue;
- }
- pos = -pos - 1;
- return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
-}
-
-FcBool
-FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
-{
- FcCharLeaf *leaf;
- FcChar32 *b;
-
- if (fcs->ref == FC_REF_CONSTANT)
- return FcFalse;
- leaf = FcCharSetFindLeafCreate (fcs, ucs4);
- if (!leaf)
- return FcFalse;
- b = &leaf->map[(ucs4 & 0xff) >> 5];
- *b |= (1 << (ucs4 & 0x1f));
- return FcTrue;
-}
-
-/*
- * An iterator for the leaves of a charset
- */
-
-typedef struct _fcCharSetIter {
- FcCharLeaf *leaf;
- FcChar32 ucs4;
- int pos;
-} FcCharSetIter;
-
-/*
- * Set iter->leaf to the leaf containing iter->ucs4 or higher
- */
-
-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;
-}
-
-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;
- }
-}
-
-
-static void
-FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
-{
- iter->ucs4 = 0;
- iter->pos = 0;
- FcCharSetIterSet (fcs, iter);
-}
-
-FcCharSet *
-FcCharSetCopy (FcCharSet *src)
-{
- if (src->ref != FC_REF_CONSTANT)
- src->ref++;
- else
- FcCacheObjectReference (src);
- return src;
-}
-
-FcBool
-FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
-{
- FcCharSetIter ai, bi;
- int i;
-
- if (a == b)
- return FcTrue;
- 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;
-
- fcs = FcCharSetCreate ();
- if (!fcs)
- goto bail0;
- FcCharSetIterStart (a, &ai);
- FcCharSetIterStart (b, &bi);
- while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
- {
- 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->ref == FC_REF_CONSTANT) {
- if (changed)
- *changed = FcFalse;
- return FcFalse;
- }
-
- 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;
-}
-
-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 = FcCharSetFindLeaf (fcs, ucs4);
- if (!leaf)
- return FcFalse;
- return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
-}
-
-static FcChar32
-FcCharSetPopCount (FcChar32 c1)
-{
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
- return __builtin_popcount (c1);
-#else
- /* hackmem 169 */
- FcChar32 c2 = (c1 >> 1) & 033333333333;
- c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
- return (((c2 + (c2 >> 3)) & 030707070707) % 077);
-#endif
-}
-
-FcChar32
-FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
-{
- FcCharSetIter ai, bi;
- FcChar32 count = 0;
-
- FcCharSetIterStart (a, &ai);
- FcCharSetIterStart (b, &bi);
- while (ai.leaf && bi.leaf)
- {
- 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);
- }
- }
- return count;
-}
-
-FcChar32
-FcCharSetCount (const FcCharSet *a)
-{
- FcCharSetIter ai;
- FcChar32 count = 0;
-
- for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
- {
- int i = 256/32;
- FcChar32 *am = ai.leaf->map;
-
- while (i--)
- count += FcCharSetPopCount (*am++);
- }
- return count;
-}
-
-FcChar32
-FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
-{
- FcCharSetIter ai, bi;
- FcChar32 count = 0;
-
- FcCharSetIterStart (a, &ai);
- FcCharSetIterStart (b, &bi);
- while (ai.leaf)
- {
- if (ai.ucs4 <= bi.ucs4)
- {
- 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);
- }
- else if (bi.leaf)
- {
- bi.ucs4 = ai.ucs4;
- FcCharSetIterSet (b, &bi);
- }
- }
- 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;
-
- if (a == b) return FcTrue;
- 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;
-
- 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
-FcCharSetNextPage (const FcCharSet *a,
- FcChar32 map[FC_CHARSET_MAP_SIZE],
- FcChar32 *next)
-{
- FcCharSetIter ai;
- FcChar32 page;
-
- ai.ucs4 = *next;
- FcCharSetIterSet (a, &ai);
- if (!ai.leaf)
- return FC_CHARSET_DONE;
-
- /*
- * 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
-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
- */
-
-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;
-}
-
-/*
- * ASCII representation of charsets.
- *
- * Each leaf is represented as 9 32-bit values, the code of the first character followed
- * by 8 32 bit values for the leaf itself. Each value is encoded as 5 ASCII characters,
- * only 85 different values are used to avoid control characters as well as the other
- * characters used to encode font names. 85**5 > 2^32 so things work out, but
- * it's not exactly human readable output. As a special case, 0 is encoded as a space
- */
-
-static const unsigned char charToValue[256] = {
- /* "" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\b" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\020" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\030" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* " " */ 0xff, 0x00, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff,
- /* "(" */ 0x05, 0x06, 0x07, 0x08, 0xff, 0xff, 0x09, 0x0a,
- /* "0" */ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
- /* "8" */ 0x13, 0x14, 0xff, 0x15, 0x16, 0xff, 0x17, 0x18,
- /* "@" */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- /* "H" */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- /* "P" */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- /* "X" */ 0x31, 0x32, 0x33, 0x34, 0xff, 0x35, 0x36, 0xff,
- /* "`" */ 0xff, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
- /* "h" */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
- /* "p" */ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
- /* "x" */ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0xff,
- /* "\200" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\210" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\220" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\230" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\240" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\250" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\260" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\270" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\300" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\310" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\320" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\330" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\340" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\350" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\360" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* "\370" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-static const FcChar8 valueToChar[0x55] = {
- /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
- /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
- /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
- /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
- /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
- /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
- /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
- /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
- /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
- /* 0x50 */ 'z', '{', '|', '}', '~',
-};
-
-static FcChar8 *
-FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
-{
- int i;
- FcChar32 v;
- FcChar32 c;
-
- if (*string == ' ')
- {
- v = 0;
- string++;
- }
- else
- {
- v = 0;
- for (i = 0; i < 5; i++)
- {
- if (!(c = (FcChar32) (unsigned char) *string++))
- return 0;
- c = charToValue[c];
- if (c == 0xff)
- return 0;
- v = v * 85 + c;
- }
- }
- *value = v;
- return string;
-}
-
-static FcBool
-FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value)
-{
- int i;
- if (value == 0)
- {
- return FcStrBufChar (buf, ' ');
- }
- else
- {
- FcChar8 string[6];
- FcChar8 *s = string + 5;
- string[5] = '\0';
- for (i = 0; i < 5; i++)
- {
- *--s = valueToChar[value % 85];
- value /= 85;
- }
- for (i = 0; i < 5; i++)
- if (!FcStrBufChar (buf, *s++))
- return FcFalse;
- }
- return FcTrue;
-}
-
-FcCharSet *
-FcNameParseCharSet (FcChar8 *string)
-{
- FcCharSet *c;
- FcChar32 ucs4;
- FcCharLeaf *leaf;
- FcCharLeaf temp;
- FcChar32 bits;
- int i;
-
- c = FcCharSetCreate ();
- if (!c)
- goto bail0;
- while (*string)
- {
- string = FcCharSetParseValue (string, &ucs4);
- if (!string)
- goto bail1;
- bits = 0;
- for (i = 0; i < 256/32; i++)
- {
- string = FcCharSetParseValue (string, &temp.map[i]);
- if (!string)
- goto bail1;
- bits |= temp.map[i];
- }
- if (bits)
- {
- leaf = malloc (sizeof (FcCharLeaf));
- if (!leaf)
- goto bail1;
- *leaf = temp;
- if (!FcCharSetInsertLeaf (c, ucs4, leaf))
- goto bail1;
- }
- }
- return c;
-bail1:
- if (c->num)
- {
- FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
- free (FcCharSetLeaves (c));
- }
- if (c->num)
- {
- FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
- free (FcCharSetNumbers (c));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- free (c);
-bail0:
- return NULL;
-}
-
-FcBool
-FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
-{
- FcCharSetIter ci;
- int i;
-#ifdef CHECK
- int len = buf->len;
-#endif
-
- for (FcCharSetIterStart (c, &ci);
- ci.leaf;
- FcCharSetIterNext (c, &ci))
- {
- if (!FcCharSetUnparseValue (buf, ci.ucs4))
- return FcFalse;
- for (i = 0; i < 256/32; i++)
- if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
- return FcFalse;
- }
-#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
-
- 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;
- FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
- 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;
-
- 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);
- 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;
-
- ent = malloc (sizeof (FcCharSetOrigEnt));
- if (!ent)
- return FcFalse;
- ent->orig = orig;
- ent->frozen = frozen;
- ent->next = *bucket;
- *bucket = ent;
- return FcTrue;
-}
-
-static FcCharSet *
-FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
-{
- 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 &&
- !memcmp (FcCharSetNumbers(&ent->set),
- FcCharSetNumbers(fcs),
- fcs->num * sizeof (FcChar16)))
- {
- FcBool ok = FcTrue;
- int i;
-
- for (i = 0; i < fcs->num; i++)
- if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
- 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;
- FcMemAlloc (FC_MEM_CHARSET, size);
-
- freezer->charsets_allocated++;
-
- ent->set.ref = FC_REF_CONSTANT;
- 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));
-
- ent_leaves = FcCharSetLeaves (&ent->set);
- for (i = 0; i < fcs->num; i++)
- ent_leaves[i] = FcPtrToOffset (ent_leaves,
- FcCharSetLeaf (fcs, i));
- 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;
-
- 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;
- }
- n = FcCharSetFreezeBase (freezer, b, fcs);
- if (!FcCharSetFreezeOrig (freezer, fcs, n))
- {
- n = NULL;
- goto bail1;
- }
- freezer->charsets_seen++;
- freezer->leaves_seen += fcs->num;
-bail1:
- if (b->num)
- {
- FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
- free (FcCharSetLeaves (b));
- }
- if (b->num)
- {
- FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
- free (FcCharSetNumbers (b));
- }
- FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
- free (b);
-bail0:
- return n;
-}
-
-FcCharSetFreezer *
-FcCharSetFreezerCreate (void)
-{
- FcCharSetFreezer *freezer;
-
- freezer = calloc (1, sizeof (FcCharSetFreezer));
- return freezer;
-}
-
-void
-FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
-{
- int i;
-
- if (FcDebug() & FC_DBG_CACHE)
- {
- printf ("\ncharsets %d -> %d leaves %d -> %d\n",
- freezer->charsets_seen, freezer->charsets_allocated,
- freezer->leaves_seen, freezer->leaves_allocated);
- }
- for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
- {
- FcCharSetEnt *ent, *next;
- for (ent = freezer->set_hash_table[i]; ent; ent = next)
- {
- next = ent->next;
- FcMemFree (FC_MEM_CHARSET, (sizeof (FcCharSetEnt) +
- ent->set.num * sizeof (FcCharLeaf *) +
- ent->set.num * sizeof (FcChar16)));
- free (ent);
- }
- }
-
- 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);
- }
- }
-
- for (i = 0; i < freezer->leaf_block_count; i++)
- {
- free (freezer->leaf_blocks[i]);
- FcMemFree (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
- }
-
- free (freezer->leaf_blocks);
- free (freezer);
-}
-
-FcBool
-FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
-{
- intptr_t *leaves;
- FcChar16 *numbers;
- int i;
-
- if (cs->ref != FC_REF_CONSTANT)
- {
- if (!serialize->cs_freezer)
- {
- serialize->cs_freezer = FcCharSetFreezerCreate ();
- if (!serialize->cs_freezer)
- return FcFalse;
- }
- if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
- return FcTrue;
-
- cs = FcCharSetFreeze (serialize->cs_freezer, cs);
- }
-
- leaves = FcCharSetLeaves (cs);
- numbers = FcCharSetNumbers (cs);
-
- 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;
- return FcTrue;
-}
-
-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 (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
- {
- cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
- if (!cs)
- return NULL;
- }
-
- cs_serialized = FcSerializePtr (serialize, cs);
- if (!cs_serialized)
- return NULL;
-
- cs_serialized->ref = FC_REF_CONSTANT;
- cs_serialized->num = cs->num;
-
- if (cs->num)
- {
- leaves = FcCharSetLeaves (cs);
- leaves_serialized = FcSerializePtr (serialize, leaves);
- if (!leaves_serialized)
- return NULL;
-
- cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
- leaves_serialized);
-
- numbers = FcCharSetNumbers (cs);
- numbers_serialized = FcSerializePtr (serialize, numbers);
- if (!numbers)
- return NULL;
-
- cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
- numbers_serialized);
-
- for (i = 0; i < cs->num; i++)
- {
- leaf = FcCharSetLeaf (cs, i);
- leaf_serialized = FcSerializePtr (serialize, leaf);
- if (!leaf_serialized)
- return NULL;
- *leaf_serialized = *leaf;
- leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
- leaf_serialized);
- numbers_serialized[i] = numbers[i];
- }
- }
- else
- {
- cs_serialized->leaves_offset = 0;
- cs_serialized->numbers_offset = 0;
- }
-
- return cs_serialized;
-}
-#define __fccharset__
-#include "fcaliastail.h"
-#undef __fccharset__
+/*
+ * fontconfig/src/fccharset.c
+ *
+ * Copyright © 2001 Keith Packard
+ *
+ * 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
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. The authors make no
+ * 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,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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>
+
+/* #define CHECK */
+
+FcCharSet *
+FcCharSetCreate (void)
+{
+ FcCharSet *fcs;
+
+ fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
+ if (!fcs)
+ return 0;
+ FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
+ fcs->ref = 1;
+ fcs->num = 0;
+ fcs->leaves_offset = 0;
+ fcs->numbers_offset = 0;
+ return fcs;
+}
+
+FcCharSet *
+FcCharSetNew (void)
+{
+ return FcCharSetCreate ();
+}
+
+void
+FcCharSetDestroy (FcCharSet *fcs)
+{
+ int i;
+
+ if (fcs->ref == FC_REF_CONSTANT)
+ {
+ FcCacheObjectDereference (fcs);
+ return;
+ }
+ if (--fcs->ref > 0)
+ return;
+ for (i = 0; i < fcs->num; i++)
+ {
+ FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
+ free (FcCharSetLeaf (fcs, i));
+ }
+ if (fcs->num)
+ {
+ /* the numbers here are estimates */
+ FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
+ free (FcCharSetLeaves (fcs));
+ FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
+ free (FcCharSetNumbers (fcs));
+ }
+ FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+ 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
+ * the (position + 1) where it should be inserted
+ */
+
+static int
+FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
+{
+ return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
+}
+
+static FcCharLeaf *
+FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
+{
+ int pos = FcCharSetFindLeafPos (fcs, ucs4);
+ if (pos >= 0)
+ return FcCharSetLeaf(fcs, pos);
+ return 0;
+}
+
+#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
+
+static FcBool
+FcCharSetPutLeaf (FcCharSet *fcs,
+ FcChar32 ucs4,
+ FcCharLeaf *leaf,
+ int pos)
+{
+ intptr_t *leaves = FcCharSetLeaves (fcs);
+ FcChar16 *numbers = FcCharSetNumbers (fcs);
+
+ ucs4 >>= 8;
+ if (ucs4 >= 0x10000)
+ return FcFalse;
+
+ if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
+ {
+ if (!fcs->num)
+ {
+ unsigned int alloced = 8;
+ leaves = malloc (alloced * sizeof (*leaves));
+ numbers = malloc (alloced * sizeof (*numbers));
+ FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
+ FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
+ }
+ else
+ {
+ unsigned int alloced = fcs->num;
+ intptr_t *new_leaves, distance;
+
+ FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves));
+ FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers));
+
+ alloced *= 2;
+ new_leaves = realloc (leaves, alloced * sizeof (*leaves));
+ numbers = realloc (numbers, alloced * sizeof (*numbers));
+
+ FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
+ FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
+
+ distance = (intptr_t) new_leaves - (intptr_t) leaves;
+ if (new_leaves && distance)
+ {
+ int i;
+ for (i = 0; i < fcs->num; i++)
+ new_leaves[i] -= distance;
+ }
+ leaves = new_leaves;
+ }
+
+ if (!leaves || !numbers)
+ return FcFalse;
+
+ fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
+ fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
+ }
+
+ 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;
+}
+
+/*
+ * Locate the leaf containing the specified char, creating it
+ * if desired
+ */
+
+FcCharLeaf *
+FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
+{
+ int pos;
+ FcCharLeaf *leaf;
+
+ pos = FcCharSetFindLeafPos (fcs, ucs4);
+ if (pos >= 0)
+ return FcCharSetLeaf(fcs, pos);
+
+ leaf = calloc (1, sizeof (FcCharLeaf));
+ if (!leaf)
+ return 0;
+
+ pos = -pos - 1;
+ if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
+ {
+ free (leaf);
+ return 0;
+ }
+ FcMemAlloc (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
+ return leaf;
+}
+
+static FcBool
+FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
+{
+ int pos;
+
+ pos = FcCharSetFindLeafPos (fcs, ucs4);
+ if (pos >= 0)
+ {
+ FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
+ free (FcCharSetLeaf (fcs, pos));
+ FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
+ leaf);
+ return FcTrue;
+ }
+ pos = -pos - 1;
+ return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
+}
+
+FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
+{
+ FcCharLeaf *leaf;
+ FcChar32 *b;
+
+ if (fcs->ref == FC_REF_CONSTANT)
+ return FcFalse;
+ leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+ if (!leaf)
+ return FcFalse;
+ b = &leaf->map[(ucs4 & 0xff) >> 5];
+ *b |= (1 << (ucs4 & 0x1f));
+ return FcTrue;
+}
+
+FcBool
+FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
+{
+ FcCharLeaf *leaf;
+ FcChar32 *b;
+
+ if (fcs->ref == FC_REF_CONSTANT)
+ return FcFalse;
+ leaf = FcCharSetFindLeaf (fcs, ucs4);
+ if (!leaf)
+ return FcTrue;
+ b = &leaf->map[(ucs4 & 0xff) >> 5];
+ *b &= ~(1 << (ucs4 & 0x1f));
+ /* We don't bother removing the leaf if it's empty */
+ return FcTrue;
+}
+
+/*
+ * An iterator for the leaves of a charset
+ */
+
+typedef struct _fcCharSetIter {
+ FcCharLeaf *leaf;
+ FcChar32 ucs4;
+ int pos;
+} FcCharSetIter;
+
+/*
+ * Set iter->leaf to the leaf containing iter->ucs4 or higher
+ */
+
+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;
+}
+
+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;
+ }
+}
+
+
+static void
+FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+ iter->ucs4 = 0;
+ iter->pos = 0;
+ FcCharSetIterSet (fcs, iter);
+}
+
+FcCharSet *
+FcCharSetCopy (FcCharSet *src)
+{
+ if (src->ref != FC_REF_CONSTANT)
+ src->ref++;
+ else
+ FcCacheObjectReference (src);
+ return src;
+}
+
+FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ int i;
+
+ if (a == b)
+ return FcTrue;
+ 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;
+
+ fcs = FcCharSetCreate ();
+ if (!fcs)
+ goto bail0;
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
+ {
+ 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->ref == FC_REF_CONSTANT) {
+ if (changed)
+ *changed = FcFalse;
+ return FcFalse;
+ }
+
+ 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;
+}
+
+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 = FcCharSetFindLeaf (fcs, ucs4);
+ if (!leaf)
+ return FcFalse;
+ return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
+}
+
+static FcChar32
+FcCharSetPopCount (FcChar32 c1)
+{
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+ return __builtin_popcount (c1);
+#else
+ /* hackmem 169 */
+ FcChar32 c2 = (c1 >> 1) & 033333333333;
+ c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
+ return (((c2 + (c2 >> 3)) & 030707070707) % 077);
+#endif
+}
+
+FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ FcChar32 count = 0;
+
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while (ai.leaf && bi.leaf)
+ {
+ 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);
+ }
+ }
+ return count;
+}
+
+FcChar32
+FcCharSetCount (const FcCharSet *a)
+{
+ FcCharSetIter ai;
+ FcChar32 count = 0;
+
+ for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
+ {
+ int i = 256/32;
+ FcChar32 *am = ai.leaf->map;
+
+ while (i--)
+ count += FcCharSetPopCount (*am++);
+ }
+ return count;
+}
+
+FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
+{
+ FcCharSetIter ai, bi;
+ FcChar32 count = 0;
+
+ FcCharSetIterStart (a, &ai);
+ FcCharSetIterStart (b, &bi);
+ while (ai.leaf)
+ {
+ if (ai.ucs4 <= bi.ucs4)
+ {
+ 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);
+ }
+ else if (bi.leaf)
+ {
+ bi.ucs4 = ai.ucs4;
+ FcCharSetIterSet (b, &bi);
+ }
+ }
+ 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;
+
+ if (a == b) return FcTrue;
+ 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;
+
+ 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
+FcCharSetNextPage (const FcCharSet *a,
+ FcChar32 map[FC_CHARSET_MAP_SIZE],
+ FcChar32 *next)
+{
+ FcCharSetIter ai;
+ FcChar32 page;
+
+ ai.ucs4 = *next;
+ FcCharSetIterSet (a, &ai);
+ if (!ai.leaf)
+ return FC_CHARSET_DONE;
+
+ /*
+ * 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
+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
+ */
+
+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;
+}
+
+/*
+ * ASCII representation of charsets.
+ *
+ * Each leaf is represented as 9 32-bit values, the code of the first character followed
+ * by 8 32 bit values for the leaf itself. Each value is encoded as 5 ASCII characters,
+ * only 85 different values are used to avoid control characters as well as the other
+ * characters used to encode font names. 85**5 > 2^32 so things work out, but
+ * it's not exactly human readable output. As a special case, 0 is encoded as a space
+ */
+
+static const unsigned char charToValue[256] = {
+ /* "" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\b" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\020" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\030" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* " " */ 0xff, 0x00, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff,
+ /* "(" */ 0x05, 0x06, 0x07, 0x08, 0xff, 0xff, 0x09, 0x0a,
+ /* "0" */ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ /* "8" */ 0x13, 0x14, 0xff, 0x15, 0x16, 0xff, 0x17, 0x18,
+ /* "@" */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ /* "H" */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ /* "P" */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ /* "X" */ 0x31, 0x32, 0x33, 0x34, 0xff, 0x35, 0x36, 0xff,
+ /* "`" */ 0xff, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
+ /* "h" */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+ /* "p" */ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
+ /* "x" */ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0xff,
+ /* "\200" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\210" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\220" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\230" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\240" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\250" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\260" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\270" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\300" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\310" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\320" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\330" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\340" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\350" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\360" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* "\370" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static const FcChar8 valueToChar[0x55] = {
+ /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
+ /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
+ /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
+ /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
+ /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+ /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
+ /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+ /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
+ /* 0x50 */ 'z', '{', '|', '}', '~',
+};
+
+static FcChar8 *
+FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
+{
+ int i;
+ FcChar32 v;
+ FcChar32 c;
+
+ if (*string == ' ')
+ {
+ v = 0;
+ string++;
+ }
+ else
+ {
+ v = 0;
+ for (i = 0; i < 5; i++)
+ {
+ if (!(c = (FcChar32) (unsigned char) *string++))
+ return 0;
+ c = charToValue[c];
+ if (c == 0xff)
+ return 0;
+ v = v * 85 + c;
+ }
+ }
+ *value = v;
+ return string;
+}
+
+static FcBool
+FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value)
+{
+ int i;
+ if (value == 0)
+ {
+ return FcStrBufChar (buf, ' ');
+ }
+ else
+ {
+ FcChar8 string[6];
+ FcChar8 *s = string + 5;
+ string[5] = '\0';
+ for (i = 0; i < 5; i++)
+ {
+ *--s = valueToChar[value % 85];
+ value /= 85;
+ }
+ for (i = 0; i < 5; i++)
+ if (!FcStrBufChar (buf, *s++))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string)
+{
+ FcCharSet *c;
+ FcChar32 ucs4;
+ FcCharLeaf *leaf;
+ FcCharLeaf temp;
+ FcChar32 bits;
+ int i;
+
+ c = FcCharSetCreate ();
+ if (!c)
+ goto bail0;
+ while (*string)
+ {
+ string = FcCharSetParseValue (string, &ucs4);
+ if (!string)
+ goto bail1;
+ bits = 0;
+ for (i = 0; i < 256/32; i++)
+ {
+ string = FcCharSetParseValue (string, &temp.map[i]);
+ if (!string)
+ goto bail1;
+ bits |= temp.map[i];
+ }
+ if (bits)
+ {
+ leaf = malloc (sizeof (FcCharLeaf));
+ if (!leaf)
+ goto bail1;
+ *leaf = temp;
+ if (!FcCharSetInsertLeaf (c, ucs4, leaf))
+ goto bail1;
+ }
+ }
+ return c;
+bail1:
+ if (c->num)
+ {
+ FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
+ free (FcCharSetLeaves (c));
+ }
+ if (c->num)
+ {
+ FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
+ free (FcCharSetNumbers (c));
+ }
+ FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+ free (c);
+bail0:
+ return NULL;
+}
+
+FcBool
+FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
+{
+ FcCharSetIter ci;
+ int i;
+#ifdef CHECK
+ int len = buf->len;
+#endif
+
+ for (FcCharSetIterStart (c, &ci);
+ ci.leaf;
+ FcCharSetIterNext (c, &ci))
+ {
+ if (!FcCharSetUnparseValue (buf, ci.ucs4))
+ return FcFalse;
+ for (i = 0; i < 256/32; i++)
+ if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
+ return FcFalse;
+ }
+#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
+
+ 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;
+ FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
+ 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;
+
+ 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);
+ 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;
+
+ ent = malloc (sizeof (FcCharSetOrigEnt));
+ if (!ent)
+ return FcFalse;
+ ent->orig = orig;
+ ent->frozen = frozen;
+ ent->next = *bucket;
+ *bucket = ent;
+ return FcTrue;
+}
+
+static FcCharSet *
+FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
+{
+ 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 &&
+ !memcmp (FcCharSetNumbers(&ent->set),
+ FcCharSetNumbers(fcs),
+ fcs->num * sizeof (FcChar16)))
+ {
+ FcBool ok = FcTrue;
+ int i;
+
+ for (i = 0; i < fcs->num; i++)
+ if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
+ 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;
+ FcMemAlloc (FC_MEM_CHARSET, size);
+
+ freezer->charsets_allocated++;
+
+ ent->set.ref = FC_REF_CONSTANT;
+ 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));
+
+ ent_leaves = FcCharSetLeaves (&ent->set);
+ for (i = 0; i < fcs->num; i++)
+ ent_leaves[i] = FcPtrToOffset (ent_leaves,
+ FcCharSetLeaf (fcs, i));
+ 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;
+
+ 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;
+ }
+ n = FcCharSetFreezeBase (freezer, b, fcs);
+ if (!FcCharSetFreezeOrig (freezer, fcs, n))
+ {
+ n = NULL;
+ goto bail1;
+ }
+ freezer->charsets_seen++;
+ freezer->leaves_seen += fcs->num;
+bail1:
+ if (b->num)
+ {
+ FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
+ free (FcCharSetLeaves (b));
+ }
+ if (b->num)
+ {
+ FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
+ free (FcCharSetNumbers (b));
+ }
+ FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+ free (b);
+bail0:
+ return n;
+}
+
+FcCharSetFreezer *
+FcCharSetFreezerCreate (void)
+{
+ FcCharSetFreezer *freezer;
+
+ freezer = calloc (1, sizeof (FcCharSetFreezer));
+ return freezer;
+}
+
+void
+FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
+{
+ int i;
+
+ if (FcDebug() & FC_DBG_CACHE)
+ {
+ printf ("\ncharsets %d -> %d leaves %d -> %d\n",
+ freezer->charsets_seen, freezer->charsets_allocated,
+ freezer->leaves_seen, freezer->leaves_allocated);
+ }
+ for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
+ {
+ FcCharSetEnt *ent, *next;
+ for (ent = freezer->set_hash_table[i]; ent; ent = next)
+ {
+ next = ent->next;
+ FcMemFree (FC_MEM_CHARSET, (sizeof (FcCharSetEnt) +
+ ent->set.num * sizeof (FcCharLeaf *) +
+ ent->set.num * sizeof (FcChar16)));
+ free (ent);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ for (i = 0; i < freezer->leaf_block_count; i++)
+ {
+ free (freezer->leaf_blocks[i]);
+ FcMemFree (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
+ }
+
+ free (freezer->leaf_blocks);
+ free (freezer);
+}
+
+FcBool
+FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
+{
+ intptr_t *leaves;
+ FcChar16 *numbers;
+ int i;
+
+ if (cs->ref != FC_REF_CONSTANT)
+ {
+ if (!serialize->cs_freezer)
+ {
+ serialize->cs_freezer = FcCharSetFreezerCreate ();
+ if (!serialize->cs_freezer)
+ return FcFalse;
+ }
+ if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
+ return FcTrue;
+
+ cs = FcCharSetFreeze (serialize->cs_freezer, cs);
+ }
+
+ leaves = FcCharSetLeaves (cs);
+ numbers = FcCharSetNumbers (cs);
+
+ 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;
+ return FcTrue;
+}
+
+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 (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
+ {
+ cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
+ if (!cs)
+ return NULL;
+ }
+
+ cs_serialized = FcSerializePtr (serialize, cs);
+ if (!cs_serialized)
+ return NULL;
+
+ cs_serialized->ref = FC_REF_CONSTANT;
+ cs_serialized->num = cs->num;
+
+ if (cs->num)
+ {
+ leaves = FcCharSetLeaves (cs);
+ leaves_serialized = FcSerializePtr (serialize, leaves);
+ if (!leaves_serialized)
+ return NULL;
+
+ cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
+ leaves_serialized);
+
+ numbers = FcCharSetNumbers (cs);
+ numbers_serialized = FcSerializePtr (serialize, numbers);
+ if (!numbers)
+ return NULL;
+
+ cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
+ numbers_serialized);
+
+ for (i = 0; i < cs->num; i++)
+ {
+ leaf = FcCharSetLeaf (cs, i);
+ leaf_serialized = FcSerializePtr (serialize, leaf);
+ if (!leaf_serialized)
+ return NULL;
+ *leaf_serialized = *leaf;
+ leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
+ leaf_serialized);
+ numbers_serialized[i] = numbers[i];
+ }
+ }
+ else
+ {
+ cs_serialized->leaves_offset = 0;
+ cs_serialized->numbers_offset = 0;
+ }
+
+ return cs_serialized;
+}
+#define __fccharset__
+#include "fcaliastail.h"
+#undef __fccharset__