Source/WebCore/ChangeLog

 12012-09-02 Takashi Sakamoto <tasak@google.com>
 2
 3 [Shadow DOM] Needs @host rule for ShadowDOM styling
 4 https://bugs.webkit.org/show_bug.cgi?id=88606
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Implemented @host-@rules according to the shadow dom spec:
 9 http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#host-at-rule
 10 The design doc is:
 11 https://docs.google.com/document/d/1P2yorchF8lci2sccr-mVSRf2dtvjKeiuyQWzCB2bEA8/edit
 12
 13 Test: fast/dom/shadow/athost-atrules.html
 14
 15 * css/CSSGrammar.y:
 16 Added rules for parsing @host @-rules.
 17 * css/CSSParser.cpp:
 18 (WebCore::CSSParser::detectAtToken):
 19 Added a new token "@host".
 20 (WebCore::CSSParser::createHostRule):
 21 Added a new method to create an @host @-rule, which is invoked from
 22 CSSGrammar.y.
 23 (WebCore):
 24 * css/CSSParser.h:
 25 Added a declaration of the above new method: createHostRule.
 26 * css/CSSPropertySourceData.h:
 27 Added HOST_RULE to enum Type.
 28 * css/StyleResolver.cpp:
 29 (WebCore::StyleResolver::addHostRule):
 30 Added a new method to register @host @-rules with shadow roots.
 31 (WebCore):
 32 (WebCore::StyleResolver::transferMatchedRules):
 33 Moved the code for "transfering matched rules" from
 34 sortAndTransferMatchedRules.
 35 (WebCore::StyleResolver::sortAndTransferMatchedRules):
 36 Modified to use transferMatchedRules.
 37 (WebCore::StyleResolver::atHostRuleSetForScope):
 38 Added a new method for finding rulesets from the given shadow root.
 39 (WebCore::StyleResolver::matchesHostRules):
 40 A new method to check whether any @host @-rules will be applied to
 41 the given element or not. This is prepared for shared styles.
 42 (WebCore::StyleResolver::matchHostRules):
 43 A new method to find matched host rules when an element is given.
 44 (WebCore::StyleResolver::matchAuthorRules):
 45 Removed sortAndTransferMatchedRules. Instead, added sortMatchedRules.
 46 After sorting, invoke matchHostRules and transfer matched rules.
 47 Since @host @-rules should override existing author rules, firstly
 48 author rules will be applied. Secondly @host @-rules will be applied.
 49 However if sorting @host @-rules and author rules in the same time,
 50 the applying order will break.
 51 (WebCore::StyleResolver::collectMatchingRulesForList):
 52 * css/StyleResolver.h:
 53 (StyleResolver):
 54 * css/StyleRule.cpp:
 55 (WebCore::StyleRuleBase::reportMemoryUsage):
 56 (WebCore::StyleRuleBase::destroy):
 57 (WebCore::StyleRuleBase::copy):
 58 (WebCore::StyleRuleBase::createCSSOMWrapper):
 59 (WebCore::StyleRuleHost::StyleRuleHost):
 60 (WebCore):
 61 Implemented class StyleRuleHost. The class is almost the same as
 62 StyleRuleBlock except type.
 63 * css/StyleRule.h:
 64 (WebCore::StyleRuleBase::isHostRule):
 65 (StyleRuleHost):
 66 (WebCore::StyleRuleHost::create):
 67 (WebCore::StyleRuleHost::copy):
 68 (WebCore):
 69 * css/StyleSheetContents.cpp:
 70 (WebCore::childRulesHaveFailedOrCanceledSubresources):
 71 * dom/ElementShadow.cpp:
 72 (WebCore::ElementShadow::ElementShadow):
 73 (WebCore::ElementShadow::addShadowRoot):
 74 Since a new shadow root is added, disable @host @-rules cache.
 75 * dom/ElementShadow.h:
 76 (WebCore::ElementShadow::hasMatchedHostRule):
 77 (WebCore::ElementShadow::hasMatchedHostRuleAvailable):
 78 (WebCore::ElementShadow::clearHasMatchedHostRule):
 79 (WebCore::ElementShadow::setHasMatchedHostRule):
 80 Added four methods for @host @-rules cache. The cache has information
 81 about whether any @host @-rules match the ElementShadow's host.
 82 The return value of hasMatchedHostRule is available only if
 83 hasMatchedHostRuleAvailable returns true.
 84 (ElementShadow):
 85 * dom/ShadowRoot.cpp:
 86 (WebCore::ShadowRoot::ShadowRoot):
 87 (WebCore::ShadowRoot::childrenChanged):
 88 When childrenChanged is invoked, disable cache about whether any @host
 89 @-rules match the shadow root's host, because all shadow elements in
 90 the shadow dom subtree might be removed or a new shadow element might
 91 be inserted into the subtree.
 92 * dom/ShadowRoot.h:
 93 (WebCore::ShadowRoot::registerShadowElement):
 94 (WebCore::ShadowRoot::unregisterShadowElement):
 95 (WebCore::ShadowRoot::hasShadowInsertionPoint):
 96 Added a new member variable, which is a number of shadow elements.
 97 If a shadow element is added to some shadow dom tree, the shadow root
 98 of the tree's register will be invoked. If removed, unregister will be
 99 invoked. hasShadowInsertionPoint quickly returns whether there exists
 100 any shadow element in the shadow dom subtree.
 101 (ShadowRoot):
 102 * html/shadow/HTMLShadowElement.cpp:
 103 (WebCore::HTMLShadowElement::HTMLShadowElement):
 104 (WebCore::HTMLShadowElement::insertedInto):
 105 Invoke registerShadowElement.
 106 (WebCore):
 107 (WebCore::HTMLShadowElement::removedFrom):
 108 Invoke unregisterShadowElement.
 109 * html/shadow/HTMLShadowElement.h:
 110
