Separate flushing layer changes from rendering in CACFLayerTreeHost
authoraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Jan 2011 19:35:43 +0000 (19:35 +0000)
committeraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Jan 2011 19:35:43 +0000 (19:35 +0000)
Old model:
  1) A change is made to a GraphicsLayer.
  2) CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon is called, which schedules the
     render timer.
  3) The timer fires, which calls through to CACFLayerTreeHost::render, which performs the
     flush and then renders.

New model:
  1) A change is made to a GraphicsLayer.
  2) CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon is called, which tells the new
     LayerChangesFlusher singleton that this host has changes that need to be flushed.
  3) LayerChangesFlusher sets up a Windows hook that will get called on the next iteration
     of the message loop.
  4) LayerChangesFlusher's hook is called, which calls through to
     CACFLayerTreeHost::flushPendingLayerChangesNow.
  5) CACFLayerTreeHost::flushPendingLayerChangesNow schedules the render timer so the changes
     that were just flushed to the context will be rendered.

When a change is made to a PlatformCALayer that doesn't have a corresponding GraphicsLayer
(e.g., for rendering <video>), CACFLayerTreeHost::layerTreeDidChange takes care of
scheduling the flush.

This change has three advantages:
  1) Whenever we flush layer changes, we first update layout. This can cause the page to
     leave compositing mode, which in turn can cause all references to the CACFLayerTreeHost
     to be dropped. By separating flushing (and thus updating layout) from rendering, we no
     longer have to worry about this happen during rendering.
  2) The new model is much more similar to how things work on the Mac, so will hopefully
     reduce the number of platform-specific bugs.
  3) CACFLayerTreeHost::shouldRender, which was used to make sure we didn't render while a
     layout was pending, is no longer needed. It actually hasn't been needed since at least
     r75987, but removing it before now would have resulted in a crash whenever a page came
     out of compositing mode due to (1).

Fixes <http://webkit.org/b/52852> Flushing layer changes and rendering are intertwined in
CACFLayerTreeHost, but shouldn't be

Reviewed by Simon Fraser.

Source/WebCore:

* WebCore.vcproj/WebCore.vcproj: Added LayerChangesFlusher.

* platform/graphics/ca/win/CACFLayerTreeHost.cpp: Added new #include, sorted existing
 #includes.
(WebCore::CACFLayerTreeHost::CACFLayerTreeHost): Initialize new member.
(WebCore::CACFLayerTreeHost::layerTreeDidChange): If we aren't already flushing changes,
schedule a flush. Removed the call to renderSoon(), which now happens when the flush is
finished.
(WebCore::CACFLayerTreeHost::destroyRenderer): Cancel any pending flush we had scheduled. Also
fixed a bug where we'd fail to clear the context's layer.
(WebCore::CACFLayerTreeHost::render): Removed code to ask the client if we should render, which
is no longer needed. Moved code to flush layer changes from here to
flushPendingLayerChangesNow, which is called via the above-described mechanism.
(WebCore::CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon): Schedule a flush. Removed
code to schedule a render, which now happens after we've flushed.
(WebCore::CACFLayerTreeHost::flushPendingLayerChangesNow): Added. Some of this code came from
render(). First we flush GraphicsLayer changes from GraphicsLayers to their underlying
PlatformCALayers, then we flush changes from PlatformCALayers to the context, then we
schedule a render so that the changes will be rendered to the screen.

* platform/graphics/ca/win/CACFLayerTreeHost.h: Removed
CACFLayerTreeHostClient::shouldRender. Added flushPendingLayerChangesNow and
m_isFlushingLayerChanges.

* platform/graphics/ca/win/LayerChangesFlusher.cpp: Added.
(WebCore::LayerChangesFlusher::shared):
(WebCore::LayerChangesFlusher::LayerChangesFlusher):
(WebCore::LayerChangesFlusher::flushPendingLayerChangesSoon):
(WebCore::LayerChangesFlusher::cancelPendingFlush):
(WebCore::LayerChangesFlusher::hookCallback):
(WebCore::LayerChangesFlusher::hookFired):
(WebCore::LayerChangesFlusher::setHook):
(WebCore::LayerChangesFlusher::removeHook):

