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