LayerChangesFlusher.cpp [plain text]
#include "config.h"
#include "LayerChangesFlusher.h"
#if USE(CA)
#include "AbstractCACFLayerTreeHost.h"
#include "StructuredExceptionHandlerSuppressor.h"
#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
namespace WebCore {
LayerChangesFlusher& LayerChangesFlusher::singleton()
{
static NeverDestroyed<LayerChangesFlusher> flusher;
return flusher;
}
LayerChangesFlusher::LayerChangesFlusher()
: m_hook(0)
, m_isCallingHosts(false)
{
}
void LayerChangesFlusher::flushPendingLayerChangesSoon(AbstractCACFLayerTreeHost* host)
{
if (!m_hostsWithChangesToFlush.add(host).isNewEntry || m_hook)
return;
setHook();
}
void LayerChangesFlusher::cancelPendingFlush(AbstractCACFLayerTreeHost* host)
{
m_hostsWithChangesToFlush.remove(host);
if (!m_hostsWithChangesToFlush.isEmpty() || !m_hook)
return;
if (m_isCallingHosts)
return;
removeHook();
}
LRESULT LayerChangesFlusher::hookCallback(int code, WPARAM wParam, LPARAM lParam)
{
ExceptionRegistration registrationStruct; StructuredExceptionHandlerSuppressor suppressor(registrationStruct);
return singleton().hookFired(code, wParam, lParam);
}
LRESULT LayerChangesFlusher::hookFired(int code, WPARAM wParam, LPARAM lParam)
{
ASSERT(m_hook);
auto hosts = copyToVector(m_hostsWithChangesToFlush);
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_hook && m_hostsWithChangesToFlush.isEmpty()) {
removeHook();
}
return result;
}
void LayerChangesFlusher::setHook()
{
ASSERT(!m_hook);
ASSERT(!m_isCallingHosts);
DWORD threadID = ::GetCurrentThreadId();
m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, 0, threadID);
ASSERT_WITH_MESSAGE(m_hook, "::SetWindowsHookExW failed with error %lu", ::GetLastError());
::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;
}
}
#endif