Source/WebCore/ChangeLog

 12016-02-25 Antti Koivisto <antti@apple.com>
 2
 3 Implement ::slotted pseudo element
 4 https://bugs.webkit.org/show_bug.cgi?id=149441
 5 <rdar://problem/22731987>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 * css/CSSGrammar.y.in:
 10
 11 Parse ::slotted.
 12
 13 * css/CSSParser.cpp:
 14 (WebCore::CSSParser::detectFunctionTypeToken):
 15 * css/CSSParserValues.cpp:
 16 (WebCore::CSSParserSelector::parsePseudoElementCueFunctionSelector):
 17 (WebCore::CSSParserSelector::parsePseudoElementSlottedFunctionSelector):
 18
 19 Tokenize ::slotted.
 20
 21 (WebCore::CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector):
 22 * css/CSSParserValues.h:
 23 * css/CSSSelector.cpp:
 24 (WebCore::CSSSelector::pseudoId):
 25 * css/CSSSelector.h:
 26 * css/ElementRuleCollector.cpp:
 27 (WebCore::ElementRuleCollector::matchAuthorRules):
 28 (WebCore::ElementRuleCollector::matchHostPseudoClassRules):
 29 (WebCore::ElementRuleCollector::matchSlottedPseudoElementRules):
 30
 31 Match ::slotted selector.
 32
 33 (WebCore::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot):
 34
 35 Collect ::slotted rules that may apply to an element in a slot.
 36
 37 (WebCore::ElementRuleCollector::matchUserRules):
 38 (WebCore::ElementRuleCollector::matchUARules):
 39 (WebCore::findSlottedPseudoElementSelector):
 40 (WebCore::ElementRuleCollector::ruleMatches):
 41 * css/ElementRuleCollector.h:
 42 * css/RuleSet.cpp:
 43 (WebCore::RuleSet::addRule):
 44
 45 Collect ::slotted rules.
 46
 47 (WebCore::RuleSet::shrinkToFit):
 48 * css/RuleSet.h:
 49 (WebCore::RuleSet::hostPseudoClassRules):
 50 (WebCore::RuleSet::slottedPseudoElementRules):
 51 (WebCore::RuleSet::focusPseudoClassRules):
 52 (WebCore::RuleSet::universalRules):
 53 * css/SelectorChecker.cpp:
 54 (WebCore::SelectorChecker::checkOne):
 55 * style/StyleSharingResolver.cpp:
 56 (WebCore::Style::SharingResolver::resolve):
 57
 58 Disable style sharing for children of shadow host. They may be affected by the shadow tree style
 59 which is not considered in style sharing checks.
 60
1612016-02-25 Said Abou-Hallawa <sabouhallawa@apple.com>
262
363 REGRESSION (r196268): Many assertion failures and crashes on SVG path animation tests when JS garbage collection happens quickly
197127

Source/WebCore/css/CSSGrammar.y.in

@@static bool selectorListDoesNotMatchAnyP
365365
366366#endif
367367
 368#if ENABLE_SHADOW_DOM
 369
 370%token <string> SLOTTEDFUNCTION
 371
 372#endif
 373
368374%%
369375
370376stylesheet:

@@pseudo:
13571363 $$ = CSSParserSelector::parsePseudoElementCueFunctionSelector($3, $5);
13581364 }
13591365#endif
 1366#if ENABLE_SHADOW_DOM
 1367 | ':' ':' SLOTTEDFUNCTION maybe_space simple_selector_list maybe_space ')' {
 1368 $$ = CSSParserSelector::parsePseudoElementSlottedFunctionSelector($3, $5);
 1369 }
 1370#endif
13601371 // use by :-webkit-any.
13611372 // FIXME: should we support generic selectors here or just simple_selectors?
13621373 // Use simple_selector_list for now to match -moz-any.
197027

Source/WebCore/css/CSSParser.cpp

@@inline bool CSSParser::detectFunctionTyp
1189411894 m_token = MATCHESFUNCTION;
1189511895 return true;
1189611896 }
 11897#if ENABLE(SHADOW_DOM)
 11898 if (isEqualToCSSIdentifier(name, "slotted")) {
 11899 m_token = SLOTTEDFUNCTION;
 11900 return true;
 11901 }
 11902#endif
