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     GraphicsLayer::unparentAndClear(m_documentOverlayRootLayer);
245     GraphicsLayer::unparentAndClear(m_viewOverlayRootLayer);
246
247     m_initialized = false;
248 }
249
250 void PageOverlayController::didChangeViewSize()
251 {
252     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
253         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View)
254             updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get());
255     }
256 }
257
258 void PageOverlayController::didChangeDocumentSize()
259 {
260     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
261         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::Document)
262             updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get());
263     }
264 }
265
266 void PageOverlayController::didChangeSettings()
267 {
268     // FIXME: We should apply these settings to all overlay sublayers recursively.
269     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
270         updateSettingsForLayer(graphicsLayer.get());
271 }
272
273 void PageOverlayController::didChangeDeviceScaleFactor()
274 {
275     if (!m_initialized)
276         return;
277
278     m_documentOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
279     m_viewOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
280
281     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
282         graphicsLayer->setNeedsDisplay();
283 }
284
285 void PageOverlayController::didChangeViewExposedRect()
286 {
287     m_page.chrome().client().scheduleCompositingLayerFlush();
288 }
289
290 void PageOverlayController::didScrollFrame(Frame& frame)
291 {
292     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
293         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View || !frame.isMainFrame())
294             overlayAndLayer.value->setNeedsDisplay();
295         overlayAndLayer.key->didScrollFrame(frame);
296     }
297 }
298
299 void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer)
300 {
301     Settings& settings = m_page.settings();
302     layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled());
303     layer.setShowDebugBorder(settings.showDebugBorders());
304     layer.setShowRepaintCounter(settings.showRepaintCounter());
305 }
306
307 bool PageOverlayController::handleMouseEvent(const PlatformMouseEvent& mouseEvent)
308 {
309     if (m_pageOverlays.isEmpty())
310         return false;
311
312     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
313         if ((*it)->mouseEvent(mouseEvent))
314             return true;
315     }
316
317     return false;
318 }
319
320 bool PageOverlayController::copyAccessibilityAttributeStringValueForPoint(String attribute, FloatPoint parameter, String& value)
321 {
322     if (m_pageOverlays.isEmpty())
323         return false;
324
325     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
326         if ((*it)->copyAccessibilityAttributeStringValueForPoint(attribute, parameter, value))
327             return true;
328     }
329
330     return false;
331 }
332
333 bool PageOverlayController::copyAccessibilityAttributeBoolValueForPoint(String attribute, FloatPoint parameter, bool& value)
334 {
335     if (m_pageOverlays.isEmpty())
336         return false;
337
338     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
339         if ((*it)->copyAccessibilityAttributeBoolValueForPoint(attribute, parameter, value))
340             return true;
341     }
342     
343     return false;
344 }
345
346 Vector<String> PageOverlayController::copyAccessibilityAttributesNames(bool parameterizedNames)
347 {
348     if (m_pageOverlays.isEmpty())
349         return { };
350
351     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
352         Vector<String> names = (*it)->copyAccessibilityAttributeNames(parameterizedNames);
353         if (!names.isEmpty())
354             return names;
355     }
356
357     return { };
358 }
359
360 void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintBehavior)
361 {
362     for (auto& overlayAndGraphicsLayer : m_overlayGraphicsLayers) {
363         if (overlayAndGraphicsLayer.value.ptr() != graphicsLayer)
364             continue;
365
366         GraphicsContextStateSaver stateSaver(graphicsContext);
367         graphicsContext.clip(clipRect);
368         overlayAndGraphicsLayer.key->drawRect(graphicsContext, enclosingIntRect(clipRect));
369
370         return;
371     }
372 }
373
374 float PageOverlayController::deviceScaleFactor() const
375 {
376     return m_page.deviceScaleFactor();
377 }
378
379 void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*)
380 {
381     m_page.chrome().client().scheduleCompositingLayerFlush();
382 }
383
384 void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay)
385 {
386     ASSERT(m_pageOverlays.contains(&overlay));
387     if (auto* layer = m_overlayGraphicsLayers.get(&overlay))
388         updateOverlayGeometry(overlay, *layer);
389 }
390
391 void PageOverlayController::didChangeOverlayBackgroundColor(PageOverlay& overlay)
392 {
393     ASSERT(m_pageOverlays.contains(&overlay));
394     if (auto* layer = m_overlayGraphicsLayers.get(&overlay))
395         layer->setBackgroundColor(overlay.backgroundColor());
396 }
397
398 bool PageOverlayController::shouldSkipLayerInDump(const GraphicsLayer*, LayerTreeAsTextBehavior behavior) const
399 {
400     return !(behavior & LayerTreeAsTextIncludePageOverlayLayers);
401 }
402
403 void PageOverlayController::tiledBackingUsageChanged(const GraphicsLayer* graphicsLayer, bool usingTiledBacking)
404 {
405     if (usingTiledBacking)
406         graphicsLayer->tiledBacking()->setIsInWindow(m_page.isInWindow());
407 }
408
409 } // namespace WebKit