2 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef ScrollableArea_h
27 #define ScrollableArea_h
29 #include "platform/PlatformExport.h"
30 #include "platform/RuntimeEnabledFeatures.h"
31 #include "platform/geometry/FloatQuad.h"
32 #include "platform/geometry/LayoutRect.h"
33 #include "platform/graphics/Color.h"
34 #include "platform/heap/Handle.h"
35 #include "platform/scroll/ScrollAnimatorBase.h"
36 #include "platform/scroll/ScrollTypes.h"
37 #include "platform/scroll/Scrollbar.h"
38 #include "wtf/MathExtras.h"
39 #include "wtf/Noncopyable.h"
40 #include "wtf/Vector.h"
48 class ProgrammaticScrollAnimator;
49 struct ScrollAlignment;
51 class ScrollAnimatorBase;
52 class CompositorAnimationTimeline;
54 enum IncludeScrollbarsInRect {
59 class PLATFORM_EXPORT ScrollableArea : public GarbageCollectedMixin {
60 WTF_MAKE_NONCOPYABLE(ScrollableArea);
63 static int pixelsPerLineStep(HostWindow*);
64 static float minFractionToStepWhenPaging();
65 static int maxOverlapBetweenPages();
67 // Convert a non-finite scroll value (Infinity, -Infinity, NaN) to 0 as
68 // per http://dev.w3.org/csswg/cssom-view/#normalize-non_finite-values.
69 static float normalizeNonFiniteScroll(float value) {
70 return std::isfinite(value) ? value : 0.0;
73 // The window that hosts the ScrollableArea. The ScrollableArea will
74 // communicate scrolls and repaints to the host window in the window's
76 virtual HostWindow* getHostWindow() const { return 0; }
78 virtual ScrollResult userScroll(ScrollGranularity, const ScrollOffset&);
80 virtual void setScrollOffset(const ScrollOffset&,
82 ScrollBehavior = ScrollBehaviorInstant);
83 virtual void scrollBy(const ScrollOffset&,
85 ScrollBehavior = ScrollBehaviorInstant);
86 void setScrollOffsetSingleAxis(ScrollbarOrientation,
89 ScrollBehavior = ScrollBehaviorInstant);
91 // Scrolls the area so that the given rect, given in the document's content
92 // coordinates, such that it's visible in the area. Returns the new location
93 // of the input rect relative once again to the document.
94 // Note, in the case of a Document container, such as FrameView, the output
95 // will always be the input rect since scrolling it can't change the location
96 // of content relative to the document, unlike an overflowing element.
97 virtual LayoutRect scrollIntoView(const LayoutRect& rectInContent,
98 const ScrollAlignment& alignX,
99 const ScrollAlignment& alignY,
100 ScrollType = ProgrammaticScroll,
101 ScrollBehavior = ScrollBehaviorInstant);
103 // Returns a rect, in the space of the area's backing graphics layer, that
104 // contains the visual region of all scrollbar parts.
105 virtual LayoutRect visualRectForScrollbarParts() const = 0;
107 static bool scrollBehaviorFromString(const String&, ScrollBehavior&);
109 void contentAreaWillPaint() const;
110 void mouseEnteredContentArea() const;
111 void mouseExitedContentArea() const;
112 void mouseMovedInContentArea() const;
113 void mouseEnteredScrollbar(Scrollbar&);
114 void mouseExitedScrollbar(Scrollbar&);
115 void mouseCapturedScrollbar();
116 void mouseReleasedScrollbar();
117 void contentAreaDidShow() const;
118 void contentAreaDidHide() const;
120 void finishCurrentScrollAnimations() const;
122 virtual void didAddScrollbar(Scrollbar&, ScrollbarOrientation);
123 virtual void willRemoveScrollbar(Scrollbar&, ScrollbarOrientation);
125 virtual void contentsResized();
127 bool hasOverlayScrollbars() const;
128 void setScrollbarOverlayColorTheme(ScrollbarOverlayColorTheme);
129 void recalculateScrollbarOverlayColorTheme(Color);
130 ScrollbarOverlayColorTheme getScrollbarOverlayColorTheme() const {
131 return static_cast<ScrollbarOverlayColorTheme>(
132 m_scrollbarOverlayColorTheme);
135 // This getter will create a ScrollAnimatorBase if it doesn't already exist.
136 ScrollAnimatorBase& scrollAnimator() const;
138 // This getter will return null if the ScrollAnimatorBase hasn't been created
140 ScrollAnimatorBase* existingScrollAnimator() const {
141 return m_scrollAnimator;
144 ProgrammaticScrollAnimator& programmaticScrollAnimator() const;
145 ProgrammaticScrollAnimator* existingProgrammaticScrollAnimator() const {
146 return m_programmaticScrollAnimator;
149 virtual CompositorAnimationTimeline* compositorAnimationTimeline() const {
153 // See Source/core/layout/README.md for an explanation of scroll origin.
154 const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
155 bool scrollOriginChanged() const { return m_scrollOriginChanged; }
157 // This is used to determine whether the incoming fractional scroll offset
158 // should be truncated to integer. Current rule is that if
159 // preferCompositingToLCDTextEnabled() is disabled (which is true on low-dpi
160 // device by default) we should do the truncation. The justification is that
161 // non-composited elements using fractional scroll offsets is causing too much
162 // nasty bugs but does not add too benefit on low-dpi devices.
163 // TODO(szager): Now that scroll offsets are floats everywhere, can we get rid
165 virtual bool shouldUseIntegerScrollOffset() const {
166 return !RuntimeEnabledFeatures::fractionalScrollOffsetsEnabled();
169 virtual bool isActive() const = 0;
170 virtual int scrollSize(ScrollbarOrientation) const = 0;
171 void setScrollbarNeedsPaintInvalidation(ScrollbarOrientation);
172 virtual bool isScrollCornerVisible() const = 0;
173 virtual IntRect scrollCornerRect() const = 0;
174 void setScrollCornerNeedsPaintInvalidation();
175 virtual void getTickmarks(Vector<IntRect>&) const {}
177 // Convert points and rects between the scrollbar and its containing Widget.
178 // The client needs to implement these in order to be aware of layout effects
179 // like CSS transforms.
180 virtual IntRect convertFromScrollbarToContainingWidget(
181 const Scrollbar& scrollbar,
182 const IntRect& scrollbarRect) const {
183 return scrollbar.Widget::convertToContainingWidget(scrollbarRect);
185 virtual IntRect convertFromContainingWidgetToScrollbar(
186 const Scrollbar& scrollbar,
187 const IntRect& parentRect) const {
188 return scrollbar.Widget::convertFromContainingWidget(parentRect);
190 virtual IntPoint convertFromScrollbarToContainingWidget(
191 const Scrollbar& scrollbar,
192 const IntPoint& scrollbarPoint) const {
193 return scrollbar.Widget::convertToContainingWidget(scrollbarPoint);
195 virtual IntPoint convertFromContainingWidgetToScrollbar(
196 const Scrollbar& scrollbar,
197 const IntPoint& parentPoint) const {
198 return scrollbar.Widget::convertFromContainingWidget(parentPoint);
201 virtual Scrollbar* horizontalScrollbar() const { return nullptr; }
202 virtual Scrollbar* verticalScrollbar() const { return nullptr; }
204 // scrollPosition is the location of the top/left of the scroll viewport in
205 // the coordinate system defined by the top/left of the overflow rect.
206 // scrollOffset is the offset of the scroll viewport from its position when
207 // scrolled all the way to the beginning of its content's flow.
208 // For a more detailed explanation of scrollPosition, scrollOffset, and
209 // scrollOrigin, see core/layout/README.md.
210 FloatPoint scrollPosition() const {
211 return FloatPoint(scrollOrigin()) + scrollOffset();
213 virtual IntSize scrollOffsetInt() const = 0;
214 virtual ScrollOffset scrollOffset() const {
215 return ScrollOffset(scrollOffsetInt());
217 virtual IntSize minimumScrollOffsetInt() const = 0;
218 virtual ScrollOffset minimumScrollOffset() const {
219 return ScrollOffset(minimumScrollOffsetInt());
221 virtual IntSize maximumScrollOffsetInt() const = 0;
222 virtual ScrollOffset maximumScrollOffset() const {
223 return ScrollOffset(maximumScrollOffsetInt());
226 virtual IntRect visibleContentRect(
227 IncludeScrollbarsInRect = ExcludeScrollbars) const;
228 virtual int visibleHeight() const { return visibleContentRect().height(); }
229 virtual int visibleWidth() const { return visibleContentRect().width(); }
230 virtual IntSize contentsSize() const = 0;
231 virtual IntPoint lastKnownMousePosition() const { return IntPoint(); }
233 virtual bool shouldSuspendScrollAnimations() const { return true; }
234 virtual void scrollbarStyleChanged() {}
235 virtual bool scrollbarsCanBeActive() const = 0;
237 // Returns the bounding box of this scrollable area, in the coordinate system
238 // of the enclosing scroll view.
239 virtual IntRect scrollableAreaBoundingBox() const = 0;
241 virtual bool scrollAnimatorEnabled() const { return false; }
243 // NOTE: Only called from Internals for testing.
244 void updateScrollOffsetFromInternals(const IntSize&);
246 IntSize clampScrollOffset(const IntSize&) const;
247 ScrollOffset clampScrollOffset(const ScrollOffset&) const;
249 // Let subclasses provide a way of asking for and servicing scroll
251 virtual bool scheduleAnimation();
252 virtual void serviceScrollAnimations(double monotonicTime);
253 virtual void updateCompositorScrollAnimations();
254 virtual void registerForAnimation() {}
255 virtual void deregisterForAnimation() {}
257 virtual bool usesCompositedScrolling() const { return false; }
258 virtual bool shouldScrollOnMainThread() const;
260 // Overlay scrollbars can "fade-out" when inactive.
261 virtual bool scrollbarsHidden() const;
262 virtual void setScrollbarsHidden(bool);
264 // Returns true if the GraphicsLayer tree needs to be rebuilt.
265 virtual bool updateAfterCompositingChange() { return false; }
267 virtual bool userInputScrollable(ScrollbarOrientation) const = 0;
268 virtual bool shouldPlaceVerticalScrollbarOnLeft() const = 0;
270 // Convenience functions
271 float scrollOffset(ScrollbarOrientation orientation) {
272 return orientation == HorizontalScrollbar ? scrollOffsetInt().width()
273 : scrollOffsetInt().height();
275 float minimumScrollOffset(ScrollbarOrientation orientation) {
276 return orientation == HorizontalScrollbar ? minimumScrollOffset().width()
277 : minimumScrollOffset().height();
279 float maximumScrollOffset(ScrollbarOrientation orientation) {
280 return orientation == HorizontalScrollbar ? maximumScrollOffset().width()
281 : maximumScrollOffset().height();
283 float clampScrollOffset(ScrollbarOrientation orientation, float offset) {
284 return clampTo(offset, minimumScrollOffset(orientation),
285 maximumScrollOffset(orientation));
288 #if defined(TIZEN_VD_NATIVE_SCROLLBARS)
289 bool useNativeScrollbars() const;
290 virtual void scrollbarSizeDidChange() {}
293 virtual GraphicsLayer* layerForContainer() const;
294 virtual GraphicsLayer* layerForScrolling() const { return 0; }
295 virtual GraphicsLayer* layerForHorizontalScrollbar() const { return 0; }
296 virtual GraphicsLayer* layerForVerticalScrollbar() const { return 0; }
297 virtual GraphicsLayer* layerForScrollCorner() const { return 0; }
298 bool hasLayerForHorizontalScrollbar() const;
299 bool hasLayerForVerticalScrollbar() const;
300 bool hasLayerForScrollCorner() const;
302 void layerForScrollingDidChange(CompositorAnimationTimeline*);
304 void cancelScrollAnimation();
305 virtual void cancelProgrammaticScrollAnimation();
307 virtual ~ScrollableArea();
309 // Called when any of horizontal scrollbar, vertical scrollbar and scroll
310 // corner is setNeedsPaintInvalidation.
311 virtual void scrollControlWasSetNeedsPaintInvalidation() = 0;
313 // Returns the default scroll style this area should scroll with when not
314 // explicitly specified. E.g. The scrolling behavior of an element can be
316 virtual ScrollBehavior scrollBehaviorStyle() const {
317 return ScrollBehaviorInstant;
320 // TODO(bokan): This is only used in FrameView to check scrollability but is
321 // needed here to allow RootFrameViewport to preserve wheelHandler
322 // semantics. Not sure why it's FrameView specific, it could probably be
323 // generalized to other types of ScrollableAreas.
324 virtual bool isScrollable() { return true; }
326 // TODO(bokan): FrameView::setScrollOffset uses updateScrollbars to scroll
327 // which bails out early if its already in updateScrollbars, the effect being
328 // that programmatic scrolls (i.e. setScrollOffset) are disabled when in
329 // updateScrollbars. Expose this here to allow RootFrameViewport to match the
330 // semantics for now but it should be cleaned up at the source.
331 virtual bool isProgrammaticallyScrollable() { return true; }
333 // Subtracts space occupied by this ScrollableArea's scrollbars.
334 // Does nothing if overlay scrollbars are enabled.
335 IntSize excludeScrollbars(const IntSize&) const;
337 virtual int verticalScrollbarWidth(
338 OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const;
339 virtual int horizontalScrollbarHeight(
340 OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const;
342 // Returns the widget associated with this ScrollableArea.
343 virtual Widget* getWidget() { return nullptr; }
345 virtual LayoutBox* layoutBox() const { return nullptr; }
347 // Maps a quad from the coordinate system of a LayoutObject contained by the
348 // ScrollableArea to the coordinate system of the ScrollableArea's visible
349 // content rect. If the LayoutObject* argument is null, the argument quad is
350 // considered to be in the coordinate space of the overflow rect.
351 virtual FloatQuad localToVisibleContentQuad(const FloatQuad&,
355 virtual bool isFrameView() const { return false; }
356 virtual bool isPaintLayerScrollableArea() const { return false; }
357 virtual bool isRootFrameViewport() const { return false; }
359 // Returns true if the scroller adjusts the scroll offset to compensate
360 // for layout movements (bit.ly/scroll-anchoring).
361 virtual bool shouldPerformScrollAnchoring() const { return false; }
363 // Need to promptly let go of owned animator objects.
365 DECLARE_VIRTUAL_TRACE();
367 virtual void clearScrollableArea();
369 virtual ScrollAnchor* scrollAnchor() { return nullptr; }
371 #if defined(OS_TIZEN_TV_PRODUCT)
372 virtual void thumbPartFocusChanged(ScrollbarOrientation, bool) {}
378 ScrollbarOrientation scrollbarOrientationFromDirection(
379 ScrollDirectionPhysical) const;
380 float scrollStep(ScrollGranularity, ScrollbarOrientation) const;
382 void setScrollOrigin(const IntPoint&);
383 void resetScrollOriginChanged() { m_scrollOriginChanged = false; }
385 // Needed to let the animators call scrollOffsetChanged.
386 friend class ScrollAnimatorCompositorCoordinator;
387 void scrollOffsetChanged(const ScrollOffset&, ScrollType);
389 bool horizontalScrollbarNeedsPaintInvalidation() const {
390 return m_horizontalScrollbarNeedsPaintInvalidation;
392 bool verticalScrollbarNeedsPaintInvalidation() const {
393 return m_verticalScrollbarNeedsPaintInvalidation;
395 bool scrollCornerNeedsPaintInvalidation() const {
396 return m_scrollCornerNeedsPaintInvalidation;
398 void clearNeedsPaintInvalidationForScrollControls() {
399 m_horizontalScrollbarNeedsPaintInvalidation = false;
400 m_verticalScrollbarNeedsPaintInvalidation = false;
401 m_scrollCornerNeedsPaintInvalidation = false;
403 void showOverlayScrollbars();
405 // Called when scrollbar hides/shows for overlay scrollbars. This callback
406 // shouldn't do any significant work as it can be called unexpectadly often
407 // on Mac. This happens because painting code has to set alpha to 1, paint,
408 // then reset to alpha, causing spurrious "visibilityChanged" calls.
409 virtual void scrollbarVisibilityChanged() {}
412 void programmaticScrollHelper(const ScrollOffset&, ScrollBehavior);
413 void userScrollHelper(const ScrollOffset&, ScrollBehavior);
415 void fadeOverlayScrollbarsTimerFired(TimerBase*);
417 // This function should be overriden by subclasses to perform the actual
418 // scroll of the content.
419 virtual void updateScrollOffset(const ScrollOffset&, ScrollType) = 0;
421 virtual int lineStep(ScrollbarOrientation) const;
422 virtual int pageStep(ScrollbarOrientation) const;
423 virtual int documentStep(ScrollbarOrientation) const;
424 virtual float pixelStep(ScrollbarOrientation) const;
426 mutable Member<ScrollAnimatorBase> m_scrollAnimator;
427 mutable Member<ProgrammaticScrollAnimator> m_programmaticScrollAnimator;
429 std::unique_ptr<Timer<ScrollableArea>> m_fadeOverlayScrollbarsTimer;
431 unsigned m_scrollbarOverlayColorTheme : 2;
433 unsigned m_scrollOriginChanged : 1;
435 unsigned m_horizontalScrollbarNeedsPaintInvalidation : 1;
436 unsigned m_verticalScrollbarNeedsPaintInvalidation : 1;
437 unsigned m_scrollCornerNeedsPaintInvalidation : 1;
438 unsigned m_scrollbarsHidden : 1;
439 unsigned m_scrollbarCaptured : 1;
441 // There are 6 possible combinations of writing mode and direction. Scroll
442 // origin will be non-zero in the x or y axis if there is any reversed
443 // direction or writing-mode. The combinations are:
444 // writing-mode / direction scrollOrigin.x() set scrollOrigin.y() set
445 // horizontal-tb / ltr NO NO
446 // horizontal-tb / rtl YES NO
447 // vertical-lr / ltr NO NO
448 // vertical-lr / rtl NO YES
449 // vertical-rl / ltr YES NO
450 // vertical-rl / rtl YES YES
451 IntPoint m_scrollOrigin;
456 #endif // ScrollableArea_h