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