* platform/graphics/ca/win/LayerChangesFlusher.cpp: Added.
(WebCore::LayerChangesFlusher::shared): Returns the singleton.
(WebCore::LayerChangesFlusher::LayerChangesFlusher): Initialize our members.
(WebCore::LayerChangesFlusher::flushPendingLayerChangesSoon): Add the host to the set of
hosts with changes that need to be flushed, and set up our hook if we haven't already.
(WebCore::LayerChangesFlusher::cancelPendingFlush): Remove the host from the set of hosts
with changes that need to be flushed. If we have no more such hosts, remove our hook, unless
we're currently in the process of calling out to our hosts, in which case we'll take care of
the hook once we're done calling out.
(WebCore::LayerChangesFlusher::hookCallback): This is the function that Windows calls when
our hook fires. Just calls through to hookFired on the singleton.
(WebCore::LayerChangesFlusher::hookFired): Tell all the hosts with changes that needed to be
flushed that it's time to flush. If no hosts re-added themselves to our set during this
process, remove our hook.
(WebCore::LayerChangesFlusher::setHook): Calls through to ::SetWindowsHookExW.
(WebCore::LayerChangesFlusher::removeHook): Calls through to ::UnhookWindowsHookEx.

* platform/graphics/ca/win/LayerChangesFlusher.h: Added.

Source/WebKit/win:

Update for CACFLayerTreeHost changes

* WebView.cpp:
(WebView::paint): Changed to flush layer changes via CACFLayerTreeHost, which will call back
to our own flushing function if needed.

* WebView.h: Removed shouldRender, which is no longer used or needed.

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

Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp
Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h
Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h [new file with mode: 0644]
Source/WebKit/win/ChangeLog
Source/WebKit/win/WebView.cpp
Source/WebKit/win/WebView.h

