- Revision
- 148713
- Author
- timothy_hor...@apple.com
- Date
- 2013-04-18 16:40:20 -0700 (Thu, 18 Apr 2013)
Log Message
Add a synchronous version of WKView endDeferringViewInWindowChanges
https://bugs.webkit.org/show_bug.cgi?id=114780
<rdar://problem/12821901>
Reviewed by Simon Fraser.
Add new WKView SPI, endDeferringViewInWindowChangesSync, which synchronously
(though with a 250 ms timeout) does the work required to reparent a WKView
without flashing white.
* UIProcess/API/mac/WKView.mm:
(-[WKView beginDeferringViewInWindowChanges]):
(-[WKView endDeferringViewInWindowChanges]):
Make begin/endDeferringViewInWindowChanges not allow nested deferrals,
as we don't need them, and they complicate synchronous-end a lot.
(-[WKView endDeferringViewInWindowChangesSync]):
Add a sync version of endDeferringViewInWindowChanges which waits
for DidUpdateInWindowState.
(-[WKView isDeferringViewInWindowChanges]):
* UIProcess/API/mac/WKViewPrivate.h: Add endDeferringViewInWindowChangesSync.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::waitForDidUpdateInWindowState):
Add waitForDidUpdateInWindowState(), which blocks for
250ms or until the WebProcess reparents all of its layers and spins
the runloop once, to prevent flashing when parenting a WKView.
If we've already timed out waiting for the WebProcess, don't block, as
it's probably quite busy and is likely to time out again.
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::isInWindow): Added.
(WebKit::WebPageProxy::waitForDidUpdateInWindowState): Added.
(WebKit::WebPageProxy::didUpdateInWindowState): Added.
* UIProcess/WebPageProxy.messages.in: Add DidUpdateInWindowState()
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didUpdateInWindowStateTimerFired): Send DidUpdateInWindowState to WebPageProxy.
(WebKit::WebPage::setIsInWindow): When setIsInWindow completes, TileController
tiles have been reparented, and the TiledCoreAnimationDrawingArea has
reconnected the layer tree to the context, start a 0-delay runloop timer
to allow painting and layer flushing to finish; when the timer fires,
we'll send the UIProcess a DidUpdateInWindowState so it can stop blocking.
* WebProcess/WebPage/WebPage.h:
(WebPage): Add didUpdateInWindowStateTimerFired and m_sendDidUpdateInWindowStateTimer.
Modified Paths
Diff
Modified: trunk/Source/WebKit2/ChangeLog (148712 => 148713)
--- trunk/Source/WebKit2/ChangeLog 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/ChangeLog 2013-04-18 23:40:20 UTC (rev 148713)
@@ -1,3 +1,55 @@
+2013-04-18 Tim Horton <timothy_hor...@apple.com>
+
+ Add a synchronous version of WKView endDeferringViewInWindowChanges
+ https://bugs.webkit.org/show_bug.cgi?id=114780
+ <rdar://problem/12821901>
+
+ Reviewed by Simon Fraser.
+
+ Add new WKView SPI, endDeferringViewInWindowChangesSync, which synchronously
+ (though with a 250 ms timeout) does the work required to reparent a WKView
+ without flashing white.
+
+ * UIProcess/API/mac/WKView.mm:
+ (-[WKView beginDeferringViewInWindowChanges]):
+ (-[WKView endDeferringViewInWindowChanges]):
+ Make begin/endDeferringViewInWindowChanges not allow nested deferrals,
+ as we don't need them, and they complicate synchronous-end a lot.
+
+ (-[WKView endDeferringViewInWindowChangesSync]):
+ Add a sync version of endDeferringViewInWindowChanges which waits
+ for DidUpdateInWindowState.
+
+ (-[WKView isDeferringViewInWindowChanges]):
+
+ * UIProcess/API/mac/WKViewPrivate.h: Add endDeferringViewInWindowChangesSync.
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::waitForDidUpdateInWindowState):
+ Add waitForDidUpdateInWindowState(), which blocks for
+ 250ms or until the WebProcess reparents all of its layers and spins
+ the runloop once, to prevent flashing when parenting a WKView.
+ If we've already timed out waiting for the WebProcess, don't block, as
+ it's probably quite busy and is likely to time out again.
+
+ * UIProcess/WebPageProxy.h:
+ (WebKit::WebPageProxy::isInWindow): Added.
+ (WebKit::WebPageProxy::waitForDidUpdateInWindowState): Added.
+ (WebKit::WebPageProxy::didUpdateInWindowState): Added.
+
+ * UIProcess/WebPageProxy.messages.in: Add DidUpdateInWindowState()
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::didUpdateInWindowStateTimerFired): Send DidUpdateInWindowState to WebPageProxy.
+ (WebKit::WebPage::setIsInWindow): When setIsInWindow completes, TileController
+ tiles have been reparented, and the TiledCoreAnimationDrawingArea has
+ reconnected the layer tree to the context, start a 0-delay runloop timer
+ to allow painting and layer flushing to finish; when the timer fires,
+ we'll send the UIProcess a DidUpdateInWindowState so it can stop blocking.
+
+ * WebProcess/WebPage/WebPage.h:
+ (WebPage): Add didUpdateInWindowStateTimerFired and m_sendDidUpdateInWindowStateTimer.
+
2013-04-18 Anders Carlsson <ander...@apple.com>
StorageManager should keep track of local storage namespaces
Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm (148712 => 148713)
--- trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm 2013-04-18 23:40:20 UTC (rev 148713)
@@ -218,7 +218,7 @@
NSRect _windowBottomCornerIntersectionRect;
unsigned _frameSizeUpdatesDisabledCount;
- unsigned _viewInWindowChangesDeferredCount;
+ BOOL _shouldDeferViewInWindowChanges;
BOOL _viewInWindowChangeWasDeferred;
@@ -3392,27 +3392,48 @@
- (void)beginDeferringViewInWindowChanges
{
- _data->_viewInWindowChangesDeferredCount++;
+ if (_data->_shouldDeferViewInWindowChanges) {
+ NSLog(@"beginDeferringViewInWindowChanges was called while already deferring view-in-window changes!");
+ return;
+ }
+
+ _data->_shouldDeferViewInWindowChanges = YES;
}
- (void)endDeferringViewInWindowChanges
{
- if (!_data->_viewInWindowChangesDeferredCount) {
- NSLog(@"endDeferringViewInWindowChanges was called without a matching beginDeferringViewInWindowChanges!");
+ if (!_data->_shouldDeferViewInWindowChanges) {
+ NSLog(@"endDeferringViewInWindowChanges was called without beginDeferringViewInWindowChanges!");
return;
}
- --_data->_viewInWindowChangesDeferredCount;
+ _data->_shouldDeferViewInWindowChanges = NO;
- if (!_data->_viewInWindowChangesDeferredCount && _data->_viewInWindowChangeWasDeferred) {
+ if (_data->_viewInWindowChangeWasDeferred) {
_data->_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
_data->_viewInWindowChangeWasDeferred = NO;
}
}
+- (void)endDeferringViewInWindowChangesSync
+{
+ if (!_data->_shouldDeferViewInWindowChanges) {
+ NSLog(@"endDeferringViewInWindowChangesSync was called without beginDeferringViewInWindowChanges!");
+ return;
+ }
+
+ PageClient* pageClient = _data->_pageClient.get();
+ bool hasPendingViewInWindowChange = _data->_viewInWindowChangeWasDeferred && _data->_page->isInWindow() != pageClient->isViewInWindow();
+
+ [self endDeferringViewInWindowChanges];
+
+ if (hasPendingViewInWindowChange)
+ _data->_page->waitForDidUpdateInWindowState();
+}
+
- (BOOL)isDeferringViewInWindowChanges
{
- return _data->_viewInWindowChangesDeferredCount;
+ return _data->_shouldDeferViewInWindowChanges;
}
- (BOOL)windowOcclusionDetectionEnabled
Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKViewPrivate.h (148712 => 148713)
--- trunk/Source/WebKit2/UIProcess/API/mac/WKViewPrivate.h 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKViewPrivate.h 2013-04-18 23:40:20 UTC (rev 148713)
@@ -67,6 +67,7 @@
- (void)beginDeferringViewInWindowChanges;
- (void)endDeferringViewInWindowChanges;
+- (void)endDeferringViewInWindowChangesSync;
- (BOOL)isDeferringViewInWindowChanges;
- (BOOL)windowOcclusionDetectionEnabled;
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (148712 => 148713)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2013-04-18 23:40:20 UTC (rev 148713)
@@ -308,6 +308,7 @@
, m_minimumLayoutWidth(0)
, m_mediaVolume(1)
, m_mayStartMediaWhenInWindow(true)
+ , m_waitingForDidUpdateInWindowState(false)
#if ENABLE(PAGE_VISIBILITY_API)
, m_visibilityState(PageVisibilityStateVisible)
#endif
@@ -1040,6 +1041,20 @@
updateBackingStoreDiscardableState();
}
+void WebPageProxy::waitForDidUpdateInWindowState()
+{
+ // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
+ if (m_waitingForDidUpdateInWindowState)
+ return;
+
+ m_waitingForDidUpdateInWindowState = true;
+
+ if (!m_process->isLaunching()) {
+ const double inWindowStateUpdateTimeout = 0.25;
+ m_process->connection()->waitForAndDispatchImmediately<Messages::WebPageProxy::DidUpdateInWindowState>(m_pageID, inWindowStateUpdateTimeout);
+ }
+}
+
IntSize WebPageProxy::viewSize() const
{
return m_pageClient->viewSize();
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (148712 => 148713)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2013-04-18 23:40:20 UTC (rev 148713)
@@ -341,6 +341,8 @@
};
typedef unsigned ViewStateFlags;
void viewStateDidChange(ViewStateFlags flags);
+ bool isInWindow() const { return m_isInWindow; }
+ void waitForDidUpdateInWindowState();
WebCore::IntSize viewSize() const;
bool isViewVisible() const { return m_isVisible; }
@@ -492,6 +494,7 @@
void listenForLayoutMilestones(WebCore::LayoutMilestones);
void setVisibilityState(WebCore::PageVisibilityState, bool isInitialState);
+ void didUpdateInWindowState() { m_waitingForDidUpdateInWindowState = false; }
bool hasHorizontalScrollbar() const { return m_mainFrameHasHorizontalScrollbar; }
bool hasVerticalScrollbar() const { return m_mainFrameHasVerticalScrollbar; }
@@ -1260,6 +1263,8 @@
float m_mediaVolume;
bool m_mayStartMediaWhenInWindow;
+ bool m_waitingForDidUpdateInWindowState;
+
#if PLATFORM(QT)
WTF::HashSet<RefPtr<QtRefCountedNetworkRequestData> > m_applicationSchemeRequests;
#endif
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in (148712 => 148713)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in 2013-04-18 23:40:20 UTC (rev 148713)
@@ -318,4 +318,5 @@
GetPluginPath(WTF::String mimeType, WTF::String urlString, WTF::String frameURLString, WTF::String pageURLString) -> (WTF::String pluginPath, uint32_t pluginLoadPolicy)
#endif
+ DidUpdateInWindowState()
}
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (148712 => 148713)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2013-04-18 23:40:20 UTC (rev 148713)
@@ -253,6 +253,7 @@
, m_accessibilityObject(0)
#endif
, m_setCanStartMediaTimer(RunLoop::main(), this, &WebPage::setCanStartMediaTimerFired)
+ , m_sendDidUpdateInWindowStateTimer(RunLoop::main(), this, &WebPage::didUpdateInWindowStateTimerFired)
, m_findController(this)
#if ENABLE(TOUCH_EVENTS)
#if PLATFORM(QT)
@@ -1977,6 +1978,11 @@
m_page->setCanStartMedia(true);
}
+void WebPage::didUpdateInWindowStateTimerFired()
+{
+ send(Messages::WebPageProxy::DidUpdateInWindowState());
+}
+
inline bool WebPage::canHandleUserEvents() const
{
#if USE(TILED_BACKING_STORE)
@@ -2011,6 +2017,7 @@
}
m_page->setIsInWindow(isInWindow);
+ m_sendDidUpdateInWindowStateTimer.startOneShot(0);
}
void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction, uint64_t downloadID)
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (148712 => 148713)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2013-04-18 23:32:20 UTC (rev 148712)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2013-04-18 23:40:20 UTC (rev 148713)
@@ -819,6 +819,7 @@
void changeSelectedIndex(int32_t index);
void setCanStartMediaTimerFired();
+ void didUpdateInWindowStateTimerFired();
bool canHandleUserEvents() const;
@@ -915,6 +916,7 @@
#endif
WebCore::RunLoop::Timer<WebPage> m_setCanStartMediaTimer;
+ WebCore::RunLoop::Timer<WebPage> m_sendDidUpdateInWindowStateTimer;
bool m_mayStartMediaWhenInWindow;
HashMap<uint64_t, RefPtr<WebUndoStep> > m_undoStepMap;