Title: [277001] trunk
Revision
277001
Author
[email protected]
Date
2021-05-04 21:38:19 -0700 (Tue, 04 May 2021)

Log Message

REGRESSION(iOS 14): Author shadow DOM invalidated unnecessarily on pseudo element change
https://bugs.webkit.org/show_bug.cgi?id=222187
<rdar://problem/74801314>

Reviewed by Ryosuke Niwa.
Source/WebCore:

Hovering the element causes us to invalidate the entire author shadow tree style.

The invalidation is triggered by the user agent stylesheet having some :hover rules targeting pseudo
elements. This should not require invalidation except for those specific elements and only for
UA shadow trees.

This patch optimizes the case and avoids unnecessary invalidations.

Test: fast/shadow-dom/shadow-style-invalidation-pseudo-element.html

* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::handleFocusEvent):
(WebCore::HTMLInputElement::handleBlurEvent):
(WebCore::HTMLInputElement::invalidateStyleOnFocusChangeIfNeeded):

Input elements with 'text-overflow:ellipsis' (which is affected by focus) were relying
on spurious invalidations that we now optimize away. Invalidate properly.

* html/HTMLInputElement.h:
* style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::collectMatchingShadowPseudoElementRules):
* style/RuleSet.cpp:
(WebCore::Style::RuleSet::evaluateDynamicMediaQueryRules):
(WebCore::Style::RuleSet::hasShadowPseudoElementRules const): Deleted.

Handle ::cue separately.

* style/RuleSet.h:
(WebCore::Style::RuleSet::cuePseudoRules const):
(WebCore::Style::RuleSet::hasShadowPseudoElementRules const):
* style/StyleInvalidationFunctions.h:
(WebCore::Style::traverseRuleFeatures):
* style/StyleInvalidator.cpp:
(WebCore::Style::Invalidator::collectRuleInformation):
(WebCore::Style::Invalidator::invalidateShadowPseudoElements):

Narrowly invalidate user agent shadow tree pseudo elements.

(WebCore::Style::Invalidator::invalidateInShadowTreeIfNeeded):
* style/StyleInvalidator.h:

LayoutTests:

* fast/shadow-dom/shadow-style-invalidation-pseudo-element-expected.txt: Added.
* fast/shadow-dom/shadow-style-invalidation-pseudo-element.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (277000 => 277001)


--- trunk/LayoutTests/ChangeLog	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/LayoutTests/ChangeLog	2021-05-05 04:38:19 UTC (rev 277001)
@@ -1,3 +1,14 @@
+2021-05-04  Antti Koivisto  <[email protected]>
+
+        REGRESSION(iOS 14): Author shadow DOM invalidated unnecessarily on pseudo element change
+        https://bugs.webkit.org/show_bug.cgi?id=222187
+        <rdar://problem/74801314>
+
+        Reviewed by Ryosuke Niwa.
+
+        * fast/shadow-dom/shadow-style-invalidation-pseudo-element-expected.txt: Added.
+        * fast/shadow-dom/shadow-style-invalidation-pseudo-element.html: Added.
+
 2021-05-04  Diego Pino Garcia  <[email protected]>
 
         [WPE] Unreviewed test gardening. Gardened several WebXR tests that are crashing in Debug.

Added: trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element-expected.txt (0 => 277001)


--- trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element-expected.txt	2021-05-05 04:38:19 UTC (rev 277001)
@@ -0,0 +1,3 @@
+
+PASS Author shadow tree is not invalidated in presence of user agent shadow tree targeting pseudo elements
+

Added: trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element.html (0 => 277001)


--- trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/shadow-style-invalidation-pseudo-element.html	2021-05-05 04:38:19 UTC (rev 277001)
@@ -0,0 +1,27 @@
+<script src=""
+<script src=""
+<style>
+:focus { color: green }
+:focus::placeholder { color: blue }
+</style>
+
+<div id=host tabindex=1></div>
+
+<script>
+var host = document.getElementById('host');
+var shadow = host.attachShadow({mode: 'closed'});
+shadow.innerHTML = `
+    <div>shadow</div>
+`;
+
+test(() => {
+    internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks();
+
+    host.focus();
+
+    var div = shadow.querySelector("div");
+    assert_equals(internals.styleChangeType(host), "InlineStyleChange");
+    assert_equals(internals.styleChangeType(div), "NoStyleChange");
+}, "Author shadow tree is not invalidated in presence of user agent shadow tree targeting pseudo elements");
+
+</script>

