Source/WebCore/ChangeLog

 12012-09-20 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 * css/CSSParser.h:
 24 Added a declaration of the above new method: createHostRule.
 25 * css/CSSPropertySourceData.h:
 26 Added HOST_RULE to enum Type.
 27 * css/StyleResolver.cpp:
 28 (WebCore::RuleData::increaseSpecificity):
 29 Added a new method to increase selector's specificity. This method is
 30 used to make @host @-rules' specificity larger than normal author
 31 rules' specificity.
 32 (RuleData):
 33 (WebCore::RuleSet::addStyleRule):
 34 (WebCore::RuleSet::addRule):
 35 Added one more argument to addStyleRule and addRule. The argument is
 36 used to know whether the given style rule comes from @host @-rules or
 37 not. If the rule comes from @shot @-rules, use increaseSpecificity and
 38 make the rule apply after rules (not @host @-rules) are applied.
 39 (WebCore::RuleSet::addRulesFromSheet):
 40 If @host @-rules are found in the given stylesheet content, invoke
 41 StyleResolver's addHostRule to register the @host @-rules with the
 42 shadow root, which has the stylesheet.
 43 (WebCore::StyleResolver::addHostRule):
 44 Added a new method to register @host @-rules with shadow roots.
 45 (WebCore):
 46 (WebCore::StyleResolver::atHostRuleSetForScope):
 47 Added a new method for finding rulesets from the given shadow root.
 48 (WebCore::StyleResolver::matchesHostRules):
 49 A new method to check whether any @host @-rules will be applied to
 50 the given element or not. This is prepared for shared styles.
 51 (WebCore::StyleResolver::matchHostRules):
 52 A new method to find matched host rules when an element is given.
 53 (WebCore::StyleResolver::matchAuthorRules):
 54 Modified to invoke matchHostRules.
 55 (WebCore::StyleResolver::locateSharedStyle):
 56 Disable sibling style cache if the given element is a shadow host and
 57 any @host @-rules are applied to the element.
 58 * css/StyleResolver.h:
 59 (StyleResolver):
 60 * css/StyleRule.cpp:
 61 (WebCore::StyleRuleBase::reportMemoryUsage):
 62 (WebCore::StyleRuleBase::destroy):
 63 (WebCore::StyleRuleBase::copy):
 64 (WebCore::StyleRuleBase::createCSSOMWrapper):
 65 (WebCore::StyleRuleHost::StyleRuleHost):
 66 (WebCore):
 67 Implemented class StyleRuleHost. The class is almost the same as
 68 StyleRuleBlock except type.
 69 * css/StyleRule.h:
 70 (WebCore::StyleRuleBase::isHostRule):
 71 (StyleRuleHost):
 72 (WebCore::StyleRuleHost::create):
 73 (WebCore::StyleRuleHost::copy):
 74 (WebCore):
 75 * css/StyleSheetContents.cpp:
 76 (WebCore::childRulesHaveFailedOrCanceledSubresources):
 77 * dom/ElementShadow.cpp:
 78 (WebCore::ElementShadow::ElementShadow):
 79 (WebCore::ElementShadow::addShadowRoot):
 80 Since a new shadow root is added, disable @host @-rules cache.
 81 * dom/ElementShadow.h:
 82 (WebCore::ElementShadow::hasMatchedHostRule):
 83 (WebCore::ElementShadow::hasMatchedHostRuleAvailable):
 84 (WebCore::ElementShadow::clearHasMatchedHostRule):
 85 (WebCore::ElementShadow::setHasMatchedHostRule):
 86 Added four methods for @host @-rules cache. The cache has information
 87 about whether any @host @-rules match the ElementShadow's host.
 88 The return value of hasMatchedHostRule is available only if
 89 hasMatchedHostRuleAvailable returns true.
 90 (ElementShadow):
 91 * dom/ShadowRoot.cpp:
 92 (WebCore::ShadowRoot::ShadowRoot):
 93 (WebCore::ShadowRoot::childrenChanged):
 94 When childrenChanged is invoked, disable cache about whether any @host
 95 @-rules match the shadow root's host, because all shadow elements in
 96 the shadow dom subtree might be removed or a new shadow element might
 97 be inserted into the subtree.
 98 * dom/ShadowRoot.h:
 99 (WebCore::ShadowRoot::registerShadowElement):
 100 (WebCore::ShadowRoot::unregisterShadowElement):
 101 (WebCore::ShadowRoot::hasShadowInsertionPoint):
 102 (ShadowRoot):
 103 * html/shadow/HTMLShadowElement.cpp:
 104 (WebCore::HTMLShadowElement::HTMLShadowElement):
 105 (WebCore::HTMLShadowElement::insertedInto):
 106 (WebCore):
 107 (WebCore::HTMLShadowElement::removedFrom):
 108 * html/shadow/HTMLShadowElement.h:
 109 These changes will be removed, because the changes will be done in bug
 110 97814. Just required to make cq-bot run correctly before landing a
 111 patch for bug 97814.
 112
