Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / SelectorChecker.cpp
index 663de6f..3a00ae5 100644 (file)
@@ -32,6 +32,7 @@
 #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"
@@ -64,13 +65,13 @@ SelectorChecker::SelectorChecker(Document& document, Mode mode)
 {
 }
 
-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;
@@ -133,7 +134,7 @@ SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& con
 
     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())
@@ -265,7 +266,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
             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;
@@ -277,10 +278,10 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
             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;
@@ -467,33 +468,34 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
 {
     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
@@ -509,12 +511,12 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
             // (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.
@@ -546,7 +548,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
         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();
@@ -559,7 +561,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
         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;
@@ -568,7 +570,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
         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();
@@ -585,13 +587,13 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                     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();
@@ -613,14 +615,14 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                 }
                 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);
@@ -629,37 +631,37 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                     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)
@@ -667,8 +669,8 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                 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;
@@ -680,8 +682,8 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
             {
                 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;
                 }
@@ -719,7 +721,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
         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();
@@ -733,7 +735,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
         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();
@@ -799,7 +801,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                     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()] != '-')
@@ -860,7 +862,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                 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);
@@ -870,7 +872,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                 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.
@@ -887,7 +889,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
                         subContext.behaviorAtBoundary = DoesNotCrossBoundary;
                         subContext.scope = 0;
 
-                        if (selector->pseudoType() == CSSSelector::PseudoHost)
+                        if (selector.pseudoType() == CSSSelector::PseudoHost)
                             break;
 
                         nextElement = NodeRenderingTraversal::parentElement(nextElement);
@@ -920,14 +922,14 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
             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;
         }
@@ -937,21 +939,21 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
     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:
@@ -1018,19 +1020,19 @@ bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& c
     }
 }
 
-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;
@@ -1049,7 +1051,7 @@ unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector)
             // 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)