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