11132012-09-20 Adam Barth <abarth@webkit.org>
2114
3115 Measure how often web pages use Worker and SharedWorker

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)
92619261 m_token = FONT_FACE_SYM;
92629262 return;
92639263
 9264 case 'h':
 9265 if (length == 5 && isEqualToCSSIdentifier(name + 2, "ost"))
 9266 m_token = HOST_SYM;
 9267 return;
 9268
92649269 case 'i':
92659270 if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
92669271 m_parsingMode = MediaQueryMode;

@@StyleRuleBase* CSSParser::createFontFaceRule()
1004910054 return result;
1005010055}
1005110056
 10057StyleRuleBase* CSSParser::createHostRule(RuleList* rules)
 10058{
 10059 m_allowImportRules = m_allowNamespaceDeclarations = false;
 10060 RefPtr<StyleRuleHost> rule;
 10061 if (rules)
 10062 rule = StyleRuleHost::create(*rules);
 10063 else {
 10064 RuleList emptyRules;
 10065 rule = StyleRuleHost::create(emptyRules);
 10066 }
 10067 StyleRuleHost* result = rule.get();
 10068 m_parsedRules.append(rule.release());
 10069 processAndAddNewRuleToSourceTreeIfNeeded();
 10070 return result;
 10071}
 10072
1005210073void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
1005310074{
1005410075 if (!m_styleSheet || !m_allowNamespaceDeclarations)

Source/WebCore/css/CSSParser.h

@@public:
282282 StyleRuleBase* createPageRule(PassOwnPtr<CSSParserSelector> pageSelector);
283283 StyleRuleBase* createRegionRule(CSSSelectorVector* regionSelector, RuleList* rules);
284284 StyleRuleBase* createMarginAtRule(CSSSelector::MarginBoxType);
 285 StyleRuleBase* createHostRule(RuleList* rules);
285286 void startDeclarationsForMarginBox();
286287 void endDeclarationsForMarginBox();
287288

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"

@@public:
219220 bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
220221 bool isInRegionRule() const { return m_isInRegionRule; }
221222
 223 void increaseSpecificity(unsigned value) { m_specificity += value; }
 224
222225 // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
223226 static const unsigned maximumIdentifierCount = 4;
224227 const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }

@@public:
261264
262265 void addRulesFromSheet(StyleSheetContents*, const MediaQueryEvaluator&, StyleResolver* = 0, const ContainerNode* = 0);
263266
264  void addStyleRule(StyleRule*, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule = false);
265  void addRule(StyleRule*, unsigned selectorIndex, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule = false);
 267 void addStyleRule(StyleRule*, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule = false, bool isHostRule = false);
 268 void addRule(StyleRule*, unsigned selectorIndex, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule = false, bool isHostRule = false);
266269 void addPageRule(StyleRulePage*);
267270 void addToRuleSet(AtomicStringImpl* key, AtomRuleMap&, const RuleData&);
268271 void addRegionRule(StyleRuleRegion*, bool hasDocumentSecurityOrigin);

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

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

@@void StyleResolver::matchAuthorRules(MatchResult& result, bool includeEmptyRules
10131104 collectMatchingRulesForRegion(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
10141105
10151106 matchScopedAuthorRules(result, includeEmptyRules);
1016 
 1107 matchHostRules(result, includeEmptyRules);
10171108 sortAndTransferMatchedRules(result);
10181109}
10191110

@@RenderStyle* StyleResolver::locateSharedStyle()
15801671 // Can't share if attribute rules apply.
15811672 if (matchesRuleSet(m_uncommonAttributeRuleSet.get()))
15821673 return 0;
 1674
 1675 // Can't share if @host @-rules apply.
 1676 if (matchesHostRules())
 1677 return 0;
 1678
15831679 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
15841680 if (parentStylePreventsSharing(m_parentStyle))
15851681 return 0;

@@void RuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, const RuleDa
26442740 rules->append(ruleData);
26452741}
26462742
2647 void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool inRegionRule)
 2743void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool inRegionRule, bool isHostRule)
