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