1/*
2 * Copyright (C) 2008, 2011, 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef ScrollableArea_h
27#define ScrollableArea_h
28
29#include "Scrollbar.h"
30#include <wtf/Vector.h>
31
32namespace WebCore {
33
34class FloatPoint;
35class GraphicsContext;
36class LayoutPoint;
37class LayoutSize;
38class PlatformTouchEvent;
39class PlatformWheelEvent;
40class ScrollAnimator;
41class GraphicsLayer;
42class TiledBacking;
43
44class ScrollableArea {
45public:
46    bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1);
47    void scrollToOffsetWithoutAnimation(const FloatPoint&);
48    void scrollToOffsetWithoutAnimation(ScrollbarOrientation, float offset);
49
50    // Should be called when the scroll position changes externally, for example if the scroll layer position
51    // is updated on the scrolling thread and we need to notify the main thread.
52    void notifyScrollPositionChanged(const IntPoint&);
53
54    // Allows subclasses to handle scroll position updates themselves. If this member function
55    // returns true, the scrollable area won't actually update the scroll position and instead
56    // expect it to happen sometime in the future.
57    virtual bool requestScrollPositionUpdate(const IntPoint&) { return false; }
58
59    bool handleWheelEvent(const PlatformWheelEvent&);
60
61#if ENABLE(TOUCH_EVENTS)
62    virtual bool isTouchScrollable() const { return false; }
63    virtual bool handleTouchEvent(const PlatformTouchEvent&);
64#endif
65
66#if PLATFORM(IOS)
67    virtual bool isOverflowScroll() const { return false; }
68    virtual void didStartScroll() { }
69    virtual void didEndScroll() { }
70    virtual void didUpdateScroll() { }
71#endif
72    virtual void setIsUserScroll(bool) { }
73
74    // Functions for controlling if you can scroll past the end of the document.
75    bool constrainsScrollingToContentEdge() const { return m_constrainsScrollingToContentEdge; }
76    void setConstrainsScrollingToContentEdge(bool constrainsScrollingToContentEdge) { m_constrainsScrollingToContentEdge = constrainsScrollingToContentEdge; }
77
78    void setVerticalScrollElasticity(ScrollElasticity scrollElasticity) { m_verticalScrollElasticity = scrollElasticity; }
79    ScrollElasticity verticalScrollElasticity() const { return static_cast<ScrollElasticity>(m_verticalScrollElasticity); }
80
81    void setHorizontalScrollElasticity(ScrollElasticity scrollElasticity) { m_horizontalScrollElasticity = scrollElasticity; }
82    ScrollElasticity horizontalScrollElasticity() const { return static_cast<ScrollElasticity>(m_horizontalScrollElasticity); }
83
84    bool inLiveResize() const { return m_inLiveResize; }
85    virtual void willStartLiveResize();
86    virtual void willEndLiveResize();
87
88    void contentAreaWillPaint() const;
89    void mouseEnteredContentArea() const;
90    void mouseExitedContentArea() const;
91    void mouseMovedInContentArea() const;
92    void mouseEnteredScrollbar(Scrollbar*) const;
93    void mouseExitedScrollbar(Scrollbar*) const;
94    void contentAreaDidShow() const;
95    void contentAreaDidHide() const;
96
97    void lockOverlayScrollbarStateToHidden(bool shouldLockState) const;
98    bool scrollbarsCanBeActive() const;
99
100    virtual void didAddScrollbar(Scrollbar*, ScrollbarOrientation);
101    virtual void willRemoveScrollbar(Scrollbar*, ScrollbarOrientation);
102
103    virtual void contentsResized();
104
105    bool hasOverlayScrollbars() const;
106    virtual void setScrollbarOverlayStyle(ScrollbarOverlayStyle);
107    ScrollbarOverlayStyle scrollbarOverlayStyle() const { return static_cast<ScrollbarOverlayStyle>(m_scrollbarOverlayStyle); }
108
109    // This getter will create a ScrollAnimator if it doesn't already exist.
110    ScrollAnimator* scrollAnimator() const;
111
112    // This getter will return null if the ScrollAnimator hasn't been created yet.
113    ScrollAnimator* existingScrollAnimator() const { return m_scrollAnimator.get(); }
114
115    const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
116    bool scrollOriginChanged() const { return m_scrollOriginChanged; }
117
118    virtual bool isActive() const = 0;
119    virtual int scrollSize(ScrollbarOrientation) const = 0;
120    virtual int scrollPosition(Scrollbar*) const = 0;
121    virtual void invalidateScrollbar(Scrollbar*, const IntRect&);
122    virtual bool isScrollCornerVisible() const = 0;
123    virtual IntRect scrollCornerRect() const = 0;
124    virtual void invalidateScrollCorner(const IntRect&);
125
126    virtual bool updatesScrollLayerPositionOnMainThread() const = 0;
127
128    virtual bool forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const = 0;
129
130    // Convert points and rects between the scrollbar and its containing view.
131    // The client needs to implement these in order to be aware of layout effects
132    // like CSS transforms.
133    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
134    {
135        return scrollbar->Widget::convertToContainingView(scrollbarRect);
136    }
137    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
138    {
139        return scrollbar->Widget::convertFromContainingView(parentRect);
140    }
141    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
142    {
143        return scrollbar->Widget::convertToContainingView(scrollbarPoint);
144    }
145    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
146    {
147        return scrollbar->Widget::convertFromContainingView(parentPoint);
148    }
149
150    virtual Scrollbar* horizontalScrollbar() const { return 0; }
151    virtual Scrollbar* verticalScrollbar() const { return 0; }
152
153    virtual IntPoint scrollPosition() const;
154    virtual IntPoint minimumScrollPosition() const;
155    virtual IntPoint maximumScrollPosition() const;
156    virtual bool scrolledToTop() const;
157    virtual bool scrolledToBottom() const;
158    virtual bool scrolledToLeft() const;
159    virtual bool scrolledToRight() const;
160
161    bool isScrolledProgrammatically() const { return m_scrolledProgrammatically; }
162    void setScrolledProgrammatically(bool state) { m_scrolledProgrammatically = state; }
163
164    enum VisibleContentRectIncludesScrollbars { ExcludeScrollbars, IncludeScrollbars };
165    enum VisibleContentRectBehavior {
166        ContentsVisibleRect,
167#if PLATFORM(IOS)
168        LegacyIOSDocumentViewRect,
169        LegacyIOSDocumentVisibleRect = LegacyIOSDocumentViewRect
170#else
171        LegacyIOSDocumentVisibleRect = ContentsVisibleRect
172#endif
173    };
174
175    IntRect visibleContentRect(VisibleContentRectBehavior = ContentsVisibleRect) const;
176    IntRect visibleContentRectIncludingScrollbars(VisibleContentRectBehavior = ContentsVisibleRect) const;
177
178    int visibleWidth() const { return visibleSize().width(); }
179    int visibleHeight() const { return visibleSize().height(); }
180    virtual IntSize visibleSize() const = 0;
181
182    virtual IntSize contentsSize() const = 0;
183    virtual IntSize overhangAmount() const { return IntSize(); }
184    virtual IntPoint lastKnownMousePosition() const { return IntPoint(); }
185    virtual bool isHandlingWheelEvent() const { return false; }
186
187    virtual int headerHeight() const { return 0; }
188    virtual int footerHeight() const { return 0; }
189
190    // The totalContentsSize() is equivalent to the contentsSize() plus the header and footer heights.
191    IntSize totalContentsSize() const;
192
193    virtual bool shouldSuspendScrollAnimations() const { return true; }
194    virtual void scrollbarStyleChanged(int /*newStyle*/, bool /*forceUpdate*/) { }
195    virtual void setVisibleScrollerThumbRect(const IntRect&) { }
196
197    // Note that this only returns scrollable areas that can actually be scrolled.
198    virtual ScrollableArea* enclosingScrollableArea() const = 0;
199
200    // Returns the bounding box of this scrollable area, in the coordinate system of the enclosing scroll view.
201    virtual IntRect scrollableAreaBoundingBox() const = 0;
202
203    virtual bool isRubberBandInProgress() const { return false; }
204
205    virtual bool scrollAnimatorEnabled() const { return false; }
206
207    // NOTE: Only called from Internals for testing.
208    void setScrollOffsetFromInternals(const IntPoint&);
209
210    static LayoutPoint constrainScrollPositionForOverhang(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, int headerHeight, int footetHeight);
211    LayoutPoint constrainScrollPositionForOverhang(const LayoutPoint& scrollPosition);
212
213    // Computes the double value for the scrollbar's current position and the current overhang amount.
214    // This function is static so that it can be called from the main thread or the scrolling thread.
215    static void computeScrollbarValueAndOverhang(float currentPosition, float totalSize, float visibleSize, float& doubleValue, float& overhangAmount);
216
217    // Let subclasses provide a way of asking for and servicing scroll
218    // animations.
219    virtual bool scheduleAnimation() { return false; }
220    void serviceScrollAnimations();
221
222#if PLATFORM(IOS)
223    bool isHorizontalScrollerPinnedToMinimumPosition() const { return !horizontalScrollbar() || scrollPosition(horizontalScrollbar()) <= minimumScrollPosition().x(); }
224    bool isHorizontalScrollerPinnedToMaximumPosition() const { return !horizontalScrollbar() || scrollPosition(horizontalScrollbar()) >= maximumScrollPosition().x(); }
225    bool isVerticalScrollerPinnedToMinimumPosition() const { return !verticalScrollbar() || scrollPosition(verticalScrollbar()) <= minimumScrollPosition().y(); }
226    bool isVerticalScrollerPinnedToMaximumPosition() const { return !verticalScrollbar() || scrollPosition(verticalScrollbar()) >= maximumScrollPosition().y(); }
227
228    bool isPinnedInBothDirections(const IntSize&) const;
229    bool isPinnedHorizontallyInDirection(int horizontalScrollDelta) const;
230    bool isPinnedVerticallyInDirection(int verticalScrollDelta) const;
231#endif
232
233    virtual TiledBacking* tiledBacking() const { return 0; }
234    virtual bool usesCompositedScrolling() const { return false; }
235
236    virtual GraphicsLayer* layerForHorizontalScrollbar() const { return 0; }
237    virtual GraphicsLayer* layerForVerticalScrollbar() const { return 0; }
238
239    bool hasLayerForHorizontalScrollbar() const;
240    bool hasLayerForVerticalScrollbar() const;
241
242    void verticalScrollbarLayerDidChange();
243    void horizontalScrollbarLayerDidChange();
244
245protected:
246    ScrollableArea();
247    virtual ~ScrollableArea();
248
249    void setScrollOrigin(const IntPoint&);
250    void resetScrollOriginChanged() { m_scrollOriginChanged = false; }
251
252    virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) = 0;
253    virtual void invalidateScrollCornerRect(const IntRect&) = 0;
254
255    friend class ScrollingCoordinator;
256    virtual GraphicsLayer* layerForScrolling() const { return 0; }
257    virtual GraphicsLayer* layerForScrollCorner() const { return 0; }
258#if ENABLE(RUBBER_BANDING)
259    virtual GraphicsLayer* layerForOverhangAreas() const { return 0; }
260#endif
261
262    bool hasLayerForScrollCorner() const;
263
264private:
265    virtual IntRect visibleContentRectInternal(VisibleContentRectIncludesScrollbars, VisibleContentRectBehavior) const;
266    void scrollPositionChanged(const IntPoint&);
267
268    // NOTE: Only called from the ScrollAnimator.
269    friend class ScrollAnimator;
270    void setScrollOffsetFromAnimation(const IntPoint&);
271
272    // This function should be overriden by subclasses to perform the actual
273    // scroll of the content.
274    virtual void setScrollOffset(const IntPoint&) = 0;
275
276    mutable OwnPtr<ScrollAnimator> m_scrollAnimator;
277
278    // There are 8 possible combinations of writing mode and direction. Scroll origin will be non-zero in the x or y axis
279    // if there is any reversed direction or writing-mode. The combinations are:
280    // writing-mode / direction     scrollOrigin.x() set    scrollOrigin.y() set
281    // horizontal-tb / ltr          NO                      NO
282    // horizontal-tb / rtl          YES                     NO
283    // horizontal-bt / ltr          NO                      YES
284    // horizontal-bt / rtl          YES                     YES
285    // vertical-lr / ltr            NO                      NO
286    // vertical-lr / rtl            NO                      YES
287    // vertical-rl / ltr            YES                     NO
288    // vertical-rl / rtl            YES                     YES
289    IntPoint m_scrollOrigin;
290
291    unsigned m_constrainsScrollingToContentEdge : 1;
292
293    unsigned m_inLiveResize : 1;
294
295    unsigned m_verticalScrollElasticity : 2; // ScrollElasticity
296    unsigned m_horizontalScrollElasticity : 2; // ScrollElasticity
297
298    unsigned m_scrollbarOverlayStyle : 2; // ScrollbarOverlayStyle
299
300    unsigned m_scrollOriginChanged : 1;
301    unsigned m_scrolledProgrammatically : 1;
302};
303
304} // namespace WebCore
305
306#endif // ScrollableArea_h
307