Modified: trunk/Source/WebCore/ChangeLog (277000 => 277001)


--- trunk/Source/WebCore/ChangeLog	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/ChangeLog	2021-05-05 04:38:19 UTC (rev 277001)
@@ -1,3 +1,52 @@
+2021-05-04  Antti Koivisto  <[email protected]>
+
+        REGRESSION(iOS 14): Author shadow DOM invalidated unnecessarily on pseudo element change
+        https://bugs.webkit.org/show_bug.cgi?id=222187
+        <rdar://problem/74801314>
+
+        Reviewed by Ryosuke Niwa.
+        
+        Hovering the element causes us to invalidate the entire author shadow tree style.
+
+        The invalidation is triggered by the user agent stylesheet having some :hover rules targeting pseudo
+        elements. This should not require invalidation except for those specific elements and only for
+        UA shadow trees.
+        
+        This patch optimizes the case and avoids unnecessary invalidations.
+
+        Test: fast/shadow-dom/shadow-style-invalidation-pseudo-element.html
+        
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::handleFocusEvent):
+        (WebCore::HTMLInputElement::handleBlurEvent):
+        (WebCore::HTMLInputElement::invalidateStyleOnFocusChangeIfNeeded):
+        
+        Input elements with 'text-overflow:ellipsis' (which is affected by focus) were relying
+        on spurious invalidations that we now optimize away. Invalidate properly.
+        
+        * html/HTMLInputElement.h:
+        * style/ElementRuleCollector.cpp:
+        (WebCore::Style::ElementRuleCollector::collectMatchingShadowPseudoElementRules):
+        * style/RuleSet.cpp:
+        (WebCore::Style::RuleSet::evaluateDynamicMediaQueryRules):
+        (WebCore::Style::RuleSet::hasShadowPseudoElementRules const): Deleted.
+        
+        Handle ::cue separately.
+        
+        * style/RuleSet.h:
+        (WebCore::Style::RuleSet::cuePseudoRules const):
+        (WebCore::Style::RuleSet::hasShadowPseudoElementRules const):
+        * style/StyleInvalidationFunctions.h:
+        (WebCore::Style::traverseRuleFeatures):
+        * style/StyleInvalidator.cpp:
+        (WebCore::Style::Invalidator::collectRuleInformation):
+        (WebCore::Style::Invalidator::invalidateShadowPseudoElements):
+        
+        Narrowly invalidate user agent shadow tree pseudo elements.
+        
+        (WebCore::Style::Invalidator::invalidateInShadowTreeIfNeeded):
+        * style/StyleInvalidator.h:
+
 2021-05-04  Kenneth Russell  <[email protected]>
 
         WebKit must treat 'webgl' and 'webgl2' as distinct context types

Modified: trunk/Source/WebCore/html/HTMLInputElement.cpp (277000 => 277001)


--- trunk/Source/WebCore/html/HTMLInputElement.cpp	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/html/HTMLInputElement.cpp	2021-05-05 04:38:19 UTC (rev 277001)
@@ -56,6 +56,7 @@
 #include "KeyboardEvent.h"
 #include "LocalizedStrings.h"
 #include "MouseEvent.h"
+#include "NodeRenderStyle.h"
 #include "Page.h"
 #include "PlatformMouseEvent.h"
 #include "RenderTextControlSingleLine.h"
@@ -520,11 +521,15 @@
 void HTMLInputElement::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
 {
     m_inputType->handleFocusEvent(oldFocusedNode, direction);
+
+    invalidateStyleOnFocusChangeIfNeeded();
 }
 
 void HTMLInputElement::handleBlurEvent()
 {
     m_inputType->handleBlurEvent();
+
+    invalidateStyleOnFocusChangeIfNeeded();
 }
 
 void HTMLInputElement::setType(const AtomString& type)
