Add editing langset feature.
authorAkira TAGOH <akira@tagoh.org>
Mon, 6 Dec 2010 03:38:18 +0000 (12:38 +0900)
committerAkira TAGOH <akira@tagoh.org>
Thu, 9 Dec 2010 02:40:08 +0000 (11:40 +0900)
The syntax to add any langset to the langset table looks like:

<match target="scan">
    <test name="family">
        <string>Buggy Sans</string>
    </test>
    <edit name="lang" mode="assign">
        <plus>
            <name>lang</name>
            <langset>
                <string>zh-cn</string>
                <string>zh-tw</string>
            </langset>
        </plus>
    </edit>
</match>

To remove any langset from the langset table:

<match target="scan">
    <test name="family">
        <string>Buggy Sans</string>
    </test>
    <edit name="lang" mode="assign">
        <minus>
            <name>lang</name>
            <langset>
                <string>ja</string>
            </langset>
        </minus>
    </edit>
</match>

fontconfig/fontconfig.h
fonts.dtd
src/fccfg.c
src/fcdbg.c
src/fcint.h
src/fclang.c
src/fcxml.c

index 260955d..29a6ed4 100644 (file)
@@ -584,6 +584,9 @@ FcLangSetCopy (const FcLangSet *ls);
 FcPublic FcBool
 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang);
 
+FcPublic FcBool
+FcLangSetDel (FcLangSet *ls, const FcChar8 *lang);
+
 FcPublic FcLangResult
 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang);
 
@@ -602,6 +605,12 @@ FcLangSetHash (const FcLangSet *ls);
 FcPublic FcStrSet *
 FcLangSetGetLangs (const FcLangSet *ls);
 
+FcLangSet *
+FcLangSetUnion (const FcLangSet *a, const FcLangSet *b);
+
+FcLangSet *
+FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b);
+
 /* fclist.c */
 FcPublic FcObjectSet *
 FcObjectSetCreate (void);
index 5f21e35..d9d4b22 100644 (file)
--- a/fonts.dtd
+++ b/fonts.dtd
 
 <!ELEMENT pattern (patelt)*>
 
