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