Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (96516 => 96517)
--- trunk/Source/WebCore/css/SelectorChecker.cpp 2011-10-03 17:37:05 UTC (rev 96516)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp 2011-10-03 17:40:18 UTC (rev 96517)
@@ -63,6 +63,8 @@
namespace WebCore {
using namespace HTMLNames;
+
+static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr);
SelectorChecker::SelectorChecker(Document* document, bool strictParsing)
: m_document(document)
@@ -261,12 +263,13 @@
namespace {
-template <bool checkValue(const Element*, AtomicStringImpl*)>
+template <bool checkValue(const Element*, AtomicStringImpl*, const QualifiedName&), bool initAttributeName>
inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
{
AtomicStringImpl* value = selector->value().impl();
+ const QualifiedName& attribute = initAttributeName ? selector->attribute() : anyQName();
for (; element; element = element->parentElement()) {
- if (checkValue(element, value) && SelectorChecker::tagMatches(element, selector)) {
+ if (checkValue(element, value, attribute) && SelectorChecker::tagMatches(element, selector)) {
if (selector->relation() == CSSSelector::Descendant)
topChildOrSubselector = 0;
else if (!topChildOrSubselector) {
@@ -296,18 +299,23 @@
return false;
}
-inline bool checkClassValue(const Element* element, AtomicStringImpl* value)
+inline bool checkClassValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
{
return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value);
}
-inline bool checkIDValue(const Element* element, AtomicStringImpl* value)
+inline bool checkIDValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
{
return element->hasID() && element->idForStyleResolution().impl() == value;
}
-inline bool checkTagValue(const Element*, AtomicStringImpl*)
+inline bool checkExactAttributeValue(const Element* element, AtomicStringImpl* value, const QualifiedName& attributeName)
{
+ return SelectorChecker::checkExactAttribute(element, attributeName, value);
+}
+
+inline bool checkTagValue(const Element*, AtomicStringImpl*, const QualifiedName&)
+{
return true;
}
@@ -323,9 +331,12 @@
case CSSSelector::None:
return true;
case CSSSelector::Class:
- return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(selector->value());
+ return checkClassValue(element, selector->value().impl(), anyQName());
case CSSSelector::Id:
- return element->hasID() && element->idForStyleResolution() == selector->value();
+ return checkIDValue(element, selector->value().impl(), anyQName());
+ case CSSSelector::Exact:
+ case CSSSelector::Set:
+ return checkExactAttributeValue(element, selector->value().impl(), selector->attribute());
case CSSSelector::PseudoClass:
return commonPseudoClassSelectorMatches(element, selector);
default:
@@ -352,17 +363,22 @@
while (selector) {
switch (selector->m_match) {
case CSSSelector::Class:
- if (!fastCheckSingleSelector<checkClassValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
+ if (!fastCheckSingleSelector<checkClassValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
case CSSSelector::Id:
- if (!fastCheckSingleSelector<checkIDValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
+ if (!fastCheckSingleSelector<checkIDValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
case CSSSelector::None:
- if (!fastCheckSingleSelector<checkTagValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
+ if (!fastCheckSingleSelector<checkTagValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
+ case CSSSelector::Set:
+ case CSSSelector::Exact:
+ if (!fastCheckSingleSelector<checkExactAttributeValue, true>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
+ return false;
+ break;
default:
ASSERT_NOT_REACHED();
}
@@ -375,16 +391,20 @@
return relation == CSSSelector::Descendant || relation == CSSSelector::Child || relation == CSSSelector::SubSelector;
}
-static inline bool isFastCheckableMatch(CSSSelector::Match match)
+static inline bool isFastCheckableMatch(const CSSSelector* selector)
{
- return match == CSSSelector::None || match == CSSSelector::Id || match == CSSSelector::Class;
+ if (selector->m_match == CSSSelector::Set)
+ return true;
+ if (selector->m_match == CSSSelector::Exact)
+ return !htmlAttributeHasCaseInsensitiveValue(selector->attribute());
+ return selector->m_match == CSSSelector::None || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class;
}
static inline bool isFastCheckableRightmostSelector(const CSSSelector* selector)
{
if (!isFastCheckableRelation(selector->relation()))
return false;
- return isFastCheckableMatch(static_cast<CSSSelector::Match>(selector->m_match)) || SelectorChecker::isCommonPseudoClassSelector(selector);
+ return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClassSelector(selector);
}
bool SelectorChecker::isFastCheckableSelector(const CSSSelector* selector)
@@ -394,7 +414,7 @@
for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
if (!isFastCheckableRelation(selector->relation()))
return false;
- if (!isFastCheckableMatch(static_cast<CSSSelector::Match>(selector->m_match)))
+ if (!isFastCheckableMatch(selector))
return false;
}
return true;
@@ -578,21 +598,13 @@
return attrSet;
}
-static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
+bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
{
static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
}
-static bool attributeQualifiedNameMatches(Attribute* attribute, const QualifiedName& selectorAttr)
-{
- if (selectorAttr.localName() != attribute->localName())
- return false;
-
- return selectorAttr.prefix() == starAtom || selectorAttr.namespaceURI() == attribute->namespaceURI();
-}
-
static bool attributeValueMatches(Attribute* attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
{
const AtomicString& value = attributeItem->value();
@@ -661,7 +673,7 @@
for (size_t i = 0; i < attributes->length(); ++i) {
Attribute* attributeItem = attributes->attributeItem(i);
- if (!attributeQualifiedNameMatches(attributeItem, selectorAttr))
+ if (!SelectorChecker::attributeNameMatches(attributeItem, selectorAttr))
continue;
if (attributeValueMatches(attributeItem, match, selectorValue, caseSensitive))
@@ -677,13 +689,13 @@
if (!SelectorChecker::tagMatches(e, sel))
return false;
- if (sel->hasAttribute()) {
- if (sel->m_match == CSSSelector::Class)
- return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());
-
- if (sel->m_match == CSSSelector::Id)
- return e->hasID() && e->idForStyleResolution() == sel->value();
-
+ if (sel->m_match == CSSSelector::Class)
+ return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());
+
+ if (sel->m_match == CSSSelector::Id)
+ return e->hasID() && e->idForStyleResolution() == sel->value();
+
+ if (sel->isAttributeSelector()) {
const QualifiedName& attr = sel->attribute();
NamedNodeMap* attributes = e->attributes(true);
Modified: trunk/Source/WebCore/css/SelectorChecker.h (96516 => 96517)
--- trunk/Source/WebCore/css/SelectorChecker.h 2011-10-03 17:37:05 UTC (rev 96516)
+++ trunk/Source/WebCore/css/SelectorChecker.h 2011-10-03 17:40:18 UTC (rev 96517)
@@ -28,6 +28,7 @@
#ifndef SelectorChecker_h
#define SelectorChecker_h
+#include "Attribute.h"
#include "CSSSelector.h"
#include "Element.h"
#include "InspectorInstrumentation.h"
@@ -83,10 +84,13 @@
void clearHasUnknownPseudoElements() { m_hasUnknownPseudoElements = false; }
static bool tagMatches(const Element*, const CSSSelector*);
+ static bool attributeNameMatches(const Attribute*, const QualifiedName&);
static bool isCommonPseudoClassSelector(const CSSSelector*);
bool commonPseudoClassSelectorMatches(const Element*, const CSSSelector*) const;
bool linkMatchesVisitedPseudoClass(const Element*) const;
bool matchesFocusPseudoClass(const Element*) const;
+ static bool fastCheckRightmostAttributeSelector(const Element*, const CSSSelector*);
+ static bool checkExactAttribute(const Element*, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value);
private:
bool checkOneSelector(CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle*, RenderStyle* elementParentStyle) const;
@@ -174,6 +178,35 @@
const AtomicString& namespaceURI = selector->tag().namespaceURI();
return namespaceURI == starAtom || namespaceURI == element->namespaceURI();
}
+
+inline bool SelectorChecker::attributeNameMatches(const Attribute* attribute, const QualifiedName& selectorAttributeName)
+{
+ if (selectorAttributeName.localName() != attribute->localName())
+ return false;
+ return selectorAttributeName.prefix() == starAtom || selectorAttributeName.namespaceURI() == attribute->namespaceURI();
+}
+
+inline bool SelectorChecker::checkExactAttribute(const Element* element, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value)
+{
+ NamedNodeMap* attributeMap = element->attributeMap();
+ if (!attributeMap)
+ return false;
+ unsigned size = attributeMap->length();
+ for (unsigned i = 0; i < size; ++i) {
+ Attribute* attribute = attributeMap->attributeItem(i);
+ if (attributeNameMatches(attribute, selectorAttributeName) && (!value || attribute->value().impl() == value))
+ return true;
+ }
+ return false;
+}
+
+inline bool SelectorChecker::fastCheckRightmostAttributeSelector(const Element* element, const CSSSelector* selector)
+{
+ if (selector->m_match == CSSSelector::Exact || selector->m_match == CSSSelector::Set)
+ return checkExactAttribute(element, selector->attribute(), selector->value().impl());
+ ASSERT(!selector->isAttributeSelector());
+ return true;
+}
}