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