11112012-09-02 Benjamin Poulain <bpoulain@apple.com>
2112
3113 Improve the way we use convertedSpaceString() in convertHTMLTextToInterchangeFormat()

Source/WebCore/css/CSSGrammar.y

@@static inline int cssyyerror(void*, const char*)
127127%token PAGE_SYM
128128%token MEDIA_SYM
129129%token FONT_FACE_SYM
 130%token HOST_SYM
130131%token CHARSET_SYM
131132%token NAMESPACE_SYM
132133%token VARFUNCTION

@@static inline int cssyyerror(void*, const char*)
214215%type <rule> page
215216%type <rule> margin_box
216217%type <rule> font_face
 218%type <rule> host
217219%type <rule> keyframes
218220%type <rule> invalid_rule
219221%type <rule> save_block

@@valid_rule:
414416 | namespace
415417 | import
416418 | region
 419 | host
417420 ;
418421
419422rule:

@@font_face:
836839 }
837840;
838841
 842before_host_rule:
 843 /* empty */ {
 844 parser->markRuleHeaderStart(CSSRuleSourceData::HOST_RULE);
 845 }
 846 ;
 847
 848host:
 849 before_host_rule HOST_SYM at_rule_header_end_maybe_space
 850 '{' at_rule_body_start maybe_space block_rule_list save_block {
 851 $$ = parser->createHostRule($7);
 852 }
 853 | before_host_rule HOST_SYM at_rule_header_end_maybe_space ';' {
 854 $$ = 0;
 855 parser->popRuleData();
 856 }
 857 ;
 858