26482744{
26492745 RuleData ruleData(rule, selectorIndex, m_ruleCount++, hasDocumentSecurityOrigin, canUseFastCheckSelector, inRegionRule);
 2746 static const unsigned athostRuleBaseSpecificity = 0x100000;
 2747
 2748 if (isHostRule)
 2749 ruleData.increaseSpecificity(athostRuleBaseSpecificity);
 2750
26502751 collectFeaturesFromRuleData(m_features, ruleData);
26512752
26522753 CSSSelector* selector = ruleData.selector();

@@void RuleSet::addRulesFromSheet(StyleSheetContents* sheet, const MediaQueryEvalu
27842885 addRegionRule(static_cast<StyleRuleRegion*>(rule), hasDocumentSecurityOrigin);
27852886 }
27862887#endif
 2888#if ENABLE(STYLE_SCOPED)
 2889 else if (rule->isHostRule())
 2890 resolver->addHostRule(static_cast<StyleRuleHost*>(rule), hasDocumentSecurityOrigin, scope);
 2891#endif
27872892 }
27882893 if (m_autoShrinkToFitEnabled)
27892894 shrinkToFit();
27902895}
27912896
2792 void RuleSet::addStyleRule(StyleRule* rule, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule)
 2897void RuleSet::addStyleRule(StyleRule* rule, bool hasDocumentSecurityOrigin, bool canUseFastCheckSelector, bool isInRegionRule, bool isHostRule)
27932898{
27942899 for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = rule->selectorList().indexOfNextSelectorAfter(selectorIndex))
2795  addRule(rule, selectorIndex, hasDocumentSecurityOrigin, canUseFastCheckSelector, isInRegionRule);
 2900 addRule(rule, selectorIndex, hasDocumentSecurityOrigin, canUseFastCheckSelector, isInRegionRule, isHostRule);
27962901}
27972902
27982903static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map)

Source/WebCore/css/StyleResolver.h

@@class RenderRegion;
7171class RuleData;
7272class RuleSet;
7373class Settings;
 74class ShadowRoot;
7475class StaticCSSRuleList;
7576class StyleBuilder;
7677class StyleImage;

@@class StyleRule;
8182class StyleRuleKeyframes;
8283class StyleRulePage;
8384class StyleRuleRegion;
 85class StyleRuleHost;
8486class StyleShader;
8587class StyleSheet;
8688class StyleSheetContents;

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

@@private:
171174 void collectFeatures();
172175 RenderStyle* locateSharedStyle();
173176 bool matchesRuleSet(RuleSet*);
 177 bool matchesHostRules();
174178 Node* locateCousinList(Element* parent, unsigned& visitedNodeCount) const;
175179 StyledElement* findSiblingForStyleSharing(Node*, unsigned& count) const;
176180 bool canShareStyleWithElement(StyledElement*) const;

@@private:
358362 void matchAuthorRules(MatchResult&, bool includeEmptyRules);
359363 void matchUserRules(MatchResult&, bool includeEmptyRules);
360364 void matchScopedAuthorRules(MatchResult&, bool includeEmptyRules);
 365 void matchHostRules(MatchResult&, bool includeEmptyRules);