index 2669043..23b413d 100644 (file)
@@ -1,3 +1,99 @@
+2011-01-21  Adam Roben  <aroben@apple.com>
+
+        Separate flushing layer changes from rendering in CACFLayerTreeHost
+
+        Old model:
+          1) A change is made to a GraphicsLayer.
+          2) CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon is called, which schedules the
+             render timer.
+          3) The timer fires, which calls through to CACFLayerTreeHost::render, which performs the
+             flush and then renders.
+
+        New model:
+          1) A change is made to a GraphicsLayer.
+          2) CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon is called, which tells the new
+             LayerChangesFlusher singleton that this host has changes that need to be flushed.
+          3) LayerChangesFlusher sets up a Windows hook that will get called on the next iteration
+             of the message loop.
+          4) LayerChangesFlusher's hook is called, which calls through to
+             CACFLayerTreeHost::flushPendingLayerChangesNow.
+          5) CACFLayerTreeHost::flushPendingLayerChangesNow schedules the render timer so the changes
+             that were just flushed to the context will be rendered.
+
+        When a change is made to a PlatformCALayer that doesn't have a corresponding GraphicsLayer
+        (e.g., for rendering <video>), CACFLayerTreeHost::layerTreeDidChange takes care of
+        scheduling the flush.
+
+        This change has three advantages:
+          1) Whenever we flush layer changes, we first update layout. This can cause the page to
+             leave compositing mode, which in turn can cause all references to the CACFLayerTreeHost
+             to be dropped. By separating flushing (and thus updating layout) from rendering, we no
+             longer have to worry about this happen during rendering.
+          2) The new model is much more similar to how things work on the Mac, so will hopefully
+             reduce the number of platform-specific bugs.
+          3) CACFLayerTreeHost::shouldRender, which was used to make sure we didn't render while a
+             layout was pending, is no longer needed. It actually hasn't been needed since at least
+             r75987, but removing it before now would have resulted in a crash whenever a page came
+             out of compositing mode due to (1).
+
+        Fixes <http://webkit.org/b/52852> Flushing layer changes and rendering are intertwined in
+        CACFLayerTreeHost, but shouldn't be
+
+        Reviewed by Simon Fraser.
+
+        * WebCore.vcproj/WebCore.vcproj: Added LayerChangesFlusher.
+
+        * platform/graphics/ca/win/CACFLayerTreeHost.cpp: Added new #include, sorted existing
+        #includes.
+        (WebCore::CACFLayerTreeHost::CACFLayerTreeHost): Initialize new member.
+        (WebCore::CACFLayerTreeHost::layerTreeDidChange): If we aren't already flushing changes,
+        schedule a flush. Removed the call to renderSoon(), which now happens when the flush is
+        finished.
+        (WebCore::CACFLayerTreeHost::destroyRenderer): Cancel any pending flush we had scheduled. Also
+        fixed a bug where we'd fail to clear the context's layer.
+        (WebCore::CACFLayerTreeHost::render): Removed code to ask the client if we should render, which
+        is no longer needed. Moved code to flush layer changes from here to
+        flushPendingLayerChangesNow, which is called via the above-described mechanism.
+        (WebCore::CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon): Schedule a flush. Removed
+        code to schedule a render, which now happens after we've flushed.
+        (WebCore::CACFLayerTreeHost::flushPendingLayerChangesNow): Added. Some of this code came from
+        render(). First we flush GraphicsLayer changes from GraphicsLayers to their underlying
+        PlatformCALayers, then we flush changes from PlatformCALayers to the context, then we
+        schedule a render so that the changes will be rendered to the screen.
+
+        * platform/graphics/ca/win/CACFLayerTreeHost.h: Removed
+        CACFLayerTreeHostClient::shouldRender. Added flushPendingLayerChangesNow and
+        m_isFlushingLayerChanges.
+
+        * platform/graphics/ca/win/LayerChangesFlusher.cpp: Added.
+        (WebCore::LayerChangesFlusher::shared):
+        (WebCore::LayerChangesFlusher::LayerChangesFlusher):
+        (WebCore::LayerChangesFlusher::flushPendingLayerChangesSoon):
+        (WebCore::LayerChangesFlusher::cancelPendingFlush):
+        (WebCore::LayerChangesFlusher::hookCallback):
+        (WebCore::LayerChangesFlusher::hookFired):
+        (WebCore::LayerChangesFlusher::setHook):
+        (WebCore::LayerChangesFlusher::removeHook):
+
+        * platform/graphics/ca/win/LayerChangesFlusher.cpp: Added.
+        (WebCore::LayerChangesFlusher::shared): Returns the singleton.
+        (WebCore::LayerChangesFlusher::LayerChangesFlusher): Initialize our members.
+        (WebCore::LayerChangesFlusher::flushPendingLayerChangesSoon): Add the host to the set of
+        hosts with changes that need to be flushed, and set up our hook if we haven't already.
+        (WebCore::LayerChangesFlusher::cancelPendingFlush): Remove the host from the set of hosts
+        with changes that need to be flushed. If we have no more such hosts, remove our hook, unless
+        we're currently in the process of calling out to our hosts, in which case we'll take care of
+        the hook once we're done calling out.
+        (WebCore::LayerChangesFlusher::hookCallback): This is the function that Windows calls when
+        our hook fires. Just calls through to hookFired on the singleton.
+        (WebCore::LayerChangesFlusher::hookFired): Tell all the hosts with changes that needed to be
+        flushed that it's time to flush. If no hosts re-added themselves to our set during this
+        process, remove our hook.
+        (WebCore::LayerChangesFlusher::setHook): Calls through to ::SetWindowsHookExW.
+        (WebCore::LayerChangesFlusher::removeHook): Calls through to ::UnhookWindowsHookEx.
+
+        * platform/graphics/ca/win/LayerChangesFlusher.h: Added.
+
 2011-01-21  Simon Fraser  <simon.fraser@apple.com>
 
         Reviewed by Sam Weinig.
index 165a193..009c8ea 100755 (executable)
                                                        </FileConfiguration>
                                                </File>
                                                <File
