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