]> git.wh0rd.org - fontconfig.git/commitdiff
Allow editing charset and lang in target="scan"
authorBehdad Esfahbod <behdad@behdad.org>
Tue, 28 Dec 2010 08:50:16 +0000 (02:50 -0600)
committerBehdad Esfahbod <behdad@behdad.org>
Tue, 28 Dec 2010 08:51:10 +0000 (02:51 -0600)
Merge commit 'fa269cf812ee304534b0e4c44662202496008db0'

Fixes:
Bug 31969 - Can't modify charset in target="scan"
Bug 23758 - Can't modify lang in target="scan"

doc/fclangset.fncs
doc/fontconfig-user.sgml
fontconfig/fontconfig.h
fonts.dtd
src/Makefile.am
src/fccfg.c
src/fcdbg.c
src/fcint.h
src/fclang.c
src/fcxml.c

index f9d578e6585f9818758268c5d08ab0626c443188..fd1634f9b3be0197eeb10ef5bb7e922851edc1e4 100644 (file)
@@ -58,6 +58,36 @@ two or three letter language from ISO 639 and Tt is a territory from ISO
 3166.
 @@
 
+@RET@          FcBool
+@FUNC@         FcLangSetDel
+@TYPE1@                FcLangSet *                     @ARG1@          ls
+@TYPE2@                const FcChar8 *                 @ARG2@          lang
+@PURPOSE@      remove a language from a langset
+@DESC@
+<parameter>lang</parameter> is removed from <parameter>ls</parameter>.
+<parameter>lang</parameter> should be of the form Ll-Tt where Ll is a
+two or three letter language from ISO 639 and Tt is a territory from ISO
+3166.
+@@
+
+@RET@          FcLangSet *
+@FUNC@         FcLangSetUnion
+@TYPE1@                const FcLangSet *               @ARG1@          ls_a
+@TYPE2@                const FcLangSet *               @ARG2@          ls_b
+@PURPOSE@      Add langsets
+@DESC@
+Returns a set including only those languages found in either <parameter>ls_a</parameter> or <parameter>ls_b</parameter>.
+@@
+
+@RET@          FcLangSet *
+@FUNC@         FcLangSetSubtract
+@TYPE1@                const FcLangSet *               @ARG1@          ls_a
+@TYPE2@                const FcLangSet *               @ARG2@          ls_b
+@PURPOSE@      Subtract langsets
+@DESC@
+Returns a set including only those languages found in <parameter>ls_a</parameter> but not <parameter>ls_b</parameter>.
+@@
+
 @RET@          FcLangResult
 @FUNC@         FcLangSetCompare
 @TYPE1@                const FcLangSet *               @ARG1@          ls_a
index 219d90653b042a48f9a3638b5ed6923577da7d6b..b870825f21685eacc3d61a15b5273c0aec6efba9 100644 (file)
@@ -431,6 +431,18 @@ instead of -.5).
   <refsect2><title><literal>&lt;matrix&gt;</literal></title><para>
 This element holds the four <literal>&lt;double&gt;</literal> elements of an affine
 transformation.
+  </para></refsect2>
+  <refsect2><title><literal>&lt;range&gt;</literal></title><para>
+This element holds the two <literal>&lt;int&gt;</literal> elements of a range
+representation.
+  </para></refsect2>
+  <refsect2><title><literal>&lt;charset&gt;</literal></title><para>
+This element holds at least one <literal>&lt;int&gt;</literal> element of
+an Unicode code point or more.
+  </para></refsect2>
+  <refsect2><title><literal>&lt;langset&gt;</literal></title><para>
+This element holds at least one <literal>&lt;string&gt;</literal> element of
+a RFC-3066-style languages or more.
   </para></refsect2>
   <refsect2><title><literal>&lt;name&gt;</literal></title><para>
 Holds a property name.  Evaluates to the first value from the property of