+                                                       RelativePath="..\platform\graphics\ca\win\LayerChangesFlusher.cpp"
+                                                       >
+                                                       <FileConfiguration
+                                                               Name="Debug_Cairo_CFLite|Win32"
+                                                               ExcludedFromBuild="true"
+                                                               >
+                                                               <Tool
+                                                                       Name="VCCLCompilerTool"
+                                                               />
+                                                       </FileConfiguration>
+                                                       <FileConfiguration
+                                                               Name="Release_Cairo_CFLite|Win32"
+                                                               ExcludedFromBuild="true"
+                                                               >
+                                                               <Tool
+                                                                       Name="VCCLCompilerTool"
+                                                               />
+                                                       </FileConfiguration>
+                                               </File>
+                                               <File
+                                                       RelativePath="..\platform\graphics\ca\win\LayerChangesFlusher.h"
+                                                       >
+                                                       <FileConfiguration
+                                                               Name="Debug_Cairo_CFLite|Win32"
+                                                               ExcludedFromBuild="true"
+                                                               >
+                                                               <Tool
+                                                                       Name="VCCustomBuildTool"
+                                                               />
+                                                       </FileConfiguration>
+                                                       <FileConfiguration
+                                                               Name="Release_Cairo_CFLite|Win32"
+                                                               ExcludedFromBuild="true"
+                                                               >
+                                                               <Tool
+                                                                       Name="VCCustomBuildTool"
+                                                               />
+                                                       </FileConfiguration>
+                                               </File>
+                                               <File
                                                        RelativePath="..\platform\graphics\ca\win\PlatformCAAnimationWin.cpp"
                                                        >
                                                </File>
index 61d76a0..1d27608 100644 (file)
  */
 
 #include "config.h"
+#include "CACFLayerTreeHost.h"
 
 #if USE(ACCELERATED_COMPOSITING)
 
-#ifndef NDEBUG
-#define D3D_DEBUG_INFO
-#endif
-
-#include "CACFLayerTreeHost.h"
-
+#include "LayerChangesFlusher.h"
 #include "PlatformCALayer.h"
 #include "WebCoreInstanceHandle.h"
 #include <WebKitSystemInterface/WebKitSystemInterface.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/StdLibExtras.h>
+
+#ifndef NDEBUG
+#define D3D_DEBUG_INFO
+#endif
+
 #include <d3d9.h>
 #include <d3dx9.h>
 
@@ -188,6 +189,7 @@ CACFLayerTreeHost::CACFLayerTreeHost()
     , m_renderTimer(this, &CACFLayerTreeHost::renderTimerFired)
     , m_mustResetLostDeviceBeforeRendering(false)
     , m_shouldFlushPendingGraphicsLayerChanges(false)
+    , m_isFlushingLayerChanges(false)
 {
     // Point the CACFContext to this
     wkCACFContextSetUserData(m_context, this);
@@ -260,7 +262,17 @@ void CACFLayerTreeHost::setRootChildLayer(PlatformCALayer* layer)
    
 void CACFLayerTreeHost::layerTreeDidChange()
 {
-    renderSoon();
+    if (m_isFlushingLayerChanges) {
+        // The layer tree is changing as a result of flushing GraphicsLayer changes to their
+        // underlying PlatformCALayers. We'll flush those changes to the context as part of that
+        // process, so there's no need to schedule another flush here.
+        return;
+    }
+
+    // The layer tree is changing as a result of someone modifying a PlatformCALayer that doesn't
+    // have a corresponding GraphicsLayer. Schedule a flush since we won't schedule one through the
+    // normal GraphicsLayer mechanisms.
+    LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
 }
 
 bool CACFLayerTreeHost::createRenderer()
@@ -337,7 +349,9 @@ bool CACFLayerTreeHost::createRenderer()
 
 void CACFLayerTreeHost::destroyRenderer()
 {
-    wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer());
+    LayerChangesFlusher::shared().cancelPendingFlush(this);
+
+    wkCACFContextSetLayer(m_context, 0);
 
     wkCACFContextSetD3DDevice(m_context, 0);
     m_d3dDevice = 0;
@@ -425,19 +439,6 @@ void CACFLayerTreeHost::render(const Vector<CGRect>& windowDirtyRects)
         return;
     }
 
-    if (m_client && !m_client->shouldRender()) {
-        renderSoon();
-        return;
-    }
-
-    if (m_shouldFlushPendingGraphicsLayerChanges) {
-        m_client->flushPendingGraphicsLayerChanges();
-        m_shouldFlushPendingGraphicsLayerChanges = false;
-    }
-
-    // Flush the root layer to the render tree.
-    wkCACFContextFlush(m_context);
-
     // All pending animations will have been started with the flush. Fire the animationStarted calls
     double currentTime = WTF::currentTime();
     double currentMediaTime = CACurrentMediaTime();
