Provide SPI to asynchronously move a WKView into a window and know when it has painted
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Dec 2014 23:00:13 +0000 (23:00 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Dec 2014 23:00:13 +0000 (23:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=139460
<rdar://problem/19135389>

Reviewed by Anders Carlsson.

* UIProcess/API/Cocoa/WKViewPrivate.h:
Add _prepareForMoveToWindow:withCompletionHandler:, which internally
goes through the motions of being parented in that window and calls
the completion handler once painting is done and the view is ready
to be displayed (upon which we expect the view to actually move into the window).

* UIProcess/API/mac/WKView.mm:
(-[WKView viewWillMoveToWindow:]):
If we currently have a _targetWindowForMovePreparation (and are
pretending to be in that window), avoid performing viewWillMoveToWindow:
for a different window.

(-[WKView viewDidMoveToWindow]):
(-[WKView doWindowDidChangeScreen]):
(-[WKView _intrinsicDeviceScaleFactor]):
(-[WKView _colorSpace]):
(-[WKView _targetWindowForMovePreparation]):
If we have a _targetWindowForMovePreparation, use its properties instead
of self.window's.

(-[WKView _prepareForMoveToWindow:withCompletionHandler:]):
Simulate a move into the target window, but defer sending the view state update.
Then, send the view state update after registering the completion handler.

* UIProcess/API/mac/WKViewInternal.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
Rename m_viewStateChangeWantsReply to m_viewStateChangeWantsSynchronousReply.

(WebKit::WebPageProxy::installViewStateChangeCompletionHandler):
Added. Allow installing a block that will be called the next time
we get a didUpdateViewState back from the WebProcess after pushing the
current view state changes.

(WebKit::WebPageProxy::viewStateDidChange):
Adapt to the aforementioned rename.

(WebKit::WebPageProxy::dispatchViewStateChange):
Adapt to the aforementioned rename.
Send the view state change callback IDs along with SetViewState.

(WebKit::WebPageProxy::updateViewState):
Adapt to the aforementioned rename.

* UIProcess/WebPageProxy.h:
* UIProcess/mac/PageClientImpl.h:
* UIProcess/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::activeWindow):
(WebKit::PageClientImpl::isViewWindowActive):
(WebKit::PageClientImpl::isViewVisible):
(WebKit::PageClientImpl::isViewVisibleOrOccluded):
(WebKit::PageClientImpl::isViewInWindow):
(WebKit::PageClientImpl::viewLayerHostingMode):
If we have a _targetWindowForMovePreparation, use its properties instead
of the WKView's window's.

* WebProcess/WebPage/DrawingArea.h:
(WebKit::DrawingArea::viewStateDidChange):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::reinitializeWebPage):
(WebKit::WebPage::setViewState):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:
* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::viewStateDidChange):
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.h:
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::TiledCoreAnimationDrawingArea::viewStateDidChange):
Push the callback IDs to the WebProcess, and accumulate them in TiledCoreAnimationDrawingArea.

(WebKit::TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired):
Call all of the callbacks after one runloop cycle, just like DidUpdateViewState.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@177104 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKViewPrivate.h
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/API/mac/WKViewInternal.h
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/mac/PageClientImpl.h
Source/WebKit2/UIProcess/mac/PageClientImpl.mm
Source/WebKit2/WebProcess/WebPage/DrawingArea.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm
Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.h
Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm

index f74b7c7..ec47e96 100644 (file)
@@ -1,3 +1,85 @@
+2014-12-10  Timothy Horton  <timothy_horton@apple.com>
+
+        Provide SPI to asynchronously move a WKView into a window and know when it has painted
+        https://bugs.webkit.org/show_bug.cgi?id=139460
+        <rdar://problem/19135389>
+
+        Reviewed by Anders Carlsson.
+
+        * UIProcess/API/Cocoa/WKViewPrivate.h:
+        Add _prepareForMoveToWindow:withCompletionHandler:, which internally
+        goes through the motions of being parented in that window and calls
+        the completion handler once painting is done and the view is ready
+        to be displayed (upon which we expect the view to actually move into the window).
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView viewWillMoveToWindow:]):
+        If we currently have a _targetWindowForMovePreparation (and are
+        pretending to be in that window), avoid performing viewWillMoveToWindow:
+        for a different window.
+
+        (-[WKView viewDidMoveToWindow]):
+        (-[WKView doWindowDidChangeScreen]):
+        (-[WKView _intrinsicDeviceScaleFactor]):
+        (-[WKView _colorSpace]):
+        (-[WKView _targetWindowForMovePreparation]):
+        If we have a _targetWindowForMovePreparation, use its properties instead
+        of self.window's.
+
+        (-[WKView _prepareForMoveToWindow:withCompletionHandler:]):
+        Simulate a move into the target window, but defer sending the view state update.
+        Then, send the view state update after registering the completion handler.
+
+        * UIProcess/API/mac/WKViewInternal.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy):
+        Rename m_viewStateChangeWantsReply to m_viewStateChangeWantsSynchronousReply.
+
+        (WebKit::WebPageProxy::installViewStateChangeCompletionHandler):
+        Added. Allow installing a block that will be called the next time
+        we get a didUpdateViewState back from the WebProcess after pushing the
+        current view state changes.
+
+        (WebKit::WebPageProxy::viewStateDidChange):
+        Adapt to the aforementioned rename.
+
+        (WebKit::WebPageProxy::dispatchViewStateChange):
+        Adapt to the aforementioned rename.
+        Send the view state change callback IDs along with SetViewState.
+
+        (WebKit::WebPageProxy::updateViewState):
+        Adapt to the aforementioned rename.
+
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/mac/PageClientImpl.h:
+        * UIProcess/mac/PageClientImpl.mm:
+        (WebKit::PageClientImpl::activeWindow):
+        (WebKit::PageClientImpl::isViewWindowActive):
+        (WebKit::PageClientImpl::isViewVisible):
+        (WebKit::PageClientImpl::isViewVisibleOrOccluded):
+        (WebKit::PageClientImpl::isViewInWindow):
+        (WebKit::PageClientImpl::viewLayerHostingMode):
+        If we have a _targetWindowForMovePreparation, use its properties instead
+        of the WKView's window's.
+
+        * WebProcess/WebPage/DrawingArea.h:
+        (WebKit::DrawingArea::viewStateDidChange):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::reinitializeWebPage):
+        (WebKit::WebPage::setViewState):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:
+        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
+        (WebKit::RemoteLayerTreeDrawingArea::viewStateDidChange):
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.h:
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
+        (WebKit::TiledCoreAnimationDrawingArea::viewStateDidChange):
+        Push the callback IDs to the WebProcess, and accumulate them in TiledCoreAnimationDrawingArea.
+
+        (WebKit::TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired):
+        Call all of the callbacks after one runloop cycle, just like DidUpdateViewState.
+
 2014-12-10  Anders Carlsson  <andersca@apple.com>
 
         Add session storage handling to StorageNamespaceProvider
index e5e49e1..85232a5 100644 (file)
 - (void)endDeferringViewInWindowChanges;
 - (void)endDeferringViewInWindowChangesSync;
 - (BOOL)isDeferringViewInWindowChanges;
+- (void)_prepareForMoveToWindow:(NSWindow *)targetWindow withCompletionHandler:(void(^)(void))completionHandler;
 
 - (BOOL)windowOcclusionDetectionEnabled;
 - (void)setWindowOcclusionDetectionEnabled:(BOOL)flag;
