]> git.wh0rd.org - fontconfig.git/blobdiff - src/fclang.c
Add consts to variables so as to move arrays into .rodata.
[fontconfig.git] / src / fclang.c
index 3ca09f70b89ce77b72139c72e52e74db320a714e..a10641edf953c89586dc9aa03f87879b1712384a 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fclang.c,v 1.4 2002/07/12 21:06:03 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
  *
- * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2002 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 #include "fcint.h"
 
 typedef struct {
-    FcChar8    *lang;
-    FcCharSet  charset;
+    const FcChar8      *lang;
+    const FcCharSet    charset;
 } FcLangCharSet;
 
-#include "../fc-lang/fclang.h"
+typedef struct {
+    int begin;
+    int end;
+} FcLangCharSetRange;
 
-#define NUM_LANG_CHAR_SET   (sizeof (fcLangCharSets) / sizeof (fcLangCharSets[0]))
-#define NUM_LANG_SET_MAP    ((NUM_LANG_CHAR_SET + 31) / 32)
+#include "../fc-lang/fclang.h"
 
 struct _FcLangSet {
     FcChar32   map[NUM_LANG_SET_MAP];
@@ -46,7 +48,7 @@ FcLangSet *
 FcFreeTypeLangSet (const FcCharSet  *charset, 
                   const FcChar8    *exclusiveLang)
 {
-    int                    i;
+    int                    i, j;
     FcChar32       missing;
     const FcCharSet *exclusiveCharset = 0;
     FcLangSet      *ls;
@@ -65,10 +67,15 @@ FcFreeTypeLangSet (const FcCharSet  *charset,
         * not support other Han languages
         */
        if (exclusiveCharset &&
-           FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang) &&
-           fcLangCharSets[i].charset.leaves != exclusiveCharset->leaves)
+           FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
        {
-           continue;
+           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;
        }
        missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
         if (FcDebug() & FC_DBG_SCANV)
@@ -141,6 +148,41 @@ FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
     }
 }
 
+/*
+ * Return FcTrue when super contains sub. 
+ *
+ * super contains sub if super and sub have the same
+ * language and either the same country or one
+ * is missing the country
+ */
+
+static FcBool
+FcLangContains (const FcChar8 *super, const FcChar8 *sub)
+{
+    FcChar8        c1, c2;
+
+    for (;;)
+    {
+       c1 = *super++;
+       c2 = *sub++;
+       
+       c1 = FcToLower (c1);
+       c2 = FcToLower (c2);
+       if (c1 != c2)
+       {
+           /* see if super has a country while sub is mising one */
+           if (c1 == '-' && c2 == '\0')
+               return FcTrue;
+           /* see if sub has a country while super is mising one */
+           if (c1 == '\0' && c2 == '-')
+               return FcTrue;
+           return FcFalse;
+       }
+       else if (!c1)
+           return FcTrue;
+    }
+}
+
 const FcCharSet *
 FcCharSetForLang (const FcChar8 *lang)
 {
@@ -226,16 +268,48 @@ bail0:
 static int
 FcLangSetIndex (const FcChar8 *lang)
 {
-    int            low, high, mid;
-    int            cmp;
+    int            low, high, mid = 0;
+    int            cmp = 0;
+    FcChar8 firstChar = FcToLower(lang[0]); 
+    FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
+    
+    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 */
+    }
 
-    low = 0;
-    high = NUM_LANG_CHAR_SET - 1;
     while (low <= high)
     {
        mid = (high + low) >> 1;
-       cmp = FcStrCmpIgnoreCase (fcLangCharSets[mid].lang, lang);
-       if (cmp == 0) 
+       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) */
+           cmp = fcLangCharSets[mid].lang[1] - secondChar;
+           if (cmp == 0 && 
+               (fcLangCharSets[mid].lang[2] != '\0' || 
+                lang[2] != '\0'))
+           {
+               cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, 
+                                        lang+2);
+           }
+       }
+       if (cmp == 0)
            return mid;
        if (cmp < 0)
            low = mid + 1;
@@ -275,9 +349,10 @@ FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
     int                    i;
 
     id = FcLangSetIndex (lang);
-    if (id >= 0)
+    if (id < 0)
+       id = -id - 1;
+    else if (FcLangSetBitGet (ls, id))
        return FcLangEqual;
