Diff
Modified: trunk/LayoutTests/ChangeLog (271929 => 271930)
--- trunk/LayoutTests/ChangeLog 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/LayoutTests/ChangeLog 2021-01-27 02:38:15 UTC (rev 271930)
@@ -1,3 +1,14 @@
+2021-01-26 Antti Koivisto <[email protected]>
+
+ REGRESSION (r271584): Hovering slowly over and out of "Top 100" items on liberation.fr does not restore animated state
+ https://bugs.webkit.org/show_bug.cgi?id=220862
+ <rdar://problem/73501684>
+
+ Reviewed by Simon Fraser.
+
+ * fast/selectors/hover-invalidation-descendant-clear-expected.html: Added.
+ * fast/selectors/hover-invalidation-descendant-clear.html: Added.
+
2021-01-26 Jonathan Bedard <[email protected]>
[LayoutTests] Pass authentication to CGI scripts
Added: trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear-expected.html (0 => 271930)
--- trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear-expected.html (rev 0)
+++ trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear-expected.html 2021-01-27 02:38:15 UTC (rev 271930)
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.parent {
+ position: relative;
+ padding: 10px;
+ background-color: silver;
+}
+
+.child {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ top: 0px;
+ background-color: green;
+ display: none;
+}
+
+#target2 .child {
+ display: block;
+}
+
+</style>
+</head>
+<body>
+<div>
+Test that clearing dynamically activated :hover rule affecting descendants works.
+</div>
+<div id="target" class="parent enableHover">
+ Hover to see a green box below.
+ <div class="child"></div>
+</div>
+<div id="target2" class="parent enableHover">
+ Hover to see a green box below.
+ <div class="child"></div>
+</div>
+</body>
+</html>
Added: trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear.html (0 => 271930)
--- trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear.html (rev 0)
+++ trunk/LayoutTests/fast/selectors/hover-invalidation-descendant-clear.html 2021-01-27 02:38:15 UTC (rev 271930)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.parent {
+ position: relative;
+ padding: 10px;
+ background-color: silver;
+}
+
+.child {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ top: 0px;
+ background-color: green;
+ display: none;
+}
+
+.enableHover:hover .child {
+ display: block;
+}
+
+</style>
+<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
+function runTest(targetSelector) {
+ var target = document.querySelector(targetSelector);
+
+ if (window.eventSender) {
+ var x = target.offsetLeft + target.offsetWidth / 2;
+ var y = target.offsetTop + target.offsetHeight / 2;
+ eventSender.mouseMoveTo(x, y);
+ }
+}
+
+async function runTests() {
+ await new Promise(requestAnimationFrame);
+ runTest("#target");
+ await new Promise(requestAnimationFrame);
+ runTest("#target2");
+ await new Promise(requestAnimationFrame);
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+</script>
+</head>
+<body _onload_="runTests()">
+<div>
+Test that clearing dynamically activated :hover rule affecting descendants works.
+</div>
+<div id="target" class="parent enableHover">
+ Hover to see a green box below.
+ <div class="child"></div>
+</div>
+<div id="target2" class="parent enableHover">
+ Hover to see a green box below.
+ <div class="child"></div>
+</div>
+</body>
+</html>
Modified: trunk/LayoutTests/platform/ios/TestExpectations (271929 => 271930)
--- trunk/LayoutTests/platform/ios/TestExpectations 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/LayoutTests/platform/ios/TestExpectations 2021-01-27 02:38:15 UTC (rev 271930)
@@ -695,6 +695,7 @@
fast/selectors/active-hover-strict.html [ Skip ]
fast/selectors/active-quirks.html [ Skip ]
fast/selectors/active-strict.html [ Skip ]
+fast/selectors/hover-invalidation-descendant-clear.html [ Skip ]
fast/selectors/hover-invalidation-descendant-dynamic.html [ Skip ]
fast/selectors/hover-quirks.html [ Skip ]
fast/selectors/hover-strict.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (271929 => 271930)
--- trunk/Source/WebCore/ChangeLog 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/ChangeLog 2021-01-27 02:38:15 UTC (rev 271930)
@@ -1,3 +1,48 @@
+2021-01-26 Antti Koivisto <[email protected]>
+
+ REGRESSION (r271584): Hovering slowly over and out of "Top 100" items on liberation.fr does not restore animated state
+ https://bugs.webkit.org/show_bug.cgi?id=220862
+ <rdar://problem/73501684>
+
+ Reviewed by Simon Fraser.
+
+ The optimization in r271584 fails to invalidate hover/active style when clearing the existing state under some circumstances.
+
+ Test: fast/selectors/hover-invalidation-descendant-clear.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::updateHoverActiveState):
+
+ We would do descendant invalidation when changing the hover/active state of the rootmost changing element.
+ However since the state of descendants was changed before this invalidation happened we would try to invalidate
+ them in a tree that was already in the new state.
+
+ Fix by scoping the descendant invalidation over all changes.
+
+ * dom/Element.cpp:
+ (WebCore::Element::setActive):
+ (WebCore::Element::setHovered):
+
+ Switch to new 3-state enum type that allows us to skip descendant invalidation that has already been done by the caller.
+ Skope it to Style namepace.
+
+ * dom/Element.h:
+ * html/HTMLAnchorElement.cpp:
+ (WebCore::HTMLAnchorElement::setActive):
+ * html/HTMLAnchorElement.h:
+ * html/HTMLLabelElement.cpp:
+ (WebCore::HTMLLabelElement::setActive):
+ (WebCore::HTMLLabelElement::setHovered):
+ * html/HTMLLabelElement.h:
+ * html/shadow/SpinButtonElement.cpp:
+ (WebCore::SpinButtonElement::setHovered):
+ * html/shadow/SpinButtonElement.h:
+ * style/PseudoClassChangeInvalidation.cpp:
+ (WebCore::Style::PseudoClassChangeInvalidation::computeInvalidation):
+ * style/PseudoClassChangeInvalidation.h:
+ (WebCore::Style::PseudoClassChangeInvalidation::PseudoClassChangeInvalidation):
+ * style/StyleValidity.h:
+
2021-01-26 Chris Dumez <[email protected]>
[GPU Process] Compositing layout test crash in WebKit::GPUProcess::lowMemoryHandler
Modified: trunk/Source/WebCore/dom/Document.cpp (271929 => 271930)
--- trunk/Source/WebCore/dom/Document.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/dom/Document.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -162,6 +162,7 @@
#include "PolicyChecker.h"
#include "PopStateEvent.h"
#include "ProcessingInstruction.h"
+#include "PseudoClassChangeInvalidation.h"
#include "PublicSuffix.h"
#include "Quirks.h"
#include "Range.h"
@@ -7188,14 +7189,26 @@
elementsToSetHover.append(element);
}
- for (auto& element : elementsToClearActive)
- element->setActive(false, false, element == elementsToClearActive.last() ? Element::IsUserActionStateChangeRoot::Yes : Element::IsUserActionStateChangeRoot::No);
- for (auto& element : elementsToSetActive)
- element->setActive(true, false, element == elementsToSetActive.last() ? Element::IsUserActionStateChangeRoot::Yes : Element::IsUserActionStateChangeRoot::No);
- for (auto& element : elementsToClearHover)
- element->setHovered(false, element == elementsToClearHover.last() ? Element::IsUserActionStateChangeRoot::Yes : Element::IsUserActionStateChangeRoot::No);
- for (auto& element : elementsToSetHover)
- element->setHovered(true, element == elementsToSetHover.last() ? Element::IsUserActionStateChangeRoot::Yes : Element::IsUserActionStateChangeRoot::No);
+ if (!elementsToClearActive.isEmpty()) {
+ Style::PseudoClassChangeInvalidation styleInvalidation(*elementsToClearActive.last(), CSSSelector::PseudoClassActive, Style::InvalidationScope::Descendants);
+ for (auto& element : elementsToClearActive)
+ element->setActive(false, false, Style::InvalidationScope::SelfChildrenAndSiblings);
+ }
+ if (!elementsToSetActive.isEmpty()) {
+ Style::PseudoClassChangeInvalidation styleInvalidation(*elementsToSetActive.last(), CSSSelector::PseudoClassActive, Style::InvalidationScope::Descendants);
+ for (auto& element : elementsToSetActive)
+ element->setActive(true, false, Style::InvalidationScope::SelfChildrenAndSiblings);
+ }
+ if (!elementsToClearHover.isEmpty()) {
+ Style::PseudoClassChangeInvalidation styleInvalidation(*elementsToClearHover.last(), CSSSelector::PseudoClassHover, Style::InvalidationScope::Descendants);
+ for (auto& element : elementsToClearHover)
+ element->setHovered(false, Style::InvalidationScope::SelfChildrenAndSiblings);
+ }
+ if (!elementsToSetHover.isEmpty()) {
+ Style::PseudoClassChangeInvalidation styleInvalidation(*elementsToSetHover.last(), CSSSelector::PseudoClassHover, Style::InvalidationScope::Descendants);
+ for (auto& element : elementsToSetHover)
+ element->setHovered(true, Style::InvalidationScope::SelfChildrenAndSiblings);
+ }
}
bool Document::haveStylesheetsLoaded() const
Modified: trunk/Source/WebCore/dom/Element.cpp (271929 => 271930)
--- trunk/Source/WebCore/dom/Element.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/dom/Element.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -679,12 +679,12 @@
return document().userActionElements().isBeingDragged(*this);
}
-void Element::setActive(bool flag, bool pause, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void Element::setActive(bool flag, bool pause, Style::InvalidationScope invalidationScope)
{
if (flag == active())
return;
{
- Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassActive, isUserActionStateChangeRoot);
+ Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassActive, invalidationScope);
document().userActionElements().setActive(*this, flag);
}
@@ -756,12 +756,12 @@
}
}
-void Element::setHovered(bool flag, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void Element::setHovered(bool flag, Style::InvalidationScope invalidationScope)
{
if (flag == hovered())
return;
{
- Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassHover, isUserActionStateChangeRoot);
+ Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassHover, invalidationScope);
document().userActionElements().setHovered(*this, flag);
}
Modified: trunk/Source/WebCore/dom/Element.h (271929 => 271930)
--- trunk/Source/WebCore/dom/Element.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/dom/Element.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -321,9 +321,8 @@
bool isBeingDragged() const { return isUserActionElement() && isUserActionElementDragged(); }
bool hasFocusWithin() const { return hasNodeFlag(NodeFlag::HasFocusWithin); };
- enum class IsUserActionStateChangeRoot { Yes, No };
- virtual void setActive(bool = true, bool pause = false, IsUserActionStateChangeRoot = IsUserActionStateChangeRoot::Yes);
- virtual void setHovered(bool = true, IsUserActionStateChangeRoot = IsUserActionStateChangeRoot::Yes);
+ virtual void setActive(bool = true, bool pause = false, Style::InvalidationScope = Style::InvalidationScope::All);
+ virtual void setHovered(bool = true, Style::InvalidationScope = Style::InvalidationScope::All);
virtual void setFocus(bool);
void setBeingDragged(bool);
void setHasFocusWithin(bool);
Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (271929 => 271930)
--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -211,7 +211,7 @@
HTMLElement::defaultEventHandler(event);
}
-void HTMLAnchorElement::setActive(bool down, bool pause, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void HTMLAnchorElement::setActive(bool down, bool pause, Style::InvalidationScope invalidationScope)
{
if (hasEditableStyle()) {
switch (document().settings().editableLinkBehavior()) {
@@ -232,7 +232,7 @@
}
}
- HTMLElement::setActive(down, pause, isUserActionStateChangeRoot);
+ HTMLElement::setActive(down, pause, invalidationScope);
}
void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomString& value)
Modified: trunk/Source/WebCore/html/HTMLAnchorElement.h (271929 => 271930)
--- trunk/Source/WebCore/html/HTMLAnchorElement.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -87,7 +87,7 @@
bool isMouseFocusable() const override;
bool isKeyboardFocusable(KeyboardEvent*) const override;
void defaultEventHandler(Event&) final;
- void setActive(bool active, bool pause, IsUserActionStateChangeRoot) final;
+ void setActive(bool active, bool pause, Style::InvalidationScope) final;
bool accessKeyAction(bool sendMouseEvents) final;
bool isURLAttribute(const Attribute&) const final;
bool canStartSelection() const final;
Modified: trunk/Source/WebCore/html/HTMLLabelElement.cpp (271929 => 271930)
--- trunk/Source/WebCore/html/HTMLLabelElement.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/HTMLLabelElement.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -85,13 +85,13 @@
return downcast<HTMLFormControlElement>(control.get())->form();
}
-void HTMLLabelElement::setActive(bool down, bool pause, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void HTMLLabelElement::setActive(bool down, bool pause, Style::InvalidationScope invalidationScope)
{
if (down == active())
return;
// Update our status first.
- HTMLElement::setActive(down, pause, isUserActionStateChangeRoot);
+ HTMLElement::setActive(down, pause, invalidationScope);
// Also update our corresponding control.
if (auto element = control())
@@ -98,13 +98,13 @@
element->setActive(down, pause);
}
-void HTMLLabelElement::setHovered(bool over, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void HTMLLabelElement::setHovered(bool over, Style::InvalidationScope invalidationScope)
{
if (over == hovered())
return;
// Update our status first.
- HTMLElement::setHovered(over, isUserActionStateChangeRoot);
+ HTMLElement::setHovered(over, invalidationScope);
// Also update our corresponding control.
if (auto element = control())
Modified: trunk/Source/WebCore/html/HTMLLabelElement.h (271929 => 271930)
--- trunk/Source/WebCore/html/HTMLLabelElement.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/HTMLLabelElement.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -45,8 +45,8 @@
bool accessKeyAction(bool sendMouseEvents) final;
// Overridden to update the hover/active state of the corresponding control.
- void setActive(bool, bool pause, IsUserActionStateChangeRoot) final;
- void setHovered(bool, IsUserActionStateChangeRoot) final;
+ void setActive(bool, bool pause, Style::InvalidationScope) final;
+ void setHovered(bool, Style::InvalidationScope) final;
// Overridden to either click() or focus() the corresponding control.
void defaultEventHandler(Event&) final;
Modified: trunk/Source/WebCore/html/shadow/SpinButtonElement.cpp (271929 => 271930)
--- trunk/Source/WebCore/html/shadow/SpinButtonElement.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/shadow/SpinButtonElement.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -249,11 +249,11 @@
step(m_upDownState == Up ? 1 : -1);
}
-void SpinButtonElement::setHovered(bool flag, IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void SpinButtonElement::setHovered(bool flag, Style::InvalidationScope invalidationScope)
{
if (!flag)
m_upDownState = Indeterminate;
- HTMLDivElement::setHovered(flag, isUserActionStateChangeRoot);
+ HTMLDivElement::setHovered(flag, invalidationScope);
}
bool SpinButtonElement::shouldRespondToMouseEvents()
Modified: trunk/Source/WebCore/html/shadow/SpinButtonElement.h (271929 => 271930)
--- trunk/Source/WebCore/html/shadow/SpinButtonElement.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/html/shadow/SpinButtonElement.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -79,7 +79,7 @@
void startRepeatingTimer();
void stopRepeatingTimer();
void repeatingTimerFired();
- void setHovered(bool, IsUserActionStateChangeRoot) override;
+ void setHovered(bool, Style::InvalidationScope) override;
bool shouldRespondToMouseEvents();
bool isMouseFocusable() const override { return false; }
Modified: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp (271929 => 271930)
--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp 2021-01-27 02:38:15 UTC (rev 271930)
@@ -32,7 +32,7 @@
namespace WebCore {
namespace Style {
-void PseudoClassChangeInvalidation::computeInvalidation(CSSSelector::PseudoClassType pseudoClass, Element::IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+void PseudoClassChangeInvalidation::computeInvalidation(CSSSelector::PseudoClassType pseudoClass, InvalidationScope invalidationScope)
{
bool shouldInvalidateCurrent = false;
bool mayAffectStyleInShadowTree = false;
@@ -57,9 +57,16 @@
for (auto& invalidationRuleSet : *invalidationRuleSets) {
// For focus/hover we flip the whole ancestor chain. We only need to do deep invalidation traversal in the change root.
auto shouldInvalidate = [&] {
- if (isUserActionStateChangeRoot == Element::IsUserActionStateChangeRoot::Yes)
+ switch (invalidationScope) {
+ case InvalidationScope::All:
return true;
- return invalidationRuleSet.matchElement != MatchElement::Ancestor;
+ case InvalidationScope::SelfChildrenAndSiblings:
+ return invalidationRuleSet.matchElement != MatchElement::Ancestor;
+ case InvalidationScope::Descendants:
+ return invalidationRuleSet.matchElement == MatchElement::Ancestor;
+ }
+ ASSERT_NOT_REACHED();
+ return true;
}();
if (!shouldInvalidate)
continue;
Modified: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h (271929 => 271930)
--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -35,11 +35,11 @@
class PseudoClassChangeInvalidation {
public:
- PseudoClassChangeInvalidation(Element&, CSSSelector::PseudoClassType, Element::IsUserActionStateChangeRoot = Element::IsUserActionStateChangeRoot::Yes);
+ PseudoClassChangeInvalidation(Element&, CSSSelector::PseudoClassType, InvalidationScope = InvalidationScope::All);
~PseudoClassChangeInvalidation();
private:
- void computeInvalidation(CSSSelector::PseudoClassType, Element::IsUserActionStateChangeRoot);
+ void computeInvalidation(CSSSelector::PseudoClassType, Style::InvalidationScope);
void invalidateStyleWithRuleSets();
const bool m_isEnabled;
@@ -48,7 +48,7 @@
Invalidator::MatchElementRuleSets m_matchElementRuleSets;
};
-inline PseudoClassChangeInvalidation::PseudoClassChangeInvalidation(Element& element, CSSSelector::PseudoClassType pseudoClassType, Element::IsUserActionStateChangeRoot isUserActionStateChangeRoot)
+inline PseudoClassChangeInvalidation::PseudoClassChangeInvalidation(Element& element, CSSSelector::PseudoClassType pseudoClassType, Style::InvalidationScope invalidationScope)
: m_isEnabled(element.needsStyleInvalidation())
, m_element(element)
@@ -55,7 +55,7 @@
{
if (!m_isEnabled)
return;
- computeInvalidation(pseudoClassType, isUserActionStateChangeRoot);
+ computeInvalidation(pseudoClassType, invalidationScope);
invalidateStyleWithRuleSets();
}
Modified: trunk/Source/WebCore/style/StyleValidity.h (271929 => 271930)
--- trunk/Source/WebCore/style/StyleValidity.h 2021-01-27 01:36:14 UTC (rev 271929)
+++ trunk/Source/WebCore/style/StyleValidity.h 2021-01-27 02:38:15 UTC (rev 271930)
@@ -40,5 +40,11 @@
RecompositeLayer
};
+enum class InvalidationScope {
+ All,
+ SelfChildrenAndSiblings,
+ Descendants
+};
+
}
}