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