Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "LayerTreeHostCAWin.h"
     28 
     29 #if HAVE(WKQCA)
     30 
     31 #include "DrawingAreaImpl.h"
     32 #include "ShareableBitmap.h"
     33 #include "UpdateInfo.h"
     34 #include "WebPage.h"
     35 #include <WebCore/GraphicsLayerCA.h>
     36 #include <WebCore/LayerChangesFlusher.h>
     37 #include <WebCore/PlatformCALayer.h>
     38 #include <WebCore/WebCoreInstanceHandle.h>
     39 #include <WebKitQuartzCoreAdditions/WKCACFImage.h>
     40 #include <WebKitQuartzCoreAdditions/WKCACFView.h>
     41 #include <wtf/CurrentTime.h>
     42 #include <wtf/Threading.h>
     43 
     44 #ifdef DEBUG_ALL
     45 #pragma comment(lib, "WebKitQuartzCoreAdditions_debug")
     46 #else
     47 #pragma comment(lib, "WebKitQuartzCoreAdditions")
     48 #endif
     49 
     50 using namespace WebCore;
     51 
     52 namespace WebKit {
     53 
     54 static HWND dummyWindow;
     55 static LPCWSTR dummyWindowClass = L"LayerTreeHostCAWindowClass";
     56 static size_t validLayerTreeHostCount;
     57 
     58 static void registerDummyWindowClass()
     59 {
     60     static bool didRegister;
     61     if (didRegister)
     62         return;
     63     didRegister = true;
     64 
     65     WNDCLASSW wndClass = {0};
     66     wndClass.lpszClassName = dummyWindowClass;
     67     wndClass.lpfnWndProc = ::DefWindowProcW;
     68     wndClass.hInstance = instanceHandle();
     69 
     70     ::RegisterClassW(&wndClass);
     71 }
     72 
     73 // This window is never shown. It is only needed so that D3D can determine the display mode, etc.
     74 static HWND createDummyWindow()
     75 {
     76     registerDummyWindowClass();
     77     return ::CreateWindowW(dummyWindowClass, 0, WS_POPUP, 0, 0, 10, 10, 0, 0, instanceHandle(), 0);
     78 }
     79 
     80 bool LayerTreeHostCAWin::supportsAcceleratedCompositing()
     81 {
     82     static bool initialized;
     83     static bool supportsAcceleratedCompositing;
     84     if (initialized)
     85         return supportsAcceleratedCompositing;
     86     initialized = true;
     87 
     88     ASSERT(!dummyWindow);
     89     dummyWindow = createDummyWindow();
     90     RetainPtr<WKCACFViewRef> view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationImage));
     91     CGRect fakeBounds = CGRectMake(0, 0, 10, 10);
     92     WKCACFViewUpdate(view.get(), dummyWindow, &fakeBounds);
     93 
     94     supportsAcceleratedCompositing = WKCACFViewCanDraw(view.get());
     95 
     96     WKCACFViewUpdate(view.get(), 0, 0);
     97     ::DestroyWindow(dummyWindow);
     98     dummyWindow = 0;
     99 
    100     return supportsAcceleratedCompositing;
    101 }
    102 
    103 PassRefPtr<LayerTreeHostCAWin> LayerTreeHostCAWin::create(WebPage* webPage)
    104 {
    105     RefPtr<LayerTreeHostCAWin> host = adoptRef(new LayerTreeHostCAWin(webPage));
    106     host->initialize();
    107     return host.release();
    108 }
    109 
    110 LayerTreeHostCAWin::LayerTreeHostCAWin(WebPage* webPage)
    111     : LayerTreeHostCA(webPage)
    112     , m_isFlushingLayerChanges(false)
    113     , m_nextDisplayTime(0)
    114 {
    115 }
    116 
    117 LayerTreeHostCAWin::~LayerTreeHostCAWin()
    118 {
    119 }
    120 
    121 void LayerTreeHostCAWin::platformInitialize(LayerTreeContext&)
    122 {
    123     ++validLayerTreeHostCount;
    124     if (!dummyWindow)
    125         dummyWindow = createDummyWindow();
    126 
    127     m_view.adoptCF(WKCACFViewCreate(kWKCACFViewDrawingDestinationImage));
    128     WKCACFViewSetContextUserData(m_view.get(), static_cast<AbstractCACFLayerTreeHost*>(this));
    129     WKCACFViewSetLayer(m_view.get(), rootLayer()->platformLayer());
    130     WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this);
    131 
    132     CGRect bounds = m_webPage->bounds();
    133     WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds);
    134 }
    135 
    136 void LayerTreeHostCAWin::invalidate()
    137 {
    138     LayerChangesFlusher::shared().cancelPendingFlush(this);
    139 
    140     WKCACFViewUpdate(m_view.get(), 0, 0);
    141     WKCACFViewSetContextUserData(m_view.get(), 0);
    142     WKCACFViewSetLayer(m_view.get(), 0);
    143     WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0);
    144 
    145     LayerTreeHostCA::invalidate();
    146 
    147     if (--validLayerTreeHostCount)
    148         return;
    149     ::DestroyWindow(dummyWindow);
    150     dummyWindow = 0;
    151 }
    152 
    153 void LayerTreeHostCAWin::scheduleLayerFlush()
    154 {
    155     LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
    156 }
    157 
    158 bool LayerTreeHostCAWin::participatesInDisplay()
    159 {
    160     return true;
    161 }
    162 
    163 bool LayerTreeHostCAWin::needsDisplay()
    164 {
    165     return timeUntilNextDisplay() <= 0;
    166 }
    167 
    168 double LayerTreeHostCAWin::timeUntilNextDisplay()
    169 {
    170     return m_nextDisplayTime - currentTime();
    171 }
    172 
    173 static IntSize size(WKCACFImageRef image)
    174 {
    175     return IntSize(WKCACFImageGetWidth(image), WKCACFImageGetHeight(image));
    176 }
    177 
    178 static PassRefPtr<ShareableBitmap> toShareableBitmap(WKCACFImageRef image)
    179 {
    180     size_t fileMappingSize;
    181     HANDLE mapping = WKCACFImageCopyFileMapping(image, &fileMappingSize);
    182     if (!mapping)
    183         return 0;
    184 
    185     RefPtr<SharedMemory> sharedMemory = SharedMemory::adopt(mapping, fileMappingSize, SharedMemory::ReadWrite);
    186     if (!sharedMemory) {
    187         ::CloseHandle(mapping);
    188         return 0;
    189     }
    190 
    191     // WKCACFImage never has an alpha channel.
    192     return ShareableBitmap::create(size(image), 0, sharedMemory.release());
    193 }
    194 
    195 void LayerTreeHostCAWin::display(UpdateInfo& updateInfo)
    196 {
    197     CGPoint imageOrigin;
    198     CFTimeInterval nextDrawTime;
    199     RetainPtr<WKCACFImageRef> image(AdoptCF, WKCACFViewCopyDrawnImage(m_view.get(), &imageOrigin, &nextDrawTime));
    200     m_nextDisplayTime = nextDrawTime - CACurrentMediaTime() + currentTime();
    201     if (!image)
    202         return;
    203     RefPtr<ShareableBitmap> bitmap = toShareableBitmap(image.get());
    204     if (!bitmap)
    205         return;
    206     if (!bitmap->createHandle(updateInfo.bitmapHandle))
    207         return;
    208     updateInfo.updateRectBounds = IntRect(IntPoint(imageOrigin.x, m_webPage->size().height() - imageOrigin.y - bitmap->size().height()), bitmap->size());
    209     updateInfo.updateRects.append(updateInfo.updateRectBounds);
    210 }
    211 
    212 void LayerTreeHostCAWin::sizeDidChange(const IntSize& newSize)
    213 {
    214     LayerTreeHostCA::sizeDidChange(newSize);
    215     CGRect bounds = CGRectMake(0, 0, newSize.width(), newSize.height());
    216     WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds);
    217     WKCACFViewFlushContext(m_view.get());
    218 }
    219 
    220 void LayerTreeHostCAWin::forceRepaint()
    221 {
    222     LayerTreeHostCA::forceRepaint();
    223     WKCACFViewFlushContext(m_view.get());
    224 }
    225 
    226 void LayerTreeHostCAWin::contextDidChangeCallback(WKCACFViewRef view, void* info)
    227 {
    228     // This should only be called on a background thread when no changes have actually
    229     // been committed to the context, eg. when a video frame has been added to an image
    230     // queue, so return without triggering animations etc.
    231     if (!isMainThread())
    232         return;
    233 
    234     LayerTreeHostCAWin* host = static_cast<LayerTreeHostCAWin*>(info);
    235     ASSERT_ARG(view, view == host->m_view);
    236     host->contextDidChange();
    237 }
    238 
    239 void LayerTreeHostCAWin::contextDidChange()
    240 {
    241     // Send currentTime to the pending animations. This function is called by CACF in a callback
    242     // which occurs after the drawInContext calls. So currentTime is very close to the time
    243     // the animations actually start
    244     double currentTime = WTF::currentTime();
    245 
    246     HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end();
    247     for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it)
    248         (*it)->animationStarted(currentTime);
    249 
    250     m_pendingAnimatedLayers.clear();
    251 
    252     m_nextDisplayTime = 0;
    253     static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->setLayerHostNeedsDisplay();
    254 }
    255 
    256 PlatformCALayer* LayerTreeHostCAWin::rootLayer() const
    257 {
    258     return static_cast<GraphicsLayerCA*>(LayerTreeHostCA::rootLayer())->platformCALayer();
    259 }
    260 
    261 void LayerTreeHostCAWin::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer)
    262 {
    263     m_pendingAnimatedLayers.add(layer);
    264 }
    265 
    266 void LayerTreeHostCAWin::layerTreeDidChange()
    267 {
    268     if (m_isFlushingLayerChanges) {
    269         // The layer tree is changing as a result of flushing GraphicsLayer changes to their
    270         // underlying PlatformCALayers. We'll flush those changes to the context as part of that
    271         // process, so there's no need to schedule another flush here.
    272         return;
    273     }
    274 
    275     // The layer tree is changing as a result of someone modifying a PlatformCALayer that doesn't
    276     // have a corresponding GraphicsLayer. Schedule a flush since we won't schedule one through the
    277     // normal GraphicsLayer mechanisms.
    278     LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
    279 }
    280 
    281 void LayerTreeHostCAWin::flushPendingLayerChangesNow()
    282 {
    283     RefPtr<LayerTreeHostCA> protector(this);
    284 
    285     m_isFlushingLayerChanges = true;
    286 
    287     // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if
    288     // requested.
    289     performScheduledLayerFlush();
    290 
    291     // Flush changes stored up in PlatformCALayers to the context so they will be rendered.
    292     WKCACFViewFlushContext(m_view.get());
    293 
    294     m_isFlushingLayerChanges = false;
    295 }
    296 
    297 } // namespace WebKit
    298 
    299 #endif // HAVE(WKQCA)
    300