index fb1a0e3..3fce0ac 100644 (file)
@@ -227,6 +227,7 @@ struct WKViewInterpretKeyEventsParameters {
     
     unsigned _frameSizeUpdatesDisabledCount;
     BOOL _shouldDeferViewInWindowChanges;
+    NSWindow *_targetWindowForMovePreparation;
 
     BOOL _viewInWindowChangeWasDeferred;
 
@@ -2497,7 +2498,7 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 
 - (void)removeWindowObservers
 {
-    NSWindow *window = [self window];
+    NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : [self window];
     if (!window)
         return;
 
@@ -2524,6 +2525,9 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 
 - (void)viewWillMoveToWindow:(NSWindow *)window
 {
+    // If we're in the middle of preparing to move to a window, we should only be moved to that window.
+    ASSERT(!_data->_targetWindowForMovePreparation || (_data->_targetWindowForMovePreparation == window));
+
     NSWindow *currentWindow = [self window];
     if (window == currentWindow)
         return;
@@ -2536,7 +2540,9 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 
 - (void)viewDidMoveToWindow
 {
-    if ([self window]) {
+    NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : self.window;
+
+    if (window) {
         [self doWindowDidChangeScreen];
 
         ViewState::Flags viewStateChanges = ViewState::WindowIsActive | ViewState::IsVisible;
@@ -2580,7 +2586,8 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 
 - (void)doWindowDidChangeScreen
 {
-    _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
+    NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : self.window;
+    _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
 }
 
 - (void)_windowDidBecomeKey:(NSNotification *)notification
@@ -2817,8 +2824,9 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 
 - (float)_intrinsicDeviceScaleFactor
 {
-    NSWindow *window = [self window];
-    if (window)
+    if (_data->_targetWindowForMovePreparation)
+        return [_data->_targetWindowForMovePreparation backingScaleFactor];
+    if (NSWindow *window = [self window])
         return [window backingScaleFactor];
     return [[NSScreen mainScreen] backingScaleFactor];
 }
@@ -2863,8 +2871,10 @@ static void* keyValueObservingContext = &keyValueObservingContext;
 - (WebKit::ColorSpaceData)_colorSpace
 {
     if (!_data->_colorSpace) {
-        if ([self window])
-            _data->_colorSpace = [[self window] colorSpace];
+        if (_data->_targetWindowForMovePreparation)
+            _data->_colorSpace = [_data->_targetWindowForMovePreparation colorSpace];
+        else if (NSWindow *window = [self window])
+            _data->_colorSpace = [window colorSpace];
         else
             _data->_colorSpace = [[NSScreen mainScreen] colorSpace];
     }
@@ -4005,6 +4015,31 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
     }
 }
 
+- (void)_prepareForMoveToWindow:(NSWindow *)targetWindow withCompletionHandler:(void(^)(void))completionHandler
+{
+    _data->_shouldDeferViewInWindowChanges = YES;
+    [self viewWillMoveToWindow:targetWindow];
+    _data->_targetWindowForMovePreparation = targetWindow;
+    [self viewDidMoveToWindow];
+
+    _data->_shouldDeferViewInWindowChanges = NO;
+
+    _data->_page->installViewStateChangeCompletionHandler(^() {
+        completionHandler();
+        ASSERT(self.window == _data->_targetWindowForMovePreparation);
+        _data->_targetWindowForMovePreparation = nil;
+    });
+
+    [self _dispatchSetTopContentInset];
+    _data->_page->viewStateDidChange(ViewState::IsInWindow, false, WebPageProxy::ViewStateChangeDispatchMode::Immediate);
+    _data->_viewInWindowChangeWasDeferred = NO;
+}
+
+- (NSWindow *)_targetWindowForMovePreparation
+{
+    return _data->_targetWindowForMovePreparation;
+}
+
 - (BOOL)isDeferringViewInWindowChanges
 {
     return _data->_shouldDeferViewInWindowChanges;
index 719ad40..9e83f8f 100644 (file)
@@ -132,4 +132,6 @@ struct WebPageConfiguration;
 
 @property (nonatomic, retain, setter=_setPrimaryTrackingArea:) NSTrackingArea *_primaryTrackingArea;
 
+@property (readonly) NSWindow *_targetWindowForMovePreparation;
+
 @end
index 627be96..471feb9 100644 (file)
@@ -375,7 +375,7 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     , m_navigationID(0)
     , m_configurationPreferenceValues(configuration.preferenceValues)
     , m_potentiallyChangedViewStateFlags(ViewState::NoFlags)
-    , m_viewStateChangeWantsReply(false)
+    , m_viewStateChangeWantsSynchronousReply(false)
     , m_isPlayingAudio(false)
 {
     m_websiteDataStore->addWebPage(*this);
@@ -1174,10 +1174,26 @@ void WebPageProxy::updateViewState(ViewState::Flags flagsToUpdate)
         m_viewState |= ViewState::IsVisuallyIdle;
 }
 
-void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, bool wantsReply, ViewStateChangeDispatchMode dispatchMode)
+void WebPageProxy::installViewStateChangeCompletionHandler(void (^completionHandler)())
+{
+    if (!isValid()) {
+        completionHandler();
+        return;
+    }
+
+    auto copiedCompletionHandler = Block_copy(completionHandler);
+    RefPtr<VoidCallback> voidCallback = VoidCallback::create([copiedCompletionHandler] (CallbackBase::Error) {
+        copiedCompletionHandler();
+        Block_release(copiedCompletionHandler);
+    }, std::make_unique<ProcessThrottler::BackgroundActivityToken>(m_process->throttler()));
+    uint64_t callbackID = m_callbacks.put(voidCallback.release());
+    m_nextViewStateChangeCallbacks.append(callbackID);
+}
+
+void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, bool wantsSynchronousReply, ViewStateChangeDispatchMode dispatchMode)
 {
     m_potentiallyChangedViewStateFlags |= mayHaveChanged;
-    m_viewStateChangeWantsReply = m_viewStateChangeWantsReply || wantsReply;
+    m_viewStateChangeWantsSynchronousReply = m_viewStateChangeWantsSynchronousReply || wantsSynchronousReply;
 
 #if PLATFORM(COCOA)
     bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ViewState::IsInWindow) && m_pageClient.isViewInWindow();
@@ -1236,10 +1252,12 @@ void WebPageProxy::dispatchViewStateChange()
 
     // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
     if (m_viewWasEverInWindow && (changed & ViewState::IsInWindow) && isInWindow())
-        m_viewStateChangeWantsReply = true;
+        m_viewStateChangeWantsSynchronousReply = true;
+
+    if (changed || m_viewStateChangeWantsSynchronousReply)
+        m_process->send(Messages::WebPage::SetViewState(m_viewState, m_viewStateChangeWantsSynchronousReply, m_nextViewStateChangeCallbacks), m_pageID);
 
-    if (changed || m_viewStateChangeWantsReply)
-        m_process->send(Messages::WebPage::SetViewState(m_viewState, m_viewStateChangeWantsReply), m_pageID);
+    m_nextViewStateChangeCallbacks.clear();
 
     // This must happen after the SetViewState message is sent, to ensure the page visibility event can fire.
     updateActivityToken();
@@ -1262,11 +1280,11 @@ void WebPageProxy::dispatchViewStateChange()
 
     updateBackingStoreDiscardableState();
 
-    if (m_viewStateChangeWantsReply)
+    if (m_viewStateChangeWantsSynchronousReply)
         waitForDidUpdateViewState();
 
     m_potentiallyChangedViewStateFlags = ViewState::NoFlags;
-    m_viewStateChangeWantsReply = false;
+    m_viewStateChangeWantsSynchronousReply = false;
 }
 
 void WebPageProxy::updateActivityToken()
index 9b55c07..337a415 100644 (file)
@@ -371,7 +371,8 @@ public:
     bool delegatesScrolling() const { return m_delegatesScrolling; }
 
     enum class ViewStateChangeDispatchMode { Deferrable, Immediate };
-    void viewStateDidChange(WebCore::ViewState::Flags mayHaveChanged, bool wantsReply = false, ViewStateChangeDispatchMode = ViewStateChangeDispatchMode::Deferrable);
+    void viewStateDidChange(WebCore::ViewState::Flags mayHaveChanged, bool wantsSynchronousReply = false, ViewStateChangeDispatchMode = ViewStateChangeDispatchMode::Deferrable);
+    void installViewStateChangeCompletionHandler(void(^completionHandler)());
     bool isInWindow() const { return m_viewState & WebCore::ViewState::IsInWindow; }
     void waitForDidUpdateViewState();
     void didUpdateViewState() { m_waitingForDidUpdateViewState = false; }
@@ -1585,7 +1586,8 @@ private:
 
     WebPreferencesStore::ValueMap m_configurationPreferenceValues;
     WebCore::ViewState::Flags m_potentiallyChangedViewStateFlags;
-    bool m_viewStateChangeWantsReply;
+    bool m_viewStateChangeWantsSynchronousReply;
+    Vector<uint64_t> m_nextViewStateChangeCallbacks;
 
     bool m_isPlayingAudio;
 };
index df7f98a..32cc1d9 100644 (file)
@@ -183,6 +183,7 @@ private:
     virtual void willRecordNavigationSnapshot(WebBackForwardListItem&) override;
 
     NSView *activeView() const;
+    NSWindow *activeWindow() const;
 
     virtual void didFirstVisuallyNonEmptyLayoutForMainFrame() override;
     virtual void didFinishLoadForMainFrame() override;
index 10dba0b..8140330 100644 (file)
@@ -196,9 +196,20 @@ NSView *PageClientImpl::activeView() const
 #endif
 }
 
+NSWindow *PageClientImpl::activeWindow() const
+{
+#if WK_API_ENABLED
+    if (m_wkView._thumbnailView)
+        return m_wkView._thumbnailView.window;
+#endif
+    if (m_wkView._targetWindowForMovePreparation)
+        return m_wkView._targetWindowForMovePreparation;
+    return m_wkView.window;
+}
+
 bool PageClientImpl::isViewWindowActive()
 {
-    NSWindow *activeViewWindow = activeView().window;
+    NSWindow *activeViewWindow = activeWindow();
     return activeViewWindow.isKeyWindow || [NSApp keyWindow] == activeViewWindow;
 }
 
@@ -215,7 +226,7 @@ void PageClientImpl::makeFirstResponder()
 bool PageClientImpl::isViewVisible()
 {
     NSView *activeView = this->activeView();
-    NSWindow *activeViewWindow = activeView.window;
+    NSWindow *activeViewWindow = activeWindow();
 
     if (!activeViewWindow)
         return false;
@@ -243,12 +254,12 @@ bool PageClientImpl::isViewVisible()
 
 bool PageClientImpl::isViewVisibleOrOccluded()
 {
-    return activeView().window.isVisible;
+    return activeWindow().isVisible;
 }
 
 bool PageClientImpl::isViewInWindow()
 {
-    return activeView().window;
+    return activeWindow();
 }
 
 bool PageClientImpl::isVisuallyIdle()
@@ -259,7 +270,7 @@ bool PageClientImpl::isVisuallyIdle()
 LayerHostingMode PageClientImpl::viewLayerHostingMode()
 {
 #if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
-    if ([activeView().window _hostsLayersInWindowServer])
+    if ([activeWindow() _hostsLayersInWindowServer])
         return LayerHostingMode::OutOfProcess;
 #endif
     return LayerHostingMode::InProcess;
index 839c008..441e118 100644 (file)
@@ -115,7 +115,7 @@ public:
 
     virtual void dispatchAfterEnsuringUpdatedScrollPosition(std::function<void ()>);
 
-    virtual void viewStateDidChange(WebCore::ViewState::Flags, bool /*wantsDidUpdateViewState*/) { }
+    virtual void viewStateDidChange(WebCore::ViewState::Flags, bool /* wantsDidUpdateViewState */, const Vector<uint64_t>& /* callbackIDs */) { }
     virtual void setLayerHostingMode(LayerHostingMode) { }
 
     virtual bool markLayersVolatileImmediatelyIfPossible() { return true; }
index 90a2415..497ce14 100644 (file)
@@ -504,7 +504,7 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
 void WebPage::reinitializeWebPage(const WebPageCreationParameters& parameters)
 {
     if (m_viewState != parameters.viewState)
-        setViewState(parameters.viewState);
+        setViewState(parameters.viewState, false, Vector<uint64_t>());
     if (m_layerHostingMode != parameters.layerHostingMode)
         setLayerHostingMode(static_cast<unsigned>(parameters.layerHostingMode));
 }
@@ -2311,7 +2311,7 @@ void WebPage::updateIsInWindow(bool isInitialState)
         layoutIfNeeded();
 }
 
-void WebPage::setViewState(ViewState::Flags viewState, bool wantsDidUpdateViewState)
+void WebPage::setViewState(ViewState::Flags viewState, bool wantsDidUpdateViewState, const Vector<uint64_t>& callbackIDs)
 {
     ViewState::Flags changed = m_viewState ^ viewState;
     m_viewState = viewState;
@@ -2320,7 +2320,7 @@ void WebPage::setViewState(ViewState::Flags viewState, bool wantsDidUpdateViewSt
     for (auto* pluginView : m_pluginViews)
         pluginView->viewStateDidChange(changed);
 
-    m_drawingArea->viewStateDidChange(changed, wantsDidUpdateViewState);
+    m_drawingArea->viewStateDidChange(changed, wantsDidUpdateViewState, callbackIDs);
 
     if (changed & ViewState::IsInWindow)
         updateIsInWindow();
index 91d9193..e1410d9 100644 (file)
@@ -925,7 +925,7 @@ private:
     void setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent&);
     void setWindowResizerSize(const WebCore::IntSize&);
     void updateIsInWindow(bool isInitialState = false);
-    void setViewState(WebCore::ViewState::Flags, bool wantsDidUpdateViewState = false);
+    void setViewState(WebCore::ViewState::Flags, bool wantsDidUpdateViewState, const Vector<uint64_t>& callbackIDs);
     void validateCommand(const String&, uint64_t);
     void executeEditCommand(const String&);
 
index ae797ec..b912da5 100644 (file)
@@ -22,7 +22,7 @@
 
 messages -> WebPage LegacyReceiver {
     SetInitialFocus(bool forward, bool isKeyboardEventValid, WebKit::WebKeyboardEvent event)
-    SetViewState(unsigned viewState, bool wantsDidUpdateViewState)
+    SetViewState(unsigned viewState, bool wantsDidUpdateViewState, Vector<uint64_t> callbackIDs)
     SetLayerHostingMode(unsigned layerHostingMode)
 
     SetSessionID(WebCore::SessionID sessionID)
index fce5c14..95a2dfc 100644 (file)
@@ -103,7 +103,7 @@ private:
 
     virtual void mainFrameContentSizeChanged(const WebCore::IntSize&) override;
 
-    virtual void viewStateDidChange(WebCore::ViewState::Flags changed, bool wantsDidUpdateViewState) override;
+    virtual void viewStateDidChange(WebCore::ViewState::Flags changed, bool wantsDidUpdateViewState, const Vector<uint64_t>& callbackIDs) override;
 
     virtual bool adjustLayerFlushThrottling(WebCore::LayerFlushThrottleState::Flags) override;
 
index 9703266..f131d5e 100644 (file)
@@ -467,7 +467,7 @@ void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
     m_connection->sendMessage(WTF::move(m_commitEncoder));
 }
 
-void RemoteLayerTreeDrawingArea::viewStateDidChange(ViewState::Flags, bool wantsDidUpdateViewState)
+void RemoteLayerTreeDrawingArea::viewStateDidChange(ViewState::Flags, bool wantsDidUpdateViewState, const Vector<uint64_t>&)
 {
     // FIXME: Should we suspend painting while not visible, like TiledCoreAnimationDrawingArea? Probably.
 
index e11f6e7..ec6824c 100644 (file)
@@ -81,7 +81,7 @@ private:
 
     virtual bool shouldUseTiledBackingForFrameView(const WebCore::FrameView*) override;
 
-    virtual void viewStateDidChange(WebCore::ViewState::Flags changed, bool wantsDidUpdateViewState) override;
+    virtual void viewStateDidChange(WebCore::ViewState::Flags changed, bool wantsDidUpdateViewState, const Vector<uint64_t>&) override;
     void didUpdateViewStateTimerFired();
 
     virtual void attachViewOverlayGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer*) override;
@@ -141,6 +141,8 @@ private:
     WebCore::TransformationMatrix m_transform;
 
     RunLoop::Timer<TiledCoreAnimationDrawingArea> m_sendDidUpdateViewStateTimer;
+    Vector<uint64_t> m_nextViewStateChangeCallbackIDs;
+    bool m_wantsDidUpdateViewState;
 
     WebCore::GraphicsLayer* m_viewOverlayRootLayer;
 };
index fabe820..919c862 100644 (file)
@@ -78,6 +78,7 @@ TiledCoreAnimationDrawingArea::TiledCoreAnimationDrawingArea(WebPage& webPage, c
     , m_scrolledExposedRect(FloatRect::infiniteRect())
     , m_transientZoomScale(1)
     , m_sendDidUpdateViewStateTimer(RunLoop::main(), this, &TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired)
+    , m_wantsDidUpdateViewState(false)
     , m_viewOverlayRootLayer(nullptr)
 {
     m_webPage.corePage()->settings().setForceCompositingMode(true);
@@ -327,8 +328,11 @@ bool TiledCoreAnimationDrawingArea::flushLayers()
     }
 }
 
-void TiledCoreAnimationDrawingArea::viewStateDidChange(ViewState::Flags changed, bool wantsDidUpdateViewState)
+void TiledCoreAnimationDrawingArea::viewStateDidChange(ViewState::Flags changed, bool wantsDidUpdateViewState, const Vector<uint64_t>& nextViewStateChangeCallbackIDs)
 {
+    m_nextViewStateChangeCallbackIDs.appendVector(nextViewStateChangeCallbackIDs);
+    m_wantsDidUpdateViewState |= wantsDidUpdateViewState;
+
     if (changed & ViewState::IsVisible) {
         if (m_webPage.isVisible())
             resumePainting();
@@ -336,14 +340,22 @@ void TiledCoreAnimationDrawingArea::viewStateDidChange(ViewState::Flags changed,
             suspendPainting();
     }
 
-    if (wantsDidUpdateViewState)
+    if (m_wantsDidUpdateViewState || !m_nextViewStateChangeCallbackIDs.isEmpty())
         m_sendDidUpdateViewStateTimer.startOneShot(0);
 }
 
 void TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired()
 {
     [CATransaction flush];
-    m_webPage.send(Messages::WebPageProxy::DidUpdateViewState());
+
+    if (m_wantsDidUpdateViewState)
+        m_webPage.send(Messages::WebPageProxy::DidUpdateViewState());
+
+    for (uint64_t callbackID : m_nextViewStateChangeCallbackIDs)
+        m_webPage.send(Messages::WebPageProxy::VoidCallback(callbackID));
+
+    m_nextViewStateChangeCallbackIDs.clear();
+    m_wantsDidUpdateViewState = false;
 }
 
 void TiledCoreAnimationDrawingArea::suspendPainting()