1 /*
2  * Copyright (c) 2010, Google Inc. All rights reserved.
3  * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "config.h"
33 #include "ScrollableArea.h"
34 
35 #include "GraphicsContext.h"
36 #include "GraphicsLayer.h"
37 #include "FloatPoint.h"
38 #include "PlatformWheelEvent.h"
39 #include "ScrollAnimator.h"
40 #include "ScrollbarTheme.h"
41 #include <wtf/PassOwnPtr.h>
42 
43 namespace WebCore {
44 
ScrollableArea()45 ScrollableArea::ScrollableArea()
46     : m_scrollAnimator(ScrollAnimator::create(this))
47     , m_constrainsScrollingToContentEdge(true)
48     , m_inLiveResize(false)
49     , m_verticalScrollElasticity(ScrollElasticityNone)
50     , m_horizontalScrollElasticity(ScrollElasticityNone)
51 {
52 }
53 
~ScrollableArea()54 ScrollableArea::~ScrollableArea()
55 {
56 }
57 
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)58 bool ScrollableArea::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
59 {
60     ScrollbarOrientation orientation;
61     Scrollbar* scrollbar;
62     if (direction == ScrollUp || direction == ScrollDown) {
63         orientation = VerticalScrollbar;
64         scrollbar = verticalScrollbar();
65     } else {
66         orientation = HorizontalScrollbar;
67         scrollbar = horizontalScrollbar();
68     }
69 
70     if (!scrollbar)
71         return false;
72 
73     float step = 0;
74     switch (granularity) {
75     case ScrollByLine:
76         step = scrollbar->lineStep();
77         break;
78     case ScrollByPage:
79         step = scrollbar->pageStep();
80         break;
81     case ScrollByDocument:
82         step = scrollbar->totalSize();
83         break;
84     case ScrollByPixel:
85         step = scrollbar->pixelStep();
86         break;
87     }
88 
89     if (direction == ScrollUp || direction == ScrollLeft)
90         multiplier = -multiplier;
91 
92     return m_scrollAnimator->scroll(orientation, granularity, step, multiplier);
93 }
94 
scrollToOffsetWithoutAnimation(const FloatPoint & offset)95 void ScrollableArea::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
96 {
97     m_scrollAnimator->scrollToOffsetWithoutAnimation(offset);
98 }
99 
scrollToOffsetWithoutAnimation(ScrollbarOrientation orientation,float offset)100 void ScrollableArea::scrollToOffsetWithoutAnimation(ScrollbarOrientation orientation, float offset)
101 {
102     if (orientation == HorizontalScrollbar)
103         scrollToXOffsetWithoutAnimation(offset);
104     else
105         scrollToYOffsetWithoutAnimation(offset);
106 }
107 
scrollToXOffsetWithoutAnimation(float x)108 void ScrollableArea::scrollToXOffsetWithoutAnimation(float x)
109 {
110     scrollToOffsetWithoutAnimation(FloatPoint(x, m_scrollAnimator->currentPosition().y()));
111 }
112 
scrollToYOffsetWithoutAnimation(float y)113 void ScrollableArea::scrollToYOffsetWithoutAnimation(float y)
114 {
115     scrollToOffsetWithoutAnimation(FloatPoint(m_scrollAnimator->currentPosition().x(), y));
116 }
117 
handleWheelEvent(PlatformWheelEvent & wheelEvent)118 void ScrollableArea::handleWheelEvent(PlatformWheelEvent& wheelEvent)
119 {
120     m_scrollAnimator->handleWheelEvent(wheelEvent);
121 }
122 
123 #if ENABLE(GESTURE_EVENTS)
handleGestureEvent(const PlatformGestureEvent & gestureEvent)124 void ScrollableArea::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
125 {
126     m_scrollAnimator->handleGestureEvent(gestureEvent);
127 }
128 #endif
129 
setScrollOffsetFromAnimation(const IntPoint & offset)130 void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset)
131 {
132     // Tell the derived class to scroll its contents.
133     setScrollOffset(offset);
134 
135     Scrollbar* verticalScrollbar = this->verticalScrollbar();
136 
137     // Tell the scrollbars to update their thumb postions.
138     if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
139         horizontalScrollbar->offsetDidChange();
140         if (horizontalScrollbar->isOverlayScrollbar()) {
141             if (!verticalScrollbar)
142                 horizontalScrollbar->invalidate();
143             else {
144                 // If there is both a horizontalScrollbar and a verticalScrollbar,
145                 // then we must also invalidate the corner between them.
146                 IntRect boundsAndCorner = horizontalScrollbar->boundsRect();
147                 boundsAndCorner.setWidth(boundsAndCorner.width() + verticalScrollbar->width());
148                 horizontalScrollbar->invalidateRect(boundsAndCorner);
149             }
150         }
151     }
152     if (verticalScrollbar) {
153         verticalScrollbar->offsetDidChange();
154         if (verticalScrollbar->isOverlayScrollbar())
155             verticalScrollbar->invalidate();
156     }
157 }
158 
willStartLiveResize()159 void ScrollableArea::willStartLiveResize()
160 {
161     if (m_inLiveResize)
162         return;
163     m_inLiveResize = true;
164     scrollAnimator()->willStartLiveResize();
165 }
166 
willEndLiveResize()167 void ScrollableArea::willEndLiveResize()
168 {
169     if (!m_inLiveResize)
170         return;
171     m_inLiveResize = false;
172     scrollAnimator()->willEndLiveResize();
173 }
174 
didAddVerticalScrollbar(Scrollbar * scrollbar)175 void ScrollableArea::didAddVerticalScrollbar(Scrollbar* scrollbar)
176 {
177     scrollAnimator()->didAddVerticalScrollbar(scrollbar);
178 }
179 
willRemoveVerticalScrollbar(Scrollbar * scrollbar)180 void ScrollableArea::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
181 {
182     scrollAnimator()->willRemoveVerticalScrollbar(scrollbar);
183 }
184 
didAddHorizontalScrollbar(Scrollbar * scrollbar)185 void ScrollableArea::didAddHorizontalScrollbar(Scrollbar* scrollbar)
186 {
187     scrollAnimator()->didAddHorizontalScrollbar(scrollbar);
188 }
189 
willRemoveHorizontalScrollbar(Scrollbar * scrollbar)190 void ScrollableArea::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
191 {
192     scrollAnimator()->willRemoveHorizontalScrollbar(scrollbar);
193 }
194 
hasOverlayScrollbars() const195 bool ScrollableArea::hasOverlayScrollbars() const
196 {
197     return (verticalScrollbar() && verticalScrollbar()->isOverlayScrollbar())
198         || (horizontalScrollbar() && horizontalScrollbar()->isOverlayScrollbar());
199 }
200 
invalidateScrollbar(Scrollbar * scrollbar,const IntRect & rect)201 void ScrollableArea::invalidateScrollbar(Scrollbar* scrollbar, const IntRect& rect)
202 {
203 #if USE(ACCELERATED_COMPOSITING)
204     if (scrollbar == horizontalScrollbar()) {
205         if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) {
206             graphicsLayer->setNeedsDisplay();
207             return;
208         }
209     } else if (scrollbar == verticalScrollbar()) {
210         if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) {
211             graphicsLayer->setNeedsDisplay();
212             return;
213         }
214     }
215 #endif
216     invalidateScrollbarRect(scrollbar, rect);
217 }
218 
invalidateScrollCorner()219 void ScrollableArea::invalidateScrollCorner()
220 {
221 #if USE(ACCELERATED_COMPOSITING)
222     if (GraphicsLayer* graphicsLayer = layerForScrollCorner()) {
223         graphicsLayer->setNeedsDisplay();
224         return;
225     }
226 #endif
227     invalidateScrollCornerRect(scrollCornerRect());
228 }
229 
hasLayerForHorizontalScrollbar() const230 bool ScrollableArea::hasLayerForHorizontalScrollbar() const
231 {
232 #if USE(ACCELERATED_COMPOSITING)
233     return layerForHorizontalScrollbar();
234 #else
235     return false;
236 #endif
237 }
238 
hasLayerForVerticalScrollbar() const239 bool ScrollableArea::hasLayerForVerticalScrollbar() const
240 {
241 #if USE(ACCELERATED_COMPOSITING)
242     return layerForVerticalScrollbar();
243 #else
244     return false;
245 #endif
246 }
247 
hasLayerForScrollCorner() const248 bool ScrollableArea::hasLayerForScrollCorner() const
249 {
250 #if USE(ACCELERATED_COMPOSITING)
251     return layerForScrollCorner();
252 #else
253     return false;
254 #endif
255 }
256 
257 } // namespace WebCore
258