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 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 | 382 |
383 void StyleResolver::clearStyleSharingList() | 383 void StyleResolver::clearStyleSharingList() |
384 { | 384 { |
385 m_styleSharingLists.resize(0); | 385 m_styleSharingLists.resize(0); |
386 } | 386 } |
387 | 387 |
388 static inline ScopedStyleResolver* scopedResolverFor(const Element& element) | 388 static inline ScopedStyleResolver* scopedResolverFor(const Element& element) |
389 { | 389 { |
390 // Ideally, returning element->treeScope().scopedStyleResolver() should be | 390 // Ideally, returning element->treeScope().scopedStyleResolver() should be |
391 // enough, but ::cue and custom pseudo elements like ::-webkit-meter-bar pie
rce | 391 // enough, but ::cue and custom pseudo elements like ::-webkit-meter-bar pie
rce |
392 // through a shadow dom boundary, yet they are not part of m_treeBoundaryCro
ssingRules. | 392 // through a shadow dom boundary, yet they are not part of m_treeBoundaryCro
ssingScopes. |
393 // The assumption here is that these rules only pierce through one boundary
and | 393 // The assumption here is that these rules only pierce through one boundary
and |
394 // that the scope of these elements do not have a style resolver due to the
fact | 394 // that the scope of these elements do not have a style resolver due to the
fact |
395 // that VTT scopes and UA shadow trees don't have <style> elements. This is | 395 // that VTT scopes and UA shadow trees don't have <style> elements. This is |
396 // backed up by the ASSERTs below. | 396 // backed up by the ASSERTs below. |
397 // | 397 // |
398 // FIXME: Make ::cue and custom pseudo elements part of boundary crossing ru
les | 398 // FIXME: Make ::cue and custom pseudo elements part of boundary crossing ru
les |
399 // when moving those rules to ScopedStyleResolver as part of issue 401359. | 399 // when moving those rules to ScopedStyleResolver as part of issue 401359. |
400 | 400 |
401 TreeScope* treeScope = &element.treeScope(); | 401 TreeScope* treeScope = &element.treeScope(); |
402 if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver()) { | 402 if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver()) { |
403 ASSERT(element.shadowPseudoId().isEmpty()); | 403 ASSERT(element.shadowPseudoId().isEmpty()); |
404 ASSERT(!element.isVTTElement()); | 404 ASSERT(!element.isVTTElement()); |
405 return resolver; | 405 return resolver; |
406 } | 406 } |
407 | 407 |
408 treeScope = treeScope->parentTreeScope(); | 408 treeScope = treeScope->parentTreeScope(); |
409 if (!treeScope) | 409 if (!treeScope) |
410 return nullptr; | 410 return nullptr; |
411 if (element.shadowPseudoId().isEmpty() && !element.isVTTElement()) | 411 if (element.shadowPseudoId().isEmpty() && !element.isVTTElement()) |
412 return nullptr; | 412 return nullptr; |
413 return treeScope->scopedStyleResolver(); | 413 return treeScope->scopedStyleResolver(); |
414 } | 414 } |
415 | 415 |
| 416 static void matchHostRules(const Element& element, ElementRuleCollector& collect
or) |
| 417 { |
| 418 ElementShadow* shadow = element.shadow(); |
| 419 if (!shadow) |
| 420 return; |
| 421 |
| 422 for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadow
Root = shadowRoot->youngerShadowRoot()) { |
| 423 if (!shadowRoot->numberOfStyles()) |
| 424 continue; |
| 425 if (ScopedStyleResolver* resolver = shadowRoot->scopedStyleResolver()) { |
| 426 collector.clearMatchedRules(); |
| 427 resolver->collectMatchingShadowHostRules(collector); |
| 428 collector.sortAndTransferMatchedRules(); |
| 429 collector.finishAddingAuthorRulesForTreeScope(); |
| 430 } |
| 431 } |
| 432 } |
| 433 |
| 434 static void matchElementScopeRules(const Element& element, ScopedStyleResolver*
elementScopeResolver, ElementRuleCollector& collector) |
| 435 { |
| 436 if (elementScopeResolver) { |
| 437 collector.clearMatchedRules(); |
| 438 elementScopeResolver->collectMatchingAuthorRules(collector); |
| 439 elementScopeResolver->collectMatchingTreeBoundaryCrossingRules(collector
); |
| 440 collector.sortAndTransferMatchedRules(); |
| 441 } |
| 442 |
| 443 if (element.isStyledElement() && element.inlineStyle() && !collector.isColle
ctingForPseudoElement()) { |
| 444 // Inline style is immutable as long as there is no CSSOM wrapper. |
| 445 bool isInlineStyleCacheable = !element.inlineStyle()->isMutable(); |
| 446 collector.addElementStyleProperties(element.inlineStyle(), isInlineStyle
Cacheable); |
| 447 } |
| 448 |
| 449 collector.finishAddingAuthorRulesForTreeScope(); |
| 450 } |
| 451 |
| 452 static bool shouldCheckScope(const Element& element, const Node& scopingNode, bo
ol isInnerTreeScope) |
| 453 { |
| 454 if (isInnerTreeScope && element.treeScope() != scopingNode.treeScope()) { |
| 455 // Check if |element| may be affected by a ::content rule in |scopingNod
e|'s style. |
| 456 // If |element| is a descendant of a shadow host which is ancestral to |
scopingNode|, |
| 457 // the |element| should be included for rule collection. |
| 458 // Skip otherwise. |
| 459 const TreeScope* scope = &scopingNode.treeScope(); |
| 460 while (scope && scope->parentTreeScope() != &element.treeScope()) |
| 461 scope = scope->parentTreeScope(); |
| 462 Element* shadowHost = scope ? scope->rootNode().shadowHost() : nullptr; |
| 463 return shadowHost && element.isDescendantOf(shadowHost); |
| 464 } |
| 465 |
| 466 // When |element| can be distributed to |scopingNode| via <shadow>, ::conten
t rule can match, |
| 467 // thus the case should be included. |
| 468 if (!isInnerTreeScope && scopingNode.parentOrShadowHostNode() == element.tre
eScope().rootNode().parentOrShadowHostNode()) |
| 469 return true; |
| 470 |
| 471 // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be
included. |
| 472 // Skip otherwise. |
| 473 return scopingNode.treeScope().scopedStyleResolver()->hasDeepOrShadowSelecto
r(); |
| 474 } |
| 475 |
| 476 void StyleResolver::matchScopedRules(const Element& element, ElementRuleCollecto
r& collector) |
| 477 { |
| 478 // Match rules from treeScopes in the reverse tree-of-trees order, since the |
| 479 // cascading order for normal rules is such that when comparing rules from |
| 480 // different shadow trees, the rule from the tree which comes first in the |
| 481 // tree-of-trees order wins. From other treeScopes than the element's own |
| 482 // scope, only tree-boundary-crossing rules may match. |
| 483 |
| 484 ScopedStyleResolver* elementScopeResolver = scopedResolverFor(element); |
| 485 bool matchElementScopeDone = !elementScopeResolver && !element.inlineStyle()
; |
| 486 |
| 487 // TODO(kochi): This loops through m_treeBoundaryCrossingScopes because to h
andle |
| 488 // Shadow DOM V0 documents as well. In pure V1 document only have to go thro
ugh |
| 489 // the chain of scopes for assigned slots. Add fast path for pure V1 documen
t. |
| 490 for (auto it = m_treeBoundaryCrossingScopes.rbegin(); it != m_treeBoundaryCr
ossingScopes.rend(); ++it) { |
| 491 const TreeScope& scope = (*it)->treeScope(); |
| 492 ScopedStyleResolver* resolver = scope.scopedStyleResolver(); |
| 493 ASSERT(resolver); |
| 494 |
| 495 bool isInnerTreeScope = element.treeScope().isInclusiveAncestorOf(scope)
; |
| 496 if (!shouldCheckScope(element, **it, isInnerTreeScope)) |
| 497 continue; |
| 498 |
| 499 if (!matchElementScopeDone && scope.isInclusiveAncestorOf(element.treeSc
ope())) { |
| 500 |
| 501 matchElementScopeDone = true; |
| 502 |
| 503 // At this point, the iterator has either encountered the scope for
the element |
| 504 // itself (if that scope has boundary-crossing rules), or the iterat
or has moved |
| 505 // to a scope which appears before the element's scope in the tree-o
f-trees order. |
| 506 // Try to match all rules from the element's scope. |
| 507 |
| 508 matchElementScopeRules(element, elementScopeResolver, collector); |
| 509 if (resolver == elementScopeResolver) { |
| 510 // Boundary-crossing rules already collected in matchElementScop
eRules. |
| 511 continue; |
| 512 } |
| 513 } |
| 514 |
| 515 collector.clearMatchedRules(); |
| 516 resolver->collectMatchingTreeBoundaryCrossingRules(collector); |
| 517 collector.sortAndTransferMatchedRules(); |
| 518 collector.finishAddingAuthorRulesForTreeScope(); |
| 519 } |
| 520 |
| 521 if (!matchElementScopeDone) |
| 522 matchElementScopeRules(element, elementScopeResolver, collector); |
| 523 } |
| 524 |
416 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto
r& collector) | 525 void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollecto
r& collector) |
417 { | 526 { |
| 527 if (element.document().styleEngine().shadowCascadeOrder() != ShadowCascadeOr
der::ShadowCascadeV1) { |
| 528 matchAuthorRulesV0(element, collector); |
| 529 return; |
| 530 } |
| 531 |
| 532 ASSERT(RuntimeEnabledFeatures::shadowDOMV1Enabled()); |
| 533 matchHostRules(element, collector); |
| 534 matchScopedRules(element, collector); |
| 535 } |
| 536 |
| 537 void StyleResolver::matchAuthorRulesV0(const Element& element, ElementRuleCollec
tor& collector) |
| 538 { |
418 collector.clearMatchedRules(); | 539 collector.clearMatchedRules(); |
419 | 540 |
420 CascadeOrder cascadeOrder = 0; | 541 CascadeOrder cascadeOrder = 0; |
421 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad
owTree; | 542 WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShad
owTree; |
422 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); | 543 collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); |
423 | 544 |
424 // Apply :host and :host-context rules from inner scopes. | 545 // Apply :host and :host-context rules from inner scopes. |
425 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) | 546 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) |
426 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, +
+cascadeOrder); | 547 resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, +
+cascadeOrder); |
427 | 548 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 if (isAuto) { | 601 if (isAuto) { |
481 state.setHasDirAutoAttribute(true); | 602 state.setHasDirAutoAttribute(true); |
482 collector.addElementStyleProperties(textDirection == LTR ? leftT
oRightDeclaration() : rightToLeftDeclaration()); | 603 collector.addElementStyleProperties(textDirection == LTR ? leftT
oRightDeclaration() : rightToLeftDeclaration()); |
483 } | 604 } |
484 } | 605 } |
485 } | 606 } |
486 | 607 |
487 matchAuthorRules(*state.element(), collector); | 608 matchAuthorRules(*state.element(), collector); |
488 | 609 |
489 if (state.element()->isStyledElement()) { | 610 if (state.element()->isStyledElement()) { |
490 if (state.element()->inlineStyle()) { | 611 // For Shadow DOM V1, inline style is already collected in matchScopedRu
les(). |
| 612 if (state.element()->document().styleEngine().shadowCascadeOrder() != Sh
adowCascadeOrder::ShadowCascadeV1 && state.element()->inlineStyle()) { |
491 // Inline style is immutable as long as there is no CSSOM wrapper. | 613 // Inline style is immutable as long as there is no CSSOM wrapper. |
492 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut
able(); | 614 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMut
able(); |
493 collector.addElementStyleProperties(state.element()->inlineStyle(),
isInlineStyleCacheable); | 615 collector.addElementStyleProperties(state.element()->inlineStyle(),
isInlineStyleCacheable); |
494 } | 616 } |
495 | 617 |
496 // Now check SMIL animation override style. | 618 // Now check SMIL animation override style. |
497 if (includeSMILProperties && state.element()->isSVGElement()) | 619 if (includeSMILProperties && state.element()->isSVGElement()) |
498 collector.addElementStyleProperties(toSVGElement(state.element())->a
nimatedSMILStyleProperties(), false /* isCacheable */); | 620 collector.addElementStyleProperties(toSVGElement(state.element())->a
nimatedSMILStyleProperties(), false /* isCacheable */); |
499 } | 621 } |
500 | 622 |
501 collector.finishAddingAuthorRulesForTreeScope(); | 623 collector.finishAddingAuthorRulesForTreeScope(); |
502 } | 624 } |
503 | 625 |
504 static bool shouldCheckScope(const Element& element, const Node& scopingNode, bo
ol isInnerTreeScope) | |
505 { | |
506 if (isInnerTreeScope && element.treeScope() != scopingNode.treeScope()) { | |
507 // Check if |element| may be affected by a ::content rule in |scopingNod
e|'s style. | |
508 // If |element| is a descendant of a shadow host which is ancestral to |
scopingNode|, | |
509 // the |element| should be included for rule collection. | |
510 // Skip otherwise. | |
511 const TreeScope* scope = &scopingNode.treeScope(); | |
512 while (scope && scope->parentTreeScope() != &element.treeScope()) | |
513 scope = scope->parentTreeScope(); | |
514 Element* shadowHost = scope ? scope->rootNode().shadowHost() : nullptr; | |
515 return shadowHost && element.isDescendantOf(shadowHost); | |
516 } | |
517 | |
518 // When |element| can be distributed to |scopingNode| via <shadow>, ::conten
t rule can match, | |
519 // thus the case should be included. | |
520 if (!isInnerTreeScope && scopingNode.parentOrShadowHostNode() == element.tre
eScope().rootNode().parentOrShadowHostNode()) | |
521 return true; | |
522 | |
523 // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be
included. | |
524 // Skip otherwise. | |
525 return scopingNode.treeScope().scopedStyleResolver()->hasDeepOrShadowSelecto
r(); | |
526 } | |
527 | |
528 void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, Ele
mentRuleCollector& collector) | 626 void StyleResolver::collectTreeBoundaryCrossingRules(const Element& element, Ele
mentRuleCollector& collector) |
529 { | 627 { |
530 if (m_treeBoundaryCrossingScopes.isEmpty()) | 628 if (m_treeBoundaryCrossingScopes.isEmpty()) |
531 return; | 629 return; |
532 | 630 |
533 // When comparing rules declared in outer treescopes, outer's rules win. | 631 // When comparing rules declared in outer treescopes, outer's rules win. |
534 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2; | 632 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingScopes.size() * 2; |
535 // When comparing rules declared in inner treescopes, inner's rules win. | 633 // When comparing rules declared in inner treescopes, inner's rules win. |
536 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size(); | 634 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingScopes.size(); |
537 | 635 |
(...skipping 1076 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1614 visitor->trace(m_uncommonAttributeRuleSet); | 1712 visitor->trace(m_uncommonAttributeRuleSet); |
1615 visitor->trace(m_watchedSelectorsRules); | 1713 visitor->trace(m_watchedSelectorsRules); |
1616 visitor->trace(m_treeBoundaryCrossingScopes); | 1714 visitor->trace(m_treeBoundaryCrossingScopes); |
1617 visitor->trace(m_styleSharingLists); | 1715 visitor->trace(m_styleSharingLists); |
1618 visitor->trace(m_pendingStyleSheets); | 1716 visitor->trace(m_pendingStyleSheets); |
1619 visitor->trace(m_document); | 1717 visitor->trace(m_document); |
1620 #endif | 1718 #endif |
1621 } | 1719 } |
1622 | 1720 |
1623 } // namespace blink | 1721 } // namespace blink |
OLD | NEW |