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();