CACFLayerTreeHost.cpp [plain text]
#include "config.h"
#include "CACFLayerTreeHost.h"
#if USE(CA)
#include "CACFLayerTreeHostClient.h"
#include "DebugPageOverlays.h"
#include "DefWndProcWindowClass.h"
#include "Frame.h"
#include "FrameView.h"
#include "LayerChangesFlusher.h"
#include "Logging.h"
#include "PlatformCALayerWin.h"
#include "PlatformLayer.h"
#include "TiledBacking.h"
#include "WKCACFViewLayerTreeHost.h"
#include "WebCoreInstanceHandle.h"
#include <limits.h>
#include <QuartzCore/CABase.h>
#include <wtf/StdLibExtras.h>
#include <wtf/UniqueArray.h>
#include <wtf/win/GDIObject.h>
#ifdef DEBUG_ALL
#pragma comment(lib, "QuartzCore_debug")
#else
#pragma comment(lib, "QuartzCore")
#endif
inline static CGRect winRectToCGRect(RECT rc)
{
return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top));
}
inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect)
{
return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top));
}
namespace WebCore {
bool CACFLayerTreeHost::acceleratedCompositingAvailable()
{
static bool available;
static bool tested;
if (tested)
return available;
tested = true;
available = true;
HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
if (!library) {
available = false;
return available;
}
FreeLibrary(library);
#ifdef DEBUG_ALL
library = LoadLibrary(TEXT("QuartzCore_debug.dll"));
#else
library = LoadLibrary(TEXT("QuartzCore.dll"));
#endif
if (!library) {
available = false;
return available;
}
FreeLibrary(library);
HWND testWindow = ::CreateWindow(defWndProcWindowClassName(), L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 20, 20, 0, 0, 0, 0);
if (!testWindow) {
available = false;
return available;
}
auto host = CACFLayerTreeHost::create();
if (!host) {
available = false;
return available;
}
host->setWindow(testWindow);
available = host->createRenderer();
host->setWindow(0);
::DestroyWindow(testWindow);
return available;
}
RefPtr<CACFLayerTreeHost> CACFLayerTreeHost::create()
{
if (!acceleratedCompositingAvailable())
return nullptr;
auto host = WKCACFViewLayerTreeHost::create();
if (!host) {
LOG_ERROR("Failed to create layer tree host for accelerated compositing.");
return nullptr;
}
host->initialize();
return host;
}
CACFLayerTreeHost::CACFLayerTreeHost()
: m_rootLayer(PlatformCALayerWin::create(PlatformCALayer::LayerTypeRootLayer, nullptr))
{
}
void CACFLayerTreeHost::initialize()
{
initializeContext(this, m_rootLayer.get());
m_rootLayer->setName("CACFLayerTreeHost rootLayer");
m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
m_rootLayer->setGeometryFlipped(true);
#ifndef NDEBUG
CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8);
m_rootLayer->setBackgroundColor(debugColor);
CGColorRelease(debugColor);
#endif
}
CACFLayerTreeHost::~CACFLayerTreeHost()
{
ASSERT_WITH_MESSAGE(m_state != WindowSet, "Must call setWindow(0) before destroying CACFLayerTreeHost");
}
void CACFLayerTreeHost::setWindow(HWND window)
{
if (window == m_window)
return;
#if ASSERT_ENABLED
switch (m_state) {
case WindowNotSet:
ASSERT_ARG(window, window);
ASSERT(!m_window);
m_state = WindowSet;
break;
case WindowSet:
ASSERT_ARG(window, !window);
ASSERT(m_window);
m_state = WindowCleared;
break;
case WindowCleared:
ASSERT_NOT_REACHED();
break;
}
#endif
if (m_window)
destroyRenderer();
m_window = window;
}
void CACFLayerTreeHost::setPage(Page* page)
{
m_page = page;
}
PlatformCALayer* CACFLayerTreeHost::rootLayer() const
{
return m_rootLayer.get();
}
void CACFLayerTreeHost::addPendingAnimatedLayer(PlatformCALayer& layer)
{
m_pendingAnimatedLayers.add(&layer);
}
void CACFLayerTreeHost::setRootChildLayer(PlatformCALayer* layer)
{
m_rootLayer->removeAllSublayers();
m_rootChildLayer = layer;
if (m_rootChildLayer)
m_rootLayer->appendSublayer(*m_rootChildLayer);
updateDebugInfoLayer(m_page->settings().showTiledScrollingIndicator());
}
void CACFLayerTreeHost::layerTreeDidChange()
{
if (m_isFlushingLayerChanges) {
return;
}
LayerChangesFlusher::singleton().flushPendingLayerChangesSoon(this);
}
void CACFLayerTreeHost::destroyRenderer()
{
m_rootLayer = nullptr;
m_rootChildLayer = nullptr;
LayerChangesFlusher::singleton().cancelPendingFlush(this);
}
static void getDirtyRects(HWND window, Vector<CGRect>& outRects)
{
ASSERT_ARG(outRects, outRects.isEmpty());
RECT clientRect;
if (!GetClientRect(window, &clientRect))
return;
auto region = adoptGDIObject(::CreateRectRgn(0, 0, 0, 0));
int regionType = GetUpdateRgn(window, region.get(), false);
if (regionType != COMPLEXREGION) {
RECT dirtyRect;
if (GetUpdateRect(window, &dirtyRect, false))
outRects.append(winRectToCGRect(dirtyRect, clientRect));
return;
}
DWORD dataSize = ::GetRegionData(region.get(), 0, 0);
auto regionDataBuffer = makeUniqueArray<unsigned char>(dataSize);
RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get());
if (!::GetRegionData(region.get(), dataSize, regionData))
return;
outRects.resize(regionData->rdh.nCount);
RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer);
for (size_t i = 0; i < outRects.size(); ++i, ++rect)
outRects[i] = winRectToCGRect(*rect, clientRect);
}
void CACFLayerTreeHost::paint(HDC dc)
{
Vector<CGRect> dirtyRects;
getDirtyRects(m_window, dirtyRects);
render(dirtyRects, dc);
}
void CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon()
{
m_shouldFlushPendingGraphicsLayerChanges = true;
LayerChangesFlusher::singleton().flushPendingLayerChangesSoon(this);
}
void CACFLayerTreeHost::setShouldInvertColors(bool)
{
}
void CACFLayerTreeHost::flushPendingLayerChangesNow()
{
RefPtr<CACFLayerTreeHost> protectedThis(this);
updateDebugInfoLayer(m_page->settings().showTiledScrollingIndicator());
m_isFlushingLayerChanges = true;
if (m_client && m_shouldFlushPendingGraphicsLayerChanges) {
m_shouldFlushPendingGraphicsLayerChanges = false;
m_client->flushPendingGraphicsLayerChanges();
}
flushContext();
m_isFlushingLayerChanges = false;
}
void CACFLayerTreeHost::contextDidChange()
{
notifyAnimationsStarted();
}
void CACFLayerTreeHost::notifyAnimationsStarted()
{
MonotonicTime currentTime = MonotonicTime::now();
HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end();
for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it)
(*it)->animationStarted(String(), currentTime);
m_pendingAnimatedLayers.clear();
}
CGRect CACFLayerTreeHost::bounds() const
{
RECT clientRect;
GetClientRect(m_window, &clientRect);
return winRectToCGRect(clientRect);
}
String CACFLayerTreeHost::layerTreeAsString() const
{
if (!m_rootLayer)
return emptyString();
return m_rootLayer->layerTreeAsString();
}
TiledBacking* CACFLayerTreeHost::mainFrameTiledBacking() const
{
if (!m_page)
return nullptr;
FrameView* frameView = m_page->mainFrame().view();
if (!frameView)
return nullptr;
return frameView->tiledBacking();
}
void CACFLayerTreeHost::updateDebugInfoLayer(bool showLayer)
{
if (showLayer) {
if (!m_debugInfoLayer) {
if (TiledBacking* tiledBacking = mainFrameTiledBacking())
m_debugInfoLayer = tiledBacking->tiledScrollingIndicatorLayer();
}
if (m_debugInfoLayer) {
#ifndef NDEBUG
m_debugInfoLayer->setName("Debug Info");
#endif
m_rootLayer->appendSublayer(*m_debugInfoLayer);
}
} else if (m_debugInfoLayer) {
m_debugInfoLayer->removeFromSuperlayer();
m_debugInfoLayer = nullptr;
}
}
}
#endif