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 | void PageOverlayController::installedPageOverlaysChanged() |
69 | { |
70 | if (hasViewOverlays()) |
71 | attachViewOverlayLayers(); |
72 | else |
73 | detachViewOverlayLayers(); |
74 | |
75 | if (auto* frameView = m_page.mainFrame().view()) |
76 | frameView->setNeedsCompositingConfigurationUpdate(); |
77 | |
78 | updateForceSynchronousScrollLayerPositionUpdates(); |
79 | } |
80 | |
81 | bool PageOverlayController::hasDocumentOverlays() const |
82 | { |
83 | for (const auto& overlay : m_pageOverlays) { |
84 | if (overlay->overlayType() == PageOverlay::OverlayType::Document) |
85 | return true; |
86 | } |
87 | return false; |
88 | } |
89 | |
90 | bool PageOverlayController::hasViewOverlays() const |
91 | { |
92 | for (const auto& overlay : m_pageOverlays) { |
93 | if (overlay->overlayType() == PageOverlay::OverlayType::View) |
94 | return true; |
95 | } |
96 | return false; |
97 | } |
98 | |
99 | void PageOverlayController::attachViewOverlayLayers() |
100 | { |
101 | if (hasViewOverlays()) |
102 | m_page.chrome().client().attachViewOverlayGraphicsLayer(&layerWithViewOverlays()); |
103 | } |
104 | |
105 | void PageOverlayController::detachViewOverlayLayers() |
106 | { |
107 | m_page.chrome().client().attachViewOverlayGraphicsLayer(nullptr); |
108 | } |
109 | |
110 | GraphicsLayer* PageOverlayController::documentOverlayRootLayer() const |
111 | { |
112 | return m_documentOverlayRootLayer.get(); |
113 | } |
114 | |
115 | GraphicsLayer* PageOverlayController::viewOverlayRootLayer() const |
116 | { |
117 | return m_viewOverlayRootLayer.get(); |
118 | } |
119 | |
120 | static void updateOverlayGeometry(PageOverlay& overlay, GraphicsLayer& graphicsLayer) |
121 | { |
122 | IntRect overlayFrame = overlay.frame(); |
123 | |
124 | if (overlayFrame.location() == graphicsLayer.position() && overlayFrame.size() == graphicsLayer.size()) |
125 | return; |
126 | |
127 | graphicsLayer.setPosition(overlayFrame.location()); |
128 | graphicsLayer.setSize(overlayFrame.size()); |
129 | } |
130 | |
131 | GraphicsLayer& PageOverlayController::layerWithDocumentOverlays() |
132 | { |
133 | createRootLayersIfNeeded(); |
134 | |
135 | bool inWindow = m_page.isInWindow(); |
136 | |
137 | for (auto& overlayAndLayer : m_overlayGraphicsLayers) { |
138 | PageOverlay& overlay = *overlayAndLayer.key; |
139 | if (overlay.overlayType() != PageOverlay::OverlayType::Document) |
140 | continue; |
141 | |
142 | auto& layer = overlayAndLayer.value; |
143 | GraphicsLayer::traverse(layer.get(), [inWindow](GraphicsLayer& layer) { |
144 | layer.setIsInWindow(inWindow); |
145 | }); |
146 | updateOverlayGeometry(overlay, layer.get()); |
147 | |
148 | if (!layer->parent()) |
149 | m_documentOverlayRootLayer->addChild(layer.copyRef()); |
150 | } |
151 | |
152 | return *m_documentOverlayRootLayer; |
153 | } |
154 | |
155 | GraphicsLayer& PageOverlayController::layerWithViewOverlays() |
156 | { |
157 | createRootLayersIfNeeded(); |
158 | |
159 | bool inWindow = m_page.isInWindow(); |
160 | |
161 | for (auto& overlayAndLayer : m_overlayGraphicsLayers) { |
162 | PageOverlay& overlay = *overlayAndLayer.key; |
163 | if (overlay.overlayType() != PageOverlay::OverlayType::View) |
164 | continue; |
165 | |
166 | auto& layer = overlayAndLayer.value; |
167 | GraphicsLayer::traverse(layer.get(), [inWindow](GraphicsLayer& layer) { |
168 | layer.setIsInWindow(inWindow); |
169 | }); |
170 | updateOverlayGeometry(overlay, layer.get()); |
171 | |
172 | if (!layer->parent()) |
173 | m_viewOverlayRootLayer->addChild(layer.copyRef()); |
174 | } |
175 | |
176 | return *m_viewOverlayRootLayer; |
177 | } |
178 | |
179 | void PageOverlayController::installPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode) |
180 | { |
181 | createRootLayersIfNeeded(); |
182 | |
183 | if (m_pageOverlays.contains(&overlay)) |
184 | return; |
185 | |
186 | m_pageOverlays.append(&overlay); |
187 | |
188 | auto layer = GraphicsLayer::create(m_page.chrome().client().graphicsLayerFactory(), *this); |
189 | layer->setAnchorPoint({ }); |
190 | layer->setBackgroundColor(overlay.backgroundColor()); |
191 | layer->setName("Overlay content" ); |
192 | |
193 | updateSettingsForLayer(layer.get()); |
194 | |
195 | switch (overlay.overlayType()) { |
196 | case PageOverlay::OverlayType::View: |
197 | m_viewOverlayRootLayer->addChild(layer.get()); |
198 | break; |
199 | case PageOverlay::OverlayType::Document: |
200 | m_documentOverlayRootLayer->addChild(layer.get()); |
201 | break; |
202 | } |
203 | |
204 | auto& rawLayer = layer.get(); |
205 | m_overlayGraphicsLayers.set(&overlay, WTFMove(layer)); |
206 | |
207 | overlay.setPage(&m_page); |
208 | |
209 | if (FrameView* frameView = m_page.mainFrame().view()) |
210 | frameView->enterCompositingMode(); |
211 | |
212 | updateOverlayGeometry(overlay, rawLayer); |
213 | |
214 | if (fadeMode == PageOverlay::FadeMode::Fade) |
215 | overlay.startFadeInAnimation(); |
216 | |
217 | installedPageOverlaysChanged(); |
218 | } |
219 | |
220 | void PageOverlayController::uninstallPageOverlay(PageOverlay& overlay, PageOverlay::FadeMode fadeMode) |
221 | { |
222 | if (fadeMode == PageOverlay::FadeMode::Fade) { |
223 | overlay.startFadeOutAnimation(); |
224 | return; |
225 | } |
226 | |
227 | overlay.setPage(nullptr); |
228 | |
229 | if (auto optionalLayer = m_overlayGraphicsLayers.take(&overlay)) |
230 | optionalLayer.value()->removeFromParent(); |
231 | |
232 | bool removed = m_pageOverlays.removeFirst(&overlay); |
233 | ASSERT_UNUSED(removed, removed); |
234 | |
235 | installedPageOverlaysChanged(); |
236 | } |
237 | |
238 | void PageOverlayController::updateForceSynchronousScrollLayerPositionUpdates() |
239 | { |
240 | #if ENABLE(ASYNC_SCROLLING) |
241 | bool forceSynchronousScrollLayerPositionUpdates = false; |
242 | |
243 | for (auto& overlay : m_pageOverlays) { |
244 | if (overlay->needsSynchronousScrolling()) |
245 | forceSynchronousScrollLayerPositionUpdates = true; |
246 | } |
247 | |
248 | if (ScrollingCoordinator* scrollingCoordinator = m_page.scrollingCoordinator()) |
249 | scrollingCoordinator->setForceSynchronousScrollLayerPositionUpdates(forceSynchronousScrollLayerPositionUpdates); |
250 | #endif |
251 | } |
252 | |
253 | void PageOverlayController::setPageOverlayNeedsDisplay(PageOverlay& overlay, const WebCore::IntRect& dirtyRect) |
254 | { |
255 | ASSERT(m_pageOverlays.contains(&overlay)); |
256 | auto* graphicsLayer = m_overlayGraphicsLayers.get(&overlay); |
257 | |
258 | if (!graphicsLayer->drawsContent()) { |
259 | graphicsLayer->setDrawsContent(true); |
260 | updateOverlayGeometry(overlay, *graphicsLayer); |
261 | } |
262 | |
263 | graphicsLayer->setNeedsDisplayInRect(dirtyRect); |
264 | } |
265 | |
266 | void PageOverlayController::setPageOverlayOpacity(PageOverlay& overlay, float opacity) |
267 | { |
268 | ASSERT(m_pageOverlays.contains(&overlay)); |
269 | m_overlayGraphicsLayers.get(&overlay)->setOpacity(opacity); |
270 | } |
271 | |
272 | void PageOverlayController::clearPageOverlay(PageOverlay& overlay) |
273 | { |
274 | ASSERT(m_pageOverlays.contains(&overlay)); |
275 | m_overlayGraphicsLayers.get(&overlay)->setDrawsContent(false); |
276 | } |
277 | |
278 | GraphicsLayer& PageOverlayController::layerForOverlay(PageOverlay& overlay) const |
279 | { |
280 | ASSERT(m_pageOverlays.contains(&overlay)); |
281 | return *m_overlayGraphicsLayers.get(&overlay); |
282 | } |
283 | |
284 | void PageOverlayController::didChangeViewSize() |
285 | { |
286 | for (auto& overlayAndLayer : m_overlayGraphicsLayers) { |
287 | if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View) |
288 | updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get()); |
289 | } |
290 | } |
291 | |
292 | void PageOverlayController::didChangeDocumentSize() |
293 | { |
294 | for (auto& overlayAndLayer : m_overlayGraphicsLayers) { |
295 | if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::Document) |
296 | updateOverlayGeometry(*overlayAndLayer.key, overlayAndLayer.value.get()); |
297 | } |
298 | } |
299 | |
300 | void PageOverlayController::didChangeSettings() |
301 | { |
302 | // FIXME: We should apply these settings to all overlay sublayers recursively. |
303 | for (auto& graphicsLayer : m_overlayGraphicsLayers.values()) |
304 | updateSettingsForLayer(graphicsLayer.get()); |
305 | } |
306 | |
307 | void PageOverlayController::didChangeDeviceScaleFactor() |
308 | { |
309 | if (!m_initialized) |
310 | return; |
311 | |
312 | m_documentOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants(); |
313 | m_viewOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants(); |
314 | |
315 | for (auto& graphicsLayer : m_overlayGraphicsLayers.values()) |
316 | graphicsLayer->setNeedsDisplay(); |
317 | } |
318 | |
319 | void PageOverlayController::didChangeViewExposedRect() |
320 | { |
321 | m_page.renderingUpdateScheduler().scheduleRenderingUpdate(); |
322 | } |
323 | |
324 | void PageOverlayController::didScrollFrame(Frame& frame) |
325 | { |
326 | for (auto& overlayAndLayer : m_overlayGraphicsLayers) { |
327 | if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View || !frame.isMainFrame()) |
328 | overlayAndLayer.value->setNeedsDisplay(); |
329 | overlayAndLayer.key->didScrollFrame(frame); |
330 | } |
331 | } |
332 | |
333 | void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer) |
334 | { |
335 | Settings& settings = m_page.settings(); |
336 | layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled()); |
337 | layer.setShowDebugBorder(settings.showDebugBorders()); |
338 | layer.setShowRepaintCounter(settings.showRepaintCounter()); |
339 | } |
340 | |
341 | bool PageOverlayController::handleMouseEvent(const PlatformMouseEvent& mouseEvent) |
342 | { |
343 | if (m_pageOverlays.isEmpty()) |
344 | return false; |
345 | |
346 | for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) { |
347 | if ((*it)->mouseEvent(mouseEvent)) |
348 | return true; |
349 | } |
350 | |
351 | return false; |
352 | } |
353 | |
354 | bool PageOverlayController::copyAccessibilityAttributeStringValueForPoint(String attribute, FloatPoint parameter, String& value) |
355 | { |
356 | if (m_pageOverlays.isEmpty()) |
357 | return false; |
358 | |
359 | for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) { |
360 | if ((*it)->copyAccessibilityAttributeStringValueForPoint(attribute, parameter, value)) |
361 | return true; |
362 | } |
363 | |
364 | return false; |
365 | } |
366 | |
367 | bool PageOverlayController::copyAccessibilityAttributeBoolValueForPoint(String attribute, FloatPoint parameter, bool& value) |
368 | { |
369 | if (m_pageOverlays.isEmpty()) |
370 | return false; |
371 | |
372 | for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) { |
373 | if ((*it)->copyAccessibilityAttributeBoolValueForPoint(attribute, parameter, value)) |
374 | return true; |
375 | } |
376 | |
377 | return false; |
378 | } |
379 | |
380 | Vector<String> PageOverlayController::copyAccessibilityAttributesNames(bool parameterizedNames) |
381 | { |
382 | if (m_pageOverlays.isEmpty()) |
383 | return { }; |
384 | |
385 | for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) { |
386 | Vector<String> names = (*it)->copyAccessibilityAttributeNames(parameterizedNames); |
387 | if (!names.isEmpty()) |
388 | return names; |
389 | } |
390 | |
391 | return { }; |
392 | } |
393 | |
394 | void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintBehavior) |
395 | { |
396 | for (auto& overlayAndGraphicsLayer : m_overlayGraphicsLayers) { |
397 | if (overlayAndGraphicsLayer.value.ptr() != graphicsLayer) |
398 | continue; |
399 | |
400 | GraphicsContextStateSaver stateSaver(graphicsContext); |
401 | graphicsContext.clip(clipRect); |
402 | overlayAndGraphicsLayer.key->drawRect(graphicsContext, enclosingIntRect(clipRect)); |
403 | |
404 | return; |
405 | } |
406 | } |
407 | |
408 | float PageOverlayController::deviceScaleFactor() const |
409 | { |
410 | return m_page.deviceScaleFactor(); |
411 | } |
412 | |
413 | void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*) |
414 | { |
415 | m_page.renderingUpdateScheduler().scheduleRenderingUpdate(); |
416 | } |
417 | |
418 | void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay) |
419 | { |
420 | ASSERT(m_pageOverlays.contains(&overlay)); |
421 | if (auto* layer = m_overlayGraphicsLayers.get(&overlay)) |
422 | updateOverlayGeometry(overlay, *layer); |
423 | } |
424 | |
425 | void PageOverlayController::didChangeOverlayBackgroundColor(PageOverlay& overlay) |
426 | { |
427 | ASSERT(m_pageOverlays.contains(&overlay)); |
428 | if (auto* layer = m_overlayGraphicsLayers.get(&overlay)) |
429 | layer->setBackgroundColor(overlay.backgroundColor()); |
430 | } |
431 | |
432 | bool PageOverlayController::shouldSkipLayerInDump(const GraphicsLayer*, LayerTreeAsTextBehavior behavior) const |
433 | { |
434 | return !(behavior & LayerTreeAsTextIncludePageOverlayLayers); |
435 | } |
436 | |
437 | void PageOverlayController::tiledBackingUsageChanged(const GraphicsLayer* graphicsLayer, bool usingTiledBacking) |
438 | { |
439 | if (usingTiledBacking) |
440 | graphicsLayer->tiledBacking()->setIsInWindow(m_page.isInWindow()); |
441 | } |
442 | |
443 | } // namespace WebKit |
444 | |