Parse matrices of expressions
authorBehdad Esfahbod <behdad@behdad.org>
Sun, 30 Dec 2012 02:39:06 +0000 (21:39 -0500)
committerBehdad Esfahbod <behdad@behdad.org>
Sun, 30 Dec 2012 02:39:06 +0000 (21:39 -0500)
Previously a <matrix> element could only accept four <double> literals.
It now accepts full expressions, which can in turn poke into the
pattern, do math, etc.

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

index 4a309a9..6b33e75 100644 (file)
--- a/fonts.dtd
+++ b/fonts.dtd
 <!ATTLIST double xml:space (default|preserve) 'preserve'>
 <!ELEMENT string (#PCDATA)>
 <!ATTLIST string xml:space (default|preserve) 'preserve'>
-<!ELEMENT matrix (double,double,double,double)>
+<!ELEMENT matrix ((%expr;), (%expr;), (%expr;), (%expr;))>
 <!ELEMENT bool (#PCDATA)>
 <!ELEMENT charset (int|range)*>
 <!ELEMENT range (int,int)>
index f94f0e0..68f9946 100644 (file)
@@ -897,9 +897,27 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        v = FcValueSave (v);
        break;
     case FcOpMatrix:
-       v.type = FcTypeMatrix;
-       v.u.m = e->u.mval;
-       v = FcValueSave (v);
+       {
+         FcMatrix m;
+         v.type = FcTypeMatrix;
+         FcValue xx, xy, yx, yy;
+         xx = FcConfigPromote (FcConfigEvaluate (p, e->u.mexpr->xx), v);
+         xy = FcConfigPromote (FcConfigEvaluate (p, e->u.mexpr->xy), v);
+         yx = FcConfigPromote (FcConfigEvaluate (p, e->u.mexpr->yx), v);
+         yy = FcConfigPromote (FcConfigEvaluate (p, e->u.mexpr->yy), v);
+         if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
+             yx.type == FcTypeDouble && yy.type == FcTypeDouble)
+         {
+           m.xx = xx.u.d;
+           m.xy = xy.u.d;
+           m.yx = yx.u.d;
+           m.yy = yy.u.d;
+           v.u.m = &m;
+         }
+         else
+           v.type = FcTypeVoid;
+         v = FcValueSave (v);
+       }
        break;
     case FcOpCharSet:
        v.type = FcTypeCharSet;
index a1ed2b2..5b8d3da 100644 (file)
@@ -249,11 +249,17 @@ FcExprPrint (const FcExpr *expr)
     case FcOpInteger: printf ("%d", expr->u.ival); break;
     case FcOpDouble: printf ("%g", expr->u.dval); break;
     case FcOpString: printf ("\"%s\"", expr->u.sval); break;
-    case FcOpMatrix: printf ("[%g %g %g %g]",
-                             expr->u.mval->xx,
-                             expr->u.mval->xy,
-                             expr->u.mval->yx,
-                             expr->u.mval->yy); break;
+    case FcOpMatrix:
+       printf ("[");
+       FcExprPrint (expr->u.mexpr->xx);
+       printf (" ");
+       FcExprPrint (expr->u.mexpr->xy);
+       printf (" ");
+       FcExprPrint (expr->u.mexpr->yx);
+       printf (" ");
+       FcExprPrint (expr->u.mexpr->yx);
+       printf ("]");
+       break;
     case FcOpRange: break;
     case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
     case FcOpCharSet: printf ("charset\n"); break;
index 87c7b9a..9dc1aa7 100644 (file)
@@ -251,13 +251,17 @@ typedef enum _FcOpFlags {
 #define FC_OP_GET_FLAGS(_x_)   (((_x_) & 0xffff0000) >> 16)
 #define FC_OP(_x_,_f_)         (FC_OP_GET_OP (_x_) | ((_f_) << 16))
 
+typedef struct _FcExprMatrix {
+  struct _FcExpr *xx, *xy, *yx, *yy;
+} FcExprMatrix;
+
 typedef struct _FcExpr {
     FcOp   op;
     union {
        int         ival;
        double      dval;
        const FcChar8       *sval;
-       FcMatrix    *mval;
+       FcExprMatrix *mexpr;
        FcBool      bval;
        FcCharSet   *cval;
        FcLangSet   *lval;
index 5cb9b2b..0ab590b 100644 (file)
@@ -105,14 +105,48 @@ FcExprCreateString (FcConfig *config, const FcChar8 *s)
     return e;
 }
 
+static FcExprMatrix *
+FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
+{
+  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
+  if (m)
+  {
+    *m = *matrix;
+  }
+  return m;
+}
+
+static void
+FcExprMatrixFreeShallow (FcExprMatrix *m)
+{
+  if (!m)
+    return;
+
+  free (m);
+}
+
+static void
+FcExprMatrixFree (FcExprMatrix *m)
+{
+  if (!m)
+    return;
+
+  FcExprDestroy (m->xx);
+  FcExprDestroy (m->xy);
+  FcExprDestroy (m->yx);
+  FcExprDestroy (m->yy);
+
+  free (m);
+}
+
 static FcExpr *
-FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
+FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
 {
     FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpMatrix;
-       e->u.mval = FcMatrixCopy (m);
+       e->u.mexpr = FcExprMatrixCopyShallow (matrix);
     }
     return e;
 }
@@ -204,7 +238,7 @@ FcExprDestroy (FcExpr *e)
        FcSharedStrFree (e->u.sval);
        break;
     case FcOpMatrix:
-       FcMatrixFree (e->u.mval);
+       FcExprMatrixFree (e->u.mexpr);
        break;
     case FcOpRange:
        break;
@@ -451,7 +485,7 @@ typedef struct _FcVStack {
 
        int             integer;
        double          _double;
-       FcMatrix        *matrix;
+       FcExprMatrix    *matrix;
        FcRange         range;
        FcBool          bool_;
        FcCharSet       *charset;
@@ -516,6 +550,10 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt,
 }
 
 
+static FcExpr *
+FcPopExpr (FcConfigParse *parse);
+
+
 static const char *
 FcTypeName (FcType type)
 {
@@ -767,16 +805,13 @@ FcVStackPushDouble (FcConfigParse *parse, double _double)
 }
 
 static FcBool
-FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
+FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
 {
     FcVStack    *vstack;
-    matrix = FcMatrixCopy (matrix);
-    if (!matrix)
-       return FcFalse;
     vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
-    vstack->u.matrix = matrix;
+    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
     vstack->tag = FcVStackMatrix;
     return FcTrue;
 }
@@ -921,7 +956,7 @@ FcVStackPopAndDestroy (FcConfigParse *parse)
     case FcVStackDouble:
        break;
     case FcVStackMatrix:
-       FcMatrixFree (vstack->u.matrix);
+       FcExprMatrixFreeShallow (vstack->u.matrix);
        break;
     case FcVStackRange:
     case FcVStackBool:
@@ -1304,38 +1339,18 @@ static void
 FcParseMatrix (FcConfigParse *parse)
 {
     FcVStack   *vstack;
-    enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
-    FcMatrix   m;
+    FcExprMatrix m;
+    int i;
 
-    while ((vstack = FcVStackPeek (parse)))
-    {
-       double  v;
-       switch (vstack->tag) {
-       case FcVStackInteger:
-           v = vstack->u.integer;
-           break;
-       case FcVStackDouble:
-           v = vstack->u._double;
-           break;
-       default:
-           FcConfigMessage (parse, FcSevereError, "non-double matrix element");
-           v = 1.0;
-           break;
-       }
-       switch (matrix_state) {
-       case m_xx: m.xx = v; break;
-       case m_xy: m.xy = v; break;
-       case m_yx: m.yx = v; break;
-       case m_yy: m.yy = v; break;
-       default: break;
-       }
-       FcVStackPopAndDestroy (parse);
-       matrix_state--;
-    }
-    if (matrix_state != m_done)
-       FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
+    m.yy = FcPopExpr (parse);
+    m.yx = FcPopExpr (parse);
+    m.xy = FcPopExpr (parse);
+    m.xx = FcPopExpr (parse);
+
+    if (FcPopExpr (parse))
+      FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
     else
-       FcVStackPushMatrix (parse, &m);
+      FcVStackPushMatrix (parse, &m);
 }
 
 static void
@@ -2426,7 +2441,7 @@ FcPopValue (FcConfigParse *parse)
        value.type = FcTypeDouble;
        break;
     case FcVStackMatrix:
-       value.u.m = FcMatrixCopy (vstack->u.matrix);
+       value.u.m = FcExprMatrixCopyShallow (vstack->u.matrix);
        if (value.u.m)
            value.type = FcTypeMatrix;
        break;