Unreviewed, rolling out r126169.
[WebKit-https.git] / Source / WebCore / platform / ScrollableArea.cpp
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
45 struct SameSizeAsScrollableArea {
46     virtual ~SameSizeAsScrollableArea();
47     void* pointer;
48     unsigned bitfields : 16;
49     IntPoint origin;
50 };
51
52 COMPILE_ASSERT(sizeof(ScrollableArea) == sizeof(SameSizeAsScrollableArea), ScrollableArea_should_stay_small);
53
54 ScrollableArea::ScrollableArea()
55     : m_constrainsScrollingToContentEdge(true)
56     , m_inLiveResize(false)
57     , m_verticalScrollElasticity(ScrollElasticityNone)
58     , m_horizontalScrollElasticity(ScrollElasticityNone)
59     , m_scrollbarOverlayStyle(ScrollbarOverlayStyleDefault)
60     , m_scrollOriginChanged(false)
61 {
62 }
63
64 ScrollableArea::~ScrollableArea()
65 {
66 }
67
68 ScrollAnimator* ScrollableArea::scrollAnimator() const
69 {
70     if (!m_scrollAnimator)
71         m_scrollAnimator = ScrollAnimator::create(const_cast<ScrollableArea*>(this));
72
73     return m_scrollAnimator.get();
74 }
75
76 void ScrollableArea::setScrollOrigin(const IntPoint& origin)
77 {
78     if (m_scrollOrigin != origin) {
79         m_scrollOrigin = origin;
80         m_scrollOriginChanged = true;
81     }
82 }
83
84 bool ScrollableArea::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
85 {
86     ScrollbarOrientation orientation;
87     Scrollbar* scrollbar;
88     if (direction == ScrollUp || direction == ScrollDown) {
89         orientation = VerticalScrollbar;
90         scrollbar = verticalScrollbar();
91     } else {
92         orientation = HorizontalScrollbar;
93         scrollbar = horizontalScrollbar();
94     }
95
96     if (!scrollbar)
97         return false;
98
99     float step = 0;
100     switch (granularity) {
101     case ScrollByLine:
102         step = scrollbar->lineStep();
103         break;
104     case ScrollByPage:
105         step = scrollbar->pageStep();
106         break;
107     case ScrollByDocument:
108         step = scrollbar->totalSize();
109         break;
110     case ScrollByPixel:
111     case ScrollByPrecisePixel:
112         step = scrollbar->pixelStep();
113         break;
114     case ScrollByPixelVelocity:
115         break;
116     }
117
118     if (granularity != ScrollByPixelVelocity && (direction == ScrollUp || direction == ScrollLeft))
119         multiplier = -multiplier;
120
121     return scrollAnimator()->scroll(orientation, granularity, step, multiplier);
122 }
123
124 void ScrollableArea::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
125 {
126     scrollAnimator()->scrollToOffsetWithoutAnimation(offset);
127 }
128
129 void ScrollableArea::scrollToOffsetWithoutAnimation(ScrollbarOrientation orientation, float offset)
130 {
131     if (orientation == HorizontalScrollbar)
132         scrollToOffsetWithoutAnimation(FloatPoint(offset, scrollAnimator()->currentPosition().y()));
133     else
134         scrollToOffsetWithoutAnimation(FloatPoint(scrollAnimator()->currentPosition().x(), offset));
135 }
136
137 void ScrollableArea::notifyScrollPositionChanged(const IntPoint& position)
138 {
139     scrollPositionChanged(position);
140     scrollAnimator()->setCurrentPosition(position);
141 }
142
143 void ScrollableArea::scrollPositionChanged(const IntPoint& position)
144 {
145     IntPoint oldPosition = scrollPosition();
146     // Tell the derived class to scroll its contents.
147     setScrollOffset(position);
148
149     Scrollbar* verticalScrollbar = this->verticalScrollbar();
150
151     // Tell the scrollbars to update their thumb postions.
152     if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
153         horizontalScrollbar->offsetDidChange();
154         if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalScrollbar()) {
155             if (!verticalScrollbar)
156                 horizontalScrollbar->invalidate();
157             else {
158                 // If there is both a horizontalScrollbar and a verticalScrollbar,
159                 // then we must also invalidate the corner between them.
160                 IntRect boundsAndCorner = horizontalScrollbar->boundsRect();
161                 boundsAndCorner.setWidth(boundsAndCorner.width() + verticalScrollbar->width());
162                 horizontalScrollbar->invalidateRect(boundsAndCorner);
163             }
164         }
165     }
166     if (verticalScrollbar) {
167         verticalScrollbar->offsetDidChange();
168         if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrollbar())
169             verticalScrollbar->invalidate();
170     }
171
172     if (scrollPosition() != oldPosition)
173         scrollAnimator()->notifyContentAreaScrolled();
174 }
175
176 bool ScrollableArea::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
177 {
178     return scrollAnimator()->handleWheelEvent(wheelEvent);
179 }
180
181 // NOTE: Only called from Internals for testing.
182 void ScrollableArea::setScrollOffsetFromInternals(const IntPoint& offset)
183 {
184     setScrollOffsetFromAnimation(offset);
185 }
186
187 void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset)
188 {
189     if (requestScrollPositionUpdate(offset))
190         return;
191
192     scrollPositionChanged(offset);
193 }
194
195 void ScrollableArea::willStartLiveResize()
196 {
197     if (m_inLiveResize)
198         return;
199     m_inLiveResize = true;
200     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
201         scrollAnimator->willStartLiveResize();
202 }
203
204 void ScrollableArea::willEndLiveResize()
205 {
206     if (!m_inLiveResize)
207         return;
208     m_inLiveResize = false;
209     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
210         scrollAnimator->willEndLiveResize();
211 }    
212
213 void ScrollableArea::contentAreaWillPaint() const
214 {
215     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
216         scrollAnimator->contentAreaWillPaint();
217 }
218
219 void ScrollableArea::mouseEnteredContentArea() const
220 {
221     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
222         scrollAnimator->mouseEnteredContentArea();
223 }
224
225 void ScrollableArea::mouseExitedContentArea() const
226 {
227     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
228         scrollAnimator->mouseEnteredContentArea();
229 }
230
231 void ScrollableArea::mouseMovedInContentArea() const
232 {
233     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
234         scrollAnimator->mouseMovedInContentArea();
235 }
236
237 void ScrollableArea::mouseEnteredScrollbar(Scrollbar* scrollbar) const
238 {
239     scrollAnimator()->mouseEnteredScrollbar(scrollbar);
240 }
241
242 void ScrollableArea::mouseExitedScrollbar(Scrollbar* scrollbar) const
243 {
244     scrollAnimator()->mouseExitedScrollbar(scrollbar);
245 }
246
247 void ScrollableArea::contentAreaDidShow() const
248 {
249     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
250         scrollAnimator->contentAreaDidShow();
251 }
252
253 void ScrollableArea::contentAreaDidHide() const
254 {
255     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
256         scrollAnimator->contentAreaDidHide();
257 }
258
259 void ScrollableArea::didAddVerticalScrollbar(Scrollbar* scrollbar)
260 {
261     scrollAnimator()->didAddVerticalScrollbar(scrollbar);
262
263     // <rdar://problem/9797253> AppKit resets the scrollbar's style when you attach a scrollbar
264     setScrollbarOverlayStyle(scrollbarOverlayStyle());
265 }
266
267 void ScrollableArea::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
268 {
269     scrollAnimator()->willRemoveVerticalScrollbar(scrollbar);
270 }
271
272 void ScrollableArea::didAddHorizontalScrollbar(Scrollbar* scrollbar)
273 {
274     scrollAnimator()->didAddHorizontalScrollbar(scrollbar);
275
276     // <rdar://problem/9797253> AppKit resets the scrollbar's style when you attach a scrollbar
277     setScrollbarOverlayStyle(scrollbarOverlayStyle());
278 }
279
280 void ScrollableArea::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
281 {
282     scrollAnimator()->willRemoveHorizontalScrollbar(scrollbar);
283 }
284
285 void ScrollableArea::contentsResized()
286 {
287     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
288         scrollAnimator->contentsResized();
289 }
290
291 bool ScrollableArea::hasOverlayScrollbars() const
292 {
293     return (verticalScrollbar() && verticalScrollbar()->isOverlayScrollbar())
294         || (horizontalScrollbar() && horizontalScrollbar()->isOverlayScrollbar());
295 }
296
297 void ScrollableArea::setScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle)
298 {
299     m_scrollbarOverlayStyle = overlayStyle;
300
301     if (horizontalScrollbar()) {
302         ScrollbarTheme::theme()->updateScrollbarOverlayStyle(horizontalScrollbar());
303         horizontalScrollbar()->invalidate();
304     }
305     
306     if (verticalScrollbar()) {
307         ScrollbarTheme::theme()->updateScrollbarOverlayStyle(verticalScrollbar());
308         verticalScrollbar()->invalidate();
309     }
310 }
311
312 void ScrollableArea::invalidateScrollbar(Scrollbar* scrollbar, const IntRect& rect)
313 {
314 #if USE(ACCELERATED_COMPOSITING)
315     if (scrollbar == horizontalScrollbar()) {
316         if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) {
317             graphicsLayer->setNeedsDisplay();
318             graphicsLayer->setContentsNeedsDisplay();
319             return;
320         }
321     } else if (scrollbar == verticalScrollbar()) {
322         if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) {
323             graphicsLayer->setNeedsDisplay();
324             graphicsLayer->setContentsNeedsDisplay();
325             return;
326         }
327     }
328 #endif
329     invalidateScrollbarRect(scrollbar, rect);
330 }
331
332 void ScrollableArea::invalidateScrollCorner(const IntRect& rect)
333 {
334 #if USE(ACCELERATED_COMPOSITING)
335     if (GraphicsLayer* graphicsLayer = layerForScrollCorner()) {
336         graphicsLayer->setNeedsDisplay();
337         return;
338     }
339 #endif
340     invalidateScrollCornerRect(rect);
341 }
342
343 bool ScrollableArea::hasLayerForHorizontalScrollbar() const
344 {
345 #if USE(ACCELERATED_COMPOSITING)
346     return layerForHorizontalScrollbar();
347 #else
348     return false;
349 #endif
350 }
351
352 bool ScrollableArea::hasLayerForVerticalScrollbar() const
353 {
354 #if USE(ACCELERATED_COMPOSITING)
355     return layerForVerticalScrollbar();
356 #else
357     return false;
358 #endif
359 }
360
361 bool ScrollableArea::hasLayerForScrollCorner() const
362 {
363 #if USE(ACCELERATED_COMPOSITING)
364     return layerForScrollCorner();
365 #else
366     return false;
367 #endif
368 }
369
370 void ScrollableArea::serviceScrollAnimations()
371 {
372     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
373         scrollAnimator->serviceScrollAnimations();
374 }
375
376 } // namespace WebCore