2002-07-07 02:00:43 +02:00
|
|
|
/*
|
2008-08-12 22:34:24 +02:00
|
|
|
* fontconfig/src/fclang.c
|
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.
|
|
|
|
*
|
2009-03-12 21:00:08 +01:00
|
|
|
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
2002-07-07 02:00:43 +02:00
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
2009-03-12 21:00:08 +01:00
|
|
|
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
2002-07-07 02:00:43 +02:00
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fcint.h"
|
2008-01-02 17:47:14 +01:00
|
|
|
#include "fcftint.h"
|
2002-07-07 02:00:43 +02:00
|
|
|
|
|
|
|
typedef struct {
|
2007-10-18 17:58:14 +02:00
|
|
|
const FcChar8 lang[8];
|
2005-10-14 23:02:31 +02:00
|
|
|
const FcCharSet charset;
|
2002-07-07 02:00:43 +02:00
|
|
|
} 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 {
|
2005-08-24 08:21:30 +02:00
|
|
|
FcStrSet *extra;
|
2009-11-16 21:39:16 +01:00
|
|
|
int map_size;
|
|
|
|
FcChar32 map[NUM_LANG_SET_MAP];
|
2002-08-22 09:36:45 +02:00
|
|
|
};
|
|
|
|
|
2009-11-16 21:39:16 +01:00
|
|
|
static void
|
|
|
|
FcLangSetBitSet (FcLangSet *ls,
|
|
|
|
unsigned int id)
|
|
|
|
{
|
|
|
|
int bucket;
|
|
|
|
|
|
|
|
id = fcLangCharSetIndices[id];
|
|
|
|
bucket = id >> 5;
|
|
|
|
if (bucket >= ls->map_size)
|
|
|
|
return; /* shouldn't happen really */
|
|
|
|
|
|
|
|
ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f));
|
|
|
|
}
|
|
|
|
|
|
|
|
static FcBool
|
|
|
|
FcLangSetBitGet (const FcLangSet *ls,
|
|
|
|
unsigned int id)
|
|
|
|
{
|
|
|
|
int bucket;
|
|
|
|
|
|
|
|
id = fcLangCharSetIndices[id];
|
|
|
|
bucket = id >> 5;
|
|
|
|
if (bucket >= ls->map_size)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
|
|
|
|
}
|
2002-08-22 09:36:45 +02:00
|
|
|
|
|
|
|
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;
|
2005-11-04 20:31:26 +01:00
|
|
|
|
2002-07-08 09:31:53 +02:00
|
|
|
if (exclusiveLang)
|
2007-11-05 21:29:44 +01:00
|
|
|
exclusiveCharset = FcLangGetCharSet (exclusiveLang);
|
2002-08-22 09:36:45 +02:00
|
|
|
ls = FcLangSetCreate ();
|
|
|
|
if (!ls)
|
|
|
|
return 0;
|
2006-08-30 13:16:22 +02:00
|
|
|
if (FcDebug() & FC_DBG_LANGSET)
|
|
|
|
{
|
2009-07-28 20:23:10 +02:00
|
|
|
printf ("font charset");
|
2006-08-30 13:16:22 +02:00
|
|
|
FcCharSetPrint (charset);
|
|
|
|
printf ("\n");
|
|
|
|
}
|
2002-07-07 02:00:43 +02:00
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
if (FcDebug() & FC_DBG_LANGSET)
|
|
|
|
{
|
2009-07-28 20:23:10 +02:00
|
|
|
printf ("%s charset", fcLangCharSets[i].lang);
|
2006-08-30 13:16:22 +02:00
|
|
|
FcCharSetPrint (&fcLangCharSets[i].charset);
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
|
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++)
|
2006-08-30 13:16:22 +02:00
|
|
|
if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
|
|
|
|
FcCharSetLeaf(exclusiveCharset, j))
|
2005-06-28 05:41:02 +02:00
|
|
|
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;
|
|
|
|
|
2006-04-06 06:33:11 +02:00
|
|
|
printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
|
2002-07-12 23:06:03 +02:00
|
|
|
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
|
2006-04-06 06:33:11 +02:00
|
|
|
printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
|
2002-07-12 23:06:03 +02:00
|
|
|
}
|
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))
|
2007-11-04 05:58:34 +01:00
|
|
|
result = FcLangDifferentTerritory;
|
2002-08-22 09:36:45 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else if (!c1)
|
|
|
|
return FcLangEqual;
|
|
|
|
else if (c1 == '-')
|
2007-11-04 05:58:34 +01:00
|
|
|
result = FcLangDifferentTerritory;
|
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 *
|
2007-11-05 21:29:44 +01:00
|
|
|
FcLangGetCharSet (const FcChar8 *lang)
|
2002-07-07 02:00:43 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int country = -1;
|
2005-11-04 20:31:26 +01:00
|
|
|
|
2002-07-07 02:00:43 +02:00
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
{
|
|
|
|
switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
|
|
|
|
case FcLangEqual:
|
|
|
|
return &fcLangCharSets[i].charset;
|
2007-11-04 05:58:34 +01:00
|
|
|
case FcLangDifferentTerritory:
|
2002-07-07 02:00:43 +02:00
|
|
|
if (country == -1)
|
|
|
|
country = i;
|
2009-11-16 21:39:16 +01:00
|
|
|
case FcLangDifferentLang:
|
2002-07-07 02:00:43 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (country == -1)
|
|
|
|
return 0;
|
2006-03-03 07:11:31 +01:00
|
|
|
return &fcLangCharSets[country].charset;
|
2002-07-07 02:00:43 +02:00
|
|
|
}
|
2002-08-22 09:36:45 +02:00
|
|
|
|
2007-11-05 21:29:44 +01:00
|
|
|
FcStrSet *
|
|
|
|
FcGetLangs (void)
|
|
|
|
{
|
|
|
|
FcStrSet *langs;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
langs = FcStrSetCreate();
|
|
|
|
if (!langs)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
FcStrSetAdd (langs, fcLangCharSets[i].lang);
|
|
|
|
|
|
|
|
return langs;
|
|
|
|
}
|
|
|
|
|
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));
|
2009-11-16 21:39:16 +01:00
|
|
|
ls->map_size = NUM_LANG_SET_MAP;
|
2005-08-24 08:21:30 +02:00
|
|
|
ls->extra = 0;
|
2002-08-22 09:36:45 +02:00
|
|
|
return ls;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcLangSetDestroy (FcLangSet *ls)
|
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
|
|
|
FcStrSetDestroy (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;
|
2009-11-16 21:39:16 +01:00
|
|
|
memset (new->map, '\0', sizeof (new->map));
|
|
|
|
memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0])));
|
2005-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *extra;
|
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
new->extra = FcStrSetCreate ();
|
|
|
|
if (!new->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
goto bail1;
|
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
list = FcStrListCreate (ls->extra);
|
2002-08-22 09:36:45 +02:00
|
|
|
if (!list)
|
|
|
|
goto bail1;
|
|
|
|
|
|
|
|
while ((extra = FcStrListNext (list)))
|
2005-08-24 08:21:30 +02:00
|
|
|
if (!FcStrSetAdd (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-08-24 08:21:30 +02:00
|
|
|
if (!ls->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
ls->extra = FcStrSetCreate ();
|
|
|
|
if (!ls->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
return FcStrSetAdd (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-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
FcStrList *list = FcStrListCreate (ls->extra);
|
2002-08-22 09:36:45 +02:00
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2009-11-16 21:39:16 +01:00
|
|
|
int i, j, count;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcLangResult best, r;
|
|
|
|
|
2009-11-16 21:39:16 +01:00
|
|
|
count = FC_MIN (lsa->map_size, lsb->map_size);
|
|
|
|
count = FC_MIN (NUM_LANG_SET_MAP, count);
|
|
|
|
for (i = 0; i < count; i++)
|
2002-08-22 09:36:45 +02:00
|
|
|
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++)
|
2009-11-16 21:39:16 +01:00
|
|
|
for (i = 0; i < count; i++)
|
2002-12-14 03:03:59 +01:00
|
|
|
if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
|
|
|
|
(lsb->map[i] & fcLangCountrySets[j][i]))
|
|
|
|
{
|
2007-11-04 05:58:34 +01:00
|
|
|
best = FcLangDifferentTerritory;
|
2002-12-14 03:03:59 +01:00
|
|
|
break;
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
if (lsa->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
r = FcLangSetCompareStrSet (lsb, lsa->extra);
|
2002-08-22 09:36:45 +02:00
|
|
|
if (r < best)
|
|
|
|
best = r;
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
if (best > FcLangEqual && lsb->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
r = FcLangSetCompareStrSet (lsa, 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-08-24 08:21:30 +02:00
|
|
|
ls.extra = 0;
|
2002-08-22 09:36:45 +02:00
|
|
|
id = FcLangSetIndex (lang);
|
|
|
|
if (id > 0)
|
|
|
|
{
|
|
|
|
FcLangSetBitSet (&ls, id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
ls.extra = &strs;
|
2002-08-22 09:36:45 +02:00
|
|
|
strs.num = 1;
|
|
|
|
strs.size = 1;
|
2005-08-24 08:21:30 +02:00
|
|
|
strs.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;
|
|
|
|
|
2009-11-16 21:39:16 +01:00
|
|
|
for (i = 0; i < ls->map_size; i++)
|
2002-08-22 09:36:45 +02:00
|
|
|
h ^= ls->map[i];
|
2005-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
|
|
|
h ^= ls->extra->num;
|
2002-08-22 09:36:45 +02:00
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcLangSet *
|
|
|
|
FcNameParseLangSet (const FcChar8 *string)
|
|
|
|
{
|
2009-11-16 21:39:16 +01:00
|
|
|
FcChar8 lang[32], c = 0;
|
2003-03-05 06:52:31 +01:00
|
|
|
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)
|
|
|
|
{
|
2009-11-16 21:39:16 +01:00
|
|
|
int i, bit, count;
|
2009-08-26 02:40:30 +02:00
|
|
|
FcChar32 bits;
|
2002-08-22 09:36:45 +02:00
|
|
|
FcBool first = FcTrue;
|
|
|
|
|
2009-11-16 21:39:16 +01:00
|
|
|
count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
|
|
|
|
for (i = 0; i < count; i++)
|
2009-08-26 02:40:30 +02:00
|
|
|
{
|
|
|
|
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[fcLangCharSetIndicesInv[id]].lang))
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
2009-08-26 02:40:30 +02:00
|
|
|
first = FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
FcStrList *list = FcStrListCreate (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, '|'))
|
2006-04-11 16:20:59 +02:00
|
|
|
{
|
|
|
|
FcStrListDone (list);
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcFalse;
|
2006-04-11 16:20:59 +02:00
|
|
|
}
|
2003-03-05 06:52:31 +01:00
|
|
|
if (!FcStrBufString (buf, extra))
|
2006-04-11 16:20:59 +02:00
|
|
|
{
|
|
|
|
FcStrListDone (list);
|
|
|
|
return FcFalse;
|
|
|
|
}
|
2002-08-22 09:36:45 +02:00
|
|
|
first = FcFalse;
|
|
|
|
}
|
2006-04-11 18:54:24 +02:00
|
|
|
FcStrListDone (list);
|
2002-08-22 09:36:45 +02:00
|
|
|
}
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcBool
|
|
|
|
FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
|
|
|
|
{
|
2009-11-16 21:39:16 +01:00
|
|
|
int i, count;
|
2002-08-22 09:36:45 +02:00
|
|
|
|
2009-11-16 21:39:16 +01:00
|
|
|
count = FC_MIN (lsa->map_size, lsb->map_size);
|
|
|
|
count = FC_MIN (NUM_LANG_SET_MAP, count);
|
|
|
|
for (i = 0; i < count; i++)
|
2002-08-22 09:36:45 +02:00
|
|
|
{
|
|
|
|
if (lsa->map[i] != lsb->map[i])
|
|
|
|
return FcFalse;
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
if (!lsa->extra && !lsb->extra)
|
2002-08-22 09:36:45 +02:00
|
|
|
return FcTrue;
|
2005-08-24 08:21:30 +02:00
|
|
|
if (lsa->extra && lsb->extra)
|
|
|
|
return FcStrSetEqual (lsa->extra, 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-08-24 08:21:30 +02:00
|
|
|
if (ls->extra)
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
FcStrList *list = FcStrListCreate (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)
|
|
|
|
{
|
2009-11-16 21:39:16 +01:00
|
|
|
int i, j, count;
|
2003-03-05 06:52:31 +01:00
|
|
|
FcChar32 missing;
|
|
|
|
|
|
|
|
if (FcDebug() & FC_DBG_MATCHV)
|
|
|
|
{
|
|
|
|
printf ("FcLangSet "); FcLangSetPrint (lsa);
|
|
|
|
printf (" contains "); FcLangSetPrint (lsb);
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* check bitmaps for missing language support
|
|
|
|
*/
|
2009-11-16 21:39:16 +01:00
|
|
|
count = FC_MIN (lsa->map_size, lsb->map_size);
|
|
|
|
count = FC_MIN (NUM_LANG_SET_MAP, count);
|
|
|
|
for (i = 0; i < count; i++)
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
|
|
|
missing = lsb->map[i] & ~lsa->map[i];
|
|
|
|
if (missing)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 32; j++)
|
|
|
|
if (missing & (1 << j))
|
|
|
|
{
|
|
|
|
if (!FcLangSetContainsLang (lsa,
|
2009-08-26 02:39:20 +02:00
|
|
|
fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
|
|
|
if (FcDebug() & FC_DBG_MATCHV)
|
2009-08-26 02:39:20 +02:00
|
|
|
printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang);
|
2003-03-05 06:52:31 +01:00
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
if (lsb->extra)
|
2003-03-05 06:52:31 +01:00
|
|
|
{
|
2005-08-24 08:21:30 +02:00
|
|
|
FcStrList *list = FcStrListCreate (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
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
FcBool
|
|
|
|
FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
|
2005-06-28 05:41:02 +02:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
|
|
|
|
return FcFalse;
|
2005-08-24 08:21:30 +02:00
|
|
|
return FcTrue;
|
2005-06-28 05:41:02 +02:00
|
|
|
}
|
2005-07-25 06:10:09 +02:00
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
FcLangSet *
|
2006-08-30 13:16:22 +02:00
|
|
|
FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
|
2005-08-24 08:21:30 +02:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcLangSet *l_serialize = FcSerializePtr (serialize, l);
|
2005-08-24 08:21:30 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
if (!l_serialize)
|
|
|
|
return NULL;
|
|
|
|
*l_serialize = *l;
|
2009-11-16 21:39:16 +01:00
|
|
|
l_serialize->extra = NULL; /* We don't serialize ls->extra */
|
2006-08-30 13:16:22 +02:00
|
|
|
return l_serialize;
|
2005-07-25 06:10:09 +02:00
|
|
|
}
|
2009-02-14 01:30:43 +01:00
|
|
|
|
|
|
|
FcStrSet *
|
|
|
|
FcLangSetGetLangs (const FcLangSet *ls)
|
|
|
|
{
|
|
|
|
FcStrSet *langs;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
langs = FcStrSetCreate();
|
|
|
|
if (!langs)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LANG_CHAR_SET; i++)
|
|
|
|
if (FcLangSetBitGet (ls, i))
|
|
|
|
FcStrSetAdd (langs, fcLangCharSets[i].lang);
|
|
|
|
|
|
|
|
if (ls->extra)
|
|
|
|
{
|
|
|
|
FcStrList *list = FcStrListCreate (ls->extra);
|
|
|
|
FcChar8 *extra;
|
|
|
|
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
while ((extra = FcStrListNext (list)))
|
|
|
|
FcStrSetAdd (langs, extra);
|
|
|
|
|
|
|
|
FcStrListDone (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return langs;
|
|
|
|
}
|
|
|
|
|
2006-09-05 11:24:01 +02:00
|
|
|
#define __fclang__
|
|
|
|
#include "fcaliastail.h"
|
2008-01-08 01:31:06 +01:00
|
|
|
#include "fcftaliastail.h"
|
2006-09-05 11:24:01 +02:00
|
|
|
#undef __fclang__
|