839859region_selector:
840860 selector_list {
841861 if ($1) {

Source/WebCore/css/CSSParser.cpp

@@inline void CSSParser::detectAtToken(int length, bool hasEscape)
92029202 m_token = FONT_FACE_SYM;
92039203 return;
92049204
 9205 case 'h':
 9206 if (length == 5 && isEqualToCSSIdentifier(name + 2, "ost"))
 9207 m_token = HOST_SYM;
 9208 return;
 9209
92059210 case 'i':
92069211 if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
92079212 m_parsingMode = MediaQueryMode;

@@StyleRuleBase* CSSParser::createFontFaceRule()
99909995 return result;
99919996}
99929997
 9998StyleRuleBase* CSSParser::createHostRule(RuleList* rules)
 9999{
 10000 m_allowImportRules = m_allowNamespaceDeclarations = false;
 10001 RefPtr<StyleRuleHost> rule;
 10002 if (rules)
 10003 rule = StyleRuleHost::create(*rules);
 10004 else {
 10005 RuleList emptyRules;
 10006 rule = StyleRuleHost::create(emptyRules);
 10007 }
 10008 StyleRuleHost* result = rule.get();
 10009 m_parsedRules.append(rule.release());
 10010 processAndAddNewRuleToSourceTreeIfNeeded();
 10011 return result;
 10012}
 10013
999310014void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
999410015{
999510016 if (!m_styleSheet || !m_allowNamespaceDeclarations)

Source/WebCore/css/CSSParser.h

@@public:
280280 StyleRuleBase* createPageRule(PassOwnPtr<CSSParserSelector> pageSelector);
281281 StyleRuleBase* createRegionRule(CSSSelectorVector* regionSelector, RuleList* rules);
282282 StyleRuleBase* createMarginAtRule(CSSSelector::MarginBoxType);
 283 StyleRuleBase* createHostRule(RuleList* rules);
283284 void startDeclarationsForMarginBox();
284285 void endDeclarationsForMarginBox();
285286

Source/WebCore/css/CSSPropertySourceData.h

@@struct CSSRuleSourceData : public RefCounted<CSSRuleSourceData> {
9494 FONT_FACE_RULE,
9595 PAGE_RULE,
9696 KEYFRAMES_RULE,
97  REGION_RULE
 97 REGION_RULE,
 98 HOST_RULE
9899 };
99100
100101 static PassRefPtr<CSSRuleSourceData> create(Type type)

Source/WebCore/css/StyleResolver.cpp

6060#include "Counter.h"
6161#include "CounterContent.h"
6262#include "CursorList.h"
 63#include "ElementShadow.h"
6364#include "FontFeatureValue.h"
6465#include "FontValue.h"
6566#include "Frame.h"

@@void StyleResolver::appendAuthorStylesheets(unsigned firstNew, const Vector<RefP
576577}
577578
578579#if ENABLE(STYLE_SCOPED)
 580void StyleResolver::addHostRule(StyleRuleHost* hostRule, bool hasDocumentSecurityOrigin, const ContainerNode* scope)
 581{
 582 if (!scope || !scope->isInShadowTree())
 583 return;
 584
 585 ShadowRoot* shadowRoot = scope->shadowRoot();
 586 if (!shadowRoot || !shadowRoot->host())
 587 return;
 588 shadowRoot->owner()->clearHasMatchedHostRule();
 589
 590 ScopedRuleSetMap::AddResult addResult = m_atHostRules.add(shadowRoot, nullptr);
 591 if (addResult.isNewEntry)
 592 addResult.iterator->second = RuleSet::create();
 593
 594 const Vector<RefPtr<StyleRuleBase> >& childRules = hostRule->childRules();
 595 for (unsigned i = 0; i < childRules.size(); ++i) {
 596 StyleRuleBase* hostStylingRule = childRules[i].get();
 597 if (hostStylingRule->isStyleRule())
 598 addResult.iterator->second->addStyleRule(static_cast<StyleRule*>(hostStylingRule), hasDocumentSecurityOrigin, true, false);
 599 }
 600}
 601
579602void StyleResolver::setupScopeStack(const ContainerNode* parent)
580603{
581604 // The scoping element stack shouldn't be used if <style scoped> isn't used anywhere.

@@void StyleResolver::collectMatchingRulesForRegion(RuleSet* rules, int& firstRule
921944 }
922945}
923946
924 void StyleResolver::sortAndTransferMatchedRules(MatchResult& result)
 947void StyleResolver::transferMatchedRules(MatchResult& result)
925948{
926  if (m_matchedRules.isEmpty())
927  return;
928 
929  sortMatchedRules();
930 
931949 if (m_checker.mode() == SelectorChecker::CollectingRules) {
932950 if (!m_ruleList)
933951 m_ruleList = StaticCSSRuleList::create();

@@void StyleResolver::sortAndTransferMatchedRules(MatchResult& result)
949967 }
950968}
951969
 970void StyleResolver::sortAndTransferMatchedRules(MatchResult& result)
 971{
 972 if (m_matchedRules.isEmpty())
 973 return;
 974
 975 sortMatchedRules();
 976 transferMatchedRules(result);
 977}
 978
952979void StyleResolver::matchScopedAuthorRules(MatchResult& result, bool includeEmptyRules)
953980{
954981#if ENABLE(STYLE_SCOPED)

@@void StyleResolver::matchScopedAuthorRules(MatchResult& result, bool includeEmpt
9961023#endif
9971024}
9981025
 1026#if ENABLE(STYLE_SCOPED)
 1027inline RuleSet* StyleResolver::atHostRuleSetForScope(const ShadowRoot* shadowRoot)
 1028{
 1029 ScopedRuleSetMap::const_iterator it = m_atHostRules.find(shadowRoot);
 1030 return it != m_atHostRules.end() ? it->second.get() : 0;
 1031}
 1032
 1033bool StyleResolver::matchesHostRules()
 1034{
 1035 if (m_atHostRules.isEmpty())
 1036 return false;
 1037
 1038 ElementShadow* shadow = m_element->shadow();
 1039 if (!shadow)
 1040 return false;
 1041 if (shadow->hasMatchedHostRuleAvailable())
 1042 return shadow->hasMatchedHostRule();
 1043
 1044 for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
 1045 if (atHostRuleSetForScope(shadowRoot)) {
 1046 shadow->setHasMatchedHostRule(true);
 1047 return true;
 1048 }
 1049 if (!shadowRoot->hasShadowInsertionPoint())
 1050 break;
 1051 }
 1052 shadow->setHasMatchedHostRule(false);
 1053 return false;
 1054}
 1055#endif
 1056
 1057void StyleResolver::matchHostRules(MatchResult& result, bool includeEmptyRules)
 1058{
 1059#if ENABLE(STYLE_SCOPED)
 1060 if (m_atHostRules.isEmpty())
 1061 return;
 1062
 1063 ElementShadow* shadow = m_element->shadow();
 1064 if (!shadow)
 1065 return;
 1066 // If Already know whether there exist any matched host rules or not, see.
 1067 if (shadow->hasMatchedHostRuleAvailable() && !shadow->hasMatchedHostRule())
 1068 return;
 1069
 1070 Vector<RuleSet*, 16> matchedRules;
 1071 for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
 1072 if (RuleSet* ruleSet = atHostRuleSetForScope(shadowRoot))
 1073 matchedRules.append(ruleSet);
 1074 if (!shadowRoot->hasShadowInsertionPoint())
 1075 break;
 1076 }
 1077 if (matchedRules.isEmpty())
 1078 return;
 1079
 1080 MatchOptions options(includeEmptyRules);
 1081 options.scope = m_element;
 1082 for (unsigned i = matchedRules.size(); i > 0; --i)
 1083 collectMatchingRules(matchedRules.at(i-1), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
 1084#else
 1085 UNUSED_PARAM(result);
 1086 UNUSED_PARAM(includeEmptyRules);
 1087#endif
 1088}
 1089
9991090void StyleResolver::matchAuthorRules(MatchResult& result, bool includeEmptyRules)
10001091{
10011092 m_matchedRules.clear();

@@void StyleResolver::matchAuthorRules(MatchResult& result, bool includeEmptyRules
10101101 collectMatchingRulesForRegion(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
10111102
10121103 matchScopedAuthorRules(result, includeEmptyRules);
 1104 if (!m_matchedRules.isEmpty())
 1105 sortMatchedRules();
10131106
1014  sortAndTransferMatchedRules(result);
 1107 matchHostRules(result, includeEmptyRules);
 1108 if (!m_matchedRules.isEmpty())
 1109 transferMatchedRules(result);
10151110}
10161111
10171112void StyleResolver::matchUserRules(MatchResult& result, bool includeEmptyRules)

@@RenderStyle* StyleResolver::locateSharedStyle()
15751670 // Can't share if attribute rules apply.
15761671 if (matchesRuleSet(m_uncommonAttributeRuleSet.get()))
15771672 return 0;
 1673#if ENABLE(STYLE_SCOPED)
 1674 // Can't share if @host @-rules apply.
 1675 if (matchesHostRules())
 1676 return 0;
 1677#endif
15781678 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
15791679 if (parentStylePreventsSharing(m_parentStyle))
15801680 return 0;

@@void RuleSet::addRulesFromSheet(StyleSheetContents* sheet, const MediaQueryEvalu
27772877 addRegionRule(static_cast<StyleRuleRegion*>(rule), hasDocumentSecurityOrigin);
27782878 }
27792879#endif
 2880#if ENABLE(STYLE_SCOPED)
 2881 else if (rule->isHostRule())
 2882 resolver->addHostRule(static_cast<StyleRuleHost*>(rule), hasDocumentSecurityOrigin, scope);
 2883#endif
27802884 }
27812885 if (m_autoShrinkToFitEnabled)
27822886 shrinkToFit();

Source/WebCore/css/StyleResolver.h

@@class RenderRegion;
7272class RuleData;
7373class RuleSet;
7474class Settings;
 75class ShadowRoot;
7576class StaticCSSRuleList;
7677class StyleBuilder;
7778class StyleImage;

@@class StyleRule;
8283class StyleRuleKeyframes;
8384class StyleRulePage;
8485class StyleRuleRegion;
 86class StyleRuleHost;
8587class StyleShader;
8688class StyleSheet;
8789class StyleSheetContents;

@@public:
136138 void popParentElement(Element*);
137139 void pushParentShadowRoot(const ShadowRoot*);
138140 void popParentShadowRoot(const ShadowRoot*);
 141 void addHostRule(StyleRuleHost*, bool, const ContainerNode*);
139142
140143 PassRefPtr<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, StyleSharingBehavior = AllowStyleSharing,
141144 RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = 0);

@@private:
360363 void matchAuthorRules(MatchResult&, bool includeEmptyRules);
361364 void matchUserRules(MatchResult&, bool includeEmptyRules);
362365 void matchScopedAuthorRules(MatchResult&, bool includeEmptyRules);
 366 void matchHostRules(MatchResult&, bool includeEmptyRules);
363367 void collectMatchingRules(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
364368 void collectMatchingRulesForRegion(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
365369 void collectMatchingRulesForList(const Vector<RuleData>*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
 370 void collectMatchingRulesForHost(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
366371 bool fastRejectSelector(const RuleData&) const;
367372 void sortMatchedRules();
 373 void transferMatchedRules(MatchResult&);
368374 void sortAndTransferMatchedRules(MatchResult&);
369375
370376 bool checkSelector(const RuleData&, const ContainerNode* scope = 0);

@@private:
544550 // This is used to decide whether m_scopingElementStack is consistent, separately from SelectorChecker::m_parentStack.
545551 const ContainerNode* m_scopeStackParent;
546552 int m_scopeStackParentBoundsIndex;
 553
 554 ScopedRuleSetMap m_atHostRules;
 555 RuleSet* atHostRuleSetForScope(const ShadowRoot*);
 556 bool matchesHostRules();
547557#endif
548558
549559 CSSToStyleMap m_styleMap;

Source/WebCore/css/StyleRule.cpp

@@void StyleRuleBase::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
7878 case Keyframes:
7979 static_cast<const StyleRuleKeyframes*>(this)->reportDescendantMemoryUsage(memoryObjectInfo);
8080 return;
 81 case Host:
 82 static_cast<const StyleRuleBlock*>(this)->reportDescendantMemoryUsage(memoryObjectInfo);
 83 return;
8184 case Unknown:
8285 case Charset:
8386 case Keyframe:

@@void StyleRuleBase::destroy()
113116 case Keyframes:
114117 delete static_cast<StyleRuleKeyframes*>(this);
115118 return;
 119 case Host:
 120 delete static_cast<StyleRuleHost*>(this);
 121 return;
116122 case Unknown:
117123 case Charset:
118124 case Keyframe:

@@PassRefPtr<StyleRuleBase> StyleRuleBase::copy() const
146152 return 0;
147153 case Keyframes:
148154 return static_cast<const StyleRuleKeyframes*>(this)->copy();
 155 case Host:
 156 return static_cast<const StyleRuleHost*>(this)->copy();
149157 case Unknown:
150158 case Charset:
151159 case Keyframe:

@@PassRefPtr<CSSRule> StyleRuleBase::createCSSOMWrapper(CSSStyleSheet* parentSheet
187195 case Keyframes:
188196 rule = WebKitCSSKeyframesRule::create(static_cast<StyleRuleKeyframes*>(self), parentSheet);
189197 break;
 198 case Host:
190199 case Unknown:
191200 case Charset:
192201 case Keyframe:

@@void StyleRuleRegion::reportDescendantMemoryUsage(MemoryObjectInfo* memoryObject
377386 info.addInstrumentedMember(m_selectorList);
378387}
379388
 389StyleRuleHost::StyleRuleHost(Vector<RefPtr<StyleRuleBase> >& adoptRules)
 390 : StyleRuleBlock(Host, adoptRules)
 391{
 392}
 393
 394StyleRuleHost::StyleRuleHost(const StyleRuleHost& o)
 395 : StyleRuleBlock(o)
 396{
 397}
 398
380399} // namespace WebCore

Source/WebCore/css/StyleRule.h

@@public:
4646 Page,
4747 Keyframes,
4848 Keyframe, // Not used. These are internally non-rule StyleKeyframe objects.
 49 Host,
4950 Region = 16
5051 };
5152 Type type() const { return static_cast<Type>(m_type); }

@@public:
5859 bool isStyleRule() const { return type() == Style; }
5960 bool isRegionRule() const { return type() == Region; }
6061 bool isImportRule() const { return type() == Import; }
 62 bool isHostRule() const { return type() == Host; }
6163
6264 PassRefPtr<StyleRuleBase> copy() const;
6365

@@private:
222224 CSSSelectorList m_selectorList;
223225};
224226
 227class StyleRuleHost : public StyleRuleBlock {
 228 public:
 229 static PassRefPtr<StyleRuleHost> create(Vector<RefPtr<StyleRuleBase> >& adoptRules)
 230 {
 231 return adoptRef(new StyleRuleHost(adoptRules));
 232 }
 233
 234 PassRefPtr<StyleRuleHost> copy() const { return adoptRef(new StyleRuleHost(*this)); }
 235
 236 private:
 237 StyleRuleHost(Vector<RefPtr<StyleRuleBase> >& adoptRules);
 238 StyleRuleHost(const StyleRuleHost&);
 239};
 240
225241} // namespace WebCore
226242
227243#endif // StyleRule_h

Source/WebCore/css/StyleSheetContents.cpp

@@static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<Style
444444 if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleRegion*>(rule)->childRules()))
445445 return true;
446446 break;
 447 case StyleRuleBase::Host:
 448 if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleHost*>(rule)->childRules()))
 449 return true;
 450 break;
