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