Blame src/fccharset.c

Packit 352660
/*
Packit 352660
 * fontconfig/src/fccharset.c
Packit 352660
 *
Packit 352660
 * Copyright © 2001 Keith Packard
Packit 352660
 *
Packit 352660
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 352660
 * documentation for any purpose is hereby granted without fee, provided that
Packit 352660
 * the above copyright notice appear in all copies and that both that
Packit 352660
 * copyright notice and this permission notice appear in supporting
Packit 352660
 * documentation, and that the name of the author(s) not be used in
Packit 352660
 * advertising or publicity pertaining to distribution of the software without
Packit 352660
 * specific, written prior permission.  The authors make no
Packit 352660
 * representations about the suitability of this software for any purpose.  It
Packit 352660
 * is provided "as is" without express or implied warranty.
Packit 352660
 *
Packit 352660
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit 352660
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit 352660
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit 352660
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit 352660
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit 352660
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
Packit 352660
 * PERFORMANCE OF THIS SOFTWARE.
Packit 352660
 */
Packit 352660
Packit 352660
#include "fcint.h"
Packit 352660
#include <stdlib.h>
Packit 352660
Packit 352660
/* #define CHECK */
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetCreate (void)
Packit 352660
{
Packit 352660
    FcCharSet	*fcs;
Packit 352660
Packit 352660
    fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
Packit 352660
    if (!fcs)
Packit 352660
	return 0;
Packit 352660
    FcRefInit (&fcs->ref, 1);
Packit 352660
    fcs->num = 0;
Packit 352660
    fcs->leaves_offset = 0;
Packit 352660
    fcs->numbers_offset = 0;
Packit 352660
    return fcs;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetPromote (FcValuePromotionBuffer *vbuf)
Packit 352660
{
Packit 352660
    FcCharSet *fcs = (FcCharSet *) vbuf;
Packit 352660
Packit 352660
    FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer));
Packit 352660
Packit 352660
    FcRefSetConst (&fcs->ref);
Packit 352660
    fcs->num = 0;
Packit 352660
    fcs->leaves_offset = 0;
Packit 352660
    fcs->numbers_offset = 0;
Packit 352660
Packit 352660
    return fcs;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetNew (void)
Packit 352660
{
Packit 352660
    return FcCharSetCreate ();
Packit 352660
}
Packit 352660
Packit 352660
void
Packit 352660
FcCharSetDestroy (FcCharSet *fcs)
Packit 352660
{
Packit 352660
    int i;
Packit 352660
Packit 352660
    if (fcs)
Packit 352660
    {
Packit 352660
	if (FcRefIsConst (&fcs->ref))
Packit 352660
	{
Packit 352660
	    FcCacheObjectDereference (fcs);
Packit 352660
	    return;
Packit 352660
	}
Packit 352660
	if (FcRefDec (&fcs->ref) != 1)
Packit 352660
	    return;
Packit 352660
	for (i = 0; i < fcs->num; i++)
Packit 352660
	    free (FcCharSetLeaf (fcs, i));
Packit 352660
	if (fcs->num)
Packit 352660
	{
Packit 352660
	    free (FcCharSetLeaves (fcs));
Packit 352660
	    free (FcCharSetNumbers (fcs));
Packit 352660
	}
Packit 352660
	free (fcs);
Packit 352660
    }
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * Search for the leaf containing with the specified num.
Packit 352660
 * Return its index if it exists, otherwise return negative of
Packit 352660
 * the (position + 1) where it should be inserted
Packit 352660
 */
Packit 352660
Packit 352660
Packit 352660
static int
Packit 352660
FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
Packit 352660
{
Packit 352660
    FcChar16		*numbers = FcCharSetNumbers(fcs);
Packit 352660
    FcChar16		page;
Packit 352660
    int			low = start;
Packit 352660
    int			high = fcs->num - 1;
Packit 352660
Packit 352660
    if (!numbers)
Packit 352660
	return -1;
Packit 352660
    while (low <= high)
Packit 352660
    {
Packit 352660
	int mid = (low + high) >> 1;
Packit 352660
	page = numbers[mid];
Packit 352660
	if (page == num)
Packit 352660
	    return mid;
Packit 352660
	if (page < num)
Packit 352660
	    low = mid + 1;
Packit 352660
	else
Packit 352660
	    high = mid - 1;
Packit 352660
    }
Packit 352660
    if (high < 0 || (high < fcs->num && numbers[high] < num))
Packit 352660
	high++;
Packit 352660
    return -(high + 1);
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * Locate the leaf containing the specified char, return
Packit 352660
 * its index if it exists, otherwise return negative of
Packit 352660
 * the (position + 1) where it should be inserted
Packit 352660
 */
Packit 352660
Packit 352660
static int
Packit 352660
FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
Packit 352660
}
Packit 352660
Packit 352660
static FcCharLeaf *
Packit 352660
FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    int	pos = FcCharSetFindLeafPos (fcs, ucs4);
Packit 352660
    if (pos >= 0)
Packit 352660
	return FcCharSetLeaf(fcs, pos);
Packit 352660
    return 0;
Packit 352660
}
Packit 352660
Packit 352660
#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetPutLeaf (FcCharSet	*fcs,
Packit 352660
		  FcChar32	ucs4,
Packit 352660
		  FcCharLeaf	*leaf,
Packit 352660
		  int		pos)