-<!ENTITY % constant 'int|double|string|matrix|bool|charset|const'>
+<!ENTITY % constant 'int|double|string|matrix|bool|charset|langset|const'>
 
 <!ELEMENT patelt (%constant;)*>
 <!ATTLIST patelt
 <!ELEMENT family (#PCDATA)>
 <!ATTLIST family xml:space (default|preserve) 'preserve'>
 
-<!ENTITY % expr 'int|double|string|matrix|bool|charset
+<!ENTITY % expr 'int|double|string|matrix|bool|charset|langset
                |name|const
                |or|and|eq|not_eq|less|less_eq|more|more_eq|contains|not_contains
                |plus|minus|times|divide|not|if|floor|ceil|round|trunc'>
 <!ELEMENT bool (#PCDATA)>
 <!ELEMENT charset (int|range)*>
 <!ELEMENT range (int,int)>
+<!ELEMENT langset (string)*>
 <!ELEMENT name (#PCDATA)>
 <!ATTLIST name xml:space (default|preserve) 'preserve'>
 <!ELEMENT const (#PCDATA)>
index ad9f7d2..6812781 100644 (file)
@@ -897,6 +897,11 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        v.u.c = e->u.cval;
        v = FcValueSave (v);
        break;
+    case FcOpLangSet:
+       v.type = FcTypeLangSet;
+       v.u.l = e->u.lval;
+       v = FcValueSave (v);
+       break;
     case FcOpBool:
        v.type = FcTypeBool;
        v.u.b = e->u.bval;
@@ -1055,6 +1060,25 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                    break;
                }
                break;
+           case FcTypeLangSet:
+               switch (e->op) {
+               case FcOpPlus:
+                   v.type = FcTypeLangSet;
+                   v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
+                   if (!v.u.l)
+                       v.type = FcTypeVoid;
+                   break;
+               case FcOpMinus:
+                   v.type = FcTypeLangSet;
+                   v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
+                   if (!v.u.l)
+                       v.type = FcTypeVoid;
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+               break;
            default:
                v.type = FcTypeVoid;
                break;
index 79e1953..cf2ff08 100644 (file)
@@ -163,6 +163,7 @@ FcOpPrint (FcOp op)
     case FcOpRange: printf ("Range"); break;
     case FcOpBool: printf ("Bool"); break;
     case FcOpCharSet: printf ("CharSet"); break;
+    case FcOpLangSet: printf ("LangSet"); break;
     case FcOpField: printf ("Field"); break;
     case FcOpConst: printf ("Const"); break;
     case FcOpAssign: printf ("Assign"); break;
@@ -214,6 +215,11 @@ FcExprPrint (const FcExpr *expr)
     case FcOpRange: break;
     case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
     case FcOpCharSet: printf ("charset\n"); break;
+    case FcOpLangSet:
+       printf ("langset:");
+       FcLangSetPrint(expr->u.lval);
+       printf ("\n");
+       break;
     case FcOpNil: printf ("nil\n"); break;
     case FcOpField: printf ("%s", FcObjectName(expr->u.object)); break;
     case FcOpConst: printf ("%s", expr->u.constant); break;
index 9519fff..3da6ec4 100644 (file)
@@ -216,7 +216,7 @@ struct _FcPattern {
                                 fs->fonts[i])
                                                
 typedef enum _FcOp {
-    FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpRange, FcOpBool, FcOpCharSet,
+    FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpRange, FcOpBool, FcOpCharSet, FcOpLangSet,
     FcOpNil,
     FcOpField, FcOpConst,
     FcOpAssign, FcOpAssignReplace,
@@ -239,6 +239,7 @@ typedef struct _FcExpr {
        FcMatrix    *mval;
        FcBool      bval;
        FcCharSet   *cval;
+       FcLangSet   *lval;
        FcObject    object;
        FcChar8     *constant;
        struct {
index 1c78328..be42b58 100644 (file)
@@ -71,6 +71,20 @@ FcLangSetBitGet (const FcLangSet *ls,
   return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
 }
 
+static void
+FcLangSetBitReset (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));
+}
+
 FcLangSet *
 FcFreeTypeLangSet (const FcCharSet  *charset,
                   const FcChar8    *exclusiveLang)
@@ -400,6 +414,23 @@ FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
     return FcStrSetAdd (ls->extra, lang);
 }
 
+FcBool
+FcLangSetDel (FcLangSet *ls, const FcChar8 *lang)
+{
+    int        id;
+
+    id = FcLangSetIndex (lang);
+    if (id >= 0)
+    {
+       FcLangSetBitReset (ls, id);
+    }
+    else if (ls->extra)
+    {
+       FcStrSetDel (ls->extra, lang);
+    }
+    return FcTrue;
+}
+
 FcLangResult
 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
 {
@@ -818,6 +849,37 @@ FcLangSetGetLangs (const FcLangSet *ls)
     return langs;
 }
 
+static FcLangSet *
+FcLangSetOperate(const FcLangSet       *a,
+                const FcLangSet        *b,
+                FcBool                 (*func) (FcLangSet      *ls,
+                                                const FcChar8  *s))
+{
+    FcLangSet  *langset = FcLangSetCopy (a);
+    FcStrList  *sl = FcStrListCreate (FcLangSetGetLangs (b));
+    FcChar8    *str;
+
+    while ((str = FcStrListNext (sl)))
+    {
+       func (langset, str);
+    }
+    FcStrListDone (sl);
+
+    return langset;
+}
+
+FcLangSet *
+FcLangSetUnion (const FcLangSet *a, const FcLangSet *b)
+{
+    return FcLangSetOperate(a, b, FcLangSetAdd);
+}
+
+FcLangSet *
+FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b)
+{
+    return FcLangSetOperate(a, b, FcLangSetDel);
+}
+
 #define __fclang__
 #include "fcaliastail.h"
 #include "fcftaliastail.h"
index 4d07f9d..1aa3e4c 100644 (file)
@@ -146,6 +146,18 @@ FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
 }
 
 static FcExpr *
+FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
+{
+    FcExpr *e = FcConfigAllocExpr (config);
+    if (e)
+    {
+       e->op = FcOpLangSet;
+       e->u.lval = FcLangSetCopy (langset);
+    }
+    return e;
+}
+
+static FcExpr *
 FcExprCreateField (FcConfig *config, const char *field)
 {
     FcExpr *e = FcConfigAllocExpr (config);
@@ -202,6 +214,9 @@ FcExprDestroy (FcExpr *e)
     case FcOpCharSet:
        FcCharSetDestroy (e->u.cval);
        break;
+    case FcOpLangSet:
+       FcLangSetDestroy (e->u.lval);
+       break;
     case FcOpBool:
        break;
     case FcOpField:
@@ -294,6 +309,7 @@ typedef enum _FcElement {
     FcElementRange,
     FcElementBool,
     FcElementCharSet,
+    FcElementLangSet,
     FcElementName,
     FcElementConst,
     FcElementOr,
@@ -356,6 +372,7 @@ static const struct {
     { "range",         FcElementRange },
     { "bool",          FcElementBool },
     { "charset",       FcElementCharSet },
+    { "langset",       FcElementLangSet },
     { "name",          FcElementName },
     { "const",         FcElementConst },
     { "or",            FcElementOr },
@@ -420,6 +437,7 @@ typedef enum _FcVStackTag {
     FcVStackRange,
     FcVStackBool,
     FcVStackCharSet,
+    FcVStackLangSet,
 
     FcVStackTest,
     FcVStackExpr,
@@ -439,6 +457,7 @@ typedef struct _FcVStack {
        FcRange         range;
        FcBool          bool_;
        FcCharSet       *charset;
+       FcLangSet       *langset;
 
        FcTest          *test;
        FcQual          qual;
@@ -571,6 +590,9 @@ FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
     case FcOpCharSet:
        FcTypecheckValue (parse, FcTypeCharSet, type);
        break;
+    case FcOpLangSet:
+       FcTypecheckValue (parse, FcTypeLangSet, type);
+       break;
     case FcOpNil:
        break;
     case FcOpField:
@@ -799,6 +821,20 @@ FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
 }
 
 static FcBool
+FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
+{
+    FcVStack   *vstack;
+    if (!langset)
+       return FcFalse;
+    vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.langset = langset;
+    vstack->tag = FcVStackLangSet;
+    return FcTrue;
+}
+
+static FcBool
 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
 {
     FcVStack    *vstack = FcVStackCreateAndPush (parse);
@@ -895,6 +931,9 @@ FcVStackPopAndDestroy (FcConfigParse *parse)
     case FcVStackCharSet:
        FcCharSetDestroy (vstack->u.charset);
        break;
+    case FcVStackLangSet:
+       FcLangSetDestroy (vstack->u.langset);
+       break;
     case FcVStackTest:
        FcTestDestroy (vstack->u.test);
        break;
@@ -1411,6 +1450,36 @@ FcParseCharSet (FcConfigParse *parse)
            FcCharSetDestroy (charset);
 }
 
+static void
+FcParseLangSet (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcLangSet  *langset = FcLangSetCreate ();
+    int n = 0;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackString:
+           if (!FcLangSetAdd (langset, vstack->u.string))
+           {
+               FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
+           }
+           else
+               n++;
+           break;
+       default:
+               FcConfigMessage (parse, FcSevereError, "invalid element in langset");
+               break;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+    if (n > 0)
+           FcVStackPushLangSet (parse, langset);
+    else
+           FcLangSetDestroy (langset);
+}
+
 static FcBool
 FcConfigLexBinding (FcConfigParse   *parse,
                    const FcChar8   *binding_string,
@@ -1665,6 +1734,9 @@ FcPopExpr (FcConfigParse *parse)
     case FcVStackCharSet:
        expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
        break;
+    case FcVStackLangSet:
+       expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
+       break;
     case FcVStackTest:
        break;
     case FcVStackExpr:
@@ -2086,6 +2158,11 @@ FcPopValue (FcConfigParse *parse)
        if (value.u.c)
            value.type = FcTypeCharSet;
        break;
+    case FcVStackLangSet:
+       value.u.l = FcLangSetCopy (vstack->u.langset);
+       if (value.u.l)
+           value.type = FcTypeLangSet;
+       break;
     default:
        FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
                         vstack->tag);
@@ -2360,6 +2437,9 @@ FcEndElement(void *userData, const XML_Char *name)
     case FcElementCharSet:
        FcParseCharSet (parse);
        break;
+    case FcElementLangSet:
+       FcParseLangSet (parse);
+       break;
     case FcElementSelectfont:
        break;
     case FcElementAcceptfont: