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