index 260955daa0437d54572313605af9557f1259c6c1..29a6ed460994c7f1f0cc3d4aa46d79afefb71746 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 cbdfdab3fb5675e159b482a1f5ed21f87e71156b..d9d4b22297b6888d2e4b1bc7d60fcfcb79d02dbf 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'>
 <!ATTLIST string xml:space (default|preserve) 'preserve'>
 <!ELEMENT matrix (double,double,double,double)>
 <!ELEMENT bool (#PCDATA)>
-<!ELEMENT charset (#PCDATA)>
-<!ATTLIST charset xml:space (default|preserve) 'preserve'>
+<!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 e300fe9491b180717ff012fa188dfee9c6a3009c..090f9b1abd72695ab6eb423c643e13c6943c8752 100644 (file)
@@ -140,7 +140,7 @@ PUBLIC_FILES = \
        $(top_srcdir)/fontconfig/fontconfig.h \
        $(top_srcdir)/src/fcdeprecate.h \
        $(top_srcdir)/fontconfig/fcprivate.h
-       
+
 PUBLIC_FT_FILES = \
        $(top_srcdir)/fontconfig/fcfreetype.h
 
@@ -160,7 +160,7 @@ fontconfig.def: $(PUBLIC_FILES) $(PUBLIC_FT_FILES)
        echo Generating $@
        (echo EXPORTS; \
        (cat $(PUBLIC_FILES) $(PUBLIC_FT_FILES) || echo 'FcERROR ()' ) | \
-       grep '^Fc[^ ]* *(' | sed -e 's/ *(.*$$//' -e 's/^/      /' | \
+       grep '^Fc[^ ]* *(' | sed -e 's/ *(.*$$//' -e 's/^/      /' | \
        sort; \
        echo LIBRARY libfontconfig-@LIBT_CURRENT_MINUS_AGE@.dll; \
        echo VERSION @LIBT_CURRENT@.@LIBT_REVISION@) >$@
index 19a9fefbdaa9cb34011b7913aba8834ddb08a11a..681278114360f37c2a8ba54a9218c9e0528a68e7 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;
@@ -1036,6 +1041,44 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                    break;
                }
                break;
+           case FcTypeCharSet:
+               switch (e->op) {
+               case FcOpPlus:
+                   v.type = FcTypeCharSet;
+                   v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
+                   if (!v.u.c)
+                       v.type = FcTypeVoid;
+                   break;
+               case FcOpMinus:
+                   v.type = FcTypeCharSet;
+                   v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
+                   if (!v.u.c)
+                       v.type = FcTypeVoid;
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   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 fc3b59602a3994f8dd56041d76ddef3bc21180c2..cf2ff0870dadb80a2aaee4b0292acca7e57f795a 100644 (file)
@@ -160,8 +160,10 @@ FcOpPrint (FcOp op)
     case FcOpDouble: printf ("Double"); break;
     case FcOpString: printf ("String"); break;
     case FcOpMatrix: printf ("Matrix"); break;
+    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;
@@ -210,8 +212,14 @@ FcExprPrint (const FcExpr *expr)
                              expr->u.mval->xy,
                              expr->u.mval->yx,
                              expr->u.mval->yy); break;
+    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 a8599138f85d625355606861a1578bbf912d762f..e662c37e22905efc8ba8be81a5c8bfaf45aa2cdb 100644 (file)
@@ -220,7 +220,7 @@ struct _FcPattern {
                                 fs->fonts[i])
                                                
 typedef enum _FcOp {
-    FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpBool, FcOpCharSet,
+    FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpRange, FcOpBool, FcOpCharSet, FcOpLangSet,
     FcOpNil,
     FcOpField, FcOpConst,
     FcOpAssign, FcOpAssignReplace,
@@ -243,6 +243,7 @@ typedef struct _FcExpr {
        FcMatrix    *mval;
        FcBool      bval;
        FcCharSet   *cval;
+       FcLangSet   *lval;
        FcObject    object;
        FcChar8     *constant;
        struct {
@@ -511,6 +512,13 @@ typedef struct _FcFileTime {
 
 typedef struct _FcCharMap FcCharMap;
 
+typedef struct _FcRange            FcRange;
+
+struct _FcRange {
+    FcChar32 begin;
+    FcChar32 end;
+};
+
 /* fcblanks.c */
 
 /* fccache.c */
index 1c78328048bb385003ffc43d24e00699a6eb356b..be42b58c4694f54747c395ab28011a490a7a4dbc 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 2bd67bf090236a6db81a5f0a418096f3a5f5669b..1aa3e4c1c0809d8f2a5c57d78972094ed507f615 100644 (file)
@@ -133,6 +133,30 @@ FcExprCreateBool (FcConfig *config, FcBool b)
     return e;
 }
 
+static FcExpr *
+FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
+{
+    FcExpr *e = FcConfigAllocExpr (config);
+    if (e)
+    {
+       e->op = FcOpCharSet;
+       e->u.cval = FcCharSetCopy (charset);
+    }
+    return e;
+}
+
+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)
 {
@@ -185,9 +209,14 @@ FcExprDestroy (FcExpr *e)
     case FcOpMatrix:
        FcMatrixFree (e->u.mval);
        break;
+    case FcOpRange:
+       break;
     case FcOpCharSet:
        FcCharSetDestroy (e->u.cval);
        break;
+    case FcOpLangSet:
+       FcLangSetDestroy (e->u.lval);
+       break;
     case FcOpBool:
        break;
     case FcOpField:
@@ -277,8 +306,10 @@ typedef enum _FcElement {
     FcElementDouble,
     FcElementString,
     FcElementMatrix,
+    FcElementRange,
     FcElementBool,
-    FcElementCharset,
+    FcElementCharSet,
+    FcElementLangSet,
     FcElementName,
     FcElementConst,
     FcElementOr,
@@ -338,8 +369,10 @@ static const struct {
     { "double",                FcElementDouble },
     { "string",                FcElementString },
     { "matrix",                FcElementMatrix },
+    { "range",         FcElementRange },
     { "bool",          FcElementBool },
-    { "charset",       FcElementCharset },
+    { "charset",       FcElementCharSet },
+    { "langset",       FcElementLangSet },
     { "name",          FcElementName },
     { "const",         FcElementConst },
     { "or",            FcElementOr },
@@ -401,7 +434,10 @@ typedef enum _FcVStackTag {
     FcVStackInteger,
     FcVStackDouble,
     FcVStackMatrix,
+    FcVStackRange,
     FcVStackBool,
+    FcVStackCharSet,
+    FcVStackLangSet,
 
     FcVStackTest,
     FcVStackExpr,
@@ -418,7 +454,10 @@ typedef struct _FcVStack {
        int             integer;
        double          _double;
        FcMatrix        *matrix;
+       FcRange         range;
        FcBool          bool_;
+       FcCharSet       *charset;
+       FcLangSet       *langset;
 
        FcTest          *test;
        FcQual          qual;
@@ -551,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:
@@ -741,6 +783,18 @@ FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
     return FcTrue;
 }
 
+static FcBool
+FcVStackPushRange (FcConfigParse *parse, FcRange *range)
+{
+    FcVStack   *vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.range.begin = range->begin;
+    vstack->u.range.end = range->end;
+    vstack->tag = FcVStackRange;
+    return FcTrue;
+}
+
 static FcBool
 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
 {
@@ -752,6 +806,34 @@ FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
     return FcTrue;
 }
 
+static FcBool
+FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
+{
+    FcVStack   *vstack;
+    if (!charset)
+       return FcFalse;
+    vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.charset = charset;
+    vstack->tag = FcVStackCharSet;
+    return FcTrue;
+}
+
+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)
 {
@@ -843,8 +925,15 @@ FcVStackPopAndDestroy (FcConfigParse *parse)
     case FcVStackMatrix:
        FcMatrixFree (vstack->u.matrix);
        break;
+    case FcVStackRange:
     case FcVStackBool:
        break;
+    case FcVStackCharSet:
+       FcCharSetDestroy (vstack->u.charset);
+       break;
+    case FcVStackLangSet:
+       FcLangSetDestroy (vstack->u.langset);
+       break;
     case FcVStackTest:
        FcTestDestroy (vstack->u.test);
        break;
@@ -1042,30 +1131,37 @@ FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
 static void
 FcParseBlank (FcConfigParse *parse)
 {
-    int            n = FcVStackElements (parse);
+    int                n = FcVStackElements (parse);
+    FcChar32   i;
     while (n-- > 0)
     {
        FcVStack    *v = FcVStackFetch (parse, n);
-       if (v->tag != FcVStackInteger)
-           FcConfigMessage (parse, FcSevereError, "non-integer blank");
-       else
+       if (!parse->config->blanks)
        {
+           parse->config->blanks = FcBlanksCreate ();
            if (!parse->config->blanks)
-           {
-               parse->config->blanks = FcBlanksCreate ();
-               if (!parse->config->blanks)
-               {
-                   FcConfigMessage (parse, FcSevereError, "out of memory");
-                   break;
-               }
-           }
+               goto bail;
+       }
+       switch (v->tag) {
+       case FcVStackInteger:
            if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
+               goto bail;
+           break;
+       case FcVStackRange:
+           for (i = v->u.range.begin; i <= v->u.range.end; i++)
            {
-               FcConfigMessage (parse, FcSevereError, "out of memory");
-               break;
+               if (!FcBlanksAdd (parse->config->blanks, i))
+                   goto bail;
            }
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereError, "invalid element in blank");
+           break;
        }
     }
+    return;
+  bail:
+    FcConfigMessage (parse, FcSevereError, "out of memory");
 }
 
 static void
@@ -1241,6 +1337,49 @@ FcParseMatrix (FcConfigParse *parse)
        FcVStackPushMatrix (parse, &m);
 }
 
+static void
+FcParseRange (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcRange    r;
+    FcChar32   n;
+    int                count = 1;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       if (count < 0)
+       {
+           FcConfigMessage (parse, FcSevereError, "too many elements in range");
+           return;
+       }
+       switch (vstack->tag) {
+       case FcVStackInteger:
+           n = vstack->u.integer;
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereError, "invalid element in range");
+           break;
+       }
+       if (count == 1)
+           r.end = n;
+       else
+           r.begin = n;
+       count--;
+       FcVStackPopAndDestroy (parse);
+    }
+    if (count < 0)
+    {
+       if (r.begin > r.end)
+       {
+           FcConfigMessage (parse, FcSevereError, "invalid range");
+           return;
+       }
+       FcVStackPushRange (parse, &r);
+    }
+    else
+       FcConfigMessage (parse, FcSevereError, "invalid range");
+}
+
 static FcBool
 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
 {
@@ -1269,6 +1408,78 @@ FcParseBool (FcConfigParse *parse)
     FcStrBufDestroy (&parse->pstack->str);
 }
 
+static void
+FcParseCharSet (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcCharSet  *charset = FcCharSetCreate ();
+    FcChar32   i;
+    int n = 0;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackInteger:
+           if (!FcCharSetAddChar (charset, vstack->u.integer))
+           {
+               FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
+           }
+           else
+               n++;
+           break;
+       case FcVStackRange:
+           for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
+           {
+               if (!FcCharSetAddChar (charset, i))
+               {
+                   FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
+               }
+               else
+                   n++;
+           }
+           break;
+       default:
+               FcConfigMessage (parse, FcSevereError, "invalid element in charset");
+               break;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+    if (n > 0)
+           FcVStackPushCharSet (parse, charset);
+    else
+           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,
@@ -1515,9 +1726,17 @@ FcPopExpr (FcConfigParse *parse)
     case FcVStackMatrix:
        expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
        break;
+    case FcVStackRange:
+       break;
     case FcVStackBool:
        expr = FcExprCreateBool (parse->config, vstack->u.bool_);
        break;
+    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:
@@ -1934,6 +2153,16 @@ FcPopValue (FcConfigParse *parse)
        value.u.b = vstack->u.bool_;
        value.type = FcTypeBool;
        break;
+    case FcVStackCharSet:
+       value.u.c = FcCharSetCopy (vstack->u.charset);
+       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);
@@ -2199,11 +2428,17 @@ FcEndElement(void *userData, const XML_Char *name)
     case FcElementMatrix:
        FcParseMatrix (parse);
        break;
+    case FcElementRange:
+       FcParseRange (parse);
+       break;
     case FcElementBool:
        FcParseBool (parse);
        break;
-    case FcElementCharset:
-/*     FcParseCharset (parse); */
+    case FcElementCharSet:
+       FcParseCharSet (parse);
+       break;
+    case FcElementLangSet:
+       FcParseLangSet (parse);
        break;
     case FcElementSelectfont:
        break;