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