diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp')
-rw-r--r-- | Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp | 270 |
1 files changed, 250 insertions, 20 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp index 81db03e..699a1fe 100644 --- a/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp +++ b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp @@ -24,46 +24,276 @@ */ #include "config.h" -#include "LayerTreeHostCA.h" +#include "LayerTreeHostCAWin.h" -#include <WebCore/NotImplemented.h> +#if HAVE(WKQCA) + +#include "DrawingAreaImpl.h" +#include "ShareableBitmap.h" +#include "UpdateInfo.h" +#include "WebPage.h" +#include <WebCore/GraphicsLayerCA.h> +#include <WebCore/LayerChangesFlusher.h> +#include <WebCore/PlatformCALayer.h> +#include <WebCore/WebCoreInstanceHandle.h> +#include <WebKitQuartzCoreAdditions/WKCACFImage.h> +#include <WebKitQuartzCoreAdditions/WKCACFView.h> +#include <wtf/CurrentTime.h> +#include <wtf/Threading.h> + +#ifdef DEBUG_ALL +#pragma comment(lib, "WebKitQuartzCoreAdditions_debug") +#else +#pragma comment(lib, "WebKitQuartzCoreAdditions") +#endif + +using namespace WebCore; namespace WebKit { -void LayerTreeHostCA::platformInitialize() +static HWND dummyWindow; +static LPCWSTR dummyWindowClass = L"LayerTreeHostCAWindowClass"; +static size_t validLayerTreeHostCount; + +static void registerDummyWindowClass() +{ + static bool didRegister; + if (didRegister) + return; + didRegister = true; + + WNDCLASSW wndClass = {0}; + wndClass.lpszClassName = dummyWindowClass; + wndClass.lpfnWndProc = ::DefWindowProcW; + wndClass.hInstance = instanceHandle(); + + ::RegisterClassW(&wndClass); +} + +// This window is never shown. It is only needed so that D3D can determine the display mode, etc. +static HWND createDummyWindow() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + registerDummyWindowClass(); + return ::CreateWindowW(dummyWindowClass, 0, WS_POPUP, 0, 0, 10, 10, 0, 0, instanceHandle(), 0); } -void LayerTreeHostCA::scheduleLayerFlush() +bool LayerTreeHostCAWin::supportsAcceleratedCompositing() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + static bool initialized; + static bool supportsAcceleratedCompositing; + if (initialized) + return supportsAcceleratedCompositing; + initialized = true; + + ASSERT(!dummyWindow); + dummyWindow = createDummyWindow(); + RetainPtr<WKCACFViewRef> view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationImage)); + CGRect fakeBounds = CGRectMake(0, 0, 10, 10); + WKCACFViewUpdate(view.get(), dummyWindow, &fakeBounds); + + supportsAcceleratedCompositing = WKCACFViewCanDraw(view.get()); + + WKCACFViewUpdate(view.get(), 0, 0); + ::DestroyWindow(dummyWindow); + dummyWindow = 0; + + return supportsAcceleratedCompositing; } -void LayerTreeHostCA::platformInvalidate() +PassRefPtr<LayerTreeHostCAWin> LayerTreeHostCAWin::create(WebPage* webPage) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + RefPtr<LayerTreeHostCAWin> host = adoptRef(new LayerTreeHostCAWin(webPage)); + host->initialize(); + return host.release(); } -void LayerTreeHostCA::platformSizeDidChange() +LayerTreeHostCAWin::LayerTreeHostCAWin(WebPage* webPage) + : LayerTreeHostCA(webPage) + , m_isFlushingLayerChanges(false) + , m_nextDisplayTime(0) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); } -void LayerTreeHostCA::platformForceRepaint() +LayerTreeHostCAWin::~LayerTreeHostCAWin() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); } -void LayerTreeHostCA::platformDidPerformScheduledLayerFlush() +void LayerTreeHostCAWin::platformInitialize(LayerTreeContext&) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + ++validLayerTreeHostCount; + if (!dummyWindow) + dummyWindow = createDummyWindow(); + + m_view.adoptCF(WKCACFViewCreate(kWKCACFViewDrawingDestinationImage)); + WKCACFViewSetContextUserData(m_view.get(), static_cast<AbstractCACFLayerTreeHost*>(this)); + WKCACFViewSetLayer(m_view.get(), rootLayer()->platformLayer()); + WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this); + + CGRect bounds = m_webPage->bounds(); + WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds); +} + +void LayerTreeHostCAWin::invalidate() +{ + LayerChangesFlusher::shared().cancelPendingFlush(this); + + WKCACFViewUpdate(m_view.get(), 0, 0); + WKCACFViewSetContextUserData(m_view.get(), 0); + WKCACFViewSetLayer(m_view.get(), 0); + WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0); + + LayerTreeHostCA::invalidate(); + + if (--validLayerTreeHostCount) + return; + ::DestroyWindow(dummyWindow); + dummyWindow = 0; +} + +void LayerTreeHostCAWin::scheduleLayerFlush() +{ + LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); +} + +bool LayerTreeHostCAWin::participatesInDisplay() +{ + return true; +} + +bool LayerTreeHostCAWin::needsDisplay() +{ + return timeUntilNextDisplay() <= 0; +} + +double LayerTreeHostCAWin::timeUntilNextDisplay() +{ + return m_nextDisplayTime - currentTime(); +} + +static IntSize size(WKCACFImageRef image) +{ + return IntSize(WKCACFImageGetWidth(image), WKCACFImageGetHeight(image)); +} + +static PassRefPtr<ShareableBitmap> toShareableBitmap(WKCACFImageRef image) +{ + size_t fileMappingSize; + HANDLE mapping = WKCACFImageCopyFileMapping(image, &fileMappingSize); + if (!mapping) + return 0; + + RefPtr<SharedMemory> sharedMemory = SharedMemory::adopt(mapping, fileMappingSize, SharedMemory::ReadWrite); + if (!sharedMemory) { + ::CloseHandle(mapping); + return 0; + } + + // WKCACFImage never has an alpha channel. + return ShareableBitmap::create(size(image), 0, sharedMemory.release()); +} + +void LayerTreeHostCAWin::display(UpdateInfo& updateInfo) +{ + CGPoint imageOrigin; + CFTimeInterval nextDrawTime; + RetainPtr<WKCACFImageRef> image(AdoptCF, WKCACFViewCopyDrawnImage(m_view.get(), &imageOrigin, &nextDrawTime)); + m_nextDisplayTime = nextDrawTime - CACurrentMediaTime() + currentTime(); + if (!image) + return; + RefPtr<ShareableBitmap> bitmap = toShareableBitmap(image.get()); + if (!bitmap) + return; + if (!bitmap->createHandle(updateInfo.bitmapHandle)) + return; + updateInfo.updateRectBounds = IntRect(IntPoint(imageOrigin.x, m_webPage->size().height() - imageOrigin.y - bitmap->size().height()), bitmap->size()); + updateInfo.updateRects.append(updateInfo.updateRectBounds); +} + +void LayerTreeHostCAWin::sizeDidChange(const IntSize& newSize) +{ + LayerTreeHostCA::sizeDidChange(newSize); + CGRect bounds = CGRectMake(0, 0, newSize.width(), newSize.height()); + WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds); + WKCACFViewFlushContext(m_view.get()); +} + +void LayerTreeHostCAWin::forceRepaint() +{ + LayerTreeHostCA::forceRepaint(); + WKCACFViewFlushContext(m_view.get()); +} + +void LayerTreeHostCAWin::contextDidChangeCallback(WKCACFViewRef view, void* info) +{ + // This should only be called on a background thread when no changes have actually + // been committed to the context, eg. when a video frame has been added to an image + // queue, so return without triggering animations etc. + if (!isMainThread()) + return; + + LayerTreeHostCAWin* host = static_cast<LayerTreeHostCAWin*>(info); + ASSERT_ARG(view, view == host->m_view); + host->contextDidChange(); +} + +void LayerTreeHostCAWin::contextDidChange() +{ + // Send currentTime to the pending animations. This function is called by CACF in a callback + // which occurs after the drawInContext calls. So currentTime is very close to the time + // the animations actually start + double currentTime = WTF::currentTime(); + + HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); + for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) + (*it)->animationStarted(currentTime); + + m_pendingAnimatedLayers.clear(); + + m_nextDisplayTime = 0; + static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->setLayerHostNeedsDisplay(); +} + +PlatformCALayer* LayerTreeHostCAWin::rootLayer() const +{ + return static_cast<GraphicsLayerCA*>(LayerTreeHostCA::rootLayer())->platformCALayer(); +} + +void LayerTreeHostCAWin::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer) +{ + m_pendingAnimatedLayers.add(layer); +} + +void LayerTreeHostCAWin::layerTreeDidChange() +{ + 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); +} + +void LayerTreeHostCAWin::flushPendingLayerChangesNow() +{ + RefPtr<LayerTreeHostCA> protector(this); + + m_isFlushingLayerChanges = true; + + // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if + // requested. + performScheduledLayerFlush(); + + // Flush changes stored up in PlatformCALayers to the context so they will be rendered. + WKCACFViewFlushContext(m_view.get()); + + m_isFlushingLayerChanges = false; } } // namespace WebKit + +#endif // HAVE(WKQCA) |