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