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