| 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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 scope->treeScope() == m_element.treeScope() || | 79 scope->treeScope() == m_element.treeScope() || |
| 80 m_element == scope->shadowHost(); | 80 m_element == scope->shadowHost(); |
| 81 } | 81 } |
| 82 current = current->tagHistory(); | 82 current = current->tagHistory(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 ASSERT_NOT_REACHED(); | 85 ASSERT_NOT_REACHED(); |
| 86 return false; | 86 return false; |
| 87 } | 87 } |
| 88 | 88 |
| 89 template<typename CharType> | |
| 90 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le
ngth) | |
| 91 { | |
| 92 for (unsigned i = 0; i < length; ++i) | |
| 93 if (isHTMLSpace<CharType>(string[i])) | |
| 94 return true; | |
| 95 return false; | |
| 96 } | |
| 97 | |
| 98 static inline bool containsHTMLSpace(const AtomicString& string) | |
| 99 { | |
| 100 if (LIKELY(string.is8Bit())) | |
| 101 return containsHTMLSpaceTemplate<LChar>(string.characters8(), string.len
gth()); | |
| 102 return containsHTMLSpaceTemplate<UChar>(string.characters16(), string.length
()); | |
| 103 } | |
| 104 | |
| 105 static bool attributeValueMatches(const Attribute& attributeItem, CSSSelector::M
atch match, const AtomicString& selectorValue, bool caseSensitive) | |
| 106 { | |
| 107 const AtomicString& value = attributeItem.value(); | |
| 108 if (value.isNull()) | |
| 109 return false; | |
| 110 | |
| 111 switch (match) { | |
| 112 case CSSSelector::Exact: | |
| 113 if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selector
Value, value)) | |
| 114 return false; | |
| 115 break; | |
| 116 case CSSSelector::List: | |
| 117 { | |
| 118 // Ignore empty selectors or selectors containing HTML spaces | |
| 119 if (selectorValue.isEmpty() || containsHTMLSpace(selectorValue)) | |
| 120 return false; | |
| 121 | |
| 122 unsigned startSearchAt = 0; | |
| 123 while (true) { | |
| 124 size_t foundPos = value.find(selectorValue, startSearchAt, caseS
ensitive); | |
| 125 if (foundPos == kNotFound) | |
| 126 return false; | |
| 127 if (!foundPos || isHTMLSpace<UChar>(value[foundPos - 1])) { | |
| 128 unsigned endStr = foundPos + selectorValue.length(); | |
| 129 if (endStr == value.length() || isHTMLSpace<UChar>(value[end
Str])) | |
| 130 break; // We found a match. | |
| 131 } | |
| 132 | |
| 133 // No match. Keep looking. | |
| 134 startSearchAt = foundPos + 1; | |
| 135 } | |
| 136 break; | |
| 137 } | |
| 138 case CSSSelector::Contain: | |
| 139 if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmp
ty()) | |
| 140 return false; | |
| 141 break; | |
| 142 case CSSSelector::Begin: | |
| 143 if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isE
mpty()) | |
| 144 return false; | |
| 145 break; | |
| 146 case CSSSelector::End: | |
| 147 if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmp
ty()) | |
| 148 return false; | |
| 149 break; | |
| 150 case CSSSelector::Hyphen: | |
| 151 if (value.length() < selectorValue.length()) | |
| 152 return false; | |
| 153 if (!value.startsWith(selectorValue, caseSensitive)) | |
| 154 return false; | |
| 155 // It they start the same, check for exact match or following '-': | |
| 156 if (value.length() != selectorValue.length() && value[selectorValue.leng
th()] != '-') | |
| 157 return false; | |
| 158 break; | |
| 159 default: | |
| 160 break; | |
| 161 } | |
| 162 | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 static bool anyAttributeMatches(const Element& element, CSSSelector::Match match
, const CSSSelector& selector) | 89 static bool anyAttributeMatches(const Element& element, CSSSelector::Match match
, const CSSSelector& selector) |
| 167 { | 90 { |
| 168 const QualifiedName& selectorAttr = selector.attribute(); | 91 const QualifiedName& selectorAttr = selector.attribute(); |
| 169 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from
the CSS grammar. | 92 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from
the CSS grammar. |
| 170 | 93 |
| 171 // Synchronize the attribute in case it is lazy-computed. | 94 if (match == CSSSelector::Set) |
| 172 element.synchronizeAttribute(selectorAttr.localName()); | 95 return element.hasAttribute(selectorAttr); |
| 96 |
| 97 ASSERT(match == CSSSelector::Exact); |
| 173 | 98 |
| 174 const AtomicString& selectorValue = selector.value(); | 99 const AtomicString& selectorValue = selector.value(); |
| 175 bool caseInsensitive = selector.attributeMatchType() == CSSSelector::CaseIns
ensitive; | 100 const AtomicString& value = element.getAttribute(selectorAttr); |
| 176 | 101 |
| 177 AttributeCollection attributes = element.attributesWithoutUpdate(); | 102 if (value.isNull()) |
| 178 AttributeCollection::iterator end = attributes.end(); | 103 return false; |
| 179 for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it)
{ | 104 if (selector.attributeMatchType() == CSSSelector::CaseInsensitive) |
| 180 const Attribute& attributeItem = *it; | 105 return equalIgnoringCase(selectorValue, value); |
| 181 | 106 return selectorValue == value; |
| 182 if (!attributeItem.matches(selectorAttr)) | |
| 183 continue; | |
| 184 | |
| 185 if (attributeValueMatches(attributeItem, match, selectorValue, !caseInse
nsitive)) | |
| 186 return true; | |
| 187 } | |
| 188 | |
| 189 return false; | |
| 190 } | 107 } |
| 191 | 108 |
| 192 bool SelectorChecker::checkOne(const CSSSelector& selector, const ContainerNode*
scope) | 109 bool SelectorChecker::checkOne(const CSSSelector& selector, const ContainerNode*
scope) |
| 193 { | 110 { |
| 194 switch (selector.match()) { | 111 switch (selector.match()) { |
| 195 case CSSSelector::Tag: | 112 case CSSSelector::Tag: |
| 196 { | 113 { |
| 197 const AtomicString& localName = selector.tagQName().localName(); | 114 const AtomicString& localName = selector.tagQName().localName(); |
| 198 return localName == starAtom || localName == m_element.localName(); | 115 return localName == starAtom || localName == m_element.localName(); |
| 199 } | 116 } |
| 200 case CSSSelector::Class: | 117 case CSSSelector::Class: |
| 201 return m_element.hasClass() && m_element.classNames().contains(selector.
value()); | 118 return m_element.hasClass() && m_element.classNames().contains(selector.
value()); |
| 202 case CSSSelector::Id: | 119 case CSSSelector::Id: |
| 203 return m_element.hasID() && m_element.idForStyleResolution() == selector
.value(); | 120 return m_element.hasID() && m_element.idForStyleResolution() == selector
.value(); |
| 204 case CSSSelector::Exact: | 121 case CSSSelector::Exact: |
| 205 case CSSSelector::Set: | 122 case CSSSelector::Set: |
| 206 case CSSSelector::Hyphen: | |
| 207 case CSSSelector::List: | |
| 208 case CSSSelector::Contain: | |
| 209 case CSSSelector::Begin: | |
| 210 case CSSSelector::End: | |
| 211 if (anyAttributeMatches(m_element, selector.match(), selector)) { | 123 if (anyAttributeMatches(m_element, selector.match(), selector)) { |
| 212 m_matchedAttributeSelector = true; | 124 m_matchedAttributeSelector = true; |
| 213 return true; | 125 return true; |
| 214 } | 126 } |
| 215 return false; | 127 return false; |
| 216 case CSSSelector::PseudoClass: | 128 case CSSSelector::PseudoClass: |
| 217 return checkPseudoClass(selector, scope); | 129 return checkPseudoClass(selector, scope); |
| 218 // FIXME(sky): Remove pseudo elements completely. | 130 // FIXME(sky): Remove pseudo elements completely. |
| 219 case CSSSelector::PseudoElement: | 131 case CSSSelector::PseudoElement: |
| 220 case CSSSelector::Unknown: | 132 case CSSSelector::Unknown: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 case CSSSelector::PseudoUnknown: | 189 case CSSSelector::PseudoUnknown: |
| 278 case CSSSelector::PseudoNotParsed: | 190 case CSSSelector::PseudoNotParsed: |
| 279 case CSSSelector::PseudoUserAgentCustomElement: | 191 case CSSSelector::PseudoUserAgentCustomElement: |
| 280 return false; | 192 return false; |
| 281 } | 193 } |
| 282 ASSERT_NOT_REACHED(); | 194 ASSERT_NOT_REACHED(); |
| 283 return false; | 195 return false; |
| 284 } | 196 } |
| 285 | 197 |
| 286 } | 198 } |
| OLD | NEW |