1/* 2 * Copyright (C) 2009 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. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "CACFLayerTreeHost.h" 28 29#if USE(ACCELERATED_COMPOSITING) 30 31#include "CACFLayerTreeHostClient.h" 32#include "DefWndProcWindowClass.h" 33#include "LayerChangesFlusher.h" 34#include "LegacyCACFLayerTreeHost.h" 35#include "PlatformCALayer.h" 36#include "WKCACFViewLayerTreeHost.h" 37#include "WebCoreInstanceHandle.h" 38#include <limits.h> 39#include <QuartzCore/CABase.h> 40#include <wtf/CurrentTime.h> 41#include <wtf/OwnArrayPtr.h> 42 43#ifdef DEBUG_ALL 44#pragma comment(lib, "QuartzCore_debug") 45#else 46#pragma comment(lib, "QuartzCore") 47#endif 48 49inline static CGRect winRectToCGRect(RECT rc) 50{ 51 return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top)); 52} 53 54inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) 55{ 56 return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top)); 57} 58 59namespace WebCore { 60 61bool CACFLayerTreeHost::acceleratedCompositingAvailable() 62{ 63 static bool available; 64 static bool tested; 65 66 if (tested) 67 return available; 68 69 tested = true; 70 71 // Initialize available to true since this function will be called from a 72 // propagation within createRenderer(). We want to be able to return true 73 // when that happens so that the test can continue. 74 available = true; 75 76 HMODULE library = LoadLibrary(TEXT("d3d9.dll")); 77 if (!library) { 78 available = false; 79 return available; 80 } 81 82 FreeLibrary(library); 83#ifdef DEBUG_ALL 84 library = LoadLibrary(TEXT("QuartzCore_debug.dll")); 85#else 86 library = LoadLibrary(TEXT("QuartzCore.dll")); 87#endif 88 if (!library) { 89 available = false; 90 return available; 91 } 92 93 FreeLibrary(library); 94 95 // Make a dummy HWND. 96 HWND testWindow = ::CreateWindow(defWndProcWindowClassName(), L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 20, 20, 0, 0, 0, 0); 97 98 if (!testWindow) { 99 available = false; 100 return available; 101 } 102 103 RefPtr<CACFLayerTreeHost> host = CACFLayerTreeHost::create(); 104 host->setWindow(testWindow); 105 available = host->createRenderer(); 106 host->setWindow(0); 107 ::DestroyWindow(testWindow); 108 109 return available; 110} 111 112PassRefPtr<CACFLayerTreeHost> CACFLayerTreeHost::create() 113{ 114 if (!acceleratedCompositingAvailable()) 115 return 0; 116 RefPtr<CACFLayerTreeHost> host = WKCACFViewLayerTreeHost::create(); 117 if (!host) 118 host = LegacyCACFLayerTreeHost::create(); 119 host->initialize(); 120 return host.release(); 121} 122 123CACFLayerTreeHost::CACFLayerTreeHost() 124 : m_client(0) 125 , m_rootLayer(PlatformCALayer::create(PlatformCALayer::LayerTypeRootLayer, 0)) 126 , m_window(0) 127 , m_shouldFlushPendingGraphicsLayerChanges(false) 128 , m_isFlushingLayerChanges(false) 129#if !ASSERT_DISABLED 130 , m_state(WindowNotSet) 131#endif 132{ 133} 134 135void CACFLayerTreeHost::initialize() 136{ 137 // Point the CACFContext to this 138 initializeContext(this, m_rootLayer.get()); 139 140 // Under the root layer, we have a clipping layer to clip the content, 141 // that contains a scroll layer that we use for scrolling the content. 142 // The root layer is the size of the client area of the window. 143 // The clipping layer is the size of the WebView client area (window less the scrollbars). 144 // The scroll layer is the size of the root child layer. 145 // Resizing the window will change the bounds of the rootLayer and the clip layer and will not 146 // cause any repositioning. 147 // Scrolling will affect only the position of the scroll layer without affecting the bounds. 148 149 m_rootLayer->setName("CACFLayerTreeHost rootLayer"); 150 m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0)); 151 m_rootLayer->setGeometryFlipped(true); 152 153#ifndef NDEBUG 154 CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8); 155 m_rootLayer->setBackgroundColor(debugColor); 156 CGColorRelease(debugColor); 157#endif 158} 159 160CACFLayerTreeHost::~CACFLayerTreeHost() 161{ 162 ASSERT_WITH_MESSAGE(m_state != WindowSet, "Must call setWindow(0) before destroying CACFLayerTreeHost"); 163} 164 165void CACFLayerTreeHost::setWindow(HWND window) 166{ 167 if (window == m_window) 168 return; 169 170#if !ASSERT_DISABLED 171 switch (m_state) { 172 case WindowNotSet: 173 ASSERT_ARG(window, window); 174 ASSERT(!m_window); 175 m_state = WindowSet; 176 break; 177 case WindowSet: 178 ASSERT_ARG(window, !window); 179 ASSERT(m_window); 180 m_state = WindowCleared; 181 break; 182 case WindowCleared: 183 ASSERT_NOT_REACHED(); 184 break; 185 } 186#endif 187 188 if (m_window) 189 destroyRenderer(); 190 191 m_window = window; 192} 193 194PlatformCALayer* CACFLayerTreeHost::rootLayer() const 195{ 196 return m_rootLayer.get(); 197} 198 199void CACFLayerTreeHost::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer) 200{ 201 m_pendingAnimatedLayers.add(layer); 202} 203 204void CACFLayerTreeHost::setRootChildLayer(PlatformCALayer* layer) 205{ 206 m_rootLayer->removeAllSublayers(); 207 m_rootChildLayer = layer; 208 if (m_rootChildLayer) 209 m_rootLayer->appendSublayer(m_rootChildLayer.get()); 210} 211 212void CACFLayerTreeHost::layerTreeDidChange() 213{ 214 if (m_isFlushingLayerChanges) { 215 // The layer tree is changing as a result of flushing GraphicsLayer changes to their 216 // underlying PlatformCALayers. We'll flush those changes to the context as part of that 217 // process, so there's no need to schedule another flush here. 218 return; 219 } 220 221 // The layer tree is changing as a result of someone modifying a PlatformCALayer that doesn't 222 // have a corresponding GraphicsLayer. Schedule a flush since we won't schedule one through the 223 // normal GraphicsLayer mechanisms. 224 LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); 225} 226 227void CACFLayerTreeHost::destroyRenderer() 228{ 229 m_rootLayer = 0; 230 m_rootChildLayer = 0; 231 LayerChangesFlusher::shared().cancelPendingFlush(this); 232} 233 234static void getDirtyRects(HWND window, Vector<CGRect>& outRects) 235{ 236 ASSERT_ARG(outRects, outRects.isEmpty()); 237 238 RECT clientRect; 239 if (!GetClientRect(window, &clientRect)) 240 return; 241 242 OwnPtr<HRGN> region = adoptPtr(CreateRectRgn(0, 0, 0, 0)); 243 int regionType = GetUpdateRgn(window, region.get(), false); 244 if (regionType != COMPLEXREGION) { 245 RECT dirtyRect; 246 if (GetUpdateRect(window, &dirtyRect, false)) 247 outRects.append(winRectToCGRect(dirtyRect, clientRect)); 248 return; 249 } 250 251 DWORD dataSize = GetRegionData(region.get(), 0, 0); 252 OwnArrayPtr<unsigned char> regionDataBuffer = adoptArrayPtr(new unsigned char[dataSize]); 253 RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); 254 if (!GetRegionData(region.get(), dataSize, regionData)) 255 return; 256 257 outRects.resize(regionData->rdh.nCount); 258 259 RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); 260 for (size_t i = 0; i < outRects.size(); ++i, ++rect) 261 outRects[i] = winRectToCGRect(*rect, clientRect); 262} 263 264void CACFLayerTreeHost::paint() 265{ 266 Vector<CGRect> dirtyRects; 267 getDirtyRects(m_window, dirtyRects); 268 render(dirtyRects); 269} 270 271void CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon() 272{ 273 m_shouldFlushPendingGraphicsLayerChanges = true; 274 LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); 275} 276 277void CACFLayerTreeHost::setShouldInvertColors(bool) 278{ 279} 280 281void CACFLayerTreeHost::flushPendingLayerChangesNow() 282{ 283 // Calling out to the client could cause our last reference to go away. 284 RefPtr<CACFLayerTreeHost> protector(this); 285 286 m_isFlushingLayerChanges = true; 287 288 // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if 289 // requested. 290 if (m_client && m_shouldFlushPendingGraphicsLayerChanges) { 291 m_shouldFlushPendingGraphicsLayerChanges = false; 292 m_client->flushPendingGraphicsLayerChanges(); 293 } 294 295 // Flush changes stored up in PlatformCALayers to the context so they will be rendered. 296 flushContext(); 297 298 m_isFlushingLayerChanges = false; 299} 300 301void CACFLayerTreeHost::contextDidChange() 302{ 303 // All pending animations will have been started with the flush. Fire the animationStarted calls. 304 notifyAnimationsStarted(); 305} 306 307void CACFLayerTreeHost::notifyAnimationsStarted() 308{ 309 // Send currentTime to the pending animations. This function is called by CACF in a callback 310 // which occurs after the drawInContext calls. So currentTime is very close to the time 311 // the animations actually start 312 double currentTime = WTF::currentTime(); 313 314 HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); 315 for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) 316 (*it)->animationStarted(currentTime); 317 318 m_pendingAnimatedLayers.clear(); 319} 320 321CGRect CACFLayerTreeHost::bounds() const 322{ 323 RECT clientRect; 324 GetClientRect(m_window, &clientRect); 325 326 return winRectToCGRect(clientRect); 327} 328 329} 330 331#endif // USE(ACCELERATED_COMPOSITING) 332