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