Make GraphicsLayers ref-counted, so their tree can persist when disconnected from...
[WebKit-https.git] / Source / WebCore / page / PageOverlayController.cpp
1 /*
2  * Copyright (C) 2014-2017 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "PageOverlayController.h"
28
29 #include "Chrome.h"
30 #include "ChromeClient.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "GraphicsLayer.h"
35 #include "Page.h"
36 #include "PageOverlay.h"
37 #include "ScrollingCoordinator.h"
38 #include "Settings.h"
39 #include "TiledBacking.h"
40
41 // FIXME: Someone needs to call didChangeSettings() if we want dynamic updates of layer border/repaint counter settings.
42
43 namespace WebCore {
44
45 PageOverlayController::PageOverlayController(Page& page)
46     :  m_page(page)
47 {
48 }
49
50 PageOverlayController::~PageOverlayController() = default;
51
52 void PageOverlayController::createRootLayersIfNeeded()
53 {
54     if (m_initialized)
55         return;
56
57     m_initialized = true;
58
59     ASSERT(!m_documentOverlayRootLayer);
60     ASSERT(!m_viewOverlayRootLayer);
61
62     m_documentOverlayRootLayer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
63     m_viewOverlayRootLayer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
64     m_documentOverlayRootLayer->setName("Document overlay Container");
65     m_viewOverlayRootLayer->setName("View overlay container");
66 }
67
68 GraphicsLayer* PageOverlayController::documentOverlayRootLayer() const
69 {
70     return m_documentOverlayRootLayer.get();
71 }
72
73 GraphicsLayer* PageOverlayController::viewOverlayRootLayer() const
74 {
75     return m_viewOverlayRootLayer.get();
76 }
77
78 static void updateOverlayGeometry(PageOverlay& overlay, GraphicsLayer& graphicsLayer)
79 {
80     IntRect overlayFrame = overlay.frame();
81
82     if (overlayFrame.location() == graphicsLayer.position() && overlayFrame.size() == graphicsLayer.size())
83         return;
84
85     graphicsLayer.setPosition(overlayFrame.location());
86     graphicsLayer.setSize(overlayFrame.size());
87 }
88
89 GraphicsLayer& PageOverlayController::layerWithDocumentOverlays()
90 {
91     createRootLayersIfNeeded();
92
93     bool inWindow = m_page.isInWindow();
94
95     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
96         PageOverlay& overlay = *overlayAndLayer.key;
97         if (overlay.overlayType() != PageOverlay::OverlayType::Document)
98             continue;
99
100         auto& layer = overlayAndLayer.value;
101         GraphicsLayer::traverse(layer.get(), [inWindow](GraphicsLayer& layer) {
102             layer.setIsInWindow(inWindow);
103         });
104         updateOverlayGeometry(overlay, layer.get());
105         
106         if (!layer->parent())
107             m_documentOverlayRootLayer->addChild(layer.copyRef());
108     }
109
110     return *m_documentOverlayRootLayer;
111 }
112
113 GraphicsLayer& PageOverlayController::layerWithViewOverlays()
114 {
115     createRootLayersIfNeeded();
116
117     bool inWindow = m_page.isInWindow();
118
119     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
120         PageOverlay& overlay = *overlayAndLayer.key;
121         if (overlay.overlayType() != PageOverlay::OverlayType::View)
122             continue;
123
124         auto& layer = overlayAndLayer.value;
125         GraphicsLayer::traverse(layer.get(), [inWindow](GraphicsLayer& layer) {
126             layer.setIsInWindow(inWindow);
127         });
128         updateOverlayGeometry(overlay, layer.get());
129         
130         if (!layer->parent())
131             m_viewOverlayRootLayer->addChild(layer.copyRef());
132     }
133
134     return *m_viewOverlayRootLayer;
135 }
136
137 void PageOverlayController::installPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode)
138 {
139     createRootLayersIfNeeded();
140
141     if (m_pageOverlays.contains(&overlay))
142         return;
143
144     m_pageOverlays.append(&overlay);
145
146     auto layer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
147     layer->setAnchorPoint(FloatPoint3D());
148     layer->setBackgroundColor(overlay.backgroundColor());
149     layer->setName("Overlay content");
150
151     updateSettingsForLayer(layer.get());
152
153     switch (overlay.overlayType()) {
154     case PageOverlay::OverlayType::View:
155         m_viewOverlayRootLayer->addChild(layer.get());
156         break;
157     case PageOverlay::OverlayType::Document:
158         m_documentOverlayRootLayer->addChild(layer.get());
159         break;
160     }
161
162     auto& rawLayer = layer.get();
163     m_overlayGraphicsLayers.set(&overlay, WTFMove(layer));
164
165     updateForceSynchronousScrollLayerPositionUpdates();
166
167     overlay.setPage(&m_page);
168
169     if (FrameView* frameView = m_page.mainFrame().view())
170         frameView->enterCompositingMode();
171
172     updateOverlayGeometry(overlay, rawLayer);
173
174     if (fadeMode == PageOverlay::FadeMode::Fade)
175         overlay.startFadeInAnimation();
176 }
177
178 void PageOverlayController::uninstallPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode)
179 {
180     if (fadeMode == PageOverlay::FadeMode::Fade) {
181         overlay.startFadeOutAnimation();
182         return;
183     }
184
185     overlay.setPage(nullptr);
186
187     if (auto optionalLayer = m_overlayGraphicsLayers.take(&overlay))
188         optionalLayer.value()->removeFromParent();
189
190     bool removed = m_pageOverlays.removeFirst(&overlay);
191     ASSERT_UNUSED(removed, removed);
192
193     updateForceSynchronousScrollLayerPositionUpdates();
194 }
195
196 void PageOverlayController::updateForceSynchronousScrollLayerPositionUpdates()
197 {
198 #if ENABLE(ASYNC_SCROLLING)
199     bool forceSynchronousScrollLayerPositionUpdates = false;
200
201     for (auto& overlay : m_pageOverlays) {
202         if (overlay->needsSynchronousScrolling())
203             forceSynchronousScrollLayerPositionUpdates = true;
204     }
205
206     if (ScrollingCoordinator* scrollingCoordinator = m_page.scrollingCoordinator())
207         scrollingCoordinator->setForceSynchronousScrollLayerPositionUpdates(forceSynchronousScrollLayerPositionUpdates);
208 #endif
209 }
210
211 void PageOverlayController::setPageOverlayNeedsDisplay(PageOverlay& overlay, const WebCore::IntRect& dirtyRect)
212 {
213     ASSERT(m_pageOverlays.contains(&overlay));
214     auto* graphicsLayer = m_overlayGraphicsLayers.get(&overlay);
215
216     if (!graphicsLayer->drawsContent()) {
217         graphicsLayer->setDrawsContent(true);
218         updateOverlayGeometry(overlay, *graphicsLayer);
219     }
220
221     graphicsLayer->setNeedsDisplayInRect(dirtyRect);
222 }
223
224 void PageOverlayController::setPageOverlayOpacity(PageOverlay& overlay, float opacity)
225 {
226     ASSERT(m_pageOverlays.contains(&overlay));
227     m_overlayGraphicsLayers.get(&overlay)->setOpacity(opacity);
228 }
229
230 void PageOverlayController::clearPageOverlay(PageOverlay& overlay)
231 {
232     ASSERT(m_pageOverlays.contains(&overlay));
233     m_overlayGraphicsLayers.get(&overlay)->setDrawsContent(false);
234 }
235
236 GraphicsLayer& PageOverlayController::layerForOverlay(PageOverlay& overlay) const
237 {
238     ASSERT(m_pageOverlays.contains(&overlay));
239     return *m_overlayGraphicsLayers.get(&overlay);
240 }
241
242 void PageOverlayController::willDetachRootLayer()
243 {
244     if (m_documentOverlayRootLayer) {
245         m_documentOverlayRootLayer->removeFromParent();
246         m_documentOverlayRootLayer = nullptr;
247     }
248
249     if (m_viewOverlayRootLayer) {
250         m_viewOverlayRootLayer->removeFromParent();
251         m_viewOverlayRootLayer = nullptr;
252     }
253     m_initialized = false;
254 }
255
256 void PageOverlayController::didChangeViewSize()
257 {
258     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
259         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View)
260             updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get());
261     }
262 }
263
264 void PageOverlayController::didChangeDocumentSize()
265 {
266     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
267         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::Document)
268             updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get());
269     }
270 }
271
272 void PageOverlayController::didChangeSettings()
273 {
274     // FIXME: We should apply these settings to all overlay sublayers recursively.
275     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
276         updateSettingsForLayer(graphicsLayer.get());
277 }
278
279 void PageOverlayController::didChangeDeviceScaleFactor()
280 {
281     if (!m_initialized)
282         return;
283
284     m_documentOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
285     m_viewOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
286
287     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
288         graphicsLayer->setNeedsDisplay();
289 }
290
291 void PageOverlayController::didChangeViewExposedRect()
292 {
293     m_page.chrome().client().scheduleCompositingLayerFlush();
294 }
295
296 void PageOverlayController::didScrollFrame(Frame& frame)
297 {
298     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
299         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View || !frame.isMainFrame())
300             overlayAndLayer.value->setNeedsDisplay();
301         overlayAndLayer.key->didScrollFrame(frame);
302     }
303 }
304
305 void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer)
306 {
307     Settings& settings = m_page.settings();
308     layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled());
309     layer.setShowDebugBorder(settings.showDebugBorders());
310     layer.setShowRepaintCounter(settings.showRepaintCounter());
311 }
312
313 bool PageOverlayController::handleMouseEvent(const PlatformMouseEvent& mouseEvent)
314 {
315     if (m_pageOverlays.isEmpty())
316         return false;
317
318     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
319         if ((*it)->mouseEvent(mouseEvent))
320             return true;
321     }
322
323     return false;
324 }
325
326 bool PageOverlayController::copyAccessibilityAttributeStringValueForPoint(String attribute, FloatPoint parameter, String& value)
327 {
328     if (m_pageOverlays.isEmpty())
329         return false;
330
331     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
332         if ((*it)->copyAccessibilityAttributeStringValueForPoint(attribute, parameter, value))
333             return true;
334     }
335
336     return false;
337 }
338
339 bool PageOverlayController::copyAccessibilityAttributeBoolValueForPoint(String attribute, FloatPoint parameter, bool& value)
340 {
341     if (m_pageOverlays.isEmpty())
342         return false;
343
344     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
345         if ((*it)->copyAccessibilityAttributeBoolValueForPoint(attribute, parameter, value))
346             return true;
347     }
348     
349     return false;
350 }
351
352 Vector<String> PageOverlayController::copyAccessibilityAttributesNames(bool parameterizedNames)
353 {
354     if (m_pageOverlays.isEmpty())
355         return { };
356
357     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
358         Vector<String> names = (*it)->copyAccessibilityAttributeNames(parameterizedNames);
359         if (!names.isEmpty())
360             return names;
361     }
362
363     return { };
364 }
365
366 void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintBehavior)
367 {
368     for (auto& overlayAndGraphicsLayer : m_overlayGraphicsLayers) {
369         if (overlayAndGraphicsLayer.value.ptr() != graphicsLayer)
370             continue;
371
372         GraphicsContextStateSaver stateSaver(graphicsContext);
373         graphicsContext.clip(clipRect);
374         overlayAndGraphicsLayer.key->drawRect(graphicsContext, enclosingIntRect(clipRect));
375
376         return;
377     }
378 }
379
380 float PageOverlayController::deviceScaleFactor() const
381 {
382     return m_page.deviceScaleFactor();
383 }
384
385 void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*)
386 {
387     m_page.chrome().client().scheduleCompositingLayerFlush();
388 }
389
390 void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay)
391 {
392     ASSERT(m_pageOverlays.contains(&overlay));
393     if (auto* layer = m_overlayGraphicsLayers.get(&overlay))
394         updateOverlayGeometry(overlay, *layer);
395 }
396
397 void PageOverlayController::didChangeOverlayBackgroundColor(PageOverlay& overlay)
398 {
399     ASSERT(m_pageOverlays.contains(&overlay));
400     if (auto* layer = m_overlayGraphicsLayers.get(&overlay))
401         layer->setBackgroundColor(overlay.backgroundColor());
402 }
403
404 bool PageOverlayController::shouldSkipLayerInDump(const GraphicsLayer*, LayerTreeAsTextBehavior behavior) const
405 {
406     return !(behavior & LayerTreeAsTextIncludePageOverlayLayers);
407 }
408
409 void PageOverlayController::tiledBackingUsageChanged(const GraphicsLayer* graphicsLayer, bool usingTiledBacking)
410 {
411     if (usingTiledBacking)
412         graphicsLayer->tiledBacking()->setIsInWindow(m_page.isInWindow());
413 }
414
415 } // namespace WebKit