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 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |