| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) | 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
| 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) | 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
| 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
All rights reserved. | 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
All rights reserved. |
| 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
| 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) | 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) |
| 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 | 54 |
| 55 SelectorChecker::SelectorChecker(const Element& element) | 55 SelectorChecker::SelectorChecker(const Element& element) |
| 56 : m_element(element) | 56 : m_element(element) |
| 57 , m_matchedAttributeSelector(false) | 57 , m_matchedAttributeSelector(false) |
| 58 , m_matchedFocusSelector(false) | 58 , m_matchedFocusSelector(false) |
| 59 , m_matchedHoverSelector(false) | 59 , m_matchedHoverSelector(false) |
| 60 , m_matchedActiveSelector(false) | 60 , m_matchedActiveSelector(false) |
| 61 { | 61 { |
| 62 } | 62 } |
| 63 | 63 |
| 64 bool SelectorChecker::match(const CSSSelector& selector, const ContainerNode* sc
ope) | 64 bool SelectorChecker::match(const CSSSelector& selector) |
| 65 { | 65 { |
| 66 bool isShadowHost = isHostInItsShadowTree(m_element, scope); | 66 const CSSSelector* current = &selector; |
| 67 | 67 |
| 68 const CSSSelector* current = &selector; | 68 do { |
| 69 while (true) { | 69 if (!checkOne(*current)) |
| 70 // Only :host should match the host: | |
| 71 // http://drafts.csswg.org/css-scoping/#host-element | |
| 72 if (isShadowHost && !current->isHostPseudoClass()) | |
| 73 return false; | 70 return false; |
| 74 if (!checkOne(*current, scope)) | |
| 75 return false; | |
| 76 if (current->isLastInTagHistory()) { | |
| 77 // Only rules in the same scope, or from :host can match. | |
| 78 return !scope || | |
| 79 scope->treeScope() == m_element.treeScope() || | |
| 80 m_element == scope->shadowHost(); | |
| 81 } | |
| 82 current = current->tagHistory(); | 71 current = current->tagHistory(); |
| 83 } | 72 } while (current); |
| 84 | 73 |
| 85 ASSERT_NOT_REACHED(); | 74 return true; |
| 86 return false; | |
| 87 } | 75 } |
| 88 | 76 |
| 89 static bool anyAttributeMatches(const Element& element, CSSSelector::Match match
, const CSSSelector& selector) | 77 static bool anyAttributeMatches(const Element& element, CSSSelector::Match match
, const CSSSelector& selector) |
| 90 { | 78 { |
| 91 const QualifiedName& selectorAttr = selector.attribute(); | 79 const QualifiedName& selectorAttr = selector.attribute(); |
| 92 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from
the CSS grammar. | 80 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from
the CSS grammar. |
| 93 | 81 |
| 94 if (match == CSSSelector::Set) | 82 if (match == CSSSelector::Set) |
| 95 return element.hasAttribute(selectorAttr); | 83 return element.hasAttribute(selectorAttr); |
| 96 | 84 |
| 97 ASSERT(match == CSSSelector::Exact); | 85 ASSERT(match == CSSSelector::Exact); |
| 98 | 86 |
| 99 const AtomicString& selectorValue = selector.value(); | 87 const AtomicString& selectorValue = selector.value(); |
| 100 const AtomicString& value = element.getAttribute(selectorAttr); | 88 const AtomicString& value = element.getAttribute(selectorAttr); |
| 101 | 89 |
| 102 if (value.isNull()) | 90 if (value.isNull()) |
| 103 return false; | 91 return false; |
| 104 if (selector.attributeMatchType() == CSSSelector::CaseInsensitive) | 92 if (selector.attributeMatchType() == CSSSelector::CaseInsensitive) |
| 105 return equalIgnoringCase(selectorValue, value); | 93 return equalIgnoringCase(selectorValue, value); |
| 106 return selectorValue == value; | 94 return selectorValue == value; |
| 107 } | 95 } |
| 108 | 96 |
| 109 bool SelectorChecker::checkOne(const CSSSelector& selector, const ContainerNode*
scope) | 97 bool SelectorChecker::checkOne(const CSSSelector& selector) |
| 110 { | 98 { |
| 111 switch (selector.match()) { | 99 switch (selector.match()) { |
| 112 case CSSSelector::Tag: | 100 case CSSSelector::Tag: |
| 113 { | 101 { |
| 114 const AtomicString& localName = selector.tagQName().localName(); | 102 const AtomicString& localName = selector.tagQName().localName(); |
| 115 return localName == starAtom || localName == m_element.localName(); | 103 return localName == starAtom || localName == m_element.localName(); |
| 116 } | 104 } |
| 117 case CSSSelector::Class: | 105 case CSSSelector::Class: |
| 118 return m_element.hasClass() && m_element.classNames().contains(selector.
value()); | 106 return m_element.hasClass() && m_element.classNames().contains(selector.
value()); |
| 119 case CSSSelector::Id: | 107 case CSSSelector::Id: |
| 120 return m_element.hasID() && m_element.idForStyleResolution() == selector
.value(); | 108 return m_element.hasID() && m_element.idForStyleResolution() == selector
.value(); |
| 121 case CSSSelector::Exact: | 109 case CSSSelector::Exact: |
| 122 case CSSSelector::Set: | 110 case CSSSelector::Set: |
| 123 if (anyAttributeMatches(m_element, selector.match(), selector)) { | 111 if (anyAttributeMatches(m_element, selector.match(), selector)) { |
| 124 m_matchedAttributeSelector = true; | 112 m_matchedAttributeSelector = true; |
| 125 return true; | 113 return true; |
| 126 } | 114 } |
| 127 return false; | 115 return false; |
| 128 case CSSSelector::PseudoClass: | 116 case CSSSelector::PseudoClass: |
| 129 return checkPseudoClass(selector, scope); | 117 return checkPseudoClass(selector); |
| 130 // FIXME(sky): Remove pseudo elements completely. | 118 // FIXME(sky): Remove pseudo elements completely. |
| 131 case CSSSelector::PseudoElement: | 119 case CSSSelector::PseudoElement: |
| 132 case CSSSelector::Unknown: | 120 case CSSSelector::Unknown: |
| 133 return false; | 121 return false; |
| 134 } | 122 } |
| 135 ASSERT_NOT_REACHED(); | 123 ASSERT_NOT_REACHED(); |
| 136 return false; | 124 return false; |
| 137 } | 125 } |
| 138 | 126 |
| 139 bool SelectorChecker::checkPseudoClass(const CSSSelector& selector, const Contai
nerNode* scope) | 127 bool SelectorChecker::checkPseudoClass(const CSSSelector& selector) |
| 140 { | 128 { |
| 141 switch (selector.pseudoType()) { | 129 switch (selector.pseudoType()) { |
| 142 case CSSSelector::PseudoFocus: | 130 case CSSSelector::PseudoFocus: |
| 143 m_matchedFocusSelector = true; | 131 m_matchedFocusSelector = true; |
| 144 return matchesFocusPseudoClass(m_element); | 132 return matchesFocusPseudoClass(m_element); |
| 145 | 133 |
| 146 case CSSSelector::PseudoHover: | 134 case CSSSelector::PseudoHover: |
| 147 m_matchedHoverSelector = true; | 135 m_matchedHoverSelector = true; |
| 148 return m_element.hovered(); | 136 return m_element.hovered(); |
| 149 | 137 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 160 if (value.length() != argument.length() && value[argument.length()]
!= '-') | 148 if (value.length() != argument.length() && value[argument.length()]
!= '-') |
| 161 break; | 149 break; |
| 162 return true; | 150 return true; |
| 163 } | 151 } |
| 164 | 152 |
| 165 case CSSSelector::PseudoUnresolved: | 153 case CSSSelector::PseudoUnresolved: |
| 166 return m_element.isUnresolvedCustomElement(); | 154 return m_element.isUnresolvedCustomElement(); |
| 167 | 155 |
| 168 case CSSSelector::PseudoHost: | 156 case CSSSelector::PseudoHost: |
| 169 { | 157 { |
| 170 const ContainerNode* shadowHost = scope->shadowHost(); | 158 // We can only get here if the selector was defined in the right |
| 171 if (!shadowHost || shadowHost != m_element) | 159 // scope so we don't need to check it. |
| 172 return false; | |
| 173 | 160 |
| 174 // For empty parameter case, i.e. just :host or :host(). | 161 // For empty parameter case, i.e. just :host or :host(). |
| 175 if (!selector.selectorList()) | 162 if (!selector.selectorList()) |
| 176 return true; | 163 return true; |
| 177 | |
| 178 // Treat the inside of :host() rules as if they were defined in the | |
| 179 // same scope as the host. | |
| 180 const ContainerNode& scope = m_element.treeScope().rootNode(); | |
| 181 | |
| 182 for (const CSSSelector* current = selector.selectorList()->first();
current; current = CSSSelectorList::next(*current)) { | 164 for (const CSSSelector* current = selector.selectorList()->first();
current; current = CSSSelectorList::next(*current)) { |
| 183 if (match(*current, &scope)) | 165 if (match(*current)) |
| 184 return true; | 166 return true; |
| 185 } | 167 } |
| 186 return false; | 168 return false; |
| 187 } | 169 } |
| 188 | 170 |
| 189 case CSSSelector::PseudoUnknown: | 171 case CSSSelector::PseudoUnknown: |
| 190 case CSSSelector::PseudoNotParsed: | 172 case CSSSelector::PseudoNotParsed: |
| 191 case CSSSelector::PseudoUserAgentCustomElement: | 173 case CSSSelector::PseudoUserAgentCustomElement: |
| 192 return false; | 174 return false; |
| 193 } | 175 } |
| 194 ASSERT_NOT_REACHED(); | 176 ASSERT_NOT_REACHED(); |
| 195 return false; | 177 return false; |
| 196 } | 178 } |
| 197 | 179 |
| 198 } | 180 } |
| OLD | NEW |