#include "core/css/CSSSelectorList.h"
#include "core/css/SiblingTraversalStrategies.h"
#include "core/dom/Document.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/NodeRenderStyle.h"
#include "core/dom/Text.h"
{
}
-static bool matchesCustomPseudoElement(const Element* element, const CSSSelector* selector)
+static bool matchesCustomPseudoElement(const Element* element, const CSSSelector& selector)
{
ShadowRoot* root = element->containingShadowRoot();
if (!root || root->type() != ShadowRoot::UserAgentShadowRoot)
return false;
- if (element->shadowPseudoId() != selector->value())
+ if (element->shadowPseudoId() != selector.value())
return false;
return true;
if (context.selector->m_match == CSSSelector::PseudoElement) {
if (context.selector->isCustomPseudoElement()) {
- if (!matchesCustomPseudoElement(context.element, context.selector))
+ if (!matchesCustomPseudoElement(context.element, *context.selector))
return SelectorFailsLocally;
} else if (context.selector->isContentPseudoElement()) {
if (!context.element->isInShadowTree() || !context.element->isInsertionPoint())
if (Element* parent = parentElement(context))
parent->setChildrenAffectedByDirectAdjacentRules();
}
- nextContext.element = context.element->previousElementSibling();
+ nextContext.element = ElementTraversal::previousSibling(*context.element);
if (!nextContext.element)
return SelectorFailsAllSiblings;
nextContext.isSubSelector = false;
if (Element* parent = parentElement(context))
parent->setChildrenAffectedByForwardPositionalRules();
}
- nextContext.element = context.element->previousElementSibling();
+ nextContext.element = ElementTraversal::previousSibling(*context.element);
nextContext.isSubSelector = false;
nextContext.elementStyle = 0;
- for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) {
+ for (; nextContext.element; nextContext.element = ElementTraversal::previousSibling(*nextContext.element)) {
Match match = this->match(nextContext, siblingTraversalStrategy, result);
if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
return match;
{
ASSERT(context.element);
Element& element = *context.element;
- const CSSSelector* const & selector = context.selector;
- ASSERT(selector);
+ ASSERT(context.selector);
+ const CSSSelector& selector = *context.selector;
+
bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.behaviorAtBoundary, context.scope);
- if (selector->m_match == CSSSelector::Tag)
- return SelectorChecker::tagMatches(element, selector->tagQName(), elementIsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement);
+ if (selector.m_match == CSSSelector::Tag)
+ return SelectorChecker::tagMatches(element, selector.tagQName(), elementIsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement);
- if (selector->m_match == CSSSelector::Class)
- return element.hasClass() && element.classNames().contains(selector->value()) && !elementIsHostInItsShadowTree;
+ if (selector.m_match == CSSSelector::Class)
+ return element.hasClass() && element.classNames().contains(selector.value()) && !elementIsHostInItsShadowTree;
- if (selector->m_match == CSSSelector::Id)
- return element.hasID() && element.idForStyleResolution() == selector->value() && !elementIsHostInItsShadowTree;
+ if (selector.m_match == CSSSelector::Id)
+ return element.hasID() && element.idForStyleResolution() == selector.value() && !elementIsHostInItsShadowTree;
- if (selector->isAttributeSelector()) {
+ if (selector.isAttributeSelector()) {
if (elementIsHostInItsShadowTree)
return false;
- if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector->m_match), *selector))
+ if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector.m_match), selector))
return false;
}
- if (selector->m_match == CSSSelector::PseudoClass) {
+ if (selector.m_match == CSSSelector::PseudoClass) {
// Handle :not up front.
- if (selector->pseudoType() == CSSSelector::PseudoNot) {
+ if (selector.pseudoType() == CSSSelector::PseudoNot) {
SelectorCheckingContext subContext(context);
subContext.isSubSelector = true;
- ASSERT(selector->selectorList());
- for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) {
+ ASSERT(selector.selectorList());
+ for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) {
// :not cannot nest. I don't really know why this is a
// restriction in CSS3, but it is, so let's honor it.
// the parser enforces that this never occurs
// (since there are no elements involved).
return checkScrollbarPseudoClass(context, &element.document(), selector);
} else if (context.hasSelectionPseudo) {
- if (selector->pseudoType() == CSSSelector::PseudoWindowInactive)
+ if (selector.pseudoType() == CSSSelector::PseudoWindowInactive)
return !element.document().page()->focusController().isActive();
}
// Normal element pseudo class checking.
- switch (selector->pseudoType()) {
+ switch (selector.pseudoType()) {
// Pseudo classes:
case CSSSelector::PseudoNot:
break; // Already handled up above.
case CSSSelector::PseudoFirstChild:
// first-child matches the first child that is an element
if (Element* parent = element.parentElement()) {
- bool result = siblingTraversalStrategy.isFirstChild(&element);
+ bool result = siblingTraversalStrategy.isFirstChild(element);
if (m_mode == ResolvingStyle) {
RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
parent->setChildrenAffectedByFirstChildRules();
case CSSSelector::PseudoFirstOfType:
// first-of-type matches the first element of its type
if (Element* parent = element.parentElement()) {
- bool result = siblingTraversalStrategy.isFirstOfType(&element, element.tagQName());
+ bool result = siblingTraversalStrategy.isFirstOfType(element, element.tagQName());
if (m_mode == ResolvingStyle)
parent->setChildrenAffectedByForwardPositionalRules();
return result;
case CSSSelector::PseudoLastChild:
// last-child matches the last child that is an element
if (Element* parent = element.parentElement()) {
- bool result = parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(&element);
+ bool result = parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(element);
if (m_mode == ResolvingStyle) {
RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
parent->setChildrenAffectedByLastChildRules();
parent->setChildrenAffectedByBackwardPositionalRules();
if (!parent->isFinishedParsingChildren())
return false;
- return siblingTraversalStrategy.isLastOfType(&element, element.tagQName());
+ return siblingTraversalStrategy.isLastOfType(element, element.tagQName());
}
break;
case CSSSelector::PseudoOnlyChild:
if (Element* parent = element.parentElement()) {
- bool firstChild = siblingTraversalStrategy.isFirstChild(&element);
- bool onlyChild = firstChild && parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(&element);
+ bool firstChild = siblingTraversalStrategy.isFirstChild(element);
+ bool onlyChild = firstChild && parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(element);
if (m_mode == ResolvingStyle) {
RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
parent->setChildrenAffectedByFirstChildRules();
}
if (!parent->isFinishedParsingChildren())
return false;
- return siblingTraversalStrategy.isFirstOfType(&element, element.tagQName()) && siblingTraversalStrategy.isLastOfType(&element, element.tagQName());
+ return siblingTraversalStrategy.isFirstOfType(element, element.tagQName()) && siblingTraversalStrategy.isLastOfType(element, element.tagQName());
}
break;
case CSSSelector::PseudoNthChild:
- if (!selector->parseNth())
+ if (!selector.parseNth())
break;
if (Element* parent = element.parentElement()) {
- int count = 1 + siblingTraversalStrategy.countElementsBefore(&element);
+ int count = 1 + siblingTraversalStrategy.countElementsBefore(element);
if (m_mode == ResolvingStyle) {
RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
element.setChildIndex(count);
parent->setChildrenAffectedByForwardPositionalRules();
}
- if (selector->matchNth(count))
+ if (selector.matchNth(count))
return true;
}
break;
case CSSSelector::PseudoNthOfType:
- if (!selector->parseNth())
+ if (!selector.parseNth())
break;
if (Element* parent = element.parentElement()) {
- int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefore(&element, element.tagQName());
+ int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefore(element, element.tagQName());
if (m_mode == ResolvingStyle)
parent->setChildrenAffectedByForwardPositionalRules();
- if (selector->matchNth(count))
+ if (selector.matchNth(count))
return true;
}
break;
case CSSSelector::PseudoNthLastChild:
- if (!selector->parseNth())
+ if (!selector.parseNth())
break;
if (Element* parent = element.parentElement()) {
if (m_mode == ResolvingStyle)
parent->setChildrenAffectedByBackwardPositionalRules();
if (!parent->isFinishedParsingChildren())
return false;
- int count = 1 + siblingTraversalStrategy.countElementsAfter(&element);
- if (selector->matchNth(count))
+ int count = 1 + siblingTraversalStrategy.countElementsAfter(element);
+ if (selector.matchNth(count))
return true;
}
break;
case CSSSelector::PseudoNthLastOfType:
- if (!selector->parseNth())
+ if (!selector.parseNth())
break;
if (Element* parent = element.parentElement()) {
if (m_mode == ResolvingStyle)
if (!parent->isFinishedParsingChildren())
return false;
- int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfter(&element, element.tagQName());
- if (selector->matchNth(count))
+ int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfter(element, element.tagQName());
+ if (selector.matchNth(count))
return true;
}
break;
{
SelectorCheckingContext subContext(context);
subContext.isSubSelector = true;
- ASSERT(selector->selectorList());
- for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
+ ASSERT(selector.selectorList());
+ for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
if (match(subContext, siblingTraversalStrategy) == SelectorMatches)
return true;
}
case CSSSelector::PseudoHover:
// If we're in quirks mode, then hover should never match anchors with no
// href and *:hover should not match anything. This is important for sites like wsj.com.
- if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !element.hasTagName(aTag)) || element.isLink()) {
+ if (m_strictParsing || context.isSubSelector || (selector.m_match == CSSSelector::Tag && selector.tagQName() != anyQName() && !element.hasTagName(aTag)) || element.isLink()) {
if (m_mode == ResolvingStyle) {
if (context.elementStyle)
context.elementStyle->setAffectedByHover();
case CSSSelector::PseudoActive:
// If we're in quirks mode, then :active should never match anchors with no
// href and *:active should not match anything.
- if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !element.hasTagName(aTag)) || element.isLink()) {
+ if (m_strictParsing || context.isSubSelector || (selector.m_match == CSSSelector::Tag && selector.tagQName() != anyQName() && !element.hasTagName(aTag)) || element.isLink()) {
if (m_mode == ResolvingStyle) {
if (context.elementStyle)
context.elementStyle->setAffectedByActive();
value = toVTTElement(element).language();
else
value = element.computeInheritedLanguage();
- const AtomicString& argument = selector->argument();
+ const AtomicString& argument = selector.argument();
if (value.isEmpty() || !value.startsWith(argument, false))
break;
if (value.length() != argument.length() && value[argument.length()] != '-')
ASSERT(element.shadow());
// For empty parameter case, i.e. just :host or :host().
- if (!selector->selectorList()) // Use *'s specificity. So just 0.
+ if (!selector.selectorList()) // Use *'s specificity. So just 0.
return true;
SelectorCheckingContext subContext(context);
unsigned maxSpecificity = 0;
// If one of simple selectors matches an element, returns SelectorMatches. Just "OR".
- for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
+ for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHostParameter;
subContext.scope = context.scope;
// Use NodeRenderingTraversal to traverse a composed ancestor list of a given element.
subContext.behaviorAtBoundary = DoesNotCrossBoundary;
subContext.scope = 0;
- if (selector->pseudoType() == CSSSelector::PseudoHost)
+ if (selector.pseudoType() == CSSSelector::PseudoHost)
break;
nextElement = NodeRenderingTraversal::parentElement(nextElement);
break;
}
return false;
- }
- else if (selector->m_match == CSSSelector::PseudoElement && selector->pseudoType() == CSSSelector::PseudoCue) {
+ } else if (selector.m_match == CSSSelector::PseudoElement && selector.pseudoType() == CSSSelector::PseudoCue) {
SelectorCheckingContext subContext(context);
subContext.isSubSelector = true;
subContext.behaviorAtBoundary = StaysWithinTreeScope;
- const CSSSelector* const & selector = context.selector;
- for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
+ const CSSSelector* contextSelector = context.selector;
+ ASSERT(contextSelector);
+ for (subContext.selector = contextSelector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
if (match(subContext, siblingTraversalStrategy) == SelectorMatches)
return true;
}
return true;
}
-bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& context, Document* document, const CSSSelector* selector) const
+bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& context, Document* document, const CSSSelector& selector) const
{
RenderScrollbar* scrollbar = context.scrollbar;
ScrollbarPart part = context.scrollbarPart;
// FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
// pseudo class and just apply to everything.
- if (selector->pseudoType() == CSSSelector::PseudoWindowInactive)
+ if (selector.pseudoType() == CSSSelector::PseudoWindowInactive)
return !document->page()->focusController().isActive();
if (!scrollbar)
return false;
- ASSERT(selector->m_match == CSSSelector::PseudoClass);
- switch (selector->pseudoType()) {
+ ASSERT(selector.m_match == CSSSelector::PseudoClass);
+ switch (selector.pseudoType()) {
case CSSSelector::PseudoEnabled:
return scrollbar->enabled();
case CSSSelector::PseudoDisabled:
}
}
-unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector)
+unsigned SelectorChecker::determineLinkMatchType(const CSSSelector& selector)
{
unsigned linkMatchType = MatchAll;
// Statically determine if this selector will match a link in visited, unvisited or any state, or never.
// :visited never matches other elements than the innermost link element.
- for (; selector; selector = selector->tagHistory()) {
- switch (selector->pseudoType()) {
+ for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
+ switch (current->pseudoType()) {
case CSSSelector::PseudoNot:
{
// :not(:visited) is equivalent to :link. Parser enforces that :not can't nest.
- ASSERT(selector->selectorList());
- for (const CSSSelector* subSelector = selector->selectorList()->first(); subSelector; subSelector = subSelector->tagHistory()) {
+ ASSERT(current->selectorList());
+ for (const CSSSelector* subSelector = current->selectorList()->first(); subSelector; subSelector = subSelector->tagHistory()) {
CSSSelector::PseudoType subType = subSelector->pseudoType();
if (subType == CSSSelector::PseudoVisited)
linkMatchType &= ~SelectorChecker::MatchVisited;
// We don't support :link and :visited inside :-webkit-any.
break;
}
- CSSSelector::Relation relation = selector->relation();
+ CSSSelector::Relation relation = current->relation();
if (relation == CSSSelector::SubSelector)
continue;
if (relation != CSSSelector::Descendant && relation != CSSSelector::Child)