@@ -2004,6 +2009,15 @@
     return document().focusedElement() != this && style.textOverflow() == TextOverflow::Ellipsis;
 }
 
+void HTMLInputElement::invalidateStyleOnFocusChangeIfNeeded()
+{
+    if (!isTextField())
+        return;
+    // Focus change may affect the result of shouldTruncateText().
+    if (auto* style = renderStyle(); style && style->textOverflow() == TextOverflow::Ellipsis)
+        invalidateStyleForSubtreeInternal();
+}
+
 ExceptionOr<int> HTMLInputElement::selectionStartForBindings() const
 {
     if (!canHaveSelection())

Modified: trunk/Source/WebCore/html/HTMLInputElement.h (277000 => 277001)


--- trunk/Source/WebCore/html/HTMLInputElement.h	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/html/HTMLInputElement.h	2021-05-05 04:38:19 UTC (rev 277001)
@@ -332,6 +332,7 @@
     void capsLockStateMayHaveChanged();
 
     bool shouldTruncateText(const RenderStyle&) const;
+    void invalidateStyleOnFocusChangeIfNeeded();
 
     ExceptionOr<int> selectionStartForBindings() const;
     ExceptionOr<void> setSelectionStartForBindings(int);

Modified: trunk/Source/WebCore/style/ElementRuleCollector.cpp (277000 => 277001)


--- trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-05-05 04:38:19 UTC (rev 277001)
@@ -339,7 +339,7 @@
 #if ENABLE(VIDEO)
     // FXIME: WebVTT should not be done by styling UA shadow trees like this.
     if (element().isWebVTTElement())
-        collectMatchingRulesForList(rules.cuePseudoRules(), matchRequest);
+        collectMatchingRulesForList(&rules.cuePseudoRules(), matchRequest);
 #endif
     auto& pseudoId = element().shadowPseudoId();
     if (!pseudoId.isEmpty())

Modified: trunk/Source/WebCore/style/RuleSet.cpp (277000 => 277001)


--- trunk/Source/WebCore/style/RuleSet.cpp	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/RuleSet.cpp	2021-05-05 04:38:19 UTC (rev 277001)
@@ -469,17 +469,6 @@
     return collectedChanges;
 }
 
-bool RuleSet::hasShadowPseudoElementRules() const
-{
-    if (!m_shadowPseudoElementRules.isEmpty())
-        return true;
-#if ENABLE(VIDEO)
-    if (!m_cuePseudoRules.isEmpty())
-        return true;
-#endif
-    return false;
-}
-
 static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map)
 {
     for (auto& vector : map.values())

Modified: trunk/Source/WebCore/style/RuleSet.h (277000 => 277001)


--- trunk/Source/WebCore/style/RuleSet.h	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/RuleSet.h	2021-05-05 04:38:19 UTC (rev 277001)
@@ -130,7 +130,7 @@
     const RuleDataVector* shadowPseudoElementRules(const AtomString& key) const { return m_shadowPseudoElementRules.get(key); }
     const RuleDataVector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; }
 #if ENABLE(VIDEO)
-    const RuleDataVector* cuePseudoRules() const { return &m_cuePseudoRules; }
+    const RuleDataVector& cuePseudoRules() const { return m_cuePseudoRules; }
 #endif
     const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; }
     const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; }
@@ -142,7 +142,7 @@
 
     unsigned ruleCount() const { return m_ruleCount; }
 
-    bool hasShadowPseudoElementRules() const;
+    bool hasShadowPseudoElementRules() const { return !m_shadowPseudoElementRules.isEmpty(); }
     bool hasHostPseudoClassRulesMatchingInShadowTree() const { return m_hasHostPseudoClassRulesMatchingInShadowTree; }
 
 private:

Modified: trunk/Source/WebCore/style/StyleInvalidationFunctions.h (277000 => 277001)


