4856ff6e744ddc496d1130143e0a66481d34fabb
[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_initialized(false)
47     , m_page(page)
48 {
49 }
50
51 PageOverlayController::~PageOverlayController() = default;
52
53 void PageOverlayController::createRootLayersIfNeeded()
54 {
55     if (m_initialized)
56         return;
57
58     m_initialized = true;
59
60     ASSERT(!m_documentOverlayRootLayer);
61     ASSERT(!m_viewOverlayRootLayer);
62
63     m_documentOverlayRootLayer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
64     m_viewOverlayRootLayer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
65     m_documentOverlayRootLayer->setName("Document overlay Container");
66     m_viewOverlayRootLayer->setName("View overlay container");
67 }
68
69 GraphicsLayer* PageOverlayController::documentOverlayRootLayer() const
70 {
71     return m_documentOverlayRootLayer.get();
72 }
73
74 GraphicsLayer* PageOverlayController::viewOverlayRootLayer() const
75 {
76     return m_viewOverlayRootLayer.get();
77 }
78
79 static void updateOverlayGeometry(PageOverlay& overlay, GraphicsLayer& graphicsLayer)
80 {
81     IntRect overlayFrame = overlay.frame();
82
83     if (overlayFrame.location() == graphicsLayer.position() && overlayFrame.size() == graphicsLayer.size())
84         return;
85
86     graphicsLayer.setPosition(overlayFrame.location());
87     graphicsLayer.setSize(overlayFrame.size());
88 }
89
90 GraphicsLayer& PageOverlayController::layerWithDocumentOverlays()
91 {
92     createRootLayersIfNeeded();
93
94     bool inWindow = m_page.isInWindow();
95
96     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
97         PageOverlay& overlay = *overlayAndLayer.key;
98         if (overlay.overlayType() != PageOverlay::OverlayType::Document)
99             continue;
100
101         GraphicsLayer& layer = *overlayAndLayer.value;
102         GraphicsLayer::traverse(layer, [inWindow](GraphicsLayer& layer) {
103             layer.setIsInWindow(inWindow);
104         });
105         updateOverlayGeometry(overlay, layer);
106         
107         if (!layer.parent())
108             m_documentOverlayRootLayer->addChild(&layer);
109     }
110
111     return *m_documentOverlayRootLayer;
112 }
113
114 GraphicsLayer& PageOverlayController::layerWithViewOverlays()
115 {
116     createRootLayersIfNeeded();
117
118     bool inWindow = m_page.isInWindow();
119
120     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
121         PageOverlay& overlay = *overlayAndLayer.key;
122         if (overlay.overlayType() != PageOverlay::OverlayType::View)
123             continue;
124
125         GraphicsLayer& layer = *overlayAndLayer.value;
126         GraphicsLayer::traverse(layer, [inWindow](GraphicsLayer& layer) {
127             layer.setIsInWindow(inWindow);
128         });
129         updateOverlayGeometry(overlay, layer);
130         
131         if (!layer.parent())
132             m_viewOverlayRootLayer->addChild(&layer);
133     }
134
135     return *m_viewOverlayRootLayer;
136 }
137
138 void PageOverlayController::installPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode)
139 {
140     createRootLayersIfNeeded();
141
142     if (m_pageOverlays.contains(&overlay))
143         return;
144
145     m_pageOverlays.append(&overlay);
146
147     std::unique_ptr<GraphicsLayer> layer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this);
148     layer->setAnchorPoint(FloatPoint3D());
149     layer->setBackgroundColor(overlay.backgroundColor());
150     layer->setName("Overlay content");
151
152     updateSettingsForLayer(*layer);
153
154     switch (overlay.overlayType()) {
155     case PageOverlay::OverlayType::View:
156         m_viewOverlayRootLayer->addChild(layer.get());
157         break;
158     case PageOverlay::OverlayType::Document:
159         m_documentOverlayRootLayer->addChild(layer.get());
160         break;
161     }
162
163     GraphicsLayer& rawLayer = *layer;
164     m_overlayGraphicsLayers.set(&overlay, WTFMove(layer));
165
166     updateForceSynchronousScrollLayerPositionUpdates();
167
168     overlay.setPage(&m_page);
169
170     if (FrameView* frameView = m_page.mainFrame().view())
171         frameView->enterCompositingMode();
172
173     updateOverlayGeometry(overlay, rawLayer);
174
175     if (fadeMode == PageOverlay::FadeMode::Fade)
176         overlay.startFadeInAnimation();
177 }
178
179 void PageOverlayController::uninstallPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode)
180 {
181     if (fadeMode == PageOverlay::FadeMode::Fade) {
182         overlay.startFadeOutAnimation();
183         return;
184     }
185
186     overlay.setPage(nullptr);
187
188     m_overlayGraphicsLayers.take(&overlay)->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     GraphicsLayer& 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     m_documentOverlayRootLayer = nullptr;
245     m_viewOverlayRootLayer = nullptr;
246     m_initialized = false;
247 }
248
249 void PageOverlayController::didChangeViewSize()
250 {
251     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
252         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View)
253             updateOverlayGeometry(*overlayAndLayer.key, *overlayAndLayer.value);
254     }
255 }
256
257 void PageOverlayController::didChangeDocumentSize()
258 {
259     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
260         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::Document)
261             updateOverlayGeometry(*overlayAndLayer.key, *overlayAndLayer.value);
262     }
263 }
264
265 void PageOverlayController::didChangeSettings()
266 {
267     // FIXME: We should apply these settings to all overlay sublayers recursively.
268     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
269         updateSettingsForLayer(*graphicsLayer);
270 }
271
272 void PageOverlayController::didChangeDeviceScaleFactor()
273 {
274     if (!m_initialized)
275         return;
276
277     m_documentOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
278     m_viewOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
279
280     for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
281         graphicsLayer->setNeedsDisplay();
282 }
283
284 void PageOverlayController::didChangeViewExposedRect()
285 {
286     m_page.chrome().client().scheduleCompositingLayerFlush();
287 }
288
289 void PageOverlayController::didScrollFrame(Frame& frame)
290 {
291     for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
292         if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View || !frame.isMainFrame())
293             overlayAndLayer.value->setNeedsDisplay();
294         overlayAndLayer.key->didScrollFrame(frame);
295     }
296 }
297
298 void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer)
299 {
300     Settings& settings = m_page.settings();
301     layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled());
302     layer.setShowDebugBorder(settings.showDebugBorders());
303     layer.setShowRepaintCounter(settings.showRepaintCounter());
304 }
305
306 bool PageOverlayController::handleMouseEvent(const PlatformMouseEvent& mouseEvent)
307 {
308     if (m_pageOverlays.isEmpty())
309         return false;
310
311     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
312         if ((*it)->mouseEvent(mouseEvent))
313             return true;
314     }
315
316     return false;
317 }
318
319 bool PageOverlayController::copyAccessibilityAttributeStringValueForPoint(String attribute, FloatPoint parameter, String& value)
320 {
321     if (m_pageOverlays.isEmpty())
322         return false;
323
324     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
325         if ((*it)->copyAccessibilityAttributeStringValueForPoint(attribute, parameter, value))
326             return true;
327     }
328
329     return false;
330 }
331
332 bool PageOverlayController::copyAccessibilityAttributeBoolValueForPoint(String attribute, FloatPoint parameter, bool& value)
333 {
334     if (m_pageOverlays.isEmpty())
335         return false;
336
337     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
338         if ((*it)->copyAccessibilityAttributeBoolValueForPoint(attribute, parameter, value))
339             return true;
340     }
341     
342     return false;
343 }
344
345 Vector<String> PageOverlayController::copyAccessibilityAttributesNames(bool parameterizedNames)
346 {
347     if (m_pageOverlays.isEmpty())
348         return { };
349
350     for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
351         Vector<String> names = (*it)->copyAccessibilityAttributeNames(parameterizedNames);
352         if (!names.isEmpty())
353             return names;
354     }
355
356     return { };
357 }
358
359 void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintBehavior)
360 {
361     for (auto& overlayAndGraphicsLayer : m_overlayGraphicsLayers) {
362         if (overlayAndGraphicsLayer.value.get() != graphicsLayer)
363             continue;
364
365         GraphicsContextStateSaver stateSaver(graphicsContext);
366         graphicsContext.clip(clipRect);
367         overlayAndGraphicsLayer.key->drawRect(graphicsContext, enclosingIntRect(clipRect));
368
369         return;
370     }
371 }
372
373 float PageOverlayController::deviceScaleFactor() const
374 {
375     return m_page.deviceScaleFactor();
376 }
377
378 void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*)
379 {
380     m_page.chrome().client().scheduleCompositingLayerFlush();
381 }
382
383 void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay)
384 {
385     ASSERT(m_pageOverlays.contains(&overlay));
386     updateOverlayGeometry(overlay, *m_overlayGraphicsLayers.get(&overlay));
387 }
388
389 void PageOverlayController::didChangeOverlayBackgroundColor(PageOverlay& overlay)
390 {
391     ASSERT(m_pageOverlays.contains(&overlay));
392     m_overlayGraphicsLayers.get(&overlay)->setBackgroundColor(overlay.backgroundColor());
393 }
394
395 bool PageOverlayController::shouldSkipLayerInDump(const GraphicsLayer*, LayerTreeAsTextBehavior behavior) const
396 {
397     return !(behavior & LayerTreeAsTextIncludePageOverlayLayers);
398 }
399
400 void PageOverlayController::tiledBackingUsageChanged(const GraphicsLayer* graphicsLayer, bool usingTiledBacking)
401 {
402     if (usingTiledBacking)
403         graphicsLayer->tiledBacking()->setIsInWindow(m_page.isInWindow());
404 }
405
406 } // namespace WebKit