Packit 352660
{
Packit 352660
    intptr_t	*leaves = FcCharSetLeaves (fcs);
Packit 352660
    FcChar16	*numbers = FcCharSetNumbers (fcs);
Packit 352660
Packit 352660
    ucs4 >>= 8;
Packit 352660
    if (ucs4 >= 0x10000)
Packit 352660
	return FcFalse;
Packit 352660
Packit 352660
    if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
Packit 352660
    {
Packit 352660
      if (!fcs->num)
Packit 352660
      {
Packit 352660
        unsigned int alloced = 8;
Packit 352660
	leaves = malloc (alloced * sizeof (*leaves));
Packit 352660
	numbers = malloc (alloced * sizeof (*numbers));
Packit 352660
	if (!leaves || !numbers)
Packit 352660
	{
Packit 352660
	    if (leaves)
Packit 352660
		free (leaves);
Packit 352660
	    if (numbers)
Packit 352660
		free (numbers);
Packit 352660
	    return FcFalse;
Packit 352660
	}
Packit 352660
      }
Packit 352660
      else
Packit 352660
      {
Packit 352660
        unsigned int alloced = fcs->num;
Packit 352660
	intptr_t *new_leaves, distance;
Packit 352660
Packit 352660
	alloced *= 2;
Packit 352660
	new_leaves = realloc (leaves, alloced * sizeof (*leaves));
Packit 352660
	if (!new_leaves)
Packit 352660
	    return FcFalse;
Packit 352660
	numbers = realloc (numbers, alloced * sizeof (*numbers));
Packit 352660
	if (!numbers)
Packit 352660
	{
Packit 352660
	    /* Revert the reallocation of leaves */
Packit 352660
	    leaves = realloc (new_leaves, (alloced / 2) * sizeof (*new_leaves));
Packit 352660
	    /* unlikely to fail though */
Packit 352660
	    if (!leaves)
Packit 352660
		return FcFalse;
Packit 352660
	    fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
Packit 352660
	    return FcFalse;
Packit 352660
	}
Packit 352660
	distance = (intptr_t) new_leaves - (intptr_t) leaves;
Packit 352660
	if (new_leaves && distance)
Packit 352660
	{
Packit 352660
	    int i;
Packit 352660
	    for (i = 0; i < fcs->num; i++)
Packit 352660
		new_leaves[i] -= distance;
Packit 352660
	}
Packit 352660
	leaves = new_leaves;
Packit 352660
      }
Packit 352660
Packit 352660
      fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
Packit 352660
      fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
Packit 352660
    }
Packit 352660
Packit 352660
    memmove (leaves + pos + 1, leaves + pos,
Packit 352660
	     (fcs->num - pos) * sizeof (*leaves));
Packit 352660
    memmove (numbers + pos + 1, numbers + pos,
Packit 352660
	     (fcs->num - pos) * sizeof (*numbers));
Packit 352660
    numbers[pos] = (FcChar16) ucs4;
Packit 352660
    leaves[pos] = FcPtrToOffset (leaves, leaf);
Packit 352660
    fcs->num++;
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * Locate the leaf containing the specified char, creating it
Packit 352660
 * if desired
Packit 352660
 */
Packit 352660
Packit 352660
FcCharLeaf *
Packit 352660
FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    int			pos;
Packit 352660
    FcCharLeaf		*leaf;
Packit 352660
Packit 352660
    pos = FcCharSetFindLeafPos (fcs, ucs4);
Packit 352660
    if (pos >= 0)
Packit 352660
	return FcCharSetLeaf(fcs, pos);
Packit 352660
Packit 352660
    leaf = calloc (1, sizeof (FcCharLeaf));
Packit 352660
    if (!leaf)
Packit 352660
	return 0;
Packit 352660
Packit 352660
    pos = -pos - 1;
Packit 352660
    if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
Packit 352660
    {
Packit 352660
	free (leaf);
Packit 352660
	return 0;
Packit 352660
    }
Packit 352660
    return leaf;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
Packit 352660
{
Packit 352660
    int		    pos;
Packit 352660
Packit 352660
    pos = FcCharSetFindLeafPos (fcs, ucs4);
Packit 352660
    if (pos >= 0)
Packit 352660
    {
Packit 352660
	free (FcCharSetLeaf (fcs, pos));
Packit 352660
	FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
Packit 352660
						   leaf);
Packit 352660
	return FcTrue;
Packit 352660
    }
Packit 352660
    pos = -pos - 1;
Packit 352660
    return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    FcCharLeaf	*leaf;
Packit 352660
    FcChar32	*b;
Packit 352660
Packit 352660
    if (fcs == NULL || FcRefIsConst (&fcs->ref))
Packit 352660
	return FcFalse;
Packit 352660
    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
Packit 352660
    if (!leaf)
Packit 352660
	return FcFalse;
Packit 352660
    b = &leaf->map[(ucs4 & 0xff) >> 5];
Packit 352660
    *b |= (1U << (ucs4 & 0x1f));
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    FcCharLeaf	*leaf;
Packit 352660
    FcChar32	*b;
Packit 352660
Packit 352660
    if (fcs == NULL || FcRefIsConst (&fcs->ref))
Packit 352660
	return FcFalse;
Packit 352660
    leaf = FcCharSetFindLeaf (fcs, ucs4);
Packit 352660
    if (!leaf)
Packit 352660
	return FcTrue;
Packit 352660
    b = &leaf->map[(ucs4 & 0xff) >> 5];
Packit 352660
    *b &= ~(1U << (ucs4 & 0x1f));
Packit 352660
    /* We don't bother removing the leaf if it's empty */
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * An iterator for the leaves of a charset
Packit 352660
 */
Packit 352660
Packit 352660
typedef struct _fcCharSetIter {
Packit 352660
    FcCharLeaf	    *leaf;
Packit 352660
    FcChar32	    ucs4;
Packit 352660
    int		    pos;
Packit 352660
} FcCharSetIter;
Packit 352660
Packit 352660
/*
Packit 352660
 * Set iter->leaf to the leaf containing iter->ucs4 or higher
Packit 352660
 */
Packit 352660
Packit 352660
static void
Packit 352660
FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
Packit 352660
{
Packit 352660
    int		    pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
Packit 352660
Packit 352660
    if (pos < 0)
Packit 352660
    {
Packit 352660
	pos = -pos - 1;
Packit 352660
	if (pos == fcs->num)
Packit 352660
	{
Packit 352660
	    iter->ucs4 = ~0;
Packit 352660
	    iter->leaf = 0;
Packit 352660
	    return;
Packit 352660
	}
Packit 352660
        iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
Packit 352660
    }
Packit 352660
    iter->leaf = FcCharSetLeaf(fcs, pos);
Packit 352660
    iter->pos = pos;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
Packit 352660
{
Packit 352660
    int	pos = iter->pos + 1;
Packit 352660
    if (pos >= fcs->num)
Packit 352660
    {
Packit 352660
	iter->ucs4 = ~0;
Packit 352660
	iter->leaf = 0;
Packit 352660
    }
Packit 352660
    else
Packit 352660
    {
Packit 352660
	iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
Packit 352660
	iter->leaf = FcCharSetLeaf(fcs, pos);
Packit 352660
	iter->pos = pos;
Packit 352660
    }
Packit 352660
}
Packit 352660
Packit 352660
Packit 352660
static void
Packit 352660
FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
Packit 352660
{
Packit 352660
    iter->ucs4 = 0;
Packit 352660
    iter->pos = 0;
Packit 352660
    FcCharSetIterSet (fcs, iter);
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetCopy (FcCharSet *src)
Packit 352660
{
Packit 352660
    if (src)
Packit 352660
    {
Packit 352660
	if (!FcRefIsConst (&src->ref))
Packit 352660
	    FcRefInc (&src->ref);
Packit 352660
	else
Packit 352660
	    FcCacheObjectReference (src);
Packit 352660
    }
Packit 352660
    return src;
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai, bi;
Packit 352660
    int		    i;
Packit 352660
Packit 352660
    if (a == b)
Packit 352660
	return FcTrue;
Packit 352660
    if (!a || !b)
Packit 352660
	return FcFalse;
Packit 352660
    for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
Packit 352660
	 ai.leaf && bi.leaf;
Packit 352660
	 FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
Packit 352660
    {
Packit 352660
	if (ai.ucs4 != bi.ucs4)
Packit 352660
	    return FcFalse;
Packit 352660
	for (i = 0; i < 256/32; i++)
Packit 352660
	    if (ai.leaf->map[i] != bi.leaf->map[i])
Packit 352660
		return FcFalse;
Packit 352660
    }
Packit 352660
    return ai.leaf == bi.leaf;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetAddLeaf (FcCharSet	*fcs,
Packit 352660
		  FcChar32	ucs4,
Packit 352660
		  FcCharLeaf	*leaf)
Packit 352660
{
Packit 352660
    FcCharLeaf   *new = FcCharSetFindLeafCreate (fcs, ucs4);
Packit 352660
    if (!new)
Packit 352660
	return FcFalse;
Packit 352660
    *new = *leaf;
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
static FcCharSet *
Packit 352660
FcCharSetOperate (const FcCharSet   *a,
Packit 352660
		  const FcCharSet   *b,
Packit 352660
		  FcBool	    (*overlap) (FcCharLeaf	    *result,
Packit 352660
						const FcCharLeaf    *al,
Packit 352660
						const FcCharLeaf    *bl),
Packit 352660
		  FcBool	aonly,
Packit 352660
		  FcBool	bonly)
Packit 352660
{
Packit 352660
    FcCharSet	    *fcs;
Packit 352660
    FcCharSetIter   ai, bi;
Packit 352660
Packit 352660
    if (!a || !b)
Packit 352660
	goto bail0;
Packit 352660
    fcs = FcCharSetCreate ();
Packit 352660
    if (!fcs)
Packit 352660
	goto bail0;
Packit 352660
    FcCharSetIterStart (a, &ai;;
Packit 352660
    FcCharSetIterStart (b, &bi);
Packit 352660
    while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
Packit 352660
    {
Packit 352660
	if (ai.ucs4 < bi.ucs4)
Packit 352660
	{
Packit 352660
	    if (aonly)
Packit 352660
	    {
Packit 352660
		if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
Packit 352660
		    goto bail1;
Packit 352660
		FcCharSetIterNext (a, &ai;;
Packit 352660
	    }
Packit 352660
	    else
Packit 352660
	    {
Packit 352660
		ai.ucs4 = bi.ucs4;
Packit 352660
		FcCharSetIterSet (a, &ai;;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	else if (bi.ucs4 < ai.ucs4 )
Packit 352660
	{
Packit 352660
	    if (bonly)
Packit 352660
	    {
Packit 352660
		if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
Packit 352660
		    goto bail1;
Packit 352660
		FcCharSetIterNext (b, &bi);
Packit 352660
	    }
Packit 352660
	    else
Packit 352660
	    {
Packit 352660
		bi.ucs4 = ai.ucs4;
Packit 352660
		FcCharSetIterSet (b, &bi);
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    FcCharLeaf  leaf;
Packit 352660
Packit 352660
	    if ((*overlap) (&leaf, ai.leaf, bi.leaf))
Packit 352660
	    {
Packit 352660
		if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
Packit 352660
		    goto bail1;
Packit 352660
	    }
Packit 352660
	    FcCharSetIterNext (a, &ai;;
Packit 352660
	    FcCharSetIterNext (b, &bi);
Packit 352660
	}
Packit 352660
    }
Packit 352660
    return fcs;
Packit 352660
bail1:
Packit 352660
    FcCharSetDestroy (fcs);
Packit 352660
bail0:
Packit 352660
    return 0;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetIntersectLeaf (FcCharLeaf *result,
Packit 352660
			const FcCharLeaf *al,
Packit 352660
			const FcCharLeaf *bl)
Packit 352660
{
Packit 352660
    int	    i;
Packit 352660
    FcBool  nonempty = FcFalse;
Packit 352660
Packit 352660
    for (i = 0; i < 256/32; i++)
Packit 352660
	if ((result->map[i] = al->map[i] & bl->map[i]))
Packit 352660
	    nonempty = FcTrue;
Packit 352660
    return nonempty;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetUnionLeaf (FcCharLeaf *result,
Packit 352660
		    const FcCharLeaf *al,
Packit 352660
		    const FcCharLeaf *bl)
Packit 352660
{
Packit 352660
    int	i;
Packit 352660
Packit 352660
    for (i = 0; i < 256/32; i++)
Packit 352660
	result->map[i] = al->map[i] | bl->map[i];
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
Packit 352660
{
Packit 352660
    int		ai = 0, bi = 0;
Packit 352660
    FcChar16	an, bn;
Packit 352660
Packit 352660
    if (!a || !b)
Packit 352660
	return FcFalse;
Packit 352660
Packit 352660
    if (FcRefIsConst (&a->ref)) {
Packit 352660
	if (changed)
Packit 352660
	    *changed = FcFalse;
Packit 352660
	return FcFalse;
Packit 352660
    }
Packit 352660
Packit 352660
    if (changed) {
Packit 352660
	*changed = !FcCharSetIsSubset(b, a);
Packit 352660
	if (!*changed)
Packit 352660
	    return FcTrue;
Packit 352660
    }
Packit 352660
Packit 352660
    while (bi < b->num)
Packit 352660
    {
Packit 352660
	an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
Packit 352660
	bn = FcCharSetNumbers(b)[bi];
Packit 352660
Packit 352660
	if (an < bn)
Packit 352660
	{
Packit 352660
	    ai = FcCharSetFindLeafForward (a, ai + 1, bn);
Packit 352660
	    if (ai < 0)
Packit 352660
		ai = -ai - 1;
Packit 352660
	}
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    FcCharLeaf *bl = FcCharSetLeaf(b, bi);
Packit 352660
	    if (bn < an)
Packit 352660
	    {
Packit 352660
		if (!FcCharSetAddLeaf (a, bn << 8, bl))
Packit 352660
		    return FcFalse;
Packit 352660
	    }
Packit 352660
	    else
Packit 352660
	    {
Packit 352660
		FcCharLeaf *al = FcCharSetLeaf(a, ai);
Packit 352660
		FcCharSetUnionLeaf (al, al, bl);
Packit 352660
	    }
Packit 352660
Packit 352660
	    ai++;
Packit 352660
	    bi++;
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetSubtractLeaf (FcCharLeaf *result,
Packit 352660
		       const FcCharLeaf *al,
Packit 352660
		       const FcCharLeaf *bl)
Packit 352660
{
Packit 352660
    int	    i;
Packit 352660
    FcBool  nonempty = FcFalse;
Packit 352660
Packit 352660
    for (i = 0; i < 256/32; i++)
Packit 352660
	if ((result->map[i] = al->map[i] & ~bl->map[i]))
Packit 352660
	    nonempty = FcTrue;
Packit 352660
    return nonempty;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
Packit 352660
{
Packit 352660
    FcCharLeaf	*leaf;
Packit 352660
Packit 352660
    if (!fcs)
Packit 352660
	return FcFalse;
Packit 352660
    leaf = FcCharSetFindLeaf (fcs, ucs4);
Packit 352660
    if (!leaf)
Packit 352660
	return FcFalse;
Packit 352660
    return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
Packit 352660
}
Packit 352660
Packit 352660
static FcChar32
Packit 352660
FcCharSetPopCount (FcChar32 c1)
Packit 352660
{
Packit 352660
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
Packit 352660
    return __builtin_popcount (c1);
Packit 352660
#else
Packit 352660
    /* hackmem 169 */
Packit 352660
    FcChar32	c2 = (c1 >> 1) & 033333333333;
Packit 352660
    c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
Packit 352660
    return (((c2 + (c2 >> 3)) & 030707070707) % 077);
Packit 352660
#endif
Packit 352660
}
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai, bi;
Packit 352660
    FcChar32	    count = 0;
Packit 352660
Packit 352660
    if (a && b)
Packit 352660
    {
Packit 352660
	FcCharSetIterStart (a, &ai;;
Packit 352660
	FcCharSetIterStart (b, &bi);
Packit 352660
	while (ai.leaf && bi.leaf)
Packit 352660
	{
Packit 352660
	    if (ai.ucs4 == bi.ucs4)
Packit 352660
	    {
Packit 352660
		FcChar32	*am = ai.leaf->map;
Packit 352660
		FcChar32	*bm = bi.leaf->map;
Packit 352660
		int		i = 256/32;
Packit 352660
		while (i--)
Packit 352660
		    count += FcCharSetPopCount (*am++ & *bm++);
Packit 352660
		FcCharSetIterNext (a, &ai;;
Packit 352660
	    }
Packit 352660
	    else if (ai.ucs4 < bi.ucs4)
Packit 352660
	    {
Packit 352660
		ai.ucs4 = bi.ucs4;
Packit 352660
		FcCharSetIterSet (a, &ai;;
Packit 352660
	    }
Packit 352660
	    if (bi.ucs4 < ai.ucs4)
Packit 352660
	    {
Packit 352660
		bi.ucs4 = ai.ucs4;
Packit 352660
		FcCharSetIterSet (b, &bi);
Packit 352660
	    }
Packit 352660
	}
Packit 352660
    }
Packit 352660
    return count;
Packit 352660
}
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetCount (const FcCharSet *a)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai;
Packit 352660
    FcChar32	    count = 0;
Packit 352660
Packit 352660
    if (a)
Packit 352660
    {
Packit 352660
	for (FcCharSetIterStart (a, &ai;; ai.leaf; FcCharSetIterNext (a, &ai))
Packit 352660
	{
Packit 352660
	    int		    i = 256/32;
Packit 352660
	    FcChar32	    *am = ai.leaf->map;
Packit 352660
Packit 352660
	    while (i--)
Packit 352660
		count += FcCharSetPopCount (*am++);
Packit 352660
	}
Packit 352660
    }
Packit 352660
    return count;
Packit 352660
}
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai, bi;
Packit 352660
    FcChar32	    count = 0;
Packit 352660
Packit 352660
    if (a && b)
Packit 352660
    {
Packit 352660
	FcCharSetIterStart (a, &ai;;
Packit 352660
	FcCharSetIterStart (b, &bi);
Packit 352660
	while (ai.leaf)
Packit 352660
	{
Packit 352660
	    if (ai.ucs4 <= bi.ucs4)
Packit 352660
	    {
Packit 352660
		FcChar32	*am = ai.leaf->map;
Packit 352660
		int		i = 256/32;
Packit 352660
		if (ai.ucs4 == bi.ucs4)
Packit 352660
		{
Packit 352660
		    FcChar32	*bm = bi.leaf->map;
Packit 352660
		    while (i--)
Packit 352660
			count += FcCharSetPopCount (*am++ & ~*bm++);
Packit 352660
		}
Packit 352660
		else
Packit 352660
		{
Packit 352660
		    while (i--)
Packit 352660
			count += FcCharSetPopCount (*am++);
Packit 352660
		}
Packit 352660
		FcCharSetIterNext (a, &ai;;
Packit 352660
	    }
Packit 352660
	    else if (bi.leaf)
Packit 352660
	    {
Packit 352660
		bi.ucs4 = ai.ucs4;
Packit 352660
		FcCharSetIterSet (b, &bi);
Packit 352660
	    }
Packit 352660
	}
Packit 352660
    }
Packit 352660
    return count;
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * return FcTrue iff a is a subset of b
Packit 352660
 */
Packit 352660
FcBool
Packit 352660
FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
Packit 352660
{
Packit 352660
    int		ai, bi;
Packit 352660
    FcChar16	an, bn;
Packit 352660
Packit 352660
    if (a == b)
Packit 352660
	return FcTrue;
Packit 352660
    if (!a || !b)
Packit 352660
	return FcFalse;
Packit 352660
    bi = 0;
Packit 352660
    ai = 0;
Packit 352660
    while (ai < a->num && bi < b->num)
Packit 352660
    {
Packit 352660
	an = FcCharSetNumbers(a)[ai];
Packit 352660
	bn = FcCharSetNumbers(b)[bi];
Packit 352660
	/*
Packit 352660
	 * Check matching pages
Packit 352660
	 */
Packit 352660
	if (an == bn)
Packit 352660
	{
Packit 352660
	    FcChar32	*am = FcCharSetLeaf(a, ai)->map;
Packit 352660
	    FcChar32	*bm = FcCharSetLeaf(b, bi)->map;
Packit 352660
	
Packit 352660
	    if (am != bm)
Packit 352660
	    {
Packit 352660
		int	i = 256/32;
Packit 352660
		/*
Packit 352660
		 * Does am have any bits not in bm?
Packit 352660
		 */
Packit 352660
		while (i--)
Packit 352660
		    if (*am++ & ~*bm++)
Packit 352660
			return FcFalse;
Packit 352660
	    }
Packit 352660
	    ai++;
Packit 352660
	    bi++;
Packit 352660
	}
Packit 352660
	/*
Packit 352660
	 * Does a have any pages not in b?
Packit 352660
	 */
Packit 352660
	else if (an < bn)
Packit 352660
	    return FcFalse;
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    bi = FcCharSetFindLeafForward (b, bi + 1, an);
Packit 352660
	    if (bi < 0)
Packit 352660
		bi = -bi - 1;
Packit 352660
	}
Packit 352660
    }
Packit 352660
    /*
Packit 352660
     * did we look at every page?
Packit 352660
     */
Packit 352660
    return ai >= a->num;
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * These two functions efficiently walk the entire charmap for
Packit 352660
 * other software (like pango) that want their own copy
Packit 352660
 */
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetNextPage (const FcCharSet  *a,
Packit 352660
		   FcChar32	    map[FC_CHARSET_MAP_SIZE],
Packit 352660
		   FcChar32	    *next)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai;
Packit 352660
    FcChar32	    page;
Packit 352660
Packit 352660
    if (!a)
Packit 352660
	return FC_CHARSET_DONE;
Packit 352660
    ai.ucs4 = *next;
Packit 352660
    FcCharSetIterSet (a, &ai;;
Packit 352660
    if (!ai.leaf)
Packit 352660
	return FC_CHARSET_DONE;
Packit 352660
Packit 352660
    /*
Packit 352660
     * Save current information
Packit 352660
     */
Packit 352660
    page = ai.ucs4;
Packit 352660
    memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
Packit 352660
    /*
Packit 352660
     * Step to next page
Packit 352660
     */
Packit 352660
    FcCharSetIterNext (a, &ai;;
Packit 352660
    *next = ai.ucs4;
Packit 352660
Packit 352660
    return page;
Packit 352660
}
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetFirstPage (const FcCharSet *a,
Packit 352660
		    FcChar32	    map[FC_CHARSET_MAP_SIZE],
Packit 352660
		    FcChar32	    *next)
Packit 352660
{
Packit 352660
    *next = 0;
Packit 352660
    return FcCharSetNextPage (a, map, next);
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * old coverage API, rather hard to use correctly
Packit 352660
 */
Packit 352660
Packit 352660
FcChar32
Packit 352660
FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
Packit 352660
{
Packit 352660
    FcCharSetIter   ai;
Packit 352660
Packit 352660
    ai.ucs4 = page;
Packit 352660
    FcCharSetIterSet (a, &ai;;
Packit 352660
    if (!ai.leaf)
Packit 352660
    {
Packit 352660
	memset (result, '\0', 256 / 8);
Packit 352660
	page = 0;
Packit 352660
    }
Packit 352660
    else
Packit 352660
    {
Packit 352660
	memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
Packit 352660
	FcCharSetIterNext (a, &ai;;
Packit 352660
	page = ai.ucs4;
Packit 352660
    }
Packit 352660
    return page;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast)
Packit 352660
{
Packit 352660
	char *s = (char *) *string;
Packit 352660
	char *t;
Packit 352660
	long first, last;
Packit 352660
Packit 352660
	while (isspace(*s))
Packit 352660
	    s++;
Packit 352660
	t = s;
Packit 352660
	errno = 0;
Packit 352660
	first = last = strtol (s, &s, 16);
Packit 352660
	if (errno)
Packit 352660
	    return FcFalse;
Packit 352660
	while (isspace(*s))
Packit 352660
	    s++;
Packit 352660
	if (*s == '-')
Packit 352660
	{
Packit 352660
	    s++;
Packit 352660
	    errno = 0;
Packit 352660
	    last = strtol (s, &s, 16);
Packit 352660
	    if (errno)
Packit 352660
		return FcFalse;
Packit 352660
	}
Packit 352660
Packit 352660
	if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff)
Packit 352660
	     return FcFalse;
Packit 352660
Packit 352660
	*string = (FcChar8 *) s;
Packit 352660
	*pfirst = first;
Packit 352660
	*plast = last;
Packit 352660
	return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcNameParseCharSet (FcChar8 *string)
Packit 352660
{
Packit 352660
    FcCharSet	*c;
Packit 352660
    FcChar32	first, last;
Packit 352660
Packit 352660
    c = FcCharSetCreate ();
Packit 352660
    if (!c)
Packit 352660
	goto bail0;
Packit 352660
    while (*string)
Packit 352660
    {
Packit 352660
	FcChar32 u;
Packit 352660
Packit 352660
	if (!FcNameParseRange (&string, &first, &last))
Packit 352660
		goto bail1;
Packit 352660
Packit 352660
	for (u = first; u < last + 1; u++)
Packit 352660
	    FcCharSetAddChar (c, u);
Packit 352660
    }
Packit 352660
    return c;
Packit 352660
bail1:
Packit 352660
    FcCharSetDestroy (c);
Packit 352660
bail0:
Packit 352660
    return NULL;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u)
Packit 352660
{
Packit 352660
    FcChar8	    buf_static[64];
Packit 352660
    snprintf ((char *) buf_static, sizeof (buf_static), "%x", u);
Packit 352660
    FcStrBufString (buf, buf_static);
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
Packit 352660
{
Packit 352660
    FcCharSetIter   ci;
Packit 352660
    FcChar32	    first, last;
Packit 352660
    int		    i;
Packit 352660
#ifdef CHECK
Packit 352660
    int		    len = buf->len;
Packit 352660
#endif
Packit 352660
Packit 352660
    first = last = 0x7FFFFFFF;
Packit 352660
Packit 352660
    for (FcCharSetIterStart (c, &ci);
Packit 352660
	 ci.leaf;
Packit 352660
	 FcCharSetIterNext (c, &ci))
Packit 352660
    {
Packit 352660
	for (i = 0; i < 256/32; i++)
Packit 352660
	{
Packit 352660
	    FcChar32 bits = ci.leaf->map[i];
Packit 352660
	    FcChar32 u = ci.ucs4 + i * 32;
Packit 352660
Packit 352660
	    while (bits)
Packit 352660
	    {
Packit 352660
		if (bits & 1)
Packit 352660
		{
Packit 352660
			if (u != last + 1)
Packit 352660
			{
Packit 352660
			    if (last != first)
Packit 352660
			    {
Packit 352660
				FcStrBufChar (buf, '-');
Packit 352660
				FcNameUnparseUnicode (buf, last);
Packit 352660
			    }
Packit 352660
			    if (last != 0x7FFFFFFF)
Packit 352660
				FcStrBufChar (buf, ' ');
Packit 352660
			    /* Start new range. */
Packit 352660
			    first = u;
Packit 352660
			    FcNameUnparseUnicode (buf, u);
Packit 352660
			}
Packit 352660
			last = u;
Packit 352660
		}
Packit 352660
		bits >>= 1;
Packit 352660
		u++;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
    }
Packit 352660
    if (last != first)
Packit 352660
    {
Packit 352660
	FcStrBufChar (buf, '-');
Packit 352660
	FcNameUnparseUnicode (buf, last);
Packit 352660
    }
Packit 352660
#ifdef CHECK
Packit 352660
    {
Packit 352660
	FcCharSet	*check;
Packit 352660
	FcChar32	missing;
Packit 352660
	FcCharSetIter	ci, checki;
Packit 352660
	
Packit 352660
	/* null terminate for parser */
Packit 352660
	FcStrBufChar (buf, '\0');
Packit 352660
	/* step back over null for life after test */
Packit 352660
	buf->len--;
Packit 352660
	check = FcNameParseCharSet (buf->buf + len);
Packit 352660
	FcCharSetIterStart (c, &ci);
Packit 352660
	FcCharSetIterStart (check, &checki;;
Packit 352660
	while (ci.leaf || checki.leaf)
Packit 352660
	{
Packit 352660
	    if (ci.ucs4 < checki.ucs4)
Packit 352660
	    {
Packit 352660
		printf ("Missing leaf node at 0x%x\n", ci.ucs4);
Packit 352660
		FcCharSetIterNext (c, &ci);
Packit 352660
	    }
Packit 352660
	    else if (checki.ucs4 < ci.ucs4)
Packit 352660
	    {
Packit 352660
		printf ("Extra leaf node at 0x%x\n", checki.ucs4);
Packit 352660
		FcCharSetIterNext (check, &checki;;
Packit 352660
	    }
Packit 352660
	    else
Packit 352660
	    {
Packit 352660
		int	    i = 256/32;
Packit 352660
		FcChar32    *cm = ci.leaf->map;
Packit 352660
		FcChar32    *checkm = checki.leaf->map;
Packit 352660
Packit 352660
		for (i = 0; i < 256; i += 32)
Packit 352660
		{
Packit 352660
		    if (*cm != *checkm)
Packit 352660
			printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
Packit 352660
				ci.ucs4 + i, *cm, *checkm);
Packit 352660
		    cm++;
Packit 352660
		    checkm++;
Packit 352660
		}
Packit 352660
		FcCharSetIterNext (c, &ci);
Packit 352660
		FcCharSetIterNext (check, &checki;;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	if ((missing = FcCharSetSubtractCount (c, check)))
Packit 352660
	    printf ("%d missing in reparsed result\n", missing);
Packit 352660
	if ((missing = FcCharSetSubtractCount (check, c)))
Packit 352660
	    printf ("%d extra in reparsed result\n", missing);
Packit 352660
	FcCharSetDestroy (check);
Packit 352660
    }
Packit 352660
#endif
Packit 352660
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
typedef struct _FcCharLeafEnt FcCharLeafEnt;
Packit 352660
Packit 352660
struct _FcCharLeafEnt {
Packit 352660
    FcCharLeafEnt   *next;
Packit 352660
    FcChar32	    hash;
Packit 352660
    FcCharLeaf	    leaf;
Packit 352660
};
Packit 352660
Packit 352660
#define FC_CHAR_LEAF_BLOCK	(4096 / sizeof (FcCharLeafEnt))
Packit 352660
#define FC_CHAR_LEAF_HASH_SIZE	257
Packit 352660
Packit 352660
typedef struct _FcCharSetEnt FcCharSetEnt;
Packit 352660
Packit 352660
struct _FcCharSetEnt {
Packit 352660
    FcCharSetEnt	*next;
Packit 352660
    FcChar32		hash;
Packit 352660
    FcCharSet		set;
Packit 352660
};
Packit 352660
Packit 352660
typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
Packit 352660
Packit 352660
struct _FcCharSetOrigEnt {
Packit 352660
    FcCharSetOrigEnt	*next;
Packit 352660
    const FcCharSet    	*orig;
Packit 352660
    const FcCharSet    	*frozen;
Packit 352660
};
Packit 352660
Packit 352660
#define FC_CHAR_SET_HASH_SIZE    67
Packit 352660
Packit 352660
struct _FcCharSetFreezer {
Packit 352660
    FcCharLeafEnt   *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
Packit 352660
    FcCharLeafEnt   **leaf_blocks;
Packit 352660
    int		    leaf_block_count;
Packit 352660
    FcCharSetEnt    *set_hash_table[FC_CHAR_SET_HASH_SIZE];
Packit 352660
    FcCharSetOrigEnt	*orig_hash_table[FC_CHAR_SET_HASH_SIZE];
Packit 352660
    FcCharLeafEnt   *current_block;
Packit 352660
    int		    leaf_remain;
Packit 352660
    int		    leaves_seen;
Packit 352660
    int		    charsets_seen;
Packit 352660
    int		    leaves_allocated;
Packit 352660
    int		    charsets_allocated;
Packit 352660
};
Packit 352660
Packit 352660
static FcCharLeafEnt *
Packit 352660
FcCharLeafEntCreate (FcCharSetFreezer *freezer)
Packit 352660
{
Packit 352660
    if (!freezer->leaf_remain)
Packit 352660
    {
Packit 352660
	FcCharLeafEnt **newBlocks;
Packit 352660
Packit 352660
	freezer->leaf_block_count++;
Packit 352660
	newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
Packit 352660
	if (!newBlocks)
Packit 352660
	    return 0;
Packit 352660
	freezer->leaf_blocks = newBlocks;
Packit 352660
	freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
Packit 352660
	if (!freezer->current_block)
Packit 352660
	    return 0;
Packit 352660
	freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
Packit 352660
    }
Packit 352660
    freezer->leaf_remain--;
Packit 352660
    freezer->leaves_allocated++;
Packit 352660
    return freezer->current_block++;
Packit 352660
}
Packit 352660
Packit 352660
static FcChar32
Packit 352660
FcCharLeafHash (FcCharLeaf *leaf)
Packit 352660
{
Packit 352660
    FcChar32	hash = 0;
Packit 352660
    int		i;
Packit 352660
Packit 352660
    for (i = 0; i < 256/32; i++)
Packit 352660
	hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
Packit 352660
    return hash;
Packit 352660
}
Packit 352660
Packit 352660
static FcCharLeaf *
Packit 352660
FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
Packit 352660
{
Packit 352660
    FcChar32			hash = FcCharLeafHash (leaf);
Packit 352660
    FcCharLeafEnt		**bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
Packit 352660
    FcCharLeafEnt		*ent;
Packit 352660
Packit 352660
    for (ent = *bucket; ent; ent = ent->next)
Packit 352660
    {
Packit 352660
	if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
Packit 352660
	    return &ent->leaf;
Packit 352660
    }
Packit 352660
Packit 352660
    ent = FcCharLeafEntCreate(freezer);
Packit 352660
    if (!ent)
Packit 352660
	return 0;
Packit 352660
    ent->leaf = *leaf;
Packit 352660
    ent->hash = hash;
Packit 352660
    ent->next = *bucket;
Packit 352660
    *bucket = ent;
Packit 352660
    return &ent->leaf;
Packit 352660
}
Packit 352660
Packit 352660
static FcChar32
Packit 352660
FcCharSetHash (FcCharSet *fcs)
Packit 352660
{
Packit 352660
    FcChar32	hash = 0;
Packit 352660
    int		i;
Packit 352660
Packit 352660
    /* hash in leaves */
Packit 352660
    for (i = 0; i < fcs->num; i++)
Packit 352660
	hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i));
Packit 352660
    /* hash in numbers */
Packit 352660
    for (i = 0; i < fcs->num; i++)
Packit 352660
	hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers(fcs)[i];
Packit 352660
    return hash;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
Packit 352660
{
Packit 352660
    FcCharSetOrigEnt	**bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
Packit 352660
    FcCharSetOrigEnt	*ent;
Packit 352660
Packit 352660
    ent = malloc (sizeof (FcCharSetOrigEnt));
Packit 352660
    if (!ent)
Packit 352660
	return FcFalse;
Packit 352660
    ent->orig = orig;
Packit 352660
    ent->frozen = frozen;
Packit 352660
    ent->next = *bucket;
Packit 352660
    *bucket = ent;
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
static FcCharSet *
Packit 352660
FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
Packit 352660
{
Packit 352660
    FcChar32		hash = FcCharSetHash (fcs);
Packit 352660
    FcCharSetEnt	**bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
Packit 352660
    FcCharSetEnt	*ent;
Packit 352660
    int			size;
Packit 352660
    int			i;
Packit 352660
Packit 352660
    for (ent = *bucket; ent; ent = ent->next)
Packit 352660
    {
Packit 352660
	if (ent->hash == hash &&
Packit 352660
	    ent->set.num == fcs->num &&
Packit 352660
	    !memcmp (FcCharSetNumbers(&ent->set),
Packit 352660
		     FcCharSetNumbers(fcs),
Packit 352660
		     fcs->num * sizeof (FcChar16)))
Packit 352660
	{
Packit 352660
	    FcBool ok = FcTrue;
Packit 352660
	    int i;
Packit 352660
Packit 352660
	    for (i = 0; i < fcs->num; i++)
Packit 352660
		if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
Packit 352660
		    ok = FcFalse;
Packit 352660
	    if (ok)
Packit 352660
		return &ent->set;
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    size = (sizeof (FcCharSetEnt) +
Packit 352660
	    fcs->num * sizeof (FcCharLeaf *) +
Packit 352660
	    fcs->num * sizeof (FcChar16));
Packit 352660
    ent = malloc (size);
Packit 352660
    if (!ent)
Packit 352660
	return 0;
Packit 352660
Packit 352660
    freezer->charsets_allocated++;
Packit 352660
Packit 352660
    FcRefSetConst (&ent->set.ref);
Packit 352660
    ent->set.num = fcs->num;
Packit 352660
    if (fcs->num)
Packit 352660
    {
Packit 352660
	intptr_t    *ent_leaves;
Packit 352660
Packit 352660
	ent->set.leaves_offset = sizeof (ent->set);
Packit 352660
	ent->set.numbers_offset = (ent->set.leaves_offset +
Packit 352660
				   fcs->num * sizeof (intptr_t));
Packit 352660
Packit 352660
	ent_leaves = FcCharSetLeaves (&ent->set);
Packit 352660
	for (i = 0; i < fcs->num; i++)
Packit 352660
	    ent_leaves[i] = FcPtrToOffset (ent_leaves,
Packit 352660
					   FcCharSetLeaf (fcs, i));
Packit 352660
	memcpy (FcCharSetNumbers (&ent->set),
Packit 352660
		FcCharSetNumbers (fcs),
Packit 352660
		fcs->num * sizeof (FcChar16));
Packit 352660
    }
Packit 352660
    else
Packit 352660
    {
Packit 352660
	ent->set.leaves_offset = 0;
Packit 352660
	ent->set.numbers_offset = 0;
Packit 352660
    }
Packit 352660
Packit 352660
    ent->hash = hash;
Packit 352660
    ent->next = *bucket;
Packit 352660
    *bucket = ent;
Packit 352660
Packit 352660
    return &ent->set;
Packit 352660
}
Packit 352660
Packit 352660
static const FcCharSet *
Packit 352660
FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
Packit 352660
{
Packit 352660
    FcCharSetOrigEnt    **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
Packit 352660
    FcCharSetOrigEnt	*ent;
Packit 352660
Packit 352660
    for (ent = *bucket; ent; ent = ent->next)
Packit 352660
	if (ent->orig == orig)
Packit 352660
	    return ent->frozen;
Packit 352660
    return NULL;
Packit 352660
}
Packit 352660
Packit 352660
const FcCharSet *
Packit 352660
FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
Packit 352660
{
Packit 352660
    FcCharSet	    *b;
Packit 352660
    const FcCharSet *n = 0;
Packit 352660
    FcCharLeaf	    *l;
Packit 352660
    int		    i;
Packit 352660
Packit 352660
    b = FcCharSetCreate ();
Packit 352660
    if (!b)
Packit 352660
	goto bail0;
Packit 352660
    for (i = 0; i < fcs->num; i++)
Packit 352660
    {
Packit 352660
	l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
Packit 352660
	if (!l)
Packit 352660
	    goto bail1;
Packit 352660
	if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
Packit 352660
	    goto bail1;
Packit 352660
    }
Packit 352660
    n = FcCharSetFreezeBase (freezer, b);
Packit 352660
    if (!FcCharSetFreezeOrig (freezer, fcs, n))
Packit 352660
    {
Packit 352660
	n = NULL;
Packit 352660
	goto bail1;
Packit 352660
    }
Packit 352660
    freezer->charsets_seen++;
Packit 352660
    freezer->leaves_seen += fcs->num;
Packit 352660
bail1:
Packit 352660
    if (b->num)
Packit 352660
	free (FcCharSetLeaves (b));
Packit 352660
    if (b->num)
Packit 352660
	free (FcCharSetNumbers (b));
Packit 352660
    free (b);
Packit 352660
bail0:
Packit 352660
    return n;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSetFreezer *
Packit 352660
FcCharSetFreezerCreate (void)
Packit 352660
{
Packit 352660
    FcCharSetFreezer	*freezer;
Packit 352660
Packit 352660
    freezer = calloc (1, sizeof (FcCharSetFreezer));
Packit 352660
    return freezer;
Packit 352660
}
Packit 352660
Packit 352660
void
Packit 352660
FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
Packit 352660
{
Packit 352660
    int i;
Packit 352660
Packit 352660
    if (FcDebug() & FC_DBG_CACHE)
Packit 352660
    {
Packit 352660
	printf ("\ncharsets %d -> %d leaves %d -> %d\n",
Packit 352660
		freezer->charsets_seen, freezer->charsets_allocated,
Packit 352660
		freezer->leaves_seen, freezer->leaves_allocated);
Packit 352660
    }
Packit 352660
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
Packit 352660
    {
Packit 352660
	FcCharSetEnt	*ent, *next;
Packit 352660
	for (ent = freezer->set_hash_table[i]; ent; ent = next)
Packit 352660
	{
Packit 352660
	    next = ent->next;
Packit 352660
	    free (ent);
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
Packit 352660
    {
Packit 352660
	FcCharSetOrigEnt	*ent, *next;
Packit 352660
	for (ent = freezer->orig_hash_table[i]; ent; ent = next)
Packit 352660
	{
Packit 352660
	    next = ent->next;
Packit 352660
	    free (ent);
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    for (i = 0; i < freezer->leaf_block_count; i++)
Packit 352660
	free (freezer->leaf_blocks[i]);
Packit 352660
Packit 352660
    free (freezer->leaf_blocks);
Packit 352660
    free (freezer);
Packit 352660
}
Packit 352660
Packit 352660
FcBool
Packit 352660
FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
Packit 352660
{
Packit 352660
    intptr_t	    *leaves;
Packit 352660
    FcChar16	    *numbers;
Packit 352660
    int		    i;
Packit 352660
Packit 352660
    if (!FcRefIsConst (&cs->ref))
Packit 352660
    {
Packit 352660
	if (!serialize->cs_freezer)
Packit 352660
	{
Packit 352660
	    serialize->cs_freezer = FcCharSetFreezerCreate ();
Packit 352660
	    if (!serialize->cs_freezer)
Packit 352660
		return FcFalse;
Packit 352660
	}
Packit 352660
	if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
Packit 352660
	    return FcTrue;
Packit 352660
Packit 352660
        cs = FcCharSetFreeze (serialize->cs_freezer, cs);
Packit 352660
    }
Packit 352660
Packit 352660
    leaves = FcCharSetLeaves (cs);
Packit 352660
    numbers = FcCharSetNumbers (cs);
Packit 352660
Packit 352660
    if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
Packit 352660
	return FcFalse;
Packit 352660
    if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
Packit 352660
	return FcFalse;
Packit 352660
    if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
Packit 352660
	return FcFalse;
Packit 352660
    for (i = 0; i < cs->num; i++)
Packit 352660
	if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
Packit 352660
			       sizeof (FcCharLeaf)))
Packit 352660
	    return FcFalse;
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
FcCharSet *
Packit 352660
FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
Packit 352660
{
Packit 352660
    FcCharSet	*cs_serialized;
Packit 352660
    intptr_t	*leaves, *leaves_serialized;
Packit 352660
    FcChar16	*numbers, *numbers_serialized;
Packit 352660
    FcCharLeaf	*leaf, *leaf_serialized;
Packit 352660
    int		i;
Packit 352660
Packit 352660
    if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer)
Packit 352660
    {
Packit 352660
	cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
Packit 352660
	if (!cs)
Packit 352660
	    return NULL;
Packit 352660
    }
Packit 352660
		
Packit 352660
    cs_serialized = FcSerializePtr (serialize, cs);
Packit 352660
    if (!cs_serialized)
Packit 352660
	return NULL;
Packit 352660
Packit 352660
    FcRefSetConst (&cs_serialized->ref);
Packit 352660
    cs_serialized->num = cs->num;
Packit 352660
Packit 352660
    if (cs->num)
Packit 352660
    {
Packit 352660
	leaves = FcCharSetLeaves (cs);
Packit 352660
	leaves_serialized = FcSerializePtr (serialize, leaves);
Packit 352660
	if (!leaves_serialized)
Packit 352660
	    return NULL;
Packit 352660
Packit 352660
	cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
Packit 352660
						      leaves_serialized);
Packit 352660
	
Packit 352660
	numbers = FcCharSetNumbers (cs);
Packit 352660
	numbers_serialized = FcSerializePtr (serialize, numbers);
Packit 352660
	if (!numbers)
Packit 352660
	    return NULL;
Packit 352660
Packit 352660
	cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
Packit 352660
						       numbers_serialized);
Packit 352660
Packit 352660
	for (i = 0; i < cs->num; i++)
Packit 352660
	{
Packit 352660
	    leaf = FcCharSetLeaf (cs, i);
Packit 352660
	    leaf_serialized = FcSerializePtr (serialize, leaf);
Packit 352660
	    if (!leaf_serialized)
Packit 352660
		return NULL;
Packit 352660
	    *leaf_serialized = *leaf;
Packit 352660
	    leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
Packit 352660
						  leaf_serialized);
Packit 352660
	    numbers_serialized[i] = numbers[i];
Packit 352660
	}
Packit 352660
    }
Packit 352660
    else
Packit 352660
    {
Packit 352660
	cs_serialized->leaves_offset = 0;
Packit 352660
	cs_serialized->numbers_offset = 0;
Packit 352660
    }
Packit 352660
Packit 352660
    return cs_serialized;
Packit 352660
}
Packit 352660
#define __fccharset__
Packit 352660
#include "fcaliastail.h"
Packit 352660
#undef __fccharset__