447451 case StyleRuleBase::Import:
448452 ASSERT_NOT_REACHED();
449453 case StyleRuleBase::Page:

Source/WebCore/dom/ElementShadow.cpp

3939namespace WebCore {
4040
4141ElementShadow::ElementShadow()
 42 : m_hasMatchedHostRuleAvailable(false)
4243{
4344}
4445

@@void ElementShadow::addShadowRoot(Element* shadowHost, PassRefPtr<ShadowRoot> sh
8990 if (shadowHost->attached())
9091 shadowHost->lazyReattach();
9192
 93 // As a new shadow dom subtree might have @host @-rules, need to disable
 94 // hasMatchedHostRules cache.
 95 clearHasMatchedHostRule();
 96
9297 InspectorInstrumentation::didPushShadowRoot(shadowHost, shadowRoot.get());
9398}
9499

Source/WebCore/dom/ElementShadow.h

@@public:
7070 ContentDistributor& distributor();
7171 const ContentDistributor& distributor() const;
7272
 73 bool hasMatchedHostRule() const { return m_hasMatchedHostRule; }
 74 bool hasMatchedHostRuleAvailable() const { return m_hasMatchedHostRuleAvailable; }
 75 void clearHasMatchedHostRule() { m_hasMatchedHostRuleAvailable = false; }
 76 void setHasMatchedHostRule(bool hasRule) { m_hasMatchedHostRule = hasRule; m_hasMatchedHostRuleAvailable = true; }
 77
7378private:
7479 void invalidateDistribution(Element* host);
7580
7681 DoublyLinkedList<ShadowRoot> m_shadowRoots;
7782 ContentDistributor m_distributor;
 83 bool m_hasMatchedHostRule;
 84 bool m_hasMatchedHostRuleAvailable;
7885 WTF_MAKE_NONCOPYABLE(ElementShadow);
7986};
8087