@@ -526,7 +527,29 @@ void CACFLayerTreeHost::renderSoon()
 void CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon()
 {
     m_shouldFlushPendingGraphicsLayerChanges = true;
+    LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
+}
+
+void CACFLayerTreeHost::flushPendingLayerChangesNow()
+{
+    // Calling out to the client could cause our last reference to go away.
+    RefPtr<CACFLayerTreeHost> protector(this);
+
+    m_isFlushingLayerChanges = true;
+
+    // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if
+    // requested.
+    if (m_client && m_shouldFlushPendingGraphicsLayerChanges) {
+        m_shouldFlushPendingGraphicsLayerChanges = false;
+        m_client->flushPendingGraphicsLayerChanges();
+    }
+
+    // Flush changes stored up in PlatformCALayers to the context so they will be rendered.
+    wkCACFContextFlush(m_context);
+
     renderSoon();
+
+    m_isFlushingLayerChanges = false;
 }
 
 CGRect CACFLayerTreeHost::bounds() const
index ffe87ef..fc61f39 100644 (file)
@@ -52,7 +52,6 @@ class PlatformCALayer;
 class CACFLayerTreeHostClient {
 public:
     virtual ~CACFLayerTreeHostClient() { }
-    virtual bool shouldRender() const = 0;
     virtual void flushPendingGraphicsLayerChanges() { }
 };
 
@@ -76,6 +75,7 @@ public:
     void paint();
     void resize();
     void flushPendingGraphicsLayerChangesSoon();
+    void flushPendingLayerChangesNow();
 
 protected:
     PlatformCALayer* rootLayer() const;
@@ -111,6 +111,7 @@ private:
     Timer<CACFLayerTreeHost> m_renderTimer;
     bool m_mustResetLostDeviceBeforeRendering;
     bool m_shouldFlushPendingGraphicsLayerChanges;
+    bool m_isFlushingLayerChanges;
     HashSet<RefPtr<PlatformCALayer> > m_pendingAnimatedLayers;
 
 #ifndef NDEBUG
diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp
new file mode 100644 (file)
index 0000000..3fd857b
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LayerChangesFlusher.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CACFLayerTreeHost.h"
+#include "WebCoreInstanceHandle.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+LayerChangesFlusher& LayerChangesFlusher::shared()
+{
+    DEFINE_STATIC_LOCAL(LayerChangesFlusher, flusher, ());
+    return flusher;
+}
+
+LayerChangesFlusher::LayerChangesFlusher()
+    : m_hook(0)
+    , m_isCallingHosts(false)
+{
+}
+
+void LayerChangesFlusher::flushPendingLayerChangesSoon(CACFLayerTreeHost* host)
+{
+    if (!m_hostsWithChangesToFlush.add(host).second || m_hook)
+        return;
+
+    setHook();
+}
+
+void LayerChangesFlusher::cancelPendingFlush(CACFLayerTreeHost* host)
+{
+    m_hostsWithChangesToFlush.remove(host);
+
+    if (!m_hostsWithChangesToFlush.isEmpty() || !m_hook)
+        return;
+
+    // We handle removing the hook when we finish calling out to the hosts, so we shouldn't
+    // mess with it while we're in the process of calling them.
+    if (m_isCallingHosts)
+        return;
+
+    removeHook();
+}
+
+LRESULT LayerChangesFlusher::hookCallback(int code, WPARAM wParam, LPARAM lParam)
+{
+    return shared().hookFired(code, wParam, lParam);
+}
+
+LRESULT LayerChangesFlusher::hookFired(int code, WPARAM wParam, LPARAM lParam)
+{
+    ASSERT(m_hook);
+
+    // Calling out to the hosts can cause m_hostsWithChangesToFlush to be modified, so we copy it
+    // into a Vector first. We have to hold a reference to them because otherwise they could be
+    // destroyed while we're calling out to them.
+    Vector<RefPtr<CACFLayerTreeHost> > hosts;
+    copyToVector(m_hostsWithChangesToFlush, hosts);
+    m_hostsWithChangesToFlush.clear();
+
+    m_isCallingHosts = true;
+    for (size_t i = 0; i < hosts.size(); ++i)
+        hosts[i]->flushPendingLayerChangesNow();
+    m_isCallingHosts = false;
+
+    LRESULT result = ::CallNextHookEx(m_hook, code, wParam, lParam);
+
+    if (m_hostsWithChangesToFlush.isEmpty()) {
+        // We won't have any work to do next time around, so just remove our hook.
+        removeHook();
+    }
+
+    return result;
+}
+
+void LayerChangesFlusher::setHook()
+{
+    ASSERT(!m_hook);
+    ASSERT(!m_isCallingHosts);
+
+    DWORD threadID = ::GetCurrentThreadId();
+
+    m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, instanceHandle(), threadID);
+    ASSERT_WITH_MESSAGE(m_hook, "::SetWindowsHookExW failed with error %lu", ::GetLastError());
+
+    // Post a message to the message queue to prevent ::GetMessage from blocking, which will ensure
+    // our hook is called soon.
+    ::PostThreadMessageW(threadID, WM_NULL, 0, 0);
+}
+
+void LayerChangesFlusher::removeHook()
+{
+    ASSERT(m_hook);
+    ASSERT(!m_isCallingHosts);
+
+    if (!::UnhookWindowsHookEx(m_hook))
+        ASSERT_WITH_MESSAGE(false, "::UnhookWindowsHookEx failed with error %lu", ::GetLastError());
+
+    m_hook = 0;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h
new file mode 100644 (file)
index 0000000..6a98a99
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LayerChangesFlusher_h
+#define LayerChangesFlusher_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <windows.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class CACFLayerTreeHost;
+
+class LayerChangesFlusher {
+    WTF_MAKE_NONCOPYABLE(LayerChangesFlusher);
+public:
+    static LayerChangesFlusher& shared();
+
+    void flushPendingLayerChangesSoon(CACFLayerTreeHost*);
+    void cancelPendingFlush(CACFLayerTreeHost*);
+
+private:
+    LayerChangesFlusher();
+    ~LayerChangesFlusher();
+
+    static LRESULT CALLBACK hookCallback(int code, WPARAM, LPARAM);
+    LRESULT hookFired(int code, WPARAM, LPARAM);
+    void setHook();
+    void removeHook();
+
+    HashSet<CACFLayerTreeHost*> m_hostsWithChangesToFlush;
+    HHOOK m_hook;
+    bool m_isCallingHosts;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // LayerChangesFlusher_h
index 3e3cc49..b1981da 100644 (file)
@@ -1,3 +1,18 @@
+2011-01-20  Adam Roben  <aroben@apple.com>
+
+        Update for CACFLayerTreeHost changes
+
+        Fixes <http://webkit.org/b/52852> Flushing layer changes and rendering are intertwined in
+        CACFLayerTreeHost, but shouldn't be
+
+        Reviewed by Simon Fraser.
+
+        * WebView.cpp:
+        (WebView::paint): Changed to flush layer changes via CACFLayerTreeHost, which will call back
+        to our own flushing function if needed.
+
+        * WebView.h: Removed shouldRender, which is no longer used or needed.
+
 2011-01-21  Adam Roben  <aroben@apple.com>
 
         Update for WKCACFLayerRenderer -> CACFLayerTreeHost rename
index 5a33d5b..6e80785 100644 (file)
@@ -990,7 +990,7 @@ void WebView::paint(HDC dc, LPARAM options)
 
 #if USE(ACCELERATED_COMPOSITING)
     if (isAcceleratedCompositing()) {
-        flushPendingGraphicsLayerChanges();
+        m_layerTreeHost->flushPendingLayerChangesNow();
         // Flushing might have taken us out of compositing mode.
         if (isAcceleratedCompositing()) {
             // FIXME: We need to paint into dc (if provided). <http://webkit.org/b/52578>
@@ -6506,18 +6506,6 @@ bool WebView::showRepaintCounter() const
     return m_page->settings()->showRepaintCounter();
 }
 
-bool WebView::shouldRender() const
-{
-    Frame* coreFrame = core(m_mainFrame);
-    if (!coreFrame)
-        return true;
-    FrameView* frameView = coreFrame->view();
-    if (!frameView)
-        return true;
-
-    return !frameView->layoutPending();
-}
-
 void WebView::flushPendingGraphicsLayerChanges()
 {
     Frame* coreFrame = core(m_mainFrame);
index c81f6d6..1a993c6 100644 (file)
@@ -948,7 +948,6 @@ private:
     virtual bool showRepaintCounter() const;
 
     // CACFLayerTreeHostClient
-    virtual bool shouldRender() const;
     virtual void flushPendingGraphicsLayerChanges();
 #endif