1/*
2 * Copyright (C) 2014 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 "DrawingArea.h"
30#include "PageOverlay.h"
31#include "WebPage.h"
32#include <WebCore/Frame.h>
33#include <WebCore/FrameView.h>
34#include <WebCore/GraphicsContext.h>
35#include <WebCore/GraphicsLayer.h>
36#include <WebCore/MainFrame.h>
37#include <WebCore/ScrollingCoordinator.h>
38#include <WebCore/Settings.h>
39#include <WebCore/TiledBacking.h>
40
41using namespace WebCore;
42
43namespace WebKit {
44
45PageOverlayController::PageOverlayController(WebPage& webPage)
46    : m_webPage(webPage)
47{
48}
49
50void PageOverlayController::initialize()
51{
52    ASSERT(!m_documentOverlayRootLayer);
53    ASSERT(!m_viewOverlayRootLayer);
54
55    m_documentOverlayRootLayer = GraphicsLayer::create(m_webPage.drawingArea()->graphicsLayerFactory(), *this);
56    m_viewOverlayRootLayer = GraphicsLayer::create(m_webPage.drawingArea()->graphicsLayerFactory(), *this);
57#ifndef NDEBUG
58    m_documentOverlayRootLayer->setName("Page Overlay container (document-relative)");
59    m_viewOverlayRootLayer->setName("Page Overlay container (view-relative)");
60#endif
61}
62
63static void updateOverlayGeometry(PageOverlay& overlay, GraphicsLayer& graphicsLayer)
64{
65    IntRect overlayFrame = overlay.frame();
66
67    if (overlayFrame.location() == graphicsLayer.position() && overlayFrame.size() == graphicsLayer.size())
68        return;
69
70    graphicsLayer.setPosition(overlayFrame.location());
71    graphicsLayer.setSize(overlayFrame.size());
72}
73
74void PageOverlayController::installPageOverlay(PassRefPtr<PageOverlay> pageOverlay, PageOverlay::FadeMode fadeMode)
75{
76    ASSERT(m_documentOverlayRootLayer);
77    ASSERT(m_viewOverlayRootLayer);
78
79    RefPtr<PageOverlay> overlay = pageOverlay;
80
81    if (m_pageOverlays.contains(overlay))
82        return;
83
84    m_pageOverlays.append(overlay);
85    overlay->setPage(&m_webPage);
86
87    if (fadeMode == PageOverlay::FadeMode::Fade)
88        overlay->startFadeInAnimation();
89
90    std::unique_ptr<GraphicsLayer> layer = GraphicsLayer::create(m_webPage.drawingArea()->graphicsLayerFactory(), *this);
91    layer->setAnchorPoint(FloatPoint3D());
92    layer->setBackgroundColor(overlay->backgroundColor());
93    updateOverlayGeometry(*overlay, *layer);
94#ifndef NDEBUG
95    layer->setName("Page Overlay content");
96#endif
97
98    updateSettingsForLayer(*layer);
99
100    switch (overlay->overlayType()) {
101    case PageOverlay::OverlayType::View:
102        m_viewOverlayRootLayer->addChild(layer.get());
103        break;
104    case PageOverlay::OverlayType::Document:
105        m_documentOverlayRootLayer->addChild(layer.get());
106        break;
107    }
108
109    m_overlayGraphicsLayers.set(overlay.get(), WTF::move(layer));
110
111    updateForceSynchronousScrollLayerPositionUpdates();
112}
113
114void PageOverlayController::uninstallPageOverlay(PageOverlay* overlay, PageOverlay::FadeMode fadeMode)
115{
116    if (fadeMode == PageOverlay::FadeMode::Fade) {
117        overlay->startFadeOutAnimation();
118        return;
119    }
120
121    overlay->setPage(nullptr);
122
123    m_overlayGraphicsLayers.take(overlay)->removeFromParent();
124
125    size_t overlayIndex = m_pageOverlays.find(overlay);
126    ASSERT(overlayIndex != notFound);
127    m_pageOverlays.remove(overlayIndex);
128
129    updateForceSynchronousScrollLayerPositionUpdates();
130}
131
132void PageOverlayController::updateForceSynchronousScrollLayerPositionUpdates()
133{
134#if ENABLE(ASYNC_SCROLLING)
135    bool forceSynchronousScrollLayerPositionUpdates = false;
136
137    for (auto& overlay : m_pageOverlays) {
138        if (overlay->overlayType() == PageOverlay::OverlayType::View)
139            forceSynchronousScrollLayerPositionUpdates = true;
140    }
141
142    if (Page* page = m_webPage.corePage()) {
143        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
144            scrollingCoordinator->setForceSynchronousScrollLayerPositionUpdates(forceSynchronousScrollLayerPositionUpdates);
145    }
146#endif
147}
148
149void PageOverlayController::setPageOverlayNeedsDisplay(PageOverlay& overlay, const WebCore::IntRect& dirtyRect)
150{
151    ASSERT(m_pageOverlays.contains(&overlay));
152    GraphicsLayer& graphicsLayer = *m_overlayGraphicsLayers.get(&overlay);
153
154    if (!graphicsLayer.drawsContent()) {
155        graphicsLayer.setDrawsContent(true);
156        updateOverlayGeometry(overlay, graphicsLayer);
157    }
158
159    graphicsLayer.setNeedsDisplayInRect(dirtyRect);
160}
161
162void PageOverlayController::setPageOverlayOpacity(PageOverlay& overlay, float opacity)
163{
164    ASSERT(m_pageOverlays.contains(&overlay));
165    m_overlayGraphicsLayers.get(&overlay)->setOpacity(opacity);
166}
167
168void PageOverlayController::clearPageOverlay(PageOverlay& overlay)
169{
170    ASSERT(m_pageOverlays.contains(&overlay));
171    m_overlayGraphicsLayers.get(&overlay)->setDrawsContent(false);
172}
173
174GraphicsLayer* PageOverlayController::layerForOverlay(PageOverlay& overlay) const
175{
176    ASSERT(m_pageOverlays.contains(&overlay));
177    return m_overlayGraphicsLayers.get(&overlay);
178}
179
180void PageOverlayController::didChangeViewSize()
181{
182    for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
183        if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View)
184            updateOverlayGeometry(*overlayAndLayer.key, *overlayAndLayer.value);
185    }
186}
187
188void PageOverlayController::didChangeDocumentSize()
189{
190    for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
191        if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::Document)
192            updateOverlayGeometry(*overlayAndLayer.key, *overlayAndLayer.value);
193    }
194}
195
196void PageOverlayController::didChangePreferences()
197{
198    for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
199        updateSettingsForLayer(*graphicsLayer);
200}
201
202void PageOverlayController::didChangeDeviceScaleFactor()
203{
204    m_documentOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
205    m_viewOverlayRootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
206
207    for (auto& graphicsLayer : m_overlayGraphicsLayers.values())
208        graphicsLayer->setNeedsDisplay();
209}
210
211void PageOverlayController::didChangeExposedRect()
212{
213    m_webPage.drawingArea()->scheduleCompositingLayerFlush();
214}
215
216void PageOverlayController::didScrollFrame(Frame* frame)
217{
218    for (auto& overlayAndLayer : m_overlayGraphicsLayers) {
219        if (overlayAndLayer.key->overlayType() == PageOverlay::OverlayType::View || !frame->isMainFrame())
220            overlayAndLayer.value->setNeedsDisplay();
221        overlayAndLayer.key->didScrollFrame(frame);
222    }
223}
224
225void PageOverlayController::flushPageOverlayLayers(FloatRect visibleRect)
226{
227    m_viewOverlayRootLayer->flushCompositingState(visibleRect);
228}
229
230void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer)
231{
232    Settings& settings = m_webPage.corePage()->settings();
233    layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled());
234    layer.setShowDebugBorder(settings.showDebugBorders());
235    layer.setShowRepaintCounter(settings.showRepaintCounter());
236}
237
238bool PageOverlayController::handleMouseEvent(const WebMouseEvent& mouseEvent)
239{
240    if (!m_pageOverlays.size())
241        return false;
242
243    for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
244        if ((*it)->mouseEvent(mouseEvent))
245            return true;
246    }
247
248    return false;
249}
250
251WKTypeRef PageOverlayController::copyAccessibilityAttributeValue(WKStringRef attribute, WKTypeRef parameter)
252{
253    if (!m_pageOverlays.size())
254        return nullptr;
255
256    for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
257        if (WKTypeRef value = (*it)->copyAccessibilityAttributeValue(attribute, parameter))
258            return value;
259    }
260
261    return nullptr;
262}
263
264WKArrayRef PageOverlayController::copyAccessibilityAttributesNames(bool parameterizedNames)
265{
266    if (!m_pageOverlays.size())
267        return nullptr;
268
269    for (auto it = m_pageOverlays.rbegin(), end = m_pageOverlays.rend(); it != end; ++it) {
270        if (WKArrayRef value = (*it)->copyAccessibilityAttributeNames(parameterizedNames))
271            return value;
272    }
273
274    return nullptr;
275}
276
277void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect)
278{
279    for (auto it = m_overlayGraphicsLayers.begin(), end = m_overlayGraphicsLayers.end(); it != end; ++it) {
280        if (it->value.get() != graphicsLayer)
281            continue;
282
283        GraphicsContextStateSaver stateSaver(graphicsContext);
284        graphicsContext.clip(clipRect);
285        it->key->drawRect(graphicsContext, enclosingIntRect(clipRect));
286
287        return;
288    }
289}
290
291float PageOverlayController::deviceScaleFactor() const
292{
293    return m_webPage.corePage()->deviceScaleFactor();
294}
295
296void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*)
297{
298    if (m_webPage.drawingArea())
299        m_webPage.drawingArea()->scheduleCompositingLayerFlush();
300}
301
302void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay)
303{
304    ASSERT(m_pageOverlays.contains(&overlay));
305    updateOverlayGeometry(overlay, *m_overlayGraphicsLayers.get(&overlay));
306}
307
308void PageOverlayController::didChangeOverlayBackgroundColor(PageOverlay& overlay)
309{
310    ASSERT(m_pageOverlays.contains(&overlay));
311    m_overlayGraphicsLayers.get(&overlay)->setBackgroundColor(overlay.backgroundColor());
312}
313
314} // namespace WebKit
315