- Revision
- 238759
- Author
- [email protected]
- Date
- 2018-11-30 16:08:50 -0800 (Fri, 30 Nov 2018)
Log Message
Can’t use RalphLauren.com on iPad because hover menus don’t stay up
https://bugs.webkit.org/show_bug.cgi?id=192236
<rdar://problem/45792118>
Reviewed by Geoffrey Garen.
Source/WebCore:
This patch introduces asynchronous content change observation.
1. Start observing synchronous content change and timer install as the result of dispatching mouseMoved event.
2. Start observing synchronous content change and style recalc schedule as the result of a timer callback (installed at #1).
3. Start observing synchronous content change as the result of a style recalc (scheduled at #2).
This patch also extends the timeout value from 100ms to 250ms. Certain content prefer longer timeouts (see http://briancherne.github.io/jquery-hoverIntent/ for details).
Test: fast/events/touch/ios/hover-when-style-change-is-async.html
* dom/Document.cpp:
(WebCore::Document::scheduleStyleRecalc):
(WebCore::Document::updateStyleIfNeeded):
* page/DOMTimer.cpp:
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::fired):
* platform/ios/wak/WKContentObservation.cpp:
(WKStartObservingStyleRecalcScheduling):
(WKStopObservingStyleRecalcScheduling):
(WKIsObservingStyleRecalcScheduling):
(WKSetShouldObserveNextStyleRecalc):
(WKShouldObserveNextStyleRecalc):
(WKSetObservedContentChange):
* platform/ios/wak/WKContentObservation.h:
LayoutTests:
* fast/events/touch/ios/hover-when-style-change-is-async-expected.txt: Added.
* fast/events/touch/ios/hover-when-style-change-is-async.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (238758 => 238759)
--- trunk/LayoutTests/ChangeLog 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/LayoutTests/ChangeLog 2018-12-01 00:08:50 UTC (rev 238759)
@@ -1,3 +1,14 @@
+2018-11-30 Zalan Bujtas <[email protected]>
+
+ Can’t use RalphLauren.com on iPad because hover menus don’t stay up
+ https://bugs.webkit.org/show_bug.cgi?id=192236
+ <rdar://problem/45792118>
+
+ Reviewed by Geoffrey Garen.
+
+ * fast/events/touch/ios/hover-when-style-change-is-async-expected.txt: Added.
+ * fast/events/touch/ios/hover-when-style-change-is-async.html: Added.
+
2018-11-30 Ryosuke Niwa <[email protected]>
ShadowRoot should have styleSheets property
Added: trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async-expected.txt (0 => 238759)
--- trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async-expected.txt 2018-12-01 00:08:50 UTC (rev 238759)
@@ -0,0 +1,2 @@
+PASS if no 'clicked' text is shown below.
+
Added: trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async.html (0 => 238759)
--- trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async.html (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/hover-when-style-change-is-async.html 2018-12-01 00:08:50 UTC (rev 238759)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<title>This test that we trigger hover when the content change is async.</title>
+<script src=""
+<style>
+#tapthis {
+ width: 400px;
+ height: 400px;
+ border: 1px solid green;
+}
+
+#hiddenFirst {
+ visibility: hidden;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<script>
+async function test() {
+ if (!window.testRunner || !testRunner.runUIScript)
+ return;
+
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+
+ let rect = tapthis.getBoundingClientRect();
+ let x = rect.left + rect.width / 2;
+ let y = rect.top + rect.height / 2;
+
+ await tapAtPoint(x, y);
+}
+</script>
+</head>
+<body _onload_="test()">
+<div id=tapthis>PASS if no 'clicked' text is shown below.</div>
+<div id=hiddenFirst></div>
+<pre id=result></pre>
+<script>
+tapthis.addEventListener("mouseover", function( event ) {
+ // 1. Install a timer on hover
+ setTimeout(function() {
+ // 2. Trigger a non-forcing style change
+ hiddenFirst.style.visibility = "visible";
+ // 3. Install a timer for style recalc
+ setTimeout(function() {
+ document.body.offsetHeight;
+ if (window.testRunner)
+ testRunner.notifyDone();
+ }, 10);
+ }, 0);
+}, false);
+
+hiddenFirst.addEventListener("click", function( event ) {
+ result.innerHTML = "clicked";
+}, false);
+
+tapthis.addEventListener("click", function( event ) {
+ result.innerHTML = "clicked";
+}, false);
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (238758 => 238759)
--- trunk/Source/WebCore/ChangeLog 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/Source/WebCore/ChangeLog 2018-12-01 00:08:50 UTC (rev 238759)
@@ -1,3 +1,35 @@
+2018-11-30 Zalan Bujtas <[email protected]>
+
+ Can’t use RalphLauren.com on iPad because hover menus don’t stay up
+ https://bugs.webkit.org/show_bug.cgi?id=192236
+ <rdar://problem/45792118>
+
+ Reviewed by Geoffrey Garen.
+
+ This patch introduces asynchronous content change observation.
+ 1. Start observing synchronous content change and timer install as the result of dispatching mouseMoved event.
+ 2. Start observing synchronous content change and style recalc schedule as the result of a timer callback (installed at #1).
+ 3. Start observing synchronous content change as the result of a style recalc (scheduled at #2).
+
+ This patch also extends the timeout value from 100ms to 250ms. Certain content prefer longer timeouts (see http://briancherne.github.io/jquery-hoverIntent/ for details).
+
+ Test: fast/events/touch/ios/hover-when-style-change-is-async.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::scheduleStyleRecalc):
+ (WebCore::Document::updateStyleIfNeeded):
+ * page/DOMTimer.cpp:
+ (WebCore::DOMTimer::install):
+ (WebCore::DOMTimer::fired):
+ * platform/ios/wak/WKContentObservation.cpp:
+ (WKStartObservingStyleRecalcScheduling):
+ (WKStopObservingStyleRecalcScheduling):
+ (WKIsObservingStyleRecalcScheduling):
+ (WKSetShouldObserveNextStyleRecalc):
+ (WKShouldObserveNextStyleRecalc):
+ (WKSetObservedContentChange):
+ * platform/ios/wak/WKContentObservation.h:
+
2018-11-30 Ryosuke Niwa <[email protected]>
ShadowRoot should have styleSheets property
Modified: trunk/Source/WebCore/dom/Document.cpp (238758 => 238759)
--- trunk/Source/WebCore/dom/Document.cpp 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/Source/WebCore/dom/Document.cpp 2018-12-01 00:08:50 UTC (rev 238759)
@@ -264,6 +264,7 @@
#include "Navigator.h"
#include "NavigatorGeolocation.h"
#include "WKContentObservation.h"
+#include "WKContentObservationInternal.h"
#endif
#if ENABLE(IOS_GESTURE_EVENTS)
@@ -1794,6 +1795,11 @@
ASSERT(childNeedsStyleRecalc() || m_pendingStyleRecalcShouldForce);
+#if PLATFORM(IOS_FAMILY)
+ if (WKIsObservingStyleRecalcScheduling())
+ WKSetObservedContentChange(WKContentIndeterminateChange);
+#endif
+
// FIXME: Why on earth is this here? This is clearly misplaced.
invalidateAccessKeyMap();
@@ -2028,10 +2034,29 @@
return false;
}
+#if PLATFORM(IOS_FAMILY)
+ auto observingContentChange = WKShouldObserveNextStyleRecalc();
+ if (observingContentChange) {
+ WKSetShouldObserveNextStyleRecalc(false);
+ WKStartObservingContentChanges();
+ }
+#endif
// The early exit above for !needsStyleRecalc() is needed when updateWidgetPositions() is called in runOrScheduleAsynchronousTasks().
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(isSafeToUpdateStyleOrLayout(*this));
resolveStyle();
+
+#if PLATFORM(IOS_FAMILY)
+ if (observingContentChange) {
+ WKStopObservingContentChanges();
+
+ auto inDeterminedState = WKObservedContentChange() == WKContentVisibilityChange || !WebThreadCountOfObservedDOMTimers();
+ if (inDeterminedState) {
+ if (auto* page = this->page())
+ page->chrome().client().observedContentChange(*frame());
+ }
+ }
+#endif
return true;
}
Modified: trunk/Source/WebCore/page/DOMTimer.cpp (238758 => 238759)
--- trunk/Source/WebCore/page/DOMTimer.cpp 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/Source/WebCore/page/DOMTimer.cpp 2018-12-01 00:08:50 UTC (rev 238759)
@@ -222,7 +222,7 @@
#if PLATFORM(IOS_FAMILY)
if (WKIsObservingDOMTimerScheduling() && is<Document>(context)) {
bool didDeferTimeout = context.activeDOMObjectsAreSuspended();
- if (!didDeferTimeout && timeout <= 100_ms && singleShot) {
+ if (!didDeferTimeout && timeout <= 250_ms && singleShot) {
WKSetObservedContentChange(WKContentIndeterminateChange);
WebThreadAddObservedDOMTimer(timer);
}
@@ -341,18 +341,16 @@
context.removeTimeout(m_timeoutId);
#if PLATFORM(IOS_FAMILY)
- bool shouldReportLackOfChanges;
- bool shouldBeginObservingChanges;
+ auto isObversingLastTimer = false;
+ auto shouldBeginObservingChanges = false;
if (is<Document>(context)) {
- shouldReportLackOfChanges = WebThreadCountOfObservedDOMTimers() == 1;
+ isObversingLastTimer = WebThreadCountOfObservedDOMTimers() == 1;
shouldBeginObservingChanges = WebThreadContainsObservedDOMTimer(this);
- } else {
- shouldReportLackOfChanges = false;
- shouldBeginObservingChanges = false;
}
if (shouldBeginObservingChanges) {
WKStartObservingContentChanges();
+ WKStartObservingStyleRecalcScheduling();
WebThreadRemoveObservedDOMTimer(this);
}
#endif
@@ -366,12 +364,19 @@
#if PLATFORM(IOS_FAMILY)
if (shouldBeginObservingChanges) {
+ WKStopObservingStyleRecalcScheduling();
WKStopObservingContentChanges();
- if (WKObservedContentChange() == WKContentVisibilityChange || shouldReportLackOfChanges) {
- Document& document = downcast<Document>(context);
- if (Page* page = document.page())
+ auto observedContentChange = WKObservedContentChange();
+ // Check if the timer callback triggered either a sync or async style update.
+ auto inDeterminedState = observedContentChange == WKContentVisibilityChange || (isObversingLastTimer && observedContentChange == WKContentNoChange);
+ if (inDeterminedState) {
+ auto& document = downcast<Document>(context);
+ if (auto* page = document.page())
page->chrome().client().observedContentChange(*document.frame());
+ } else if (observedContentChange == WKContentIndeterminateChange) {
+ // An async style recalc has been scheduled. Let's observe it.
+ WKSetShouldObserveNextStyleRecalc(true);
}
}
#endif
Modified: trunk/Source/WebCore/platform/ios/wak/WKContentObservation.cpp (238758 => 238759)
--- trunk/Source/WebCore/platform/ios/wak/WKContentObservation.cpp 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/Source/WebCore/platform/ios/wak/WKContentObservation.cpp 2018-12-01 00:08:50 UTC (rev 238759)
@@ -37,8 +37,9 @@
WKContentChange _WKContentChange = WKContentNoChange;
bool _WKObservingContentChanges = false;
bool _WKObservingDOMTimerScheduling = false;
+bool _WKObservingStyleRecalScheduling = false;
+bool _WKObservingNextStyleRecalc = false;
-
bool WKObservingContentChanges(void)
{
return _WKObservingContentChanges;
@@ -71,6 +72,31 @@
return _WKObservingDOMTimerScheduling;
}
+void WKStartObservingStyleRecalcScheduling(void)
+{
+ _WKObservingStyleRecalScheduling = true;
+}
+
+void WKStopObservingStyleRecalcScheduling(void)
+{
+ _WKObservingStyleRecalScheduling = false;
+}
+
+bool WKIsObservingStyleRecalcScheduling(void)
+{
+ return _WKObservingStyleRecalScheduling;
+}
+
+void WKSetShouldObserveNextStyleRecalc(bool observe)
+{
+ _WKObservingNextStyleRecalc = observe;
+}
+
+bool WKShouldObserveNextStyleRecalc(void)
+{
+ return _WKObservingNextStyleRecalc;
+}
+
WKContentChange WKObservedContentChange(void)
{
return _WKContentChange;
@@ -84,8 +110,9 @@
if (change == WKContentVisibilityChange) {
_WKContentChange = change;
- // Don't need to listen to DOM timers anymore.
+ // Don't need to listen to DOM timers/style recalcs anymore.
WebThreadClearObservedDOMTimers();
+ _WKObservingNextStyleRecalc = false;
return;
}
Modified: trunk/Source/WebCore/platform/ios/wak/WKContentObservation.h (238758 => 238759)
--- trunk/Source/WebCore/platform/ios/wak/WKContentObservation.h 2018-11-30 23:33:39 UTC (rev 238758)
+++ trunk/Source/WebCore/platform/ios/wak/WKContentObservation.h 2018-12-01 00:08:50 UTC (rev 238759)
@@ -46,6 +46,13 @@
WEBCORE_EXPORT void WKStopObservingDOMTimerScheduling(void);
WEBCORE_EXPORT bool WKIsObservingDOMTimerScheduling(void);
+WEBCORE_EXPORT void WKStartObservingStyleRecalcScheduling(void);
+WEBCORE_EXPORT void WKStopObservingStyleRecalcScheduling(void);
+WEBCORE_EXPORT bool WKIsObservingStyleRecalcScheduling(void);
+
+WEBCORE_EXPORT void WKSetShouldObserveNextStyleRecalc(bool);
+WEBCORE_EXPORT bool WKShouldObserveNextStyleRecalc(void);
+
WEBCORE_EXPORT WKContentChange WKObservedContentChange(void);
WEBCORE_EXPORT int WebThreadCountOfObservedDOMTimers(void);