Comcast website displays bottom of page when loaded
[WebKit-https.git] / Source / WebCore / page / scrolling / ScrollingTree.cpp
1 /*
2  * Copyright (C) 2012 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 "ScrollingTree.h"
28
29 #if ENABLE(THREADED_SCROLLING)
30
31 #include "PlatformWheelEvent.h"
32 #include "ScrollingCoordinator.h"
33 #include "ScrollingThread.h"
34 #include "ScrollingTreeNode.h"
35 #include "ScrollingTreeState.h"
36 #include <wtf/MainThread.h>
37
38 namespace WebCore {
39
40 PassRefPtr<ScrollingTree> ScrollingTree::create(ScrollingCoordinator* scrollingCoordinator)
41 {
42     return adoptRef(new ScrollingTree(scrollingCoordinator));
43 }
44
45 ScrollingTree::ScrollingTree(ScrollingCoordinator* scrollingCoordinator)
46     : m_scrollingCoordinator(scrollingCoordinator)
47     , m_rootNode(ScrollingTreeNode::create(this))
48     , m_hasWheelEventHandlers(false)
49     , m_canGoBack(false)
50     , m_canGoForward(false)
51     , m_mainFramePinnedToTheLeft(false)
52     , m_mainFramePinnedToTheRight(false)
53 {
54 }
55
56 ScrollingTree::~ScrollingTree()
57 {
58     ASSERT(!m_scrollingCoordinator);
59 }
60
61 ScrollingTree::EventResult ScrollingTree::tryToHandleWheelEvent(const PlatformWheelEvent& wheelEvent)
62 {
63     {
64         MutexLocker lock(m_mutex);
65
66         if (m_hasWheelEventHandlers)
67             return SendToMainThread;
68
69         if (!m_nonFastScrollableRegion.isEmpty()) {
70             // FIXME: This is not correct for non-default scroll origins.
71             IntPoint position = wheelEvent.position();
72             position.moveBy(m_mainFrameScrollPosition);
73             if (m_nonFastScrollableRegion.contains(position))
74                 return SendToMainThread;
75         }
76     }
77
78     if (willWheelEventStartSwipeGesture(wheelEvent))
79         return DidNotHandleEvent;
80
81     ScrollingThread::dispatch(bind(&ScrollingTree::handleWheelEvent, this, wheelEvent));
82     return DidHandleEvent;
83 }
84
85 void ScrollingTree::updateBackForwardState(bool canGoBack, bool canGoForward)
86 {
87     MutexLocker locker(m_swipeStateMutex);
88
89     m_canGoBack = canGoBack;
90     m_canGoForward = canGoForward;
91 }
92
93 void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
94 {
95     ASSERT(ScrollingThread::isCurrentThread());
96
97     m_rootNode->handleWheelEvent(wheelEvent);
98 }
99
100 static void derefScrollingCoordinator(ScrollingCoordinator* scrollingCoordinator)
101 {
102     ASSERT(isMainThread());
103
104     scrollingCoordinator->deref();
105 }
106
107 void ScrollingTree::invalidate()
108 {
109     // Invalidate is dispatched by the ScrollingCoordinator class on the ScrollingThread
110     // to break the reference cycle between ScrollingTree and ScrollingCoordinator when the
111     // ScrollingCoordinator's page is destroyed.
112     ASSERT(ScrollingThread::isCurrentThread());
113
114     // Since this can potentially be the last reference to the scrolling coordinator,
115     // we need to release it on the main thread since it has member variables (such as timers)
116     // that expect to be destroyed from the main thread.
117     callOnMainThread(bind(derefScrollingCoordinator, m_scrollingCoordinator.release().leakRef()));
118 }
119
120 void ScrollingTree::commitNewTreeState(PassOwnPtr<ScrollingTreeState> scrollingTreeState)
121 {
122     ASSERT(ScrollingThread::isCurrentThread());
123
124     if (scrollingTreeState->changedProperties() & (ScrollingTreeState::WheelEventHandlerCount | ScrollingTreeState::NonFastScrollableRegion | ScrollingTreeState::ScrollLayer)) {
125         MutexLocker lock(m_mutex);
126
127         if (scrollingTreeState->changedProperties() & ScrollingTreeState::ScrollLayer)
128             m_mainFrameScrollPosition = IntPoint();
129         if (scrollingTreeState->changedProperties() & ScrollingTreeState::WheelEventHandlerCount)
130             m_hasWheelEventHandlers = scrollingTreeState->wheelEventHandlerCount();
131         if (scrollingTreeState->changedProperties() & ScrollingTreeState::NonFastScrollableRegion)
132             m_nonFastScrollableRegion = scrollingTreeState->nonFastScrollableRegion();
133     }
134
135     m_rootNode->update(scrollingTreeState.get());
136
137     updateDebugRootLayer();
138 }
139
140 void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight)
141 {
142     MutexLocker locker(m_swipeStateMutex);
143
144     m_mainFramePinnedToTheLeft = pinnedToTheLeft;
145     m_mainFramePinnedToTheRight = pinnedToTheRight;
146 }
147
148 void ScrollingTree::updateMainFrameScrollPosition(const IntPoint& scrollPosition)
149 {
150     if (!m_scrollingCoordinator)
151         return;
152
153     {
154         MutexLocker lock(m_mutex);
155         m_mainFrameScrollPosition = scrollPosition;
156     }
157
158     callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPosition, m_scrollingCoordinator.get(), scrollPosition));
159 }
160
161 IntPoint ScrollingTree::mainFrameScrollPosition()
162 {
163     MutexLocker lock(m_mutex);
164     return m_mainFrameScrollPosition;
165 }
166
167 void ScrollingTree::updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint& scrollPosition)
168 {
169     if (!m_scrollingCoordinator)
170         return;
171
172     {
173         MutexLocker lock(m_mutex);
174         m_mainFrameScrollPosition = scrollPosition;
175     }
176
177     callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPositionAndScrollLayerPosition, m_scrollingCoordinator.get()));
178 }
179
180 #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
181 void ScrollingTree::handleWheelEventPhase(PlatformWheelEventPhase phase)
182 {
183     if (!m_scrollingCoordinator)
184         return;
185
186     callOnMainThread(bind(&ScrollingCoordinator::handleWheelEventPhase, m_scrollingCoordinator.get(), phase));
187 }
188 #endif
189
190 bool ScrollingTree::canGoBack()
191 {
192     MutexLocker lock(m_swipeStateMutex);
193
194     return m_canGoBack;
195 }
196
197 bool ScrollingTree::canGoForward()
198 {
199     MutexLocker lock(m_swipeStateMutex);
200
201     return m_canGoForward;
202 }
203
204 bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wheelEvent)
205 {
206     if (wheelEvent.phase() != PlatformWheelEventPhaseBegan)
207         return false;
208     if (!wheelEvent.deltaX())
209         return false;
210
211     MutexLocker lock(m_swipeStateMutex);
212
213     if (wheelEvent.deltaX() > 0 && m_mainFramePinnedToTheLeft && m_canGoBack)
214         return true;
215     if (wheelEvent.deltaX() < 0 && m_mainFramePinnedToTheRight && m_canGoForward)
216         return true;
217
218     return false;
219 }
220
221 } // namespace WebCore
222
223 #endif // ENABLE(THREADED_SCROLLING)