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