2002-07-07 02:00:43 +02:00
|
|
|
/*
|
2003-03-05 06:52:31 +01:00
|
|
|
* $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
|
2002-07-07 02:00:43 +02:00
|
|
|
*
|
2004-12-07 02:14:46 +01:00
|
|
|
* Copyright © 2002 Keith Packard
|
2002-07-07 02:00:43 +02:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation, and that the name of 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.
|
|
|
|
*
|
|
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
* EVENT SHALL KEITH PACKARD 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.
|
|
|
|
*/
|
|
|
|
|
2005-06-28 05:41:02 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/mman.h>
|
2002-07-07 02:00:43 +02:00
|
|
|
#include "fcint.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
FcChar8 *lang;
|
|
|
|
FcCharSet charset;
|
|
|
|
} FcLangCharSet;
|
|
|
|
|
2003-03-05 06:52:31 +01:00
|
|
|
typedef struct {
|
|
|
|
int begin;
|
|
|
|
int end;
|
|
|
|
} FcLangCharSetRange;
|
|
|
|
|
2002-07-08 09:31:53 +02:00
|
|
|
#include "../fc-lang/fclang.h"
|
2002-07-07 02:00:43 +02:00
|
|
|
|
2002-08-22 09:36:45 +02:00
|
|
|
struct _FcLangSet {
|
|
|
|
FcChar32 map[NUM_LANG_SET_MAP];
|
2005-06-28 05:41:02 +02:00
|
|
|
FcStrSetPtr extra;
|
2002-08-22 09:36:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
|
|
|
|
#define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
|
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcFreeTypeLangSet (const FcCharSet *charset,
|
2002-07-08 09:31:53 +02:00
|
|
|
const FcChar8 *exclusiveLang)
|
2002-07-07 02:00:43 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
int i, j;
|
2002-07-08 09:31:53 +02:00
|
|
|
FcChar32 missing;
|
|
|
|
const FcCharSet *exclusiveCharset = 0;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangSet *ls;
|
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
|
2002-07-08 09:31:53 +02:00
|
|
|
if (exclusiveLang)
|
|
|
|
exclusiveCharset = FcCharSetForLang (exclusiveLang);
|
2002-08-22 09:36:45 +02:00
|
|
|
ls = FcLangSetCreate ();
|
|
|
|
if (!ls)
|
|
|
|
return 0;
|
2002-07-07 02:00:43 +02:00
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
2002-07-08 09:31:53 +02:00
|
|
|
/*
|
|
|
|
* Check for Han charsets to make fonts
|
|
|
|
* which advertise support for a single language
|
|
|
|
* not support other Han languages
|
|
|
|
*/
|
|
|
|
if (exclusiveCharset &&
|
2005-06-28 05:41:02 +02:00
|
|
|
FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
|
2002-07-08 09:31:53 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < fcLangCharSets[i].charset.num; j++)
|
|
|
|
if (FcCharSetGetLeaf(&fcLangCharSets[i].charset, j) !=
|
|
|
|
FcCharSetGetLeaf(exclusiveCharset, j))
|
|
|
|
continue;
|
2002-07-08 09:31:53 +02:00
|
|
|
}
|
2002-07-07 02:00:43 +02:00
|
|
|
missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
|
|
|
|
if (FcDebug() & FC_DBG_SCANV)
|
2002-07-12 23:06:03 +02:00
|
|
|
{
|
|
|
|
if (missing && missing < 10)
|
|
|
|
{
|
|
|
|
FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
|
|
|
|
charset);
|
|
|
|
FcChar32 ucs4;
|
|
|
|
FcChar32 map[FC_CHARSET_MAP_SIZE];
|
|
|
|
FcChar32 next;
|
|
|
|
|
|
|
|
printf ("\n%s(%d) ", fcLangCharSets[i].lang, missing);
|
|
|
|
printf ("{");
|
|
|
|
for (ucs4 = FcCharSetFirstPage (missed, map, &next);
|
|
|
|
ucs4 != FC_CHARSET_DONE;
|
|
|
|
ucs4 = FcCharSetNextPage (missed, map, &next))
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
|
|
|
|
if (map[i])
|
|
|
|
{
|
|
|
|
for (j = 0; j < 32; j++)
|
|
|
|
if (map[i] & (1 << j))
|
|
|
|
printf (" %04x", ucs4 + i * 32 + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf (" }\n\t");
|
|
|
|
FcCharSetDestroy (missed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf ("%s(%d) ", fcLangCharSets[i].lang, missing);
|
|
|
|
}
|
2002-07-08 09:31:53 +02:00
|
|
|
if (!missing)
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangSetBitSet (ls, i);
|
2002-07-07 02:00:43 +02:00
|
|
|
}
|
2002-07-08 09:31:53 +02:00
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
if (FcDebug() & FC_DBG_SCANV)
|
|
|
|
printf ("\n");
|
2002-08-22 09:36:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
return ls;
|
2002-07-07 02:00:43 +02:00
|
|
|
}
|
|
|
|
|
2002-08-22 09:36:45 +02:00
|
|
|
#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
|
2002-07-07 02:00:43 +02:00
|
|
|
|
|
|
|
FcLangResult
|
|
|
|
FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
|
|
|
|
{
|
|
|
|
FcChar8 c1, c2;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangResult result = FcLangDifferentLang;
|
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
c1 = *s1++;
|
|
|
|
c2 = *s2++;
|
2002-08-22 09:36:45 +02:00
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
c1 = FcToLower (c1);
|
|
|
|
c2 = FcToLower (c2);
|
|
|
|
if (c1 != c2)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
|
|
|
if (FcLangEnd (c1) && FcLangEnd (c2))
|
|
|
|
result = FcLangDifferentCountry;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else if (!c1)
|
|
|
|
return FcLangEqual;
|
|
|
|
else if (c1 == '-')
|
|
|
|
result = FcLangDifferentCountry;
|
2002-07-07 02:00:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-05 06:52:31 +01:00
|
|
|
/*
|
2003-07-20 18:06:18 +02:00
|
|
|
* Return FcTrue when super contains sub.
|
2003-03-05 06:52:31 +01:00
|
|
|
*
|
2003-07-20 18:06:18 +02:00
|
|
|
* super contains sub if super and sub have the same
|
|
|
|
* language and either the same country or one
|
|
|
|
* is missing the country
|
2003-03-05 06:52:31 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
static FcBool
|
2003-07-20 18:06:18 +02:00
|
|
|
FcLangContains (const FcChar8 *super, const FcChar8 *sub)
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
|
|
|
FcChar8 c1, c2;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2003-07-20 18:06:18 +02:00
|
|
|
c1 = *super++;
|
|
|
|
c2 = *sub++;
|
2003-03-05 06:52:31 +01:00
|
|
|
|
|
|
|
c1 = FcToLower (c1);
|
|
|
|
c2 = FcToLower (c2);
|
|
|
|
if (c1 != c2)
|
|
|
|
{
|
2003-07-20 18:06:18 +02:00
|
|
|
/* see if super has a country while sub is mising one */
|
2003-03-05 06:52:31 +01:00
|
|
|
if (c1 == '-' && c2 == '\0')
|
|
|
|
return FcTrue;
|
2003-07-20 18:06:18 +02:00
|
|
|
/* see if sub has a country while super is mising one */
|
|
|
|
if (c1 == '\0' && c2 == '-')
|
|
|
|
return FcTrue;
|
2003-03-05 06:52:31 +01:00
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
else if (!c1)
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
const FcCharSet *
|
|
|
|
FcCharSetForLang (const FcChar8 *lang)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int country = -1;
|
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
|
|
|
switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
|
|
|
|
case FcLangEqual:
|
|
|
|
return &fcLangCharSets[i].charset;
|
|
|
|
case FcLangDifferentCountry:
|
|
|
|
if (country == -1)
|
|
|
|
country = i;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (country == -1)
|
|
|
|
return 0;
|
|
|
|
return &fcLangCharSets[i].charset;
|
|
|
|
}
|
2002-08-22 09:36:45 +02:00
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcLangSetCreate (void)
|
|
|
|
{
|
|
|
|
FcLangSet *ls;
|
|
|
|
|
|
|
|
ls = malloc (sizeof (FcLangSet));
|
|
|
|
if (!ls)
|
|
|
|
return 0;
|
|
|
|
FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
|
|
|
|
memset (ls->map, '\0', sizeof (ls->map));
|
2005-06-28 05:41:02 +02:00
|
|
|
ls->extra = FcStrSetPtrCreateDynamic(0);
|
2002-08-22 09:36:45 +02:00
|
|
|
return ls;
|
|
|
|
}
|
|
|
|
|
2005-06-28 05:41:02 +02:00
|
|
|
void
|
|
|
|
FcLangSetPtrDestroy (FcLangSetPtr li)
|
|
|
|
{
|
|
|
|
if (li.storage == FcStorageDynamic)
|
|
|
|
FcLangSetDestroy(FcLangSetPtrU(li));
|
|
|
|
}
|
|
|
|
|
2002-08-22 09:36:45 +02:00
|
|
|
void
|
|
|
|
FcLangSetDestroy (FcLangSet *ls)
|
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
|
|
|
FcStrSetDestroy (FcStrSetPtrU(ls->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
|
|
|
|
free (ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcLangSetCopy (const FcLangSet *ls)
|
|
|
|
{
|
|
|
|
FcLangSet *new;
|
|
|
|
|
|
|
|
new = FcLangSetCreate ();
|
|
|
|
if (!new)
|
|
|
|
goto bail0;
|
|
|
|
memcpy (new->map, ls->map, sizeof (new->map));
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *extra;
|
|
|
|
|
2005-06-28 05:41:02 +02:00
|
|
|
new->extra = FcStrSetPtrCreateDynamic(FcStrSetCreate ());
|
|
|
|
if (!FcStrSetPtrU(new->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
goto bail1;
|
|
|
|
|
2005-06-28 05:41:02 +02:00
|
|
|
list = FcStrListCreate (FcStrSetPtrU(ls->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
if (!list)
|
|
|
|
goto bail1;
|
|
|
|
|
|
|
|
while ((extra = FcStrListNext (list)))
|
2005-06-28 05:41:02 +02:00
|
|
|
if (!FcStrSetAdd (FcStrSetPtrU(new->extra), extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
|
|
|
FcStrListDone (list);
|
|
|
|
goto bail1;
|
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
|
|
|
}
|
|
|
|
return new;
|
|
|
|
bail1:
|
|
|
|
FcLangSetDestroy (new);
|
|
|
|
bail0:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
FcLangSetIndex (const FcChar8 *lang)
|
|
|
|
{
|
2003-04-17 19:43:04 +02:00
|
|
|
int low, high, mid = 0;
|
|
|
|
int cmp = 0;
|
2003-03-05 06:52:31 +01:00
|
|
|
FcChar8 firstChar = FcToLower(lang[0]);
|
2003-06-09 19:31:03 +02:00
|
|
|
FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
|
2003-03-05 06:52:31 +01:00
|
|
|
|
|
|
|
if (firstChar < 'a')
|
|
|
|
{
|
|
|
|
low = 0;
|
|
|
|
high = fcLangCharSetRanges[0].begin;
|
|
|
|
}
|
|
|
|
else if(firstChar > 'z')
|
|
|
|
{
|
|
|
|
low = fcLangCharSetRanges[25].begin;
|
|
|
|
high = NUM_LANG_CHAR_SET - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
low = fcLangCharSetRanges[firstChar - 'a'].begin;
|
|
|
|
high = fcLangCharSetRanges[firstChar - 'a'].end;
|
|
|
|
/* no matches */
|
|
|
|
if (low > high)
|
|
|
|
return -low; /* next entry after where it would be */
|
|
|
|
}
|
2002-08-22 09:36:45 +02:00
|
|
|
|
|
|
|
while (low <= high)
|
|
|
|
{
|
|
|
|
mid = (high + low) >> 1;
|
2003-03-05 06:52:31 +01:00
|
|
|
if(fcLangCharSets[mid].lang[0] != firstChar)
|
|
|
|
cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
|
|
|
|
else
|
|
|
|
{ /* fast path for resolving 2-letter languages (by far the most common) after
|
|
|
|
* finding the first char (probably already true because of the hash table) */
|
2003-06-09 19:31:03 +02:00
|
|
|
cmp = fcLangCharSets[mid].lang[1] - secondChar;
|
|
|
|
if (cmp == 0 &&
|
|
|
|
(fcLangCharSets[mid].lang[2] != '\0' ||
|
|
|
|
lang[2] != '\0'))
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
2003-06-09 19:31:03 +02:00
|
|
|
cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
|
|
|
|
lang+2);
|
2003-03-05 06:52:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cmp == 0)
|
2002-08-22 09:36:45 +02:00
|
|
|
return mid;
|
|
|
|
if (cmp < 0)
|
|
|
|
low = mid + 1;
|
|
|
|
else
|
|
|
|
high = mid - 1;
|
|
|
|
}
|
|
|
|
if (cmp < 0)
|
|
|
|
mid++;
|
|
|
|
return -(mid + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
|
|
|
|
id = FcLangSetIndex (lang);
|
|
|
|
if (id >= 0)
|
|
|
|
{
|
|
|
|
FcLangSetBitSet (ls, id);
|
|
|
|
return FcTrue;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (!FcStrSetPtrU(ls->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
ls->extra = FcStrSetPtrCreateDynamic(FcStrSetCreate ());
|
|
|
|
if (!FcStrSetPtrU(ls->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
return FcStrSetAdd (FcStrSetPtrU(ls->extra), lang);
|
2002-08-22 09:36:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FcLangResult
|
|
|
|
FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
FcLangResult best, r;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
id = FcLangSetIndex (lang);
|
2002-08-27 01:34:31 +02:00
|
|
|
if (id < 0)
|
|
|
|
id = -id - 1;
|
|
|
|
else if (FcLangSetBitGet (ls, id))
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcLangEqual;
|
|
|
|
best = FcLangDifferentLang;
|
|
|
|
for (i = id - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
r = FcLangCompare (lang, fcLangCharSets[i].lang);
|
|
|
|
if (r == FcLangDifferentLang)
|
|
|
|
break;
|
|
|
|
if (FcLangSetBitGet (ls, i) && r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
|
|
|
for (i = id; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
|
|
|
r = FcLangCompare (lang, fcLangCharSets[i].lang);
|
|
|
|
if (r == FcLangDifferentLang)
|
|
|
|
break;
|
|
|
|
if (FcLangSetBitGet (ls, i) && r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
FcChar8 *extra;
|
|
|
|
FcLangResult r;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while (best > FcLangEqual && (extra = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
r = FcLangCompare (lang, extra);
|
|
|
|
if (r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FcLangResult
|
|
|
|
FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
|
|
|
|
{
|
|
|
|
FcStrList *list = FcStrListCreate (set);
|
|
|
|
FcLangResult r, best = FcLangDifferentLang;
|
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while (best > FcLangEqual && (extra = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
r = FcLangSetHasLang (ls, extra);
|
|
|
|
if (r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangResult
|
|
|
|
FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
|
|
|
|
{
|
2002-12-14 03:03:59 +01:00
|
|
|
int i, j;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangResult best, r;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
if (lsa->map[i] & lsb->map[i])
|
|
|
|
return FcLangEqual;
|
|
|
|
best = FcLangDifferentLang;
|
2002-12-14 03:03:59 +01:00
|
|
|
for (j = 0; j < NUM_COUNTRY_SET; j++)
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
|
|
|
|
(lsb->map[i] & fcLangCountrySets[j][i]))
|
|
|
|
{
|
|
|
|
best = FcLangDifferentCountry;
|
|
|
|
break;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(lsa->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
r = FcLangSetCompareStrSet (lsb, FcStrSetPtrU(lsa->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
if (r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (best > FcLangEqual && FcStrSetPtrU(lsb->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
r = FcLangSetCompareStrSet (lsa, FcStrSetPtrU(lsb->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
if (r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Used in computing values -- mustn't allocate any storage
|
|
|
|
*/
|
|
|
|
FcLangSet *
|
|
|
|
FcLangSetPromote (const FcChar8 *lang)
|
|
|
|
{
|
|
|
|
static FcLangSet ls;
|
|
|
|
static FcStrSet strs;
|
|
|
|
static FcChar8 *str;
|
|
|
|
int id;
|
|
|
|
|
|
|
|
memset (ls.map, '\0', sizeof (ls.map));
|
2005-06-28 05:41:02 +02:00
|
|
|
ls.extra = FcStrSetPtrCreateDynamic(0);
|
2002-08-22 09:36:45 +02:00
|
|
|
id = FcLangSetIndex (lang);
|
|
|
|
if (id > 0)
|
|
|
|
{
|
|
|
|
FcLangSetBitSet (&ls, id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
ls.extra = FcStrSetPtrCreateDynamic(&strs);
|
2002-08-22 09:36:45 +02:00
|
|
|
strs.num = 1;
|
|
|
|
strs.size = 1;
|
2005-06-28 05:41:02 +02:00
|
|
|
strs.storage = FcStorageDynamic;
|
|
|
|
strs.u.strs = &str;
|
2002-08-22 20:53:22 +02:00
|
|
|
strs.ref = 1;
|
2002-08-22 09:36:45 +02:00
|
|
|
str = (FcChar8 *) lang;
|
|
|
|
}
|
|
|
|
return &ls;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcChar32
|
|
|
|
FcLangSetHash (const FcLangSet *ls)
|
|
|
|
{
|
|
|
|
FcChar32 h = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
h ^= ls->map[i];
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
|
|
|
h ^= FcStrSetPtrU(ls->extra)->num;
|
2002-08-22 09:36:45 +02:00
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcNameParseLangSet (const FcChar8 *string)
|
|
|
|
{
|
2003-03-05 06:52:31 +01:00
|
|
|
FcChar8 lang[32],c;
|
|
|
|
int i;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangSet *ls;
|
|
|
|
|
|
|
|
ls = FcLangSetCreate ();
|
|
|
|
if (!ls)
|
|
|
|
goto bail0;
|
|
|
|
|
2003-03-05 06:52:31 +01:00
|
|
|
for(;;)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2003-03-05 06:52:31 +01:00
|
|
|
for(i = 0; i < 31;i++)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2003-03-05 06:52:31 +01:00
|
|
|
c = *string++;
|
|
|
|
if(c == '\0' || c == '|')
|
|
|
|
break; /* end of this code */
|
|
|
|
lang[i] = c;
|
2002-08-22 09:36:45 +02:00
|
|
|
}
|
2003-03-05 06:52:31 +01:00
|
|
|
lang[i] = '\0';
|
|
|
|
if (!FcLangSetAdd (ls, lang))
|
|
|
|
goto bail1;
|
|
|
|
if(c == '\0')
|
|
|
|
break;
|
2002-08-22 09:36:45 +02:00
|
|
|
}
|
|
|
|
return ls;
|
|
|
|
bail1:
|
|
|
|
FcLangSetDestroy (ls);
|
|
|
|
bail0:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
|
|
|
|
{
|
|
|
|
int i, bit;
|
|
|
|
FcChar32 bits;
|
|
|
|
FcBool first = FcTrue;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
{
|
|
|
|
if ((bits = ls->map[i]))
|
|
|
|
{
|
|
|
|
for (bit = 0; bit <= 31; bit++)
|
|
|
|
if (bits & (1 << bit))
|
|
|
|
{
|
|
|
|
int id = (i << 5) | bit;
|
|
|
|
if (!first)
|
|
|
|
if (!FcStrBufChar (buf, '|'))
|
|
|
|
return FcFalse;
|
|
|
|
if (!FcStrBufString (buf, fcLangCharSets[id].lang))
|
|
|
|
return FcFalse;
|
|
|
|
first = FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
if (!list)
|
|
|
|
return FcFalse;
|
|
|
|
while ((extra = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
if (!first)
|
|
|
|
if (!FcStrBufChar (buf, '|'))
|
|
|
|
return FcFalse;
|
2003-03-05 06:52:31 +01:00
|
|
|
if (!FcStrBufString (buf, extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
|
|
|
first = FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
{
|
|
|
|
if (lsa->map[i] != lsb->map[i])
|
|
|
|
return FcFalse;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (!FcStrSetPtrU(lsa->extra) && !FcStrSetPtrU(lsb->extra))
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcTrue;
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(lsa->extra) && FcStrSetPtrU(lsb->extra))
|
|
|
|
return FcStrSetEqual (FcStrSetPtrU(lsa->extra), FcStrSetPtrU(lsb->extra));
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
|
|
|
}
|
2003-03-05 06:52:31 +01:00
|
|
|
|
|
|
|
static FcBool
|
|
|
|
FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
id = FcLangSetIndex (lang);
|
|
|
|
if (id < 0)
|
|
|
|
id = -id - 1;
|
|
|
|
else if (FcLangSetBitGet (ls, id))
|
|
|
|
return FcTrue;
|
|
|
|
/*
|
|
|
|
* search up and down among equal languages for a match
|
|
|
|
*/
|
|
|
|
for (i = id - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
|
|
|
|
break;
|
|
|
|
if (FcLangSetBitGet (ls, i) &&
|
|
|
|
FcLangContains (fcLangCharSets[i].lang, lang))
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
for (i = id; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
|
|
|
if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
|
|
|
|
break;
|
|
|
|
if (FcLangSetBitGet (ls, i) &&
|
|
|
|
FcLangContains (fcLangCharSets[i].lang, lang))
|
|
|
|
return FcTrue;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(ls->extra))
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
|
2003-03-05 06:52:31 +01:00
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while ((extra = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
if (FcLangContains (extra, lang))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
|
|
|
if (extra)
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return FcTrue if lsa contains every language in lsb
|
|
|
|
*/
|
|
|
|
FcBool
|
|
|
|
FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
FcChar32 missing;
|
|
|
|
|
|
|
|
if (FcDebug() & FC_DBG_MATCHV)
|
|
|
|
{
|
|
|
|
printf ("FcLangSet "); FcLangSetPrint (lsa);
|
|
|
|
printf (" contains "); FcLangSetPrint (lsb);
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* check bitmaps for missing language support
|
|
|
|
*/
|
|
|
|
for (i = 0; i < NUM_LANG_SET_MAP; i++)
|
|
|
|
{
|
|
|
|
missing = lsb->map[i] & ~lsa->map[i];
|
|
|
|
if (missing)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 32; j++)
|
|
|
|
if (missing & (1 << j))
|
|
|
|
{
|
|
|
|
if (!FcLangSetContainsLang (lsa,
|
|
|
|
fcLangCharSets[i*32 + j].lang))
|
|
|
|
{
|
|
|
|
if (FcDebug() & FC_DBG_MATCHV)
|
|
|
|
printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
if (FcStrSetPtrU(lsb->extra))
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
2005-06-28 05:41:02 +02:00
|
|
|
FcStrList *list = FcStrListCreate (FcStrSetPtrU(lsb->extra));
|
2003-03-05 06:52:31 +01:00
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while ((extra = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
if (!FcLangSetContainsLang (lsa, extra))
|
|
|
|
{
|
|
|
|
if (FcDebug() & FC_DBG_MATCHV)
|
|
|
|
printf ("\tMissing string %s\n", extra);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
|
|
|
if (extra)
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FcTrue;
|
|
|
|
}
|
2005-06-28 05:41:02 +02:00
|
|
|
|
|
|
|
static FcLangSet * langsets = 0;
|
|
|
|
static int langset_ptr = 0, langset_count = 0;
|
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcLangSetPtrU (FcLangSetPtr li)
|
|
|
|
{
|
|
|
|
switch (li.storage)
|
|
|
|
{
|
|
|
|
case FcStorageDynamic:
|
|
|
|
return li.u.dyn;
|
|
|
|
case FcStorageStatic:
|
|
|
|
return &langsets[li.u.stat];
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangSetPtr
|
|
|
|
FcLangSetPtrCreateDynamic (FcLangSet *li)
|
|
|
|
{
|
|
|
|
FcLangSetPtr new;
|
|
|
|
new.storage = FcStorageDynamic;
|
|
|
|
new.u.dyn = li;
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcLangSetClearStatic (void)
|
|
|
|
{
|
|
|
|
FcStrSetClearStatic();
|
|
|
|
langset_ptr = 0;
|
|
|
|
langset_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* should only write one copy of any particular FcLangSet */
|
|
|
|
FcBool
|
|
|
|
FcLangSetPrepareSerialize (FcLangSet *l)
|
|
|
|
{
|
|
|
|
langset_count++;
|
|
|
|
if (l && FcStrSetPtrU(l->extra))
|
|
|
|
return FcStrSetPrepareSerialize (FcStrSetPtrU(l->extra));
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangSetPtr
|
|
|
|
FcLangSetSerialize(FcLangSet *l)
|
|
|
|
{
|
|
|
|
FcLangSetPtr new;
|
|
|
|
int p = langset_ptr;
|
|
|
|
|
|
|
|
if (!l) return FcLangSetPtrCreateDynamic(0);
|
|
|
|
|
|
|
|
if (!langsets)
|
|
|
|
{
|
|
|
|
FcLangSet* t;
|
|
|
|
t = (FcLangSet *)malloc(langset_count * sizeof(FcLangSet));
|
|
|
|
if (!t)
|
|
|
|
return FcLangSetPtrCreateDynamic(0);
|
|
|
|
langsets = t;
|
|
|
|
langset_ptr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
langsets[langset_ptr] = *l;
|
|
|
|
if (FcStrSetPtrU(l->extra))
|
|
|
|
langsets[langset_ptr].extra =
|
|
|
|
FcStrSetSerialize(FcStrSetPtrU(l->extra));
|
|
|
|
else
|
|
|
|
langsets[langset_ptr].extra = FcStrSetPtrCreateDynamic(0);
|
|
|
|
langset_ptr++;
|
|
|
|
new.storage = FcStorageStatic;
|
|
|
|
new.u.stat = p;
|
|
|
|
return new;
|
|
|
|
}
|
2005-07-25 06:10:09 +02:00
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcLangSetWrite (int fd, FcCache *metadata)
|
|
|
|
{
|
|
|
|
metadata->langsets_length = langset_ptr;
|
|
|
|
metadata->langsets_offset = FcCacheNextOffset(fd);
|
|
|
|
|
|
|
|
if (langset_ptr > 0)
|
|
|
|
{
|
|
|
|
lseek (fd, metadata->langsets_offset, SEEK_SET);
|
|
|
|
return write(fd, langsets,
|
|
|
|
metadata->langsets_length * sizeof(FcLangSet)) != -1;
|
|
|
|
}
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcLangSetRead (int fd, FcCache metadata)
|
|
|
|
{
|
|
|
|
langsets = mmap(NULL,
|
|
|
|
metadata.langsets_length * sizeof (FcLangSet),
|
|
|
|
PROT_READ,
|
|
|
|
MAP_SHARED, fd, metadata.langsets_offset);
|
|
|
|
if (langsets == MAP_FAILED)
|
|
|
|
return FcFalse;
|
|
|
|
langset_count = langset_ptr = metadata.langsets_length;
|
|
|
|
return FcTrue;
|
|
|
|
}
|