Rework to apply the intermixed test and edit elements in one-pass

This commit is contained in:
Akira TAGOH 2013-07-04 19:51:03 +09:00
parent 1162515a98
commit d420e1df98
4 changed files with 331 additions and 351 deletions

View File

@ -214,10 +214,8 @@ FcSubstDestroy (FcSubst *s)
while (s) while (s)
{ {
n = s->next; n = s->next;
if (s->test) if (s->rule)
FcTestDestroy (s->test); FcRuleDestroy (s->rule);
if (s->edit)
FcEditDestroy (s->edit);
free (s); free (s);
s = n; s = n;
} }
@ -226,8 +224,6 @@ FcSubstDestroy (FcSubst *s)
FcExpr * FcExpr *
FcConfigAllocExpr (FcConfig *config) FcConfigAllocExpr (FcConfig *config)
{ {
FcExpr *e;
if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
{ {
FcExprPage *new_page; FcExprPage *new_page;
@ -241,10 +237,7 @@ FcConfigAllocExpr (FcConfig *config)
config->expr_pool = new_page; config->expr_pool = new_page;
} }
e = config->expr_pool->next++; return config->expr_pool->next++;
FcRefInit (&e->ref, 1);
return e;
} }
FcConfig * FcConfig *
@ -649,15 +642,13 @@ FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
return FcConfigSetRescanInterval (config, rescanInterval); return FcConfigSetRescanInterval (config, rescanInterval);
} }
FcBool FcBool
FcConfigAddEdit (FcConfig *config, FcConfigAddRule (FcConfig *config,
FcTest *test, FcRule *rule,
FcEdit *edit,
FcMatchKind kind) FcMatchKind kind)
{ {
FcSubst *subst, **prev; FcSubst *subst, **prev;
FcTest *t; FcRule *r;
int num; int num;
switch (kind) { switch (kind) {
@ -678,15 +669,18 @@ FcConfigAddEdit (FcConfig *config,
return FcFalse; return FcFalse;
for (; *prev; prev = &(*prev)->next); for (; *prev; prev = &(*prev)->next);
*prev = subst; *prev = subst;
subst->next = 0; subst->next = NULL;
subst->test = test; subst->rule = rule;
subst->edit = edit;
num = 0; num = 0;
for (t = test; t; t = t->next) for (r = rule; r; r = r->next)
{ {
if (t->kind == FcMatchDefault) if (r->type == FcRuleTest)
t->kind = kind; {
num++; if (r->u.test &&
r->u.test->kind == FcMatchDefault)
r->u.test->kind = kind;
num++;
}
} }
if (config->maxObjects < num) if (config->maxObjects < num)
config->maxObjects = num; config->maxObjects = num;
@ -1491,13 +1485,12 @@ FcConfigSubstituteWithPat (FcConfig *config,
{ {
FcValue v; FcValue v;
FcSubst *s; FcSubst *s;
FcSubState *st; FcRule *r;
int i; FcValueList *l, *value = NULL;
FcTest *t;
FcEdit *e;
FcValueList *l;
FcPattern *m; FcPattern *m;
FcStrSet *strs; FcStrSet *strs;
FcPatternElt *elt = NULL;
FcObject object = FC_INVALID_OBJECT;
if (!config) if (!config)
{ {
@ -1542,10 +1535,6 @@ FcConfigSubstituteWithPat (FcConfig *config,
return FcFalse; return FcFalse;
} }
st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
if (!st && config->maxObjects)
return FcFalse;
if (FcDebug () & FC_DBG_EDIT) if (FcDebug () & FC_DBG_EDIT)
{ {
printf ("FcConfigSubstitute "); printf ("FcConfigSubstitute ");
@ -1553,194 +1542,174 @@ FcConfigSubstituteWithPat (FcConfig *config,
} }
for (; s; s = s->next) for (; s; s = s->next)
{ {
/* r = s->rule;
* Check the tests to see if for (; r; r = r->next)
* they all match the pattern
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{ {
if (FcDebug () & FC_DBG_EDIT) switch (r->type) {
{ case FcRuleUnknown:
printf ("FcConfigSubstitute test "); /* shouldn't be reached */
FcTestPrint (t); break;
} case FcRuleTest:
st[i].elt = 0; /*
if (kind == FcMatchFont && t->kind == FcMatchPattern) * Check the tests to see if
m = p_pat; * they all match the pattern
else */
m = p; if (FcDebug () & FC_DBG_EDIT)
if (m)
st[i].elt = FcPatternObjectFindElt (m, t->object);
else
st[i].elt = 0;
/*
* If there's no such field in the font,
* then FcQualAll matches while FcQualAny does not
*/
if (!st[i].elt)
{
if (t->qual == FcQualAll)
{ {
st[i].value = 0; printf ("FcConfigSubstitute test ");
continue; FcTestPrint (r->u.test);
} }
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
m = p_pat;
else else
break; m = p;
} if (m)
/* elt = FcPatternObjectFindElt (m, r->u.test->object);
* Check to see if there is a match, mark the location else
* to apply match-relative edits elt = NULL;
*/
st[i].value = FcConfigMatchValueList (m, p_pat, kind, t, st[i].elt->values);
if (!st[i].value)
break;
if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
break;
if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
break;
}
if (t)
{
if (FcDebug () & FC_DBG_EDIT)
printf ("No match\n");
continue;
}
if (FcDebug () & FC_DBG_EDIT)
{
printf ("Substitute ");
FcSubstPrint (s);
}
for (e = s->edit; e; e = e->next)
{
/*
* Evaluate the list of expressions
*/
l = FcConfigValues (p, p_pat,kind, e->expr, e->binding);
/*
* Locate any test associated with this field, skipping
* tests associated with the pattern when substituting in
* the font
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{
if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
t->object == e->object)
{
/*
* KLUDGE - the pattern may have been reallocated or
* things may have been inserted or deleted above
* this element by other edits. Go back and find
* the element again
*/
if (e != s->edit && st[i].elt)
st[i].elt = FcPatternObjectFindElt (p, t->object);
if (!st[i].elt)
t = 0;
break;
}
}
switch (FC_OP_GET_OP (e->op)) {
case FcOpAssign:
/* /*
* If there was a test, then replace the matched * If there's no such field in the font,
* value with the new list of values * then FcQualAll matches while FcQualAny does not
*/ */
if (t) if (!elt)
{ {
FcValueList *thisValue = st[i].value; if (r->u.test->qual == FcQualAll)
FcValueList *nextValue = thisValue;
/*
* Append the new list of values after the current value
*/
FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l, e->object);
/*
* Delete the marked value
*/
if (thisValue)
FcConfigDel (&st[i].elt->values, thisValue);
/*
* Adjust any pointers into the value list to ensure
* future edits occur at the same place
*/
for (t = s->test, i = 0; t; t = t->next, i++)
{ {
if (st[i].value == thisValue) value = NULL;
st[i].value = nextValue; continue;
} }
break; else
}
/* fall through ... */
case FcOpAssignReplace:
/*
* Delete all of the values and insert
* the new set
*/
FcConfigPatternDel (p, e->object);
FcConfigPatternAdd (p, e->object, l, FcTrue);
/*
* Adjust any pointers into the value list as they no
* longer point to anything valid
*/
if (t)
{
FcPatternElt *thisElt = st[i].elt;
for (t = s->test, i = 0; t; t = t->next, i++)
{ {
if (st[i].elt == thisElt) if (FcDebug () & FC_DBG_EDIT)
st[i].value = 0; printf ("No match\n");
goto bail;
} }
} }
break; /*
case FcOpPrepend: * Check to see if there is a match, mark the location
if (t) * to apply match-relative edits
*/
value = FcConfigMatchValueList (m, p_pat, kind, r->u.test, elt->values);
if (!value ||
(r->u.test->qual == FcQualFirst && value != elt->values) ||
(r->u.test->qual == FcQualNotFirst && value == elt->values))
{ {
FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l, e->object); if (FcDebug () & FC_DBG_EDIT)
break; printf ("No match\n");
goto bail;
} }
/* fall through ... */ object = r->u.test->object;
case FcOpPrependFirst:
FcConfigPatternAdd (p, e->object, l, FcFalse);
break; break;
case FcOpAppend: case FcRuleEdit:
if (t) if (FcDebug () & FC_DBG_EDIT)
{ {
FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object); printf ("Substitute ");
break; FcEditPrint (r->u.edit);
printf ("\n\n");
} }
/* fall through ... */ /*
case FcOpAppendLast: * Evaluate the list of expressions
FcConfigPatternAdd (p, e->object, l, FcTrue); */
break; l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
case FcOpDelete: /*
if (t) * Locate any test associated with this field, skipping
{ * tests associated with the pattern when substituting in
FcConfigDel (&st[i].elt->values, st[i].value); * the font
break; */
} if (object != r->u.edit->object)
/* fall through ... */ value = NULL;
case FcOpDeleteAll:
FcConfigPatternDel (p, e->object);
break;
default:
FcValueListDestroy (l);
break;
}
}
/*
* Now go through the pattern and eliminate
* any properties without data
*/
for (e = s->edit; e; e = e->next)
FcConfigPatternCanon (p, e->object);
if (FcDebug () & FC_DBG_EDIT) switch (FC_OP_GET_OP (r->u.edit->op)) {
{ case FcOpAssign:
printf ("FcConfigSubstitute edit"); /*
FcPatternPrint (p); * If there was a test, then replace the matched
* value with the new list of values
*/
if (value)
{
FcValueList *thisValue = value;
FcValueList *nextValue = thisValue;
/*
* Append the new list of values after the current value
*/
FcConfigAdd (&elt->values, thisValue, FcTrue, l, r->u.edit->object);
/*
* Delete the marked value
*/
if (thisValue)
FcConfigDel (&elt->values, thisValue);
/*
* Adjust a pointer into the value list to ensure
* future edits occur at the same place
*/
value = nextValue;
break;
}
/* fall through ... */
case FcOpAssignReplace:
/*
* Delete all of the values and insert
* the new set
*/
FcConfigPatternDel (p, r->u.edit->object);
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
/*
* Adjust a pointer into the value list as they no
* longer point to anything valid
*/
value = NULL;
break;
case FcOpPrepend:
if (value)
{
FcConfigAdd (&elt->values, value, FcFalse, l, r->u.edit->object);
break;
}
/* fall through ... */
case FcOpPrependFirst:
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
break;
case FcOpAppend:
if (value)
{
FcConfigAdd (&elt->values, value, FcTrue, l, r->u.edit->object);
break;
}
/* fall through ... */
case FcOpAppendLast:
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
break;
case FcOpDelete:
if (value)
{
FcConfigDel (&elt->values, value);
break;
}
/* fall through ... */
case FcOpDeleteAll:
FcConfigPatternDel (p, r->u.edit->object);
break;
default:
FcValueListDestroy (l);
break;
}
/*
* Now go through the pattern and eliminate
* any properties without data
*/
FcConfigPatternCanon (p, r->u.edit->object);
if (FcDebug () & FC_DBG_EDIT)
{
printf ("FcConfigSubstitute edit");
FcPatternPrint (p);
}
break;
}
} }
bail:;
} }
free (st);
if (FcDebug () & FC_DBG_EDIT) if (FcDebug () & FC_DBG_EDIT)
{ {
printf ("FcConfigSubstitute done"); printf ("FcConfigSubstitute done");

View File

@ -427,21 +427,38 @@ FcEditPrint (const FcEdit *edit)
void void
FcSubstPrint (const FcSubst *subst) FcSubstPrint (const FcSubst *subst)
{ {
FcEdit *e; FcRule *r;
FcTest *t; FcRuleType last_type = FcRuleUnknown;
printf ("match\n"); printf ("match\n");
for (t = subst->test; t; t = t->next) for (r = subst->rule; r; r = r->next)
{ {
if (last_type != r->type)
{
switch (r->type) {
case FcRuleTest:
printf ("[test]\n");
break;
case FcRuleEdit:
printf ("[edit]\n");
break;
default:
break;
}
last_type = r->type;
}
printf ("\t"); printf ("\t");
FcTestPrint (t); switch (r->type) {
} case FcRuleTest:
printf ("edit\n"); FcTestPrint (r->u.test);
for (e = subst->edit; e; e = e->next) break;
{ case FcRuleEdit:
printf ("\t"); FcEditPrint (r->u.edit);
FcEditPrint (e); printf (";\n");
printf (";\n"); break;
default:
break;
}
} }
printf ("\n"); printf ("\n");
} }

View File

@ -241,7 +241,6 @@ typedef struct _FcExprName {
typedef struct _FcExpr { typedef struct _FcExpr {
FcOp op; FcOp op;
FcRef ref;
union { union {
int ival; int ival;
double dval; double dval;
@ -275,7 +274,6 @@ typedef enum _FcQual {
#define FcMatchDefault ((FcMatchKind) -1) #define FcMatchDefault ((FcMatchKind) -1)
typedef struct _FcTest { typedef struct _FcTest {
struct _FcTest *next;
FcMatchKind kind; FcMatchKind kind;
FcQual qual; FcQual qual;
FcObject object; FcObject object;
@ -284,17 +282,28 @@ typedef struct _FcTest {
} FcTest; } FcTest;
typedef struct _FcEdit { typedef struct _FcEdit {
struct _FcEdit *next;
FcObject object; FcObject object;
FcOp op; FcOp op;
FcExpr *expr; FcExpr *expr;
FcValueBinding binding; FcValueBinding binding;
} FcEdit; } FcEdit;
typedef enum _FcRuleType {
FcRuleUnknown, FcRuleTest, FcRuleEdit
} FcRuleType;
typedef struct _FcRule {
struct _FcRule *next;
FcRuleType type;
union {
FcTest *test;
FcEdit *edit;
} u;
} FcRule;
typedef struct _FcSubst { typedef struct _FcSubst {
struct _FcSubst *next; struct _FcSubst *next;
FcTest *test; FcRule *rule;
FcEdit *edit;
} FcSubst; } FcSubst;
typedef struct _FcCharLeaf { typedef struct _FcCharLeaf {
@ -614,10 +623,9 @@ FcPrivate FcBool
FcConfigAddBlank (FcConfig *config, FcConfigAddBlank (FcConfig *config,
FcChar32 blank); FcChar32 blank);
FcPrivate FcBool FcBool
FcConfigAddEdit (FcConfig *config, FcConfigAddRule (FcConfig *config,
FcTest *test, FcRule *rule,
FcEdit *edit,
FcMatchKind kind); FcMatchKind kind);
FcPrivate void FcPrivate void
@ -844,6 +852,9 @@ FcTestDestroy (FcTest *test);
FcPrivate void FcPrivate void
FcEditDestroy (FcEdit *e); FcEditDestroy (FcEdit *e);
void
FcRuleDestroy (FcRule *rule);
/* fclang.c */ /* fclang.c */
FcPrivate FcLangSet * FcPrivate FcLangSet *
FcFreeTypeLangSet (const FcCharSet *charset, FcFreeTypeLangSet (const FcCharSet *charset,

View File

@ -62,12 +62,28 @@ FcExprDestroy (FcExpr *e);
void void
FcTestDestroy (FcTest *test) FcTestDestroy (FcTest *test)
{ {
if (test->next)
FcTestDestroy (test->next);
FcExprDestroy (test->expr); FcExprDestroy (test->expr);
free (test); free (test);
} }
void
FcRuleDestroy (FcRule *rule)
{
if (rule->next)
FcRuleDestroy (rule->next);
switch (rule->type) {
case FcRuleTest:
FcTestDestroy (rule->u.test);
break;
case FcRuleEdit:
FcEditDestroy (rule->u.edit);
break;
default:
break;
}
free (rule);
}
static FcExpr * static FcExpr *
FcExprCreateInteger (FcConfig *config, int i) FcExprCreateInteger (FcConfig *config, int i)
{ {
@ -223,24 +239,11 @@ FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
return e; return e;
} }
static FcExpr *
FcExprReference (FcExpr *e)
{
if (e)
{
FcRefInc (&e->ref);
}
return e;
}
static void static void
FcExprDestroy (FcExpr *e) FcExprDestroy (FcExpr *e)
{ {
if (!e) if (!e)
return; return;
if (FcRefDec (&e->ref) != 1)
return;
switch (FC_OP_GET_OP (e->op)) { switch (FC_OP_GET_OP (e->op)) {
case FcOpInteger: case FcOpInteger:
break; break;
@ -313,8 +316,6 @@ FcExprDestroy (FcExpr *e)
void void
FcEditDestroy (FcEdit *e) FcEditDestroy (FcEdit *e)
{ {
if (e->next)
FcEditDestroy (e->next);
if (e->expr) if (e->expr)
FcExprDestroy (e->expr); FcExprDestroy (e->expr);
free (e); free (e);
@ -727,7 +728,6 @@ FcTestCreate (FcConfigParse *parse,
{ {
const FcObjectType *o; const FcObjectType *o;
test->next = 0;
test->kind = kind; test->kind = kind;
test->qual = qual; test->qual = qual;
test->object = FcObjectFromName ((const char *) field); test->object = FcObjectFromName ((const char *) field);
@ -740,21 +740,6 @@ FcTestCreate (FcConfigParse *parse,
return test; return test;
} }
static FcTest *
FcTestDuplicate (FcTest *test)
{
FcTest *retval = (FcTest *) malloc (sizeof (FcTest));
if (retval)
{
memcpy (retval, test, sizeof (FcTest));
retval->next = NULL;
retval->expr = FcExprReference (test->expr);
}
return retval;
}
static FcEdit * static FcEdit *
FcEditCreate (FcConfigParse *parse, FcEditCreate (FcConfigParse *parse,
FcObject object, FcObject object,
@ -768,7 +753,6 @@ FcEditCreate (FcConfigParse *parse,
{ {
const FcObjectType *o; const FcObjectType *o;
e->next = 0;
e->object = object; e->object = object;
e->op = op; e->op = op;
e->expr = expr; e->expr = expr;
@ -780,6 +764,34 @@ FcEditCreate (FcConfigParse *parse,
return e; return e;
} }
static FcRule *
FcRuleCreate (FcRuleType type,
void *p)
{
FcRule *r = (FcRule *) malloc (sizeof (FcRule));
if (!r)
return NULL;
r->next = NULL;
r->type = type;
switch (type)
{
case FcRuleTest:
r->u.test = (FcTest *) p;
break;
case FcRuleEdit:
r->u.edit = (FcEdit *) p;
break;
default:
free (r);
r = NULL;
break;
}
return r;
}
static FcVStack * static FcVStack *
FcVStackCreateAndPush (FcConfigParse *parse) FcVStackCreateAndPush (FcConfigParse *parse)
{ {
@ -1685,9 +1697,9 @@ static void
FcParseAlias (FcConfigParse *parse) FcParseAlias (FcConfigParse *parse)
{ {
FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
FcEdit *edit = 0, *next; FcEdit *edit = 0;
FcVStack *vstack; FcVStack *vstack;
FcTest *test = NULL; FcRule *rule = NULL, *r;
FcValueBinding binding; FcValueBinding binding;
if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
@ -1732,8 +1744,14 @@ FcParseAlias (FcConfigParse *parse)
vstack->tag = FcVStackNone; vstack->tag = FcVStackNone;
break; break;
case FcVStackTest: case FcVStackTest:
vstack->u.test->next = test; if (rule)
test = vstack->u.test; {
r = FcRuleCreate (FcRuleTest, vstack->u.test);
r->next = rule;
rule = r;
}
else
rule = FcRuleCreate (FcRuleTest, vstack->u.test);
vstack->tag = FcVStackNone; vstack->tag = FcVStackNone;
break; break;
default: default:
@ -1751,8 +1769,35 @@ FcParseAlias (FcConfigParse *parse)
FcExprDestroy (accept); FcExprDestroy (accept);
if (def) if (def)
FcExprDestroy (def); FcExprDestroy (def);
if (rule)
FcRuleDestroy (rule);
return; return;
} }
if (!prefer &&
!accept &&
!def)
{
FcExprDestroy (family);
return;
}
else
{
FcTest *t = FcTestCreate (parse, FcMatchPattern,
FcQualAny,
(FcChar8 *) FC_FAMILY,
FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
family);
if (rule)
{
for (r = rule; r->next; r = r->next);
r->next = FcRuleCreate (FcRuleTest, t);
r = r->next;
}
else
{
r = rule = FcRuleCreate (FcRuleTest, t);
}
}
if (prefer) if (prefer)
{ {
edit = FcEditCreate (parse, edit = FcEditCreate (parse,
@ -1760,60 +1805,46 @@ FcParseAlias (FcConfigParse *parse)
FcOpPrepend, FcOpPrepend,
prefer, prefer,
binding); binding);
if (edit) if (!edit)
edit->next = 0;
else
FcExprDestroy (prefer); FcExprDestroy (prefer);
else
{
r->next = FcRuleCreate (FcRuleEdit, edit);
r = r->next;
}
} }
if (accept) if (accept)
{ {
next = edit;
edit = FcEditCreate (parse, edit = FcEditCreate (parse,
FC_FAMILY_OBJECT, FC_FAMILY_OBJECT,
FcOpAppend, FcOpAppend,
accept, accept,
binding); binding);
if (edit) if (!edit)
edit->next = next;
else
FcExprDestroy (accept); FcExprDestroy (accept);
else
{
r->next = FcRuleCreate (FcRuleEdit, edit);
r = r->next;
}
} }
if (def) if (def)
{ {
next = edit;
edit = FcEditCreate (parse, edit = FcEditCreate (parse,
FC_FAMILY_OBJECT, FC_FAMILY_OBJECT,
FcOpAppendLast, FcOpAppendLast,
def, def,
binding); binding);
if (edit) if (!edit)
edit->next = next;
else
FcExprDestroy (def); FcExprDestroy (def);
}
if (edit)
{
FcTest *t = FcTestCreate (parse, FcMatchPattern,
FcQualAny,
(FcChar8 *) FC_FAMILY,
FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
family);
if (test)
{
FcTest *p = test;
while (p->next)
p = p->next;
p->next = t;
}
else else
test = t; {
if (test) r->next = FcRuleCreate (FcRuleEdit, edit);
if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) r = r->next;
FcTestDestroy (test); }
} }
else if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
FcExprDestroy (family); FcRuleDestroy (rule);
} }
static FcExpr * static FcExpr *
@ -2414,22 +2445,14 @@ FcParseEdit (FcConfigParse *parse)
FcEditDestroy (edit); FcEditDestroy (edit);
} }
typedef struct FcSubstStack {
FcTest *test;
FcEdit *edit;
} FcSubstStack;
static void static void
FcParseMatch (FcConfigParse *parse) FcParseMatch (FcConfigParse *parse)
{ {
const FcChar8 *kind_name; const FcChar8 *kind_name;
FcMatchKind kind; FcMatchKind kind;
FcTest *test = 0;
FcEdit *edit = 0; FcEdit *edit = 0;
FcVStack *vstack; FcVStack *vstack;
FcBool tested = FcFalse; FcRule *rule = NULL, *r;
FcSubstStack *sstack = NULL;
int len, pos = 0, i;
kind_name = FcConfigGetAttribute (parse, "target"); kind_name = FcConfigGetAttribute (parse, "target");
if (!kind_name) if (!kind_name)
@ -2448,55 +2471,29 @@ FcParseMatch (FcConfigParse *parse)
return; return;
} }
} }
len = FcVStackElements(parse);
if (len > 0)
{
sstack = malloc (sizeof (FcSubstStack) * (len + 1));
if (!sstack)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
}
while ((vstack = FcVStackPeek (parse))) while ((vstack = FcVStackPeek (parse)))
{ {
switch ((int) vstack->tag) { switch ((int) vstack->tag) {
case FcVStackTest: case FcVStackTest:
vstack->u.test->next = test; r = FcRuleCreate (FcRuleTest, vstack->u.test);
test = vstack->u.test; if (rule)
r->next = rule;
rule = r;
vstack->tag = FcVStackNone; vstack->tag = FcVStackNone;
tested = FcTrue;
for (i = 0; i < pos; i++)
{
FcTest *t = FcTestDuplicate(test);
t->next = sstack[i].test;
sstack[i].test = t;
}
break; break;
case FcVStackEdit: case FcVStackEdit:
/* due to the reverse traversal, <edit> node appears faster than if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
* <test> node if any. so we have to deal with it here rather than
* the above in FcVStackTest, and put recipes in reverse order.
*/
if (tested)
{
sstack[pos].test = test;
sstack[pos].edit = edit;
pos++;
test = NULL;
edit = NULL;
tested = FcFalse;
}
vstack->u.edit->next = edit;
edit = vstack->u.edit;
vstack->tag = FcVStackNone;
if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
{ {
FcConfigMessage (parse, FcSevereError, FcConfigMessage (parse, FcSevereError,
"<match target=\"scan\"> cannot edit user-defined object \"%s\"", "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
FcObjectName(edit->object)); FcObjectName(edit->object));
break;
} }
r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
if (rule)
r->next = rule;
rule = r;
vstack->tag = FcVStackNone;
break; break;
default: default:
FcConfigMessage (parse, FcSevereWarning, "invalid match element"); FcConfigMessage (parse, FcSevereWarning, "invalid match element");
@ -2504,22 +2501,8 @@ FcParseMatch (FcConfigParse *parse)
} }
FcVStackPopAndDestroy (parse); FcVStackPopAndDestroy (parse);
} }
if (!FcConfigAddEdit (parse->config, test, edit, kind)) if (!FcConfigAddRule (parse->config, rule, kind))
FcConfigMessage (parse, FcSevereError, "out of memory"); FcConfigMessage (parse, FcSevereError, "out of memory");
if (sstack)
{
int i;
for (i = 0; i < pos; i++)
{
if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
}
free (sstack);
}
} }
static void static void