2 * Copyright (C) 2006, 2007, 2008, 2014-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ScrollView.h"
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>
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)
60 ScrollView::~ScrollView()
64 void ScrollView::addChild(PassRefPtr<Widget> prpChild)
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);
74 void ScrollView::removeChild(Widget& child)
76 ASSERT(child.parent() == this);
77 child.setParent(nullptr);
78 m_children.remove(&child);
79 if (child.platformWidget())
80 platformRemoveChild(&child);
83 bool ScrollView::setHasHorizontalScrollbar(bool hasBar, bool* contentSizeAffected)
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();
96 if (!hasBar && m_horizontalScrollbar) {
97 bool wasOverlayScrollbar = m_horizontalScrollbar->isOverlayScrollbar();
98 willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
99 removeChild(*m_horizontalScrollbar);
100 m_horizontalScrollbar = nullptr;
101 if (contentSizeAffected)
102 *contentSizeAffected = !wasOverlayScrollbar;
109 bool ScrollView::setHasVerticalScrollbar(bool hasBar, bool* contentSizeAffected)
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();
122 if (!hasBar && m_verticalScrollbar) {
123 bool wasOverlayScrollbar = m_verticalScrollbar->isOverlayScrollbar();
124 willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
125 removeChild(*m_verticalScrollbar);
126 m_verticalScrollbar = nullptr;
127 if (contentSizeAffected)
128 *contentSizeAffected = !wasOverlayScrollbar;
135 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
137 return Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
140 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
141 bool horizontalLock, bool verticalLock)
143 bool needsUpdate = false;
145 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
146 m_horizontalScrollbarMode = horizontalMode;
150 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
151 m_verticalScrollbarMode = verticalMode;
156 setHorizontalScrollbarLock();
159 setVerticalScrollbarLock();
164 if (platformWidget())
165 platformSetScrollbarModes();
167 updateScrollbars(scrollOffset());
170 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
172 if (platformWidget()) {
173 platformScrollbarModes(horizontalMode, verticalMode);
176 horizontalMode = m_horizontalScrollbarMode;
177 verticalMode = m_verticalScrollbarMode;
180 void ScrollView::setCanHaveScrollbars(bool canScroll)
182 ScrollbarMode newHorizontalMode;
183 ScrollbarMode newVerticalMode;
185 scrollbarModes(newHorizontalMode, newVerticalMode);
187 if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
188 newVerticalMode = ScrollbarAuto;
190 newVerticalMode = ScrollbarAlwaysOff;
192 if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
193 newHorizontalMode = ScrollbarAuto;
195 newHorizontalMode = ScrollbarAlwaysOff;
197 setScrollbarModes(newHorizontalMode, newVerticalMode);
200 void ScrollView::setCanBlitOnScroll(bool b)
202 if (platformWidget()) {
203 platformSetCanBlitOnScroll(b);
207 m_canBlitOnScroll = b;
210 bool ScrollView::canBlitOnScroll() const
212 if (platformWidget())
213 return platformCanBlitOnScroll();
215 return m_canBlitOnScroll;
218 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
220 m_paintsEntireContents = paintsEntireContents;
223 void ScrollView::setClipsRepaints(bool clipsRepaints)
225 m_clipsRepaints = clipsRepaints;
228 void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
230 if (m_delegatesScrolling == delegatesScrolling)
233 m_delegatesScrolling = delegatesScrolling;
234 delegatesScrollingDidChange();
237 IntPoint ScrollView::contentsScrollPosition() const
240 if (platformWidget())
241 return actualScrollPosition();
243 return scrollPosition();
246 void ScrollView::setContentsScrollPosition(const IntPoint& position)
249 if (platformWidget())
250 setActualScrollPosition(position);
252 setScrollPosition(position);
256 IntRect ScrollView::unobscuredContentRect(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
258 return unobscuredContentRectInternal(scrollbarInclusion);
262 IntRect ScrollView::unobscuredContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
264 FloatSize visibleContentSize = unscaledUnobscuredVisibleContentSize(scrollbarInclusion);
265 visibleContentSize.scale(1 / visibleContentScaleFactor());
266 return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize));
269 IntSize ScrollView::unscaledVisibleContentSizeIncludingObscuredArea(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
271 if (platformWidget())
272 return platformVisibleContentSizeIncludingObscuredArea(scrollbarInclusion == IncludeScrollbars);
274 #if USE(TILED_BACKING_STORE)
275 if (!m_fixedVisibleContentRect.isEmpty())
276 return m_fixedVisibleContentRect.size();
279 int verticalScrollbarWidth = 0;
280 int horizontalScrollbarHeight = 0;
282 if (scrollbarInclusion == ExcludeScrollbars) {
283 if (Scrollbar* verticalBar = verticalScrollbar())
284 verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
285 if (Scrollbar* horizontalBar = horizontalScrollbar())
286 horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
289 return IntSize(width() - verticalScrollbarWidth, height() - horizontalScrollbarHeight).expandedTo(IntSize());
292 IntSize ScrollView::unscaledUnobscuredVisibleContentSize(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
294 IntSize visibleContentSize = unscaledVisibleContentSizeIncludingObscuredArea(scrollbarInclusion);
296 if (platformWidget())
297 return platformVisibleContentSize(scrollbarInclusion == IncludeScrollbars);
299 #if USE(TILED_BACKING_STORE)
300 if (!m_fixedVisibleContentRect.isEmpty())
301 return visibleContentSize;
304 visibleContentSize.setHeight(visibleContentSize.height() - topContentInset());
305 return visibleContentSize;
308 IntRect ScrollView::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior visibleContentRectBehavior) const
311 if (visibleContentRectBehavior == LegacyIOSDocumentViewRect) {
312 if (platformWidget())
313 return platformVisibleContentRect(scrollbarInclusion == IncludeScrollbars);
316 if (platformWidget())
317 return unobscuredContentRect(scrollbarInclusion);
319 UNUSED_PARAM(visibleContentRectBehavior);
322 if (platformWidget())
323 return platformVisibleContentRect(scrollbarInclusion == IncludeScrollbars);
325 #if USE(TILED_BACKING_STORE)
326 if (!m_fixedVisibleContentRect.isEmpty())
327 return m_fixedVisibleContentRect;
330 return unobscuredContentRect(scrollbarInclusion);
333 IntSize ScrollView::layoutSize() const
335 return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? unscaledUnobscuredVisibleContentSize(ExcludeScrollbars) : m_fixedLayoutSize;
338 IntSize ScrollView::fixedLayoutSize() const
340 return m_fixedLayoutSize;
343 void ScrollView::setFixedLayoutSize(const IntSize& newSize)
345 if (fixedLayoutSize() == newSize)
347 m_fixedLayoutSize = newSize;
348 if (m_useFixedLayout)
349 availableContentSizeChanged(AvailableSizeChangeReason::AreaSizeChanged);
352 bool ScrollView::useFixedLayout() const
354 return m_useFixedLayout;
357 void ScrollView::setUseFixedLayout(bool enable)
359 if (useFixedLayout() == enable)
361 m_useFixedLayout = enable;
362 if (!m_fixedLayoutSize.isEmpty())
363 availableContentSizeChanged(AvailableSizeChangeReason::AreaSizeChanged);
366 void ScrollView::availableContentSizeChanged(AvailableSizeChangeReason reason)
368 ScrollableArea::availableContentSizeChanged(reason);
369 if (reason != AvailableSizeChangeReason::ScrollbarsChanged)
370 updateScrollbars(scrollOffset());
373 IntSize ScrollView::contentsSize() const
375 return m_contentsSize;
378 void ScrollView::setContentsSize(const IntSize& newSize)
380 if (contentsSize() == newSize)
382 m_contentsSize = newSize;
383 if (platformWidget())
384 platformSetContentsSize();
386 updateScrollbars(scrollOffset());
387 updateOverhangAreas();
390 IntPoint ScrollView::maximumScrollPosition() const
392 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
393 maximumOffset.clampNegativeToZero();
394 return maximumOffset;
397 IntPoint ScrollView::minimumScrollPosition() const
399 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
402 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
404 if (!constrainsScrollingToContentEdge())
407 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
408 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
409 return newScrollPosition;
412 IntSize ScrollView::documentScrollOffsetRelativeToViewOrigin() const
414 return scrollOffset() - IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
417 IntPoint ScrollView::documentScrollPositionRelativeToViewOrigin() const
419 IntPoint scrollPosition = this->scrollPosition();
420 return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight() - topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
423 IntSize ScrollView::documentScrollOffsetRelativeToScrollableAreaOrigin() const
425 return scrollOffset() - IntSize(0, headerHeight());
428 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
430 // If no scrollbars are present, it does not indicate content is not be scrollable.
431 if (!m_horizontalScrollbar && !m_verticalScrollbar && !prohibitsScrolling()) {
432 IntSize scrollSize = m_contentsSize - visibleContentRect(LegacyIOSDocumentVisibleRect).size();
433 scrollSize.clampNegativeToZero();
434 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
437 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
438 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
441 void ScrollView::notifyPageThatContentAreaWillPaint() const
445 void ScrollView::setScrollOffset(const IntPoint& offset)
447 int horizontalOffset = offset.x();
448 int verticalOffset = offset.y();
449 if (constrainsScrollingToContentEdge()) {
450 horizontalOffset = std::max(std::min(horizontalOffset, contentsWidth() - visibleWidth()), 0);
451 verticalOffset = std::max(std::min(verticalOffset, totalContentsSize().height() - visibleHeight()), 0);
454 IntSize newOffset = m_scrollOffset;
455 newOffset.setWidth(horizontalOffset - scrollOrigin().x());
456 newOffset.setHeight(verticalOffset - scrollOrigin().y());
461 void ScrollView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
463 // We should not attempt to actually modify (paint) platform widgets if the layout phase
464 // is not complete. Instead, defer the scroll event until the layout finishes.
465 if (shouldDeferScrollUpdateAfterContentSizeChange()) {
466 // We only care about the most recent scroll position change request
467 m_deferredScrollPositions = std::make_unique<std::pair<IntPoint, IntPoint>>(std::make_pair(oldPosition, newPosition));
471 scrollPositionChangedViaPlatformWidgetImpl(oldPosition, newPosition);
474 void ScrollView::handleDeferredScrollUpdateAfterContentSizeChange()
476 ASSERT(!shouldDeferScrollUpdateAfterContentSizeChange());
478 if (!m_deferredScrollDelta && !m_deferredScrollPositions)
481 ASSERT(static_cast<bool>(m_deferredScrollDelta) != static_cast<bool>(m_deferredScrollPositions));
483 if (m_deferredScrollDelta)
484 completeUpdatesAfterScrollTo(*m_deferredScrollDelta);
485 else if (m_deferredScrollPositions)
486 scrollPositionChangedViaPlatformWidgetImpl(m_deferredScrollPositions->first, m_deferredScrollPositions->second);
488 m_deferredScrollDelta = nullptr;
489 m_deferredScrollPositions = nullptr;
492 void ScrollView::scrollTo(const IntSize& newOffset)
494 IntSize scrollDelta = newOffset - m_scrollOffset;
495 if (scrollDelta.isZero())
497 m_scrollOffset = newOffset;
499 if (scrollbarsSuppressed())
502 #if USE(TILED_BACKING_STORE)
503 if (delegatesScrolling()) {
504 requestScrollPositionUpdate(IntPoint(newOffset));
508 // We should not attempt to actually modify layer contents if the layout phase
509 // is not complete. Instead, defer the scroll event until the layout finishes.
510 if (shouldDeferScrollUpdateAfterContentSizeChange()) {
511 ASSERT(!m_deferredScrollDelta);
512 m_deferredScrollDelta = std::make_unique<IntSize>(scrollDelta);
516 completeUpdatesAfterScrollTo(scrollDelta);
519 void ScrollView::completeUpdatesAfterScrollTo(const IntSize& scrollDelta)
521 updateLayerPositionsAfterScrolling();
522 scrollContents(scrollDelta);
523 updateCompositingLayersAfterScrolling();
526 int ScrollView::scrollPosition(Scrollbar* scrollbar) const
528 if (scrollbar->orientation() == HorizontalScrollbar)
529 return scrollPosition().x() + scrollOrigin().x();
530 if (scrollbar->orientation() == VerticalScrollbar)
531 return scrollPosition().y() + scrollOrigin().y();
535 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
537 if (prohibitsScrolling())
540 if (platformWidget()) {
541 platformSetScrollPosition(scrollPoint);
545 IntPoint newScrollPosition = !delegatesScrolling() ? adjustScrollPositionWithinRange(scrollPoint) : scrollPoint;
547 if ((!delegatesScrolling() || !inProgrammaticScroll()) && newScrollPosition == scrollPosition())
550 if (requestScrollPositionUpdate(newScrollPosition))
553 updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
556 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
558 if (platformWidget())
559 return platformScroll(direction, granularity);
561 return ScrollableArea::scroll(direction, granularity);
564 bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
566 return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
569 IntSize ScrollView::overhangAmount() const
573 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
574 if (physicalScrollY < 0)
575 stretch.setHeight(physicalScrollY);
576 else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight())
577 stretch.setHeight(physicalScrollY - (totalContentsSize().height() - visibleHeight()));
579 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
580 if (physicalScrollX < 0)
581 stretch.setWidth(physicalScrollX);
582 else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth())
583 stretch.setWidth(physicalScrollX - (contentsWidth() - visibleWidth()));
588 void ScrollView::windowResizerRectChanged()
590 if (platformWidget())
593 updateScrollbars(scrollOffset());
596 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
598 if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget() || delegatesScrolling())
601 bool hasOverlayScrollbars = (!m_horizontalScrollbar || m_horizontalScrollbar->isOverlayScrollbar()) && (!m_verticalScrollbar || m_verticalScrollbar->isOverlayScrollbar());
603 // If we came in here with the view already needing a layout, then go ahead and do that
604 // first. (This will be the common case, e.g., when the page changes due to window resizing for example).
605 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
606 if (!m_scrollbarsSuppressed && !hasOverlayScrollbars) {
607 m_inUpdateScrollbars = true;
608 updateContentsSize();
609 m_inUpdateScrollbars = false;
612 IntRect oldScrollCornerRect = scrollCornerRect();
614 bool hasHorizontalScrollbar = m_horizontalScrollbar;
615 bool hasVerticalScrollbar = m_verticalScrollbar;
617 bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
618 bool newHasVerticalScrollbar = hasVerticalScrollbar;
620 ScrollbarMode hScroll = m_horizontalScrollbarMode;
621 ScrollbarMode vScroll = m_verticalScrollbarMode;
623 if (hScroll != ScrollbarAuto)
624 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
625 if (vScroll != ScrollbarAuto)
626 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
628 bool scrollbarAddedOrRemoved = false;
630 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
631 if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
632 if (setHasHorizontalScrollbar(newHasHorizontalScrollbar))
633 scrollbarAddedOrRemoved = true;
636 if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
637 if (setHasVerticalScrollbar(newHasVerticalScrollbar))
638 scrollbarAddedOrRemoved = true;
641 bool sendContentResizedNotification = false;
643 IntSize docSize = totalContentsSize();
644 IntSize fullVisibleSize = unobscuredContentRectIncludingScrollbars().size();
646 if (hScroll == ScrollbarAuto)
647 newHasHorizontalScrollbar = docSize.width() > visibleWidth();
648 if (vScroll == ScrollbarAuto)
649 newHasVerticalScrollbar = docSize.height() > visibleHeight();
651 bool needAnotherPass = false;
652 if (!hasOverlayScrollbars) {
653 // If we ever turn one scrollbar off, always turn the other one off too. Never ever
654 // try to both gain/lose a scrollbar in the same pass.
655 if (!m_updateScrollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()) {
656 if (hScroll == ScrollbarAuto)
657 newHasHorizontalScrollbar = false;
658 if (vScroll == ScrollbarAuto)
659 newHasVerticalScrollbar = false;
661 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) {
662 newHasVerticalScrollbar = false;
663 needAnotherPass = true;
665 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) {
666 newHasHorizontalScrollbar = false;
667 needAnotherPass = true;
671 if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
672 if (scrollOrigin().y() && !newHasHorizontalScrollbar)
673 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x(), scrollOrigin().y() - m_horizontalScrollbar->height()));
674 if (m_horizontalScrollbar)
675 m_horizontalScrollbar->invalidate();
677 bool changeAffectsContentSize = false;
678 if (setHasHorizontalScrollbar(newHasHorizontalScrollbar, &changeAffectsContentSize)) {
679 scrollbarAddedOrRemoved = true;
680 sendContentResizedNotification |= changeAffectsContentSize;
684 if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
685 if (scrollOrigin().x() && !newHasVerticalScrollbar)
686 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x() - m_verticalScrollbar->width(), scrollOrigin().y()));
687 if (m_verticalScrollbar)
688 m_verticalScrollbar->invalidate();
690 bool changeAffectsContentSize = false;
691 if (setHasVerticalScrollbar(newHasVerticalScrollbar, &changeAffectsContentSize)) {
692 scrollbarAddedOrRemoved = true;
693 sendContentResizedNotification |= changeAffectsContentSize;
697 const unsigned cMaxUpdateScrollbarsPass = 2;
698 if ((sendContentResizedNotification || needAnotherPass) && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
699 m_updateScrollbarsPass++;
700 availableContentSizeChanged(AvailableSizeChangeReason::ScrollbarsChanged);
701 updateContentsSize();
702 IntSize newDocSize = totalContentsSize();
703 if (newDocSize == docSize) {
704 // The layout with the new scroll state had no impact on
705 // the document's overall size, so updateScrollbars didn't get called.
707 updateScrollbars(desiredOffset);
709 m_updateScrollbarsPass--;
713 if (scrollbarAddedOrRemoved)
714 addedOrRemovedScrollbar();
716 // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
717 // doing it multiple times).
718 if (m_updateScrollbarsPass)
721 m_inUpdateScrollbars = true;
723 if (m_horizontalScrollbar) {
724 int clientWidth = visibleWidth();
725 int pageStep = Scrollbar::pageStep(clientWidth);
726 IntRect oldRect(m_horizontalScrollbar->frameRect());
728 height() - m_horizontalScrollbar->height(),
729 width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
730 m_horizontalScrollbar->height());
731 m_horizontalScrollbar->setFrameRect(hBarRect);
732 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
733 m_horizontalScrollbar->invalidate();
735 if (m_scrollbarsSuppressed)
736 m_horizontalScrollbar->setSuppressInvalidation(true);
737 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
738 m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
739 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
740 if (m_scrollbarsSuppressed)
741 m_horizontalScrollbar->setSuppressInvalidation(false);
744 if (m_verticalScrollbar) {
745 int clientHeight = visibleHeight();
746 int pageStep = Scrollbar::pageStep(clientHeight);
747 IntRect oldRect(m_verticalScrollbar->frameRect());
748 IntRect vBarRect(width() - m_verticalScrollbar->width(),
750 m_verticalScrollbar->width(),
751 height() - topContentInset() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
752 m_verticalScrollbar->setFrameRect(vBarRect);
753 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
754 m_verticalScrollbar->invalidate();
756 if (m_scrollbarsSuppressed)
757 m_verticalScrollbar->setSuppressInvalidation(true);
758 m_verticalScrollbar->setEnabled(totalContentsSize().height() > clientHeight);
759 m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
760 m_verticalScrollbar->setProportion(clientHeight, totalContentsSize().height());
761 if (m_scrollbarsSuppressed)
762 m_verticalScrollbar->setSuppressInvalidation(false);
765 if (hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar) {
766 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
768 positionScrollbarLayers();
769 updateScrollCorner();
770 if (!m_horizontalScrollbar && !m_verticalScrollbar)
771 invalidateScrollCornerRect(oldScrollCornerRect);
774 IntPoint adjustedScrollPosition = IntPoint(desiredOffset);
775 if (!isRubberBandInProgress())
776 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
778 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) {
779 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition + toIntSize(scrollOrigin()));
780 resetScrollOriginChanged();
783 // Make sure the scrollbar offsets are up to date.
784 if (m_horizontalScrollbar)
785 m_horizontalScrollbar->offsetDidChange();
786 if (m_verticalScrollbar)
787 m_verticalScrollbar->offsetDidChange();
789 m_inUpdateScrollbars = false;
792 const int panIconSizeLength = 16;
794 IntRect ScrollView::rectToCopyOnScroll() const
796 IntRect scrollViewRect = convertToRootView(IntRect(0, 0, visibleWidth(), visibleHeight()));
797 if (hasOverlayScrollbars()) {
798 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
799 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
801 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
802 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
804 return scrollViewRect;
807 void ScrollView::scrollContents(const IntSize& scrollDelta)
809 HostWindow* window = hostWindow();
813 // Since scrolling is double buffered, we will be blitting the scroll view's intersection
814 // with the clip rect every time to keep it smooth.
815 IntRect clipRect = windowClipRect();
816 IntRect scrollViewRect = rectToCopyOnScroll();
817 IntRect updateRect = clipRect;
818 updateRect.intersect(scrollViewRect);
820 // Invalidate the root view (not the backing store).
821 window->invalidateRootView(updateRect);
823 if (m_drawPanScrollIcon) {
824 // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
825 // https://bugs.webkit.org/show_bug.cgi?id=47837
826 int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
827 IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
828 IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
829 panScrollIconDirtyRect.intersect(clipRect);
830 window->invalidateContentsAndRootView(panScrollIconDirtyRect);
833 if (canBlitOnScroll()) { // The main frame can just blit the WebView window
834 // FIXME: Find a way to scroll subframes with this faster path
835 if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
836 scrollContentsSlowPath(updateRect);
838 // We need to go ahead and repaint the entire backing store. Do it now before moving the
840 scrollContentsSlowPath(updateRect);
843 // Invalidate the overhang areas if they are visible.
844 updateOverhangAreas();
846 // This call will move children with native widgets (plugins) and invalidate them as well.
849 // Now blit the backingstore into the window which should be very fast.
850 window->invalidateRootView(IntRect());
853 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
855 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
859 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
861 hostWindow()->invalidateContentsForSlowScroll(updateRect);
864 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const
866 if (delegatesScrolling())
867 return convertFromRootView(rootViewPoint);
869 IntPoint viewPoint = convertFromRootView(rootViewPoint);
870 return viewPoint + documentScrollOffsetRelativeToViewOrigin();
873 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const
875 if (delegatesScrolling())
876 return convertToRootView(contentsPoint);
878 IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)) - scrollOffset();
879 return convertToRootView(viewPoint);
882 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const
884 if (delegatesScrolling())
885 return convertFromRootView(rootViewRect);
887 IntRect viewRect = convertFromRootView(rootViewRect);
888 viewRect.move(documentScrollOffsetRelativeToViewOrigin());
892 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const
894 if (delegatesScrolling())
895 return convertToRootView(contentsRect);
897 IntRect viewRect = contentsRect;
898 viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
899 return convertToRootView(viewRect);
902 IntPoint ScrollView::rootViewToTotalContents(const IntPoint& rootViewPoint) const
904 if (delegatesScrolling())
905 return convertFromRootView(rootViewPoint);
907 IntPoint viewPoint = convertFromRootView(rootViewPoint);
908 return viewPoint + scrollOffset() - IntSize(0, topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
911 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
913 if (delegatesScrolling())
914 return convertFromContainingWindow(windowPoint);
916 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
917 return viewPoint + documentScrollOffsetRelativeToViewOrigin();
920 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
922 if (delegatesScrolling())
923 return convertToContainingWindow(contentsPoint);
925 IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)) - scrollOffset();
926 return convertToContainingWindow(viewPoint);
929 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
931 if (delegatesScrolling())
932 return convertFromContainingWindow(windowRect);
934 IntRect viewRect = convertFromContainingWindow(windowRect);
935 viewRect.move(documentScrollOffsetRelativeToViewOrigin());
939 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
941 if (delegatesScrolling())
942 return convertToContainingWindow(contentsRect);
944 IntRect viewRect = contentsRect;
945 viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
946 return convertToContainingWindow(viewRect);
949 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
951 HostWindow* window = hostWindow();
952 if (platformWidget())
953 return platformContentsToScreen(rect);
956 return window->rootViewToScreen(contentsToRootView(rect));
959 IntPoint ScrollView::screenToContents(const IntPoint& point) const
961 HostWindow* window = hostWindow();
962 if (platformWidget())
963 return platformScreenToContents(point);
966 return rootViewToContents(window->screenToRootView(point));
969 bool ScrollView::containsScrollbarsAvoidingResizer() const
971 return !m_scrollbarsAvoidingResizer;
974 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
976 int oldCount = m_scrollbarsAvoidingResizer;
977 m_scrollbarsAvoidingResizer += overlapDelta;
979 parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
980 else if (!scrollbarsSuppressed()) {
981 // If we went from n to 0 or from 0 to n and we're the outermost view,
982 // we need to invalidate the windowResizerRect(), since it will now need to paint
984 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
985 (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
986 invalidateRect(windowResizerRect());
990 void ScrollView::setParent(ScrollView* parentView)
992 if (parentView == parent())
995 if (m_scrollbarsAvoidingResizer && parent())
996 parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
998 Widget::setParent(parentView);
1000 if (m_scrollbarsAvoidingResizer && parent())
1001 parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
1004 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
1006 if (suppressed == m_scrollbarsSuppressed)
1009 m_scrollbarsSuppressed = suppressed;
1011 if (platformWidget())
1012 platformSetScrollbarsSuppressed(repaintOnUnsuppress);
1013 else if (repaintOnUnsuppress && !suppressed) {
1014 if (m_horizontalScrollbar)
1015 m_horizontalScrollbar->invalidate();
1016 if (m_verticalScrollbar)
1017 m_verticalScrollbar->invalidate();
1019 // Invalidate the scroll corner too on unsuppress.
1020 invalidateRect(scrollCornerRect());
1024 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
1026 if (platformWidget())
1029 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1030 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint))
1031 return m_horizontalScrollbar.get();
1032 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint))
1033 return m_verticalScrollbar.get();
1037 void ScrollView::setScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle)
1039 ScrollableArea::setScrollbarOverlayStyle(overlayStyle);
1040 platformSetScrollbarOverlayStyle(overlayStyle);
1043 void ScrollView::setFrameRect(const IntRect& newRect)
1045 IntRect oldRect = frameRect();
1047 if (newRect == oldRect)
1050 Widget::setFrameRect(newRect);
1051 frameRectsChanged();
1053 if (!m_useFixedLayout && oldRect.size() != newRect.size())
1054 availableContentSizeChanged(AvailableSizeChangeReason::AreaSizeChanged);
1057 void ScrollView::frameRectsChanged()
1059 if (platformWidget())
1062 HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1063 for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1064 (*current)->frameRectsChanged();
1067 void ScrollView::clipRectChanged()
1069 HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1070 for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1071 (*current)->clipRectChanged();
1074 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
1076 if (!graphicsLayer || !scrollbar)
1079 IntRect scrollbarRect = scrollbar->frameRect();
1080 graphicsLayer->setPosition(scrollbarRect.location());
1082 if (scrollbarRect.size() == graphicsLayer->size())
1085 graphicsLayer->setSize(scrollbarRect.size());
1087 if (graphicsLayer->usesContentsLayer()) {
1088 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
1092 graphicsLayer->setDrawsContent(true);
1093 graphicsLayer->setNeedsDisplay();
1096 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
1100 graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
1101 graphicsLayer->setPosition(cornerRect.location());
1102 if (cornerRect.size() != graphicsLayer->size())
1103 graphicsLayer->setNeedsDisplay();
1104 graphicsLayer->setSize(cornerRect.size());
1107 void ScrollView::positionScrollbarLayers()
1109 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
1110 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
1111 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
1114 void ScrollView::repaintContentRectangle(const IntRect& rect)
1116 IntRect paintRect = rect;
1117 if (clipsRepaints() && !paintsEntireContents())
1118 paintRect.intersect(visibleContentRect(LegacyIOSDocumentVisibleRect));
1119 if (paintRect.isEmpty())
1122 if (platformWidget()) {
1123 notifyPageThatContentAreaWillPaint();
1124 platformRepaintContentRectangle(paintRect);
1128 if (HostWindow* window = hostWindow())
1129 window->invalidateContentsAndRootView(contentsToWindow(paintRect));
1132 IntRect ScrollView::scrollCornerRect() const
1136 if (hasOverlayScrollbars())
1139 int heightTrackedByScrollbar = height() - topContentInset();
1141 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
1142 cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
1143 height() - m_horizontalScrollbar->height(),
1144 width() - m_horizontalScrollbar->width(),
1145 m_horizontalScrollbar->height()));
1148 if (m_verticalScrollbar && heightTrackedByScrollbar - m_verticalScrollbar->height() > 0) {
1149 cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
1150 m_verticalScrollbar->height() + topContentInset(),
1151 m_verticalScrollbar->width(),
1152 heightTrackedByScrollbar - m_verticalScrollbar->height()));
1158 bool ScrollView::isScrollCornerVisible() const
1160 return !scrollCornerRect().isEmpty();
1163 void ScrollView::scrollbarStyleChanged(ScrollbarStyle newStyle, bool forceUpdate)
1165 ScrollableArea::scrollbarStyleChanged(newStyle, forceUpdate);
1169 updateScrollbars(scrollOffset());
1170 positionScrollbarLayers();
1173 void ScrollView::updateScrollCorner()
1177 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
1179 ScrollbarTheme::theme()->paintScrollCorner(this, context, cornerRect);
1182 void ScrollView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
1184 bar->paint(context, rect);
1187 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
1189 invalidateRect(rect);
1192 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
1194 if (m_horizontalScrollbar && !layerForHorizontalScrollbar())
1195 paintScrollbar(context, m_horizontalScrollbar.get(), rect);
1196 if (m_verticalScrollbar && !layerForVerticalScrollbar())
1197 paintScrollbar(context, m_verticalScrollbar.get(), rect);
1199 if (layerForScrollCorner())
1202 paintScrollCorner(context, scrollCornerRect());
1205 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
1207 static Image* panScrollIcon = Image::loadPlatformResource("panIcon").leakRef();
1208 IntPoint iconGCPoint = m_panScrollIconPoint;
1210 iconGCPoint = parent()->windowToContents(iconGCPoint);
1211 context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, iconGCPoint);
1214 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
1216 if (platformWidget()) {
1217 Widget::paint(context, rect);
1221 if (context->paintingDisabled() && !context->updatingControlTints())
1224 notifyPageThatContentAreaWillPaint();
1226 IntRect documentDirtyRect = rect;
1227 if (!paintsEntireContents()) {
1228 IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect(LegacyIOSDocumentVisibleRect).size());
1229 documentDirtyRect.intersect(visibleAreaWithoutScrollbars);
1232 if (!documentDirtyRect.isEmpty()) {
1233 GraphicsContextStateSaver stateSaver(*context);
1235 context->translate(x(), y());
1236 documentDirtyRect.moveBy(-location());
1238 if (!paintsEntireContents()) {
1239 context->translate(-scrollX(), -scrollY());
1240 documentDirtyRect.moveBy(scrollPosition());
1242 context->clip(visibleContentRect(LegacyIOSDocumentVisibleRect));
1245 paintContents(context, documentDirtyRect);
1248 #if ENABLE(RUBBER_BANDING)
1249 if (!layerForOverhangAreas())
1250 calculateAndPaintOverhangAreas(context, rect);
1252 calculateAndPaintOverhangAreas(context, rect);
1255 // Now paint the scrollbars.
1256 if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
1257 GraphicsContextStateSaver stateSaver(*context);
1258 IntRect scrollViewDirtyRect = rect;
1259 IntRect visibleAreaWithScrollbars(location(), unobscuredContentRectIncludingScrollbars().size());
1260 scrollViewDirtyRect.intersect(visibleAreaWithScrollbars);
1261 context->translate(x(), y());
1262 scrollViewDirtyRect.moveBy(-location());
1263 context->clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size()));
1265 paintScrollbars(context, scrollViewDirtyRect);
1268 // Paint the panScroll Icon
1269 if (m_drawPanScrollIcon)
1270 paintPanScrollIcon(context);
1273 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1275 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1276 ? verticalScrollbar()->width() : 0;
1277 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1278 ? horizontalScrollbar()->height() : 0;
1280 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
1281 if (physicalScrollY < 0) {
1282 horizontalOverhangRect = frameRect();
1283 horizontalOverhangRect.setHeight(-physicalScrollY);
1284 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1285 } else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight()) {
1286 int height = physicalScrollY - (totalContentsSize().height() - visibleHeight());
1287 horizontalOverhangRect = frameRect();
1288 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
1289 horizontalOverhangRect.setHeight(height);
1290 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1293 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
1294 if (physicalScrollX < 0) {
1295 verticalOverhangRect.setWidth(-physicalScrollX);
1296 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1297 verticalOverhangRect.setX(frameRect().x());
1298 if (horizontalOverhangRect.y() == frameRect().y())
1299 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1301 verticalOverhangRect.setY(frameRect().y());
1302 } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
1303 int width = physicalScrollX - (contentsWidth() - visibleWidth());
1304 verticalOverhangRect.setWidth(width);
1305 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1306 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
1307 if (horizontalOverhangRect.y() == frameRect().y())
1308 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1310 verticalOverhangRect.setY(frameRect().y());
1314 void ScrollView::updateOverhangAreas()
1316 HostWindow* window = hostWindow();
1320 IntRect horizontalOverhangRect;
1321 IntRect verticalOverhangRect;
1322 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1323 if (!horizontalOverhangRect.isEmpty())
1324 window->invalidateContentsAndRootView(horizontalOverhangRect);
1325 if (!verticalOverhangRect.isEmpty())
1326 window->invalidateContentsAndRootView(verticalOverhangRect);
1329 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
1331 ScrollbarTheme::theme()->paintOverhangAreas(this, context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1334 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const IntRect& dirtyRect)
1336 IntRect horizontalOverhangRect;
1337 IntRect verticalOverhangRect;
1338 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1340 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
1341 paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1344 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1346 if (!scrollbarCornerPresent())
1349 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1351 if (m_horizontalScrollbar) {
1352 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1353 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1354 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1356 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1359 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1360 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1361 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1363 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1366 bool ScrollView::scrollbarCornerPresent() const
1368 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
1369 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
1372 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1374 // Scrollbars won't be transformed within us
1375 IntRect newRect = localRect;
1376 newRect.moveBy(scrollbar->location());
1380 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1382 IntRect newRect = parentRect;
1383 // Scrollbars won't be transformed within us
1384 newRect.moveBy(-scrollbar->location());
1388 // FIXME: test these on windows
1389 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1391 // Scrollbars won't be transformed within us
1392 IntPoint newPoint = localPoint;
1393 newPoint.moveBy(scrollbar->location());
1397 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1399 IntPoint newPoint = parentPoint;
1400 // Scrollbars won't be transformed within us
1401 newPoint.moveBy(-scrollbar->location());
1405 void ScrollView::setParentVisible(bool visible)
1407 if (isParentVisible() == visible)
1410 Widget::setParentVisible(visible);
1412 if (!isSelfVisible())
1415 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1416 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1417 (*it)->setParentVisible(visible);
1420 void ScrollView::show()
1422 if (!isSelfVisible()) {
1423 setSelfVisible(true);
1424 if (isParentVisible()) {
1425 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1426 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1427 (*it)->setParentVisible(true);
1434 void ScrollView::hide()
1436 if (isSelfVisible()) {
1437 if (isParentVisible()) {
1438 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1439 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1440 (*it)->setParentVisible(false);
1442 setSelfVisible(false);
1448 bool ScrollView::isOffscreen() const
1450 if (platformWidget())
1451 return platformIsOffscreen();
1456 // FIXME: Add a HostWindow::isOffscreen method here. Since only Mac implements this method
1457 // currently, we can add the method when the other platforms decide to implement this concept.
1462 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1464 HostWindow* window = hostWindow();
1467 m_drawPanScrollIcon = true;
1468 m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1469 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1472 void ScrollView::removePanScrollIcon()
1474 HostWindow* window = hostWindow();
1477 m_drawPanScrollIcon = false;
1478 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1481 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1483 if (scrollOrigin() == origin)
1486 ScrollableArea::setScrollOrigin(origin);
1488 if (platformWidget()) {
1489 platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1493 // Update if the scroll origin changes, since our position will be different if the content size did not change.
1494 if (updatePositionAtAll && updatePositionSynchronously)
1495 updateScrollbars(scrollOffset());
1498 void ScrollView::styleDidChange()
1500 if (m_horizontalScrollbar)
1501 m_horizontalScrollbar->styleChanged();
1503 if (m_verticalScrollbar)
1504 m_verticalScrollbar->styleChanged();
1507 #if !PLATFORM(COCOA)
1509 void ScrollView::platformAddChild(Widget*)
1513 void ScrollView::platformRemoveChild(Widget*)
1519 #if !PLATFORM(COCOA)
1521 void ScrollView::platformSetScrollbarsSuppressed(bool)
1525 void ScrollView::platformSetScrollOrigin(const IntPoint&, bool, bool)
1529 void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle)
1535 #if !PLATFORM(COCOA)
1537 void ScrollView::platformSetScrollbarModes()
1541 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1543 horizontal = ScrollbarAuto;
1544 vertical = ScrollbarAuto;
1547 void ScrollView::platformSetCanBlitOnScroll(bool)
1551 bool ScrollView::platformCanBlitOnScroll() const
1556 IntRect ScrollView::platformVisibleContentRect(bool) const
1561 float ScrollView::platformTopContentInset() const
1566 void ScrollView::platformSetTopContentInset(float)
1570 IntSize ScrollView::platformVisibleContentSize(bool) const
1575 IntRect ScrollView::platformVisibleContentRectIncludingObscuredArea(bool) const
1580 IntSize ScrollView::platformVisibleContentSizeIncludingObscuredArea(bool) const
1585 void ScrollView::platformSetContentsSize()
1589 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1594 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1599 void ScrollView::platformSetScrollPosition(const IntPoint&)
1603 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1608 void ScrollView::platformRepaintContentRectangle(const IntRect&)
1612 bool ScrollView::platformIsOffscreen() const