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