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. |
| 6 * All rights reserved. |
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 7 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 8 * 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/) | 9 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. |
| 10 * (http://www.torchmobile.com/) |
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 11 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 12 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
11 * | 13 * |
12 * This library is free software; you can redistribute it and/or | 14 * This library is free software; you can redistribute it and/or |
13 * modify it under the terms of the GNU Library General Public | 15 * modify it under the terms of the GNU Library General Public |
14 * License as published by the Free Software Foundation; either | 16 * License as published by the Free Software Foundation; either |
15 * version 2 of the License, or (at your option) any later version. | 17 * version 2 of the License, or (at your option) any later version. |
16 * | 18 * |
17 * This library is distributed in the hope that it will be useful, | 19 * This library is distributed in the hope that it will be useful, |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 if (element.tagQName().localNameUpper() != tagQName.localNameUpper()) | 97 if (element.tagQName().localNameUpper() != tagQName.localNameUpper()) |
96 return false; | 98 return false; |
97 } | 99 } |
98 const AtomicString& namespaceURI = tagQName.namespaceURI(); | 100 const AtomicString& namespaceURI = tagQName.namespaceURI(); |
99 return namespaceURI == starAtom || namespaceURI == element.namespaceURI(); | 101 return namespaceURI == starAtom || namespaceURI == element.namespaceURI(); |
100 } | 102 } |
101 | 103 |
102 static Element* parentElement( | 104 static Element* parentElement( |
103 const SelectorChecker::SelectorCheckingContext& context) { | 105 const SelectorChecker::SelectorCheckingContext& context) { |
104 // - If context.scope is a shadow root, we should walk up to its shadow host. | 106 // - If context.scope is a shadow root, we should walk up to its shadow host. |
105 // - If context.scope is some element in some shadow tree and querySelector in
itialized the context, | 107 // - If context.scope is some element in some shadow tree and querySelector |
106 // e.g. shadowRoot.querySelector(':host *'), | 108 // initialized the context, e.g. shadowRoot.querySelector(':host *'), |
107 // (a) context.element has the same treescope as context.scope, need to walk
up to its shadow host. | 109 // (a) context.element has the same treescope as context.scope, need to walk |
| 110 // up to its shadow host. |
108 // (b) Otherwise, should not walk up from a shadow root to a shadow host. | 111 // (b) Otherwise, should not walk up from a shadow root to a shadow host. |
109 if (context.scope && | 112 if (context.scope && |
110 (context.scope == context.element->containingShadowRoot() || | 113 (context.scope == context.element->containingShadowRoot() || |
111 context.scope->treeScope() == context.element->treeScope())) | 114 context.scope->treeScope() == context.element->treeScope())) |
112 return context.element->parentOrShadowHostElement(); | 115 return context.element->parentOrShadowHostElement(); |
113 return context.element->parentElement(); | 116 return context.element->parentElement(); |
114 } | 117 } |
115 | 118 |
116 static const HTMLSlotElement* findSlotElementInScope( | 119 static const HTMLSlotElement* findSlotElementInScope( |
117 const SelectorChecker::SelectorCheckingContext& context) { | 120 const SelectorChecker::SelectorCheckingContext& context) { |
(...skipping 11 matching lines...) Expand all Loading... |
129 | 132 |
130 static bool scopeContainsLastMatchedElement( | 133 static bool scopeContainsLastMatchedElement( |
131 const SelectorChecker::SelectorCheckingContext& context) { | 134 const SelectorChecker::SelectorCheckingContext& context) { |
132 // If this context isn't scoped, skip checking. | 135 // If this context isn't scoped, skip checking. |
133 if (!context.scope) | 136 if (!context.scope) |
134 return true; | 137 return true; |
135 | 138 |
136 if (context.scope->treeScope() == context.element->treeScope()) | 139 if (context.scope->treeScope() == context.element->treeScope()) |
137 return true; | 140 return true; |
138 | 141 |
139 // Because Blink treats a shadow host's TreeScope as a separate one from its d
escendent shadow roots, | 142 // Because Blink treats a shadow host's TreeScope as a separate one from its |
140 // if the last matched element is a shadow host, the condition above isn't met
, even though it | 143 // descendent shadow roots, if the last matched element is a shadow host, the |
141 // should be. | 144 // condition above isn't met, even though it should be. |
142 return context.element == context.scope->ownerShadowHost() && | 145 return context.element == context.scope->ownerShadowHost() && |
143 (!context.previousElement || | 146 (!context.previousElement || |
144 context.previousElement->isInDescendantTreeOf(context.element)); | 147 context.previousElement->isInDescendantTreeOf(context.element)); |
145 } | 148 } |
146 | 149 |
147 static inline bool nextSelectorExceedsScope( | 150 static inline bool nextSelectorExceedsScope( |
148 const SelectorChecker::SelectorCheckingContext& context) { | 151 const SelectorChecker::SelectorCheckingContext& context) { |
149 if (context.scope && context.scope->isInShadowTree()) | 152 if (context.scope && context.scope->isInShadowTree()) |
150 return context.element == context.scope->ownerShadowHost(); | 153 return context.element == context.scope->ownerShadowHost(); |
151 | 154 |
152 return false; | 155 return false; |
153 } | 156 } |
154 | 157 |
155 static bool shouldMatchHoverOrActive( | 158 static bool shouldMatchHoverOrActive( |
156 const SelectorChecker::SelectorCheckingContext& context) { | 159 const SelectorChecker::SelectorCheckingContext& context) { |
157 // If we're in quirks mode, then :hover and :active should never match anchors
with no | 160 // If we're in quirks mode, then :hover and :active should never match anchors |
158 // href and *:hover and *:active should not match anything. This is specified
in | 161 // with no href and *:hover and *:active should not match anything. This is |
159 // https://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk | 162 // specified in https://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk |
160 if (!context.element->document().inQuirksMode()) | 163 if (!context.element->document().inQuirksMode()) |
161 return true; | 164 return true; |
162 if (context.isSubSelector) | 165 if (context.isSubSelector) |
163 return true; | 166 return true; |
164 if (context.element->isLink()) | 167 if (context.element->isLink()) |
165 return true; | 168 return true; |
166 const CSSSelector* selector = context.selector; | 169 const CSSSelector* selector = context.selector; |
167 while (selector->relation() == CSSSelector::SubSelector && | 170 while (selector->relation() == CSSSelector::SubSelector && |
168 selector->tagHistory()) { | 171 selector->tagHistory()) { |
169 selector = selector->tagHistory(); | 172 selector = selector->tagHistory(); |
(...skipping 20 matching lines...) Expand all Loading... |
190 | 193 |
191 static bool isLastOfType(Element& element, const QualifiedName& type) { | 194 static bool isLastOfType(Element& element, const QualifiedName& type) { |
192 return !ElementTraversal::nextSibling(element, HasTagName(type)); | 195 return !ElementTraversal::nextSibling(element, HasTagName(type)); |
193 } | 196 } |
194 | 197 |
195 // Recursive check of selectors and combinators | 198 // Recursive check of selectors and combinators |
196 // It can return 4 different values: | 199 // It can return 4 different values: |
197 // * SelectorMatches - the selector matches the element e | 200 // * SelectorMatches - the selector matches the element e |
198 // * SelectorFailsLocally - the selector fails for the element e | 201 // * SelectorFailsLocally - the selector fails for the element e |
199 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e | 202 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e |
200 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e | 203 // * SelectorFailsCompletely - the selector fails for e and any sibling or |
| 204 // ancestor of e |
201 SelectorChecker::Match SelectorChecker::matchSelector( | 205 SelectorChecker::Match SelectorChecker::matchSelector( |
202 const SelectorCheckingContext& context, | 206 const SelectorCheckingContext& context, |
203 MatchResult& result) const { | 207 MatchResult& result) const { |
204 MatchResult subResult; | 208 MatchResult subResult; |
205 if (!checkOne(context, subResult)) | 209 if (!checkOne(context, subResult)) |
206 return SelectorFailsLocally; | 210 return SelectorFailsLocally; |
207 | 211 |
208 if (subResult.dynamicPseudo != PseudoIdNone) | 212 if (subResult.dynamicPseudo != PseudoIdNone) |
209 result.dynamicPseudo = subResult.dynamicPseudo; | 213 result.dynamicPseudo = subResult.dynamicPseudo; |
210 | 214 |
(...skipping 21 matching lines...) Expand all Loading... |
232 } | 236 } |
233 if (match == SelectorMatches) | 237 if (match == SelectorMatches) |
234 result.specificity += subResult.specificity; | 238 result.specificity += subResult.specificity; |
235 return match; | 239 return match; |
236 } | 240 } |
237 | 241 |
238 static inline SelectorChecker::SelectorCheckingContext | 242 static inline SelectorChecker::SelectorCheckingContext |
239 prepareNextContextForRelation( | 243 prepareNextContextForRelation( |
240 const SelectorChecker::SelectorCheckingContext& context) { | 244 const SelectorChecker::SelectorCheckingContext& context) { |
241 SelectorChecker::SelectorCheckingContext nextContext(context); | 245 SelectorChecker::SelectorCheckingContext nextContext(context); |
242 ASSERT(context.selector->tagHistory()); | 246 DCHECK(context.selector->tagHistory()); |
243 nextContext.selector = context.selector->tagHistory(); | 247 nextContext.selector = context.selector->tagHistory(); |
244 return nextContext; | 248 return nextContext; |
245 } | 249 } |
246 | 250 |
247 SelectorChecker::Match SelectorChecker::matchForSubSelector( | 251 SelectorChecker::Match SelectorChecker::matchForSubSelector( |
248 const SelectorCheckingContext& context, | 252 const SelectorCheckingContext& context, |
249 MatchResult& result) const { | 253 MatchResult& result) const { |
250 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); | 254 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); |
251 | 255 |
252 PseudoId dynamicPseudo = result.dynamicPseudo; | 256 PseudoId dynamicPseudo = result.dynamicPseudo; |
(...skipping 30 matching lines...) Expand all Loading... |
283 return element.parentOrShadowHostElement(); | 287 return element.parentOrShadowHostElement(); |
284 } | 288 } |
285 | 289 |
286 SelectorChecker::Match SelectorChecker::matchForRelation( | 290 SelectorChecker::Match SelectorChecker::matchForRelation( |
287 const SelectorCheckingContext& context, | 291 const SelectorCheckingContext& context, |
288 MatchResult& result) const { | 292 MatchResult& result) const { |
289 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); | 293 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); |
290 | 294 |
291 CSSSelector::RelationType relation = context.selector->relation(); | 295 CSSSelector::RelationType relation = context.selector->relation(); |
292 | 296 |
293 // Disable :visited matching when we see the first link or try to match anythi
ng else than an ancestors. | 297 // Disable :visited matching when we see the first link or try to match |
| 298 // anything else than an ancestors. |
294 if (!context.isSubSelector && | 299 if (!context.isSubSelector && |
295 (context.element->isLink() || | 300 (context.element->isLink() || |
296 (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) | 301 (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) |
297 nextContext.visitedMatchType = VisitedMatchDisabled; | 302 nextContext.visitedMatchType = VisitedMatchDisabled; |
298 | 303 |
299 nextContext.inRightmostCompound = false; | 304 nextContext.inRightmostCompound = false; |
300 nextContext.isSubSelector = false; | 305 nextContext.isSubSelector = false; |
301 nextContext.previousElement = context.element; | 306 nextContext.previousElement = context.element; |
302 nextContext.pseudoId = PseudoIdNone; | 307 nextContext.pseudoId = PseudoIdNone; |
303 | 308 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 match == SelectorFailsCompletely) | 378 match == SelectorFailsCompletely) |
374 return match; | 379 return match; |
375 } | 380 } |
376 return SelectorFailsAllSiblings; | 381 return SelectorFailsAllSiblings; |
377 | 382 |
378 case CSSSelector::ShadowPseudo: { | 383 case CSSSelector::ShadowPseudo: { |
379 if (!m_isUARule && !m_isQuerySelector && | 384 if (!m_isUARule && !m_isQuerySelector && |
380 context.selector->getPseudoType() == CSSSelector::PseudoShadow) | 385 context.selector->getPseudoType() == CSSSelector::PseudoShadow) |
381 Deprecation::countDeprecation(context.element->document(), | 386 Deprecation::countDeprecation(context.element->document(), |
382 UseCounter::CSSSelectorPseudoShadow); | 387 UseCounter::CSSSelectorPseudoShadow); |
383 // If we're in the same tree-scope as the scoping element, then following
a shadow descendant combinator would escape that and thus the scope. | 388 // If we're in the same tree-scope as the scoping element, then following |
| 389 // a shadow descendant combinator would escape that and thus the scope. |
384 if (context.scope && context.scope->ownerShadowHost() && | 390 if (context.scope && context.scope->ownerShadowHost() && |
385 context.scope->ownerShadowHost()->treeScope() == | 391 context.scope->ownerShadowHost()->treeScope() == |
386 context.element->treeScope()) | 392 context.element->treeScope()) |
387 return SelectorFailsCompletely; | 393 return SelectorFailsCompletely; |
388 | 394 |
389 Element* shadowHost = context.element->ownerShadowHost(); | 395 Element* shadowHost = context.element->ownerShadowHost(); |
390 if (!shadowHost) | 396 if (!shadowHost) |
391 return SelectorFailsCompletely; | 397 return SelectorFailsCompletely; |
392 nextContext.element = shadowHost; | 398 nextContext.element = shadowHost; |
393 return matchSelector(nextContext, result); | 399 return matchSelector(nextContext, result); |
394 } | 400 } |
395 | 401 |
396 case CSSSelector::ShadowDeep: { | 402 case CSSSelector::ShadowDeep: { |
397 if (!m_isUARule && !m_isQuerySelector) | 403 if (!m_isUARule && !m_isQuerySelector) |
398 Deprecation::countDeprecation(context.element->document(), | 404 Deprecation::countDeprecation(context.element->document(), |
399 UseCounter::CSSDeepCombinator); | 405 UseCounter::CSSDeepCombinator); |
400 if (ShadowRoot* root = context.element->containingShadowRoot()) { | 406 if (ShadowRoot* root = context.element->containingShadowRoot()) { |
401 if (root->type() == ShadowRootType::UserAgent) | 407 if (root->type() == ShadowRootType::UserAgent) |
402 return SelectorFailsCompletely; | 408 return SelectorFailsCompletely; |
403 } | 409 } |
404 | 410 |
405 if (context.selector->relationIsAffectedByPseudoContent()) { | 411 if (context.selector->relationIsAffectedByPseudoContent()) { |
406 // TODO(kochi): closed mode tree should be handled as well for ::content
. | 412 // TODO(kochi): closed mode tree should be handled as well for |
| 413 // ::content. |
407 for (Element* element = context.element; element; | 414 for (Element* element = context.element; element; |
408 element = element->parentOrShadowHostElement()) { | 415 element = element->parentOrShadowHostElement()) { |
409 if (matchForPseudoContent(nextContext, *element, result) == | 416 if (matchForPseudoContent(nextContext, *element, result) == |
410 SelectorMatches) { | 417 SelectorMatches) { |
411 if (context.element->isInShadowTree()) | 418 if (context.element->isInShadowTree()) |
412 UseCounter::count(context.element->document(), | 419 UseCounter::count(context.element->document(), |
413 UseCounter::CSSDeepCombinatorAndShadow); | 420 UseCounter::CSSDeepCombinatorAndShadow); |
414 return SelectorMatches; | 421 return SelectorMatches; |
415 } | 422 } |
416 } | 423 } |
(...skipping 21 matching lines...) Expand all Loading... |
438 if (!slot) | 445 if (!slot) |
439 return SelectorFailsCompletely; | 446 return SelectorFailsCompletely; |
440 | 447 |
441 nextContext.element = const_cast<HTMLSlotElement*>(slot); | 448 nextContext.element = const_cast<HTMLSlotElement*>(slot); |
442 return matchSelector(nextContext, result); | 449 return matchSelector(nextContext, result); |
443 } | 450 } |
444 | 451 |
445 case CSSSelector::SubSelector: | 452 case CSSSelector::SubSelector: |
446 break; | 453 break; |
447 } | 454 } |
448 ASSERT_NOT_REACHED(); | 455 NOTREACHED(); |
449 return SelectorFailsCompletely; | 456 return SelectorFailsCompletely; |
450 } | 457 } |
451 | 458 |
452 SelectorChecker::Match SelectorChecker::matchForPseudoContent( | 459 SelectorChecker::Match SelectorChecker::matchForPseudoContent( |
453 const SelectorCheckingContext& context, | 460 const SelectorCheckingContext& context, |
454 const Element& element, | 461 const Element& element, |
455 MatchResult& result) const { | 462 MatchResult& result) const { |
456 HeapVector<Member<InsertionPoint>, 8> insertionPoints; | 463 HeapVector<Member<InsertionPoint>, 8> insertionPoints; |
457 collectDestinationInsertionPoints(element, insertionPoints); | 464 collectDestinationInsertionPoints(element, insertionPoints); |
458 SelectorCheckingContext nextContext(context); | 465 SelectorCheckingContext nextContext(context); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 if (value.length() < selectorValue.length()) | 529 if (value.length() < selectorValue.length()) |
523 return false; | 530 return false; |
524 if (!value.startsWith(selectorValue, caseSensitivity)) | 531 if (!value.startsWith(selectorValue, caseSensitivity)) |
525 return false; | 532 return false; |
526 // It they start the same, check for exact match or following '-': | 533 // It they start the same, check for exact match or following '-': |
527 if (value.length() != selectorValue.length() && | 534 if (value.length() != selectorValue.length() && |
528 value[selectorValue.length()] != '-') | 535 value[selectorValue.length()] != '-') |
529 return false; | 536 return false; |
530 return true; | 537 return true; |
531 default: | 538 default: |
532 ASSERT_NOT_REACHED(); | 539 NOTREACHED(); |
533 return false; | 540 return false; |
534 } | 541 } |
535 } | 542 } |
536 | 543 |
537 static bool anyAttributeMatches(Element& element, | 544 static bool anyAttributeMatches(Element& element, |
538 CSSSelector::MatchType match, | 545 CSSSelector::MatchType match, |
539 const CSSSelector& selector) { | 546 const CSSSelector& selector) { |
540 const QualifiedName& selectorAttr = selector.attribute(); | 547 const QualifiedName& selectorAttr = selector.attribute(); |
541 ASSERT(selectorAttr.localName() != | 548 // Should not be possible from the CSS grammar. |
542 starAtom); // Should not be possible from the CSS grammar. | 549 DCHECK_NE(selectorAttr.localName(), starAtom); |
543 | 550 |
544 // Synchronize the attribute in case it is lazy-computed. | 551 // Synchronize the attribute in case it is lazy-computed. |
545 // Currently all lazy properties have a null namespace, so only pass localName
(). | 552 // Currently all lazy properties have a null namespace, so only pass |
| 553 // localName(). |
546 element.synchronizeAttribute(selectorAttr.localName()); | 554 element.synchronizeAttribute(selectorAttr.localName()); |
547 | 555 |
548 const AtomicString& selectorValue = selector.value(); | 556 const AtomicString& selectorValue = selector.value(); |
549 TextCaseSensitivity caseSensitivity = | 557 TextCaseSensitivity caseSensitivity = |
550 (selector.attributeMatch() == CSSSelector::CaseInsensitive) | 558 (selector.attributeMatch() == CSSSelector::CaseInsensitive) |
551 ? TextCaseASCIIInsensitive | 559 ? TextCaseASCIIInsensitive |
552 : TextCaseSensitive; | 560 : TextCaseSensitive; |
553 | 561 |
554 AttributeCollection attributes = element.attributesWithoutUpdate(); | 562 AttributeCollection attributes = element.attributesWithoutUpdate(); |
555 for (const auto& attributeItem : attributes) { | 563 for (const auto& attributeItem : attributes) { |
(...skipping 28 matching lines...) Expand all Loading... |
584 } | 592 } |
585 if (selectorAttr.namespaceURI() != starAtom) | 593 if (selectorAttr.namespaceURI() != starAtom) |
586 return false; | 594 return false; |
587 } | 595 } |
588 | 596 |
589 return false; | 597 return false; |
590 } | 598 } |
591 | 599 |
592 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, | 600 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, |
593 MatchResult& result) const { | 601 MatchResult& result) const { |
594 ASSERT(context.element); | 602 DCHECK(context.element); |
595 Element& element = *context.element; | 603 Element& element = *context.element; |
596 ASSERT(context.selector); | 604 DCHECK(context.selector); |
597 const CSSSelector& selector = *context.selector; | 605 const CSSSelector& selector = *context.selector; |
598 | 606 |
599 // Only :host and :host-context() should match the host: http://drafts.csswg.o
rg/css-scoping/#host-element | 607 // Only :host and :host-context() should match the host: |
| 608 // http://drafts.csswg.org/css-scoping/#host-element |
600 if (context.scope && context.scope->ownerShadowHost() == element && | 609 if (context.scope && context.scope->ownerShadowHost() == element && |
601 (!selector.isHostPseudoClass() && !context.treatShadowHostAsNormalScope && | 610 (!selector.isHostPseudoClass() && !context.treatShadowHostAsNormalScope && |
602 selector.match() != CSSSelector::PseudoElement)) | 611 selector.match() != CSSSelector::PseudoElement)) |
603 return false; | 612 return false; |
604 | 613 |
605 switch (selector.match()) { | 614 switch (selector.match()) { |
606 case CSSSelector::Tag: | 615 case CSSSelector::Tag: |
607 return matchesTagName(element, selector.tagQName()); | 616 return matchesTagName(element, selector.tagQName()); |
608 case CSSSelector::Class: | 617 case CSSSelector::Class: |
609 return element.hasClass() && | 618 return element.hasClass() && |
(...skipping 11 matching lines...) Expand all Loading... |
621 case CSSSelector::AttributeBegin: | 630 case CSSSelector::AttributeBegin: |
622 case CSSSelector::AttributeEnd: | 631 case CSSSelector::AttributeEnd: |
623 return anyAttributeMatches(element, selector.match(), selector); | 632 return anyAttributeMatches(element, selector.match(), selector); |
624 | 633 |
625 case CSSSelector::PseudoClass: | 634 case CSSSelector::PseudoClass: |
626 return checkPseudoClass(context, result); | 635 return checkPseudoClass(context, result); |
627 case CSSSelector::PseudoElement: | 636 case CSSSelector::PseudoElement: |
628 return checkPseudoElement(context, result); | 637 return checkPseudoElement(context, result); |
629 | 638 |
630 default: | 639 default: |
631 ASSERT_NOT_REACHED(); | 640 NOTREACHED(); |
632 return false; | 641 return false; |
633 } | 642 } |
634 } | 643 } |
635 | 644 |
636 bool SelectorChecker::checkPseudoNot(const SelectorCheckingContext& context, | 645 bool SelectorChecker::checkPseudoNot(const SelectorCheckingContext& context, |
637 MatchResult& result) const { | 646 MatchResult& result) const { |
638 const CSSSelector& selector = *context.selector; | 647 const CSSSelector& selector = *context.selector; |
639 | 648 |
640 SelectorCheckingContext subContext(context); | 649 SelectorCheckingContext subContext(context); |
641 subContext.isSubSelector = true; | 650 subContext.isSubSelector = true; |
642 ASSERT(selector.selectorList()); | 651 DCHECK(selector.selectorList()); |
643 for (subContext.selector = selector.selectorList()->first(); | 652 for (subContext.selector = selector.selectorList()->first(); |
644 subContext.selector; | 653 subContext.selector; |
645 subContext.selector = subContext.selector->tagHistory()) { | 654 subContext.selector = subContext.selector->tagHistory()) { |
646 // :not cannot nest. I don't really know why this is a | 655 // :not cannot nest. I don't really know why this is a |
647 // restriction in CSS3, but it is, so let's honor it. | 656 // restriction in CSS3, but it is, so let's honor it. |
648 // the parser enforces that this never occurs | 657 // the parser enforces that this never occurs |
649 ASSERT(subContext.selector->getPseudoType() != CSSSelector::PseudoNot); | 658 DCHECK_NE(subContext.selector->getPseudoType(), CSSSelector::PseudoNot); |
650 // We select between :visited and :link when applying. We don't know which o
ne applied (or not) yet. | 659 // We select between :visited and :link when applying. We don't know which |
| 660 // one applied (or not) yet. |
651 if (subContext.selector->getPseudoType() == CSSSelector::PseudoVisited || | 661 if (subContext.selector->getPseudoType() == CSSSelector::PseudoVisited || |
652 (subContext.selector->getPseudoType() == CSSSelector::PseudoLink && | 662 (subContext.selector->getPseudoType() == CSSSelector::PseudoLink && |
653 subContext.visitedMatchType == VisitedMatchEnabled)) | 663 subContext.visitedMatchType == VisitedMatchEnabled)) |
654 return true; | 664 return true; |
655 if (m_mode == SharingRules) { | 665 if (m_mode == SharingRules) { |
656 // context.scope is not available if m_mode == SharingRules. | 666 // context.scope is not available if m_mode == SharingRules. |
657 // We cannot determine whether :host or :scope matches a given element or
not. | 667 // We cannot determine whether :host or :scope matches a given element or |
| 668 // not. |
658 if (subContext.selector->isHostPseudoClass() || | 669 if (subContext.selector->isHostPseudoClass() || |
659 subContext.selector->getPseudoType() == CSSSelector::PseudoScope) | 670 subContext.selector->getPseudoType() == CSSSelector::PseudoScope) |
660 return true; | 671 return true; |
661 // :hover, :active, :focus, :-webkit-drag relies on setting flags on | 672 // :hover, :active, :focus, :-webkit-drag relies on setting flags on |
662 // ComputedStyle even if the whole selector may not match. That | 673 // ComputedStyle even if the whole selector may not match. That |
663 // means we cannot share style between elements which may fail | 674 // means we cannot share style between elements which may fail |
664 // matching the same selector for different reasons. An example is | 675 // matching the same selector for different reasons. An example is |
665 // [attr]:hover which both fail for :hover, but an element without | 676 // [attr]:hover which both fail for :hover, but an element without |
666 // attr won't reach the :hover selector, hence not setting the bit. | 677 // attr won't reach the :hover selector, hence not setting the bit. |
667 if (subContext.selector->isUserActionPseudoClass()) | 678 if (subContext.selector->isUserActionPseudoClass()) |
668 return true; | 679 return true; |
669 } | 680 } |
670 if (!checkOne(subContext, result)) | 681 if (!checkOne(subContext, result)) |
671 return true; | 682 return true; |
672 } | 683 } |
673 return false; | 684 return false; |
674 } | 685 } |
675 | 686 |
676 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, | 687 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, |
677 MatchResult& result) const { | 688 MatchResult& result) const { |
678 Element& element = *context.element; | 689 Element& element = *context.element; |
679 const CSSSelector& selector = *context.selector; | 690 const CSSSelector& selector = *context.selector; |
680 | 691 |
681 if (context.hasScrollbarPseudo) { | 692 if (context.hasScrollbarPseudo) { |
682 // CSS scrollbars match a specific subset of pseudo classes, and they have s
pecialized rules for each | 693 // CSS scrollbars match a specific subset of pseudo classes, and they have |
| 694 // specialized rules for each |
683 // (since there are no elements involved). | 695 // (since there are no elements involved). |
684 return checkScrollbarPseudoClass(context, result); | 696 return checkScrollbarPseudoClass(context, result); |
685 } | 697 } |
686 | 698 |
687 switch (selector.getPseudoType()) { | 699 switch (selector.getPseudoType()) { |
688 case CSSSelector::PseudoNot: | 700 case CSSSelector::PseudoNot: |
689 return checkPseudoNot(context, result); | 701 return checkPseudoNot(context, result); |
690 case CSSSelector::PseudoEmpty: { | 702 case CSSSelector::PseudoEmpty: { |
691 bool result = true; | 703 bool result = true; |
692 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { | 704 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
809 if (!parent->isFinishedParsingChildren()) | 821 if (!parent->isFinishedParsingChildren()) |
810 return false; | 822 return false; |
811 return selector.matchNth(NthIndexCache::nthLastOfTypeIndex(element)); | 823 return selector.matchNth(NthIndexCache::nthLastOfTypeIndex(element)); |
812 } | 824 } |
813 break; | 825 break; |
814 case CSSSelector::PseudoTarget: | 826 case CSSSelector::PseudoTarget: |
815 return element == element.document().cssTarget(); | 827 return element == element.document().cssTarget(); |
816 case CSSSelector::PseudoAny: { | 828 case CSSSelector::PseudoAny: { |
817 SelectorCheckingContext subContext(context); | 829 SelectorCheckingContext subContext(context); |
818 subContext.isSubSelector = true; | 830 subContext.isSubSelector = true; |
819 ASSERT(selector.selectorList()); | 831 DCHECK(selector.selectorList()); |
820 for (subContext.selector = selector.selectorList()->first(); | 832 for (subContext.selector = selector.selectorList()->first(); |
821 subContext.selector; | 833 subContext.selector; |
822 subContext.selector = CSSSelectorList::next(*subContext.selector)) { | 834 subContext.selector = CSSSelectorList::next(*subContext.selector)) { |
823 if (match(subContext)) | 835 if (match(subContext)) |
824 return true; | 836 return true; |
825 } | 837 } |
826 } break; | 838 } break; |
827 case CSSSelector::PseudoAutofill: | 839 case CSSSelector::PseudoAutofill: |
828 return element.isFormControlElement() && | 840 return element.isFormControlElement() && |
829 toHTMLFormControlElement(element).isAutofilled(); | 841 toHTMLFormControlElement(element).isAutofilled(); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 const AtomicString& argument = selector.argument(); | 958 const AtomicString& argument = selector.argument(); |
947 if (value.isEmpty() || | 959 if (value.isEmpty() || |
948 !value.startsWith(argument, TextCaseASCIIInsensitive)) | 960 !value.startsWith(argument, TextCaseASCIIInsensitive)) |
949 break; | 961 break; |
950 if (value.length() != argument.length() && | 962 if (value.length() != argument.length() && |
951 value[argument.length()] != '-') | 963 value[argument.length()] != '-') |
952 break; | 964 break; |
953 return true; | 965 return true; |
954 } | 966 } |
955 case CSSSelector::PseudoFullScreen: | 967 case CSSSelector::PseudoFullScreen: |
956 // While a Document is in the fullscreen state, and the document's current
fullscreen | 968 // While a Document is in the fullscreen state, and the document's current |
957 // element is an element in the document, the 'full-screen' pseudoclass ap
plies to | 969 // fullscreen element is an element in the document, the 'full-screen' |
958 // that element. Also, an <iframe>, <object> or <embed> element whose chil
d browsing | 970 // pseudoclass applies to that element. Also, an <iframe>, <object> or |
959 // context's Document is in the fullscreen state has the 'full-screen' pse
udoclass applied. | 971 // <embed> element whose child browsing context's Document is in the |
| 972 // fullscreen state has the 'full-screen' pseudoclass applied. |
960 if (isHTMLFrameElementBase(element) && | 973 if (isHTMLFrameElementBase(element) && |
961 element.containsFullScreenElement()) | 974 element.containsFullScreenElement()) |
962 return true; | 975 return true; |
963 return Fullscreen::isCurrentFullScreenElement(element); | 976 return Fullscreen::isCurrentFullScreenElement(element); |
964 case CSSSelector::PseudoFullScreenAncestor: | 977 case CSSSelector::PseudoFullScreenAncestor: |
965 return element.containsFullScreenElement(); | 978 return element.containsFullScreenElement(); |
966 case CSSSelector::PseudoInRange: | 979 case CSSSelector::PseudoInRange: |
967 if (m_mode == ResolvingStyle) | 980 if (m_mode == ResolvingStyle) |
968 element.document().setContainsValidityStyleRules(); | 981 element.document().setContainsValidityStyleRules(); |
969 return element.isInRange(); | 982 return element.isInRange(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 case CSSSelector::PseudoIncrement: | 1026 case CSSSelector::PseudoIncrement: |
1014 case CSSSelector::PseudoStart: | 1027 case CSSSelector::PseudoStart: |
1015 case CSSSelector::PseudoEnd: | 1028 case CSSSelector::PseudoEnd: |
1016 case CSSSelector::PseudoDoubleButton: | 1029 case CSSSelector::PseudoDoubleButton: |
1017 case CSSSelector::PseudoSingleButton: | 1030 case CSSSelector::PseudoSingleButton: |
1018 case CSSSelector::PseudoNoButton: | 1031 case CSSSelector::PseudoNoButton: |
1019 case CSSSelector::PseudoCornerPresent: | 1032 case CSSSelector::PseudoCornerPresent: |
1020 return false; | 1033 return false; |
1021 case CSSSelector::PseudoUnknown: | 1034 case CSSSelector::PseudoUnknown: |
1022 default: | 1035 default: |
1023 ASSERT_NOT_REACHED(); | 1036 NOTREACHED(); |
1024 break; | 1037 break; |
1025 } | 1038 } |
1026 return false; | 1039 return false; |
1027 } | 1040 } |
1028 | 1041 |
1029 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context, | 1042 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context, |
1030 MatchResult& result) const { | 1043 MatchResult& result) const { |
1031 const CSSSelector& selector = *context.selector; | 1044 const CSSSelector& selector = *context.selector; |
1032 Element& element = *context.element; | 1045 Element& element = *context.element; |
1033 | 1046 |
(...skipping 25 matching lines...) Expand all Loading... |
1059 return root->type() == ShadowRootType::UserAgent && | 1072 return root->type() == ShadowRootType::UserAgent && |
1060 element.shadowPseudoId() == selector.value(); | 1073 element.shadowPseudoId() == selector.value(); |
1061 return false; | 1074 return false; |
1062 case CSSSelector::PseudoSlotted: { | 1075 case CSSSelector::PseudoSlotted: { |
1063 SelectorCheckingContext subContext(context); | 1076 SelectorCheckingContext subContext(context); |
1064 subContext.isSubSelector = true; | 1077 subContext.isSubSelector = true; |
1065 subContext.scope = nullptr; | 1078 subContext.scope = nullptr; |
1066 subContext.treatShadowHostAsNormalScope = false; | 1079 subContext.treatShadowHostAsNormalScope = false; |
1067 | 1080 |
1068 // ::slotted() only allows one compound selector. | 1081 // ::slotted() only allows one compound selector. |
1069 ASSERT(selector.selectorList()->first()); | 1082 DCHECK(selector.selectorList()->first()); |
1070 ASSERT(!CSSSelectorList::next(*selector.selectorList()->first())); | 1083 DCHECK(!CSSSelectorList::next(*selector.selectorList()->first())); |
1071 subContext.selector = selector.selectorList()->first(); | 1084 subContext.selector = selector.selectorList()->first(); |
1072 return match(subContext); | 1085 return match(subContext); |
1073 } | 1086 } |
1074 case CSSSelector::PseudoContent: | 1087 case CSSSelector::PseudoContent: |
1075 return element.isInShadowTree() && element.isInsertionPoint(); | 1088 return element.isInShadowTree() && element.isInsertionPoint(); |
1076 case CSSSelector::PseudoShadow: | 1089 case CSSSelector::PseudoShadow: |
1077 return element.isInShadowTree() && context.previousElement; | 1090 return element.isInShadowTree() && context.previousElement; |
1078 default: | 1091 default: |
1079 if (m_mode == SharingRules) | 1092 if (m_mode == SharingRules) |
1080 return true; | 1093 return true; |
1081 ASSERT(m_mode != QueryingRules); | 1094 DCHECK_NE(m_mode, QueryingRules); |
1082 result.dynamicPseudo = CSSSelector::pseudoId(selector.getPseudoType()); | 1095 result.dynamicPseudo = CSSSelector::pseudoId(selector.getPseudoType()); |
1083 ASSERT(result.dynamicPseudo != PseudoIdNone); | 1096 DCHECK_NE(result.dynamicPseudo, PseudoIdNone); |
1084 return true; | 1097 return true; |
1085 } | 1098 } |
1086 } | 1099 } |
1087 | 1100 |
1088 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, | 1101 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, |
1089 MatchResult& result) const { | 1102 MatchResult& result) const { |
1090 const CSSSelector& selector = *context.selector; | 1103 const CSSSelector& selector = *context.selector; |
1091 Element& element = *context.element; | 1104 Element& element = *context.element; |
1092 | 1105 |
1093 if (m_mode == SharingRules) | 1106 if (m_mode == SharingRules) |
1094 return true; | 1107 return true; |
1095 // :host only matches a shadow host when :host is in a shadow tree of the shad
ow host. | 1108 // :host only matches a shadow host when :host is in a shadow tree of the |
| 1109 // shadow host. |
1096 if (!context.scope) | 1110 if (!context.scope) |
1097 return false; | 1111 return false; |
1098 const ContainerNode* shadowHost = context.scope->ownerShadowHost(); | 1112 const ContainerNode* shadowHost = context.scope->ownerShadowHost(); |
1099 if (!shadowHost || shadowHost != element) | 1113 if (!shadowHost || shadowHost != element) |
1100 return false; | 1114 return false; |
1101 ASSERT(element.shadow()); | 1115 DCHECK(element.shadow()); |
1102 | 1116 |
1103 // For the case with no parameters, i.e. just :host. | 1117 // For the case with no parameters, i.e. just :host. |
1104 if (!selector.selectorList()) | 1118 if (!selector.selectorList()) |
1105 return true; | 1119 return true; |
1106 | 1120 |
1107 SelectorCheckingContext subContext(context); | 1121 SelectorCheckingContext subContext(context); |
1108 subContext.isSubSelector = true; | 1122 subContext.isSubSelector = true; |
1109 | 1123 |
1110 bool matched = false; | 1124 bool matched = false; |
1111 unsigned maxSpecificity = 0; | 1125 unsigned maxSpecificity = 0; |
1112 | 1126 |
1113 // If one of simple selectors matches an element, returns SelectorMatches. Jus
t "OR". | 1127 // If one of simple selectors matches an element, returns SelectorMatches. |
| 1128 // Just "OR". |
1114 for (subContext.selector = selector.selectorList()->first(); | 1129 for (subContext.selector = selector.selectorList()->first(); |
1115 subContext.selector; | 1130 subContext.selector; |
1116 subContext.selector = CSSSelectorList::next(*subContext.selector)) { | 1131 subContext.selector = CSSSelectorList::next(*subContext.selector)) { |
1117 subContext.treatShadowHostAsNormalScope = true; | 1132 subContext.treatShadowHostAsNormalScope = true; |
1118 subContext.scope = context.scope; | 1133 subContext.scope = context.scope; |
1119 // Use FlatTreeTraversal to traverse a composed ancestor list of a given ele
ment. | 1134 // Use FlatTreeTraversal to traverse a composed ancestor list of a given |
| 1135 // element. |
1120 Element* nextElement = &element; | 1136 Element* nextElement = &element; |
1121 SelectorCheckingContext hostContext(subContext); | 1137 SelectorCheckingContext hostContext(subContext); |
1122 do { | 1138 do { |
1123 MatchResult subResult; | 1139 MatchResult subResult; |
1124 hostContext.element = nextElement; | 1140 hostContext.element = nextElement; |
1125 if (match(hostContext, subResult)) { | 1141 if (match(hostContext, subResult)) { |
1126 matched = true; | 1142 matched = true; |
1127 // Consider div:host(div:host(div:host(div:host...))). | 1143 // Consider div:host(div:host(div:host(div:host...))). |
1128 maxSpecificity = | 1144 maxSpecificity = |
1129 std::max(maxSpecificity, hostContext.selector->specificity() + | 1145 std::max(maxSpecificity, hostContext.selector->specificity() + |
(...skipping 20 matching lines...) Expand all Loading... |
1150 } | 1166 } |
1151 | 1167 |
1152 bool SelectorChecker::checkScrollbarPseudoClass( | 1168 bool SelectorChecker::checkScrollbarPseudoClass( |
1153 const SelectorCheckingContext& context, | 1169 const SelectorCheckingContext& context, |
1154 MatchResult& result) const { | 1170 MatchResult& result) const { |
1155 const CSSSelector& selector = *context.selector; | 1171 const CSSSelector& selector = *context.selector; |
1156 | 1172 |
1157 if (selector.getPseudoType() == CSSSelector::PseudoNot) | 1173 if (selector.getPseudoType() == CSSSelector::PseudoNot) |
1158 return checkPseudoNot(context, result); | 1174 return checkPseudoNot(context, result); |
1159 | 1175 |
1160 // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventua
lly :window-inactive should become a real | 1176 // FIXME: This is a temporary hack for resizers and scrollbar corners. |
| 1177 // Eventually :window-inactive should become a real |
1161 // pseudo class and just apply to everything. | 1178 // pseudo class and just apply to everything. |
1162 if (selector.getPseudoType() == CSSSelector::PseudoWindowInactive) | 1179 if (selector.getPseudoType() == CSSSelector::PseudoWindowInactive) |
1163 return !context.element->document().page()->focusController().isActive(); | 1180 return !context.element->document().page()->focusController().isActive(); |
1164 | 1181 |
1165 if (!m_scrollbar) | 1182 if (!m_scrollbar) |
1166 return false; | 1183 return false; |
1167 | 1184 |
1168 switch (selector.getPseudoType()) { | 1185 switch (selector.getPseudoType()) { |
1169 case CSSSelector::PseudoEnabled: | 1186 case CSSSelector::PseudoEnabled: |
1170 return m_scrollbar->enabled(); | 1187 return m_scrollbar->enabled(); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1253 } | 1270 } |
1254 | 1271 |
1255 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) { | 1272 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) { |
1256 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element), | 1273 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element), |
1257 CSSSelector::PseudoFocus)) | 1274 CSSSelector::PseudoFocus)) |
1258 return true; | 1275 return true; |
1259 return element.isFocused() && isFrameFocused(element); | 1276 return element.isFocused() && isFrameFocused(element); |
1260 } | 1277 } |
1261 | 1278 |
1262 } // namespace blink | 1279 } // namespace blink |
OLD | NEW |