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