Chromium Code Reviews| 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 "sky/engine/core/dom/Document.h" | 32 #include "sky/engine/core/dom/Document.h" |
| 33 #include "sky/engine/core/dom/shadow/ShadowRoot.h" | 33 #include "sky/engine/core/dom/shadow/ShadowRoot.h" |
| 34 #include "sky/engine/core/editing/FrameSelection.h" | 34 #include "sky/engine/core/editing/FrameSelection.h" |
| 35 #include "sky/engine/core/frame/LocalFrame.h" | 35 #include "sky/engine/core/frame/LocalFrame.h" |
| 36 #include "sky/engine/core/html/parser/HTMLParserIdioms.h" | 36 #include "sky/engine/core/html/parser/HTMLParserIdioms.h" |
| 37 #include "sky/engine/core/page/FocusController.h" | 37 #include "sky/engine/core/page/FocusController.h" |
| 38 #include "sky/engine/core/rendering/style/RenderStyle.h" | 38 #include "sky/engine/core/rendering/style/RenderStyle.h" |
| 39 | 39 |
| 40 namespace blink { | 40 namespace blink { |
| 41 | 41 |
| 42 SelectorChecker::SelectorChecker(Document& document, Mode mode) | 42 SelectorChecker::SelectorChecker() |
| 43 : m_mode(mode) | 43 : m_matchedAttributeSelector(false) |
| 44 , m_matchedFocusSelector(false) | |
| 45 , m_matchedHoverSelector(false) | |
| 46 , m_matchedActiveSelector(false) | |
| 44 { | 47 { |
| 45 } | 48 } |
| 46 | 49 |
| 47 static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheck ingContext& context) | 50 static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheck ingContext& context) |
| 48 { | 51 { |
| 49 if (!context.scope) | 52 if (!context.scope) |
| 50 return true; | 53 return true; |
| 51 | 54 |
| 52 ASSERT(context.scope); | 55 ASSERT(context.scope); |
| 53 if (context.scope->treeScope() == context.element->treeScope()) | 56 if (context.scope->treeScope() == context.element->treeScope()) |
| 54 return true; | 57 return true; |
| 55 | 58 |
| 56 // Because Blink treats a shadow host's TreeScope as a separate one from its descendent shadow roots, | 59 // Because Blink treats a shadow host's TreeScope as a separate one from its descendent shadow roots, |
| 57 // if the last matched element is a shadow host, the condition above isn't m et, even though it | 60 // if the last matched element is a shadow host, the condition above isn't m et, even though it |
| 58 // should be. | 61 // should be. |
| 59 return context.element == context.scope->shadowHost(); | 62 return context.element == context.scope->shadowHost(); |
| 60 } | 63 } |
| 61 | 64 |
| 62 bool SelectorChecker::match(const SelectorCheckingContext& context) const | 65 bool SelectorChecker::match(const SelectorCheckingContext& context) |
| 63 { | 66 { |
| 64 // FIXME(sky): Get rid of SelectorCheckingContext. | 67 // FIXME(sky): Get rid of SelectorCheckingContext. |
| 65 SelectorCheckingContext matchContext(context); | 68 SelectorCheckingContext matchContext(context); |
| 66 | 69 |
| 67 bool isShadowHost = isHostInItsShadowTree(*context.element, context.scope); | 70 bool isShadowHost = isHostInItsShadowTree(*context.element, context.scope); |
| 68 | 71 |
| 69 while (true) { | 72 while (true) { |
| 70 const CSSSelector& selector = *matchContext.selector; | 73 const CSSSelector& selector = *matchContext.selector; |
| 71 // Only :host and :host-context() should match the host: | 74 // Only :host and :host-context() should match the host: |
| 72 // http://drafts.csswg.org/css-scoping/#host-element | 75 // http://drafts.csswg.org/css-scoping/#host-element |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 if (value.length() != selectorValue.length() && value[selectorValue.leng th()] != '-') | 156 if (value.length() != selectorValue.length() && value[selectorValue.leng th()] != '-') |
| 154 return false; | 157 return false; |
| 155 break; | 158 break; |
| 156 default: | 159 default: |
| 157 break; | 160 break; |
| 158 } | 161 } |
| 159 | 162 |
| 160 return true; | 163 return true; |
| 161 } | 164 } |
| 162 | 165 |
| 163 static bool anyAttributeMatches(Element& element, CSSSelector::Match match, cons t CSSSelector& selector) | 166 static bool anyAttributeMatches(const Element& element, CSSSelector::Match match , const CSSSelector& selector) |
| 164 { | 167 { |
| 165 const QualifiedName& selectorAttr = selector.attribute(); | 168 const QualifiedName& selectorAttr = selector.attribute(); |
| 166 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar. | 169 ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar. |
| 167 | 170 |
| 168 // Synchronize the attribute in case it is lazy-computed. | 171 // Synchronize the attribute in case it is lazy-computed. |
| 169 element.synchronizeAttribute(selectorAttr.localName()); | 172 element.synchronizeAttribute(selectorAttr.localName()); |
| 170 | 173 |
| 171 const AtomicString& selectorValue = selector.value(); | 174 const AtomicString& selectorValue = selector.value(); |
| 172 bool caseInsensitive = selector.attributeMatchType() == CSSSelector::CaseIns ensitive; | 175 bool caseInsensitive = selector.attributeMatchType() == CSSSelector::CaseIns ensitive; |
| 173 | 176 |
| 174 AttributeCollection attributes = element.attributesWithoutUpdate(); | 177 AttributeCollection attributes = element.attributesWithoutUpdate(); |
| 175 AttributeCollection::iterator end = attributes.end(); | 178 AttributeCollection::iterator end = attributes.end(); |
| 176 for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { | 179 for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { |
| 177 const Attribute& attributeItem = *it; | 180 const Attribute& attributeItem = *it; |
| 178 | 181 |
| 179 if (!attributeItem.matches(selectorAttr)) | 182 if (!attributeItem.matches(selectorAttr)) |
| 180 continue; | 183 continue; |
| 181 | 184 |
| 182 if (attributeValueMatches(attributeItem, match, selectorValue, !caseInse nsitive)) | 185 if (attributeValueMatches(attributeItem, match, selectorValue, !caseInse nsitive)) |
| 183 return true; | 186 return true; |
| 184 } | 187 } |
| 185 | 188 |
| 186 return false; | 189 return false; |
| 187 } | 190 } |
| 188 | 191 |
| 189 bool SelectorChecker::checkOne(const SelectorCheckingContext& context) const | 192 bool SelectorChecker::checkOne(const SelectorCheckingContext& context) |
| 190 { | 193 { |
| 191 ASSERT(context.element); | 194 ASSERT(context.element); |
| 192 Element& element = *context.element; | 195 const Element& element = *context.element; |
| 193 ASSERT(context.selector); | 196 ASSERT(context.selector); |
| 194 const CSSSelector& selector = *context.selector; | 197 const CSSSelector& selector = *context.selector; |
| 195 | 198 |
| 196 switch (selector.match()) { | 199 switch (selector.match()) { |
| 197 case CSSSelector::Tag: | 200 case CSSSelector::Tag: |
| 198 return tagMatches(element, selector.tagQName()); | 201 return tagMatches(element, selector.tagQName()); |
| 199 case CSSSelector::Class: | 202 case CSSSelector::Class: |
| 200 return element.hasClass() && element.classNames().contains(selector.valu e()); | 203 return element.hasClass() && element.classNames().contains(selector.valu e()); |
| 201 case CSSSelector::Id: | 204 case CSSSelector::Id: |
| 202 return element.hasID() && element.idForStyleResolution() == selector.val ue(); | 205 return element.hasID() && element.idForStyleResolution() == selector.val ue(); |
| 203 case CSSSelector::Exact: | 206 case CSSSelector::Exact: |
| 204 case CSSSelector::Set: | 207 case CSSSelector::Set: |
| 205 case CSSSelector::Hyphen: | 208 case CSSSelector::Hyphen: |
| 206 case CSSSelector::List: | 209 case CSSSelector::List: |
| 207 case CSSSelector::Contain: | 210 case CSSSelector::Contain: |
| 208 case CSSSelector::Begin: | 211 case CSSSelector::Begin: |
| 209 case CSSSelector::End: | 212 case CSSSelector::End: |
| 210 if (anyAttributeMatches(element, selector.match(), selector)) { | 213 if (anyAttributeMatches(element, selector.match(), selector)) { |
| 211 if (m_mode == ResolvingStyle && context.elementStyle) | 214 m_matchedAttributeSelector = true; |
| 212 context.elementStyle->setUnique(); | |
| 213 return true; | 215 return true; |
| 214 } | 216 } |
| 215 return false; | 217 return false; |
| 216 case CSSSelector::PseudoClass: | 218 case CSSSelector::PseudoClass: |
| 217 return checkPseudoClass(context); | 219 return checkPseudoClass(context); |
| 218 // FIXME(sky): Remove pseudo elements completely. | 220 // FIXME(sky): Remove pseudo elements completely. |
| 219 case CSSSelector::PseudoElement: | 221 case CSSSelector::PseudoElement: |
| 220 case CSSSelector::Unknown: | 222 case CSSSelector::Unknown: |
| 221 return false; | 223 return false; |
| 222 } | 224 } |
| 223 ASSERT_NOT_REACHED(); | 225 ASSERT_NOT_REACHED(); |
| 224 return false; | 226 return false; |
| 225 } | 227 } |
| 226 | 228 |
| 227 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context) c onst | 229 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context) |
| 228 { | 230 { |
| 229 ASSERT(context.element); | 231 ASSERT(context.element); |
| 230 Element& element = *context.element; | 232 const Element& element = *context.element; |
| 231 ASSERT(context.selector); | 233 ASSERT(context.selector); |
| 232 const CSSSelector& selector = *context.selector; | 234 const CSSSelector& selector = *context.selector; |
| 233 ASSERT(selector.match() == CSSSelector::PseudoClass); | 235 ASSERT(selector.match() == CSSSelector::PseudoClass); |
| 234 | 236 |
| 235 // Normal element pseudo class checking. | 237 // Normal element pseudo class checking. |
| 236 switch (selector.pseudoType()) { | 238 switch (selector.pseudoType()) { |
| 237 case CSSSelector::PseudoFocus: | 239 case CSSSelector::PseudoFocus: |
| 238 if (m_mode == ResolvingStyle) { | 240 m_matchedFocusSelector = true; |
| 239 if (context.elementStyle) | |
| 240 context.elementStyle->setAffectedByFocus(); | |
| 241 } | |
| 242 return matchesFocusPseudoClass(element); | 241 return matchesFocusPseudoClass(element); |
| 243 | 242 |
| 244 case CSSSelector::PseudoHover: | 243 case CSSSelector::PseudoHover: |
| 245 if (m_mode == ResolvingStyle) { | 244 m_matchedHoverSelector = true; |
| 246 if (context.elementStyle) | |
| 247 context.elementStyle->setAffectedByHover(); | |
| 248 } | |
| 249 return element.hovered(); | 245 return element.hovered(); |
| 250 | 246 |
| 251 case CSSSelector::PseudoActive: | 247 case CSSSelector::PseudoActive: |
| 252 if (m_mode == ResolvingStyle) { | 248 m_matchedActiveSelector = true; |
| 253 if (context.elementStyle) | |
| 254 context.elementStyle->setAffectedByActive(); | |
| 255 } | |
| 256 return element.active(); | 249 return element.active(); |
| 257 | 250 |
| 258 case CSSSelector::PseudoLang: | 251 case CSSSelector::PseudoLang: |
| 259 { | 252 { |
| 260 AtomicString value = element.computeInheritedLanguage(); | 253 AtomicString value = element.computeInheritedLanguage(); |
| 261 const AtomicString& argument = selector.argument(); | 254 const AtomicString& argument = selector.argument(); |
| 262 if (value.isEmpty() || !value.startsWith(argument, false)) | 255 if (value.isEmpty() || !value.startsWith(argument, false)) |
| 263 break; | 256 break; |
| 264 if (value.length() != argument.length() && value[argument.length()] != '-') | 257 if (value.length() != argument.length() && value[argument.length()] != '-') |
| 265 break; | 258 break; |
| 266 return true; | 259 return true; |
| 267 } | 260 } |
| 268 | 261 |
| 269 case CSSSelector::PseudoUnresolved: | 262 case CSSSelector::PseudoUnresolved: |
| 270 return element.isUnresolvedCustomElement(); | 263 return element.isUnresolvedCustomElement(); |
| 271 | 264 |
| 272 case CSSSelector::PseudoHost: | 265 case CSSSelector::PseudoHost: |
| 273 { | 266 { |
| 274 if (m_mode == SharingRules) | |
|
eseidel1
2015/01/09 02:04:17
Do we care about removal of this early-out?
| |
| 275 return true; | |
| 276 // :host only matches a shadow host when :host is in a shadow tree o f the shadow host. | 267 // :host only matches a shadow host when :host is in a shadow tree o f the shadow host. |
| 277 if (!context.scope) | 268 if (!context.scope) |
| 278 return false; | 269 return false; |
| 279 const ContainerNode* shadowHost = context.scope->shadowHost(); | 270 const ContainerNode* shadowHost = context.scope->shadowHost(); |
| 280 if (!shadowHost || shadowHost != element) | 271 if (!shadowHost || shadowHost != element) |
| 281 return false; | 272 return false; |
| 282 ASSERT(element.shadow()); | 273 ASSERT(element.shadow()); |
| 283 | 274 |
| 284 // For empty parameter case, i.e. just :host or :host(). | 275 // For empty parameter case, i.e. just :host or :host(). |
| 285 if (!selector.selectorList()) | 276 if (!selector.selectorList()) |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 313 return false; | 304 return false; |
| 314 LocalFrame* frame = element.document().frame(); | 305 LocalFrame* frame = element.document().frame(); |
| 315 if (!frame) | 306 if (!frame) |
| 316 return false; | 307 return false; |
| 317 if (!frame->selection().isFocusedAndActive()) | 308 if (!frame->selection().isFocusedAndActive()) |
| 318 return false; | 309 return false; |
| 319 return true; | 310 return true; |
| 320 } | 311 } |
| 321 | 312 |
| 322 } | 313 } |
| OLD | NEW |