Source/WebCore/dom/ShadowRoot.cpp

@@ShadowRoot::ShadowRoot(Document* document)
5555 , m_applyAuthorStyles(false)
5656 , m_resetStyleInheritance(false)
5757 , m_insertionPointAssignedTo(0)
 58 , m_numberOfShadowElementChildren(0)
5859{
5960 ASSERT(document);
6061

@@void ShadowRoot::childrenChanged(bool changedByParser, Node* beforeChange, Node*
228229{
229230 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
230231 owner()->invalidateDistribution();
 232 owner()->clearHasMatchedHostRule();
231233}
232234
233235}

Source/WebCore/dom/ShadowRoot.h

@@public:
8989 InsertionPoint* assignedTo() const;
9090 void setAssignedTo(InsertionPoint*);
9191
 92 void registerShadowElement() { ++m_numberOfShadowElementChildren; }
 93 void unregisterShadowElement() { --m_numberOfShadowElementChildren; }
 94 bool hasShadowInsertionPoint() const { return m_numberOfShadowElementChildren > 0; }
 95
9296#ifndef NDEBUG
9397 ShadowRootType type() const { return m_type; }
9498#endif

@@private:
106110 bool m_applyAuthorStyles : 1;
107111 bool m_resetStyleInheritance : 1;
108112 InsertionPoint* m_insertionPointAssignedTo;
 113 size_t m_numberOfShadowElementChildren;
109114
110115#ifndef NDEBUG
111116 ShadowRootType m_type;

Source/WebCore/html/shadow/HTMLShadowElement.cpp

@@class Document;
4141
4242inline HTMLShadowElement::HTMLShadowElement(const QualifiedName& tagName, Document* document)
4343 : InsertionPoint(tagName, document)
 44 , m_registeredWithShadowRoot(false)
4445{
4546 ASSERT(hasTagName(HTMLNames::shadowTag));
4647}

@@bool HTMLShadowElement::doesSelectFromHostChildren() const
6869 return false;
6970}
7071
 72Node::InsertionNotificationRequest HTMLShadowElement::insertedInto(ContainerNode* insertionPoint)
 73{
 74 InsertionPoint::insertedInto(insertionPoint);
 75
 76 if (insertionPoint->inDocument() && isActive()) {
 77 if (ShadowRoot* root = shadowRoot()) {
 78 root->registerShadowElement();
 79 m_registeredWithShadowRoot = true;
 80 }
 81 }
 82
 83 return InsertionDone;
 84}
 85
 86void HTMLShadowElement::removedFrom(ContainerNode* insertionPoint)
 87{
 88 if (insertionPoint->inDocument() && m_registeredWithShadowRoot) {
 89 ShadowRoot* root = shadowRoot();
 90 if (!root)
 91 root = insertionPoint->shadowRoot();
 92 if (root)
 93 root->unregisterShadowElement();
 94 m_registeredWithShadowRoot = false;
 95 }
 96 InsertionPoint::removedFrom(insertionPoint);
 97}
 98
