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