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