1189711903 return false;
11898 
1189911904 case 9:
1190011905 if (isEqualToCSSIdentifier(name, "nth-child")) {
1190111906 m_token = NTHCHILDFUNCTIONS;
197027

Source/WebCore/css/CSSParserValues.cpp

@@CSSParserSelector* CSSParserSelector::pa
231231}
232232#endif
233233
 234#if ENABLE(SHADOW_DOM)
 235CSSParserSelector* CSSParserSelector::parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>* parsedSelectorVector)
 236{
 237 ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "slotted(");
 238
 239 std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> selectorVector(parsedSelectorVector);
 240
 241 if (!selectorVector)
 242 return nullptr;
 243
 244 auto selector = std::make_unique<CSSParserSelector>();
 245 selector->m_selector->setMatch(CSSSelector::PseudoElement);
 246 selector->m_selector->setPseudoElementType(CSSSelector::PseudoElementSlotted);
 247 selector->adoptSelectorVector(*selectorVector);
 248 return selector.release();
 249}
 250#endif
 251
234252CSSParserSelector* CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString)
235253{
236254 if (pseudoTypeString.length() && pseudoTypeString[pseudoTypeString.length() - 1] == '(')
197027

Source/WebCore/css/CSSParserValues.h

@@class CSSParserSelector {
203203public:
204204 static CSSParserSelector* parsePagePseudoSelector(const CSSParserString& pseudoTypeString);
205205 static CSSParserSelector* parsePseudoElementSelector(CSSParserString& pseudoTypeString);
206  static CSSParserSelector* parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>* selectorVector);
 206 static CSSParserSelector* parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>*);
 207#if ENABLE(SHADOW_DOM)
 208 static CSSParserSelector* parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>*);
 209#endif
207210 static CSSParserSelector* parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString);
208211
209212 CSSParserSelector();
197027

Source/WebCore/css/CSSSelector.cpp

@@PseudoId CSSSelector::pseudoId(PseudoEle
299299#if ENABLE(VIDEO_TRACK)
300300 case PseudoElementCue:
301301#endif
 302#if ENABLE(SHADOW_DOM)
 303 case PseudoElementSlotted:
 304#endif
302305 case PseudoElementUnknown:
303306 case PseudoElementUserAgentCustom:
304307 case PseudoElementWebKitCustom:
197027

Source/WebCore/css/CSSSelector.h

@@namespace WebCore {
181181 PseudoElementScrollbarTrack,
182182 PseudoElementScrollbarTrackPiece,
183183 PseudoElementSelection,
 184#if ENABLE(SHADOW_DOM)
 185 PseudoElementSlotted,
 186#endif
184187 PseudoElementUserAgentCustom,
185188 PseudoElementWebKitCustom,
186189 };
197027

Source/WebCore/css/ElementRuleCollector.cpp

3636#include "CSSSelectorList.h"
3737#include "CSSValueKeywords.h"
3838#include "HTMLElement.h"
 39#include "HTMLSlotElement.h"
3940#include "InspectorInstrumentation.h"
4041#include "NodeRenderStyle.h"
4142#include "RenderRegion.h"

@@void ElementRuleCollector::matchAuthorRu
206207#if ENABLE(SHADOW_DOM)
207208 if (m_element.shadowRoot())
208209 matchHostPseudoClassRules(includeEmptyRules);
 210
 211 auto* parent = m_element.parentNode();
 212 if (parent && parent->shadowRoot())
 213 matchSlottedPseudoElementRules(includeEmptyRules);
209214#endif
210215
211216 clearMatchedRules();

@@void ElementRuleCollector::matchHostPseu
241246 // FIXME: Match the spec when it is finalized.
242247 sortAndTransferMatchedRules();
243248}
 249
 250void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules)
 251{
 252 auto* hostShadowRoot = m_element.parentNode()->shadowRoot();
 253 ASSERT(hostShadowRoot);
 254 auto* slot = hostShadowRoot->findAssignedSlot(m_element);
 255 if (!slot)
 256 return;
 257 auto* shadowAuthorStyle = hostShadowRoot->styleResolver().ruleSets().authorStyle();
 258 if (!shadowAuthorStyle)
 259 return;
 260 // Find out if there are any ::slotted rules in the shadow tree matching the current slot.
 261 // FIXME: This is really part of the slot style and could be cached when resolving it.
 262 ElementRuleCollector collector(*slot, *shadowAuthorStyle, nullptr);
 263 auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules);
 264 if (slottedPseudoElementRules.isEmpty())
 265 return;
 266
 267 TemporaryChange<bool> change(m_isMatchindSlottedPseudoElement, true);
 268
 269 clearMatchedRules();
 270 m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
 271 auto ruleRange = m_result.ranges.authorRuleRange();
 272
 273 // Match in the current scope.
 274 MatchRequest matchRequest(nullptr, includeEmptyRules);
 275 collectMatchingRulesForList(&slottedPseudoElementRules, matchRequest, ruleRange);
 276
 277 // FIXME: What is the correct order?
 278 sortAndTransferMatchedRules();
 279}
 280
 281RuleSet::RuleDataVector ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
 282{
 283 ASSERT(is<HTMLSlotElement>(m_element));
 284
 285 clearMatchedRules();
 286
 287 m_mode = SelectorChecker::Mode::CollectingRules;
 288
 289 // Match global author rules.
 290 MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
 291 StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
 292 collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange);
 293
 294 if (m_matchedRules.isEmpty())
 295 return { };
 296
 297 RuleSet::RuleDataVector ruleDataVector;
 298 for (auto& matchedRule : m_matchedRules)
 299 ruleDataVector.append(*matchedRule.ruleData);
 300 return ruleDataVector;
 301}
