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