Rework to apply the intermixed test and edit elements in one-pass
This commit is contained in:
parent
1162515a98
commit
d420e1df98
367
src/fccfg.c
367
src/fccfg.c
|
@ -214,10 +214,8 @@ FcSubstDestroy (FcSubst *s)
|
|||
while (s)
|
||||
{
|
||||
n = s->next;
|
||||
if (s->test)
|
||||
FcTestDestroy (s->test);
|
||||
if (s->edit)
|
||||
FcEditDestroy (s->edit);
|
||||
if (s->rule)
|
||||
FcRuleDestroy (s->rule);
|
||||
free (s);
|
||||
s = n;
|
||||
}
|
||||
|
@ -226,8 +224,6 @@ FcSubstDestroy (FcSubst *s)
|
|||
FcExpr *
|
||||
FcConfigAllocExpr (FcConfig *config)
|
||||
{
|
||||
FcExpr *e;
|
||||
|
||||
if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
|
||||
{
|
||||
FcExprPage *new_page;
|
||||
|
@ -241,10 +237,7 @@ FcConfigAllocExpr (FcConfig *config)
|
|||
config->expr_pool = new_page;
|
||||
}
|
||||
|
||||
e = config->expr_pool->next++;
|
||||
FcRefInit (&e->ref, 1);
|
||||
|
||||
return e;
|
||||
return config->expr_pool->next++;
|
||||
}
|
||||
|
||||
FcConfig *
|
||||
|
@ -649,15 +642,13 @@ FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
|
|||
return FcConfigSetRescanInterval (config, rescanInterval);
|
||||
}
|
||||
|
||||
|
||||
FcBool
|
||||
FcConfigAddEdit (FcConfig *config,
|
||||
FcTest *test,
|
||||
FcEdit *edit,
|
||||
FcConfigAddRule (FcConfig *config,
|
||||
FcRule *rule,
|
||||
FcMatchKind kind)
|
||||
{
|
||||
FcSubst *subst, **prev;
|
||||
FcTest *t;
|
||||
FcRule *r;
|
||||
int num;
|
||||
|
||||
switch (kind) {
|
||||
|
@ -678,15 +669,18 @@ FcConfigAddEdit (FcConfig *config,
|
|||
return FcFalse;
|
||||
for (; *prev; prev = &(*prev)->next);
|
||||
*prev = subst;
|
||||
subst->next = 0;
|
||||
subst->test = test;
|
||||
subst->edit = edit;
|
||||
subst->next = NULL;
|
||||
subst->rule = rule;
|
||||
num = 0;
|
||||
for (t = test; t; t = t->next)
|
||||
for (r = rule; r; r = r->next)
|
||||
{
|
||||
if (t->kind == FcMatchDefault)
|
||||
t->kind = kind;
|
||||
num++;
|
||||
if (r->type == FcRuleTest)
|
||||
{
|
||||
if (r->u.test &&
|
||||
r->u.test->kind == FcMatchDefault)
|
||||
r->u.test->kind = kind;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (config->maxObjects < num)
|
||||
config->maxObjects = num;
|
||||
|
@ -1491,13 +1485,12 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
|||
{
|
||||
FcValue v;
|
||||
FcSubst *s;
|
||||
FcSubState *st;
|
||||
int i;
|
||||
FcTest *t;
|
||||
FcEdit *e;
|
||||
FcValueList *l;
|
||||
FcRule *r;
|
||||
FcValueList *l, *value = NULL;
|
||||
FcPattern *m;
|
||||
FcStrSet *strs;
|
||||
FcPatternElt *elt = NULL;
|
||||
FcObject object = FC_INVALID_OBJECT;
|
||||
|
||||
if (!config)
|
||||
{
|
||||
|
@ -1542,10 +1535,6 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
|||
return FcFalse;
|
||||
}
|
||||
|
||||
st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
|
||||
if (!st && config->maxObjects)
|
||||
return FcFalse;
|
||||
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
{
|
||||
printf ("FcConfigSubstitute ");
|
||||
|
@ -1553,194 +1542,174 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
|||
}
|
||||
for (; s; s = s->next)
|
||||
{
|
||||
/*
|
||||
* Check the tests to see if
|
||||
* they all match the pattern
|
||||
*/
|
||||
for (t = s->test, i = 0; t; t = t->next, i++)
|
||||
r = s->rule;
|
||||
for (; r; r = r->next)
|
||||
{
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
{
|
||||
printf ("FcConfigSubstitute test ");
|
||||
FcTestPrint (t);
|
||||
}
|
||||
st[i].elt = 0;
|
||||
if (kind == FcMatchFont && t->kind == FcMatchPattern)
|
||||
m = p_pat;
|
||||
else
|
||||
m = p;
|
||||
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)
|
||||
switch (r->type) {
|
||||
case FcRuleUnknown:
|
||||
/* shouldn't be reached */
|
||||
break;
|
||||
case FcRuleTest:
|
||||
/*
|
||||
* Check the tests to see if
|
||||
* they all match the pattern
|
||||
*/
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
{
|
||||
st[i].value = 0;
|
||||
continue;
|
||||
printf ("FcConfigSubstitute test ");
|
||||
FcTestPrint (r->u.test);
|
||||
}
|
||||
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
|
||||
m = p_pat;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Check to see if there is a match, mark the location
|
||||
* to apply match-relative edits
|
||||
*/
|
||||
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:
|
||||
m = p;
|
||||
if (m)
|
||||
elt = FcPatternObjectFindElt (m, r->u.test->object);
|
||||
else
|
||||
elt = NULL;
|
||||
/*
|
||||
* If there was a test, then replace the matched
|
||||
* value with the new list of values
|
||||
* If there's no such field in the font,
|
||||
* then FcQualAll matches while FcQualAny does not
|
||||
*/
|
||||
if (t)
|
||||
if (!elt)
|
||||
{
|
||||
FcValueList *thisValue = st[i].value;
|
||||
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 (r->u.test->qual == FcQualAll)
|
||||
{
|
||||
if (st[i].value == thisValue)
|
||||
st[i].value = nextValue;
|
||||
value = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* 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++)
|
||||
else
|
||||
{
|
||||
if (st[i].elt == thisElt)
|
||||
st[i].value = 0;
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
printf ("No match\n");
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FcOpPrepend:
|
||||
if (t)
|
||||
/*
|
||||
* Check to see if there is a match, mark the location
|
||||
* 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);
|
||||
break;
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
printf ("No match\n");
|
||||
goto bail;
|
||||
}
|
||||
/* fall through ... */
|
||||
case FcOpPrependFirst:
|
||||
FcConfigPatternAdd (p, e->object, l, FcFalse);
|
||||
object = r->u.test->object;
|
||||
break;
|
||||
case FcOpAppend:
|
||||
if (t)
|
||||
case FcRuleEdit:
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
{
|
||||
FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object);
|
||||
break;
|
||||
printf ("Substitute ");
|
||||
FcEditPrint (r->u.edit);
|
||||
printf ("\n\n");
|
||||
}
|
||||
/* fall through ... */
|
||||
case FcOpAppendLast:
|
||||
FcConfigPatternAdd (p, e->object, l, FcTrue);
|
||||
break;
|
||||
case FcOpDelete:
|
||||
if (t)
|
||||
{
|
||||
FcConfigDel (&st[i].elt->values, st[i].value);
|
||||
break;
|
||||
}
|
||||
/* fall through ... */
|
||||
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);
|
||||
/*
|
||||
* Evaluate the list of expressions
|
||||
*/
|
||||
l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
|
||||
/*
|
||||
* Locate any test associated with this field, skipping
|
||||
* tests associated with the pattern when substituting in
|
||||
* the font
|
||||
*/
|
||||
if (object != r->u.edit->object)
|
||||
value = NULL;
|
||||
|
||||
if (FcDebug () & FC_DBG_EDIT)
|
||||
{
|
||||
printf ("FcConfigSubstitute edit");
|
||||
FcPatternPrint (p);
|
||||
switch (FC_OP_GET_OP (r->u.edit->op)) {
|
||||
case FcOpAssign:
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
printf ("FcConfigSubstitute done");
|
||||
|
|
39
src/fcdbg.c
39
src/fcdbg.c
|
@ -427,21 +427,38 @@ FcEditPrint (const FcEdit *edit)
|
|||
void
|
||||
FcSubstPrint (const FcSubst *subst)
|
||||
{
|
||||
FcEdit *e;
|
||||
FcTest *t;
|
||||
FcRule *r;
|
||||
FcRuleType last_type = FcRuleUnknown;
|
||||
|
||||
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");
|
||||
FcTestPrint (t);
|
||||
}
|
||||
printf ("edit\n");
|
||||
for (e = subst->edit; e; e = e->next)
|
||||
{
|
||||
printf ("\t");
|
||||
FcEditPrint (e);
|
||||
printf (";\n");
|
||||
switch (r->type) {
|
||||
case FcRuleTest:
|
||||
FcTestPrint (r->u.test);
|
||||
break;
|
||||
case FcRuleEdit:
|
||||
FcEditPrint (r->u.edit);
|
||||
printf (";\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
|
29
src/fcint.h
29
src/fcint.h
|
@ -241,7 +241,6 @@ typedef struct _FcExprName {
|
|||
|
||||
typedef struct _FcExpr {
|
||||
FcOp op;
|
||||
FcRef ref;
|
||||
union {
|
||||
int ival;
|
||||
double dval;
|
||||
|
@ -275,7 +274,6 @@ typedef enum _FcQual {
|
|||
#define FcMatchDefault ((FcMatchKind) -1)
|
||||
|
||||
typedef struct _FcTest {
|
||||
struct _FcTest *next;
|
||||
FcMatchKind kind;
|
||||
FcQual qual;
|
||||
FcObject object;
|
||||
|
@ -284,17 +282,28 @@ typedef struct _FcTest {
|
|||
} FcTest;
|
||||
|
||||
typedef struct _FcEdit {
|
||||
struct _FcEdit *next;
|
||||
FcObject object;
|
||||
FcOp op;
|
||||
FcExpr *expr;
|
||||
FcValueBinding binding;
|
||||
} 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 {
|
||||
struct _FcSubst *next;
|
||||
FcTest *test;
|
||||
FcEdit *edit;
|
||||
FcRule *rule;
|
||||
} FcSubst;
|
||||
|
||||
typedef struct _FcCharLeaf {
|
||||
|
@ -614,10 +623,9 @@ FcPrivate FcBool
|
|||
FcConfigAddBlank (FcConfig *config,
|
||||
FcChar32 blank);
|
||||
|
||||
FcPrivate FcBool
|
||||
FcConfigAddEdit (FcConfig *config,
|
||||
FcTest *test,
|
||||
FcEdit *edit,
|
||||
FcBool
|
||||
FcConfigAddRule (FcConfig *config,
|
||||
FcRule *rule,
|
||||
FcMatchKind kind);
|
||||
|
||||
FcPrivate void
|
||||
|
@ -844,6 +852,9 @@ FcTestDestroy (FcTest *test);
|
|||
FcPrivate void
|
||||
FcEditDestroy (FcEdit *e);
|
||||
|
||||
void
|
||||
FcRuleDestroy (FcRule *rule);
|
||||
|
||||
/* fclang.c */
|
||||
FcPrivate FcLangSet *
|
||||
FcFreeTypeLangSet (const FcCharSet *charset,
|
||||
|
|
247
src/fcxml.c
247
src/fcxml.c
|
@ -62,12 +62,28 @@ FcExprDestroy (FcExpr *e);
|
|||
void
|
||||
FcTestDestroy (FcTest *test)
|
||||
{
|
||||
if (test->next)
|
||||
FcTestDestroy (test->next);
|
||||
FcExprDestroy (test->expr);
|
||||
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 *
|
||||
FcExprCreateInteger (FcConfig *config, int i)
|
||||
{
|
||||
|
@ -223,24 +239,11 @@ FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
|
|||
return e;
|
||||
}
|
||||
|
||||
static FcExpr *
|
||||
FcExprReference (FcExpr *e)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
FcRefInc (&e->ref);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static void
|
||||
FcExprDestroy (FcExpr *e)
|
||||
{
|
||||
if (!e)
|
||||
return;
|
||||
if (FcRefDec (&e->ref) != 1)
|
||||
return;
|
||||
switch (FC_OP_GET_OP (e->op)) {
|
||||
case FcOpInteger:
|
||||
break;
|
||||
|
@ -313,8 +316,6 @@ FcExprDestroy (FcExpr *e)
|
|||
void
|
||||
FcEditDestroy (FcEdit *e)
|
||||
{
|
||||
if (e->next)
|
||||
FcEditDestroy (e->next);
|
||||
if (e->expr)
|
||||
FcExprDestroy (e->expr);
|
||||
free (e);
|
||||
|
@ -727,7 +728,6 @@ FcTestCreate (FcConfigParse *parse,
|
|||
{
|
||||
const FcObjectType *o;
|
||||
|
||||
test->next = 0;
|
||||
test->kind = kind;
|
||||
test->qual = qual;
|
||||
test->object = FcObjectFromName ((const char *) field);
|
||||
|
@ -740,21 +740,6 @@ FcTestCreate (FcConfigParse *parse,
|
|||
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 *
|
||||
FcEditCreate (FcConfigParse *parse,
|
||||
FcObject object,
|
||||
|
@ -768,7 +753,6 @@ FcEditCreate (FcConfigParse *parse,
|
|||
{
|
||||
const FcObjectType *o;
|
||||
|
||||
e->next = 0;
|
||||
e->object = object;
|
||||
e->op = op;
|
||||
e->expr = expr;
|
||||
|
@ -780,6 +764,34 @@ FcEditCreate (FcConfigParse *parse,
|
|||
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 *
|
||||
FcVStackCreateAndPush (FcConfigParse *parse)
|
||||
{
|
||||
|
@ -1685,9 +1697,9 @@ static void
|
|||
FcParseAlias (FcConfigParse *parse)
|
||||
{
|
||||
FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
|
||||
FcEdit *edit = 0, *next;
|
||||
FcEdit *edit = 0;
|
||||
FcVStack *vstack;
|
||||
FcTest *test = NULL;
|
||||
FcRule *rule = NULL, *r;
|
||||
FcValueBinding binding;
|
||||
|
||||
if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
|
||||
|
@ -1732,8 +1744,14 @@ FcParseAlias (FcConfigParse *parse)
|
|||
vstack->tag = FcVStackNone;
|
||||
break;
|
||||
case FcVStackTest:
|
||||
vstack->u.test->next = test;
|
||||
test = vstack->u.test;
|
||||
if (rule)
|
||||
{
|
||||
r = FcRuleCreate (FcRuleTest, vstack->u.test);
|
||||
r->next = rule;
|
||||
rule = r;
|
||||
}
|
||||
else
|
||||
rule = FcRuleCreate (FcRuleTest, vstack->u.test);
|
||||
vstack->tag = FcVStackNone;
|
||||
break;
|
||||
default:
|
||||
|
@ -1751,8 +1769,35 @@ FcParseAlias (FcConfigParse *parse)
|
|||
FcExprDestroy (accept);
|
||||
if (def)
|
||||
FcExprDestroy (def);
|
||||
if (rule)
|
||||
FcRuleDestroy (rule);
|
||||
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)
|
||||
{
|
||||
edit = FcEditCreate (parse,
|
||||
|
@ -1760,60 +1805,46 @@ FcParseAlias (FcConfigParse *parse)
|
|||
FcOpPrepend,
|
||||
prefer,
|
||||
binding);
|
||||
if (edit)
|
||||
edit->next = 0;
|
||||
else
|
||||
if (!edit)
|
||||
FcExprDestroy (prefer);
|
||||
else
|
||||
{
|
||||
r->next = FcRuleCreate (FcRuleEdit, edit);
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
if (accept)
|
||||
{
|
||||
next = edit;
|
||||
edit = FcEditCreate (parse,
|
||||
FC_FAMILY_OBJECT,
|
||||
FcOpAppend,
|
||||
accept,
|
||||
binding);
|
||||
if (edit)
|
||||
edit->next = next;
|
||||
else
|
||||
if (!edit)
|
||||
FcExprDestroy (accept);
|
||||
else
|
||||
{
|
||||
r->next = FcRuleCreate (FcRuleEdit, edit);
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
if (def)
|
||||
{
|
||||
next = edit;
|
||||
edit = FcEditCreate (parse,
|
||||
FC_FAMILY_OBJECT,
|
||||
FcOpAppendLast,
|
||||
def,
|
||||
binding);
|
||||
if (edit)
|
||||
edit->next = next;
|
||||
else
|
||||
if (!edit)
|
||||
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
|
||||
test = t;
|
||||
if (test)
|
||||
if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
|
||||
FcTestDestroy (test);
|
||||
{
|
||||
r->next = FcRuleCreate (FcRuleEdit, edit);
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
FcExprDestroy (family);
|
||||
if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
|
||||
FcRuleDestroy (rule);
|
||||
}
|
||||
|
||||
static FcExpr *
|
||||
|
@ -2414,22 +2445,14 @@ FcParseEdit (FcConfigParse *parse)
|
|||
FcEditDestroy (edit);
|
||||
}
|
||||
|
||||
typedef struct FcSubstStack {
|
||||
FcTest *test;
|
||||
FcEdit *edit;
|
||||
} FcSubstStack;
|
||||
|
||||
static void
|
||||
FcParseMatch (FcConfigParse *parse)
|
||||
{
|
||||
const FcChar8 *kind_name;
|
||||
FcMatchKind kind;
|
||||
FcTest *test = 0;
|
||||
FcEdit *edit = 0;
|
||||
FcVStack *vstack;
|
||||
FcBool tested = FcFalse;
|
||||
FcSubstStack *sstack = NULL;
|
||||
int len, pos = 0, i;
|
||||
FcRule *rule = NULL, *r;
|
||||
|
||||
kind_name = FcConfigGetAttribute (parse, "target");
|
||||
if (!kind_name)
|
||||
|
@ -2448,55 +2471,29 @@ FcParseMatch (FcConfigParse *parse)
|
|||
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)))
|
||||
{
|
||||
switch ((int) vstack->tag) {
|
||||
case FcVStackTest:
|
||||
vstack->u.test->next = test;
|
||||
test = vstack->u.test;
|
||||
r = FcRuleCreate (FcRuleTest, vstack->u.test);
|
||||
if (rule)
|
||||
r->next = rule;
|
||||
rule = r;
|
||||
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;
|
||||
case FcVStackEdit:
|
||||
/* due to the reverse traversal, <edit> node appears faster than
|
||||
* <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)
|
||||
if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
|
||||
{
|
||||
FcConfigMessage (parse, FcSevereError,
|
||||
"<match target=\"scan\"> cannot edit user-defined object \"%s\"",
|
||||
FcObjectName(edit->object));
|
||||
break;
|
||||
}
|
||||
r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
|
||||
if (rule)
|
||||
r->next = rule;
|
||||
rule = r;
|
||||
vstack->tag = FcVStackNone;
|
||||
break;
|
||||
default:
|
||||
FcConfigMessage (parse, FcSevereWarning, "invalid match element");
|
||||
|
@ -2504,22 +2501,8 @@ FcParseMatch (FcConfigParse *parse)
|
|||
}
|
||||
FcVStackPopAndDestroy (parse);
|
||||
}
|
||||
if (!FcConfigAddEdit (parse->config, test, edit, kind))
|
||||
if (!FcConfigAddRule (parse->config, rule, kind))
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue