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 |