Disable outdated WritableStream API
[WebKit-https.git] / Source / WebCore / page / AutoscrollController.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4  * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "AutoscrollController.h"
30
31 #include "EventHandler.h"
32 #include "FrameView.h"
33 #include "HitTestResult.h"
34 #include "MainFrame.h"
35 #include "Page.h"
36 #include "RenderBox.h"
37 #include "RenderView.h"
38 #include "ScrollView.h"
39 #include "Settings.h"
40 #include <wtf/CurrentTime.h>
41
42 namespace WebCore {
43
44 // Delay time in second for start autoscroll if pointer is in border edge of scrollable element.
45 static const double autoscrollDelay = 0.2;
46
47 // When the autoscroll or the panScroll is triggered when do the scroll every 50ms to make it smooth.
48 static const Seconds autoscrollInterval { 50_ms };
49
50 #if ENABLE(PAN_SCROLLING)
51 static Frame* getMainFrame(Frame* frame)
52 {
53     Page* page = frame->page();
54     return page ? &page->mainFrame() : 0;
55 }
56 #endif
57
58 AutoscrollController::AutoscrollController()
59     : m_autoscrollTimer(*this, &AutoscrollController::autoscrollTimerFired)
60     , m_autoscrollRenderer(nullptr)
61     , m_autoscrollType(NoAutoscroll)
62     , m_dragAndDropAutoscrollStartTime(0)
63 {
64 }
65
66 RenderBox* AutoscrollController::autoscrollRenderer() const
67 {
68     return m_autoscrollRenderer;
69 }
70
71 bool AutoscrollController::autoscrollInProgress() const
72 {
73     return m_autoscrollType == AutoscrollForSelection;
74 }
75
76 void AutoscrollController::startAutoscrollForSelection(RenderObject* renderer)
77 {
78     // We don't want to trigger the autoscroll or the panScroll if it's already active
79     if (m_autoscrollTimer.isActive())
80         return;
81     RenderBox* scrollable = RenderBox::findAutoscrollable(renderer);
82     if (!scrollable)
83         return;
84     m_autoscrollType = AutoscrollForSelection;
85     m_autoscrollRenderer = scrollable;
86     startAutoscrollTimer();
87 }
88
89 void AutoscrollController::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
90 {
91     RenderBox* scrollable = m_autoscrollRenderer;
92     m_autoscrollTimer.stop();
93     m_autoscrollRenderer = nullptr;
94
95     if (!scrollable)
96         return;
97
98     Frame& frame = scrollable->frame();
99     if (autoscrollInProgress() && frame.eventHandler().mouseDownWasInSubframe()) {
100         if (Frame* subframe = frame.eventHandler().subframeForTargetNode(frame.eventHandler().mousePressNode()))
101             subframe->eventHandler().stopAutoscrollTimer(rendererIsBeingDestroyed);
102         return;
103     }
104
105     if (!rendererIsBeingDestroyed)
106         scrollable->stopAutoscroll();
107 #if ENABLE(PAN_SCROLLING)
108     if (panScrollInProgress()) {
109         FrameView& frameView = scrollable->view().frameView();
110         frameView.removePanScrollIcon();
111         frameView.setCursor(pointerCursor());
112     }
113 #endif
114
115     m_autoscrollType = NoAutoscroll;
116
117 #if ENABLE(PAN_SCROLLING)
118     // If we're not in the top frame we notify it that we are not doing a panScroll any more.
119     if (!frame.isMainFrame())
120         frame.mainFrame().eventHandler().didPanScrollStop();
121 #endif
122 }
123
124 void AutoscrollController::updateAutoscrollRenderer()
125 {
126     if (!m_autoscrollRenderer)
127         return;
128
129     RenderObject* renderer = m_autoscrollRenderer;
130
131 #if ENABLE(PAN_SCROLLING)
132     HitTestResult hitTest = m_autoscrollRenderer->frame().eventHandler().hitTestResultAtPoint(m_panScrollStartPos, HitTestRequest::ReadOnly | HitTestRequest::Active);
133
134     if (Node* nodeAtPoint = hitTest.innerNode())
135         renderer = nodeAtPoint->renderer();
136 #endif
137
138     while (renderer && !(is<RenderBox>(*renderer) && downcast<RenderBox>(*renderer).canAutoscroll()))
139         renderer = renderer->parent();
140     m_autoscrollRenderer = is<RenderBox>(renderer) ? downcast<RenderBox>(renderer) : nullptr;
141 }
142
143 void AutoscrollController::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime)
144 {
145     if (!dropTargetNode) {
146         stopAutoscrollTimer();
147         return;
148     }
149
150     RenderBox* scrollable = RenderBox::findAutoscrollable(dropTargetNode->renderer());
151     if (!scrollable) {
152         stopAutoscrollTimer();
153         return;
154     }
155
156     Frame& frame = scrollable->frame();
157
158     Page* page = frame.page();
159     if (!page || !page->settings().autoscrollForDragAndDropEnabled()) {
160         stopAutoscrollTimer();
161         return;
162     }
163
164     IntSize offset = scrollable->calculateAutoscrollDirection(eventPosition);
165     if (offset.isZero()) {
166         stopAutoscrollTimer();
167         return;
168     }
169
170     m_dragAndDropAutoscrollReferencePosition = eventPosition + offset;
171
172     if (m_autoscrollType == NoAutoscroll) {
173         m_autoscrollType = AutoscrollForDragAndDrop;
174         m_autoscrollRenderer = scrollable;
175         m_dragAndDropAutoscrollStartTime = eventTime;
176         startAutoscrollTimer();
177     } else if (m_autoscrollRenderer != scrollable) {
178         m_dragAndDropAutoscrollStartTime = eventTime;
179         m_autoscrollRenderer = scrollable;
180     }
181 }
182
183 #if ENABLE(PAN_SCROLLING)
184 void AutoscrollController::didPanScrollStart()
185 {
186     m_autoscrollType = AutoscrollForPan;
187 }
188
189 void AutoscrollController::didPanScrollStop()
190 {
191     m_autoscrollType = NoAutoscroll;
192 }
193
194 void AutoscrollController::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
195 {
196     switch (m_autoscrollType) {
197     case AutoscrollForPan:
198         if (mouseEvent.button() == MiddleButton)
199             m_autoscrollType = AutoscrollForPanCanStop;
200         break;
201     case AutoscrollForPanCanStop:
202         stopAutoscrollTimer();
203         break;
204     }
205 }
206
207 bool AutoscrollController::panScrollInProgress() const
208 {
209     return m_autoscrollType == AutoscrollForPan || m_autoscrollType == AutoscrollForPanCanStop;
210 }
211
212 void AutoscrollController::startPanScrolling(RenderBox* scrollable, const IntPoint& lastKnownMousePosition)
213 {
214     // We don't want to trigger the autoscroll or the panScroll if it's already active
215     if (m_autoscrollTimer.isActive())
216         return;
217
218     m_autoscrollType = AutoscrollForPan;
219     m_autoscrollRenderer = scrollable;
220     m_panScrollStartPos = lastKnownMousePosition;
221
222     if (FrameView* view = scrollable->frame().view())
223         view->addPanScrollIcon(lastKnownMousePosition);
224     scrollable->frame().eventHandler().didPanScrollStart();
225     startAutoscrollTimer();
226 }
227 #else
228 bool AutoscrollController::panScrollInProgress() const
229 {
230     return false;
231 }
232 #endif
233
234 void AutoscrollController::autoscrollTimerFired()
235 {
236     if (!m_autoscrollRenderer) {
237         stopAutoscrollTimer();
238         return;
239     }
240
241     Frame& frame = m_autoscrollRenderer->frame();
242     switch (m_autoscrollType) {
243     case AutoscrollForDragAndDrop:
244         if (WTF::currentTime() - m_dragAndDropAutoscrollStartTime > autoscrollDelay)
245             m_autoscrollRenderer->autoscroll(m_dragAndDropAutoscrollReferencePosition);
246         break;
247     case AutoscrollForSelection: {
248         if (!frame.eventHandler().mousePressed()) {
249             stopAutoscrollTimer();
250             return;
251         }
252 #if ENABLE(DRAG_SUPPORT)
253         frame.eventHandler().updateSelectionForMouseDrag();
254 #endif
255         m_autoscrollRenderer->autoscroll(frame.eventHandler().effectiveMousePositionForSelectionAutoscroll());
256         break;
257     }
258     case NoAutoscroll:
259         break;
260 #if ENABLE(PAN_SCROLLING)
261     case AutoscrollForPanCanStop:
262     case AutoscrollForPan:
263         // we verify that the main frame hasn't received the order to stop the panScroll
264         if (Frame* mainFrame = getMainFrame(&frame)) {
265             if (!mainFrame->eventHandler().panScrollInProgress()) {
266                 stopAutoscrollTimer();
267                 return;
268             }
269         }
270         if (FrameView* view = frame.view())
271             updatePanScrollState(view, frame.eventHandler().lastKnownMousePosition());
272         m_autoscrollRenderer->panScroll(m_panScrollStartPos);
273         break;
274 #endif
275     }
276 }
277
278 void AutoscrollController::startAutoscrollTimer()
279 {
280     m_autoscrollTimer.startRepeating(autoscrollInterval);
281 }
282
283 #if ENABLE(PAN_SCROLLING)
284 void AutoscrollController::updatePanScrollState(FrameView* view, const IntPoint& lastKnownMousePosition)
285 {
286     // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
287     // So we don't want to change the cursor over this area
288     bool east = m_panScrollStartPos.x() < (lastKnownMousePosition.x() - ScrollView::noPanScrollRadius);
289     bool west = m_panScrollStartPos.x() > (lastKnownMousePosition.x() + ScrollView::noPanScrollRadius);
290     bool north = m_panScrollStartPos.y() > (lastKnownMousePosition.y() + ScrollView::noPanScrollRadius);
291     bool south = m_panScrollStartPos.y() < (lastKnownMousePosition.y() - ScrollView::noPanScrollRadius);
292
293     if (m_autoscrollType == AutoscrollForPan && (east || west || north || south))
294         m_autoscrollType = AutoscrollForPanCanStop;
295
296     if (north) {
297         if (east)
298             view->setCursor(northEastPanningCursor());
299         else if (west)
300             view->setCursor(northWestPanningCursor());
301         else
302             view->setCursor(northPanningCursor());
303     } else if (south) {
304         if (east)
305             view->setCursor(southEastPanningCursor());
306         else if (west)
307             view->setCursor(southWestPanningCursor());
308         else
309             view->setCursor(southPanningCursor());
310     } else if (east)
311         view->setCursor(eastPanningCursor());
312     else if (west)
313         view->setCursor(westPanningCursor());
314     else
315         view->setCursor(middlePanningCursor());
316 }
317 #endif
318
319 } // namespace WebCore