7199} // namespace WebCore

Source/WebCore/html/shadow/HTMLShadowElement.h

@@public:
4646 bool isSelectValid() const OVERRIDE { return true; }
4747 bool doesSelectFromHostChildren() const;
4848
 49protected:
 50 virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
 51 virtual void removedFrom(ContainerNode*) OVERRIDE;
 52
4953private:
5054 HTMLShadowElement(const QualifiedName&, Document*);
 55
 56 bool m_registeredWithShadowRoot;
5157};
5258
5359} // namespace WebCore

LayoutTests/ChangeLog

 12012-09-02 Takashi Sakamoto <tasak@google.com>
 2
 3 [Shadow DOM] Needs @host rule for ShadowDOM styling
 4 https://bugs.webkit.org/show_bug.cgi?id=88606
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * fast/dom/shadow/athost-atrules-expected.txt: Added.
 9 * fast/dom/shadow/athost-atrules.html: Added.
 10
1112012-09-02 Yoshifumi Inoue <yosin@chromium.org>
212
313 [Tests] fast/forms/time-multiple-fields/time-multiple-fields-appearance-*.html should dump text instead of render tree

LayoutTests/fast/dom/shadow/athost-atrules-expected.txt

 1host: rgb(255, 0, 0)
 2host: rgb(255, 0, 0)
 3hostA: rgb(255, 0, 0)
 4hostB: rgb(0, 0, 255)
 5host: rgb(0, 0, 255)
 6host: rgb(128, 128, 128)
 7host: rgb(0, 0, 255)
 8host: rgb(0, 0, 255)
 9host: rgb(128, 128, 128)
 10host: rgb(255, 255, 0)
 11host: rgb(255, 0, 0)
 12nestedHost: rgb(0, 0, 255)
 13host: rgb(255, 0, 0)
 14host: rgb(255, 255, 0)
 15Hello