--- trunk/Source/WebCore/style/StyleInvalidationFunctions.h	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/StyleInvalidationFunctions.h	2021-05-05 04:38:19 UTC (rev 277001)
@@ -65,8 +65,14 @@
     auto& ruleSets = element.styleResolver().ruleSets();
 
     auto mayAffectShadowTree = [&] {
-        if (element.shadowRoot() && ruleSets.authorStyle().hasShadowPseudoElementRules())
-            return true;
+        if (element.shadowRoot() && element.shadowRoot()->isUserAgentShadowRoot()) {
+            if (ruleSets.authorStyle().hasShadowPseudoElementRules())
+                return true;
+#if ENABLE(VIDEO)
+            if (element.isMediaElement() && !ruleSets.authorStyle().cuePseudoRules().isEmpty())
+                return true;
+#endif
+        }
         if (is<HTMLSlotElement>(element) && !ruleSets.authorStyle().slottedPseudoElementRules().isEmpty())
             return true;
         return false;

Modified: trunk/Source/WebCore/style/StyleInvalidator.cpp (277000 => 277001)


--- trunk/Source/WebCore/style/StyleInvalidator.cpp	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/StyleInvalidator.cpp	2021-05-05 04:38:19 UTC (rev 277001)
@@ -117,6 +117,10 @@
             information.hasHostPseudoClassRules = true;
         if (ruleSet->hasShadowPseudoElementRules())
             information.hasShadowPseudoElementRules = true;
+#if ENABLE(VIDEO)
+        if (!ruleSet->cuePseudoRules().isEmpty())
+            information.hasCuePseudoElementRules = true;
+#endif
         if (!ruleSet->partPseudoElementRules().isEmpty())
             information.hasPartPseudoElementRules = true;
     }
@@ -315,6 +319,22 @@
     }
 }
 
+void Invalidator::invalidateShadowPseudoElements(ShadowRoot& shadowRoot)
+{
+    if (shadowRoot.mode() != ShadowRootMode::UserAgent)
+        return;
+
+    for (auto& descendant : descendantsOfType<Element>(shadowRoot)) {
+        auto& shadowPseudoId = descendant.shadowPseudoId();
+        if (!shadowPseudoId)
+            continue;
+        for (auto& ruleSet : m_ruleSets) {
+            if (ruleSet->shadowPseudoElementRules(shadowPseudoId))
+                descendant.invalidateStyleInternal();
+        }
+    }
+}
+
 void Invalidator::invalidateInShadowTreeIfNeeded(Element& element)
 {
     auto* shadowRoot = element.shadowRoot();
@@ -321,9 +341,13 @@
     if (!shadowRoot)
         return;
 
-    // FIXME: This could do actual rule matching too.
     if (m_ruleInformation.hasShadowPseudoElementRules)
+        invalidateShadowPseudoElements(*shadowRoot);
+
+#if ENABLE(VIDEO)
+    if (m_ruleInformation.hasCuePseudoElementRules && element.isMediaElement())
         element.invalidateStyleForSubtreeInternal();
+#endif
 
     // FIXME: More fine-grained invalidation for ::part()
     if (m_ruleInformation.hasPartPseudoElementRules)

Modified: trunk/Source/WebCore/style/StyleInvalidator.h (277000 => 277001)


--- trunk/Source/WebCore/style/StyleInvalidator.h	2021-05-05 02:45:49 UTC (rev 277000)
+++ trunk/Source/WebCore/style/StyleInvalidator.h	2021-05-05 04:38:19 UTC (rev 277001)
@@ -71,6 +71,7 @@
     void invalidateStyleForTree(Element&, SelectorFilter*);
     void invalidateStyleForDescendants(Element&, SelectorFilter*);
     void invalidateInShadowTreeIfNeeded(Element&);
+    void invalidateShadowPseudoElements(ShadowRoot&);
     void invalidateStyleWithMatchElement(Element&, MatchElement);
 
     struct RuleInformation {
@@ -77,6 +78,7 @@
         bool hasSlottedPseudoElementRules { false };
         bool hasHostPseudoClassRules { false };
         bool hasShadowPseudoElementRules { false };
+        bool hasCuePseudoElementRules { false };
         bool hasPartPseudoElementRules { false };
     };
     RuleInformation collectRuleInformation();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to