Remove ScrollView::scrollOffset() in preparation for scrollOffset vs. scrollPosition...
[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(IntPoint(m_scrollOffset), 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     IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
392     maximumOffset.clampNegativeToZero();
393     return maximumOffset;
394 }
395
396 ScrollPosition ScrollView::minimumScrollPosition() const
397 {
398     return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
399 }
400
401 ScrollPosition ScrollView::adjustScrollPositionWithinRange(const ScrollPosition& scrollPoint) const
402 {
403     if (!constrainsScrollingToContentEdge())
404         return scrollPoint;
405
406     return scrollPoint.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
407 }
408
409 IntSize ScrollView::documentScrollOffsetRelativeToViewOrigin() const
410 {
411     return toIntSize(scrollPosition()) - IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
412 }
413
414 IntPoint ScrollView::documentScrollPositionRelativeToViewOrigin() const
415 {
416     IntPoint scrollPosition = this->scrollPosition();
417     return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight() - topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
418 }
419
420 IntSize ScrollView::documentScrollOffsetRelativeToScrollableAreaOrigin() const
421 {
422     return toIntSize(scrollPosition()) - IntSize(0, headerHeight());
423 }
424
425 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
426 {
427     // If no scrollbars are present, it does not indicate content is not be scrollable.
428     if (!m_horizontalScrollbar && !m_verticalScrollbar && !prohibitsScrolling()) {
429         IntSize scrollSize = m_contentsSize - visibleContentRect(LegacyIOSDocumentVisibleRect).size();
430         scrollSize.clampNegativeToZero();
431         return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
432     }
433
434     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
435     return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
436 }
437
438 void ScrollView::notifyPageThatContentAreaWillPaint() const
439 {
440 }
441
442 void ScrollView::setScrollOffset(const IntPoint& offset)
443 {
444     int horizontalOffset = offset.x();
445     int verticalOffset = offset.y();
446     if (constrainsScrollingToContentEdge()) {
447         horizontalOffset = std::max(std::min(horizontalOffset, contentsWidth() - visibleWidth()), 0);
448         verticalOffset = std::max(std::min(verticalOffset, totalContentsSize().height() - visibleHeight()), 0);
449     }
450
451     IntSize newOffset = m_scrollOffset;
452     newOffset.setWidth(horizontalOffset - scrollOrigin().x());
453     newOffset.setHeight(verticalOffset - scrollOrigin().y());
454
455     scrollTo(newOffset);
456 }
457
458 void ScrollView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
459 {
460     // We should not attempt to actually modify (paint) platform widgets if the layout phase
461     // is not complete. Instead, defer the scroll event until the layout finishes.
462     if (shouldDeferScrollUpdateAfterContentSizeChange()) {
463         // We only care about the most recent scroll position change request
464         m_deferredScrollPositions = std::make_unique<std::pair<IntPoint, IntPoint>>(std::make_pair(oldPosition, newPosition));
465         return;
466     }
467
468     scrollPositionChangedViaPlatformWidgetImpl(oldPosition, newPosition);
469 }
470
471 void ScrollView::handleDeferredScrollUpdateAfterContentSizeChange()
472 {
473     ASSERT(!shouldDeferScrollUpdateAfterContentSizeChange());
474
475     if (!m_deferredScrollDelta && !m_deferredScrollPositions)
476         return;
477
478     ASSERT(static_cast<bool>(m_deferredScrollDelta) != static_cast<bool>(m_deferredScrollPositions));
479
480     if (m_deferredScrollDelta)
481         completeUpdatesAfterScrollTo(*m_deferredScrollDelta);
482     else if (m_deferredScrollPositions)
483         scrollPositionChangedViaPlatformWidgetImpl(m_deferredScrollPositions->first, m_deferredScrollPositions->second);
484     
485     m_deferredScrollDelta = nullptr;
486     m_deferredScrollPositions = nullptr;
487 }
488
489 void ScrollView::scrollTo(const IntSize& newOffset)
490 {
491     IntSize scrollDelta = newOffset - m_scrollOffset;
492     if (scrollDelta.isZero())
493         return;
494     m_scrollOffset = newOffset;
495
496     if (scrollbarsSuppressed())
497         return;
498
499 #if USE(COORDINATED_GRAPHICS)
500     if (delegatesScrolling()) {
501         requestScrollPositionUpdate(IntPoint(newOffset));
502         return;
503     }
504 #endif
505     // We should not attempt to actually modify layer contents if the layout phase
506     // is not complete. Instead, defer the scroll event until the layout finishes.
507     if (shouldDeferScrollUpdateAfterContentSizeChange()) {
508         ASSERT(!m_deferredScrollDelta);
509         m_deferredScrollDelta = std::make_unique<IntSize>(scrollDelta);
510         return;
511     }
512
513     completeUpdatesAfterScrollTo(scrollDelta);
514 }
515
516 void ScrollView::completeUpdatesAfterScrollTo(const IntSize& scrollDelta)
517 {
518     updateLayerPositionsAfterScrolling();
519     scrollContents(scrollDelta);
520     updateCompositingLayersAfterScrolling();
521 }
522
523 int ScrollView::scrollPosition(Scrollbar* scrollbar) const
524 {
525     if (scrollbar->orientation() == HorizontalScrollbar)
526         return scrollPosition().x() + scrollOrigin().x();
527     if (scrollbar->orientation() == VerticalScrollbar)
528         return scrollPosition().y() + scrollOrigin().y();
529     return 0;
530 }
531
532 void ScrollView::setScrollPosition(const ScrollPosition& scrollPosition)
533 {
534     if (prohibitsScrolling())
535         return;
536
537     if (platformWidget()) {
538         platformSetScrollPosition(scrollPosition);
539         return;
540     }
541
542     IntPoint newScrollPosition = !delegatesScrolling() ? adjustScrollPositionWithinRange(scrollPosition) : scrollPosition;
543
544     if ((!delegatesScrolling() || !inProgrammaticScroll()) && newScrollPosition == this->scrollPosition())
545         return;
546
547     if (requestScrollPositionUpdate(newScrollPosition))
548         return;
549
550     updateScrollbars(newScrollPosition);
551 }
552
553 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
554 {
555     if (platformWidget())
556         return platformScroll(direction, granularity);
557
558     return ScrollableArea::scroll(direction, granularity);
559 }
560
561 bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
562 {
563     return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
564 }
565
566 IntSize ScrollView::overhangAmount() const
567 {
568     IntSize stretch;
569
570     int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
571     if (physicalScrollY < 0)
572         stretch.setHeight(physicalScrollY);
573     else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight())
574         stretch.setHeight(physicalScrollY - (totalContentsSize().height() - visibleHeight()));
575
576     int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
577     if (physicalScrollX < 0)
578         stretch.setWidth(physicalScrollX);
579     else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth())
580         stretch.setWidth(physicalScrollX - (contentsWidth() - visibleWidth()));
581
582     return stretch;
583 }
584
585 void ScrollView::updateScrollbars(const ScrollPosition& desiredPosition)
586 {
587     if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget() || delegatesScrolling())
588         return;
589
590     bool hasOverlayScrollbars = (!m_horizontalScrollbar || m_horizontalScrollbar->isOverlayScrollbar()) && (!m_verticalScrollbar || m_verticalScrollbar->isOverlayScrollbar());
591
592     // If we came in here with the view already needing a layout then do that first.
593     // (This will be the common case, e.g., when the page changes due to window resizing for example).
594     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
595     if (!m_scrollbarsSuppressed && !hasOverlayScrollbars) {
596         m_inUpdateScrollbars = true;
597         updateContentsSize();
598         m_inUpdateScrollbars = false;
599     }
600
601     IntRect oldScrollCornerRect = scrollCornerRect();
602
603     bool hasHorizontalScrollbar = m_horizontalScrollbar;
604     bool hasVerticalScrollbar = m_verticalScrollbar;
605     
606     bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
607     bool newHasVerticalScrollbar = hasVerticalScrollbar;
608    
609     ScrollbarMode hScroll = m_horizontalScrollbarMode;
610     ScrollbarMode vScroll = m_verticalScrollbarMode;
611
612     if (hScroll != ScrollbarAuto)
613         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
614     if (vScroll != ScrollbarAuto)
615         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
616
617     bool scrollbarAddedOrRemoved = false;
618
619     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
620         if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
621             if (setHasHorizontalScrollbar(newHasHorizontalScrollbar))
622                 scrollbarAddedOrRemoved = true;
623         }
624
625         if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
626             if (setHasVerticalScrollbar(newHasVerticalScrollbar))
627                 scrollbarAddedOrRemoved = true;
628         }
629     } else {
630         bool sendContentResizedNotification = false;
631         
632         IntSize docSize = totalContentsSize();
633         IntSize fullVisibleSize = unobscuredContentRectIncludingScrollbars().size();
634
635         if (hScroll == ScrollbarAuto)
636             newHasHorizontalScrollbar = docSize.width() > visibleWidth();
637         if (vScroll == ScrollbarAuto)
638             newHasVerticalScrollbar = docSize.height() > visibleHeight();
639
640         bool needAnotherPass = false;
641         if (!hasOverlayScrollbars) {
642             // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
643             // try to both gain/lose a scrollbar in the same pass.
644             if (!m_updateScrollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()) {
645                 if (hScroll == ScrollbarAuto)
646                     newHasHorizontalScrollbar = false;
647                 if (vScroll == ScrollbarAuto)
648                     newHasVerticalScrollbar = false;
649             }
650             if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) {
651                 newHasVerticalScrollbar = false;
652                 needAnotherPass = true;
653             }
654             if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) {
655                 newHasHorizontalScrollbar = false;
656                 needAnotherPass = true;
657             }
658         }
659
660         if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
661             if (scrollOrigin().y() && !newHasHorizontalScrollbar)
662                 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x(), scrollOrigin().y() - m_horizontalScrollbar->occupiedHeight()));
663             if (m_horizontalScrollbar)
664                 m_horizontalScrollbar->invalidate();
665
666             bool changeAffectsContentSize = false;
667             if (setHasHorizontalScrollbar(newHasHorizontalScrollbar, &changeAffectsContentSize)) {
668                 scrollbarAddedOrRemoved = true;
669                 sendContentResizedNotification |= changeAffectsContentSize;
670             }
671         }
672
673         if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
674             if (scrollOrigin().x() && !newHasVerticalScrollbar)
675                 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x() - m_verticalScrollbar->occupiedWidth(), scrollOrigin().y()));
676             if (m_verticalScrollbar)
677                 m_verticalScrollbar->invalidate();
678
679             bool changeAffectsContentSize = false;
680             if (setHasVerticalScrollbar(newHasVerticalScrollbar, &changeAffectsContentSize)) {
681                 scrollbarAddedOrRemoved = true;
682                 sendContentResizedNotification |= changeAffectsContentSize;
683             }
684         }
685
686         const unsigned cMaxUpdateScrollbarsPass = 2;
687         if ((sendContentResizedNotification || needAnotherPass) && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
688             m_updateScrollbarsPass++;
689             availableContentSizeChanged(AvailableSizeChangeReason::ScrollbarsChanged);
690             updateContentsSize();
691             IntSize newDocSize = totalContentsSize();
692             if (newDocSize == docSize) {
693                 // The layout with the new scroll state had no impact on
694                 // the document's overall size, so updateScrollbars didn't get called.
695                 // Recur manually.
696                 updateScrollbars(desiredPosition);
697             }
698             m_updateScrollbarsPass--;
699         }
700     }
701
702     if (scrollbarAddedOrRemoved)
703         addedOrRemovedScrollbar();
704
705     // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
706     // doing it multiple times).
707     if (m_updateScrollbarsPass)
708         return;
709
710     m_inUpdateScrollbars = true;
711
712     if (m_horizontalScrollbar) {
713         int clientWidth = visibleWidth();
714         int pageStep = Scrollbar::pageStep(clientWidth);
715         IntRect oldRect(m_horizontalScrollbar->frameRect());
716         IntRect hBarRect(0,
717             height() - m_horizontalScrollbar->height(),
718             width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
719             m_horizontalScrollbar->height());
720         m_horizontalScrollbar->setFrameRect(hBarRect);
721         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
722             m_horizontalScrollbar->invalidate();
723
724         if (m_scrollbarsSuppressed)
725             m_horizontalScrollbar->setSuppressInvalidation(true);
726         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
727         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
728         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
729         if (m_scrollbarsSuppressed)
730             m_horizontalScrollbar->setSuppressInvalidation(false); 
731     } 
732
733     if (m_verticalScrollbar) {
734         int clientHeight = visibleHeight();
735         int pageStep = Scrollbar::pageStep(clientHeight);
736         IntRect oldRect(m_verticalScrollbar->frameRect());
737         IntRect vBarRect(width() - m_verticalScrollbar->width(), 
738             topContentInset(),
739             m_verticalScrollbar->width(),
740             height() - topContentInset() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
741         m_verticalScrollbar->setFrameRect(vBarRect);
742         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
743             m_verticalScrollbar->invalidate();
744
745         if (m_scrollbarsSuppressed)
746             m_verticalScrollbar->setSuppressInvalidation(true);
747         m_verticalScrollbar->setEnabled(totalContentsSize().height() > clientHeight);
748         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
749         m_verticalScrollbar->setProportion(clientHeight, totalContentsSize().height());
750         if (m_scrollbarsSuppressed)
751             m_verticalScrollbar->setSuppressInvalidation(false);
752     }
753
754     if (hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar) {
755         // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
756         frameRectsChanged();
757         positionScrollbarLayers();
758         updateScrollCorner();
759         if (!m_horizontalScrollbar && !m_verticalScrollbar)
760             invalidateScrollCornerRect(oldScrollCornerRect);
761     }
762
763     IntPoint adjustedScrollPosition = desiredPosition;
764     if (!isRubberBandInProgress())
765         adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
766
767     if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) {
768         ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition + toIntSize(scrollOrigin()));
769         resetScrollOriginChanged();
770     }
771
772     // Make sure the scrollbar offsets are up to date.
773     if (m_horizontalScrollbar)
774         m_horizontalScrollbar->offsetDidChange();
775     if (m_verticalScrollbar)
776         m_verticalScrollbar->offsetDidChange();
777
778     m_inUpdateScrollbars = false;
779 }
780
781 const int panIconSizeLength = 16;
782
783 IntRect ScrollView::rectToCopyOnScroll() const
784 {
785     IntRect scrollViewRect = convertToRootView(IntRect(0, 0, visibleWidth(), visibleHeight()));
786     if (hasOverlayScrollbars()) {
787         int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
788         int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
789         
790         scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
791         scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
792     }
793     return scrollViewRect;
794 }
795
796 void ScrollView::scrollContents(const IntSize& scrollDelta)
797 {
798     HostWindow* window = hostWindow();
799     if (!window)
800         return;
801
802     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
803     // with the clip rect every time to keep it smooth.
804     IntRect clipRect = windowClipRect();
805     IntRect scrollViewRect = rectToCopyOnScroll();    
806     IntRect updateRect = clipRect;
807     updateRect.intersect(scrollViewRect);
808
809     // Invalidate the root view (not the backing store).
810     window->invalidateRootView(updateRect);
811
812     if (m_drawPanScrollIcon) {
813         // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
814         // https://bugs.webkit.org/show_bug.cgi?id=47837
815         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
816         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
817         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
818         panScrollIconDirtyRect.intersect(clipRect);
819         window->invalidateContentsAndRootView(panScrollIconDirtyRect);
820     }
821
822     if (canBlitOnScroll()) { // The main frame can just blit the WebView window
823         // FIXME: Find a way to scroll subframes with this faster path
824         if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
825             scrollContentsSlowPath(updateRect);
826     } else { 
827         // We need to repaint the entire backing store. Do it now before moving the windowed plugins.
828         scrollContentsSlowPath(updateRect);
829     }
830
831     // Invalidate the overhang areas if they are visible.
832     updateOverhangAreas();
833
834     // This call will move children with native widgets (plugins) and invalidate them as well.
835     frameRectsChanged();
836
837     // Now blit the backingstore into the window which should be very fast.
838     window->invalidateRootView(IntRect());
839 }
840
841 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
842 {
843     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
844     return true;
845 }
846
847 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
848 {
849     hostWindow()->invalidateContentsForSlowScroll(updateRect);
850 }
851
852 IntPoint ScrollView::viewToContents(const IntPoint& point) const
853 {
854     return point + documentScrollOffsetRelativeToViewOrigin();
855 }
856
857 IntPoint ScrollView::contentsToView(const IntPoint& point) const
858 {
859     return point - documentScrollOffsetRelativeToViewOrigin();
860 }
861
862 IntRect ScrollView::viewToContents(IntRect rect) const
863 {
864     rect.move(documentScrollOffsetRelativeToViewOrigin());
865     return rect;
866 }
867
868 IntRect ScrollView::contentsToView(IntRect rect) const
869 {
870     rect.move(-documentScrollOffsetRelativeToViewOrigin());
871     return rect;
872 }
873
874 IntPoint ScrollView::contentsToContainingViewContents(const IntPoint& point) const
875 {
876     if (const ScrollView* parentScrollView = parent()) {
877         IntPoint pointInContainingView = convertToContainingView(contentsToView(point));
878         return parentScrollView->viewToContents(pointInContainingView);
879     }
880
881     return contentsToView(point);
882 }
883
884 IntRect ScrollView::contentsToContainingViewContents(IntRect rect) const
885 {
886     if (const ScrollView* parentScrollView = parent()) {
887         IntRect rectInContainingView = convertToContainingView(contentsToView(rect));
888         return parentScrollView->viewToContents(rectInContainingView);
889     }
890
891     return contentsToView(rect);
892 }
893
894 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const
895 {
896     if (delegatesScrolling())
897         return convertFromRootView(rootViewPoint);
898
899     return viewToContents(convertFromRootView(rootViewPoint));
900 }
901
902 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const
903 {
904     if (delegatesScrolling())
905         return convertToRootView(contentsPoint);
906
907     return convertToRootView(contentsToView(contentsPoint));
908 }
909
910 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const
911 {
912     if (delegatesScrolling())
913         return convertFromRootView(rootViewRect);
914
915     return viewToContents(convertFromRootView(rootViewRect));
916 }
917
918 IntPoint ScrollView::rootViewToTotalContents(const IntPoint& rootViewPoint) const
919 {
920     if (delegatesScrolling())
921         return convertFromRootView(rootViewPoint);
922
923     IntPoint viewPoint = convertFromRootView(rootViewPoint);
924     // Like rootViewToContents(), but ignores headerHeight.
925     return viewPoint + toIntSize(scrollPosition()) - IntSize(0, topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
926 }
927
928 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const
929 {
930     if (delegatesScrolling())
931         return convertToRootView(contentsRect);
932
933     return convertToRootView(contentsToView(contentsRect));
934 }
935
936 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
937 {
938     if (delegatesScrolling())
939         return convertFromContainingWindow(windowPoint);
940
941     return viewToContents(convertFromContainingWindow(windowPoint));
942 }
943
944 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
945 {
946     if (delegatesScrolling())
947         return convertToContainingWindow(contentsPoint);
948
949     return convertToContainingWindow(contentsToView(contentsPoint));
950 }
951
952 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
953 {
954     if (delegatesScrolling())
955         return convertFromContainingWindow(windowRect);
956
957     return viewToContents(convertFromContainingWindow(windowRect));
958 }
959
960 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
961 {
962     if (delegatesScrolling())
963         return convertToContainingWindow(contentsRect);
964
965     return convertToContainingWindow(contentsToView(contentsRect));
966 }
967
968 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
969 {
970     HostWindow* window = hostWindow();
971     if (platformWidget())
972         return platformContentsToScreen(rect);
973     if (!window)
974         return IntRect();
975     return window->rootViewToScreen(contentsToRootView(rect));
976 }
977
978 IntPoint ScrollView::screenToContents(const IntPoint& point) const
979 {
980     HostWindow* window = hostWindow();
981     if (platformWidget())
982         return platformScreenToContents(point);
983     if (!window)
984         return IntPoint();
985     return rootViewToContents(window->screenToRootView(point));
986 }
987
988 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
989 {
990     if (suppressed == m_scrollbarsSuppressed)
991         return;
992
993     m_scrollbarsSuppressed = suppressed;
994
995     if (platformWidget())
996         platformSetScrollbarsSuppressed(repaintOnUnsuppress);
997     else if (repaintOnUnsuppress && !suppressed) {
998         if (m_horizontalScrollbar)
999             m_horizontalScrollbar->invalidate();
1000         if (m_verticalScrollbar)
1001             m_verticalScrollbar->invalidate();
1002
1003         // Invalidate the scroll corner too on unsuppress.
1004         invalidateRect(scrollCornerRect());
1005     }
1006 }
1007
1008 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
1009 {
1010     if (platformWidget())
1011         return 0;
1012
1013     // convertFromContainingWindow doesn't do what it sounds like it does. We need it here just to get this
1014     // point into the right coordinates if this is the ScrollView of a sub-frame.
1015     IntPoint convertedPoint = convertFromContainingWindow(windowPoint);
1016     if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(convertedPoint))
1017         return m_horizontalScrollbar.get();
1018     if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(convertedPoint))
1019         return m_verticalScrollbar.get();
1020     return 0;
1021 }
1022
1023 void ScrollView::setScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle)
1024 {
1025     ScrollableArea::setScrollbarOverlayStyle(overlayStyle);
1026     platformSetScrollbarOverlayStyle(overlayStyle);
1027 }
1028
1029 void ScrollView::setFrameRect(const IntRect& newRect)
1030 {
1031     Ref<ScrollView> protect(*this);
1032     IntRect oldRect = frameRect();
1033     
1034     if (newRect == oldRect)
1035         return;
1036
1037     Widget::setFrameRect(newRect);
1038     frameRectsChanged();
1039
1040     updateScrollbars(scrollPosition());
1041     
1042     if (!m_useFixedLayout && oldRect.size() != newRect.size())
1043         availableContentSizeChanged(AvailableSizeChangeReason::AreaSizeChanged);
1044 }
1045
1046 void ScrollView::frameRectsChanged()
1047 {
1048     if (platformWidget())
1049         return;
1050
1051     HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1052     for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1053         (*current)->frameRectsChanged();
1054 }
1055
1056 void ScrollView::clipRectChanged()
1057 {
1058     HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1059     for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1060         (*current)->clipRectChanged();
1061 }
1062
1063 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
1064 {
1065     if (!graphicsLayer || !scrollbar)
1066         return;
1067
1068     IntRect scrollbarRect = scrollbar->frameRect();
1069     graphicsLayer->setPosition(scrollbarRect.location());
1070
1071     if (scrollbarRect.size() == graphicsLayer->size())
1072         return;
1073
1074     graphicsLayer->setSize(scrollbarRect.size());
1075
1076     if (graphicsLayer->usesContentsLayer()) {
1077         graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
1078         return;
1079     }
1080
1081     graphicsLayer->setDrawsContent(true);
1082     graphicsLayer->setNeedsDisplay();
1083 }
1084
1085 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
1086 {
1087     if (!graphicsLayer)
1088         return;
1089     graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
1090     graphicsLayer->setPosition(cornerRect.location());
1091     if (cornerRect.size() != graphicsLayer->size())
1092         graphicsLayer->setNeedsDisplay();
1093     graphicsLayer->setSize(cornerRect.size());
1094 }
1095
1096 void ScrollView::positionScrollbarLayers()
1097 {
1098     positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
1099     positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
1100     positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
1101 }
1102
1103 void ScrollView::repaintContentRectangle(const IntRect& rect)
1104 {
1105     IntRect paintRect = rect;
1106     if (clipsRepaints() && !paintsEntireContents())
1107         paintRect.intersect(visibleContentRect(LegacyIOSDocumentVisibleRect));
1108     if (paintRect.isEmpty())
1109         return;
1110
1111     if (platformWidget()) {
1112         notifyPageThatContentAreaWillPaint();
1113         platformRepaintContentRectangle(paintRect);
1114         return;
1115     }
1116
1117     if (HostWindow* window = hostWindow())
1118         window->invalidateContentsAndRootView(contentsToWindow(paintRect));
1119 }
1120
1121 IntRect ScrollView::scrollCornerRect() const
1122 {
1123     IntRect cornerRect;
1124
1125     if (hasOverlayScrollbars())
1126         return cornerRect;
1127
1128     int heightTrackedByScrollbar = height() - topContentInset();
1129
1130     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
1131         cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
1132             height() - m_horizontalScrollbar->height(),
1133             width() - m_horizontalScrollbar->width(),
1134             m_horizontalScrollbar->height()));
1135     }
1136
1137     if (m_verticalScrollbar && heightTrackedByScrollbar - m_verticalScrollbar->height() > 0) {
1138         cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
1139             m_verticalScrollbar->height() + topContentInset(),
1140             m_verticalScrollbar->width(),
1141             heightTrackedByScrollbar - m_verticalScrollbar->height()));
1142     }
1143
1144     return cornerRect;
1145 }
1146
1147 bool ScrollView::isScrollCornerVisible() const
1148 {
1149     return !scrollCornerRect().isEmpty();
1150 }
1151
1152 void ScrollView::scrollbarStyleChanged(ScrollbarStyle newStyle, bool forceUpdate)
1153 {
1154     ScrollableArea::scrollbarStyleChanged(newStyle, forceUpdate);
1155     if (!forceUpdate)
1156         return;
1157
1158     updateScrollbars(scrollPosition());
1159     positionScrollbarLayers();
1160 }
1161
1162 void ScrollView::updateScrollCorner()
1163 {
1164 }
1165
1166 void ScrollView::paintScrollCorner(GraphicsContext& context, const IntRect& cornerRect)
1167 {
1168     ScrollbarTheme::theme().paintScrollCorner(this, context, cornerRect);
1169 }
1170
1171 void ScrollView::paintScrollbar(GraphicsContext& context, Scrollbar& bar, const IntRect& rect)
1172 {
1173     bar.paint(context, rect);
1174 }
1175
1176 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
1177 {
1178     invalidateRect(rect);
1179 }
1180
1181 void ScrollView::paintScrollbars(GraphicsContext& context, const IntRect& rect)
1182 {
1183     if (m_horizontalScrollbar && !layerForHorizontalScrollbar())
1184         paintScrollbar(context, *m_horizontalScrollbar.get(), rect);
1185     if (m_verticalScrollbar && !layerForVerticalScrollbar())
1186         paintScrollbar(context, *m_verticalScrollbar.get(), rect);
1187
1188     if (layerForScrollCorner())
1189         return;
1190
1191     paintScrollCorner(context, scrollCornerRect());
1192 }
1193
1194 void ScrollView::paintPanScrollIcon(GraphicsContext& context)
1195 {
1196     static Image* panScrollIcon = Image::loadPlatformResource("panIcon").leakRef();
1197     if (!panScrollIcon)
1198         return;
1199     IntPoint iconGCPoint = m_panScrollIconPoint;
1200     if (parent())
1201         iconGCPoint = parent()->windowToContents(iconGCPoint);
1202     context.drawImage(*panScrollIcon, iconGCPoint);
1203 }
1204
1205 void ScrollView::paint(GraphicsContext& context, const IntRect& rect)
1206 {
1207     if (platformWidget()) {
1208         Widget::paint(context, rect);
1209         return;
1210     }
1211
1212     if (context.paintingDisabled() && !context.updatingControlTints())
1213         return;
1214
1215     notifyPageThatContentAreaWillPaint();
1216
1217     IntRect documentDirtyRect = rect;
1218     if (!paintsEntireContents()) {
1219         IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect(LegacyIOSDocumentVisibleRect).size());
1220         documentDirtyRect.intersect(visibleAreaWithoutScrollbars);
1221     }
1222
1223     if (!documentDirtyRect.isEmpty()) {
1224         GraphicsContextStateSaver stateSaver(context);
1225
1226         context.translate(x(), y());
1227         documentDirtyRect.moveBy(-location());
1228
1229         if (!paintsEntireContents()) {
1230             context.translate(-scrollX(), -scrollY());
1231             documentDirtyRect.moveBy(scrollPosition());
1232
1233             context.clip(visibleContentRect(LegacyIOSDocumentVisibleRect));
1234         }
1235
1236         paintContents(context, documentDirtyRect);
1237     }
1238
1239 #if ENABLE(RUBBER_BANDING)
1240     if (!layerForOverhangAreas())
1241         calculateAndPaintOverhangAreas(context, rect);
1242 #else
1243     calculateAndPaintOverhangAreas(context, rect);
1244 #endif
1245
1246     // Now paint the scrollbars.
1247     if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
1248         GraphicsContextStateSaver stateSaver(context);
1249         IntRect scrollViewDirtyRect = rect;
1250         IntRect visibleAreaWithScrollbars(location(), unobscuredContentRectIncludingScrollbars().size());
1251         scrollViewDirtyRect.intersect(visibleAreaWithScrollbars);
1252         context.translate(x(), y());
1253         scrollViewDirtyRect.moveBy(-location());
1254         context.clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size()));
1255
1256         paintScrollbars(context, scrollViewDirtyRect);
1257     }
1258
1259     // Paint the panScroll Icon
1260     if (m_drawPanScrollIcon)
1261         paintPanScrollIcon(context);
1262 }
1263
1264 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1265 {
1266     IntSize scrollbarSpace = scrollbarIntrusion();
1267
1268     int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
1269     if (physicalScrollY < 0) {
1270         horizontalOverhangRect = frameRect();
1271         horizontalOverhangRect.setHeight(-physicalScrollY);
1272         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - scrollbarSpace.width());
1273     } else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight()) {
1274         int height = physicalScrollY - (totalContentsSize().height() - visibleHeight());
1275         horizontalOverhangRect = frameRect();
1276         horizontalOverhangRect.setY(frameRect().maxY() - height - scrollbarSpace.height());
1277         horizontalOverhangRect.setHeight(height);
1278         horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - scrollbarSpace.width());
1279     }
1280
1281     int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
1282     if (physicalScrollX < 0) {
1283         verticalOverhangRect.setWidth(-physicalScrollX);
1284         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - scrollbarSpace.height());
1285         verticalOverhangRect.setX(frameRect().x());
1286         if (horizontalOverhangRect.y() == frameRect().y())
1287             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1288         else
1289             verticalOverhangRect.setY(frameRect().y());
1290     } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
1291         int width = physicalScrollX - (contentsWidth() - visibleWidth());
1292         verticalOverhangRect.setWidth(width);
1293         verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - scrollbarSpace.height());
1294         verticalOverhangRect.setX(frameRect().maxX() - width - scrollbarSpace.width());
1295         if (horizontalOverhangRect.y() == frameRect().y())
1296             verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1297         else
1298             verticalOverhangRect.setY(frameRect().y());
1299     }
1300 }
1301
1302 void ScrollView::updateOverhangAreas()
1303 {
1304     HostWindow* window = hostWindow();
1305     if (!window)
1306         return;
1307
1308     IntRect horizontalOverhangRect;
1309     IntRect verticalOverhangRect;
1310     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1311     if (!horizontalOverhangRect.isEmpty())
1312         window->invalidateContentsAndRootView(horizontalOverhangRect);
1313     if (!verticalOverhangRect.isEmpty())
1314         window->invalidateContentsAndRootView(verticalOverhangRect);
1315 }
1316
1317 void ScrollView::paintOverhangAreas(GraphicsContext& context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
1318 {
1319     ScrollbarTheme::theme().paintOverhangAreas(*this, context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1320 }
1321
1322 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext& context, const IntRect& dirtyRect)
1323 {
1324     IntRect horizontalOverhangRect;
1325     IntRect verticalOverhangRect;
1326     calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1327
1328     if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
1329         paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1330 }
1331
1332 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1333 {
1334     if (!scrollbarCornerPresent())
1335         return false;
1336
1337     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1338
1339     if (m_horizontalScrollbar) {
1340         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1341         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1342         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1343
1344         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1345     }
1346
1347     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1348     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1349     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1350     
1351     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1352 }
1353
1354 bool ScrollView::scrollbarCornerPresent() const
1355 {
1356     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
1357         || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
1358 }
1359
1360 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1361 {
1362     // Scrollbars won't be transformed within us
1363     IntRect newRect = localRect;
1364     newRect.moveBy(scrollbar->location());
1365     return newRect;
1366 }
1367
1368 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1369 {
1370     IntRect newRect = parentRect;
1371     // Scrollbars won't be transformed within us
1372     newRect.moveBy(-scrollbar->location());
1373     return newRect;
1374 }
1375
1376 // FIXME: test these on windows
1377 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1378 {
1379     // Scrollbars won't be transformed within us
1380     IntPoint newPoint = localPoint;
1381     newPoint.moveBy(scrollbar->location());
1382     return newPoint;
1383 }
1384
1385 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1386 {
1387     IntPoint newPoint = parentPoint;
1388     // Scrollbars won't be transformed within us
1389     newPoint.moveBy(-scrollbar->location());
1390     return newPoint;
1391 }
1392
1393 void ScrollView::setParentVisible(bool visible)
1394 {
1395     if (isParentVisible() == visible)
1396         return;
1397     
1398     Widget::setParentVisible(visible);
1399
1400     if (!isSelfVisible())
1401         return;
1402         
1403     HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1404     for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1405         (*it)->setParentVisible(visible);
1406 }
1407
1408 void ScrollView::show()
1409 {
1410     if (!isSelfVisible()) {
1411         setSelfVisible(true);
1412         if (isParentVisible()) {
1413             HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1414             for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1415                 (*it)->setParentVisible(true);
1416         }
1417     }
1418
1419     Widget::show();
1420 }
1421
1422 void ScrollView::hide()
1423 {
1424     if (isSelfVisible()) {
1425         if (isParentVisible()) {
1426             HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1427             for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1428                 (*it)->setParentVisible(false);
1429         }
1430         setSelfVisible(false);
1431     }
1432
1433     Widget::hide();
1434 }
1435
1436 bool ScrollView::isOffscreen() const
1437 {
1438     if (platformWidget())
1439         return platformIsOffscreen();
1440     
1441     if (!isVisible())
1442         return true;
1443     
1444     // FIXME: Add a HostWindow::isOffscreen method here.  Since only Mac implements this method
1445     // currently, we can add the method when the other platforms decide to implement this concept.
1446     return false;
1447 }
1448
1449
1450 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1451 {
1452     HostWindow* window = hostWindow();
1453     if (!window)
1454         return;
1455     m_drawPanScrollIcon = true;    
1456     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1457     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1458 }
1459
1460 void ScrollView::removePanScrollIcon()
1461 {
1462     HostWindow* window = hostWindow();
1463     if (!window)
1464         return;
1465     m_drawPanScrollIcon = false; 
1466     window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1467 }
1468
1469 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1470 {
1471     if (scrollOrigin() == origin)
1472         return;
1473
1474     ScrollableArea::setScrollOrigin(origin);
1475
1476     if (platformWidget()) {
1477         platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1478         return;
1479     }
1480     
1481     // Update if the scroll origin changes, since our position will be different if the content size did not change.
1482     if (updatePositionAtAll && updatePositionSynchronously)
1483         updateScrollbars(scrollPosition());
1484 }
1485
1486 void ScrollView::styleDidChange()
1487 {
1488     if (m_horizontalScrollbar)
1489         m_horizontalScrollbar->styleChanged();
1490
1491     if (m_verticalScrollbar)
1492         m_verticalScrollbar->styleChanged();
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 }