Add CSS -webkit-appearance property for Apple Pay buttons
[WebKit-https.git] / Source / WebCore / platform / ScrollableArea.h
1 /*
2  * Copyright (C) 2008-2016 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 #include <wtf/WeakPtr.h>
32
33 namespace WebCore {
34
35 class FloatPoint;
36 class GraphicsContext;
37 class LayoutPoint;
38 class LayoutSize;
39 class PlatformTouchEvent;
40 class PlatformWheelEvent;
41 class ScrollAnimator;
42 class GraphicsLayer;
43 class TiledBacking;
44
45 // scrollPosition is in content coordinates (0,0 is at scrollOrigin), so may have negative components.
46 typedef IntPoint ScrollPosition;
47 // scrollOffset() is the value used by scrollbars (min is 0,0), and should never have negative components.
48 typedef IntPoint ScrollOffset;
49
50 class ScrollableArea {
51 public:
52     WEBCORE_EXPORT bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1);
53     WEBCORE_EXPORT void scrollToOffsetWithoutAnimation(const FloatPoint&);
54     void scrollToOffsetWithoutAnimation(ScrollbarOrientation, float offset);
55
56     // Should be called when the scroll position changes externally, for example if the scroll layer position
57     // is updated on the scrolling thread and we need to notify the main thread.
58     WEBCORE_EXPORT void notifyScrollPositionChanged(const ScrollPosition&);
59
60     // Allows subclasses to handle scroll position updates themselves. If this member function
61     // returns true, the scrollable area won't actually update the scroll position and instead
62     // expect it to happen sometime in the future.
63     virtual bool requestScrollPositionUpdate(const ScrollPosition&) { return false; }
64
65     WEBCORE_EXPORT bool handleWheelEvent(const PlatformWheelEvent&);
66
67     WeakPtr<ScrollableArea> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
68
69 #if ENABLE(CSS_SCROLL_SNAP)
70     const Vector<LayoutUnit>* horizontalSnapOffsets() const { return m_horizontalSnapOffsets.get(); };
71     const Vector<LayoutUnit>* verticalSnapOffsets() const { return m_verticalSnapOffsets.get(); };
72     virtual void updateSnapOffsets() { };
73     void setHorizontalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>>);
74     void setVerticalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>>);
75     void clearHorizontalSnapOffsets();
76     void clearVerticalSnapOffsets();
77     unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
78     void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
79     unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; }
80     void setCurrentVerticalSnapPointIndex(unsigned index) { m_currentVerticalSnapPointIndex = index; }
81     IntPoint nearestActiveSnapPoint(const IntPoint&);
82 #endif
83
84     void updateScrollSnapState();
85
86 #if ENABLE(TOUCH_EVENTS)
87     virtual bool isTouchScrollable() const { return false; }
88     virtual bool handleTouchEvent(const PlatformTouchEvent&);
89 #endif
90
91 #if PLATFORM(IOS)
92     virtual bool isOverflowScroll() const { return false; }
93     virtual void didStartScroll() { }
94     virtual void didEndScroll() { }
95     virtual void didUpdateScroll() { }
96 #endif
97     virtual void setIsUserScroll(bool) { }
98
99     // Functions for controlling if you can scroll past the end of the document.
100     bool constrainsScrollingToContentEdge() const { return m_constrainsScrollingToContentEdge; }
101     void setConstrainsScrollingToContentEdge(bool constrainsScrollingToContentEdge) { m_constrainsScrollingToContentEdge = constrainsScrollingToContentEdge; }
102
103     void setVerticalScrollElasticity(ScrollElasticity scrollElasticity) { m_verticalScrollElasticity = scrollElasticity; }
104     ScrollElasticity verticalScrollElasticity() const { return static_cast<ScrollElasticity>(m_verticalScrollElasticity); }
105
106     void setHorizontalScrollElasticity(ScrollElasticity scrollElasticity) { m_horizontalScrollElasticity = scrollElasticity; }
107     ScrollElasticity horizontalScrollElasticity() const { return static_cast<ScrollElasticity>(m_horizontalScrollElasticity); }
108
109     bool inLiveResize() const { return m_inLiveResize; }
110     WEBCORE_EXPORT virtual void willStartLiveResize();
111     WEBCORE_EXPORT virtual void willEndLiveResize();
112
113     WEBCORE_EXPORT void contentAreaWillPaint() const;
114     WEBCORE_EXPORT void mouseEnteredContentArea() const;
115     WEBCORE_EXPORT void mouseExitedContentArea() const;
116     WEBCORE_EXPORT void mouseMovedInContentArea() const;
117     WEBCORE_EXPORT void mouseEnteredScrollbar(Scrollbar*) const;
118     void mouseExitedScrollbar(Scrollbar*) const;
119     void mouseIsDownInScrollbar(Scrollbar*, bool) const;
120     void contentAreaDidShow() const;
121     void contentAreaDidHide() const;
122
123     void lockOverlayScrollbarStateToHidden(bool shouldLockState) const;
124     WEBCORE_EXPORT bool scrollbarsCanBeActive() const;
125
126     WEBCORE_EXPORT virtual void didAddScrollbar(Scrollbar*, ScrollbarOrientation);
127     WEBCORE_EXPORT virtual void willRemoveScrollbar(Scrollbar*, ScrollbarOrientation);
128
129     WEBCORE_EXPORT virtual void contentsResized();
130
131     // Force the contents to recompute their size (i.e. do layout).
132     virtual void updateContentsSize() { }
133
134     enum class AvailableSizeChangeReason {
135         ScrollbarsChanged,
136         AreaSizeChanged
137     };
138     WEBCORE_EXPORT virtual void availableContentSizeChanged(AvailableSizeChangeReason);
139
140     bool hasOverlayScrollbars() const;
141     WEBCORE_EXPORT virtual void setScrollbarOverlayStyle(ScrollbarOverlayStyle);
142     ScrollbarOverlayStyle scrollbarOverlayStyle() const { return static_cast<ScrollbarOverlayStyle>(m_scrollbarOverlayStyle); }
143
144     // This getter will create a ScrollAnimator if it doesn't already exist.
145     WEBCORE_EXPORT ScrollAnimator& scrollAnimator() const;
146
147     // This getter will return null if the ScrollAnimator hasn't been created yet.
148     ScrollAnimator* existingScrollAnimator() const { return m_scrollAnimator.get(); }
149
150     virtual bool isActive() const = 0;
151     virtual int scrollSize(ScrollbarOrientation) const = 0;
152     virtual int scrollOffset(ScrollbarOrientation) const = 0;
153     WEBCORE_EXPORT virtual void invalidateScrollbar(Scrollbar&, const IntRect&);
154     virtual bool isScrollCornerVisible() const = 0;
155     virtual IntRect scrollCornerRect() const = 0;
156     WEBCORE_EXPORT virtual void invalidateScrollCorner(const IntRect&);
157
158     virtual bool forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const = 0;
159
160     // Convert points and rects between the scrollbar and its containing view.
161     // The client needs to implement these in order to be aware of layout effects
162     // like CSS transforms.
163     virtual IntRect convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
164     {
165         return scrollbar.Widget::convertToContainingView(scrollbarRect);
166     }
167     virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
168     {
169         return scrollbar.Widget::convertFromContainingView(parentRect);
170     }
171     virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
172     {
173         return scrollbar.Widget::convertToContainingView(scrollbarPoint);
174     }
175     virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
176     {
177         return scrollbar.Widget::convertFromContainingView(parentPoint);
178     }
179
180     int horizontalScrollbarIntrusion() const;
181     int verticalScrollbarIntrusion() const;
182     WEBCORE_EXPORT IntSize scrollbarIntrusion() const;
183
184     virtual Scrollbar* horizontalScrollbar() const { return nullptr; }
185     virtual Scrollbar* verticalScrollbar() const { return nullptr; }
186
187     const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
188     bool scrollOriginChanged() const { return m_scrollOriginChanged; }
189
190     virtual ScrollPosition scrollPosition() const;
191     virtual ScrollPosition minimumScrollPosition() const;
192     virtual ScrollPosition maximumScrollPosition() const;
193
194     ScrollPosition constrainScrollPosition(const ScrollPosition& position) const
195     {
196         return position.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
197     }
198
199     ScrollOffset maximumScrollOffset() const;
200
201     WEBCORE_EXPORT ScrollPosition scrollPositionFromOffset(ScrollOffset) const;
202     WEBCORE_EXPORT ScrollOffset scrollOffsetFromPosition(ScrollPosition) const;
203
204     template<typename PositionType, typename SizeType>
205     static PositionType scrollPositionFromOffset(PositionType offset, SizeType scrollOrigin)
206     {
207         return offset - scrollOrigin;
208     }
209
210     template<typename PositionType, typename SizeType>
211     static PositionType scrollOffsetFromPosition(PositionType position, SizeType scrollOrigin)
212     {
213         return position + scrollOrigin;
214     }
215
216     WEBCORE_EXPORT virtual bool scrolledToTop() const;
217     WEBCORE_EXPORT virtual bool scrolledToBottom() const;
218     WEBCORE_EXPORT virtual bool scrolledToLeft() const;
219     WEBCORE_EXPORT virtual bool scrolledToRight() const;
220
221     bool isScrolledProgrammatically() const { return m_scrolledProgrammatically; }
222     void setScrolledProgrammatically(bool state) { m_scrolledProgrammatically = state; }
223
224     enum VisibleContentRectIncludesScrollbars { ExcludeScrollbars, IncludeScrollbars };
225     enum VisibleContentRectBehavior {
226         ContentsVisibleRect,
227 #if PLATFORM(IOS)
228         LegacyIOSDocumentViewRect,
229         LegacyIOSDocumentVisibleRect = LegacyIOSDocumentViewRect
230 #else
231         LegacyIOSDocumentVisibleRect = ContentsVisibleRect
232 #endif
233     };
234
235     WEBCORE_EXPORT IntRect visibleContentRect(VisibleContentRectBehavior = ContentsVisibleRect) const;
236     WEBCORE_EXPORT IntRect visibleContentRectIncludingScrollbars(VisibleContentRectBehavior = ContentsVisibleRect) const;
237
238     int visibleWidth() const { return visibleSize().width(); }
239     int visibleHeight() const { return visibleSize().height(); }
240     virtual IntSize visibleSize() const = 0;
241
242     virtual IntSize contentsSize() const = 0;
243     virtual IntSize overhangAmount() const { return IntSize(); }
244     virtual IntPoint lastKnownMousePosition() const { return IntPoint(); }
245     virtual bool isHandlingWheelEvent() const { return false; }
246
247     virtual int headerHeight() const { return 0; }
248     virtual int footerHeight() const { return 0; }
249
250     // The totalContentsSize() is equivalent to the contentsSize() plus the header and footer heights.
251     WEBCORE_EXPORT IntSize totalContentsSize() const;
252
253     virtual bool shouldSuspendScrollAnimations() const { return true; }
254     WEBCORE_EXPORT virtual void scrollbarStyleChanged(ScrollbarStyle /*newStyle*/, bool /*forceUpdate*/);
255     virtual void setVisibleScrollerThumbRect(const IntRect&) { }
256     
257     // Note that this only returns scrollable areas that can actually be scrolled.
258     virtual ScrollableArea* enclosingScrollableArea() const = 0;
259
260     virtual bool isScrollableOrRubberbandable() = 0;
261     virtual bool hasScrollableOrRubberbandableAncestor() = 0;
262
263     // Returns the bounding box of this scrollable area, in the coordinate system of the enclosing scroll view.
264     virtual IntRect scrollableAreaBoundingBox(bool* = nullptr) const = 0;
265
266     virtual bool isRubberBandInProgress() const { return false; }
267     virtual bool isScrollSnapInProgress() const { return false; }
268
269     virtual bool scrollAnimatorEnabled() const { return false; }
270
271     // NOTE: Only called from Internals for testing.
272     WEBCORE_EXPORT void setScrollOffsetFromInternals(const ScrollOffset&);
273
274     WEBCORE_EXPORT static LayoutPoint constrainScrollPositionForOverhang(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, int headerHeight, int footetHeight);
275     LayoutPoint constrainScrollPositionForOverhang(const LayoutPoint& scrollPosition);
276
277     // Computes the double value for the scrollbar's current position and the current overhang amount.
278     // This function is static so that it can be called from the main thread or the scrolling thread.
279     static void computeScrollbarValueAndOverhang(float currentPosition, float totalSize, float visibleSize, float& doubleValue, float& overhangAmount);
280
281     // Let subclasses provide a way of asking for and servicing scroll
282     // animations.
283     virtual bool scheduleAnimation() { return false; }
284     void serviceScrollAnimations();
285
286 #if PLATFORM(IOS)
287     bool isHorizontalScrollerPinnedToMinimumPosition() const { return !horizontalScrollbar() || scrollOffset(HorizontalScrollbar) <= 0; }
288     bool isHorizontalScrollerPinnedToMaximumPosition() const { return !horizontalScrollbar() || scrollOffset(HorizontalScrollbar) >= maximumScrollOffset().x(); }
289     bool isVerticalScrollerPinnedToMinimumPosition() const { return !verticalScrollbar() || scrollOffset(VerticalScrollbar) <= 0; }
290     bool isVerticalScrollerPinnedToMaximumPosition() const { return !verticalScrollbar() || scrollOffset(VerticalScrollbar) >= maximumScrollOffset().y(); }
291
292     bool isPinnedInBothDirections(const IntSize&) const; 
293     bool isPinnedHorizontallyInDirection(int horizontalScrollDelta) const; 
294     bool isPinnedVerticallyInDirection(int verticalScrollDelta) const;
295 #endif
296
297     virtual TiledBacking* tiledBacking() const { return nullptr; }
298
299     // True if scrolling happens by moving compositing layers.
300     virtual bool usesCompositedScrolling() const { return false; }
301     // True if the contents can be scrolled asynchronously (i.e. by a ScrollingCoordinator).
302     virtual bool usesAsyncScrolling() const { return false; }
303
304     virtual GraphicsLayer* layerForHorizontalScrollbar() const { return nullptr; }
305     virtual GraphicsLayer* layerForVerticalScrollbar() const { return nullptr; }
306
307     bool hasLayerForHorizontalScrollbar() const;
308     bool hasLayerForVerticalScrollbar() const;
309
310     void verticalScrollbarLayerDidChange();
311     void horizontalScrollbarLayerDidChange();
312
313     virtual bool usesMockScrollAnimator() const { return false; }
314     virtual void logMockScrollAnimatorMessage(const String&) const { };
315
316     virtual bool shouldPlaceBlockDirectionScrollbarOnLeft() const = 0;
317
318 protected:
319     WEBCORE_EXPORT ScrollableArea();
320     WEBCORE_EXPORT virtual ~ScrollableArea();
321
322     void setScrollOrigin(const IntPoint&);
323     void resetScrollOriginChanged() { m_scrollOriginChanged = false; }
324
325     WEBCORE_EXPORT virtual float adjustScrollStepForFixedContent(float step, ScrollbarOrientation, ScrollGranularity);
326     virtual void invalidateScrollbarRect(Scrollbar&, const IntRect&) = 0;
327     virtual void invalidateScrollCornerRect(const IntRect&) = 0;
328
329     friend class ScrollingCoordinator;
330     virtual GraphicsLayer* layerForScrolling() const { return nullptr; }
331     virtual GraphicsLayer* layerForScrollCorner() const { return nullptr; }
332 #if ENABLE(RUBBER_BANDING)
333     virtual GraphicsLayer* layerForOverhangAreas() const { return nullptr; }
334 #endif
335
336     bool hasLayerForScrollCorner() const;
337
338 private:
339     WEBCORE_EXPORT virtual IntRect visibleContentRectInternal(VisibleContentRectIncludesScrollbars, VisibleContentRectBehavior) const;
340     void scrollPositionChanged(const ScrollPosition&);
341     
342     // NOTE: Only called from the ScrollAnimator.
343     friend class ScrollAnimator;
344     void setScrollOffsetFromAnimation(const ScrollOffset&);
345
346     // This function should be overriden by subclasses to perform the actual
347     // scroll of the content.
348     virtual void setScrollOffset(const ScrollOffset&) = 0;
349
350     mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator;
351
352     WeakPtrFactory<ScrollableArea> m_weakPtrFactory { this };
353
354 #if ENABLE(CSS_SCROLL_SNAP)
355     std::unique_ptr<Vector<LayoutUnit>> m_horizontalSnapOffsets;
356     std::unique_ptr<Vector<LayoutUnit>> m_verticalSnapOffsets;
357     unsigned m_currentHorizontalSnapPointIndex { 0 };
358     unsigned m_currentVerticalSnapPointIndex { 0 };
359 #endif
360
361     // There are 8 possible combinations of writing mode and direction. Scroll origin will be non-zero in the x or y axis
362     // if there is any reversed direction or writing-mode. The combinations are:
363     // writing-mode / direction     scrollOrigin.x() set    scrollOrigin.y() set
364     // horizontal-tb / ltr          NO                      NO
365     // horizontal-tb / rtl          YES                     NO
366     // horizontal-bt / ltr          NO                      YES
367     // horizontal-bt / rtl          YES                     YES
368     // vertical-lr / ltr            NO                      NO
369     // vertical-lr / rtl            NO                      YES
370     // vertical-rl / ltr            YES                     NO
371     // vertical-rl / rtl            YES                     YES
372     IntPoint m_scrollOrigin;
373
374     unsigned m_constrainsScrollingToContentEdge : 1;
375
376     unsigned m_inLiveResize : 1;
377
378     unsigned m_verticalScrollElasticity : 2; // ScrollElasticity
379     unsigned m_horizontalScrollElasticity : 2; // ScrollElasticity
380
381     unsigned m_scrollbarOverlayStyle : 2; // ScrollbarOverlayStyle
382
383     unsigned m_scrollOriginChanged : 1;
384     unsigned m_scrolledProgrammatically : 1;
385 };
386
387 } // namespace WebCore
388
389 #endif // ScrollableArea_h