2 * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Holger Hans Peter Freyther
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "Scrollbar.h"
32 #include "ScrollableArea.h"
33 #include "ScrollTypes.h"
36 #include <wtf/HashSet.h>
38 #if PLATFORM(MAC) && defined __OBJC__
39 @protocol WebCoreFrameScrollView;
47 class ScrollView : public Widget, public ScrollableArea {
51 // ScrollableArea functions.
52 virtual int scrollSize(ScrollbarOrientation) const OVERRIDE;
53 virtual int scrollPosition(Scrollbar*) const OVERRIDE;
54 virtual void setScrollOffset(const IntPoint&) OVERRIDE;
55 virtual bool isScrollCornerVisible() const OVERRIDE;
56 virtual void scrollbarStyleChanged(int newStyle, bool forceUpdate) OVERRIDE;
58 virtual void notifyPageThatContentAreaWillPaint() const;
60 // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea.
61 virtual void scrollTo(const IntSize& newOffset);
63 // The window thats hosts the ScrollView. The ScrollView will communicate scrolls and repaints to the
64 // host window in the window's coordinate space.
65 virtual HostWindow* hostWindow() const = 0;
67 // Returns a clip rect in host window coordinates. Used to clip the blit on a scroll.
68 virtual IntRect windowClipRect(bool clipToContents = true) const = 0;
70 // Functions for child manipulation and inspection.
71 const HashSet<RefPtr<Widget>>& children() const { return m_children; }
72 virtual void addChild(PassRefPtr<Widget>);
73 virtual void removeChild(Widget*);
75 // If the scroll view does not use a native widget, then it will have cross-platform Scrollbars. These functions
76 // can be used to obtain those scrollbars.
77 virtual Scrollbar* horizontalScrollbar() const OVERRIDE { return m_horizontalScrollbar.get(); }
78 virtual Scrollbar* verticalScrollbar() const OVERRIDE { return m_verticalScrollbar.get(); }
79 bool isScrollViewScrollbar(const Widget* child) const { return horizontalScrollbar() == child || verticalScrollbar() == child; }
81 void positionScrollbarLayers();
83 // Functions for setting and retrieving the scrolling mode in each axis (horizontal/vertical). The mode has values of
84 // AlwaysOff, AlwaysOn, and Auto. AlwaysOff means never show a scrollbar, AlwaysOn means always show a scrollbar.
85 // Auto means show a scrollbar only when one is needed.
86 // Note that for platforms with native widgets, these modes are considered advisory. In other words the underlying native
87 // widget may choose not to honor the requested modes.
88 void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool horizontalLock = false, bool verticalLock = false);
89 void setHorizontalScrollbarMode(ScrollbarMode mode, bool lock = false) { setScrollbarModes(mode, verticalScrollbarMode(), lock, verticalScrollbarLock()); }
90 void setVerticalScrollbarMode(ScrollbarMode mode, bool lock = false) { setScrollbarModes(horizontalScrollbarMode(), mode, horizontalScrollbarLock(), lock); };
91 void scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const;
92 ScrollbarMode horizontalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return horizontal; }
93 ScrollbarMode verticalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return vertical; }
95 void setHorizontalScrollbarLock(bool lock = true) { m_horizontalScrollbarLock = lock; }
96 bool horizontalScrollbarLock() const { return m_horizontalScrollbarLock; }
97 void setVerticalScrollbarLock(bool lock = true) { m_verticalScrollbarLock = lock; }
98 bool verticalScrollbarLock() const { return m_verticalScrollbarLock; }
100 void setScrollingModesLock(bool lock = true) { m_horizontalScrollbarLock = m_verticalScrollbarLock = lock; }
102 virtual void setCanHaveScrollbars(bool);
103 bool canHaveScrollbars() const { return horizontalScrollbarMode() != ScrollbarAlwaysOff || verticalScrollbarMode() != ScrollbarAlwaysOff; }
105 virtual bool avoidScrollbarCreation() const { return false; }
107 virtual void setScrollbarOverlayStyle(ScrollbarOverlayStyle) OVERRIDE;
109 // By default you only receive paint events for the area that is visible. In the case of using a
110 // tiled backing store, this function can be set, so that the view paints the entire contents.
111 bool paintsEntireContents() const { return m_paintsEntireContents; }
112 void setPaintsEntireContents(bool);
114 // By default, paint events are clipped to the visible area. If set to
115 // false, paint events are no longer clipped. paintsEntireContents() implies !clipsRepaints().
116 bool clipsRepaints() const { return m_clipsRepaints; }
117 void setClipsRepaints(bool);
119 // By default programmatic scrolling is handled by WebCore and not by the UI application.
120 // In the case of using a tiled backing store, this mode can be set, so that the scroll requests
121 // are delegated to the UI application.
122 bool delegatesScrolling() const { return m_delegatesScrolling; }
123 void setDelegatesScrolling(bool);
125 // Overridden by FrameView to create custom CSS scrollbars if applicable.
126 virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation);
128 // If the prohibits scrolling flag is set, then all scrolling in the view (even programmatic scrolling) is turned off.
129 void setProhibitsScrolling(bool b) { m_prohibitsScrolling = b; }
130 bool prohibitsScrolling() const { return m_prohibitsScrolling; }
132 // Whether or not a scroll view will blit visible contents when it is scrolled. Blitting is disabled in situations
133 // where it would cause rendering glitches (such as with fixed backgrounds or when the view is partially transparent).
134 void setCanBlitOnScroll(bool);
135 bool canBlitOnScroll() const;
137 // The visible content rect has a location that is the scrolled offset of the document. The width and height are the viewport width
138 // and height. By default the scrollbars themselves are excluded from this rectangle, but an optional boolean argument allows them to be
140 // In the situation the client is responsible for the scrolling (ie. with a tiled backing store) it is possible to use
141 // the setFixedVisibleContentRect instead for the mainframe, though this must be updated manually, e.g just before resuming the page
142 // which usually will happen when panning, pinching and rotation ends, or when scale or position are changed manually.
143 virtual IntRect visibleContentRect(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const OVERRIDE;
144 virtual void setFixedVisibleContentRect(const IntRect& visibleContentRect) { m_fixedVisibleContentRect = visibleContentRect; }
145 IntRect fixedVisibleContentRect() const { return m_fixedVisibleContentRect; }
146 IntSize visibleSize() const { return visibleContentRect().size(); }
147 virtual int visibleWidth() const OVERRIDE { return visibleContentRect().width(); }
148 virtual int visibleHeight() const OVERRIDE { return visibleContentRect().height(); }
150 // visibleContentRect().size() is computed from unscaledVisibleContentSize() divided by the value of visibleContentScaleFactor.
151 // visibleContentScaleFactor is usually 1, except when the setting applyPageScaleFactorInCompositor is true and the
152 // ScrollView is the main frame; in that case, visibleContentScaleFactor is equal to the page's pageScaleFactor.
153 // Ports that don't use pageScaleFactor can treat unscaledVisibleContentSize and visibleContentRect().size() as equivalent.
154 IntSize unscaledVisibleContentSize(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const;
155 virtual float visibleContentScaleFactor() const { return 1; }
157 // Functions for getting/setting the size webkit should use to layout the contents. By default this is the same as the visible
158 // content size. Explicitly setting a layout size value will cause webkit to layout the contents using this size instead.
159 IntSize layoutSize() const;
160 int layoutWidth() const { return layoutSize().width(); }
161 int layoutHeight() const { return layoutSize().height(); }
162 IntSize fixedLayoutSize() const;
163 void setFixedLayoutSize(const IntSize&);
164 bool useFixedLayout() const;
165 void setUseFixedLayout(bool enable);
167 // Functions for getting/setting the size of the document contained inside the ScrollView (as an IntSize or as individual width and height
169 virtual IntSize contentsSize() const OVERRIDE; // Always at least as big as the visibleWidth()/visibleHeight().
170 int contentsWidth() const { return contentsSize().width(); }
171 int contentsHeight() const { return contentsSize().height(); }
172 virtual void setContentsSize(const IntSize&);
174 // Functions for querying the current scrolled position (both as a point, a size, or as individual X and Y values).
175 virtual IntPoint scrollPosition() const OVERRIDE { return visibleContentRect().location(); }
176 IntSize scrollOffset() const { return toIntSize(visibleContentRect().location()); } // Gets the scrolled position as an IntSize. Convenient for adding to other sizes.
177 virtual IntPoint maximumScrollPosition() const OVERRIDE; // The maximum position we can be scrolled to.
178 virtual IntPoint minimumScrollPosition() const OVERRIDE; // The minimum position we can be scrolled to.
179 // Adjust the passed in scroll position to keep it between the minimum and maximum positions.
180 IntPoint adjustScrollPositionWithinRange(const IntPoint&) const;
181 int scrollX() const { return scrollPosition().x(); }
182 int scrollY() const { return scrollPosition().y(); }
184 // scrollOffset() anchors its (0,0) point at the top end of the header if this ScrollableArea
185 // has a header, so it is relative to the totalContentsSize(). scrollOffsetRelativeToDocument()
186 // anchors (0,0) at the top of the Document, which will be beneath any headers, so it is relative
187 // to contentsSize().
188 IntSize scrollOffsetRelativeToDocument() const;
189 IntPoint scrollPositionRelativeToDocument() const;
191 virtual IntSize overhangAmount() const OVERRIDE;
193 void cacheCurrentScrollPosition() { m_cachedScrollPosition = scrollPosition(); }
194 IntPoint cachedScrollPosition() const { return m_cachedScrollPosition; }
196 // Functions for scrolling the view.
197 virtual void setScrollPosition(const IntPoint&);
198 void scrollBy(const IntSize& s) { return setScrollPosition(scrollPosition() + s); }
200 // This function scrolls by lines, pages or pixels.
201 bool scroll(ScrollDirection, ScrollGranularity);
203 // A logical scroll that just ends up calling the corresponding physical scroll() based off the document's writing mode.
204 bool logicalScroll(ScrollLogicalDirection, ScrollGranularity);
206 // Scroll the actual contents of the view (either blitting or invalidating as needed).
207 void scrollContents(const IntSize& scrollDelta);
209 // This gives us a means of blocking painting on our scrollbars until the first layout has occurred.
210 void setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress = false);
211 bool scrollbarsSuppressed() const { return m_scrollbarsSuppressed; }
213 IntPoint rootViewToContents(const IntPoint&) const;
214 IntPoint contentsToRootView(const IntPoint&) const;
215 IntRect rootViewToContents(const IntRect&) const;
216 IntRect contentsToRootView(const IntRect&) const;
218 IntPoint rootViewToTotalContents(const IntPoint&) const;
220 // Event coordinates are assumed to be in the coordinate space of a window that contains
221 // the entire widget hierarchy. It is up to the platform to decide what the precise definition
222 // of containing window is. (For example on Mac it is the containing NSWindow.)
223 IntPoint windowToContents(const IntPoint&) const;
224 IntPoint contentsToWindow(const IntPoint&) const;
225 IntRect windowToContents(const IntRect&) const;
226 IntRect contentsToWindow(const IntRect&) const;
228 // Functions for converting to and from screen coordinates.
229 IntRect contentsToScreen(const IntRect&) const;
230 IntPoint screenToContents(const IntPoint&) const;
232 // The purpose of this function is to answer whether or not the scroll view is currently visible. Animations and painting updates can be suspended if
233 // we know that we are either not in a window right now or if that window is not visible.
234 bool isOffscreen() const;
236 // These functions are used to enable scrollbars to avoid window resizer controls that overlap the scroll view. This happens on Mac
238 virtual IntRect windowResizerRect() const { return IntRect(); }
239 bool containsScrollbarsAvoidingResizer() const;
240 void adjustScrollbarsAvoidingResizerCount(int overlapDelta);
241 void windowResizerRectChanged();
243 virtual void setParent(ScrollView*); // Overridden to update the overlapping scrollbar count.
245 // Called when our frame rect changes (or the rect/scroll position of an ancestor changes).
246 virtual void frameRectsChanged();
248 // Widget override to update our scrollbars and notify our contents of the resize.
249 virtual void setFrameRect(const IntRect&);
251 // Widget override to notify our contents of a cliprect change.
252 virtual void clipRectChanged() OVERRIDE;
254 // For platforms that need to hit test scrollbars from within the engine's event handlers (like Win32).
255 Scrollbar* scrollbarAtPoint(const IntPoint& windowPoint);
257 IntPoint convertChildToSelf(const Widget* child, const IntPoint& point) const
259 IntPoint newPoint = point;
260 if (!isScrollViewScrollbar(child))
261 newPoint = point - scrollOffset();
262 newPoint.moveBy(child->location());
266 IntPoint convertSelfToChild(const Widget* child, const IntPoint& point) const
268 IntPoint newPoint = point;
269 if (!isScrollViewScrollbar(child))
270 newPoint = point + scrollOffset();
271 newPoint.moveBy(-child->location());
275 // Widget override. Handles painting of the contents of the view as well as the scrollbars.
276 virtual void paint(GraphicsContext*, const IntRect&);
277 void paintScrollbars(GraphicsContext*, const IntRect&);
279 // Widget overrides to ensure that our children's visibility status is kept up to date when we get shown and hidden.
282 virtual void setParentVisible(bool);
285 static const int noPanScrollRadius = 15;
286 void addPanScrollIcon(const IntPoint&);
287 void removePanScrollIcon();
288 void paintPanScrollIcon(GraphicsContext*);
290 virtual bool isPointInScrollbarCorner(const IntPoint&);
291 virtual bool scrollbarCornerPresent() const;
292 virtual IntRect scrollCornerRect() const;
293 virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect);
294 virtual void paintScrollbar(GraphicsContext*, Scrollbar*, const IntRect&);
296 virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const OVERRIDE;
297 virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const OVERRIDE;
298 virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const OVERRIDE;
299 virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const OVERRIDE;
301 void calculateAndPaintOverhangAreas(GraphicsContext*, const IntRect& dirtyRect);
303 virtual bool isScrollView() const OVERRIDE { return true; }
308 virtual void repaintContentRectangle(const IntRect&, bool now = false);
309 virtual void paintContents(GraphicsContext*, const IntRect& damageRect) = 0;
311 virtual void paintOverhangAreas(GraphicsContext*, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect);
313 virtual void visibleContentsResized() = 0;
314 virtual void addedOrRemovedScrollbar() = 0;
315 virtual void delegatesScrollingDidChange() { }
316 virtual void fixedLayoutSizeChanged();
318 // These functions are used to create/destroy scrollbars.
319 // They return true if the scrollbar was added or removed.
320 bool setHasHorizontalScrollbar(bool, bool* contentSizeAffected = 0);
321 bool setHasVerticalScrollbar(bool, bool* contentSizeAffected = 0);
323 virtual void updateScrollCorner();
324 virtual void invalidateScrollCornerRect(const IntRect&) OVERRIDE;
326 // Scroll the content by blitting the pixels.
327 virtual bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
328 // Scroll the content by invalidating everything.
329 virtual void scrollContentsSlowPath(const IntRect& updateRect);
331 void setScrollOrigin(const IntPoint&, bool updatePositionAtAll, bool updatePositionSynchronously);
333 // Subclassed by FrameView to check the writing-mode of the document.
334 virtual bool isVerticalDocument() const { return true; }
335 virtual bool isFlippedDocument() const { return false; }
337 // Called to update the scrollbars to accurately reflect the state of the view.
338 void updateScrollbars(const IntSize& desiredOffset);
341 RefPtr<Scrollbar> m_horizontalScrollbar;
342 RefPtr<Scrollbar> m_verticalScrollbar;
343 ScrollbarMode m_horizontalScrollbarMode;
344 ScrollbarMode m_verticalScrollbarMode;
346 bool m_horizontalScrollbarLock;
347 bool m_verticalScrollbarLock;
349 bool m_prohibitsScrolling;
351 HashSet<RefPtr<Widget> > m_children;
353 // This bool is unused on Mac OS because we directly ask the platform widget
354 // whether it is safe to blit on scroll.
355 bool m_canBlitOnScroll;
357 IntRect m_fixedVisibleContentRect;
358 IntSize m_scrollOffset; // FIXME: Would rather store this as a position, but we will wait to make this change until more code is shared.
359 IntPoint m_cachedScrollPosition;
360 IntSize m_fixedLayoutSize;
361 IntSize m_contentsSize;
363 int m_scrollbarsAvoidingResizer;
364 bool m_scrollbarsSuppressed;
366 bool m_inUpdateScrollbars;
367 unsigned m_updateScrollbarsPass;
369 IntPoint m_panScrollIconPoint;
370 bool m_drawPanScrollIcon;
371 bool m_useFixedLayout;
373 bool m_paintsEntireContents;
374 bool m_clipsRepaints;
375 bool m_delegatesScrolling;
380 IntRect rectToCopyOnScroll() const;
382 // Called when the scroll position within this view changes. FrameView overrides this to generate repaint invalidations.
383 virtual void repaintFixedElementsAfterScrolling() { }
384 virtual void updateFixedElementsAfterScrolling() { }
386 void platformAddChild(Widget*);
387 void platformRemoveChild(Widget*);
388 void platformSetScrollbarModes();
389 void platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const;
390 void platformSetCanBlitOnScroll(bool);
391 bool platformCanBlitOnScroll() const;
392 IntRect platformVisibleContentRect(bool includeScrollbars) const;
393 IntSize platformVisibleContentSize(bool includeScrollbars) const;
394 void platformSetContentsSize();
395 IntRect platformContentsToScreen(const IntRect&) const;
396 IntPoint platformScreenToContents(const IntPoint&) const;
397 void platformSetScrollPosition(const IntPoint&);
398 bool platformScroll(ScrollDirection, ScrollGranularity);
399 void platformSetScrollbarsSuppressed(bool repaintOnUnsuppress);
400 void platformRepaintContentRectangle(const IntRect&, bool now);
401 bool platformIsOffscreen() const;
402 void platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle);
404 void platformSetScrollOrigin(const IntPoint&, bool updatePositionAtAll, bool updatePositionSynchronously);
406 void calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect);
407 void updateOverhangAreas();
409 #if PLATFORM(MAC) && defined __OBJC__
411 NSView* documentView() const;
414 NSScrollView<WebCoreFrameScrollView>* scrollView() const;
416 }; // class ScrollView
418 inline ScrollView* toScrollView(Widget* widget)
420 ASSERT(!widget || widget->isScrollView());
421 return static_cast<ScrollView*>(widget);
424 inline const ScrollView* toScrollView(const Widget* widget)
426 ASSERT(!widget || widget->isScrollView());
427 return static_cast<const ScrollView*>(widget);
430 // This will catch anyone doing an unnecessary cast.
431 void toScrollView(const ScrollView*);
433 } // namespace WebCore
435 #endif // ScrollView_h