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