244302#endif
245303
246304void ElementRuleCollector::matchUserRules(bool includeEmptyRules)

@@void ElementRuleCollector::matchUARules(
284342 sortAndTransferMatchedRules();
285343}
286344
 345#if ENABLE(SHADOW_DOM)
 346static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector)
 347{
 348 for (; selector; selector = selector->tagHistory()) {
 349 if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
 350 if (auto* list = selector->selectorList())
 351 return list->first();
 352 break;
 353 }
 354 };
 355 return nullptr;
 356}
 357#endif
 358
287359inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
288360{
289361 // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.

@@inline bool ElementRuleCollector::ruleMa
356428 } else
357429#endif // ENABLE(CSS_SELECTOR_JIT)
358430 {
 431 auto* selector = ruleData.selector();
 432#if ENABLE(SHADOW_DOM)
 433 if (m_isMatchindSlottedPseudoElement) {
 434 selector = findSlottedPseudoElementSelector(ruleData.selector());
 435 if (!selector)
 436 return false;
 437 }
 438
 439#endif
359440 // Slow path.
360441 SelectorChecker selectorChecker(m_element.document());
361  selectorMatches = selectorChecker.match(*ruleData.selector(), m_element, context, specificity);
 442 selectorMatches = selectorChecker.match(*selector, m_element, context, specificity);
362443 }
363444
364445 commitStyleRelations(context.styleRelations);
197027

Source/WebCore/css/ElementRuleCollector.h

@@private:
7373 void matchUARules(RuleSet*);
7474#if ENABLE(SHADOW_DOM)
7575 void matchHostPseudoClassRules(bool includeEmptyRules);
 76 void matchSlottedPseudoElementRules(bool includeEmptyRules);
 77 RuleSet::RuleDataVector collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules);
7678#endif
7779
7880 void collectMatchingRules(const MatchRequest&, StyleResolver::RuleRange&);

@@private:
98100 PseudoStyleRequest m_pseudoStyleRequest { NOPSEUDO };
99101 bool m_sameOriginOnly { false };
100102 SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle };
 103#if ENABLE(SHADOW_DOM)
 104 bool m_isMatchindSlottedPseudoElement { false };
 105#endif
101106
102107 Vector<MatchedRule, 64> m_matchedRules;
103108
197027

Source/WebCore/css/RuleSet.cpp

@@void RuleSet::addRule(StyleRule* rule, u
266266 m_hostPseudoClassRules.append(ruleData);
267267 return;
268268 }
 269 if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
 270 // ::slotted pseudo elements work accross shadow boundary making filtering difficult.
 271 ruleData.disableSelectorFiltering();
 272 m_slottedPseudoElementRules.append(ruleData);
 273 return;
 274 }
269275#endif
270276 if (selector->relation() != CSSSelector::SubSelector)
271277 break;

@@void RuleSet::shrinkToFit()
422428#if ENABLE(VIDEO_TRACK)
423429 m_cuePseudoRules.shrinkToFit();
424430#endif
 431#if ENABLE(SHADOW_DOM)
 432 m_hostPseudoClassRules.shrinkToFit();
 433 m_slottedPseudoElementRules.shrinkToFit();
 434#endif
425435 m_focusPseudoClassRules.shrinkToFit();
426436 m_universalRules.shrinkToFit();
427437 m_pageRules.shrinkToFit();
197027

Source/WebCore/css/RuleSet.h

@@public:
184184#endif
185185#if ENABLE(SHADOW_DOM)
186186 const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; }
 187 const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; }
187188#endif
188189 const RuleDataVector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; }
189190 const RuleDataVector* universalRules() const { return &m_universalRules; }

@@private:
210211#endif
211212#if ENABLE(SHADOW_DOM)
212213 RuleDataVector m_hostPseudoClassRules;
 214 RuleDataVector m_slottedPseudoElementRules;
213215#endif
214216 RuleDataVector m_focusPseudoClassRules;
215217 RuleDataVector m_universalRules;
197027

Source/WebCore/css/SelectorChecker.cpp

4444#include "HTMLOptionElement.h"
4545#include "HTMLParserIdioms.h"
4646#include "HTMLProgressElement.h"
 47#include "HTMLSlotElement.h"
