[CoordinatedGraphics] invisible webview should not paint the content
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / CoordinatedGraphics / CoordinatedDrawingArea.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if USE(COORDINATED_GRAPHICS)
30 #include "CoordinatedDrawingArea.h"
31
32 #include "CoordinatedLayerTreeHost.h"
33 #include "DrawingAreaProxyMessages.h"
34 #include "LayerTreeContext.h"
35 #include "PageOverlayController.h"
36 #include "ShareableBitmap.h"
37 #include "UpdateInfo.h"
38 #include "WebPage.h"
39 #include "WebPageCreationParameters.h"
40 #include "WebPreferencesKeys.h"
41 #include "WebProcess.h"
42 #include <WebCore/GraphicsContext.h>
43 #include <WebCore/MainFrame.h>
44 #include <WebCore/Page.h>
45 #include <WebCore/PageOverlayController.h>
46 #include <WebCore/Settings.h>
47
48 using namespace WebCore;
49
50 namespace WebKit {
51
52 CoordinatedDrawingArea::~CoordinatedDrawingArea()
53 {
54     if (m_layerTreeHost)
55         m_layerTreeHost->invalidate();
56 }
57
58 CoordinatedDrawingArea::CoordinatedDrawingArea(WebPage& webPage, const WebPageCreationParameters& parameters)
59 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
60     : DrawingArea(DrawingAreaTypeCoordinated, webPage)
61 #else
62     : DrawingArea(DrawingAreaTypeImpl, webPage)
63 #endif
64     , m_backingStoreStateID(0)
65     , m_isPaintingEnabled(true)
66     , m_inUpdateBackingStoreState(false)
67     , m_shouldSendDidUpdateBackingStoreState(false)
68     , m_isWaitingForDidUpdate(false)
69     , m_compositingAccordingToProxyMessages(false)
70     , m_layerTreeStateIsFrozen(false)
71     , m_wantsToExitAcceleratedCompositingMode(false)
72     , m_isPaintingSuspended(false)
73     , m_displayTimer(RunLoop::main(), this, &CoordinatedDrawingArea::displayTimerFired)
74     , m_exitCompositingTimer(RunLoop::main(), this, &CoordinatedDrawingArea::exitAcceleratedCompositingMode)
75 {
76     // Always use compositing in CoordinatedGraphics
77     enterAcceleratedCompositingMode(0);
78
79     if (!(parameters.viewState & ViewState::IsVisible))
80         suspendPainting();
81 }
82
83 void CoordinatedDrawingArea::setNeedsDisplay()
84 {
85     if (!m_isPaintingEnabled)
86         return;
87
88     if (m_layerTreeHost) {
89         ASSERT(m_dirtyRegion.isEmpty());
90         m_layerTreeHost->setNonCompositedContentsNeedDisplay();
91         return;
92     }
93
94     setNeedsDisplayInRect(m_webPage.bounds());
95 }
96
97 void CoordinatedDrawingArea::setNeedsDisplayInRect(const IntRect& rect)
98 {
99     if (!m_isPaintingEnabled)
100         return;
101
102     if (m_layerTreeHost) {
103         ASSERT(m_dirtyRegion.isEmpty());
104         m_layerTreeHost->setNonCompositedContentsNeedDisplayInRect(rect);
105         return;
106     }
107
108     IntRect dirtyRect = rect;
109     dirtyRect.intersect(m_webPage.bounds());
110
111     if (dirtyRect.isEmpty())
112         return;
113
114     m_dirtyRegion.unite(dirtyRect);
115     scheduleDisplay();
116 }
117
118 void CoordinatedDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
119 {
120     if (!m_isPaintingEnabled)
121         return;
122
123     if (m_layerTreeHost) {
124         ASSERT(m_scrollRect.isEmpty());
125         ASSERT(m_scrollOffset.isEmpty());
126         ASSERT(m_dirtyRegion.isEmpty());
127
128         m_layerTreeHost->scrollNonCompositedContents(scrollRect);
129         return;
130     }
131
132     if (scrollRect.isEmpty())
133         return;
134
135     if (!m_scrollRect.isEmpty() && scrollRect != m_scrollRect) {
136         unsigned scrollArea = scrollRect.width() * scrollRect.height();
137         unsigned currentScrollArea = m_scrollRect.width() * m_scrollRect.height();
138
139         if (currentScrollArea >= scrollArea) {
140             // The rect being scrolled is at least as large as the rect we'd like to scroll.
141             // Go ahead and just invalidate the scroll rect.
142             setNeedsDisplayInRect(scrollRect);
143             return;
144         }
145
146         // Just repaint the entire current scroll rect, we'll scroll the new rect instead.
147         setNeedsDisplayInRect(m_scrollRect);
148         m_scrollRect = IntRect();
149         m_scrollOffset = IntSize();
150     }
151
152     // Get the part of the dirty region that is in the scroll rect.
153     Region dirtyRegionInScrollRect = intersect(scrollRect, m_dirtyRegion);
154     if (!dirtyRegionInScrollRect.isEmpty()) {
155         // There are parts of the dirty region that are inside the scroll rect.
156         // We need to subtract them from the region, move them and re-add them.
157         m_dirtyRegion.subtract(scrollRect);
158
159         // Move the dirty parts.
160         Region movedDirtyRegionInScrollRect = intersect(translate(dirtyRegionInScrollRect, scrollDelta), scrollRect);
161
162         // And add them back.
163         m_dirtyRegion.unite(movedDirtyRegionInScrollRect);
164     }
165
166     // Compute the scroll repaint region.
167     Region scrollRepaintRegion = subtract(scrollRect, translate(scrollRect, scrollDelta));
168
169     m_dirtyRegion.unite(scrollRepaintRegion);
170     scheduleDisplay();
171
172     m_scrollRect = scrollRect;
173     m_scrollOffset += scrollDelta;
174 }
175
176 void CoordinatedDrawingArea::pageBackgroundTransparencyChanged()
177 {
178     if (m_layerTreeHost)
179         m_layerTreeHost->pageBackgroundTransparencyChanged();
180 }
181
182 void CoordinatedDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
183 {
184     if (m_layerTreeStateIsFrozen == isFrozen)
185         return;
186
187     m_layerTreeStateIsFrozen = isFrozen;
188
189     if (m_layerTreeHost)
190         m_layerTreeHost->setLayerFlushSchedulingEnabled(!isFrozen);
191
192     if (isFrozen)
193         m_exitCompositingTimer.stop();
194     else if (m_wantsToExitAcceleratedCompositingMode)
195         exitAcceleratedCompositingModeSoon();
196 }
197
198 void CoordinatedDrawingArea::forceRepaint()
199 {
200     setNeedsDisplay();
201
202     m_webPage.layoutIfNeeded();
203
204     if (m_layerTreeHost) {
205         // FIXME: We need to do the same work as the layerHostDidFlushLayers function here,
206         // but clearly it doesn't make sense to call the function with that name.
207         // Consider refactoring and renaming it.
208         if (m_compositingAccordingToProxyMessages)
209             m_layerTreeHost->forceRepaint();
210         else {
211             // Call setShouldNotifyAfterNextScheduledLayerFlush(false) here to
212             // prevent layerHostDidFlushLayers() from being called a second time.
213             m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
214             layerHostDidFlushLayers();
215         }
216         return;
217     }
218
219     m_isWaitingForDidUpdate = false;
220     display();
221 }
222
223 bool CoordinatedDrawingArea::forceRepaintAsync(uint64_t callbackID)
224 {
225     return m_layerTreeHost && m_layerTreeHost->forceRepaintAsync(callbackID);
226 }
227
228 void CoordinatedDrawingArea::setPaintingEnabled(bool paintingEnabled)
229 {
230     m_isPaintingEnabled = paintingEnabled;
231 }
232
233 void CoordinatedDrawingArea::updatePreferences(const WebPreferencesStore& store)
234 {
235     m_webPage.corePage()->settings().setForceCompositingMode(store.getBoolValueForKey(WebPreferencesKey::forceCompositingModeKey()));
236 }
237
238 void CoordinatedDrawingArea::mainFrameContentSizeChanged(const WebCore::IntSize&)
239 {
240     m_webPage.mainFrame()->pageOverlayController().didChangeDocumentSize();
241 }
242
243 void CoordinatedDrawingArea::layerHostDidFlushLayers()
244 {
245     ASSERT(m_layerTreeHost);
246
247     m_layerTreeHost->forceRepaint();
248
249     if (m_shouldSendDidUpdateBackingStoreState && !exitAcceleratedCompositingModePending()) {
250         sendDidUpdateBackingStoreState();
251         return;
252     }
253
254     if (!m_layerTreeHost)
255         return;
256
257     ASSERT(!m_compositingAccordingToProxyMessages);
258     if (!exitAcceleratedCompositingModePending()) {
259         m_webPage.send(Messages::DrawingAreaProxy::EnterAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext()));
260         m_compositingAccordingToProxyMessages = true;
261     }
262 }
263
264 GraphicsLayerFactory* CoordinatedDrawingArea::graphicsLayerFactory()
265 {
266     if (m_layerTreeHost)
267         return m_layerTreeHost->graphicsLayerFactory();
268
269     return 0;
270 }
271
272 void CoordinatedDrawingArea::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
273 {
274     // FIXME: Instead of using nested if statements, we should keep a compositing state
275     // enum in the CoordinatedDrawingArea object and have a changeAcceleratedCompositingState function
276     // that takes the new state.
277
278     if (graphicsLayer) {
279         if (!m_layerTreeHost) {
280             // We're actually entering accelerated compositing mode.
281             enterAcceleratedCompositingMode(graphicsLayer);
282         } else {
283             // We're already in accelerated compositing mode, but the root compositing layer changed.
284
285             m_exitCompositingTimer.stop();
286             m_wantsToExitAcceleratedCompositingMode = false;
287
288             // If we haven't sent the EnterAcceleratedCompositingMode message, make sure that the
289             // layer tree host calls us back after the next layer flush so we can send it then.
290             if (!m_compositingAccordingToProxyMessages)
291                 m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
292
293             m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
294         }
295     } else {
296         if (m_layerTreeHost)
297             m_layerTreeHost->setRootCompositingLayer(0);
298     }
299 }
300
301 void CoordinatedDrawingArea::scheduleCompositingLayerFlush()
302 {
303     if (!m_layerTreeHost)
304         return;
305     m_layerTreeHost->scheduleLayerFlush();
306 }
307
308 void CoordinatedDrawingArea::scheduleCompositingLayerFlushImmediately()
309 {
310     scheduleCompositingLayerFlush();
311 }
312
313 void CoordinatedDrawingArea::updateBackingStoreState(uint64_t stateID, bool respondImmediately, float deviceScaleFactor, const WebCore::IntSize& size, const WebCore::IntSize& scrollOffset)
314 {
315     ASSERT(!m_inUpdateBackingStoreState);
316     m_inUpdateBackingStoreState = true;
317
318     ASSERT_ARG(stateID, stateID >= m_backingStoreStateID);
319     if (stateID != m_backingStoreStateID) {
320         m_backingStoreStateID = stateID;
321         m_shouldSendDidUpdateBackingStoreState = true;
322
323         m_webPage.setDeviceScaleFactor(deviceScaleFactor);
324         m_webPage.setSize(size);
325         m_webPage.layoutIfNeeded();
326         m_webPage.scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset);
327
328         if (m_layerTreeHost) {
329             // Coordinated Graphics sets the size of the root layer to contents size.
330             if (!m_webPage.useFixedLayout())
331                 m_layerTreeHost->sizeDidChange(m_webPage.size());
332         } else
333             m_dirtyRegion = m_webPage.bounds();
334     } else {
335         ASSERT(size == m_webPage.size());
336         if (!m_shouldSendDidUpdateBackingStoreState) {
337             // We've already sent a DidUpdateBackingStoreState message for this state. We have nothing more to do.
338             m_inUpdateBackingStoreState = false;
339             return;
340         }
341     }
342
343     // The UI process has updated to a new backing store state. Any Update messages we sent before
344     // this point will be ignored. We wait to set this to false until after updating the page's
345     // size so that any displays triggered by the relayout will be ignored. If we're supposed to
346     // respond to the UpdateBackingStoreState message immediately, we'll do a display anyway in
347     // sendDidUpdateBackingStoreState; otherwise we shouldn't do one right now.
348     m_isWaitingForDidUpdate = false;
349
350     if (respondImmediately) {
351         // Make sure to resume painting if we're supposed to respond immediately, otherwise we'll just
352         // send back an empty UpdateInfo struct.
353         if (m_isPaintingSuspended)
354             resumePainting();
355
356         sendDidUpdateBackingStoreState();
357     }
358
359     m_inUpdateBackingStoreState = false;
360 }
361
362 void CoordinatedDrawingArea::sendDidUpdateBackingStoreState()
363 {
364     ASSERT(!m_isWaitingForDidUpdate);
365     ASSERT(m_shouldSendDidUpdateBackingStoreState);
366
367     m_shouldSendDidUpdateBackingStoreState = false;
368
369     UpdateInfo updateInfo;
370
371     if (!m_isPaintingSuspended && !m_layerTreeHost)
372         display(updateInfo);
373
374     LayerTreeContext layerTreeContext;
375
376     if (m_isPaintingSuspended || m_layerTreeHost) {
377         updateInfo.viewSize = m_webPage.size();
378         updateInfo.deviceScaleFactor = m_webPage.corePage()->deviceScaleFactor();
379
380         if (m_layerTreeHost) {
381             layerTreeContext = m_layerTreeHost->layerTreeContext();
382
383             // We don't want the layer tree host to notify after the next scheduled
384             // layer flush because that might end up sending an EnterAcceleratedCompositingMode
385             // message back to the UI process, but the updated layer tree context
386             // will be sent back in the DidUpdateBackingStoreState message.
387             m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
388             m_layerTreeHost->forceRepaint();
389         }
390     }
391
392     m_webPage.send(Messages::DrawingAreaProxy::DidUpdateBackingStoreState(m_backingStoreStateID, updateInfo, layerTreeContext));
393     m_compositingAccordingToProxyMessages = !layerTreeContext.isEmpty();
394 }
395
396 void CoordinatedDrawingArea::didUpdate()
397 {
398     // We might get didUpdate messages from the UI process even after we've
399     // entered accelerated compositing mode. Ignore them.
400     if (m_layerTreeHost)
401         return;
402
403     m_isWaitingForDidUpdate = false;
404
405     // Display if needed. We call displayTimerFired here since it will throttle updates to 60fps.
406     displayTimerFired();
407 }
408
409 void CoordinatedDrawingArea::suspendPainting()
410 {
411     ASSERT(!m_isPaintingSuspended);
412
413     if (m_layerTreeHost)
414         m_layerTreeHost->pauseRendering();
415
416     m_isPaintingSuspended = true;
417     m_displayTimer.stop();
418
419     m_webPage.corePage()->suspendScriptedAnimations();
420 }
421
422 void CoordinatedDrawingArea::resumePainting()
423 {
424     if (!m_isPaintingSuspended) {
425         // FIXME: We can get a call to resumePainting when painting is not suspended.
426         // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>.
427         return;
428     }
429
430     if (m_layerTreeHost)
431         m_layerTreeHost->resumeRendering();
432
433     m_isPaintingSuspended = false;
434
435     // FIXME: We shouldn't always repaint everything here.
436     setNeedsDisplay();
437
438     m_webPage.corePage()->resumeScriptedAnimations();
439 }
440
441 void CoordinatedDrawingArea::enterAcceleratedCompositingMode(GraphicsLayer* graphicsLayer)
442 {
443     m_exitCompositingTimer.stop();
444     m_wantsToExitAcceleratedCompositingMode = false;
445
446     ASSERT(!m_layerTreeHost);
447
448     m_layerTreeHost = LayerTreeHost::create(&m_webPage);
449     if (!m_inUpdateBackingStoreState)
450         m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
451
452     m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
453
454     // Non-composited content will now be handled exclusively by the layer tree host.
455     m_dirtyRegion = Region();
456     m_scrollRect = IntRect();
457     m_scrollOffset = IntSize();
458     m_displayTimer.stop();
459     m_isWaitingForDidUpdate = false;
460 }
461
462 void CoordinatedDrawingArea::exitAcceleratedCompositingModeSoon()
463 {
464     if (m_layerTreeStateIsFrozen) {
465         m_wantsToExitAcceleratedCompositingMode = true;
466         return;
467     }
468
469     if (exitAcceleratedCompositingModePending())
470         return;
471
472     m_exitCompositingTimer.startOneShot(0);
473 }
474
475 void CoordinatedDrawingArea::scheduleDisplay()
476 {
477     ASSERT(!m_layerTreeHost);
478
479     if (m_isWaitingForDidUpdate)
480         return;
481
482     if (m_isPaintingSuspended)
483         return;
484
485     if (m_dirtyRegion.isEmpty())
486         return;
487
488     if (m_displayTimer.isActive())
489         return;
490
491     m_displayTimer.startOneShot(0);
492 }
493
494 void CoordinatedDrawingArea::displayTimerFired()
495 {
496     display();
497 }
498
499 void CoordinatedDrawingArea::display()
500 {
501     ASSERT(!m_layerTreeHost);
502     ASSERT(!m_isWaitingForDidUpdate);
503     ASSERT(!m_inUpdateBackingStoreState);
504
505     if (m_isPaintingSuspended)
506         return;
507
508     if (m_dirtyRegion.isEmpty())
509         return;
510
511     if (m_shouldSendDidUpdateBackingStoreState) {
512         sendDidUpdateBackingStoreState();
513         return;
514     }
515
516     UpdateInfo updateInfo;
517     display(updateInfo);
518
519     if (m_layerTreeHost) {
520         // The call to update caused layout which turned on accelerated compositing.
521         // Don't send an Update message in this case.
522         return;
523     }
524
525     m_webPage.send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
526     m_isWaitingForDidUpdate = true;
527 }
528
529 static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
530 {
531     const size_t rectThreshold = 10;
532     const double wastedSpaceThreshold = 0.75;
533
534     if (rects.size() <= 1 || rects.size() > rectThreshold)
535         return true;
536
537     // Attempt to guess whether or not we should use the region bounds rect or the individual rects.
538     // We do this by computing the percentage of "wasted space" in the bounds. If that wasted space
539     // is too large, then we will do individual rect painting instead.
540     unsigned boundsArea = bounds.width() * bounds.height();
541     unsigned rectsArea = 0;
542     for (auto& rect : rects)
543         rectsArea += rect.width() * rect.height();
544
545     double wastedSpace = 1 - (static_cast<double>(rectsArea) / boundsArea);
546
547     return wastedSpace <= wastedSpaceThreshold;
548 }
549
550 void CoordinatedDrawingArea::display(UpdateInfo& updateInfo)
551 {
552     ASSERT(!m_isPaintingSuspended);
553     ASSERT(!m_layerTreeHost);
554     ASSERT(!m_webPage.size().isEmpty());
555
556     m_webPage.layoutIfNeeded();
557
558     // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
559     // in charge of displaying, we have nothing more to do.
560     if (m_layerTreeHost)
561         return;
562
563     updateInfo.viewSize = m_webPage.size();
564     updateInfo.deviceScaleFactor = m_webPage.corePage()->deviceScaleFactor();
565
566     IntRect bounds = m_dirtyRegion.bounds();
567     ASSERT(m_webPage.bounds().contains(bounds));
568
569     IntSize bitmapSize = bounds.size();
570     float deviceScaleFactor = m_webPage.corePage()->deviceScaleFactor();
571     bitmapSize.scale(deviceScaleFactor);
572     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bitmapSize, ShareableBitmap::SupportsAlpha);
573     if (!bitmap)
574         return;
575
576     if (!bitmap->createHandle(updateInfo.bitmapHandle))
577         return;
578
579     Vector<IntRect> rects = m_dirtyRegion.rects();
580
581     if (shouldPaintBoundsRect(bounds, rects)) {
582         rects.clear();
583         rects.append(bounds);
584     }
585
586     updateInfo.scrollRect = m_scrollRect;
587     updateInfo.scrollOffset = m_scrollOffset;
588
589     m_dirtyRegion = Region();
590     m_scrollRect = IntRect();
591     m_scrollOffset = IntSize();
592
593     auto graphicsContext = bitmap->createGraphicsContext();
594     graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
595
596     updateInfo.updateRectBounds = bounds;
597
598     graphicsContext->translate(-bounds.x(), -bounds.y());
599
600     for (auto& rect : rects) {
601         m_webPage.drawRect(*graphicsContext, rect);
602         updateInfo.updateRects.append(rect);
603     }
604
605     // Layout can trigger more calls to setNeedsDisplay and we don't want to process them
606     // until the UI process has painted the update, so we stop the timer here.
607     m_displayTimer.stop();
608 }
609
610 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
611 void CoordinatedDrawingArea::didReceiveCoordinatedLayerTreeHostMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
612 {
613     if (m_layerTreeHost)
614         m_layerTreeHost->didReceiveCoordinatedLayerTreeHostMessage(connection, decoder);
615 }
616 #endif
617
618 void CoordinatedDrawingArea::viewStateDidChange(ViewState::Flags changed, bool, const Vector<uint64_t>&)
619 {
620     if (changed & ViewState::IsVisible) {
621         if (m_webPage.isVisible())
622             resumePainting();
623         else
624             suspendPainting();
625     }
626 }
627
628 void CoordinatedDrawingArea::attachViewOverlayGraphicsLayer(WebCore::Frame* frame, WebCore::GraphicsLayer* viewOverlayRootLayer)
629 {
630     if (!frame->isMainFrame())
631         return;
632
633     if (!m_layerTreeHost)
634         return;
635
636     CoordinatedLayerTreeHost* coordinatedLayerTreeHost = static_cast<CoordinatedLayerTreeHost*>(m_layerTreeHost.get());
637     coordinatedLayerTreeHost->setViewOverlayRootLayer(viewOverlayRootLayer);
638 }
639
640 } // namespace WebKit
641 #endif // USE(COORDINATED_GRAPHICS)