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