• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008 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 COMPUTER, 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 COMPUTER, 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 #include "config.h"
27 #include "platform/scroll/ScrollView.h"
28 
29 #include "platform/graphics/GraphicsContextStateSaver.h"
30 #include "platform/graphics/GraphicsLayer.h"
31 #include "platform/HostWindow.h"
32 #include "platform/scroll/ScrollbarTheme.h"
33 #include "wtf/StdLibExtras.h"
34 
35 using namespace std;
36 
37 namespace WebCore {
38 
ScrollView()39 ScrollView::ScrollView()
40     : m_horizontalScrollbarMode(ScrollbarAuto)
41     , m_verticalScrollbarMode(ScrollbarAuto)
42     , m_horizontalScrollbarLock(false)
43     , m_verticalScrollbarLock(false)
44     , m_canBlitOnScroll(true)
45     , m_scrollbarsAvoidingResizer(0)
46     , m_scrollbarsSuppressed(false)
47     , m_inUpdateScrollbars(false)
48     , m_updateScrollbarsPass(0)
49     , m_drawPanScrollIcon(false)
50     , m_paintsEntireContents(false)
51     , m_clipsRepaints(true)
52 {
53 }
54 
~ScrollView()55 ScrollView::~ScrollView()
56 {
57 }
58 
addChild(PassRefPtr<Widget> prpChild)59 void ScrollView::addChild(PassRefPtr<Widget> prpChild)
60 {
61     Widget* child = prpChild.get();
62     ASSERT(child != this && !child->parent());
63     child->setParent(this);
64     m_children.add(prpChild);
65 }
66 
removeChild(Widget * child)67 void ScrollView::removeChild(Widget* child)
68 {
69     ASSERT(child->parent() == this);
70     child->setParent(0);
71     m_children.remove(child);
72 }
73 
setHasHorizontalScrollbar(bool hasBar)74 void ScrollView::setHasHorizontalScrollbar(bool hasBar)
75 {
76     if (hasBar && !m_horizontalScrollbar) {
77         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
78         addChild(m_horizontalScrollbar.get());
79         didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
80         m_horizontalScrollbar->styleChanged();
81     } else if (!hasBar && m_horizontalScrollbar) {
82         willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
83         removeChild(m_horizontalScrollbar.get());
84         m_horizontalScrollbar = 0;
85     }
86 }
87 
setHasVerticalScrollbar(bool hasBar)88 void ScrollView::setHasVerticalScrollbar(bool hasBar)
89 {
90     if (hasBar && !m_verticalScrollbar) {
91         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
92         addChild(m_verticalScrollbar.get());
93         didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
94         m_verticalScrollbar->styleChanged();
95     } else if (!hasBar && m_verticalScrollbar) {
96         willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
97         removeChild(m_verticalScrollbar.get());
98         m_verticalScrollbar = 0;
99     }
100 }
101 
createScrollbar(ScrollbarOrientation orientation)102 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
103 {
104     return Scrollbar::create(this, orientation, RegularScrollbar);
105 }
106 
setScrollbarModes(ScrollbarMode horizontalMode,ScrollbarMode verticalMode,bool horizontalLock,bool verticalLock)107 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
108                                    bool horizontalLock, bool verticalLock)
109 {
110     bool needsUpdate = false;
111 
112     if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
113         m_horizontalScrollbarMode = horizontalMode;
114         needsUpdate = true;
115     }
116 
117     if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
118         m_verticalScrollbarMode = verticalMode;
119         needsUpdate = true;
120     }
121 
122     if (horizontalLock)
123         setHorizontalScrollbarLock();
124 
125     if (verticalLock)
126         setVerticalScrollbarLock();
127 
128     if (!needsUpdate)
129         return;
130 
131     updateScrollbars(scrollOffset());
132 
133     if (!layerForScrolling())
134         return;
135     blink::WebLayer* layer = layerForScrolling()->platformLayer();
136     if (!layer)
137         return;
138     layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInputScrollable(VerticalScrollbar));
139 }
140 
scrollbarModes(ScrollbarMode & horizontalMode,ScrollbarMode & verticalMode) const141 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
142 {
143     horizontalMode = m_horizontalScrollbarMode;
144     verticalMode = m_verticalScrollbarMode;
145 }
146 
setCanHaveScrollbars(bool canScroll)147 void ScrollView::setCanHaveScrollbars(bool canScroll)
148 {
149     ScrollbarMode newHorizontalMode;
150     ScrollbarMode newVerticalMode;
151 
152     scrollbarModes(newHorizontalMode, newVerticalMode);
153 
154     if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
155         newVerticalMode = ScrollbarAuto;
156     else if (!canScroll)
157         newVerticalMode = ScrollbarAlwaysOff;
158 
159     if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
160         newHorizontalMode = ScrollbarAuto;
161     else if (!canScroll)
162         newHorizontalMode = ScrollbarAlwaysOff;
163 
164     setScrollbarModes(newHorizontalMode, newVerticalMode);
165 }
166 
setCanBlitOnScroll(bool b)167 void ScrollView::setCanBlitOnScroll(bool b)
168 {
169     m_canBlitOnScroll = b;
170 }
171 
canBlitOnScroll() const172 bool ScrollView::canBlitOnScroll() const
173 {
174     return m_canBlitOnScroll;
175 }
176 
setPaintsEntireContents(bool paintsEntireContents)177 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
178 {
179     m_paintsEntireContents = paintsEntireContents;
180 }
181 
setClipsRepaints(bool clipsRepaints)182 void ScrollView::setClipsRepaints(bool clipsRepaints)
183 {
184     m_clipsRepaints = clipsRepaints;
185 }
186 
unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const187 IntSize ScrollView::unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const
188 {
189     return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect().size()) : frameRect().size();
190 }
191 
excludeScrollbars(const IntSize & size) const192 IntSize ScrollView::excludeScrollbars(const IntSize& size) const
193 {
194     int verticalScrollbarWidth = 0;
195     int horizontalScrollbarHeight = 0;
196 
197     if (Scrollbar* verticalBar = verticalScrollbar())
198         verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
199     if (Scrollbar* horizontalBar = horizontalScrollbar())
200         horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
201 
202     return IntSize(max(0, size.width() - verticalScrollbarWidth),
203         max(0, size.height() - horizontalScrollbarHeight));
204 
205 }
206 
visibleContentRect(IncludeScrollbarsInRect scollbarInclusion) const207 IntRect ScrollView::visibleContentRect(IncludeScrollbarsInRect scollbarInclusion) const
208 {
209     FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion);
210     visibleContentSize.scale(1 / visibleContentScaleFactor());
211     return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize));
212 }
213 
contentsSize() const214 IntSize ScrollView::contentsSize() const
215 {
216     return m_contentsSize;
217 }
218 
setContentsSize(const IntSize & newSize)219 void ScrollView::setContentsSize(const IntSize& newSize)
220 {
221     if (contentsSize() == newSize)
222         return;
223     m_contentsSize = newSize;
224     updateScrollbars(scrollOffset());
225     updateOverhangAreas();
226 }
227 
maximumScrollPosition() const228 IntPoint ScrollView::maximumScrollPosition() const
229 {
230     IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), contentsHeight() - visibleHeight() - scrollOrigin().y());
231     maximumOffset.clampNegativeToZero();
232     return maximumOffset;
233 }
234 
minimumScrollPosition() const235 IntPoint ScrollView::minimumScrollPosition() const
236 {
237     return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
238 }
239 
adjustScrollPositionWithinRange(const IntPoint & scrollPoint) const240 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
241 {
242     if (!constrainsScrollingToContentEdge())
243         return scrollPoint;
244 
245     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
246     newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
247     return newScrollPosition;
248 }
249 
scrollSize(ScrollbarOrientation orientation) const250 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
251 {
252     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
253 
254     // If no scrollbars are present, the content may still be scrollable.
255     if (!scrollbar) {
256         IntSize scrollSize = m_contentsSize - visibleContentRect().size();
257         scrollSize.clampNegativeToZero();
258         return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
259     }
260 
261     return scrollbar->totalSize() - scrollbar->visibleSize();
262 }
263 
notifyPageThatContentAreaWillPaint() const264 void ScrollView::notifyPageThatContentAreaWillPaint() const
265 {
266 }
267 
setScrollOffset(const IntPoint & offset)268 void ScrollView::setScrollOffset(const IntPoint& offset)
269 {
270     scrollTo(toIntSize(adjustScrollPositionWithinRange(offset)));
271 }
272 
scrollTo(const IntSize & newOffset)273 void ScrollView::scrollTo(const IntSize& newOffset)
274 {
275     IntSize scrollDelta = newOffset - m_scrollOffset;
276     if (scrollDelta == IntSize())
277         return;
278     m_scrollOffset = newOffset;
279 
280     if (scrollbarsSuppressed())
281         return;
282 
283     repaintFixedElementsAfterScrolling();
284     scrollContents(scrollDelta);
285     updateFixedElementsAfterScrolling();
286 }
287 
setScrollPosition(const IntPoint & scrollPoint)288 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
289 {
290     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
291 
292     if (newScrollPosition == scrollPosition())
293         return;
294 
295     updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
296 }
297 
scroll(ScrollDirection direction,ScrollGranularity granularity)298 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
299 {
300     ScrollDirection physicalDirection =
301         toPhysicalDirection(direction, isVerticalDocument(), isFlippedDocument());
302 
303     return ScrollableArea::scroll(physicalDirection, granularity);
304 }
305 
overhangAmount() const306 IntSize ScrollView::overhangAmount() const
307 {
308     IntSize stretch;
309 
310     IntPoint currentScrollPosition = scrollPosition();
311     IntPoint minScrollPosition = minimumScrollPosition();
312     IntPoint maxScrollPosition = maximumScrollPosition();
313 
314     if (currentScrollPosition.x() < minScrollPosition.x())
315         stretch.setWidth(currentScrollPosition.x() - minScrollPosition.x());
316     if (currentScrollPosition.x() > maxScrollPosition.x())
317         stretch.setWidth(currentScrollPosition.x() - maxScrollPosition.x());
318 
319     if (currentScrollPosition.y() < minScrollPosition.y())
320         stretch.setHeight(currentScrollPosition.y() - minScrollPosition.y());
321     if (currentScrollPosition.y() > maxScrollPosition.y())
322         stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y());
323 
324     return stretch;
325 }
326 
windowResizerRectChanged()327 void ScrollView::windowResizerRectChanged()
328 {
329     updateScrollbars(scrollOffset());
330 }
331 
332 static const unsigned cMaxUpdateScrollbarsPass = 2;
333 
updateScrollbars(const IntSize & desiredOffset)334 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
335 {
336     if (m_inUpdateScrollbars)
337         return;
338 
339     // If we came in here with the view already needing a layout, then go ahead and do that
340     // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
341     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
342     if (!m_scrollbarsSuppressed) {
343         m_inUpdateScrollbars = true;
344         scrollbarExistenceDidChange();
345         m_inUpdateScrollbars = false;
346     }
347 
348     IntRect oldScrollCornerRect = scrollCornerRect();
349 
350     bool hasHorizontalScrollbar = m_horizontalScrollbar;
351     bool hasVerticalScrollbar = m_verticalScrollbar;
352 
353     bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
354     bool newHasVerticalScrollbar = hasVerticalScrollbar;
355 
356     ScrollbarMode hScroll = m_horizontalScrollbarMode;
357     ScrollbarMode vScroll = m_verticalScrollbarMode;
358 
359     if (hScroll != ScrollbarAuto)
360         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
361     if (vScroll != ScrollbarAuto)
362         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
363 
364     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
365         if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
366             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
367         if (hasVerticalScrollbar != newHasVerticalScrollbar)
368             setHasVerticalScrollbar(newHasVerticalScrollbar);
369     } else {
370         bool scrollbarExistenceChanged = false;
371 
372         IntSize docSize = contentsSize();
373         IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size();
374 
375         bool scrollbarsAreOverlay = ScrollbarTheme::theme()->usesOverlayScrollbars();
376 
377         if (hScroll == ScrollbarAuto) {
378             newHasHorizontalScrollbar = docSize.width() > visibleWidth();
379             if (!scrollbarsAreOverlay && newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height())
380                 newHasHorizontalScrollbar = false;
381         }
382         if (vScroll == ScrollbarAuto) {
383             newHasVerticalScrollbar = docSize.height() > visibleHeight();
384             if (!scrollbarsAreOverlay && newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height())
385                 newHasVerticalScrollbar = false;
386         }
387 
388         if (!scrollbarsAreOverlay) {
389             // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
390             // try to both gain/lose a scrollbar in the same pass.
391             if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
392                 newHasVerticalScrollbar = false;
393             if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
394                 newHasHorizontalScrollbar = false;
395         }
396 
397         if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
398             scrollbarExistenceChanged = true;
399             if (scrollOrigin().y() && !newHasHorizontalScrollbar && !scrollbarsAreOverlay)
400                 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x(), scrollOrigin().y() - m_horizontalScrollbar->height()));
401             if (hasHorizontalScrollbar)
402                 m_horizontalScrollbar->invalidate();
403             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
404         }
405 
406         if (hasVerticalScrollbar != newHasVerticalScrollbar) {
407             scrollbarExistenceChanged = true;
408             if (scrollOrigin().x() && !newHasVerticalScrollbar && !scrollbarsAreOverlay)
409                 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x() - m_verticalScrollbar->width(), scrollOrigin().y()));
410             if (hasVerticalScrollbar)
411                 m_verticalScrollbar->invalidate();
412             setHasVerticalScrollbar(newHasVerticalScrollbar);
413         }
414 
415         if (scrollbarExistenceChanged) {
416             if (scrollbarsAreOverlay) {
417                 // Synchronize status of scrollbar layers if necessary.
418                 m_inUpdateScrollbars = true;
419                 scrollbarExistenceDidChange();
420                 m_inUpdateScrollbars = false;
421             } else if (m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
422                 m_updateScrollbarsPass++;
423                 contentsResized();
424                 scrollbarExistenceDidChange();
425                 IntSize newDocSize = contentsSize();
426                 if (newDocSize == docSize) {
427                     // The layout with the new scroll state had no impact on
428                     // the document's overall size, so updateScrollbars didn't get called.
429                     // Recur manually.
430                     updateScrollbars(desiredOffset);
431                 }
432                 m_updateScrollbarsPass--;
433             }
434         }
435     }
436 
437     // Set up the range, but only do this if we're not in a nested call (to avoid
438     // doing it multiple times).
439     if (m_updateScrollbarsPass)
440         return;
441 
442     m_inUpdateScrollbars = true;
443 
444     if (m_horizontalScrollbar) {
445         int clientWidth = visibleWidth();
446         IntRect oldRect(m_horizontalScrollbar->frameRect());
447         IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScrollbar) ? m_verticalScrollbar->width() : 0,
448                         height() - m_horizontalScrollbar->height(),
449                         width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
450                         m_horizontalScrollbar->height());
451         m_horizontalScrollbar->setFrameRect(hBarRect);
452         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
453             m_horizontalScrollbar->invalidate();
454 
455         if (m_scrollbarsSuppressed)
456             m_horizontalScrollbar->setSuppressInvalidation(true);
457         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
458         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
459         if (m_scrollbarsSuppressed)
460             m_horizontalScrollbar->setSuppressInvalidation(false);
461     }
462 
463     if (m_verticalScrollbar) {
464         int clientHeight = visibleHeight();
465         IntRect oldRect(m_verticalScrollbar->frameRect());
466         IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
467                          0,
468                          m_verticalScrollbar->width(),
469                          height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
470         m_verticalScrollbar->setFrameRect(vBarRect);
471         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
472             m_verticalScrollbar->invalidate();
473 
474         if (m_scrollbarsSuppressed)
475             m_verticalScrollbar->setSuppressInvalidation(true);
476         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
477         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
478         if (m_scrollbarsSuppressed)
479             m_verticalScrollbar->setSuppressInvalidation(false);
480     }
481 
482     if (hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar) {
483         // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
484         frameRectsChanged();
485         positionScrollbarLayers();
486         updateScrollCorner();
487         if (!m_horizontalScrollbar && !m_verticalScrollbar)
488             invalidateScrollCornerRect(oldScrollCornerRect);
489     }
490 
491     IntPoint adjustedScrollPosition = IntPoint(desiredOffset);
492     if (!isRubberBandInProgress())
493         adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
494 
495     if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) {
496         ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition);
497         resetScrollOriginChanged();
498     }
499 
500     // Make sure the scrollbar offsets are up to date.
501     if (m_horizontalScrollbar)
502         m_horizontalScrollbar->offsetDidChange();
503     if (m_verticalScrollbar)
504         m_verticalScrollbar->offsetDidChange();
505 
506     m_inUpdateScrollbars = false;
507 }
508 
509 const int panIconSizeLength = 16;
510 
rectToCopyOnScroll() const511 IntRect ScrollView::rectToCopyOnScroll() const
512 {
513     IntRect scrollViewRect = convertToRootView(IntRect((shouldPlaceVerticalScrollbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visibleWidth(), visibleHeight()));
514     if (hasOverlayScrollbars()) {
515         int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
516         int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
517 
518         scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
519         scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
520     }
521     return scrollViewRect;
522 }
523 
scrollContents(const IntSize & scrollDelta)524 void ScrollView::scrollContents(const IntSize& scrollDelta)
525 {
526     HostWindow* window = hostWindow();
527     if (!window)
528         return;
529 
530     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
531     // with the clip rect every time to keep it smooth.
532     IntRect clipRect = windowClipRect();
533     IntRect scrollViewRect = rectToCopyOnScroll();
534     IntRect updateRect = clipRect;
535     updateRect.intersect(scrollViewRect);
536 
537     if (m_drawPanScrollIcon) {
538         // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
539         // https://bugs.webkit.org/show_bug.cgi?id=47837
540         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
541         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
542         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
543         panScrollIconDirtyRect.intersect(clipRect);
544         window->invalidateContentsAndRootView(panScrollIconDirtyRect);
545     }
546 
547     if (canBlitOnScroll()) { // The main frame can just blit the WebView window
548         // FIXME: Find a way to scroll subframes with this faster path
549         if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
550             scrollContentsSlowPath(updateRect);
551     } else {
552        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
553        // windowed plugins.
554        scrollContentsSlowPath(updateRect);
555     }
556 
557     // Invalidate the overhang areas if they are visible.
558     updateOverhangAreas();
559 
560     // This call will move children with native widgets (plugins) and invalidate them as well.
561     frameRectsChanged();
562 }
563 
scrollContentsFastPath(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)564 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
565 {
566     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
567     return true;
568 }
569 
scrollContentsSlowPath(const IntRect & updateRect)570 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
571 {
572     hostWindow()->invalidateContentsForSlowScroll(updateRect);
573 }
574 
rootViewToContents(const IntPoint & rootViewPoint) const575 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const
576 {
577     IntPoint viewPoint = convertFromRootView(rootViewPoint);
578     return viewPoint + scrollOffset();
579 }
580 
contentsToRootView(const IntPoint & contentsPoint) const581 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const
582 {
583     IntPoint viewPoint = contentsPoint - scrollOffset();
584     return convertToRootView(viewPoint);
585 }
586 
rootViewToContents(const IntRect & rootViewRect) const587 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const
588 {
589     IntRect viewRect = convertFromRootView(rootViewRect);
590     viewRect.move(scrollOffset());
591     return viewRect;
592 }
593 
contentsToRootView(const IntRect & contentsRect) const594 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const
595 {
596     IntRect viewRect = contentsRect;
597     viewRect.move(-scrollOffset());
598     return convertToRootView(viewRect);
599 }
600 
windowToContents(const IntPoint & windowPoint) const601 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
602 {
603     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
604     return viewPoint + scrollOffset();
605 }
606 
contentsToWindow(const IntPoint & contentsPoint) const607 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
608 {
609     IntPoint viewPoint = contentsPoint - scrollOffset();
610     return convertToContainingWindow(viewPoint);
611 }
612 
windowToContents(const IntRect & windowRect) const613 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
614 {
615     IntRect viewRect = convertFromContainingWindow(windowRect);
616     viewRect.move(scrollOffset());
617     return viewRect;
618 }
619 
contentsToWindow(const IntRect & contentsRect) const620 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
621 {
622     IntRect viewRect = contentsRect;
623     viewRect.move(-scrollOffset());
624     return convertToContainingWindow(viewRect);
625 }
626 
contentsToScreen(const IntRect & rect) const627 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
628 {
629     HostWindow* window = hostWindow();
630     if (!window)
631         return IntRect();
632     return window->rootViewToScreen(contentsToRootView(rect));
633 }
634 
screenToContents(const IntPoint & point) const635 IntPoint ScrollView::screenToContents(const IntPoint& point) const
636 {
637     HostWindow* window = hostWindow();
638     if (!window)
639         return IntPoint();
640     return rootViewToContents(window->screenToRootView(point));
641 }
642 
containsScrollbarsAvoidingResizer() const643 bool ScrollView::containsScrollbarsAvoidingResizer() const
644 {
645     return !m_scrollbarsAvoidingResizer;
646 }
647 
adjustScrollbarsAvoidingResizerCount(int overlapDelta)648 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
649 {
650     int oldCount = m_scrollbarsAvoidingResizer;
651     m_scrollbarsAvoidingResizer += overlapDelta;
652     if (parent())
653         toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(overlapDelta);
654     else if (!scrollbarsSuppressed()) {
655         // If we went from n to 0 or from 0 to n and we're the outermost view,
656         // we need to invalidate the windowResizerRect(), since it will now need to paint
657         // differently.
658         if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
659             (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
660             invalidateRect(windowResizerRect());
661     }
662 }
663 
setParent(Widget * parentView)664 void ScrollView::setParent(Widget* parentView)
665 {
666     if (parentView == parent())
667         return;
668 
669     if (m_scrollbarsAvoidingResizer && parent())
670         toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
671 
672     Widget::setParent(parentView);
673 
674     if (m_scrollbarsAvoidingResizer && parent())
675         toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
676 }
677 
setScrollbarsSuppressed(bool suppressed,bool repaintOnUnsuppress)678 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
679 {
680     if (suppressed == m_scrollbarsSuppressed)
681         return;
682 
683     m_scrollbarsSuppressed = suppressed;
684 
685     if (repaintOnUnsuppress && !suppressed) {
686         if (m_horizontalScrollbar)
687             m_horizontalScrollbar->invalidate();
688         if (m_verticalScrollbar)
689             m_verticalScrollbar->invalidate();
690 
691         // Invalidate the scroll corner too on unsuppress.
692         invalidateRect(scrollCornerRect());
693     }
694 }
695 
scrollbarAtPoint(const IntPoint & windowPoint)696 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
697 {
698     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
699     if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint))
700         return m_horizontalScrollbar.get();
701     if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint))
702         return m_verticalScrollbar.get();
703     return 0;
704 }
705 
setFrameRect(const IntRect & newRect)706 void ScrollView::setFrameRect(const IntRect& newRect)
707 {
708     IntRect oldRect = frameRect();
709 
710     if (newRect == oldRect)
711         return;
712 
713     Widget::setFrameRect(newRect);
714 
715     updateScrollbars(scrollOffset());
716 
717     frameRectsChanged();
718 }
719 
frameRectsChanged()720 void ScrollView::frameRectsChanged()
721 {
722     HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
723     for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
724         (*current)->frameRectsChanged();
725 }
726 
clipRectChanged()727 void ScrollView::clipRectChanged()
728 {
729     HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
730     for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
731         (*current)->clipRectChanged();
732 }
733 
positionScrollbarLayer(GraphicsLayer * graphicsLayer,Scrollbar * scrollbar)734 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
735 {
736     if (!graphicsLayer || !scrollbar)
737         return;
738 
739     IntRect scrollbarRect = scrollbar->frameRect();
740     graphicsLayer->setPosition(scrollbarRect.location());
741 
742     if (scrollbarRect.size() == graphicsLayer->size())
743         return;
744 
745     graphicsLayer->setSize(scrollbarRect.size());
746 
747     if (graphicsLayer->hasContentsLayer()) {
748         graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
749         return;
750     }
751 
752     graphicsLayer->setDrawsContent(true);
753     graphicsLayer->setNeedsDisplay();
754 }
755 
positionScrollCornerLayer(GraphicsLayer * graphicsLayer,const IntRect & cornerRect)756 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
757 {
758     if (!graphicsLayer)
759         return;
760     graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
761     graphicsLayer->setPosition(cornerRect.location());
762     if (cornerRect.size() != graphicsLayer->size())
763         graphicsLayer->setNeedsDisplay();
764     graphicsLayer->setSize(cornerRect.size());
765 }
766 
positionScrollbarLayers()767 void ScrollView::positionScrollbarLayers()
768 {
769     positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
770     positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
771     positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
772 }
773 
userInputScrollable(ScrollbarOrientation orientation) const774 bool ScrollView::userInputScrollable(ScrollbarOrientation orientation) const
775 {
776     ScrollbarMode mode = (orientation == HorizontalScrollbar) ?
777         m_horizontalScrollbarMode : m_verticalScrollbarMode;
778 
779     return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn;
780 }
781 
shouldPlaceVerticalScrollbarOnLeft() const782 bool ScrollView::shouldPlaceVerticalScrollbarOnLeft() const
783 {
784     return false;
785 }
786 
repaintContentRectangle(const IntRect & rect)787 void ScrollView::repaintContentRectangle(const IntRect& rect)
788 {
789     IntRect paintRect = rect;
790     if (clipsRepaints() && !paintsEntireContents())
791         paintRect.intersect(visibleContentRect());
792     if (paintRect.isEmpty())
793         return;
794 
795     if (HostWindow* window = hostWindow())
796         window->invalidateContentsAndRootView(contentsToWindow(paintRect));
797 }
798 
scrollCornerRect() const799 IntRect ScrollView::scrollCornerRect() const
800 {
801     IntRect cornerRect;
802 
803     if (hasOverlayScrollbars())
804         return cornerRect;
805 
806     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
807         cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_horizontalScrollbar->width(),
808                                  height() - m_horizontalScrollbar->height(),
809                                  width() - m_horizontalScrollbar->width(),
810                                  m_horizontalScrollbar->height()));
811     }
812 
813     if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
814         cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
815                                  m_verticalScrollbar->height(),
816                                  m_verticalScrollbar->width(),
817                                  height() - m_verticalScrollbar->height()));
818     }
819 
820     return cornerRect;
821 }
822 
isScrollCornerVisible() const823 bool ScrollView::isScrollCornerVisible() const
824 {
825     return !scrollCornerRect().isEmpty();
826 }
827 
scrollbarStyleChanged(int,bool forceUpdate)828 void ScrollView::scrollbarStyleChanged(int, bool forceUpdate)
829 {
830     if (!forceUpdate)
831         return;
832 
833     contentsResized();
834     updateScrollbars(scrollOffset());
835     positionScrollbarLayers();
836 }
837 
updateScrollCorner()838 void ScrollView::updateScrollCorner()
839 {
840 }
841 
paintScrollCorner(GraphicsContext * context,const IntRect & cornerRect)842 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
843 {
844     ScrollbarTheme::theme()->paintScrollCorner(context, cornerRect);
845 }
846 
paintScrollbar(GraphicsContext * context,Scrollbar * bar,const IntRect & rect)847 void ScrollView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
848 {
849     bar->paint(context, rect);
850 }
851 
invalidateScrollCornerRect(const IntRect & rect)852 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
853 {
854     invalidateRect(rect);
855 }
856 
paintScrollbars(GraphicsContext * context,const IntRect & rect)857 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
858 {
859     if (m_horizontalScrollbar && !layerForHorizontalScrollbar())
860         paintScrollbar(context, m_horizontalScrollbar.get(), rect);
861     if (m_verticalScrollbar && !layerForVerticalScrollbar())
862         paintScrollbar(context, m_verticalScrollbar.get(), rect);
863 
864     if (layerForScrollCorner())
865         return;
866     paintScrollCorner(context, scrollCornerRect());
867 }
868 
paintPanScrollIcon(GraphicsContext * context)869 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
870 {
871     DEFINE_STATIC_REF(Image, panScrollIcon, (Image::loadPlatformResource("panIcon")));
872     IntPoint iconGCPoint = m_panScrollIconPoint;
873     if (parent())
874         iconGCPoint = toScrollView(parent())->windowToContents(iconGCPoint);
875     context->drawImage(panScrollIcon, iconGCPoint);
876 }
877 
paint(GraphicsContext * context,const IntRect & rect)878 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
879 {
880     if (context->paintingDisabled() && !context->updatingControlTints())
881         return;
882 
883     notifyPageThatContentAreaWillPaint();
884 
885     IntRect documentDirtyRect = rect;
886     if (!paintsEntireContents()) {
887         IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect().size());
888         documentDirtyRect.intersect(visibleAreaWithoutScrollbars);
889     }
890 
891     if (!documentDirtyRect.isEmpty()) {
892         GraphicsContextStateSaver stateSaver(*context);
893 
894         context->translate(x(), y());
895         documentDirtyRect.moveBy(-location());
896 
897         if (!paintsEntireContents()) {
898             context->translate(-scrollX(), -scrollY());
899             documentDirtyRect.moveBy(scrollPosition());
900 
901             context->clip(visibleContentRect());
902         }
903 
904         paintContents(context, documentDirtyRect);
905     }
906 
907     calculateAndPaintOverhangAreas(context, rect);
908 
909     // Now paint the scrollbars.
910     if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
911         GraphicsContextStateSaver stateSaver(*context);
912         IntRect scrollViewDirtyRect = rect;
913         IntRect visibleAreaWithScrollbars(location(), visibleContentRect(IncludeScrollbars).size());
914         scrollViewDirtyRect.intersect(visibleAreaWithScrollbars);
915         context->translate(x(), y());
916         scrollViewDirtyRect.moveBy(-location());
917 
918         paintScrollbars(context, scrollViewDirtyRect);
919     }
920 
921     // Paint the panScroll Icon
922     if (m_drawPanScrollIcon)
923         paintPanScrollIcon(context);
924 }
925 
calculateOverhangAreasForPainting(IntRect & horizontalOverhangRect,IntRect & verticalOverhangRect)926 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
927 {
928     int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
929         ? verticalScrollbar()->width() : 0;
930     int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
931         ? horizontalScrollbar()->height() : 0;
932 
933     int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
934     if (physicalScrollY < 0) {
935         horizontalOverhangRect = frameRect();
936         horizontalOverhangRect.setHeight(-physicalScrollY);
937         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
938     } else if (contentsHeight() && physicalScrollY > contentsHeight() - visibleHeight()) {
939         int height = physicalScrollY - (contentsHeight() - visibleHeight());
940         horizontalOverhangRect = frameRect();
941         horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
942         horizontalOverhangRect.setHeight(height);
943         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
944     }
945 
946     int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
947     if (physicalScrollX < 0) {
948         verticalOverhangRect.setWidth(-physicalScrollX);
949         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
950         verticalOverhangRect.setX(frameRect().x());
951         if (horizontalOverhangRect.y() == frameRect().y())
952             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
953         else
954             verticalOverhangRect.setY(frameRect().y());
955     } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
956         int width = physicalScrollX - (contentsWidth() - visibleWidth());
957         verticalOverhangRect.setWidth(width);
958         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
959         verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
960         if (horizontalOverhangRect.y() == frameRect().y())
961             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
962         else
963             verticalOverhangRect.setY(frameRect().y());
964     }
965 }
966 
updateOverhangAreas()967 void ScrollView::updateOverhangAreas()
968 {
969     HostWindow* window = hostWindow();
970     if (!window)
971         return;
972 
973     IntRect horizontalOverhangRect;
974     IntRect verticalOverhangRect;
975     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
976     if (!horizontalOverhangRect.isEmpty())
977         window->invalidateContentsAndRootView(horizontalOverhangRect);
978     if (!verticalOverhangRect.isEmpty())
979         window->invalidateContentsAndRootView(verticalOverhangRect);
980 }
981 
paintOverhangAreas(GraphicsContext * context,const IntRect & horizontalOverhangRect,const IntRect & verticalOverhangRect,const IntRect & dirtyRect)982 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
983 {
984     ScrollbarTheme::theme()->paintOverhangBackground(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
985     ScrollbarTheme::theme()->paintOverhangShadows(context, scrollOffset(), horizontalOverhangRect, verticalOverhangRect, dirtyRect);
986 }
987 
calculateAndPaintOverhangAreas(GraphicsContext * context,const IntRect & dirtyRect)988 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const IntRect& dirtyRect)
989 {
990     IntRect horizontalOverhangRect;
991     IntRect verticalOverhangRect;
992     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
993 
994     if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
995         paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
996 }
997 
calculateAndPaintOverhangBackground(GraphicsContext * context,const IntRect & dirtyRect)998 void ScrollView::calculateAndPaintOverhangBackground(GraphicsContext* context, const IntRect& dirtyRect)
999 {
1000     IntRect horizontalOverhangRect;
1001     IntRect verticalOverhangRect;
1002     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1003 
1004     if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
1005         ScrollbarTheme::theme()->paintOverhangBackground(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1006 }
1007 
isPointInScrollbarCorner(const IntPoint & windowPoint)1008 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1009 {
1010     if (!scrollbarCornerPresent())
1011         return false;
1012 
1013     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1014 
1015     if (m_horizontalScrollbar) {
1016         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1017         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1018         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1019 
1020         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1021     }
1022 
1023     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1024     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1025     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1026 
1027     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1028 }
1029 
scrollbarCornerPresent() const1030 bool ScrollView::scrollbarCornerPresent() const
1031 {
1032     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
1033         || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
1034 }
1035 
convertFromScrollbarToContainingView(const Scrollbar * scrollbar,const IntRect & localRect) const1036 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1037 {
1038     // Scrollbars won't be transformed within us
1039     IntRect newRect = localRect;
1040     newRect.moveBy(scrollbar->location());
1041     return newRect;
1042 }
1043 
convertFromContainingViewToScrollbar(const Scrollbar * scrollbar,const IntRect & parentRect) const1044 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1045 {
1046     IntRect newRect = parentRect;
1047     // Scrollbars won't be transformed within us
1048     newRect.moveBy(-scrollbar->location());
1049     return newRect;
1050 }
1051 
1052 // FIXME: test these on windows
convertFromScrollbarToContainingView(const Scrollbar * scrollbar,const IntPoint & localPoint) const1053 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1054 {
1055     // Scrollbars won't be transformed within us
1056     IntPoint newPoint = localPoint;
1057     newPoint.moveBy(scrollbar->location());
1058     return newPoint;
1059 }
1060 
convertFromContainingViewToScrollbar(const Scrollbar * scrollbar,const IntPoint & parentPoint) const1061 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1062 {
1063     IntPoint newPoint = parentPoint;
1064     // Scrollbars won't be transformed within us
1065     newPoint.moveBy(-scrollbar->location());
1066     return newPoint;
1067 }
1068 
setParentVisible(bool visible)1069 void ScrollView::setParentVisible(bool visible)
1070 {
1071     if (isParentVisible() == visible)
1072         return;
1073 
1074     Widget::setParentVisible(visible);
1075 
1076     if (!isSelfVisible())
1077         return;
1078 
1079     HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1080     for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1081         (*it)->setParentVisible(visible);
1082 }
1083 
show()1084 void ScrollView::show()
1085 {
1086     if (!isSelfVisible()) {
1087         setSelfVisible(true);
1088         if (isParentVisible()) {
1089             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1090             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1091                 (*it)->setParentVisible(true);
1092         }
1093     }
1094 
1095     Widget::show();
1096 }
1097 
hide()1098 void ScrollView::hide()
1099 {
1100     if (isSelfVisible()) {
1101         if (isParentVisible()) {
1102             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1103             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1104                 (*it)->setParentVisible(false);
1105         }
1106         setSelfVisible(false);
1107     }
1108 
1109     Widget::hide();
1110 }
1111 
isOffscreen() const1112 bool ScrollView::isOffscreen() const
1113 {
1114     return !isVisible();
1115 }
1116 
1117 
addPanScrollIcon(const IntPoint & iconPosition)1118 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1119 {
1120     HostWindow* window = hostWindow();
1121     if (!window)
1122         return;
1123     m_drawPanScrollIcon = true;
1124     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1125     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1126 }
1127 
removePanScrollIcon()1128 void ScrollView::removePanScrollIcon()
1129 {
1130     HostWindow* window = hostWindow();
1131     if (!window)
1132         return;
1133     m_drawPanScrollIcon = false;
1134     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1135 }
1136 
setScrollOrigin(const IntPoint & origin,bool updatePositionAtAll,bool updatePositionSynchronously)1137 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1138 {
1139     if (scrollOrigin() == origin)
1140         return;
1141 
1142     ScrollableArea::setScrollOrigin(origin);
1143 
1144     // Update if the scroll origin changes, since our position will be different if the content size did not change.
1145     if (updatePositionAtAll && updatePositionSynchronously)
1146         updateScrollbars(scrollOffset());
1147 }
1148 
pageStep(ScrollbarOrientation orientation) const1149 int ScrollView::pageStep(ScrollbarOrientation orientation) const
1150 {
1151     int length = (orientation == HorizontalScrollbar) ? visibleWidth() : visibleHeight();
1152     int minPageStep = static_cast<float>(length) * minFractionToStepWhenPaging();
1153     int pageStep = std::max(minPageStep, length - maxOverlapBetweenPages());
1154 
1155     return std::max(pageStep, 1);
1156 }
1157 
1158 } // namespace WebCore
1159