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 "ScrollView.h"
28 
29 #include "AXObjectCache.h"
30 #include "GraphicsContext.h"
31 #include "GraphicsLayer.h"
32 #include "HostWindow.h"
33 #include "PlatformMouseEvent.h"
34 #include "PlatformWheelEvent.h"
35 #include "ScrollAnimator.h"
36 #include "Scrollbar.h"
37 #include "ScrollbarTheme.h"
38 #include <wtf/StdLibExtras.h>
39 
40 using namespace std;
41 
42 namespace WebCore {
43 
ScrollView()44 ScrollView::ScrollView()
45     : m_horizontalScrollbarMode(ScrollbarAuto)
46     , m_verticalScrollbarMode(ScrollbarAuto)
47     , m_horizontalScrollbarLock(false)
48     , m_verticalScrollbarLock(false)
49     , m_prohibitsScrolling(false)
50     , m_canBlitOnScroll(true)
51     , m_scrollbarsAvoidingResizer(0)
52     , m_scrollbarsSuppressed(false)
53     , m_inUpdateScrollbars(false)
54     , m_updateScrollbarsPass(0)
55     , m_drawPanScrollIcon(false)
56     , m_useFixedLayout(false)
57     , m_paintsEntireContents(false)
58     , m_clipsRepaints(true)
59     , m_delegatesScrolling(false)
60     , m_containsScrollableAreaWithOverlayScrollbars(false)
61 {
62     platformInit();
63 }
64 
~ScrollView()65 ScrollView::~ScrollView()
66 {
67     platformDestroy();
68 }
69 
addChild(PassRefPtr<Widget> prpChild)70 void ScrollView::addChild(PassRefPtr<Widget> prpChild)
71 {
72     Widget* child = prpChild.get();
73     ASSERT(child != this && !child->parent());
74     child->setParent(this);
75     m_children.add(prpChild);
76     if (child->platformWidget())
77         platformAddChild(child);
78 }
79 
removeChild(Widget * child)80 void ScrollView::removeChild(Widget* child)
81 {
82     ASSERT(child->parent() == this);
83     child->setParent(0);
84     m_children.remove(child);
85     if (child->platformWidget())
86         platformRemoveChild(child);
87 }
88 
setHasHorizontalScrollbar(bool hasBar)89 void ScrollView::setHasHorizontalScrollbar(bool hasBar)
90 {
91     if (hasBar && avoidScrollbarCreation())
92         return;
93 
94     if (hasBar && !m_horizontalScrollbar) {
95         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
96         addChild(m_horizontalScrollbar.get());
97         didAddHorizontalScrollbar(m_horizontalScrollbar.get());
98         m_horizontalScrollbar->styleChanged();
99     } else if (!hasBar && m_horizontalScrollbar) {
100         willRemoveHorizontalScrollbar(m_horizontalScrollbar.get());
101         removeChild(m_horizontalScrollbar.get());
102         m_horizontalScrollbar = 0;
103     }
104 
105     if (AXObjectCache::accessibilityEnabled() && axObjectCache())
106         axObjectCache()->handleScrollbarUpdate(this);
107 }
108 
setHasVerticalScrollbar(bool hasBar)109 void ScrollView::setHasVerticalScrollbar(bool hasBar)
110 {
111     if (hasBar && avoidScrollbarCreation())
112         return;
113 
114     if (hasBar && !m_verticalScrollbar) {
115         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
116         addChild(m_verticalScrollbar.get());
117         didAddVerticalScrollbar(m_verticalScrollbar.get());
118         m_verticalScrollbar->styleChanged();
119     } else if (!hasBar && m_verticalScrollbar) {
120         willRemoveVerticalScrollbar(m_verticalScrollbar.get());
121         removeChild(m_verticalScrollbar.get());
122         m_verticalScrollbar = 0;
123     }
124 
125     if (AXObjectCache::accessibilityEnabled() && axObjectCache())
126         axObjectCache()->handleScrollbarUpdate(this);
127 }
128 
129 #if !PLATFORM(GTK)
createScrollbar(ScrollbarOrientation orientation)130 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
131 {
132     return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
133 }
134 
setScrollbarModes(ScrollbarMode horizontalMode,ScrollbarMode verticalMode,bool horizontalLock,bool verticalLock)135 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
136                                    bool horizontalLock, bool verticalLock)
137 {
138     bool needsUpdate = false;
139 
140     if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
141         m_horizontalScrollbarMode = horizontalMode;
142         needsUpdate = true;
143     }
144 
145     if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
146         m_verticalScrollbarMode = verticalMode;
147         needsUpdate = true;
148     }
149 
150     if (horizontalLock)
151         setHorizontalScrollbarLock();
152 
153     if (verticalLock)
154         setVerticalScrollbarLock();
155 
156     if (!needsUpdate)
157         return;
158 
159     if (platformWidget())
160         platformSetScrollbarModes();
161     else
162         updateScrollbars(scrollOffset());
163 }
164 #endif
165 
scrollbarModes(ScrollbarMode & horizontalMode,ScrollbarMode & verticalMode) const166 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
167 {
168     if (platformWidget()) {
169         platformScrollbarModes(horizontalMode, verticalMode);
170         return;
171     }
172     horizontalMode = m_horizontalScrollbarMode;
173     verticalMode = m_verticalScrollbarMode;
174 }
175 
setCanHaveScrollbars(bool canScroll)176 void ScrollView::setCanHaveScrollbars(bool canScroll)
177 {
178     ScrollbarMode newHorizontalMode;
179     ScrollbarMode newVerticalMode;
180 
181     scrollbarModes(newHorizontalMode, newVerticalMode);
182 
183     if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
184         newVerticalMode = ScrollbarAuto;
185     else if (!canScroll)
186         newVerticalMode = ScrollbarAlwaysOff;
187 
188     if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
189         newHorizontalMode = ScrollbarAuto;
190     else if (!canScroll)
191         newHorizontalMode = ScrollbarAlwaysOff;
192 
193     setScrollbarModes(newHorizontalMode, newVerticalMode);
194 }
195 
setCanBlitOnScroll(bool b)196 void ScrollView::setCanBlitOnScroll(bool b)
197 {
198     if (platformWidget()) {
199         platformSetCanBlitOnScroll(b);
200         return;
201     }
202 
203     m_canBlitOnScroll = b;
204 }
205 
canBlitOnScroll() const206 bool ScrollView::canBlitOnScroll() const
207 {
208     if (platformWidget())
209         return platformCanBlitOnScroll();
210 
211     return m_canBlitOnScroll;
212 }
213 
setPaintsEntireContents(bool paintsEntireContents)214 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
215 {
216     m_paintsEntireContents = paintsEntireContents;
217 }
218 
setClipsRepaints(bool clipsRepaints)219 void ScrollView::setClipsRepaints(bool clipsRepaints)
220 {
221     m_clipsRepaints = clipsRepaints;
222 }
223 
setDelegatesScrolling(bool delegatesScrolling)224 void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
225 {
226     m_delegatesScrolling = delegatesScrolling;
227 }
228 
229 #if !PLATFORM(GTK)
visibleContentRect(bool includeScrollbars) const230 IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
231 {
232     if (platformWidget())
233         return platformVisibleContentRect(includeScrollbars);
234 
235 #if !PLATFORM(EFL)
236     if (paintsEntireContents())
237         return IntRect(IntPoint(0, 0), contentsSize());
238 #endif
239 
240     int verticalScrollbarWidth = verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()
241         && !includeScrollbars ? verticalScrollbar()->width() : 0;
242     int horizontalScrollbarHeight = horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()
243         && !includeScrollbars ? horizontalScrollbar()->height() : 0;
244 
245     return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
246                    IntSize(max(0, m_boundsSize.width() - verticalScrollbarWidth),
247                            max(0, m_boundsSize.height() - horizontalScrollbarHeight)));
248 }
249 #endif
250 
layoutWidth() const251 int ScrollView::layoutWidth() const
252 {
253     return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleWidth() : m_fixedLayoutSize.width();
254 }
255 
layoutHeight() const256 int ScrollView::layoutHeight() const
257 {
258     return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleHeight() : m_fixedLayoutSize.height();
259 }
260 
fixedLayoutSize() const261 IntSize ScrollView::fixedLayoutSize() const
262 {
263     return m_fixedLayoutSize;
264 }
265 
setFixedLayoutSize(const IntSize & newSize)266 void ScrollView::setFixedLayoutSize(const IntSize& newSize)
267 {
268     if (fixedLayoutSize() == newSize)
269         return;
270     m_fixedLayoutSize = newSize;
271     updateScrollbars(scrollOffset());
272 }
273 
useFixedLayout() const274 bool ScrollView::useFixedLayout() const
275 {
276     return m_useFixedLayout;
277 }
278 
setUseFixedLayout(bool enable)279 void ScrollView::setUseFixedLayout(bool enable)
280 {
281     if (useFixedLayout() == enable)
282         return;
283     m_useFixedLayout = enable;
284     updateScrollbars(scrollOffset());
285 }
286 
contentsSize() const287 IntSize ScrollView::contentsSize() const
288 {
289     if (platformWidget())
290         return platformContentsSize();
291     return m_contentsSize;
292 }
293 
setContentsSize(const IntSize & newSize)294 void ScrollView::setContentsSize(const IntSize& newSize)
295 {
296     if (contentsSize() == newSize)
297         return;
298     m_contentsSize = newSize;
299     if (platformWidget())
300         platformSetContentsSize();
301     else
302         updateScrollbars(scrollOffset());
303 }
304 
maximumScrollPosition() const305 IntPoint ScrollView::maximumScrollPosition() const
306 {
307     IntPoint maximumOffset(contentsWidth() - visibleWidth() - m_scrollOrigin.x(), contentsHeight() - visibleHeight() - m_scrollOrigin.y());
308     maximumOffset.clampNegativeToZero();
309     return maximumOffset;
310 }
311 
minimumScrollPosition() const312 IntPoint ScrollView::minimumScrollPosition() const
313 {
314     return IntPoint(-m_scrollOrigin.x(), -m_scrollOrigin.y());
315 }
316 
adjustScrollPositionWithinRange(const IntPoint & scrollPoint) const317 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
318 {
319     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
320     newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
321     return newScrollPosition;
322 }
323 
scrollSize(ScrollbarOrientation orientation) const324 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
325 {
326     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
327     return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
328 }
329 
didCompleteRubberBand(const IntSize &) const330 void ScrollView::didCompleteRubberBand(const IntSize&) const
331 {
332 }
333 
notifyPageThatContentAreaWillPaint() const334 void ScrollView::notifyPageThatContentAreaWillPaint() const
335 {
336 }
337 
setScrollOffset(const IntPoint & offset)338 void ScrollView::setScrollOffset(const IntPoint& offset)
339 {
340     int horizontalOffset = offset.x();
341     int verticalOffset = offset.y();
342     if (constrainsScrollingToContentEdge()) {
343         horizontalOffset = max(min(horizontalOffset, contentsWidth() - visibleWidth()), 0);
344         verticalOffset = max(min(verticalOffset, contentsHeight() - visibleHeight()), 0);
345     }
346 
347     IntSize newOffset = m_scrollOffset;
348     newOffset.setWidth(horizontalOffset - m_scrollOrigin.x());
349     newOffset.setHeight(verticalOffset - m_scrollOrigin.y());
350 
351     scrollTo(newOffset);
352 }
353 
scrollTo(const IntSize & newOffset)354 void ScrollView::scrollTo(const IntSize& newOffset)
355 {
356     IntSize scrollDelta = newOffset - m_scrollOffset;
357     if (scrollDelta == IntSize())
358         return;
359     m_scrollOffset = newOffset;
360 
361     if (scrollbarsSuppressed())
362         return;
363 
364     repaintFixedElementsAfterScrolling();
365     scrollContents(scrollDelta);
366 }
367 
scrollPosition(Scrollbar * scrollbar) const368 int ScrollView::scrollPosition(Scrollbar* scrollbar) const
369 {
370     if (scrollbar->orientation() == HorizontalScrollbar)
371         return scrollPosition().x() + m_scrollOrigin.x();
372     if (scrollbar->orientation() == VerticalScrollbar)
373         return scrollPosition().y() + m_scrollOrigin.y();
374     return 0;
375 }
376 
setScrollPosition(const IntPoint & scrollPoint)377 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
378 {
379     if (prohibitsScrolling())
380         return;
381 
382     if (platformWidget()) {
383         platformSetScrollPosition(scrollPoint);
384         return;
385     }
386 
387 #if ENABLE(TILED_BACKING_STORE)
388     if (delegatesScrolling()) {
389         hostWindow()->delegatedScrollRequested(scrollPoint);
390         if (!m_actualVisibleContentRect.isEmpty())
391             m_actualVisibleContentRect.setLocation(scrollPoint);
392         return;
393     }
394 #endif
395 
396     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
397 
398     if (newScrollPosition == scrollPosition())
399         return;
400 
401     updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
402 }
403 
scroll(ScrollDirection direction,ScrollGranularity granularity)404 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
405 {
406     if (platformWidget())
407         return platformScroll(direction, granularity);
408 
409     return ScrollableArea::scroll(direction, granularity);
410 }
411 
logicalScroll(ScrollLogicalDirection direction,ScrollGranularity granularity)412 bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
413 {
414     return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
415 }
416 
overhangAmount() const417 IntSize ScrollView::overhangAmount() const
418 {
419     IntSize stretch;
420 
421     int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y();
422     if (physicalScrollY < 0)
423         stretch.setHeight(physicalScrollY);
424     else if (physicalScrollY > contentsHeight() - visibleContentRect().height())
425         stretch.setHeight(physicalScrollY - (contentsHeight() - visibleContentRect().height()));
426 
427     int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x();
428     if (physicalScrollX < 0)
429         stretch.setWidth(physicalScrollX);
430     else if (physicalScrollX > contentsWidth() - visibleContentRect().width())
431         stretch.setWidth(physicalScrollX - (contentsWidth() - visibleContentRect().width()));
432 
433     return stretch;
434 }
435 
windowResizerRectChanged()436 void ScrollView::windowResizerRectChanged()
437 {
438     if (platformWidget())
439         return;
440 
441     updateScrollbars(scrollOffset());
442 }
443 
444 static const unsigned cMaxUpdateScrollbarsPass = 2;
445 
updateScrollbars(const IntSize & desiredOffset)446 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
447 {
448     if (m_inUpdateScrollbars || prohibitsScrolling() || delegatesScrolling() || platformWidget())
449         return;
450 
451     // If we came in here with the view already needing a layout, then go ahead and do that
452     // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
453     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
454     if (!m_scrollbarsSuppressed) {
455         m_inUpdateScrollbars = true;
456         visibleContentsResized();
457         m_inUpdateScrollbars = false;
458     }
459 
460     bool hasHorizontalScrollbar = m_horizontalScrollbar;
461     bool hasVerticalScrollbar = m_verticalScrollbar;
462 
463     bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
464     bool newHasVerticalScrollbar = hasVerticalScrollbar;
465 
466     ScrollbarMode hScroll = m_horizontalScrollbarMode;
467     ScrollbarMode vScroll = m_verticalScrollbarMode;
468 
469     if (hScroll != ScrollbarAuto)
470         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
471     if (vScroll != ScrollbarAuto)
472         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
473 
474     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
475         if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
476             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
477         if (hasVerticalScrollbar != newHasVerticalScrollbar)
478             setHasVerticalScrollbar(newHasVerticalScrollbar);
479     } else {
480         bool sendContentResizedNotification = false;
481 
482         IntSize docSize = contentsSize();
483         IntSize frameSize = m_boundsSize;
484 
485         if (hScroll == ScrollbarAuto) {
486             newHasHorizontalScrollbar = docSize.width() > visibleWidth();
487             if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
488                 newHasHorizontalScrollbar = false;
489         }
490         if (vScroll == ScrollbarAuto) {
491             newHasVerticalScrollbar = docSize.height() > visibleHeight();
492             if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
493                 newHasVerticalScrollbar = false;
494         }
495 
496         // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
497         // try to both gain/lose a scrollbar in the same pass.
498         if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
499             newHasVerticalScrollbar = false;
500         if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
501             newHasHorizontalScrollbar = false;
502 
503         if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
504             if (m_scrollOrigin.y() && !newHasHorizontalScrollbar)
505                 m_scrollOrigin.setY(m_scrollOrigin.y() - m_horizontalScrollbar->height());
506             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
507             sendContentResizedNotification = true;
508         }
509 
510         if (hasVerticalScrollbar != newHasVerticalScrollbar) {
511             if (m_scrollOrigin.x() && !newHasVerticalScrollbar)
512                 m_scrollOrigin.setX(m_scrollOrigin.x() - m_verticalScrollbar->width());
513             setHasVerticalScrollbar(newHasVerticalScrollbar);
514             sendContentResizedNotification = true;
515         }
516 
517         if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
518             m_updateScrollbarsPass++;
519             contentsResized();
520             visibleContentsResized();
521             IntSize newDocSize = contentsSize();
522             if (newDocSize == docSize) {
523                 // The layout with the new scroll state had no impact on
524                 // the document's overall size, so updateScrollbars didn't get called.
525                 // Recur manually.
526                 updateScrollbars(desiredOffset);
527             }
528             m_updateScrollbarsPass--;
529         }
530     }
531 
532     // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
533     // doing it multiple times).
534     if (m_updateScrollbarsPass)
535         return;
536 
537     m_inUpdateScrollbars = true;
538 
539     IntPoint scrollPoint = adjustScrollPositionWithinRange(IntPoint(desiredOffset));
540     IntSize scroll(scrollPoint.x(), scrollPoint.y());
541 
542     if (m_horizontalScrollbar) {
543         int clientWidth = visibleWidth();
544         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
545         int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
546         IntRect oldRect(m_horizontalScrollbar->frameRect());
547         IntRect hBarRect = IntRect(0,
548                                    m_boundsSize.height() - m_horizontalScrollbar->height(),
549                                    m_boundsSize.width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
550                                    m_horizontalScrollbar->height());
551         m_horizontalScrollbar->setFrameRect(hBarRect);
552         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
553             m_horizontalScrollbar->invalidate();
554 
555         if (m_scrollbarsSuppressed)
556             m_horizontalScrollbar->setSuppressInvalidation(true);
557         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
558         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
559         if (m_scrollbarsSuppressed)
560             m_horizontalScrollbar->setSuppressInvalidation(false);
561     }
562 
563     if (m_verticalScrollbar) {
564         int clientHeight = visibleHeight();
565         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
566         int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
567         IntRect oldRect(m_verticalScrollbar->frameRect());
568         IntRect vBarRect = IntRect(m_boundsSize.width() - m_verticalScrollbar->width(),
569                                    0,
570                                    m_verticalScrollbar->width(),
571                                    m_boundsSize.height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
572         m_verticalScrollbar->setFrameRect(vBarRect);
573         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
574             m_verticalScrollbar->invalidate();
575 
576         if (m_scrollbarsSuppressed)
577             m_verticalScrollbar->setSuppressInvalidation(true);
578         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
579         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
580         if (m_scrollbarsSuppressed)
581             m_verticalScrollbar->setSuppressInvalidation(false);
582     }
583 
584     if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) {
585         // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
586         frameRectsChanged();
587         positionScrollbarLayers();
588         updateScrollCorner();
589     }
590 
591     ScrollableArea::scrollToOffsetWithoutAnimation(FloatPoint(scroll.width() + m_scrollOrigin.x(), scroll.height() + m_scrollOrigin.y()));
592 
593     // Make sure the scrollbar offsets are up to date.
594     if (m_horizontalScrollbar)
595         m_horizontalScrollbar->offsetDidChange();
596     if (m_verticalScrollbar)
597         m_verticalScrollbar->offsetDidChange();
598 
599     m_inUpdateScrollbars = false;
600 }
601 
602 const int panIconSizeLength = 16;
603 
rectToCopyOnScroll() const604 IntRect ScrollView::rectToCopyOnScroll() const
605 {
606     IntRect scrollViewRect = convertToContainingWindow(IntRect(0, 0, visibleWidth(), visibleHeight()));
607     if (hasOverlayScrollbars()) {
608         int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
609         int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
610 
611         scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
612         scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
613     }
614     return scrollViewRect;
615 }
616 
scrollContents(const IntSize & scrollDelta)617 void ScrollView::scrollContents(const IntSize& scrollDelta)
618 {
619     if (!hostWindow())
620         return;
621 
622     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
623     // with the clip rect every time to keep it smooth.
624     IntRect clipRect = windowClipRect();
625     IntRect scrollViewRect = rectToCopyOnScroll();
626     IntRect updateRect = clipRect;
627     updateRect.intersect(scrollViewRect);
628 
629     // Invalidate the window (not the backing store).
630     hostWindow()->invalidateWindow(updateRect, false /*immediate*/);
631 
632     if (m_drawPanScrollIcon) {
633         // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
634         // https://bugs.webkit.org/show_bug.cgi?id=47837
635         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
636         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
637         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
638         panScrollIconDirtyRect.intersect(clipRect);
639         hostWindow()->invalidateContentsAndWindow(panScrollIconDirtyRect, false /*immediate*/);
640     }
641 
642     if (canBlitOnScroll()) { // The main frame can just blit the WebView window
643         // FIXME: Find a way to scroll subframes with this faster path
644         if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
645             scrollContentsSlowPath(updateRect);
646     } else {
647        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
648        // windowed plugins.
649        scrollContentsSlowPath(updateRect);
650     }
651 
652     // Invalidate the overhang areas if they are visible.
653     IntRect horizontalOverhangRect;
654     IntRect verticalOverhangRect;
655     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
656     if (!horizontalOverhangRect.isEmpty())
657         hostWindow()->invalidateContentsAndWindow(horizontalOverhangRect, false /*immediate*/);
658     if (!verticalOverhangRect.isEmpty())
659         hostWindow()->invalidateContentsAndWindow(verticalOverhangRect, false /*immediate*/);
660 
661     // This call will move children with native widgets (plugins) and invalidate them as well.
662     frameRectsChanged();
663 
664     // Now blit the backingstore into the window which should be very fast.
665     hostWindow()->invalidateWindow(IntRect(), true);
666 }
667 
scrollContentsFastPath(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)668 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
669 {
670     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
671     return true;
672 }
673 
scrollContentsSlowPath(const IntRect & updateRect)674 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
675 {
676     hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
677 }
678 
windowToContents(const IntPoint & windowPoint) const679 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
680 {
681     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
682     return viewPoint + scrollOffset();
683 }
684 
contentsToWindow(const IntPoint & contentsPoint) const685 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
686 {
687     IntPoint viewPoint = contentsPoint - scrollOffset();
688     return convertToContainingWindow(viewPoint);
689 }
690 
windowToContents(const IntRect & windowRect) const691 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
692 {
693     IntRect viewRect = convertFromContainingWindow(windowRect);
694     viewRect.move(scrollOffset());
695     return viewRect;
696 }
697 
contentsToWindow(const IntRect & contentsRect) const698 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
699 {
700     IntRect viewRect = contentsRect;
701     viewRect.move(-scrollOffset());
702     return convertToContainingWindow(viewRect);
703 }
704 
contentsToScreen(const IntRect & rect) const705 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
706 {
707     if (platformWidget())
708         return platformContentsToScreen(rect);
709     if (!hostWindow())
710         return IntRect();
711     return hostWindow()->windowToScreen(contentsToWindow(rect));
712 }
713 
screenToContents(const IntPoint & point) const714 IntPoint ScrollView::screenToContents(const IntPoint& point) const
715 {
716     if (platformWidget())
717         return platformScreenToContents(point);
718     if (!hostWindow())
719         return IntPoint();
720     return windowToContents(hostWindow()->screenToWindow(point));
721 }
722 
containsScrollbarsAvoidingResizer() const723 bool ScrollView::containsScrollbarsAvoidingResizer() const
724 {
725     return !m_scrollbarsAvoidingResizer;
726 }
727 
adjustScrollbarsAvoidingResizerCount(int overlapDelta)728 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
729 {
730     int oldCount = m_scrollbarsAvoidingResizer;
731     m_scrollbarsAvoidingResizer += overlapDelta;
732     if (parent())
733         parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
734     else if (!scrollbarsSuppressed()) {
735         // If we went from n to 0 or from 0 to n and we're the outermost view,
736         // we need to invalidate the windowResizerRect(), since it will now need to paint
737         // differently.
738         if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
739             (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
740             invalidateRect(windowResizerRect());
741     }
742 }
743 
setParent(ScrollView * parentView)744 void ScrollView::setParent(ScrollView* parentView)
745 {
746     if (parentView == parent())
747         return;
748 
749     if (m_scrollbarsAvoidingResizer && parent())
750         parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
751 
752     Widget::setParent(parentView);
753 
754     if (m_scrollbarsAvoidingResizer && parent())
755         parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
756 }
757 
setScrollbarsSuppressed(bool suppressed,bool repaintOnUnsuppress)758 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
759 {
760     if (suppressed == m_scrollbarsSuppressed)
761         return;
762 
763     m_scrollbarsSuppressed = suppressed;
764 
765     if (platformWidget())
766         platformSetScrollbarsSuppressed(repaintOnUnsuppress);
767     else if (repaintOnUnsuppress && !suppressed) {
768         if (m_horizontalScrollbar)
769             m_horizontalScrollbar->invalidate();
770         if (m_verticalScrollbar)
771             m_verticalScrollbar->invalidate();
772 
773         // Invalidate the scroll corner too on unsuppress.
774         invalidateRect(scrollCornerRect());
775     }
776 }
777 
scrollbarAtPoint(const IntPoint & windowPoint)778 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
779 {
780     if (platformWidget())
781         return 0;
782 
783     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
784     if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint))
785         return m_horizontalScrollbar.get();
786     if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint))
787         return m_verticalScrollbar.get();
788     return 0;
789 }
790 
wheelEvent(PlatformWheelEvent & e)791 void ScrollView::wheelEvent(PlatformWheelEvent& e)
792 {
793     // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
794 #if PLATFORM(WX)
795     if (!canHaveScrollbars()) {
796 #else
797     if (!canHaveScrollbars() || platformWidget()) {
798 #endif
799         return;
800     }
801 
802     ScrollableArea::handleWheelEvent(e);
803 }
804 
805 #if ENABLE(GESTURE_EVENTS)
806 void ScrollView::gestureEvent(const PlatformGestureEvent& gestureEvent)
807 {
808     if (platformWidget())
809         return;
810 
811     ScrollableArea::handleGestureEvent(gestureEvent);
812 }
813 #endif
814 
815 void ScrollView::setFrameRect(const IntRect& newRect)
816 {
817     IntRect oldRect = frameRect();
818 
819     if (newRect == oldRect)
820         return;
821 
822     Widget::setFrameRect(newRect);
823 
824     frameRectsChanged();
825 }
826 
827 void ScrollView::setBoundsSize(const IntSize& newSize)
828 {
829     if (newSize == m_boundsSize)
830         return;
831 
832     Widget::setBoundsSize(newSize);
833     m_boundsSize = newSize;
834 
835     if (platformWidget())
836         return;
837 
838     updateScrollbars(m_scrollOffset);
839     if (!m_useFixedLayout)
840         contentsResized();
841 
842     positionScrollbarLayers();
843 }
844 
845 void ScrollView::setInitialBoundsSize(const IntSize& newSize)
846 {
847     ASSERT(m_boundsSize.isZero());
848     m_boundsSize = newSize;
849 }
850 
851 void ScrollView::frameRectsChanged()
852 {
853     if (platformWidget())
854         return;
855 
856     HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
857     for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
858         (*current)->frameRectsChanged();
859 }
860 
861 #if USE(ACCELERATED_COMPOSITING)
862 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
863 {
864     if (!graphicsLayer || !scrollbar)
865         return;
866     graphicsLayer->setDrawsContent(true);
867     IntRect scrollbarRect = scrollbar->frameRect();
868     graphicsLayer->setPosition(scrollbarRect.location());
869     if (scrollbarRect.size() != graphicsLayer->size())
870         graphicsLayer->setNeedsDisplay();
871     graphicsLayer->setSize(scrollbarRect.size());
872 }
873 
874 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
875 {
876     if (!graphicsLayer)
877         return;
878     graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
879     graphicsLayer->setPosition(cornerRect.location());
880     if (cornerRect.size() != graphicsLayer->size())
881         graphicsLayer->setNeedsDisplay();
882     graphicsLayer->setSize(cornerRect.size());
883 }
884 #endif
885 
886 
887 void ScrollView::positionScrollbarLayers()
888 {
889 #if USE(ACCELERATED_COMPOSITING)
890     positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
891     positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
892     positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
893 #endif
894 }
895 
896 void ScrollView::repaintContentRectangle(const IntRect& rect, bool now)
897 {
898     IntRect paintRect = rect;
899     if (clipsRepaints() && !paintsEntireContents())
900         paintRect.intersect(visibleContentRect());
901     if (paintRect.isEmpty())
902         return;
903 
904     if (platformWidget()) {
905         platformRepaintContentRectangle(paintRect, now);
906         return;
907     }
908 
909     if (hostWindow())
910         hostWindow()->invalidateContentsAndWindow(contentsToWindow(paintRect), now /*immediate*/);
911 }
912 
913 IntRect ScrollView::scrollCornerRect() const
914 {
915     IntRect cornerRect;
916 
917     if (hasOverlayScrollbars())
918         return cornerRect;
919 
920     if (m_horizontalScrollbar && m_boundsSize.width() - m_horizontalScrollbar->width() > 0) {
921         cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
922                                  m_boundsSize.height() - m_horizontalScrollbar->height(),
923                                  m_boundsSize.width() - m_horizontalScrollbar->width(),
924                                  m_horizontalScrollbar->height()));
925     }
926 
927     if (m_verticalScrollbar && m_boundsSize.height() - m_verticalScrollbar->height() > 0) {
928         cornerRect.unite(IntRect(m_boundsSize.width() - m_verticalScrollbar->width(),
929                                  m_verticalScrollbar->height(),
930                                  m_verticalScrollbar->width(),
931                                  m_boundsSize.height() - m_verticalScrollbar->height()));
932     }
933 
934     return cornerRect;
935 }
936 
937 bool ScrollView::isScrollCornerVisible() const
938 {
939     return !scrollCornerRect().isEmpty();
940 }
941 
942 void ScrollView::updateScrollCorner()
943 {
944 }
945 
946 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
947 {
948     ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect);
949 }
950 
951 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
952 {
953     invalidateRect(rect);
954 }
955 
956 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
957 {
958     if (m_horizontalScrollbar
959 #if USE(ACCELERATED_COMPOSITING)
960         && !layerForHorizontalScrollbar()
961 #endif
962                                       )
963         m_horizontalScrollbar->paint(context, rect);
964     if (m_verticalScrollbar
965 #if USE(ACCELERATED_COMPOSITING)
966         && !layerForVerticalScrollbar()
967 #endif
968                                     )
969         m_verticalScrollbar->paint(context, rect);
970 
971 #if USE(ACCELERATED_COMPOSITING)
972     if (layerForScrollCorner())
973         return;
974 #endif
975     paintScrollCorner(context, scrollCornerRect());
976 }
977 
978 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
979 {
980     static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
981     context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, m_panScrollIconPoint);
982 }
983 
984 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
985 {
986     if (platformWidget()) {
987         Widget::paint(context, rect);
988         return;
989     }
990 
991     if (context->paintingDisabled() && !context->updatingControlTints())
992         return;
993 
994     notifyPageThatContentAreaWillPaint();
995 
996     // If we encounter any overlay scrollbars as we paint, this will be set to true.
997     m_containsScrollableAreaWithOverlayScrollbars = false;
998 
999     IntRect clipRect = frameRect();
1000     if (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1001         clipRect.setWidth(clipRect.width() - verticalScrollbar()->width());
1002     if (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1003         clipRect.setHeight(clipRect.height() - horizontalScrollbar()->height());
1004 
1005     IntRect documentDirtyRect = rect;
1006     documentDirtyRect.intersect(clipRect);
1007 
1008     if (!documentDirtyRect.isEmpty()) {
1009         GraphicsContextStateSaver stateSaver(*context);
1010 
1011         context->translate(x(), y());
1012         documentDirtyRect.move(-x(), -y());
1013 
1014         if (!paintsEntireContents()) {
1015             context->translate(-scrollX(), -scrollY());
1016             documentDirtyRect.move(scrollX(), scrollY());
1017 
1018             context->clip(visibleContentRect());
1019         }
1020 
1021         paintContents(context, documentDirtyRect);
1022     }
1023 
1024     IntRect horizontalOverhangRect;
1025     IntRect verticalOverhangRect;
1026     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1027 
1028     if (rect.intersects(horizontalOverhangRect) || rect.intersects(verticalOverhangRect))
1029         paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, rect);
1030 
1031     // Now paint the scrollbars.
1032     if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
1033         GraphicsContextStateSaver stateSaver(*context);
1034         IntRect scrollViewDirtyRect = rect;
1035         scrollViewDirtyRect.intersect(frameRect());
1036         context->translate(x(), y());
1037         scrollViewDirtyRect.move(-x(), -y());
1038 
1039         paintScrollbars(context, scrollViewDirtyRect);
1040     }
1041 
1042     // Paint the panScroll Icon
1043     if (m_drawPanScrollIcon)
1044         paintPanScrollIcon(context);
1045 }
1046 
1047 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1048 {
1049     int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1050         ? verticalScrollbar()->width() : 0;
1051     int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1052         ? horizontalScrollbar()->height() : 0;
1053 
1054     int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y();
1055     if (physicalScrollY < 0) {
1056         horizontalOverhangRect = frameRect();
1057         horizontalOverhangRect.setHeight(-physicalScrollY);
1058     } else if (physicalScrollY > contentsHeight() - visibleContentRect().height()) {
1059         int height = physicalScrollY - (contentsHeight() - visibleContentRect().height());
1060         horizontalOverhangRect = frameRect();
1061         horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
1062         horizontalOverhangRect.setHeight(height);
1063     }
1064 
1065     int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x();
1066     if (physicalScrollX < 0) {
1067         verticalOverhangRect.setWidth(-physicalScrollX);
1068         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height());
1069         verticalOverhangRect.setX(frameRect().x());
1070         if (horizontalOverhangRect.y() == frameRect().y())
1071             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1072         else
1073             verticalOverhangRect.setY(frameRect().y());
1074     } else if (physicalScrollX > contentsWidth() - visibleContentRect().width()) {
1075         int width = physicalScrollX - (contentsWidth() - visibleContentRect().width());
1076         verticalOverhangRect.setWidth(width);
1077         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height());
1078         verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
1079         if (horizontalOverhangRect.y() == frameRect().y())
1080             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1081         else
1082             verticalOverhangRect.setY(frameRect().y());
1083     }
1084 }
1085 
1086 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect&)
1087 {
1088     // FIXME: This should be checking the dirty rect.
1089 
1090     context->setFillColor(Color::white, ColorSpaceDeviceRGB);
1091     if (!horizontalOverhangRect.isEmpty())
1092         context->fillRect(horizontalOverhangRect);
1093 
1094     context->setFillColor(Color::white, ColorSpaceDeviceRGB);
1095     if (!verticalOverhangRect.isEmpty())
1096         context->fillRect(verticalOverhangRect);
1097 }
1098 
1099 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1100 {
1101     if (!scrollbarCornerPresent())
1102         return false;
1103 
1104     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1105 
1106     if (m_horizontalScrollbar) {
1107         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1108         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1109         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1110 
1111         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1112     }
1113 
1114     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1115     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1116     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1117 
1118     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1119 }
1120 
1121 bool ScrollView::scrollbarCornerPresent() const
1122 {
1123     return (m_horizontalScrollbar && m_boundsSize.width() - m_horizontalScrollbar->width() > 0) ||
1124            (m_verticalScrollbar && m_boundsSize.height() - m_verticalScrollbar->height() > 0);
1125 }
1126 
1127 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1128 {
1129     // Scrollbars won't be transformed within us
1130     IntRect newRect = localRect;
1131     newRect.move(scrollbar->x(), scrollbar->y());
1132     return newRect;
1133 }
1134 
1135 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1136 {
1137     IntRect newRect = parentRect;
1138     // Scrollbars won't be transformed within us
1139     newRect.move(-scrollbar->x(), -scrollbar->y());
1140     return newRect;
1141 }
1142 
1143 // FIXME: test these on windows
1144 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1145 {
1146     // Scrollbars won't be transformed within us
1147     IntPoint newPoint = localPoint;
1148     newPoint.move(scrollbar->x(), scrollbar->y());
1149     return newPoint;
1150 }
1151 
1152 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1153 {
1154     IntPoint newPoint = parentPoint;
1155     // Scrollbars won't be transformed within us
1156     newPoint.move(-scrollbar->x(), -scrollbar->y());
1157     return newPoint;
1158 }
1159 
1160 void ScrollView::setParentVisible(bool visible)
1161 {
1162     if (isParentVisible() == visible)
1163         return;
1164 
1165     Widget::setParentVisible(visible);
1166 
1167     if (!isSelfVisible())
1168         return;
1169 
1170     HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1171     for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1172         (*it)->setParentVisible(visible);
1173 }
1174 
1175 void ScrollView::show()
1176 {
1177     if (!isSelfVisible()) {
1178         setSelfVisible(true);
1179         if (isParentVisible()) {
1180             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1181             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1182                 (*it)->setParentVisible(true);
1183         }
1184     }
1185 
1186     Widget::show();
1187 }
1188 
1189 void ScrollView::hide()
1190 {
1191     if (isSelfVisible()) {
1192         if (isParentVisible()) {
1193             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1194             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1195                 (*it)->setParentVisible(false);
1196         }
1197         setSelfVisible(false);
1198     }
1199 
1200     Widget::hide();
1201 }
1202 
1203 bool ScrollView::isOffscreen() const
1204 {
1205     if (platformWidget())
1206         return platformIsOffscreen();
1207 
1208     if (!isVisible())
1209         return true;
1210 
1211     // FIXME: Add a HostWindow::isOffscreen method here.  Since only Mac implements this method
1212     // currently, we can add the method when the other platforms decide to implement this concept.
1213     return false;
1214 }
1215 
1216 
1217 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1218 {
1219     if (!hostWindow())
1220         return;
1221     m_drawPanScrollIcon = true;
1222     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1223     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1224 }
1225 
1226 void ScrollView::removePanScrollIcon()
1227 {
1228     if (!hostWindow())
1229         return;
1230     m_drawPanScrollIcon = false;
1231     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1232 }
1233 
1234 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1235 {
1236     if (m_scrollOrigin == origin)
1237         return;
1238 
1239     m_scrollOrigin = origin;
1240 
1241     if (platformWidget()) {
1242         platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1243         return;
1244     }
1245 
1246     // Update if the scroll origin changes, since our position will be different if the content size did not change.
1247     if (updatePositionAtAll && updatePositionSynchronously)
1248         updateScrollbars(scrollOffset());
1249 }
1250 
1251 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(EFL)
1252 
1253 void ScrollView::platformInit()
1254 {
1255 }
1256 
1257 void ScrollView::platformDestroy()
1258 {
1259 }
1260 
1261 #endif
1262 
1263 #if !PLATFORM(WX) && !PLATFORM(QT) && !PLATFORM(MAC)
1264 
1265 void ScrollView::platformAddChild(Widget*)
1266 {
1267 }
1268 
1269 void ScrollView::platformRemoveChild(Widget*)
1270 {
1271 }
1272 
1273 #endif
1274 
1275 #if !PLATFORM(MAC)
1276 
1277 void ScrollView::platformSetScrollbarsSuppressed(bool)
1278 {
1279 }
1280 
1281 void ScrollView::platformSetScrollOrigin(const IntPoint&, bool updatePositionAtAll, bool updatePositionSynchronously)
1282 {
1283 }
1284 
1285 #endif
1286 
1287 #if !PLATFORM(MAC) && !PLATFORM(WX)
1288 
1289 void ScrollView::platformSetScrollbarModes()
1290 {
1291 }
1292 
1293 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1294 {
1295     horizontal = ScrollbarAuto;
1296     vertical = ScrollbarAuto;
1297 }
1298 
1299 void ScrollView::platformSetCanBlitOnScroll(bool)
1300 {
1301 }
1302 
1303 bool ScrollView::platformCanBlitOnScroll() const
1304 {
1305     return false;
1306 }
1307 
1308 IntRect ScrollView::platformVisibleContentRect(bool) const
1309 {
1310     return IntRect();
1311 }
1312 
1313 IntSize ScrollView::platformContentsSize() const
1314 {
1315     return IntSize();
1316 }
1317 
1318 void ScrollView::platformSetContentsSize()
1319 {
1320 }
1321 
1322 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1323 {
1324     return rect;
1325 }
1326 
1327 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1328 {
1329     return point;
1330 }
1331 
1332 void ScrollView::platformSetScrollPosition(const IntPoint&)
1333 {
1334 }
1335 
1336 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1337 {
1338     return true;
1339 }
1340 
1341 void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/)
1342 {
1343 }
1344 
1345 bool ScrollView::platformIsOffscreen() const
1346 {
1347     return false;
1348 }
1349 
1350 #endif
1351 
1352 }
1353