Use WeakPtrs to avoid using deallocated Widgets and ScrollableAreas
[WebKit.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 updatesScrollLayerPositionOnMainThread() const = 0;
159
160     virtual bool forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const = 0;
161
162     // Convert points and rects between the scrollbar and its containing view.
163     // The client needs to implement these in order to be aware of layout effects
164     // like CSS transforms.
165     virtual IntRect convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
166     {
167         return scrollbar.Widget::convertToContainingView(scrollbarRect);
168     }
169     virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
170     {
171         return scrollbar.Widget::convertFromContainingView(parentRect);
172     }
173     virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
174     {
175         return scrollbar.Widget::convertToContainingView(scrollbarPoint);
176     }
177     virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
178     {
179         return scrollbar.Widget::convertFromContainingView(parentPoint);
180     }
181
182     int horizontalScrollbarIntrusion() const;
183     int verticalScrollbarIntrusion() const;
184     WEBCORE_EXPORT IntSize scrollbarIntrusion() const;
185
186     virtual Scrollbar* horizontalScrollbar() const { return nullptr; }
187     virtual Scrollbar* verticalScrollbar() const { return nullptr; }
188
189     const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
190     bool scrollOriginChanged() const { return m_scrollOriginChanged; }
191
192     virtual ScrollPosition scrollPosition() const;
193     virtual ScrollPosition minimumScrollPosition() const;
194     virtual ScrollPosition maximumScrollPosition() const;
195
196     ScrollPosition constrainScrollPosition(const ScrollPosition& position) const
197     {
198         return position.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
199     }
200
201     ScrollOffset maximumScrollOffset() const;
202
203     WEBCORE_EXPORT ScrollPosition scrollPositionFromOffset(ScrollOffset) const;
204     WEBCORE_EXPORT ScrollOffset scrollOffsetFromPosition(ScrollPosition) const;
205
206     template<typename PositionType, typename SizeType>
207     static PositionType scrollPositionFromOffset(PositionType offset, SizeType scrollOrigin)
208     {
209         return offset - scrollOrigin;
210     }
211
212     template<typename PositionType, typename SizeType>
213     static PositionType scrollOffsetFromPosition(PositionType position, SizeType scrollOrigin)
214     {
215         return position + scrollOrigin;
216     }
217
218     WEBCORE_EXPORT virtual bool scrolledToTop() const;
219     WEBCORE_EXPORT virtual bool scrolledToBottom() const;
220     WEBCORE_EXPORT virtual bool scrolledToLeft() const;
221     WEBCORE_EXPORT virtual bool scrolledToRight() const;
222
223     bool isScrolledProgrammatically() const { return m_scrolledProgrammatically; }
224     void setScrolledProgrammatically(bool state) { m_scrolledProgrammatically = state; }
225
226     enum VisibleContentRectIncludesScrollbars { ExcludeScrollbars, IncludeScrollbars };
227     enum VisibleContentRectBehavior {
228         ContentsVisibleRect,
229 #if PLATFORM(IOS)
230         LegacyIOSDocumentViewRect,
231         LegacyIOSDocumentVisibleRect = LegacyIOSDocumentViewRect
232 #else
233         LegacyIOSDocumentVisibleRect = ContentsVisibleRect
234 #endif
235     };
236
237     WEBCORE_EXPORT IntRect visibleContentRect(VisibleContentRectBehavior = ContentsVisibleRect) const;
238     WEBCORE_EXPORT IntRect visibleContentRectIncludingScrollbars(VisibleContentRectBehavior = ContentsVisibleRect) const;
239
240     int visibleWidth() const { return visibleSize().width(); }
241     int visibleHeight() const { return visibleSize().height(); }
242     virtual IntSize visibleSize() const = 0;
243
244     virtual IntSize contentsSize() const = 0;
245     virtual IntSize overhangAmount() const { return IntSize(); }
246     virtual IntPoint lastKnownMousePosition() const { return IntPoint(); }
247     virtual bool isHandlingWheelEvent() const { return false; }
248
249     virtual int headerHeight() const { return 0; }
250     virtual int footerHeight() const { return 0; }
251
252     // The totalContentsSize() is equivalent to the contentsSize() plus the header and footer heights.
253     WEBCORE_EXPORT IntSize totalContentsSize() const;
254
255     virtual bool shouldSuspendScrollAnimations() const { return true; }
256     WEBCORE_EXPORT virtual void scrollbarStyleChanged(ScrollbarStyle /*newStyle*/, bool /*forceUpdate*/);
257     virtual void setVisibleScrollerThumbRect(const IntRect&) { }
258     
259     // Note that this only returns scrollable areas that can actually be scrolled.
260     virtual ScrollableArea* enclosingScrollableArea() const = 0;
261
262     virtual bool isScrollableOrRubberbandable() = 0;
263     virtual bool hasScrollableOrRubberbandableAncestor() = 0;
264
265     // Returns the bounding box of this scrollable area, in the coordinate system of the enclosing scroll view.
266     virtual IntRect scrollableAreaBoundingBox(bool* = nullptr) const = 0;
267
268     virtual bool isRubberBandInProgress() const { return false; }
269     virtual bool isScrollSnapInProgress() const { return false; }
270
271     virtual bool scrollAnimatorEnabled() const { return false; }
272
273     // NOTE: Only called from Internals for testing.
274     WEBCORE_EXPORT void setScrollOffsetFromInternals(const ScrollOffset&);
275
276     WEBCORE_EXPORT static LayoutPoint constrainScrollPositionForOverhang(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, int headerHeight, int footetHeight);
277     LayoutPoint constrainScrollPositionForOverhang(const LayoutPoint& scrollPosition);
278
279     // Computes the double value for the scrollbar's current position and the current overhang amount.
280     // This function is static so that it can be called from the main thread or the scrolling thread.
281     static void computeScrollbarValueAndOverhang(float currentPosition, float totalSize, float visibleSize, float& doubleValue, float& overhangAmount);
282
283     // Let subclasses provide a way of asking for and servicing scroll
284     // animations.
285     virtual bool scheduleAnimation() { return false; }
286     void serviceScrollAnimations();
287
288 #if PLATFORM(IOS)
289     bool isHorizontalScrollerPinnedToMinimumPosition() const { return !horizontalScrollbar() || scrollOffset(HorizontalScrollbar) <= 0; }
290     bool isHorizontalScrollerPinnedToMaximumPosition() const { return !horizontalScrollbar() || scrollOffset(HorizontalScrollbar) >= maximumScrollOffset().x(); }
291     bool isVerticalScrollerPinnedToMinimumPosition() const { return !verticalScrollbar() || scrollOffset(VerticalScrollbar) <= 0; }
292     bool isVerticalScrollerPinnedToMaximumPosition() const { return !verticalScrollbar() || scrollOffset(VerticalScrollbar) >= maximumScrollOffset().y(); }
293
294     bool isPinnedInBothDirections(const IntSize&) const; 
295     bool isPinnedHorizontallyInDirection(int horizontalScrollDelta) const; 
296     bool isPinnedVerticallyInDirection(int verticalScrollDelta) const;
297 #endif
298
299     virtual TiledBacking* tiledBacking() const { return nullptr; }
300
301     // True if scrolling happens by moving compositing layers.
302     virtual bool usesCompositedScrolling() const { return false; }
303     // True if the contents can be scrolled asynchronously (i.e. by a ScrollingCoordinator).
304     virtual bool usesAsyncScrolling() const { return false; }
305
306     virtual GraphicsLayer* layerForHorizontalScrollbar() const { return nullptr; }
307     virtual GraphicsLayer* layerForVerticalScrollbar() const { return nullptr; }
308
309     bool hasLayerForHorizontalScrollbar() const;
310     bool hasLayerForVerticalScrollbar() const;
311
312     void verticalScrollbarLayerDidChange();
313     void horizontalScrollbarLayerDidChange();
314
315     virtual bool usesMockScrollAnimator() const { return false; }
316     virtual void logMockScrollAnimatorMessage(const String&) const { };
317
318     bool verticalScrollbarIsOnLeft() const;
319     static bool systemLanguageIsRTL();
320
321 protected:
322     WEBCORE_EXPORT ScrollableArea();
323     WEBCORE_EXPORT virtual ~ScrollableArea();
324
325     void setScrollOrigin(const IntPoint&);
326     void resetScrollOriginChanged() { m_scrollOriginChanged = false; }
327
328     WEBCORE_EXPORT virtual float adjustScrollStepForFixedContent(float step, ScrollbarOrientation, ScrollGranularity);
329     virtual void invalidateScrollbarRect(Scrollbar&, const IntRect&) = 0;
330     virtual void invalidateScrollCornerRect(const IntRect&) = 0;
331
332     friend class ScrollingCoordinator;
333     virtual GraphicsLayer* layerForScrolling() const { return nullptr; }
334     virtual GraphicsLayer* layerForScrollCorner() const { return nullptr; }
335 #if ENABLE(RUBBER_BANDING)
336     virtual GraphicsLayer* layerForOverhangAreas() const { return nullptr; }
337 #endif
338
339     bool hasLayerForScrollCorner() const;
340
341 private:
342     WEBCORE_EXPORT virtual IntRect visibleContentRectInternal(VisibleContentRectIncludesScrollbars, VisibleContentRectBehavior) const;
343     void scrollPositionChanged(const ScrollPosition&);
344     
345     // NOTE: Only called from the ScrollAnimator.
346     friend class ScrollAnimator;
347     void setScrollOffsetFromAnimation(const ScrollOffset&);
348
349     // This function should be overriden by subclasses to perform the actual
350     // scroll of the content.
351     virtual void setScrollOffset(const ScrollOffset&) = 0;
352
353     mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator;
354
355     WeakPtrFactory<ScrollableArea> m_weakPtrFactory { this };
356
357 #if ENABLE(CSS_SCROLL_SNAP)
358     std::unique_ptr<Vector<LayoutUnit>> m_horizontalSnapOffsets;
359     std::unique_ptr<Vector<LayoutUnit>> m_verticalSnapOffsets;
360     unsigned m_currentHorizontalSnapPointIndex { 0 };
361     unsigned m_currentVerticalSnapPointIndex { 0 };
362 #endif
363
364     // There are 8 possible combinations of writing mode and direction. Scroll origin will be non-zero in the x or y axis
365     // if there is any reversed direction or writing-mode. The combinations are:
366     // writing-mode / direction     scrollOrigin.x() set    scrollOrigin.y() set
367     // horizontal-tb / ltr          NO                      NO
368     // horizontal-tb / rtl          YES                     NO
369     // horizontal-bt / ltr          NO                      YES
370     // horizontal-bt / rtl          YES                     YES
371     // vertical-lr / ltr            NO                      NO
372     // vertical-lr / rtl            NO                      YES
373     // vertical-rl / ltr            YES                     NO
374     // vertical-rl / rtl            YES                     YES
375     IntPoint m_scrollOrigin;
376
377     unsigned m_constrainsScrollingToContentEdge : 1;
378
379     unsigned m_inLiveResize : 1;
380
381     unsigned m_verticalScrollElasticity : 2; // ScrollElasticity
382     unsigned m_horizontalScrollElasticity : 2; // ScrollElasticity
383
384     unsigned m_scrollbarOverlayStyle : 2; // ScrollbarOverlayStyle
385
386     unsigned m_scrollOriginChanged : 1;
387     unsigned m_scrolledProgrammatically : 1;
388 };
389
390 } // namespace WebCore
391
392 #endif // ScrollableArea_h