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
47using namespace std;
48
49namespace WebCore {
50
51ScrollView::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
72ScrollView::~ScrollView()
73{
74    platformDestroy();
75}
76
77void 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
87void 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
96void 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
116void 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)
137PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
138{
139    return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
140}
141
142void 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
173void 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
183void 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
203void ScrollView::setCanBlitOnScroll(bool b)
204{
205    if (platformWidget()) {
206        platformSetCanBlitOnScroll(b);
207        return;
208    }
209
210    m_canBlitOnScroll = b;
211}
212
213bool ScrollView::canBlitOnScroll() const
214{
215    if (platformWidget())
216        return platformCanBlitOnScroll();
217
218    return m_canBlitOnScroll;
219}
220
221void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
222{
223    m_paintsEntireContents = paintsEntireContents;
224}
225
226void ScrollView::setClipsRepaints(bool clipsRepaints)
227{
228    m_clipsRepaints = clipsRepaints;
229}
230
231void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
232{
233    m_delegatesScrolling = delegatesScrolling;
234}
235
236#if !USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR)
237IntRect 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
256int ScrollView::layoutWidth() const
257{
258    return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleWidth() : m_fixedLayoutSize.width();
259}
260
261int ScrollView::layoutHeight() const
262{
263    return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleHeight() : m_fixedLayoutSize.height();
264}
265
266IntSize ScrollView::fixedLayoutSize() const
267{
268    return m_fixedLayoutSize;
269}
270
271void ScrollView::setFixedLayoutSize(const IntSize& newSize)
272{
273    if (fixedLayoutSize() == newSize)
274        return;
275    m_fixedLayoutSize = newSize;
276    updateScrollbars(scrollOffset());
277}
278
279bool ScrollView::useFixedLayout() const
280{
281    return m_useFixedLayout;
282}
283
284void ScrollView::setUseFixedLayout(bool enable)
285{
286    if (useFixedLayout() == enable)
287        return;
288    m_useFixedLayout = enable;
289    updateScrollbars(scrollOffset());
290}
291
292IntSize ScrollView::contentsSize() const
293{
294    if (platformWidget())
295        return platformContentsSize();
296    return m_contentsSize;
297}
298
299void 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)
311int ScrollView::actualWidth() const {
312    if (platformWidget())
313        return platformActualWidth();
314    return width();
315}
316
317int ScrollView::actualHeight() const {
318    if (platformWidget())
319        return platformActualHeight();
320    return height();
321}
322
323int ScrollView::actualScrollX() const {
324    if (platformWidget())
325        return platformActualScrollX();
326    return scrollX();
327}
328
329int ScrollView::actualScrollY() const {
330    if (platformWidget())
331        return platformActualScrollY();
332    return scrollY();
333}
334
335FrameView* ScrollView::frameView() {
336    if (this->isFrameView()) {
337        FrameView* frameView = reinterpret_cast<FrameView*>(this);
338        return frameView;
339    }
340    return 0;
341}
342#endif
343
344IntPoint 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
351IntPoint ScrollView::minimumScrollPosition() const
352{
353    return IntPoint(-m_scrollOrigin.x(), -m_scrollOrigin.y());
354}
355
356IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
357{
358    IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
359    newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
360    return newScrollPosition;
361}
362
363int 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
369void ScrollView::didCompleteRubberBand(const IntSize&) const
370{
371}
372
373void ScrollView::notifyPageThatContentAreaWillPaint() const
374{
375}
376
377void 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
393void 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
427int 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
436void 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
463bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
464{
465    if (platformWidget())
466        return platformScroll(direction, granularity);
467
468    return ScrollableArea::scroll(direction, granularity);
469}
470
471bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
472{
473    return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
474}
475
476IntSize 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
495void ScrollView::windowResizerRectChanged()
496{
497    if (platformWidget())
498        return;
499
500    updateScrollbars(scrollOffset());
501}
502
503static const unsigned cMaxUpdateScrollbarsPass = 2;
504
505void 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
659const int panIconSizeLength = 16;
660
661void 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
720bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
721{
722    hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
723    return true;
724}
725
726void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
727{
728    hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
729}
730
731IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
732{
733    IntPoint viewPoint = convertFromContainingWindow(windowPoint);
734    return viewPoint + scrollOffset();
735}
736
737IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
738{
739    IntPoint viewPoint = contentsPoint - scrollOffset();
740    return convertToContainingWindow(viewPoint);
741}
742
743IntRect ScrollView::windowToContents(const IntRect& windowRect) const
744{
745    IntRect viewRect = convertFromContainingWindow(windowRect);
746    viewRect.move(scrollOffset());
747    return viewRect;
748}
749
750IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
751{
752    IntRect viewRect = contentsRect;
753    viewRect.move(-scrollOffset());
754    return convertToContainingWindow(viewRect);
755}
756
757IntRect 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
766IntPoint 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
775bool ScrollView::containsScrollbarsAvoidingResizer() const
776{
777    return !m_scrollbarsAvoidingResizer;
778}
779
780void 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
796void 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
810void 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
830Scrollbar* 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
843void 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)
858void ScrollView::gestureEvent(const PlatformGestureEvent& gestureEvent)
859{
860    if (platformWidget())
861        return;
862
863    ScrollableArea::handleGestureEvent(gestureEvent);
864}
865#endif
866
867void ScrollView::setFrameRect(const IntRect& newRect)
868{
869    IntRect oldRect = frameRect();
870
871    if (newRect == oldRect)
872        return;
873
874    Widget::setFrameRect(newRect);
875}
876
877void 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
895void ScrollView::setInitialBoundsSize(const IntSize& newSize)
896{
897    ASSERT(m_boundsSize.isZero());
898    m_boundsSize = newSize;
899}
900
901void 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)
913static 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
925static 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
938void 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
948void 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
968IntRect 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
992bool ScrollView::isScrollCornerVisible() const
993{
994    return !scrollCornerRect().isEmpty();
995}
996
997void ScrollView::updateScrollCorner()
998{
999}
1000
1001void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
1002{
1003    ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect);
1004}
1005
1006void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
1007{
1008    invalidateRect(rect);
1009}
1010
1011void 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
1033void ScrollView::paintPanScrollIcon(GraphicsContext* context)
1034{
1035    static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
1036    context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, m_panScrollIconPoint);
1037}
1038
1039void 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
1098void 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
1137void 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
1150bool 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
1172bool 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
1178IntRect 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
1186IntRect 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
1195IntPoint 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
1203IntPoint 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
1211void 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
1226void 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
1240void 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
1254bool 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
1268void 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
1277void 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
1285void 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
1304void ScrollView::platformInit()
1305{
1306}
1307
1308void ScrollView::platformDestroy()
1309{
1310}
1311
1312#endif
1313
1314#if !PLATFORM(WX) && !PLATFORM(QT) && !PLATFORM(MAC)
1315
1316void ScrollView::platformAddChild(Widget*)
1317{
1318}
1319
1320void ScrollView::platformRemoveChild(Widget*)
1321{
1322}
1323
1324#endif
1325
1326#if !PLATFORM(MAC)
1327
1328void ScrollView::platformSetScrollbarsSuppressed(bool)
1329{
1330}
1331
1332void 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)
1341void ScrollView::platformSetScrollbarModes()
1342{
1343}
1344
1345void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1346{
1347    horizontal = ScrollbarAuto;
1348    vertical = ScrollbarAuto;
1349}
1350#endif
1351
1352void ScrollView::platformSetCanBlitOnScroll(bool)
1353{
1354}
1355
1356bool ScrollView::platformCanBlitOnScroll() const
1357{
1358    return false;
1359}
1360
1361#if !PLATFORM(ANDROID)
1362IntRect ScrollView::platformVisibleContentRect(bool) const
1363{
1364    return IntRect();
1365}
1366#endif
1367
1368#if !PLATFORM(ANDROID)
1369IntSize ScrollView::platformContentsSize() const
1370{
1371    return IntSize();
1372}
1373#endif
1374
1375void ScrollView::platformSetContentsSize()
1376{
1377}
1378
1379IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1380{
1381    return rect;
1382}
1383
1384IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1385{
1386    return point;
1387}
1388
1389#if !PLATFORM(ANDROID)
1390void ScrollView::platformSetScrollPosition(const IntPoint&)
1391{
1392}
1393#endif
1394
1395bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1396{
1397    return true;
1398}
1399
1400#if !PLATFORM(ANDROID)
1401void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/)
1402{
1403}
1404
1405#ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
1406void ScrollView::platformOffscreenContentRectangle(const IntRect& )
1407{
1408}
1409#endif
1410
1411bool ScrollView::platformIsOffscreen() const
1412{
1413    return false;
1414}
1415
1416#endif
1417#endif
1418
1419}
1420