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

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 for comments 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()) {
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()) {
rune 2016/03/18 12:04:12 Adding inline style here means we'll have inline s
kochi 2016/03/22 08:16:59 Yes, in v0/v1 mix, /deep/ wins against inline styl
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 // TODO(kochi): This loops through m_treeBoundaryCrossingScopes because to h andle
486 // Shadow DOM V0 documents as well. In pure V1 document only have to go thro ugh
487 // the chain of scopes for assigned slots. Add fast path for pure V1 documen t.
488 for (auto it = m_treeBoundaryCrossingScopes.rbegin(); it != m_treeBoundaryCr ossingScopes.rend(); ++it) {
489 const TreeScope& scope = (*it)->treeScope();
490 ScopedStyleResolver* resolver = scope.scopedStyleResolver();
491 ASSERT(resolver);
492
493 bool isInnerTreeScope = element.treeScope().isInclusiveAncestorOf(scope) ;
494 if (!shouldCheckScope(element, **it, isInnerTreeScope))
495 continue;
496
497 if (!matchElementScopeDone && scope.isInclusiveAncestorOf(element.treeSc ope())) {
498
499 matchElementScopeDone = true;
500
501 // At this point, the iterator has either encountered the scope for the element
502 // itself (if that scope has boundary-crossing rules), or the iterat or has moved
503 // to a scope which appears before the element's scope in the tree-o f-trees order.
504 // Try to match all rules from the element's scope.
505
506 matchElementScopeRules(element, elementScopeResolver, collector);
507 if (resolver == elementScopeResolver) {
508 // Boundary-crossing rules already collected in matchElementScop eRules.
509 continue;
510 }
511 }
512
513 collector.clearMatchedRules();
514 resolver->collectMatchingTreeBoundaryCrossingRules(collector);
515 collector.sortAndTransferMatchedRules();
516 collector.finishAddingAuthorRulesForTreeScope();
517 }
518
519 if (!matchElementScopeDone)
520 matchElementScopeRules(element, elementScopeResolver, collector);
521 }
522
414 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto r& collector) 523 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto r& collector)
415 { 524 {
525 if (!element.document().styleEngine().useCascadeOrderForShadowDOMV1()) {
526 matchAuthorRulesV0(element, collector);
527 return;
528 }
529
530 ASSERT(RuntimeEnabledFeatures::shadowDOMV1Enabled());
531 matchHostRules(element, collector);
532 matchScopedRules(element, collector);
533 }
534
535 void StyleResolver::matchAuthorRulesV0(const Element& element, ElementRuleCollec tor& collector)
536 {
416 collector.clearMatchedRules(); 537 collector.clearMatchedRules();
417 538
418 CascadeOrder cascadeOrder = 0; 539 CascadeOrder cascadeOrder = 0;
419 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad owTree; 540 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad owTree;
420 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); 541 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
421 542
422 // Apply :host and :host-context rules from inner scopes. 543 // Apply :host and :host-context rules from inner scopes.
423 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) 544 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
424 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, + +cascadeOrder); 545 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, + +cascadeOrder);
425 546
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 if (isAuto) { 599 if (isAuto) {
479 state.setHasDirAutoAttribute(true); 600 state.setHasDirAutoAttribute(true);
480 collector.addElementStyleProperties(textDirection == LTR ? leftT oRightDeclaration() : rightToLeftDeclaration()); 601 collector.addElementStyleProperties(textDirection == LTR ? leftT oRightDeclaration() : rightToLeftDeclaration());
481 } 602 }
482 } 603 }
483 } 604 }
484 605
485 matchAuthorRules(*state.element(), collector); 606 matchAuthorRules(*state.element(), collector);
486 607
487 if (state.element()->isStyledElement()) { 608 if (state.element()->isStyledElement()) {
488 if (state.element()->inlineStyle()) { 609 // For Shadow DOM V1, inline style is already collected in matchScopedRu les().
610 if (!state.element()->document().styleEngine().useCascadeOrderForShadowD OMV1() && state.element()->inlineStyle()) {
489 // Inline style is immutable as long as there is no CSSOM wrapper. 611 // Inline style is immutable as long as there is no CSSOM wrapper.
490 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut able(); 612 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut able();
491 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable); 613 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
492 } 614 }
493 615
494 // Now check SMIL animation override style. 616 // Now check SMIL animation override style.
495 if (includeSMILProperties && state.element()->isSVGElement()) 617 if (includeSMILProperties && state.element()->isSVGElement())
496 collector.addElementStyleProperties(toSVGElement(state.element())->a nimatedSMILStyleProperties(), false /* isCacheable */); 618 collector.addElementStyleProperties(toSVGElement(state.element())->a nimatedSMILStyleProperties(), false /* isCacheable */);
497 } 619 }
498 620
499 collector.finishAddingAuthorRulesForTreeScope(); 621 collector.finishAddingAuthorRulesForTreeScope();
500 } 622 }
501 623
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) 624 void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, Ele mentRuleCollector& collector)
527 { 625 {
528 if (m_treeBoundaryCrossingScopes.isEmpty()) 626 if (m_treeBoundaryCrossingScopes.isEmpty())
529 return; 627 return;
530 628
531 // When comparing rules declared in outer treescopes, outer's rules win. 629 // When comparing rules declared in outer treescopes, outer's rules win.
532 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2; 630 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2;
533 // When comparing rules declared in inner treescopes, inner's rules win. 631 // When comparing rules declared in inner treescopes, inner's rules win.
534 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size(); 632 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size();
535 633
(...skipping 1076 matching lines...) Expand 10 before | Expand all | Expand 10 after
1612 visitor->trace(m_uncommonAttributeRuleSet); 1710 visitor->trace(m_uncommonAttributeRuleSet);
1613 visitor->trace(m_watchedSelectorsRules); 1711 visitor->trace(m_watchedSelectorsRules);
1614 visitor->trace(m_treeBoundaryCrossingScopes); 1712 visitor->trace(m_treeBoundaryCrossingScopes);
1615 visitor->trace(m_styleSharingLists); 1713 visitor->trace(m_styleSharingLists);
1616 visitor->trace(m_pendingStyleSheets); 1714 visitor->trace(m_pendingStyleSheets);
1617 visitor->trace(m_document); 1715 visitor->trace(m_document);
1618 #endif 1716 #endif
1619 } 1717 }
1620 1718
1621 } // namespace blink 1719 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698