Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp

Issue 1803933002: Use correct cascading order for Shadow DOM v1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix inline style Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 369 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 380
381 void StyleResolver::clearStyleSharingList() 381 void StyleResolver::clearStyleSharingList()
382 { 382 {
383 m_styleSharingLists.resize(0); 383 m_styleSharingLists.resize(0);
384 } 384 }
385 385
386 static inline ScopedStyleResolver* scopedResolverFor(const Element& element) 386 static inline ScopedStyleResolver* scopedResolverFor(const Element& element)
387 { 387 {
388 // Ideally, returning element->treeScope().scopedStyleResolver() should be 388 // Ideally, returning element->treeScope().scopedStyleResolver() should be
389 // enough, but ::cue and custom pseudo elements like ::-webkit-meter-bar pie rce 389 // enough, but ::cue and custom pseudo elements like ::-webkit-meter-bar pie rce
390 // through a shadow dom boundary, yet they are not part of m_treeBoundaryCro ssingRules. 390 // through a shadow dom boundary, yet they are not part of m_treeBoundaryCro ssingScopes.
391 // The assumption here is that these rules only pierce through one boundary and 391 // The assumption here is that these rules only pierce through one boundary and
392 // that the scope of these elements do not have a style resolver due to the fact 392 // that the scope of these elements do not have a style resolver due to the fact
393 // that VTT scopes and UA shadow trees don't have <style> elements. This is 393 // that VTT scopes and UA shadow trees don't have <style> elements. This is
394 // backed up by the ASSERTs below. 394 // backed up by the ASSERTs below.
395 // 395 //
396 // FIXME: Make ::cue and custom pseudo elements part of boundary crossing ru les 396 // FIXME: Make ::cue and custom pseudo elements part of boundary crossing ru les
397 // when moving those rules to ScopedStyleResolver as part of issue 401359. 397 // when moving those rules to ScopedStyleResolver as part of issue 401359.
398 398
399 TreeScope* treeScope = &element.treeScope(); 399 TreeScope* treeScope = &element.treeScope();
400 if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver()) { 400 if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver()) {
401 ASSERT(element.shadowPseudoId().isEmpty()); 401 ASSERT(element.shadowPseudoId().isEmpty());
402 ASSERT(!element.isVTTElement()); 402 ASSERT(!element.isVTTElement());
403 return resolver; 403 return resolver;
404 } 404 }
405 405
406 treeScope = treeScope->parentTreeScope(); 406 treeScope = treeScope->parentTreeScope();
407 if (!treeScope) 407 if (!treeScope)
408 return nullptr; 408 return nullptr;
409 if (element.shadowPseudoId().isEmpty() && !element.isVTTElement()) 409 if (element.shadowPseudoId().isEmpty() && !element.isVTTElement())
410 return nullptr; 410 return nullptr;
411 return treeScope->scopedStyleResolver(); 411 return treeScope->scopedStyleResolver();
412 } 412 }
413 413
414 static void matchHostRules(const Element& element, ElementRuleCollector& collect or)
415 {
416 ElementShadow* shadow = element.shadow();
417 if (!shadow)
418 return;
419
420 for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadow Root = shadowRoot->youngerShadowRoot()) {
rune 2016/03/17 10:59:02 This method is used for V1. Can we have multiple s
kochi 2016/03/18 09:00:52 Yeah, it is counterintuitive at a glance but once
rune 2016/03/18 12:04:12 No, it was just me thinking out loud to confirm it
421 if (!shadowRoot->numberOfStyles())
422 continue;
423 if (ScopedStyleResolver* resolver = shadowRoot->scopedStyleResolver()) {
424 collector.clearMatchedRules();
425 resolver->collectMatchingShadowHostRules(collector);
426 collector.sortAndTransferMatchedRules();
427 collector.finishAddingAuthorRulesForTreeScope();
428 }
429 }
430 }
431
432 static void matchElementScopeRules(const Element& element, ScopedStyleResolver* elementScopeResolver, ElementRuleCollector& collector)
433 {
434 if (elementScopeResolver) {
435 collector.clearMatchedRules();
436 elementScopeResolver->collectMatchingAuthorRules(collector);
437 elementScopeResolver->collectMatchingTreeBoundaryCrossingRules(collector );
438 collector.sortAndTransferMatchedRules();
439 }
440
441 if (element.isStyledElement() && element.inlineStyle() && !collector.isColle ctingForPseudoElement()) {
442 // Inline style is immutable as long as there is no CSSOM wrapper.
443 bool isInlineStyleCacheable = !element.inlineStyle()->isMutable();
444 collector.addElementStyleProperties(element.inlineStyle(), isInlineStyle Cacheable);
445 }
446
447 collector.finishAddingAuthorRulesForTreeScope();
448 }
449
450 static bool shouldCheckScope(const Element& element, const Node& scopingNode, bo ol isInnerTreeScope)
451 {
452 if (isInnerTreeScope && element.treeScope() != scopingNode.treeScope()) {
453 // Check if |element| may be affected by a ::content rule in |scopingNod e|'s style.
454 // If |element| is a descendant of a shadow host which is ancestral to | scopingNode|,
455 // the |element| should be included for rule collection.
456 // Skip otherwise.
457 const TreeScope* scope = &scopingNode.treeScope();
458 while (scope && scope->parentTreeScope() != &element.treeScope())
459 scope = scope->parentTreeScope();
460 Element* shadowHost = scope ? scope->rootNode().shadowHost() : nullptr;
461 return shadowHost && element.isDescendantOf(shadowHost);
462 }
463
464 // When |element| can be distributed to |scopingNode| via <shadow>, ::conten t rule can match,
465 // thus the case should be included.
466 if (!isInnerTreeScope && scopingNode.parentOrShadowHostNode() == element.tre eScope().rootNode().parentOrShadowHostNode())
467 return true;
468
469 // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be included.
470 // Skip otherwise.
471 return scopingNode.treeScope().scopedStyleResolver()->hasDeepOrShadowSelecto r();
472 }
473
474 void StyleResolver::matchScopedRules(const Element& element, ElementRuleCollecto r& collector)
475 {
476 // Match rules from treeScopes in the reverse tree-of-trees order, since the
477 // cascading order for normal rules is such that when comparing rules from
478 // different shadow trees, the rule from the tree which comes first in the
479 // tree-of-trees order wins. From other treeScopes than the element's own
480 // scope, only tree-boundary-crossing rules may match.
481
482 ScopedStyleResolver* elementScopeResolver = scopedResolverFor(element);
483 bool matchElementScopeDone = !elementScopeResolver && !element.inlineStyle() ;
484
485 for (auto it = m_treeBoundaryCrossingScopes.rbegin(); it != m_treeBoundaryCr ossingScopes.rend(); ++it) {
rune 2016/03/17 10:59:02 We should not need to walk m_treeBoundaryCrossingS
kochi 2016/03/18 09:00:52 Added TODO comment. Probably we can have an "pure
rune 2016/03/18 12:04:12 Acknowledged. We can iterate on this.
486 const TreeScope& scope = (*it)->treeScope();
487 ScopedStyleResolver* resolver = scope.scopedStyleResolver();
488 ASSERT(resolver);
489
490 bool isInnerTreeScope = element.treeScope().isInclusiveAncestorOf(scope) ;
491 if (!shouldCheckScope(element, **it, isInnerTreeScope))
492 continue;
493
494 if (!matchElementScopeDone && scope.isInclusiveAncestorOf(element.treeSc ope())) {
495
496 matchElementScopeDone = true;
497
498 // At this point, the iterator has either encountered the scope for the element
499 // itself (if that scope has boundary-crossing rules), or the iterat or has moved
500 // to a scope which appears before the element's scope in the tree-o f-trees order.
501 // Try to match all rules from the element's scope.
502
503 matchElementScopeRules(element, elementScopeResolver, collector);
504 if (resolver == elementScopeResolver) {
505 // Boundary-crossing rules already collected in matchElementScop eRules.
506 continue;
507 }
508 }
509
510 collector.clearMatchedRules();
511 resolver->collectMatchingTreeBoundaryCrossingRules(collector);
512 collector.sortAndTransferMatchedRules();
513 collector.finishAddingAuthorRulesForTreeScope();
514 }
515
516 if (!matchElementScopeDone)
517 matchElementScopeRules(element, elementScopeResolver, collector);
518 }
519
414 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto r& collector) 520 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto r& collector)
415 { 521 {
522 if (!element.document().useCascadeOrderForShadowDOMV1()) {
523 matchAuthorRulesV0(element, collector);
524 return;
525 }
526
527 ASSERT(RuntimeEnabledFeatures::shadowDOMV1Enabled());
528 matchHostRules(element, collector);
529 matchScopedRules(element, collector);
530 }
531
532 void StyleResolver::matchAuthorRulesV0(const Element& element, ElementRuleCollec tor& collector)
533 {
416 collector.clearMatchedRules(); 534 collector.clearMatchedRules();
417 535
418 CascadeOrder cascadeOrder = 0; 536 CascadeOrder cascadeOrder = 0;
419 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad owTree; 537 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad owTree;
420 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); 538 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
421 539
422 // Apply :host and :host-context rules from inner scopes. 540 // Apply :host and :host-context rules from inner scopes.
423 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) 541 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
424 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, + +cascadeOrder); 542 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, + +cascadeOrder);
425 543
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 if (isAuto) { 596 if (isAuto) {
479 state.setHasDirAutoAttribute(true); 597 state.setHasDirAutoAttribute(true);
480 collector.addElementStyleProperties(textDirection == LTR ? leftT oRightDeclaration() : rightToLeftDeclaration()); 598 collector.addElementStyleProperties(textDirection == LTR ? leftT oRightDeclaration() : rightToLeftDeclaration());
481 } 599 }
482 } 600 }
483 } 601 }
484 602
485 matchAuthorRules(*state.element(), collector); 603 matchAuthorRules(*state.element(), collector);
486 604
487 if (state.element()->isStyledElement()) { 605 if (state.element()->isStyledElement()) {
488 if (state.element()->inlineStyle()) { 606 // For Shadow DOM V1, inline style is already collected in matchScopedRu les().
607 if (!state.element()->document().useCascadeOrderForShadowDOMV1() && stat e.element()->inlineStyle()) {
489 // Inline style is immutable as long as there is no CSSOM wrapper. 608 // Inline style is immutable as long as there is no CSSOM wrapper.
490 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut able(); 609 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut able();
491 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable); 610 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
492 } 611 }
493 612
494 // Now check SMIL animation override style. 613 // Now check SMIL animation override style.
495 if (includeSMILProperties && state.element()->isSVGElement()) 614 if (includeSMILProperties && state.element()->isSVGElement())
496 collector.addElementStyleProperties(toSVGElement(state.element())->a nimatedSMILStyleProperties(), false /* isCacheable */); 615 collector.addElementStyleProperties(toSVGElement(state.element())->a nimatedSMILStyleProperties(), false /* isCacheable */);
497 } 616 }
498 617
499 collector.finishAddingAuthorRulesForTreeScope(); 618 collector.finishAddingAuthorRulesForTreeScope();
500 } 619 }
501 620
502 static bool shouldCheckScope(const Element& element, const Node& scopingNode, bo ol isInnerTreeScope)
503 {
504 if (isInnerTreeScope && element.treeScope() != scopingNode.treeScope()) {
505 // Check if |element| may be affected by a ::content rule in |scopingNod e|'s style.
506 // If |element| is a descendant of a shadow host which is ancestral to | scopingNode|,
507 // the |element| should be included for rule collection.
508 // Skip otherwise.
509 const TreeScope* scope = &scopingNode.treeScope();
510 while (scope && scope->parentTreeScope() != &element.treeScope())
511 scope = scope->parentTreeScope();
512 Element* shadowHost = scope ? scope->rootNode().shadowHost() : nullptr;
513 return shadowHost && element.isDescendantOf(shadowHost);
514 }
515
516 // When |element| can be distributed to |scopingNode| via <shadow>, ::conten t rule can match,
517 // thus the case should be included.
518 if (!isInnerTreeScope && scopingNode.parentOrShadowHostNode() == element.tre eScope().rootNode().parentOrShadowHostNode())
519 return true;
520
521 // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be included.
522 // Skip otherwise.
523 return scopingNode.treeScope().scopedStyleResolver()->hasDeepOrShadowSelecto r();
524 }
525
526 void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, Ele mentRuleCollector& collector) 621 void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, Ele mentRuleCollector& collector)
527 { 622 {
528 if (m_treeBoundaryCrossingScopes.isEmpty()) 623 if (m_treeBoundaryCrossingScopes.isEmpty())
529 return; 624 return;
530 625
531 // When comparing rules declared in outer treescopes, outer's rules win. 626 // When comparing rules declared in outer treescopes, outer's rules win.
532 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2; 627 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2;
533 // When comparing rules declared in inner treescopes, inner's rules win. 628 // When comparing rules declared in inner treescopes, inner's rules win.
534 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size(); 629 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size();
535 630
(...skipping 1076 matching lines...) Expand 10 before | Expand all | Expand 10 after
1612 visitor->trace(m_uncommonAttributeRuleSet); 1707 visitor->trace(m_uncommonAttributeRuleSet);
1613 visitor->trace(m_watchedSelectorsRules); 1708 visitor->trace(m_watchedSelectorsRules);
1614 visitor->trace(m_treeBoundaryCrossingScopes); 1709 visitor->trace(m_treeBoundaryCrossingScopes);
1615 visitor->trace(m_styleSharingLists); 1710 visitor->trace(m_styleSharingLists);
1616 visitor->trace(m_pendingStyleSheets); 1711 visitor->trace(m_pendingStyleSheets);
1617 visitor->trace(m_document); 1712 visitor->trace(m_document);
1618 #endif 1713 #endif
1619 } 1714 }
1620 1715
1621 } // namespace blink 1716 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698