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