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