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