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