-    id = -id - 1;
     best = FcLangDifferentLang;
     for (i = id - 1; i >= 0; i--)
     {
@@ -338,13 +413,21 @@ FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
 FcLangResult
 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
 {
-    int                    i;
+    int                    i, j;
     FcLangResult    best, r;
 
     for (i = 0; i < NUM_LANG_SET_MAP; i++)
        if (lsa->map[i] & lsb->map[i])
            return FcLangEqual;
     best = FcLangDifferentLang;
+    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;
+           }
     if (lsa->extra)
     {
        r = FcLangSetCompareStrSet (lsb, lsa->extra);
@@ -384,6 +467,7 @@ FcLangSetPromote (const FcChar8 *lang)
        strs.num = 1;
        strs.size = 1;
        strs.strs = &str;
+       strs.ref = 1;
        str = (FcChar8 *) lang;
     }
     return &ls;
@@ -405,32 +489,28 @@ FcLangSetHash (const FcLangSet *ls)
 FcLangSet *
 FcNameParseLangSet (const FcChar8 *string)
 {
-    FcChar8        lang[32];
-    const FcChar8   *end, *next;
+    FcChar8        lang[32],c;
+    int i;
     FcLangSet      *ls;
 
     ls = FcLangSetCreate ();
     if (!ls)
        goto bail0;
 
-    while (string && *string) 
+    for(;;)
     {
-       end = (FcChar8 *) strchr ((char *) string, '|');
-       if (!end)
+       for(i = 0; i < 31;i++)
        {
-           end = string + strlen ((char *) string);
-           next = end;
-       }
-       else
-           next = end + 1;
-       if (end - string < sizeof (lang) - 1)
-       {
-           strncpy ((char *) lang, (char *) string, end - string);
-           lang[end-string] = '\0';
-           if (!FcLangSetAdd (ls, lang))
-               goto bail1;
+           c = *string++;
+           if(c == '\0' || c == '|')
+               break; /* end of this code */
+           lang[i] = c;
        }
-       string = next;
+       lang[i] = '\0';
+       if (!FcLangSetAdd (ls, lang))
+           goto bail1;
+       if(c == '\0')
+           break;
     }
     return ls;
 bail1:
@@ -475,7 +555,7 @@ FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
            if (!first)
                if (!FcStrBufChar (buf, '|'))
                    return FcFalse;
-           if (!FcStrBufString (buf, extra));
+           if (!FcStrBufString (buf, extra))
                return FcFalse;
            first = FcFalse;
        }
@@ -499,3 +579,193 @@ FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
        return FcStrSetEqual (lsa->extra, lsb->extra);
     return FcFalse;
 }
+
+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;
+    }
+    if (ls->extra)
+    {
+       FcStrList       *list = FcStrListCreate (ls->extra);
+       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;
+                   }
+               }
+       }
+    }
+    if (lsb->extra)
+    {
+       FcStrList   *list = FcStrListCreate (lsb->extra);
+       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;
+}
+
+static FcLangSet ** langsets = 0;
+static int langset_bank_count = 0, langset_ptr = 0, langset_count = 0;
+
+void
+FcLangSetNewBank (void)
+{
+    langset_count = 0;
+}
+
+/* ideally, should only write one copy of any particular FcLangSet */
+int
+FcLangSetNeededBytes (const FcLangSet *l)
+{
+    langset_count++;
+    return sizeof (FcLangSet);
+}
+
+static FcBool
+FcLangSetEnsureBank (int bi)
+{
+    if (!langsets || bi >= langset_bank_count)
+    {
+       int new_count = langset_bank_count + 2;
+       int i;
+       FcLangSet** tt;
+       tt = realloc(langsets, new_count * sizeof(FcLangSet *));
+       if (!tt)
+           return FcFalse;
+
+       langsets = tt;
+       for (i = langset_bank_count; i < new_count; i++)
+           langsets[i] = 0; 
+       langset_bank_count = new_count;
+    }
+
+    return FcTrue;
+}
+
+void *
+FcLangSetDistributeBytes (FcCache * metadata, void * block_ptr)
+{
+    int bi = FcCacheBankToIndex(metadata->bank);
+    if (!FcLangSetEnsureBank(bi))
+       return 0;
+
+    langsets[bi] = block_ptr;
+    block_ptr = (void *)((char *)block_ptr +
+                        langset_count * sizeof(FcLangSet));
+    langset_ptr = 0;
+    metadata->langset_count = langset_count;
+    return block_ptr;
+}
+
+FcLangSet *
+FcLangSetSerialize(int bank, FcLangSet *l)
+{
+    int p = langset_ptr, bi = FcCacheBankToIndex(bank);
+
+    if (!l) return 0;
+
+    langsets[bi][langset_ptr] = *l;
+    langsets[bi][langset_ptr].extra = 0;
+    langset_ptr++;
+    return &langsets[bi][p];
+}
+
+void *
+FcLangSetUnserialize (FcCache metadata, void *block_ptr)
+{
+    int bi = FcCacheBankToIndex(metadata.bank);
+    if (!FcLangSetEnsureBank(bi))
+       return 0;
+
+    FcMemAlloc (FC_MEM_LANGSET, metadata.langset_count * sizeof(FcLangSet));
+    langsets[bi] = (FcLangSet *)block_ptr;
+    block_ptr = (void *)((char *)block_ptr +
+                        metadata.langset_count * sizeof(FcLangSet));
+    return block_ptr;
+}