summaryrefslogtreecommitdiff
path: root/src/css.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/css.cc')
-rw-r--r--src/css.cc141
1 files changed, 72 insertions, 69 deletions
diff --git a/src/css.cc b/src/css.cc
index d4dc72ad..4938a1cf 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -1,7 +1,7 @@
/*
* File: css.cc
*
- * Copyright 2008-2009 Johannes Hofmann <Johannes.Hofmann@gmx.de>
+ * Copyright 2008-2014 Johannes Hofmann <Johannes.Hofmann@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -108,33 +108,31 @@ CssSelector::CssSelector () {
struct CombinatorAndSelector *cs;
refCount = 0;
- selectorList = new lout::misc::SimpleVector
- <struct CombinatorAndSelector> (1);
- selectorList->increase ();
- cs = selectorList->getRef (selectorList->size () - 1);
+ matchCacheOffset = -1;
+ selectorList.increase ();
+ cs = selectorList.getRef (selectorList.size () - 1);
- cs->notMatchingBefore = -1;
cs->combinator = COMB_NONE;
cs->selector = new CssSimpleSelector ();
}
CssSelector::~CssSelector () {
- for (int i = selectorList->size () - 1; i >= 0; i--)
- delete selectorList->getRef (i)->selector;
- delete selectorList;
+ for (int i = selectorList.size () - 1; i >= 0; i--)
+ delete selectorList.getRef (i)->selector;
}
/**
* \brief Return whether selector matches at a given node in the document tree.
*/
bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
- int i, Combinator comb) {
+ int i, Combinator comb, MatchCache *matchCache) {
+ int *matchCacheEntry;
assert (node);
if (i < 0)
return true;
- struct CombinatorAndSelector *cs = selectorList->getRef (i);
+ struct CombinatorAndSelector *cs = selectorList.getRef (i);
CssSimpleSelector *sel = cs->selector;
switch (comb) {
@@ -148,14 +146,16 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
break;
case COMB_DESCENDANT:
node = docTree->parent (node);
+ matchCacheEntry = matchCache->getRef(matchCacheOffset + i);
for (const DoctreeNode *n = node;
- n && n->num > cs->notMatchingBefore; n = docTree->parent (n))
- if (sel->match (n) && match (docTree, n, i - 1, cs->combinator))
+ n && n->num > *matchCacheEntry; n = docTree->parent (n))
+ if (sel->match (n) &&
+ match (docTree, n, i - 1, cs->combinator, matchCache))
return true;
if (node) // remember that it didn't match to avoid future tests
- cs->notMatchingBefore = node->num;
+ *matchCacheEntry = node->num;
return false;
break;
@@ -167,23 +167,23 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
return false;
// tail recursion should be optimized by the compiler
- return match (docTree, node, i - 1, cs->combinator);
+ return match (docTree, node, i - 1, cs->combinator, matchCache);
}
void CssSelector::addSimpleSelector (Combinator c) {
struct CombinatorAndSelector *cs;
- selectorList->increase ();
- cs = selectorList->getRef (selectorList->size () - 1);
+ assert (matchCacheOffset == -1);
+ selectorList.increase ();
+ cs = selectorList.getRef (selectorList.size () - 1);
cs->combinator = c;
- cs->notMatchingBefore = -1;
cs->selector = new CssSimpleSelector ();
}
bool CssSelector::checksPseudoClass () {
- for (int i = 0; i < selectorList->size (); i++)
- if (selectorList->getRef (i)->selector->getPseudoClass ())
+ for (int i = 0; i < selectorList.size (); i++)
+ if (selectorList.getRef (i)->selector->getPseudoClass ())
return true;
return false;
}
@@ -197,18 +197,18 @@ bool CssSelector::checksPseudoClass () {
int CssSelector::specificity () {
int spec = 0;
- for (int i = 0; i < selectorList->size (); i++)
- spec += selectorList->getRef (i)->selector->specificity ();
+ for (int i = 0; i < selectorList.size (); i++)
+ spec += selectorList.getRef (i)->selector->specificity ();
return spec;
}
void CssSelector::print () {
- for (int i = 0; i < selectorList->size (); i++) {
- selectorList->getRef (i)->selector->print ();
+ for (int i = 0; i < selectorList.size (); i++) {
+ selectorList.getRef (i)->selector->print ();
- if (i < selectorList->size () - 1) {
- switch (selectorList->getRef (i + 1)->combinator) {
+ if (i < selectorList.size () - 1) {
+ switch (selectorList.getRef (i + 1)->combinator) {
case COMB_CHILD:
fprintf (stderr, "> ");
break;
@@ -230,17 +230,13 @@ void CssSelector::print () {
CssSimpleSelector::CssSimpleSelector () {
element = ELEMENT_ANY;
- klass = NULL;
id = NULL;
pseudo = NULL;
}
CssSimpleSelector::~CssSimpleSelector () {
- if (klass) {
- for (int i = 0; i < klass->size (); i++)
- dFree (klass->get (i));
- delete klass;
- }
+ for (int i = 0; i < klass.size (); i++)
+ dFree (klass.get (i));
dFree (id);
dFree (pseudo);
}
@@ -248,10 +244,8 @@ CssSimpleSelector::~CssSimpleSelector () {
void CssSimpleSelector::setSelect (SelectType t, const char *v) {
switch (t) {
case SELECT_CLASS:
- if (klass == NULL)
- klass = new lout::misc::SimpleVector <char *> (1);
- klass->increase ();
- klass->set (klass->size () - 1, dStrdup (v));
+ klass.increase ();
+ klass.set (klass.size () - 1, dStrdup (v));
break;
case SELECT_PSEUDO_CLASS:
if (pseudo == NULL)
@@ -279,20 +273,18 @@ bool CssSimpleSelector::match (const DoctreeNode *n) {
return false;
if (id != NULL && (n->id == NULL || dStrAsciiCasecmp (id, n->id) != 0))
return false;
- if (klass != NULL) {
- for (int i = 0; i < klass->size (); i++) {
- bool found = false;
- if (n->klass != NULL) {
- for (int j = 0; j < n->klass->size (); j++) {
- if (dStrAsciiCasecmp (klass->get(i), n->klass->get(j)) == 0) {
- found = true;
- break;
- }
+ for (int i = 0; i < klass.size (); i++) {
+ bool found = false;
+ if (n->klass != NULL) {
+ for (int j = 0; j < n->klass->size (); j++) {
+ if (dStrAsciiCasecmp (klass.get(i), n->klass->get(j)) == 0) {
+ found = true;
+ break;
}
}
- if (! found)
- return false;
}
+ if (! found)
+ return false;
}
return true;
@@ -308,8 +300,7 @@ int CssSimpleSelector::specificity () {
if (id)
spec += 1 << 20;
- if (klass)
- spec += klass->size() << 10;
+ spec += klass.size() << 10;
if (pseudo)
spec += 1 << 10;
if (element != ELEMENT_ANY)
@@ -321,11 +312,9 @@ int CssSimpleSelector::specificity () {
void CssSimpleSelector::print () {
fprintf (stderr, "Element %d, pseudo %s, id %s ",
element, pseudo, id);
- if (klass != NULL) {
- fprintf (stderr, "class ");
- for (int i = 0; i < klass->size (); i++)
- fprintf (stderr, ".%s", klass->get (i));
- }
+ fprintf (stderr, "class ");
+ for (int i = 0; i < klass.size (); i++)
+ fprintf (stderr, ".%s", klass.get (i));
}
CssRule::CssRule (CssSelector *selector, CssPropertyList *props, int pos) {
@@ -344,9 +333,9 @@ CssRule::~CssRule () {
props->unref ();
}
-void CssRule::apply (CssPropertyList *props,
- Doctree *docTree, const DoctreeNode *node) {
- if (selector->match (docTree, node))
+void CssRule::apply (CssPropertyList *props, Doctree *docTree,
+ const DoctreeNode *node, MatchCache *matchCache) const {
+ if (selector->match (docTree, node, matchCache))
this->props->apply (props);
}
@@ -410,6 +399,8 @@ void CssStyleSheet::addRule (CssRule *rule) {
}
if (ruleList) {
+ rule->selector->setMatchCacheOffset (matchCacheOffset);
+ matchCacheOffset += rule->selector->size ();
ruleList->insert (rule);
} else {
assert (top->getElement () == CssSimpleSelector::ELEMENT_NONE);
@@ -423,10 +414,10 @@ void CssStyleSheet::addRule (CssRule *rule) {
* The properties are set as defined by the rules in the stylesheet that
* match at the given node in the document tree.
*/
-void CssStyleSheet::apply (CssPropertyList *props,
- Doctree *docTree, const DoctreeNode *node) {
+void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree,
+ const DoctreeNode *node, MatchCache *matchCache) const {
static const int maxLists = 32;
- RuleList *ruleList[maxLists];
+ const RuleList *ruleList[maxLists];
int numLists = 0, index[maxLists] = {0};
if (node->id) {
@@ -470,7 +461,7 @@ void CssStyleSheet::apply (CssPropertyList *props,
int minSpecIndex = -1;
for (int i = 0; i < numLists; i++) {
- RuleList *rl = ruleList[i];
+ const RuleList *rl = ruleList[i];
if (rl && rl->size () > index[i] &&
(rl->get(index[i])->specificity () < minSpec ||
@@ -484,8 +475,8 @@ void CssStyleSheet::apply (CssPropertyList *props,
}
if (minSpecIndex >= 0) {
- ruleList[minSpecIndex]->get (index[minSpecIndex])->apply
- (props, docTree, node);
+ CssRule *rule = ruleList[minSpecIndex]->get (index[minSpecIndex]);
+ rule->apply(props, docTree, node, matchCache);
index[minSpecIndex]++;
} else {
break;
@@ -493,8 +484,11 @@ void CssStyleSheet::apply (CssPropertyList *props,
}
}
+CssStyleSheet CssContext::userAgentSheet;
+
CssContext::CssContext () {
pos = 0;
+ matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1);
}
/**
@@ -511,23 +505,28 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree,
CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant,
CssPropertyList *nonCssHints) {
- sheet[CSS_PRIMARY_USER_AGENT].apply (props, docTree, node);
- sheet[CSS_PRIMARY_USER].apply (props, docTree, node);
+ userAgentSheet.apply (props, docTree, node,
+ &matchCache[CSS_PRIMARY_USER_AGENT]);
+ sheet[CSS_PRIMARY_USER].apply (props, docTree, node,
+ &matchCache[CSS_PRIMARY_USER]);
if (nonCssHints)
nonCssHints->apply (props);
- sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node);
+ sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node,
+ &matchCache[CSS_PRIMARY_AUTHOR]);
if (tagStyle)
tagStyle->apply (props);
- sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node);
+ sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node,
+ &matchCache[CSS_PRIMARY_AUTHOR_IMPORTANT]);
if (tagStyleImportant)
tagStyleImportant->apply (props);
- sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node);
+ sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node,
+ &matchCache[CSS_PRIMARY_USER_IMPORTANT]);
}
void CssContext::addRule (CssSelector *sel, CssPropertyList *props,
@@ -541,8 +540,12 @@ void CssContext::addRule (CssSelector *sel, CssPropertyList *props,
!rule->isSafe ()) {
MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n");
delete rule;
- } else {
+ } else if (order == CSS_PRIMARY_USER_AGENT) {
+ userAgentSheet.addRule (rule);
+ matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1);
+ } else {
sheet[order].addRule (rule);
+ matchCache[order].setSize (sheet[order].matchCacheOffset, -1);
}
}
}