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