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)
{
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");

View File

@ -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");
}

View File

@ -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,

View File

@ -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