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