[EFL] Call requestScrollPositionUpdate() instead of delegatedScrollRequested() in...
[WebKit-https.git] / Source / WebCore / platform / ScrollView.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2014 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 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
136 {
137     return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
138 }
139
140 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
141                                    bool horizontalLock, bool verticalLock)
142 {
143     bool needsUpdate = false;
144
145     if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
146         m_horizontalScrollbarMode = horizontalMode;
147         needsUpdate = true;
148     }
149
150     if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
151         m_verticalScrollbarMode = verticalMode;
152         needsUpdate = true;
153     }
154
155     if (horizontalLock)
156         setHorizontalScrollbarLock();
157
158     if (verticalLock)
159         setVerticalScrollbarLock();
160
161     if (!needsUpdate)
162         return;
163
164     if (platformWidget())
165         platformSetScrollbarModes();
166     else
167         updateScrollbars(scrollOffset());
168 }
169
170 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
171 {
172     if (platformWidget()) {
173         platformScrollbarModes(horizontalMode, verticalMode);
174         return;
175     }
176     horizontalMode = m_horizontalScrollbarMode;
177     verticalMode = m_verticalScrollbarMode;
178 }
179
180 void ScrollView::setCanHaveScrollbars(bool canScroll)
181 {
182     ScrollbarMode newHorizontalMode;
183     ScrollbarMode newVerticalMode;
184     
185     scrollbarModes(newHorizontalMode, newVerticalMode);
186     
187     if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
188         newVerticalMode = ScrollbarAuto;
189     else if (!canScroll)
190         newVerticalMode = ScrollbarAlwaysOff;
191     
192     if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
193         newHorizontalMode = ScrollbarAuto;
194     else if (!canScroll)
195         newHorizontalMode = ScrollbarAlwaysOff;
196     
197     setScrollbarModes(newHorizontalMode, newVerticalMode);
198 }
199
200 void ScrollView::setCanBlitOnScroll(bool b)
201 {
202     if (platformWidget()) {
203         platformSetCanBlitOnScroll(b);
204         return;
205     }
206
207     m_canBlitOnScroll = b;
208 }
209
210 bool ScrollView::canBlitOnScroll() const
211 {
212     if (platformWidget())
213         return platformCanBlitOnScroll();
214
215     return m_canBlitOnScroll;
216 }
217
218 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
219 {
220     m_paintsEntireContents = paintsEntireContents;
221 }
222
223 void ScrollView::setClipsRepaints(bool clipsRepaints)
224 {
225     m_clipsRepaints = clipsRepaints;
226 }
227
228 void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
229 {
230     if (m_delegatesScrolling == delegatesScrolling)
231         return;
232
233     m_delegatesScrolling = delegatesScrolling;
234     delegatesScrollingDidChange();
235 }
236
237 IntPoint ScrollView::contentsScrollPosition() const
238 {
239 #if PLATFORM(IOS)
240     if (platformWidget())
241         return actualScrollPosition();
242 #endif
243     return scrollPosition();
244 }
245
246 void ScrollView::setContentsScrollPosition(const IntPoint& position)
247 {
248 #if PLATFORM(IOS)
249     if (platformWidget())
250         setActualScrollPosition(position);
251 #endif
252     setScrollPosition(position);
253 }
254
255 #if !PLATFORM(IOS)
256 IntRect ScrollView::unobscuredContentRect(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
257 {
258     return unobscuredContentRectInternal(scrollbarInclusion);
259 }
260 #endif
261
262 IntRect ScrollView::unobscuredContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
263 {
264     FloatSize visibleContentSize = unscaledUnobscuredVisibleContentSize(scrollbarInclusion);
265     visibleContentSize.scale(1 / visibleContentScaleFactor());
266     return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize));
267 }
268
269 IntSize ScrollView::unscaledVisibleContentSizeIncludingObscuredArea(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
270 {
271     if (platformWidget())
272         return platformVisibleContentSizeIncludingObscuredArea(scrollbarInclusion == IncludeScrollbars);
273
274 #if USE(TILED_BACKING_STORE)
275     if (!m_fixedVisibleContentRect.isEmpty())
276         return m_fixedVisibleContentRect.size();
277 #endif
278
279     int verticalScrollbarWidth = 0;
280     int horizontalScrollbarHeight = 0;
281
282     if (scrollbarInclusion == ExcludeScrollbars) {
283         if (Scrollbar* verticalBar = verticalScrollbar())
284             verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
285         if (Scrollbar* horizontalBar = horizontalScrollbar())
286             horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
287     }
288
289     return IntSize(width() - verticalScrollbarWidth, height() - horizontalScrollbarHeight).expandedTo(IntSize());
290 }
291     
292 IntSize ScrollView::unscaledUnobscuredVisibleContentSize(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
293 {
294     IntSize visibleContentSize = unscaledVisibleContentSizeIncludingObscuredArea(scrollbarInclusion);
295
296     if (platformWidget())
297         return platformVisibleContentSize(scrollbarInclusion == IncludeScrollbars);
298
299 #if USE(TILED_BACKING_STORE)
300     if (!m_fixedVisibleContentRect.isEmpty())
301         return visibleContentSize;
302 #endif
303
304     visibleContentSize.setHeight(visibleContentSize.height() - topContentInset());
305     return visibleContentSize;
306 }
307
308 IntRect ScrollView::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior visibleContentRectBehavior) const
309 {
310 #if PLATFORM(IOS)
311     if (visibleContentRectBehavior == LegacyIOSDocumentViewRect) {
312         if (platformWidget())
313             return platformVisibleContentRect(scrollbarInclusion == IncludeScrollbars);
314     }
315     
316     if (platformWidget())
317         return unobscuredContentRect(scrollbarInclusion);
318 #else
319     UNUSED_PARAM(visibleContentRectBehavior);
320 #endif
321
322     if (platformWidget())
323         return platformVisibleContentRect(scrollbarInclusion == IncludeScrollbars);
324
325 #if USE(TILED_BACKING_STORE)
326     if (!m_fixedVisibleContentRect.isEmpty())
327         return m_fixedVisibleContentRect;
328 #endif
329
330     return unobscuredContentRect(scrollbarInclusion);
331 }
332
333 IntSize ScrollView::layoutSize() const
334 {
335     return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? unscaledUnobscuredVisibleContentSize(ExcludeScrollbars) : m_fixedLayoutSize;
336 }
337
338 IntSize ScrollView::fixedLayoutSize() const
339 {
340     return m_fixedLayoutSize;
341 }
342
343 void ScrollView::setFixedLayoutSize(const IntSize& newSize)
344 {
345     if (fixedLayoutSize() == newSize)
346         return;
347     m_fixedLayoutSize = newSize;
348     if (m_useFixedLayout)
349         fixedLayoutSizeChanged();
350 }
351
352 bool ScrollView::useFixedLayout() const
353 {
354     return m_useFixedLayout;
355 }
356
357 void ScrollView::setUseFixedLayout(bool enable)
358 {
359     if (useFixedLayout() == enable)
360         return;
361     m_useFixedLayout = enable;
362     if (!m_fixedLayoutSize.isEmpty())
363         fixedLayoutSizeChanged();
364 }
365
366 void ScrollView::fixedLayoutSizeChanged()
367 {
368     updateScrollbars(scrollOffset());
369     contentsResized();
370 }
371
372 IntSize ScrollView::contentsSize() const
373 {
374     return m_contentsSize;
375 }
376
377 void ScrollView::setContentsSize(const IntSize& newSize)
378 {
379     if (contentsSize() == newSize)
380         return;
381     m_contentsSize = newSize;
382     if (platformWidget())
383         platformSetContentsSize();
384     else
385         updateScrollbars(scrollOffset());
386     updateOverhangAreas();
387 }
388
389 IntPoint ScrollView::maximumScrollPosition() const
390 {
391     IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
392     maximumOffset.clampNegativeToZero();
393     return maximumOffset;
394 }
395
396 IntPoint ScrollView::minimumScrollPosition() const
397 {
398     return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
399 }
400
401 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
402 {
403     if (!constrainsScrollingToContentEdge())
404         return scrollPoint;
405
406     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
407     newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
408     return newScrollPosition;
409 }
410
411 IntSize ScrollView::documentScrollOffsetRelativeToViewOrigin() const
412 {
413     return scrollOffset() - IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
414 }
415
416 IntPoint ScrollView::documentScrollPositionRelativeToViewOrigin() const
417 {
418     IntPoint scrollPosition = this->scrollPosition();
419     return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight() - topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
420 }
421
422 IntSize ScrollView::documentScrollOffsetRelativeToScrollableAreaOrigin() const
423 {
424     return scrollOffset() - IntSize(0, headerHeight());
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         requestScrollPositionUpdate(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 = Scrollbar::pageStep(clientWidth);
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 = Scrollbar::pageStep(clientHeight);
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 + documentScrollOffsetRelativeToViewOrigin();
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(TopContentInsetType::WebCoreOrPlatformContentInset)) - 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(documentScrollOffsetRelativeToViewOrigin());
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(TopContentInsetType::WebCoreOrPlatformContentInset)));
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() - IntSize(0, topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
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 + documentScrollOffsetRelativeToViewOrigin();
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(TopContentInsetType::WebCoreOrPlatformContentInset)) - 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(documentScrollOffsetRelativeToViewOrigin());
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(TopContentInsetType::WebCoreOrPlatformContentInset)));
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         context->clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size()));
1222
1223         paintScrollbars(context, scrollViewDirtyRect);
1224     }
1225
1226     // Paint the panScroll Icon
1227     if (m_drawPanScrollIcon)
1228         paintPanScrollIcon(context);
1229 }
1230
1231 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1232 {
1233     int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1234         ? verticalScrollbar()->width() : 0;
1235     int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1236         ? horizontalScrollbar()->height() : 0;
1237
1238     int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
1239     if (physicalScrollY < 0) {
1240         horizontalOverhangRect = frameRect();
1241         horizontalOverhangRect.setHeight(-physicalScrollY);
1242         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1243     } else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight()) {
1244         int height = physicalScrollY - (totalContentsSize().height() - visibleHeight());
1245         horizontalOverhangRect = frameRect();
1246         horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
1247         horizontalOverhangRect.setHeight(height);
1248         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1249     }
1250
1251     int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
1252     if (physicalScrollX < 0) {
1253         verticalOverhangRect.setWidth(-physicalScrollX);
1254         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1255         verticalOverhangRect.setX(frameRect().x());
1256         if (horizontalOverhangRect.y() == frameRect().y())
1257             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1258         else
1259             verticalOverhangRect.setY(frameRect().y());
1260     } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
1261         int width = physicalScrollX - (contentsWidth() - visibleWidth());
1262         verticalOverhangRect.setWidth(width);
1263         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1264         verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
1265         if (horizontalOverhangRect.y() == frameRect().y())
1266             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1267         else
1268             verticalOverhangRect.setY(frameRect().y());
1269     }
1270 }
1271
1272 void ScrollView::updateOverhangAreas()
1273 {
1274     HostWindow* window = hostWindow();
1275     if (!window)
1276         return;
1277
1278     IntRect horizontalOverhangRect;
1279     IntRect verticalOverhangRect;
1280     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1281     if (!horizontalOverhangRect.isEmpty())
1282         window->invalidateContentsAndRootView(horizontalOverhangRect);
1283     if (!verticalOverhangRect.isEmpty())
1284         window->invalidateContentsAndRootView(verticalOverhangRect);
1285 }
1286
1287 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
1288 {
1289     ScrollbarTheme::theme()->paintOverhangAreas(this, context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1290 }
1291
1292 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const IntRect& dirtyRect)
1293 {
1294     IntRect horizontalOverhangRect;
1295     IntRect verticalOverhangRect;
1296     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1297
1298     if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
1299         paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1300 }
1301
1302 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1303 {
1304     if (!scrollbarCornerPresent())
1305         return false;
1306
1307     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1308
1309     if (m_horizontalScrollbar) {
1310         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1311         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1312         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1313
1314         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1315     }
1316
1317     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1318     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1319     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1320     
1321     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1322 }
1323
1324 bool ScrollView::scrollbarCornerPresent() const
1325 {
1326     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
1327         || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
1328 }
1329
1330 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1331 {
1332     // Scrollbars won't be transformed within us
1333     IntRect newRect = localRect;
1334     newRect.moveBy(scrollbar->location());
1335     return newRect;
1336 }
1337
1338 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1339 {
1340     IntRect newRect = parentRect;
1341     // Scrollbars won't be transformed within us
1342     newRect.moveBy(-scrollbar->location());
1343     return newRect;
1344 }
1345
1346 // FIXME: test these on windows
1347 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1348 {
1349     // Scrollbars won't be transformed within us
1350     IntPoint newPoint = localPoint;
1351     newPoint.moveBy(scrollbar->location());
1352     return newPoint;
1353 }
1354
1355 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1356 {
1357     IntPoint newPoint = parentPoint;
1358     // Scrollbars won't be transformed within us
1359     newPoint.moveBy(-scrollbar->location());
1360     return newPoint;
1361 }
1362
1363 void ScrollView::setParentVisible(bool visible)
1364 {
1365     if (isParentVisible() == visible)
1366         return;
1367     
1368     Widget::setParentVisible(visible);
1369
1370     if (!isSelfVisible())
1371         return;
1372         
1373     HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1374     for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1375         (*it)->setParentVisible(visible);
1376 }
1377
1378 void ScrollView::show()
1379 {
1380     if (!isSelfVisible()) {
1381         setSelfVisible(true);
1382         if (isParentVisible()) {
1383             HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1384             for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1385                 (*it)->setParentVisible(true);
1386         }
1387     }
1388
1389     Widget::show();
1390 }
1391
1392 void ScrollView::hide()
1393 {
1394     if (isSelfVisible()) {
1395         if (isParentVisible()) {
1396             HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1397             for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1398                 (*it)->setParentVisible(false);
1399         }
1400         setSelfVisible(false);
1401     }
1402
1403     Widget::hide();
1404 }
1405
1406 bool ScrollView::isOffscreen() const
1407 {
1408     if (platformWidget())
1409         return platformIsOffscreen();
1410     
1411     if (!isVisible())
1412         return true;
1413     
1414     // FIXME: Add a HostWindow::isOffscreen method here.  Since only Mac implements this method
1415     // currently, we can add the method when the other platforms decide to implement this concept.
1416     return false;
1417 }
1418
1419
1420 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1421 {
1422     HostWindow* window = hostWindow();
1423     if (!window)
1424         return;
1425     m_drawPanScrollIcon = true;    
1426     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1427     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1428 }
1429
1430 void ScrollView::removePanScrollIcon()
1431 {
1432     HostWindow* window = hostWindow();
1433     if (!window)
1434         return;
1435     m_drawPanScrollIcon = false; 
1436     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1437 }
1438
1439 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1440 {
1441     if (scrollOrigin() == origin)
1442         return;
1443
1444     ScrollableArea::setScrollOrigin(origin);
1445
1446     if (platformWidget()) {
1447         platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1448         return;
1449     }
1450     
1451     // Update if the scroll origin changes, since our position will be different if the content size did not change.
1452     if (updatePositionAtAll && updatePositionSynchronously)
1453         updateScrollbars(scrollOffset());
1454 }
1455
1456 void ScrollView::styleDidChange()
1457 {
1458     if (m_horizontalScrollbar)
1459         m_horizontalScrollbar->styleChanged();
1460
1461     if (m_verticalScrollbar)
1462         m_verticalScrollbar->styleChanged();
1463 }
1464
1465 #if !PLATFORM(COCOA)
1466
1467 void ScrollView::platformAddChild(Widget*)
1468 {
1469 }
1470
1471 void ScrollView::platformRemoveChild(Widget*)
1472 {
1473 }
1474
1475 #endif
1476
1477 #if !PLATFORM(COCOA)
1478
1479 void ScrollView::platformSetScrollbarsSuppressed(bool)
1480 {
1481 }
1482
1483 void ScrollView::platformSetScrollOrigin(const IntPoint&, bool, bool)
1484 {
1485 }
1486
1487 void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle)
1488 {
1489 }
1490
1491 #endif
1492
1493 #if !PLATFORM(COCOA)
1494
1495 void ScrollView::platformSetScrollbarModes()
1496 {
1497 }
1498
1499 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1500 {
1501     horizontal = ScrollbarAuto;
1502     vertical = ScrollbarAuto;
1503 }
1504
1505 void ScrollView::platformSetCanBlitOnScroll(bool)
1506 {
1507 }
1508
1509 bool ScrollView::platformCanBlitOnScroll() const
1510 {
1511     return false;
1512 }
1513
1514 IntRect ScrollView::platformVisibleContentRect(bool) const
1515 {
1516     return IntRect();
1517 }
1518
1519 float ScrollView::platformTopContentInset() const
1520 {
1521     return 0;
1522 }
1523
1524 void ScrollView::platformSetTopContentInset(float)
1525 {
1526 }
1527
1528 IntSize ScrollView::platformVisibleContentSize(bool) const
1529 {
1530     return IntSize();
1531 }
1532
1533 IntRect ScrollView::platformVisibleContentRectIncludingObscuredArea(bool) const
1534 {
1535     return IntRect();
1536 }
1537
1538 IntSize ScrollView::platformVisibleContentSizeIncludingObscuredArea(bool) const
1539 {
1540     return IntSize();
1541 }
1542
1543 void ScrollView::platformSetContentsSize()
1544 {
1545 }
1546
1547 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1548 {
1549     return rect;
1550 }
1551
1552 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1553 {
1554     return point;
1555 }
1556
1557 void ScrollView::platformSetScrollPosition(const IntPoint&)
1558 {
1559 }
1560
1561 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1562 {
1563     return true;
1564 }
1565
1566 void ScrollView::platformRepaintContentRectangle(const IntRect&)
1567 {
1568 }
1569
1570 bool ScrollView::platformIsOffscreen() const
1571 {
1572     return false;
1573 }
1574
1575 #endif
1576
1577 }