[wk2] Don't dispatch view state changes immediately
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Jun 2014 20:43:50 +0000 (20:43 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Jun 2014 20:43:50 +0000 (20:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133713

Reviewed by Simon Fraser.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
(WebKit::WebPageProxy::viewStateDidChange):
(WebKit::WebPageProxy::dispatchViewStateChange):
(WebKit::WebPageProxy::updateViewState): Deleted.
* UIProcess/WebPageProxy.h:
On PLATFORM(COCOA), wait until just before CA is going to commit the UI process layer
tree to dispatch view state changes to the Web process. This avoids sending multiple
view state change messages to the Web process within one run-loop cycle, for example
when a view is moved around in the view hierarchy but the view state otherwise remains the same.

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h

index 2483f9a..4c817ed 100644 (file)
@@ -1,5 +1,23 @@
 2014-06-11  Timothy Horton  <timothy_horton@apple.com>
 
+        [wk2] Don't dispatch view state changes immediately
+        https://bugs.webkit.org/show_bug.cgi?id=133713
+
+        Reviewed by Simon Fraser.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy):
+        (WebKit::WebPageProxy::viewStateDidChange):
+        (WebKit::WebPageProxy::dispatchViewStateChange):
+        (WebKit::WebPageProxy::updateViewState): Deleted.
+        * UIProcess/WebPageProxy.h:
+        On PLATFORM(COCOA), wait until just before CA is going to commit the UI process layer
+        tree to dispatch view state changes to the Web process. This avoids sending multiple
+        view state change messages to the Web process within one run-loop cycle, for example
+        when a view is moved around in the view hierarchy but the view state otherwise remains the same.
+
+2014-06-11  Timothy Horton  <timothy_horton@apple.com>
+
         Make it possible for waitForAndDispatchImmediately to bail if a sync message comes in from the other direction
         https://bugs.webkit.org/show_bug.cgi?id=133708
 
index 448b13a..185687a 100644 (file)
 
 #if PLATFORM(COCOA)
 #include "ViewSnapshotStore.h"
+#include <WebCore/RunLoopObserver.h>
 #endif
 
 #if PLATFORM(IOS)
@@ -365,6 +366,8 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     , m_scrollPinningBehavior(DoNotPin)
     , m_navigationID(0)
     , m_configurationPreferenceValues(configuration.preferenceValues)
+    , m_potentiallyChangedViewStateFlags(ViewState::NoFlags)
+    , m_viewStateChangeWantsReply(WantsReplyOrNot::DoesNotWantReply)
 {
     if (m_process->state() == WebProcessProxy::State::Running) {
         if (m_userContentController)
@@ -409,6 +412,13 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     IPC::Connection* connection = m_process->state() == WebProcessProxy::State::Running ? m_process->connection() : nullptr;
     m_process->context().storageManager().createSessionStorageNamespace(m_pageID, connection, std::numeric_limits<unsigned>::max());
     setSession(*configuration.session);
+
+#if PLATFORM(COCOA)
+    const CFIndex viewStateChangeRunLoopOrder = (CFIndex)RunLoopObserver::WellKnownRunLoopOrders::CoreAnimationCommit - 1;
+    m_viewStateChangeDispatcher = RunLoopObserver::create(viewStateChangeRunLoopOrder, [this]() {
+        this->dispatchViewStateChange();
+    });
+#endif
 }
 
 WebPageProxy::~WebPageProxy()
@@ -1092,25 +1102,41 @@ void WebPageProxy::updateViewState(ViewState::Flags flagsToUpdate)
 
 void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, WantsReplyOrNot wantsReply)
 {
+    m_potentiallyChangedViewStateFlags |= mayHaveChanged;
+    m_viewStateChangeWantsReply = (wantsReply == WantsReplyOrNot::DoesWantReply || m_viewStateChangeWantsReply == WantsReplyOrNot::DoesWantReply) ? WantsReplyOrNot::DoesWantReply : WantsReplyOrNot::DoesNotWantReply;
+
+#if PLATFORM(COCOA)
+    m_viewStateChangeDispatcher->schedule();
+#else
+    dispatchViewStateChange();
+#endif
+}
+
+void WebPageProxy::dispatchViewStateChange()
+{
+#if PLATFORM(COCOA)
+    m_viewStateChangeDispatcher->invalidate();
+#endif
+
     if (!isValid())
         return;
 
     // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
-    if (mayHaveChanged & ViewState::IsVisible)
-        mayHaveChanged |= ViewState::IsVisibleOrOccluded | ViewState::IsVisuallyIdle;
+    if (m_potentiallyChangedViewStateFlags & ViewState::IsVisible)
+        m_potentiallyChangedViewStateFlags |= ViewState::IsVisibleOrOccluded | ViewState::IsVisuallyIdle;
 
     // Record the prior view state, update the flags that may have changed,
     // and check which flags have actually changed.
     ViewState::Flags previousViewState = m_viewState;
-    updateViewState(mayHaveChanged);
+    updateViewState(m_potentiallyChangedViewStateFlags);
     ViewState::Flags changed = m_viewState ^ previousViewState;
 
     if (changed)
-        m_process->send(Messages::WebPage::SetViewState(m_viewState, wantsReply == WantsReplyOrNot::DoesWantReply), m_pageID);
-    
+        m_process->send(Messages::WebPage::SetViewState(m_viewState, m_viewStateChangeWantsReply == WantsReplyOrNot::DoesWantReply), m_pageID);
+
     // This must happen after the SetViewState message is sent, to ensure the page visibility event can fire.
     updateActivityToken();
-    
+
     if (changed & ViewState::IsVisuallyIdle)
         m_process->pageSuppressibilityChanged(this);
 
@@ -1120,7 +1146,7 @@ void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, WantsRepl
     if ((changed & ViewState::IsVisible) && !isViewVisible())
         m_process->responsivenessTimer()->stop();
 
-    if ((mayHaveChanged & ViewState::IsInWindow) && (m_viewState & ViewState::IsInWindow)) {
+    if ((m_potentiallyChangedViewStateFlags & ViewState::IsInWindow) && (m_viewState & ViewState::IsInWindow)) {
         LayerHostingMode layerHostingMode = m_pageClient.viewLayerHostingMode();
         if (m_layerHostingMode != layerHostingMode) {
             m_layerHostingMode = layerHostingMode;
@@ -1128,7 +1154,7 @@ void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, WantsRepl
         }
     }
 
-    if ((mayHaveChanged & ViewState::IsInWindow) && !(m_viewState & ViewState::IsInWindow)) {
+    if ((m_potentiallyChangedViewStateFlags & ViewState::IsInWindow) && !(m_viewState & ViewState::IsInWindow)) {
 #if ENABLE(INPUT_TYPE_COLOR_POPOVER)
         // When leaving the current page, close the popover color well.
         if (m_colorPicker)
@@ -1142,8 +1168,11 @@ void WebPageProxy::viewStateDidChange(ViewState::Flags mayHaveChanged, WantsRepl
     }
 
     updateBackingStoreDiscardableState();
+
+    m_potentiallyChangedViewStateFlags = ViewState::NoFlags;
+    m_viewStateChangeWantsReply = WantsReplyOrNot::DoesNotWantReply;
 }
-    
+
 void WebPageProxy::updateActivityToken()
 {
 #if PLATFORM(IOS)
index 710928f..4cfa36a 100644 (file)
@@ -125,6 +125,7 @@ class FloatRect;
 class GraphicsLayer;
 class IntSize;
 class ProtectionSpace;
+class RunLoopObserver;
 class SharedBuffer;
 struct FileChooserSettings;
 struct TextAlternativeWithRange;
@@ -1458,6 +1459,8 @@ private:
 
     WebPreferencesStore preferencesStore() const;
 
+    void dispatchViewStateChange();
+
     PageClient& m_pageClient;
     std::unique_ptr<API::LoaderClient> m_loaderClient;
     std::unique_ptr<API::PolicyClient> m_policyClient;
@@ -1716,6 +1719,7 @@ private:
         
 #if PLATFORM(COCOA)
     HashMap<String, String> m_temporaryPDFFiles;
+    std::unique_ptr<WebCore::RunLoopObserver> m_viewStateChangeDispatcher;
 #endif
         
     WebCore::ScrollPinningBehavior m_scrollPinningBehavior;
@@ -1723,6 +1727,8 @@ private:
     uint64_t m_navigationID;
 
     WebPreferencesStore::ValueMap m_configurationPreferenceValues;
+    WebCore::ViewState::Flags m_potentiallyChangedViewStateFlags;
+    WantsReplyOrNot m_viewStateChangeWantsReply;
 };
 
 } // namespace WebKit