4748#include "HTMLStyleElement.h"
4849#include "InspectorInstrumentation.h"
4950#include "Page.h"

@@bool SelectorChecker::checkOne(CheckingC
10381039 return false;
10391040 }
10401041#endif
1041  // ### add the rest of the checks...
 1042#if ENABLE(SHADOW_DOM)
 1043 if (selector.match() == CSSSelector::PseudoElement && selector.pseudoElementType() == CSSSelector::PseudoElementSlotted) {
 1044 // We see ::slotted() pseudo elements when collecting slotted rules from the slot shadow tree only.
 1045 ASSERT(checkingContext.resolvingMode == Mode::CollectingRules);
 1046 return is<HTMLSlotElement>(element);
 1047 }
 1048#endif
10421049 return true;
10431050}
10441051
197027

Source/WebCore/style/StyleSharingResolver.cpp

@@const Element* SharingResolver::resolve(
7676 if (!element.parentElement())
7777 return nullptr;
7878 auto& parentElement = *element.parentElement();
 79 if (parentElement.shadowRoot())
 80 return nullptr;
7981 if (!parentElement.renderStyle())
8082 return nullptr;
8183 // If the element has inline style it is probably unique.
197027

LayoutTests/ChangeLog

 12016-02-25 Antti Koivisto <antti@apple.com>
 2
 3 Implement ::slotted pseudo element
 4 https://bugs.webkit.org/show_bug.cgi?id=149441
 5 <rdar://problem/22731987>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Enable the test, fix it and update it to the current spec.
 10
 11 * fast/shadow-dom/css-scoping-shadow-slotted-rule.html:
 12 * platform/mac/TestExpectations:
 13
1142016-02-24 Carlos Garcia Campos <cgarcia@igalia.com>
215
316 REGRESSION(r195949): [GTK] Test /webkit2/WebKitWebView/insert/link is failing since r195949
197027

LayoutTests/fast/shadow-dom/css-scoping-shadow-slotted-rule.html

11<!DOCTYPE html>
22<html>
33<head>
4  <title>CSS Scoping - :slotted pesudo element must allow selecting elements assigned to a slot element</title>
 4 <title>CSS Scoping - :slotted pseudo element must allow selecting elements assigned to a slot element</title>
55 <link rel="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"/>
66 <link rel="help" href="http://www.w3.org/TR/css-scoping-1/#selectors-data-model">
77 <link rel="match" href="reference/green-box.html"/>

1212 display: block;
1313 width: 100px;
1414 height: 100px;
15  background: red;
 15 color: red;
 16 background: green;
1617 }
1718 my-host > div, nested-host {
1819 display: block;

2324 <p>Test passes if you see a single 100px by 100px green box below.</p>
2425 <my-host>
2526 <div class="green">FAIL1</div>
26  <div><span>FAIL2</span></div>
 27 <myelem><span>FAIL2</span></myelem>
2728 <nested-host>
2829 <span>FAIL3</span>
2930 </nested-host>

3637 try {
3738 var shadowHost = document.querySelector('my-host');
3839 shadowRoot = shadowHost.attachShadow({mode: 'open'});
39  shadowRoot.innerHTML = '<slot></slot><style> ::slotted > .green, ::slotted span { color:green; } </style>';
 40 shadowRoot.innerHTML = '<slot></slot><style> ::slotted(.green), ::slotted(myelem) { color:green; } </style>';
4041
4142 shadowHost = document.querySelector('nested-host');
4243 shadowRoot = shadowHost.attachShadow({mode: 'open'});
43  shadowRoot.innerHTML = '<slot></slot>';
 44 shadowRoot.innerHTML = '<style> .mydiv ::slotted(*) { color:green; } </style><div class=mydiv><slot></slot></div>';
4445
4546 shadowHost = document.querySelector('another-host');
4647 shadowRoot = shadowHost.attachShadow({mode: 'open'});
47  shadowRoot.innerHTML = '<style> ::slotted { color:green; } </style><slot></slot>';
 48 shadowRoot.innerHTML = '<style> ::slotted(*) { color:green; } </style><slot></slot>';
4849 } catch (exception) {
4950 document.body.appendChild(document.createTextNode(exception));
5051 }
197027

LayoutTests/platform/mac/TestExpectations

@@webkit.org/b/149128 fast/text/control-ch
12501250
12511251webkit.org/b/148695 fast/shadow-dom [ Pass ]
12521252webkit.org/b/149440 fast/shadow-dom/css-scoping-shadow-host-functional-rule.html [ ImageOnlyFailure ]
1253 webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slotted-rule.html [ ImageOnlyFailure ]
12541253webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slot-display-override.html [ ImageOnlyFailure ]
12551254
12561255# Touch events is not enabled on Mac
197027