361366 void collectMatchingRules(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
362367 void collectMatchingRulesForRegion(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
363368 void collectMatchingRulesForList(const Vector<RuleData>*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
 369 void collectMatchingRulesForHost(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
364370 bool fastRejectSelector(const RuleData&) const;
365371 void sortMatchedRules();
366372 void sortAndTransferMatchedRules(MatchResult&);

@@private:
524530 typedef HashMap<const ContainerNode*, OwnPtr<RuleSet> > ScopedRuleSetMap;
525531
526532 RuleSet* ruleSetForScope(const ContainerNode*) const;
 533 RuleSet* atHostRuleSetForScope(const ShadowRoot*);
527534
528535 void setupScopeStack(const ContainerNode*);
529536 bool scopeStackIsConsistent(const ContainerNode* parent) const { return parent && parent == m_scopeStackParent; }
530537
531538 ScopedRuleSetMap m_scopedAuthorStyles;
 539 ScopedRuleSetMap m_atHostRules;
532540
533541 struct ScopeStackFrame {
534542 ScopeStackFrame() : m_scope(0), m_authorStyleBoundsIndex(0), m_ruleSet(0) { }

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()
116119 case Keyframes:
117120 delete static_cast<StyleRuleKeyframes*>(this);
118121 return;
 122 case Host:
 123 delete static_cast<StyleRuleHost*>(this);
 124 return;
119125 case Unknown:
120126 case Charset:
121127 case Keyframe:

@@PassRefPtr<StyleRuleBase> StyleRuleBase::copy() const
149155 return 0;
150156 case Keyframes:
151157 return static_cast<const StyleRuleKeyframes*>(this)->copy();
 158 case Host:
 159 return static_cast<const StyleRuleHost*>(this)->copy();
152160 case Unknown:
153161 case Charset:
154162 case Keyframe:

@@PassRefPtr<CSSRule> StyleRuleBase::createCSSOMWrapper(CSSStyleSheet* parentSheet
190198 case Keyframes:
191199 rule = WebKitCSSKeyframesRule::create(static_cast<StyleRuleKeyframes*>(self), parentSheet);
192200 break;
 201 case Host:
193202 case Unknown:
194203 case Charset:
195204 case Keyframe:

@@void StyleRuleRegion::reportDescendantMemoryUsage(MemoryObjectInfo* memoryObject
380389 info.addMember(m_selectorList);
381390}
382391
 392StyleRuleHost::StyleRuleHost(Vector<RefPtr<StyleRuleBase> >& adoptRules)
 393 : StyleRuleBlock(Host, adoptRules)
 394{
 395}
 396
 397StyleRuleHost::StyleRuleHost(const StyleRuleHost& o)
 398 : StyleRuleBlock(o)
 399{
 400}
 401
383402} // 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:
223225 CSSSelectorList m_selectorList;
224226};
225227
 228class StyleRuleHost : public StyleRuleBlock {
 229 public:
 230 static PassRefPtr<StyleRuleHost> create(Vector<RefPtr<StyleRuleBase> >& adoptRules)
 231 {
 232 return adoptRef(new StyleRuleHost(adoptRules));
 233 }
 234
 235 PassRefPtr<StyleRuleHost> copy() const { return adoptRef(new StyleRuleHost(*this)); }
 236
 237 private:
 238 StyleRuleHost(Vector<RefPtr<StyleRuleBase> >& adoptRules);
 239 StyleRuleHost(const StyleRuleHost&);
 240};
 241
226242} // namespace WebCore
227243
228244#endif // StyleRule_h

Source/WebCore/css/StyleSheetContents.cpp

@@static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<Style
433433 if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleRegion*>(rule)->childRules()))
434434 return true;
435435 break;
 436 case StyleRuleBase::Host:
 437 if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleHost*>(rule)->childRules()))
 438 return true;
 439 break;
436440 case StyleRuleBase::Import:
437441 ASSERT_NOT_REACHED();
438442 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:
7171 ContentDistributor& distributor();
7272 const ContentDistributor& distributor() const;
7373
 74 bool hasMatchedHostRule() const { return m_hasMatchedHostRule; }
 75 bool hasMatchedHostRuleAvailable() const { return m_hasMatchedHostRuleAvailable; }
 76 void clearHasMatchedHostRule() { m_hasMatchedHostRuleAvailable = false; }
 77 void setHasMatchedHostRule(bool hasRule) { m_hasMatchedHostRule = hasRule; m_hasMatchedHostRuleAvailable = true; }
 78
7479private:
7580 void invalidateDistribution(Element* host);
7681
7782 DoublyLinkedList<ShadowRoot> m_shadowRoots;
7883 ContentDistributor m_distributor;
 84 bool m_hasMatchedHostRule;
 85 bool m_hasMatchedHostRuleAvailable;
7986};
8087
8188inline ShadowRoot* ElementShadow::youngestShadowRoot() const

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*
223224{
224225 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
225226 owner()->invalidateDistribution();
 227 owner()->clearHasMatchedHostRule();
226228}
227229
228230}

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:
108112 bool m_applyAuthorStyles : 1;
109113 bool m_resetStyleInheritance : 1;
110114 InsertionPoint* m_insertionPointAssignedTo;
 115 size_t m_numberOfShadowElementChildren;
111116
112117#ifndef NDEBUG
113118 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-20 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-20 Kent Tamura <tkent@chromium.org>
212
313 [Win] Update test expectation

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>