LayoutTests/fast/dom/shadow/athost-atrules.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<style>
 5#host {
 6 color: gray;
 7}
 8</style>
 9<script src="../../js/resources/js-test-pre.js"></script>
 10<script src="resources/polyfill.js"></script>
 11<script>
 12function dumpComputedStyle(node)
 13{
 14 debug(node.id + ": " + document.defaultView.getComputedStyle(node, null).getPropertyValue('color'));
 15}
 16
 17function preprocessForTest()
 18{
 19 var parent = document.getElementById("parent");
 20 parent.innerHTML = '<div id="host"><span>Hello</span></div>';
 21}
 22
 23function testSimpleContentCase()
 24{
 25 preprocessForTest();
 26 var host = document.getElementById("host");
 27 var shadow = new WebKitShadowRoot(host);
 28 shadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 29 dumpComputedStyle(host);
 30}
 31
 32function testSimpleShadowCase()
 33{
 34 preprocessForTest();
 35 var host = document.getElementById("host");
 36 var shadow = new WebKitShadowRoot(host);
 37 shadow.innerHTML = "<style>@host { div { color: red; } }</style><shadow></shadow>";
 38 dumpComputedStyle(host);
 39}
 40
 41function testHostWithSelector()
 42{
 43 var parent = document.getElementById("parent");
 44 parent.innerHTML = "<style scoped> .host { color: gray };</style>"
 45 + "<div id='hostA' class='host'><span>Hello</span></div>"
 46 + "<span id='hostB' class='host'><span>World</span></span>";
 47
 48 var hostA = document.getElementById("hostA");
 49 var shadowA = new WebKitShadowRoot(hostA);
 50 var style = "<style>@host { div { color: red; } span { color: blue; } }</style>";
 51 shadowA.innerHTML = style + "<shadow></shadow>";
 52
 53 var hostB = document.getElementById("hostB");
 54 var shadowB = new WebKitShadowRoot(hostB);
 55 shadowB.innerHTML = style + "<shadow></shadow>";
 56
 57 dumpComputedStyle(hostA);
 58 dumpComputedStyle(hostB);
 59}
 60
 61function testPseudoHostWithScoped()
 62{
 63 preprocessForTest();
 64 var host = document.getElementById("host");
 65 var shadow = new WebKitShadowRoot(host);
 66 shadow.innerHTML = "<div><style scoped>@host { div { color: red; } }</style><shadow></shadow><div><style scoped>@host { div { color: blue; } }</style></div></div>";
 67 dumpComputedStyle(host);
 68}
 69
 70function testPseudoHostWithFallbackShadow()
 71{
 72 preprocessForTest();
 73 var host = document.getElementById("host");
 74 var oldestShadow = new WebKitShadowRoot(host);
 75 var youngestShadow = new WebKitShadowRoot(host);
 76 oldestShadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 77 youngestShadow.innerHTML = "<content><shadow></shadow></content>";
 78 dumpComputedStyle(host);
 79}
 80
 81function testTwoShadowRootsCase()
 82{
 83 preprocessForTest();
 84 var host = document.getElementById("host");
 85 var oldestShadow = new WebKitShadowRoot(host);
 86 var youngestShadow = new WebKitShadowRoot(host);
 87 oldestShadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 88 youngestShadow.innerHTML = "<style>@host { div { color: blue; } }</style><shadow></shadow>";
 89 dumpComputedStyle(host);
 90}
 91
 92function testTwoShadowRootsCreatingDifferentOrderCase()
 93{
 94 preprocessForTest();
 95 var host = document.getElementById("host");
 96 var oldestShadow = new WebKitShadowRoot(host);
 97 var youngestShadow = new WebKitShadowRoot(host);
 98 youngestShadow.innerHTML = "<style>@host { div { color: blue; } }</style><shadow></shadow>";
 99 oldestShadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 100 dumpComputedStyle(host);
 101}
 102
 103function testMultipleShadowRootsWithInertShadowContent()
 104{
 105 preprocessForTest();
 106 var host = document.getElementById("host");
 107 var oldestShadow = new WebKitShadowRoot(host);
 108 var olderShadow = new WebKitShadowRoot(host);
 109 var youngerShadow = new WebKitShadowRoot(host);
 110 var youngestShadow = new WebKitShadowRoot(host);
 111
 112 youngestShadow.innerHTML = "<shadow></shadow>";
 113 youngerShadow.innerHTML = "<content></content>";
 114 olderShadow.innerHTML = "<style>@host { div { color: green; } }</style><shadow></shadow>";
 115 oldestShadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 116 dumpComputedStyle(host);
 117}
 118
 119function testMultipleShadowRootsWithInertShadow()
 120{
 121 preprocessForTest();
 122 var host = document.getElementById("host");
 123 var oldestShadow = new WebKitShadowRoot(host);
 124 var olderShadow = new WebKitShadowRoot(host);
 125 var youngerShadow = new WebKitShadowRoot(host);
 126 var youngestShadow = new WebKitShadowRoot(host);
 127
 128 youngestShadow.innerHTML = "<style>@host { div { color: yellow; } }</style><shadow></shadow>";
 129 youngerShadow.innerHTML = "<style>@host { div { color: blue; } }</style><div>inert</div>";
 130 olderShadow.innerHTML = "<style>@host { div { color: green; } }</style><shadow></shadow>";
 131 oldestShadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 132 dumpComputedStyle(host);
 133}
 134
 135function testNestedCase()
 136{
 137 preprocessForTest();
 138 var host = document.getElementById("host");
 139 var outerShadow = new WebKitShadowRoot(host);
 140 outerShadow.innerHTML = '<style>@host { div { color: red; } }</style><div id="nestedHost">InnerShadow</div>';
 141 var nested = outerShadow.getElementById("nestedHost");
 142 var innerShadow = new WebKitShadowRoot(nested);
 143 innerShadow.innerHTML = '<style>@host { div { color: blue; } }</style>Show <shadow></shadow> in outer.';
 144 dumpComputedStyle(host);
 145 dumpComputedStyle(nested);
 146}
 147
 148function testHostVsScopedStyle()
 149{
 150 preprocessForTest();
 151 var host = document.getElementById("host");
 152 host.innerHTML = "<style scoped>#host { color: yellow; }</style><span>Hello</span>";
 153 var shadow = new WebKitShadowRoot(host);
 154 shadow.innerHTML = "<style>@host { #host { color: red; } }</style><content></content>";
 155 dumpComputedStyle(host);
 156}
 157
 158function testHostVsInlineStyle()
 159{
 160 preprocessForTest();
 161 var host = document.getElementById("host");
 162 host.style.color = "yellow";
 163 host.innerHTML = "<span>Hello</span>";
 164 var shadow = new WebKitShadowRoot(host);
 165 shadow.innerHTML = "<style>@host { div { color: red; } }</style><content></content>";
 166 dumpComputedStyle(host);
 167}
 168
 169function runTests()
 170{
 171 testSimpleContentCase();
 172 testSimpleShadowCase();
 173 testHostWithSelector();
 174 testPseudoHostWithScoped();
 175 testPseudoHostWithFallbackShadow();
 176 testTwoShadowRootsCase();
 177 testTwoShadowRootsCreatingDifferentOrderCase();
 178 testMultipleShadowRootsWithInertShadowContent();
 179 testMultipleShadowRootsWithInertShadow();
 180 testNestedCase();
 181 testHostVsScopedStyle();
 182 testHostVsInlineStyle();
 183}
 184</script>
 185</head>
 186<body onload="runTests()">
 187 <div id="parent">
 188 </div>
 189</body>
 190</html>