| 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 21 matching lines...) Expand all Loading... |
| 32 #include "HTMLNames.h" | 32 #include "HTMLNames.h" |
| 33 #include "core/dom/Element.h" | 33 #include "core/dom/Element.h" |
| 34 #include "core/html/HTMLDocument.h" | 34 #include "core/html/HTMLDocument.h" |
| 35 | 35 |
| 36 namespace WebCore { | 36 namespace WebCore { |
| 37 | 37 |
| 38 using namespace HTMLNames; | 38 using namespace HTMLNames; |
| 39 | 39 |
| 40 namespace { | 40 namespace { |
| 41 | 41 |
| 42 template <bool checkValue(const Element&, const CSSSelector*)> | 42 template <bool checkValue(const Element&, const CSSSelector&)> |
| 43 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*
& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOr
SubselectorMatchElement) | 43 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*
& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOr
SubselectorMatchElement) |
| 44 { | 44 { |
| 45 for (; element; element = element->parentElement()) { | 45 for (; element; element = element->parentElement()) { |
| 46 if (checkValue(*element, selector)) { | 46 if (checkValue(*element, *selector)) { |
| 47 if (selector->relation() == CSSSelector::Descendant) | 47 if (selector->relation() == CSSSelector::Descendant) |
| 48 topChildOrSubselector = 0; | 48 topChildOrSubselector = 0; |
| 49 else if (!topChildOrSubselector) { | 49 else if (!topChildOrSubselector) { |
| 50 ASSERT(selector->relation() == CSSSelector::Child || selector->r
elation() == CSSSelector::SubSelector); | 50 ASSERT(selector->relation() == CSSSelector::Child || selector->r
elation() == CSSSelector::SubSelector); |
| 51 topChildOrSubselector = selector; | 51 topChildOrSubselector = selector; |
| 52 topChildOrSubselectorMatchElement = element; | 52 topChildOrSubselectorMatchElement = element; |
| 53 } | 53 } |
| 54 if (selector->relation() != CSSSelector::SubSelector) | 54 if (selector->relation() != CSSSelector::SubSelector) |
| 55 element = element->parentElement(); | 55 element = element->parentElement(); |
| 56 selector = selector->tagHistory(); | 56 selector = selector->tagHistory(); |
| 57 return true; | 57 return true; |
| 58 } | 58 } |
| 59 if (topChildOrSubselector) { | 59 if (topChildOrSubselector) { |
| 60 // Child or subselector check failed. | 60 // Child or subselector check failed. |
| 61 // If the match element is null, topChildOrSubselector was also the
very topmost selector and had to match | 61 // If the match element is null, topChildOrSubselector was also the
very topmost selector and had to match |
| 62 // the original element we were checking. | 62 // the original element we were checking. |
| 63 if (!topChildOrSubselectorMatchElement) | 63 if (!topChildOrSubselectorMatchElement) |
| 64 return false; | 64 return false; |
| 65 // There may be other matches down the ancestor chain. | 65 // There may be other matches down the ancestor chain. |
| 66 // Rewind to the topmost child or subselector and the element it mat
ched, continue checking ancestors. | 66 // Rewind to the topmost child or subselector and the element it mat
ched, continue checking ancestors. |
| 67 selector = topChildOrSubselector; | 67 selector = topChildOrSubselector; |
| 68 element = topChildOrSubselectorMatchElement->parentElement(); | 68 element = topChildOrSubselectorMatchElement->parentElement(); |
| 69 topChildOrSubselector = 0; | 69 topChildOrSubselector = 0; |
| 70 return true; | 70 return true; |
| 71 } | 71 } |
| 72 } | 72 } |
| 73 return false; | 73 return false; |
| 74 } | 74 } |
| 75 | 75 |
| 76 inline bool checkClassValue(const Element& element, const CSSSelector* selector) | 76 inline bool checkClassValue(const Element& element, const CSSSelector& selector) |
| 77 { | 77 { |
| 78 return element.hasClass() && element.classNames().contains(selector->value()
); | 78 return element.hasClass() && element.classNames().contains(selector.value())
; |
| 79 } | 79 } |
| 80 | 80 |
| 81 inline bool checkIDValue(const Element& element, const CSSSelector* selector) | 81 inline bool checkIDValue(const Element& element, const CSSSelector& selector) |
| 82 { | 82 { |
| 83 return element.hasID() && element.idForStyleResolution() == selector->value(
); | 83 return element.hasID() && element.idForStyleResolution() == selector.value()
; |
| 84 } | 84 } |
| 85 | 85 |
| 86 inline bool checkExactAttributeValue(const Element& element, const CSSSelector*
selector) | 86 inline bool checkExactAttributeValue(const Element& element, const CSSSelector&
selector) |
| 87 { | 87 { |
| 88 return SelectorChecker::checkExactAttribute(element, selector->attribute(),
selector->value().impl()); | 88 return SelectorChecker::checkExactAttribute(element, selector.attribute(), s
elector.value().impl()); |
| 89 } | 89 } |
| 90 | 90 |
| 91 inline bool checkTagValue(const Element& element, const CSSSelector* selector) | 91 inline bool checkTagValue(const Element& element, const CSSSelector& selector) |
| 92 { | 92 { |
| 93 return SelectorChecker::tagMatches(element, selector->tagQName()); | 93 return SelectorChecker::tagMatches(element, selector.tagQName()); |
| 94 } | 94 } |
| 95 | 95 |
| 96 } | 96 } |
| 97 | 97 |
| 98 SelectorCheckerFastPath::SelectorCheckerFastPath(const CSSSelector* selector, co
nst Element& element) | 98 SelectorCheckerFastPath::SelectorCheckerFastPath(const CSSSelector& selector, co
nst Element& element) |
| 99 : m_selector(selector) | 99 : m_selector(selector) |
| 100 , m_element(element) | 100 , m_element(element) |
| 101 { | 101 { |
| 102 } | 102 } |
| 103 | 103 |
| 104 bool SelectorCheckerFastPath::matchesRightmostSelector(SelectorChecker::VisitedM
atchType visitedMatchType) const | 104 bool SelectorCheckerFastPath::matchesRightmostSelector(SelectorChecker::VisitedM
atchType visitedMatchType) const |
| 105 { | 105 { |
| 106 ASSERT(SelectorCheckerFastPath::canUse(m_selector)); | 106 ASSERT(SelectorCheckerFastPath::canUse(m_selector)); |
| 107 | 107 |
| 108 switch (m_selector->m_match) { | 108 switch (m_selector.m_match) { |
| 109 case CSSSelector::Tag: | 109 case CSSSelector::Tag: |
| 110 return checkTagValue(m_element, m_selector); | 110 return checkTagValue(m_element, m_selector); |
| 111 case CSSSelector::Class: | 111 case CSSSelector::Class: |
| 112 return checkClassValue(m_element, m_selector); | 112 return checkClassValue(m_element, m_selector); |
| 113 case CSSSelector::Id: | 113 case CSSSelector::Id: |
| 114 return checkIDValue(m_element, m_selector); | 114 return checkIDValue(m_element, m_selector); |
| 115 case CSSSelector::Exact: | 115 case CSSSelector::Exact: |
| 116 case CSSSelector::Set: | 116 case CSSSelector::Set: |
| 117 return checkExactAttributeValue(m_element, m_selector); | 117 return checkExactAttributeValue(m_element, m_selector); |
| 118 case CSSSelector::PseudoClass: | 118 case CSSSelector::PseudoClass: |
| 119 return commonPseudoClassSelectorMatches(visitedMatchType); | 119 return commonPseudoClassSelectorMatches(visitedMatchType); |
| 120 default: | 120 default: |
| 121 ASSERT_NOT_REACHED(); | 121 ASSERT_NOT_REACHED(); |
| 122 } | 122 } |
| 123 return false; | 123 return false; |
| 124 } | 124 } |
| 125 | 125 |
| 126 bool SelectorCheckerFastPath::matches() const | 126 bool SelectorCheckerFastPath::matches() const |
| 127 { | 127 { |
| 128 ASSERT(matchesRightmostSelector(SelectorChecker::VisitedMatchEnabled)); | 128 ASSERT(matchesRightmostSelector(SelectorChecker::VisitedMatchEnabled)); |
| 129 const CSSSelector* selector = m_selector; | 129 const CSSSelector* selector = &m_selector; |
| 130 const Element* element = &m_element; | 130 const Element* element = &m_element; |
| 131 | 131 |
| 132 const CSSSelector* topChildOrSubselector = 0; | 132 const CSSSelector* topChildOrSubselector = 0; |
| 133 const Element* topChildOrSubselectorMatchElement = 0; | 133 const Element* topChildOrSubselectorMatchElement = 0; |
| 134 if (selector->relation() == CSSSelector::Child || selector->relation() == CS
SSelector::SubSelector) | 134 if (selector->relation() == CSSSelector::Child || selector->relation() == CS
SSelector::SubSelector) |
| 135 topChildOrSubselector = selector; | 135 topChildOrSubselector = selector; |
| 136 | 136 |
| 137 if (selector->relation() != CSSSelector::SubSelector) | 137 if (selector->relation() != CSSSelector::SubSelector) |
| 138 element = element->parentElement(); | 138 element = element->parentElement(); |
| 139 | 139 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 164 } | 164 } |
| 165 } | 165 } |
| 166 return true; | 166 return true; |
| 167 } | 167 } |
| 168 | 168 |
| 169 static inline bool isFastCheckableRelation(CSSSelector::Relation relation) | 169 static inline bool isFastCheckableRelation(CSSSelector::Relation relation) |
| 170 { | 170 { |
| 171 return relation == CSSSelector::Descendant || relation == CSSSelector::Child
|| relation == CSSSelector::SubSelector; | 171 return relation == CSSSelector::Descendant || relation == CSSSelector::Child
|| relation == CSSSelector::SubSelector; |
| 172 } | 172 } |
| 173 | 173 |
| 174 static inline bool isFastCheckableMatch(const CSSSelector* selector) | 174 static inline bool isFastCheckableMatch(const CSSSelector& selector) |
| 175 { | 175 { |
| 176 if (selector->m_match == CSSSelector::Set) { | 176 if (selector.m_match == CSSSelector::Set) { |
| 177 // Style attribute is generated lazily but the fast path doesn't trigger
it. | 177 // Style attribute is generated lazily but the fast path doesn't trigger
it. |
| 178 // Disallow them here rather than making the fast path more branchy. | 178 // Disallow them here rather than making the fast path more branchy. |
| 179 return selector->attribute() != styleAttr; | 179 return selector.attribute() != styleAttr; |
| 180 } | 180 } |
| 181 if (selector->m_match == CSSSelector::Exact) | 181 if (selector.m_match == CSSSelector::Exact) |
| 182 return selector->attribute() != styleAttr && HTMLDocument::isCaseSensiti
veAttribute(selector->attribute()); | 182 return selector.attribute() != styleAttr && HTMLDocument::isCaseSensitiv
eAttribute(selector.attribute()); |
| 183 return selector->m_match == CSSSelector::Tag || selector->m_match == CSSSele
ctor::Id || selector->m_match == CSSSelector::Class; | 183 return selector.m_match == CSSSelector::Tag || selector.m_match == CSSSelect
or::Id || selector.m_match == CSSSelector::Class; |
| 184 } | 184 } |
| 185 | 185 |
| 186 static inline bool isFastCheckableRightmostSelector(const CSSSelector* selector) | 186 static inline bool isFastCheckableRightmostSelector(const CSSSelector& selector) |
| 187 { | 187 { |
| 188 if (!isFastCheckableRelation(selector->relation())) | 188 if (!isFastCheckableRelation(selector.relation())) |
| 189 return false; | 189 return false; |
| 190 return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClas
sSelector(selector); | 190 return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClas
sSelector(selector); |
| 191 } | 191 } |
| 192 | 192 |
| 193 bool SelectorCheckerFastPath::canUse(const CSSSelector* selector) | 193 bool SelectorCheckerFastPath::canUse(const CSSSelector& selector) |
| 194 { | 194 { |
| 195 if (!isFastCheckableRightmostSelector(selector)) | 195 if (!isFastCheckableRightmostSelector(selector)) |
| 196 return false; | 196 return false; |
| 197 for (selector = selector->tagHistory(); selector; selector = selector->tagHi
story()) { | 197 for (const CSSSelector* current = selector.tagHistory(); current; current =
current->tagHistory()) { |
| 198 if (!isFastCheckableRelation(selector->relation())) | 198 if (!isFastCheckableRelation(current->relation())) |
| 199 return false; | 199 return false; |
| 200 if (!isFastCheckableMatch(selector)) | 200 if (!isFastCheckableMatch(*current)) |
| 201 return false; | 201 return false; |
| 202 } | 202 } |
| 203 return true; | 203 return true; |
| 204 } | 204 } |
| 205 | 205 |
| 206 bool SelectorCheckerFastPath::commonPseudoClassSelectorMatches(SelectorChecker::
VisitedMatchType visitedMatchType) const | 206 bool SelectorCheckerFastPath::commonPseudoClassSelectorMatches(SelectorChecker::
VisitedMatchType visitedMatchType) const |
| 207 { | 207 { |
| 208 ASSERT(SelectorChecker::isCommonPseudoClassSelector(m_selector)); | 208 ASSERT(SelectorChecker::isCommonPseudoClassSelector(m_selector)); |
| 209 switch (m_selector->pseudoType()) { | 209 switch (m_selector.pseudoType()) { |
| 210 case CSSSelector::PseudoLink: | 210 case CSSSelector::PseudoLink: |
| 211 case CSSSelector::PseudoAnyLink: | 211 case CSSSelector::PseudoAnyLink: |
| 212 return m_element.isLink(); | 212 return m_element.isLink(); |
| 213 case CSSSelector::PseudoVisited: | 213 case CSSSelector::PseudoVisited: |
| 214 return m_element.isLink() && visitedMatchType == SelectorChecker::Visite
dMatchEnabled; | 214 return m_element.isLink() && visitedMatchType == SelectorChecker::Visite
dMatchEnabled; |
| 215 case CSSSelector::PseudoFocus: | 215 case CSSSelector::PseudoFocus: |
| 216 return SelectorChecker::matchesFocusPseudoClass(m_element); | 216 return SelectorChecker::matchesFocusPseudoClass(m_element); |
| 217 default: | 217 default: |
| 218 ASSERT_NOT_REACHED(); | 218 ASSERT_NOT_REACHED(); |
| 219 } | 219 } |
| 220 return true; | 220 return true; |
| 221 } | 221 } |
| 222 | 222 |
| 223 | 223 |
| 224 } | 224 } |
| OLD | NEW |