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 fixedLayoutSizeChanged();
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 fixedLayoutSizeChanged();
366 void ScrollView::fixedLayoutSizeChanged()
368 updateScrollbars(scrollOffset());
372 IntSize ScrollView::contentsSize() const
374 return m_contentsSize;
377 void ScrollView::setContentsSize(const IntSize& newSize)
379 if (contentsSize() == newSize)
381 m_contentsSize = newSize;
382 if (platformWidget())
383 platformSetContentsSize();
385 updateScrollbars(scrollOffset());
386 updateOverhangAreas();
389 IntPoint ScrollView::maximumScrollPosition() const
391 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
392 maximumOffset.clampNegativeToZero();
393 return maximumOffset;
396 IntPoint ScrollView::minimumScrollPosition() const
398 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
401 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
403 if (!constrainsScrollingToContentEdge())
406 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
407 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
408 return newScrollPosition;
411 IntSize ScrollView::documentScrollOffsetRelativeToViewOrigin() const
413 return scrollOffset() - IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
416 IntPoint ScrollView::documentScrollPositionRelativeToViewOrigin() const
418 IntPoint scrollPosition = this->scrollPosition();
419 return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight() - topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
422 IntSize ScrollView::documentScrollOffsetRelativeToScrollableAreaOrigin() const
424 return scrollOffset() - IntSize(0, headerHeight());
427 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
429 // If no scrollbars are present, it does not indicate content is not be scrollable.
430 if (!m_horizontalScrollbar && !m_verticalScrollbar && !prohibitsScrolling()) {
431 IntSize scrollSize = m_contentsSize - visibleContentRect(LegacyIOSDocumentVisibleRect).size();
432 scrollSize.clampNegativeToZero();
433 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
436 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
437 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
440 void ScrollView::notifyPageThatContentAreaWillPaint() const
444 void ScrollView::setScrollOffset(const IntPoint& offset)
446 int horizontalOffset = offset.x();
447 int verticalOffset = offset.y();
448 if (constrainsScrollingToContentEdge()) {
449 horizontalOffset = std::max(std::min(horizontalOffset, contentsWidth() - visibleWidth()), 0);
450 verticalOffset = std::max(std::min(verticalOffset, totalContentsSize().height() - visibleHeight()), 0);
453 IntSize newOffset = m_scrollOffset;
454 newOffset.setWidth(horizontalOffset - scrollOrigin().x());
455 newOffset.setHeight(verticalOffset - scrollOrigin().y());
460 void ScrollView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
462 // We should not attempt to actually modify (paint) platform widgets if the layout phase
463 // is not complete. Instead, defer the scroll event until the layout finishes.
464 if (shouldDeferScrollUpdateAfterContentSizeChange()) {
465 // We only care about the most recent scroll position change request
466 m_deferredScrollPositions = std::make_unique<std::pair<IntPoint, IntPoint>>(std::make_pair(oldPosition, newPosition));
470 scrollPositionChangedViaPlatformWidgetImpl(oldPosition, newPosition);
473 void ScrollView::handleDeferredScrollUpdateAfterContentSizeChange()
475 ASSERT(!shouldDeferScrollUpdateAfterContentSizeChange());
477 if (!m_deferredScrollDelta && !m_deferredScrollPositions)
480 ASSERT(static_cast<bool>(m_deferredScrollDelta) != static_cast<bool>(m_deferredScrollPositions));
482 if (m_deferredScrollDelta)
483 completeUpdatesAfterScrollTo(*m_deferredScrollDelta);
484 else if (m_deferredScrollPositions)
485 scrollPositionChangedViaPlatformWidgetImpl(m_deferredScrollPositions->first, m_deferredScrollPositions->second);
487 m_deferredScrollDelta = nullptr;
488 m_deferredScrollPositions = nullptr;
491 void ScrollView::scrollTo(const IntSize& newOffset)
493 IntSize scrollDelta = newOffset - m_scrollOffset;
494 if (scrollDelta.isZero())
496 m_scrollOffset = newOffset;
498 if (scrollbarsSuppressed())
501 #if USE(TILED_BACKING_STORE)
502 if (delegatesScrolling()) {
503 requestScrollPositionUpdate(IntPoint(newOffset));
507 // We should not attempt to actually modify layer contents if the layout phase
508 // is not complete. Instead, defer the scroll event until the layout finishes.
509 if (shouldDeferScrollUpdateAfterContentSizeChange()) {
510 ASSERT(!m_deferredScrollDelta);
511 m_deferredScrollDelta = std::make_unique<IntSize>(scrollDelta);
515 completeUpdatesAfterScrollTo(scrollDelta);
518 void ScrollView::completeUpdatesAfterScrollTo(const IntSize& scrollDelta)
520 updateLayerPositionsAfterScrolling();
521 scrollContents(scrollDelta);
522 updateCompositingLayersAfterScrolling();
525 int ScrollView::scrollPosition(Scrollbar* scrollbar) const
527 if (scrollbar->orientation() == HorizontalScrollbar)
528 return scrollPosition().x() + scrollOrigin().x();
529 if (scrollbar->orientation() == VerticalScrollbar)
530 return scrollPosition().y() + scrollOrigin().y();
534 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
536 if (prohibitsScrolling())
539 if (platformWidget()) {
540 platformSetScrollPosition(scrollPoint);
544 IntPoint newScrollPosition = !delegatesScrolling() ? adjustScrollPositionWithinRange(scrollPoint) : scrollPoint;
546 if ((!delegatesScrolling() || !inProgrammaticScroll()) && newScrollPosition == scrollPosition())
549 if (requestScrollPositionUpdate(newScrollPosition))
552 updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
555 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
557 if (platformWidget())
558 return platformScroll(direction, granularity);
560 return ScrollableArea::scroll(direction, granularity);
563 bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
565 return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
568 IntSize ScrollView::overhangAmount() const
572 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
573 if (physicalScrollY < 0)
574 stretch.setHeight(physicalScrollY);
575 else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight())
576 stretch.setHeight(physicalScrollY - (totalContentsSize().height() - visibleHeight()));
578 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
579 if (physicalScrollX < 0)
580 stretch.setWidth(physicalScrollX);
581 else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth())
582 stretch.setWidth(physicalScrollX - (contentsWidth() - visibleWidth()));
587 void ScrollView::windowResizerRectChanged()
589 if (platformWidget())
592 updateScrollbars(scrollOffset());
595 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
597 if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget() || delegatesScrolling())
600 bool hasOverlayScrollbars = (!m_horizontalScrollbar || m_horizontalScrollbar->isOverlayScrollbar()) && (!m_verticalScrollbar || m_verticalScrollbar->isOverlayScrollbar());
602 // If we came in here with the view already needing a layout, then go ahead and do that
603 // first. (This will be the common case, e.g., when the page changes due to window resizing for example).
604 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
605 if (!m_scrollbarsSuppressed && !hasOverlayScrollbars) {
606 m_inUpdateScrollbars = true;
607 visibleContentsResized();
608 m_inUpdateScrollbars = false;
611 IntRect oldScrollCornerRect = scrollCornerRect();
613 bool hasHorizontalScrollbar = m_horizontalScrollbar;
614 bool hasVerticalScrollbar = m_verticalScrollbar;
616 bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
617 bool newHasVerticalScrollbar = hasVerticalScrollbar;
619 ScrollbarMode hScroll = m_horizontalScrollbarMode;
620 ScrollbarMode vScroll = m_verticalScrollbarMode;
622 if (hScroll != ScrollbarAuto)
623 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
624 if (vScroll != ScrollbarAuto)
625 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
627 bool scrollbarAddedOrRemoved = false;
629 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
630 if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
631 if (setHasHorizontalScrollbar(newHasHorizontalScrollbar))
632 scrollbarAddedOrRemoved = true;
635 if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
636 if (setHasVerticalScrollbar(newHasVerticalScrollbar))
637 scrollbarAddedOrRemoved = true;
640 bool sendContentResizedNotification = false;
642 IntSize docSize = totalContentsSize();
643 IntSize fullVisibleSize = unobscuredContentRectIncludingScrollbars().size();
645 if (hScroll == ScrollbarAuto)
646 newHasHorizontalScrollbar = docSize.width() > visibleWidth();
647 if (vScroll == ScrollbarAuto)
648 newHasVerticalScrollbar = docSize.height() > visibleHeight();
650 bool needAnotherPass = false;
651 if (!hasOverlayScrollbars) {
652 // If we ever turn one scrollbar off, always turn the other one off too. Never ever
653 // try to both gain/lose a scrollbar in the same pass.
654 if (!m_updateScrollbarsPass && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()) {
655 if (hScroll == ScrollbarAuto)
656 newHasHorizontalScrollbar = false;
657 if (vScroll == ScrollbarAuto)
658 newHasVerticalScrollbar = false;
660 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) {
661 newHasVerticalScrollbar = false;
662 needAnotherPass = true;
664 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) {
665 newHasHorizontalScrollbar = false;
666 needAnotherPass = true;
670 if (hasHorizontalScrollbar != newHasHorizontalScrollbar && (hasHorizontalScrollbar || !avoidScrollbarCreation())) {
671 if (scrollOrigin().y() && !newHasHorizontalScrollbar)
672 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x(), scrollOrigin().y() - m_horizontalScrollbar->height()));
673 if (m_horizontalScrollbar)
674 m_horizontalScrollbar->invalidate();
676 bool changeAffectsContentSize = false;
677 if (setHasHorizontalScrollbar(newHasHorizontalScrollbar, &changeAffectsContentSize)) {
678 scrollbarAddedOrRemoved = true;
679 sendContentResizedNotification |= changeAffectsContentSize;
683 if (hasVerticalScrollbar != newHasVerticalScrollbar && (hasVerticalScrollbar || !avoidScrollbarCreation())) {
684 if (scrollOrigin().x() && !newHasVerticalScrollbar)
685 ScrollableArea::setScrollOrigin(IntPoint(scrollOrigin().x() - m_verticalScrollbar->width(), scrollOrigin().y()));
686 if (m_verticalScrollbar)
687 m_verticalScrollbar->invalidate();
689 bool changeAffectsContentSize = false;
690 if (setHasVerticalScrollbar(newHasVerticalScrollbar, &changeAffectsContentSize)) {
691 scrollbarAddedOrRemoved = true;
692 sendContentResizedNotification |= changeAffectsContentSize;
696 const unsigned cMaxUpdateScrollbarsPass = 2;
697 if ((sendContentResizedNotification || needAnotherPass) && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
698 m_updateScrollbarsPass++;
700 visibleContentsResized();
701 IntSize newDocSize = totalContentsSize();
702 if (newDocSize == docSize) {
703 // The layout with the new scroll state had no impact on
704 // the document's overall size, so updateScrollbars didn't get called.
706 updateScrollbars(desiredOffset);
708 m_updateScrollbarsPass--;
712 if (scrollbarAddedOrRemoved)
713 addedOrRemovedScrollbar();
715 // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
716 // doing it multiple times).
717 if (m_updateScrollbarsPass)
720 m_inUpdateScrollbars = true;
722 if (m_horizontalScrollbar) {
723 int clientWidth = visibleWidth();
724 int pageStep = Scrollbar::pageStep(clientWidth);
725 IntRect oldRect(m_horizontalScrollbar->frameRect());
727 height() - m_horizontalScrollbar->height(),
728 width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
729 m_horizontalScrollbar->height());
730 m_horizontalScrollbar->setFrameRect(hBarRect);
731 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
732 m_horizontalScrollbar->invalidate();
734 if (m_scrollbarsSuppressed)
735 m_horizontalScrollbar->setSuppressInvalidation(true);
736 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
737 m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
738 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
739 if (m_scrollbarsSuppressed)
740 m_horizontalScrollbar->setSuppressInvalidation(false);
743 if (m_verticalScrollbar) {
744 int clientHeight = visibleHeight();
745 int pageStep = Scrollbar::pageStep(clientHeight);
746 IntRect oldRect(m_verticalScrollbar->frameRect());
747 IntRect vBarRect(width() - m_verticalScrollbar->width(),
749 m_verticalScrollbar->width(),
750 height() - topContentInset() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
751 m_verticalScrollbar->setFrameRect(vBarRect);
752 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
753 m_verticalScrollbar->invalidate();
755 if (m_scrollbarsSuppressed)
756 m_verticalScrollbar->setSuppressInvalidation(true);
757 m_verticalScrollbar->setEnabled(totalContentsSize().height() > clientHeight);
758 m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
759 m_verticalScrollbar->setProportion(clientHeight, totalContentsSize().height());
760 if (m_scrollbarsSuppressed)
761 m_verticalScrollbar->setSuppressInvalidation(false);
764 if (hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar) {
765 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
767 positionScrollbarLayers();
768 updateScrollCorner();
769 if (!m_horizontalScrollbar && !m_verticalScrollbar)
770 invalidateScrollCornerRect(oldScrollCornerRect);
773 IntPoint adjustedScrollPosition = IntPoint(desiredOffset);
774 if (!isRubberBandInProgress())
775 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
777 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) {
778 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition + toIntSize(scrollOrigin()));
779 resetScrollOriginChanged();
782 // Make sure the scrollbar offsets are up to date.
783 if (m_horizontalScrollbar)
784 m_horizontalScrollbar->offsetDidChange();
785 if (m_verticalScrollbar)
786 m_verticalScrollbar->offsetDidChange();
788 m_inUpdateScrollbars = false;
791 const int panIconSizeLength = 16;
793 IntRect ScrollView::rectToCopyOnScroll() const
795 IntRect scrollViewRect = convertToRootView(IntRect(0, 0, visibleWidth(), visibleHeight()));
796 if (hasOverlayScrollbars()) {
797 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
798 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
800 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
801 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
803 return scrollViewRect;
806 void ScrollView::scrollContents(const IntSize& scrollDelta)
808 HostWindow* window = hostWindow();
812 // Since scrolling is double buffered, we will be blitting the scroll view's intersection
813 // with the clip rect every time to keep it smooth.
814 IntRect clipRect = windowClipRect();
815 IntRect scrollViewRect = rectToCopyOnScroll();
816 IntRect updateRect = clipRect;
817 updateRect.intersect(scrollViewRect);
819 // Invalidate the root view (not the backing store).
820 window->invalidateRootView(updateRect);
822 if (m_drawPanScrollIcon) {
823 // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
824 // https://bugs.webkit.org/show_bug.cgi?id=47837
825 int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
826 IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
827 IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
828 panScrollIconDirtyRect.intersect(clipRect);
829 window->invalidateContentsAndRootView(panScrollIconDirtyRect);
832 if (canBlitOnScroll()) { // The main frame can just blit the WebView window
833 // FIXME: Find a way to scroll subframes with this faster path
834 if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
835 scrollContentsSlowPath(updateRect);
837 // We need to go ahead and repaint the entire backing store. Do it now before moving the
839 scrollContentsSlowPath(updateRect);
842 // Invalidate the overhang areas if they are visible.
843 updateOverhangAreas();
845 // This call will move children with native widgets (plugins) and invalidate them as well.
848 // Now blit the backingstore into the window which should be very fast.
849 window->invalidateRootView(IntRect());
852 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
854 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
858 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
860 hostWindow()->invalidateContentsForSlowScroll(updateRect);
863 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const
865 if (delegatesScrolling())
866 return convertFromRootView(rootViewPoint);
868 IntPoint viewPoint = convertFromRootView(rootViewPoint);
869 return viewPoint + documentScrollOffsetRelativeToViewOrigin();
872 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const
874 if (delegatesScrolling())
875 return convertToRootView(contentsPoint);
877 IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)) - scrollOffset();
878 return convertToRootView(viewPoint);
881 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const
883 if (delegatesScrolling())
884 return convertFromRootView(rootViewRect);
886 IntRect viewRect = convertFromRootView(rootViewRect);
887 viewRect.move(documentScrollOffsetRelativeToViewOrigin());
891 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const
893 if (delegatesScrolling())
894 return convertToRootView(contentsRect);
896 IntRect viewRect = contentsRect;
897 viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
898 return convertToRootView(viewRect);
901 IntPoint ScrollView::rootViewToTotalContents(const IntPoint& rootViewPoint) const
903 if (delegatesScrolling())
904 return convertFromRootView(rootViewPoint);
906 IntPoint viewPoint = convertFromRootView(rootViewPoint);
907 return viewPoint + scrollOffset() - IntSize(0, topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset));
910 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
912 if (delegatesScrolling())
913 return convertFromContainingWindow(windowPoint);
915 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
916 return viewPoint + documentScrollOffsetRelativeToViewOrigin();
919 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
921 if (delegatesScrolling())
922 return convertToContainingWindow(contentsPoint);
924 IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)) - scrollOffset();
925 return convertToContainingWindow(viewPoint);
928 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
930 if (delegatesScrolling())
931 return convertFromContainingWindow(windowRect);
933 IntRect viewRect = convertFromContainingWindow(windowRect);
934 viewRect.move(documentScrollOffsetRelativeToViewOrigin());
938 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
940 if (delegatesScrolling())
941 return convertToContainingWindow(contentsRect);
943 IntRect viewRect = contentsRect;
944 viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
945 return convertToContainingWindow(viewRect);
948 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
950 HostWindow* window = hostWindow();
951 if (platformWidget())
952 return platformContentsToScreen(rect);
955 return window->rootViewToScreen(contentsToRootView(rect));
958 IntPoint ScrollView::screenToContents(const IntPoint& point) const
960 HostWindow* window = hostWindow();
961 if (platformWidget())
962 return platformScreenToContents(point);
965 return rootViewToContents(window->screenToRootView(point));
968 bool ScrollView::containsScrollbarsAvoidingResizer() const
970 return !m_scrollbarsAvoidingResizer;
973 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
975 int oldCount = m_scrollbarsAvoidingResizer;
976 m_scrollbarsAvoidingResizer += overlapDelta;
978 parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
979 else if (!scrollbarsSuppressed()) {
980 // If we went from n to 0 or from 0 to n and we're the outermost view,
981 // we need to invalidate the windowResizerRect(), since it will now need to paint
983 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
984 (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
985 invalidateRect(windowResizerRect());
989 void ScrollView::setParent(ScrollView* parentView)
991 if (parentView == parent())
994 if (m_scrollbarsAvoidingResizer && parent())
995 parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
997 Widget::setParent(parentView);
999 if (m_scrollbarsAvoidingResizer && parent())
1000 parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
1003 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
1005 if (suppressed == m_scrollbarsSuppressed)
1008 m_scrollbarsSuppressed = suppressed;
1010 if (platformWidget())
1011 platformSetScrollbarsSuppressed(repaintOnUnsuppress);
1012 else if (repaintOnUnsuppress && !suppressed) {
1013 if (m_horizontalScrollbar)
1014 m_horizontalScrollbar->invalidate();
1015 if (m_verticalScrollbar)
1016 m_verticalScrollbar->invalidate();
1018 // Invalidate the scroll corner too on unsuppress.
1019 invalidateRect(scrollCornerRect());
1023 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
1025 if (platformWidget())
1028 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1029 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint))
1030 return m_horizontalScrollbar.get();
1031 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint))
1032 return m_verticalScrollbar.get();
1036 void ScrollView::setScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle)
1038 ScrollableArea::setScrollbarOverlayStyle(overlayStyle);
1039 platformSetScrollbarOverlayStyle(overlayStyle);
1042 void ScrollView::setFrameRect(const IntRect& newRect)
1044 IntRect oldRect = frameRect();
1046 if (newRect == oldRect)
1049 Widget::setFrameRect(newRect);
1051 frameRectsChanged();
1053 updateScrollbars(scrollOffset());
1055 if (!m_useFixedLayout && oldRect.size() != newRect.size())
1059 void ScrollView::frameRectsChanged()
1061 if (platformWidget())
1064 HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1065 for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1066 (*current)->frameRectsChanged();
1069 void ScrollView::clipRectChanged()
1071 HashSet<RefPtr<Widget>>::const_iterator end = m_children.end();
1072 for (HashSet<RefPtr<Widget>>::const_iterator current = m_children.begin(); current != end; ++current)
1073 (*current)->clipRectChanged();
1076 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
1078 if (!graphicsLayer || !scrollbar)
1081 IntRect scrollbarRect = scrollbar->frameRect();
1082 graphicsLayer->setPosition(scrollbarRect.location());
1084 if (scrollbarRect.size() == graphicsLayer->size())
1087 graphicsLayer->setSize(scrollbarRect.size());
1089 if (graphicsLayer->usesContentsLayer()) {
1090 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
1094 graphicsLayer->setDrawsContent(true);
1095 graphicsLayer->setNeedsDisplay();
1098 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
1102 graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
1103 graphicsLayer->setPosition(cornerRect.location());
1104 if (cornerRect.size() != graphicsLayer->size())
1105 graphicsLayer->setNeedsDisplay();
1106 graphicsLayer->setSize(cornerRect.size());
1109 void ScrollView::positionScrollbarLayers()
1111 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
1112 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
1113 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
1116 void ScrollView::repaintContentRectangle(const IntRect& rect)
1118 IntRect paintRect = rect;
1119 if (clipsRepaints() && !paintsEntireContents())
1120 paintRect.intersect(visibleContentRect(LegacyIOSDocumentVisibleRect));
1121 if (paintRect.isEmpty())
1124 if (platformWidget()) {
1125 notifyPageThatContentAreaWillPaint();
1126 platformRepaintContentRectangle(paintRect);
1130 if (HostWindow* window = hostWindow())
1131 window->invalidateContentsAndRootView(contentsToWindow(paintRect));
1134 IntRect ScrollView::scrollCornerRect() const
1138 if (hasOverlayScrollbars())
1141 int heightTrackedByScrollbar = height() - topContentInset();
1143 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
1144 cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
1145 height() - m_horizontalScrollbar->height(),
1146 width() - m_horizontalScrollbar->width(),
1147 m_horizontalScrollbar->height()));
1150 if (m_verticalScrollbar && heightTrackedByScrollbar - m_verticalScrollbar->height() > 0) {
1151 cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
1152 m_verticalScrollbar->height() + topContentInset(),
1153 m_verticalScrollbar->width(),
1154 heightTrackedByScrollbar - m_verticalScrollbar->height()));
1160 bool ScrollView::isScrollCornerVisible() const
1162 return !scrollCornerRect().isEmpty();
1165 void ScrollView::scrollbarStyleChanged(ScrollbarStyle, bool forceUpdate)
1171 updateScrollbars(scrollOffset());
1172 positionScrollbarLayers();
1175 void ScrollView::updateScrollCorner()
1179 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
1181 ScrollbarTheme::theme()->paintScrollCorner(this, context, cornerRect);
1184 void ScrollView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
1186 bar->paint(context, rect);
1189 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
1191 invalidateRect(rect);
1194 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
1196 if (m_horizontalScrollbar && !layerForHorizontalScrollbar())
1197 paintScrollbar(context, m_horizontalScrollbar.get(), rect);
1198 if (m_verticalScrollbar && !layerForVerticalScrollbar())
1199 paintScrollbar(context, m_verticalScrollbar.get(), rect);
1201 if (layerForScrollCorner())
1204 paintScrollCorner(context, scrollCornerRect());
1207 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
1209 static Image* panScrollIcon = Image::loadPlatformResource("panIcon").leakRef();
1210 IntPoint iconGCPoint = m_panScrollIconPoint;
1212 iconGCPoint = parent()->windowToContents(iconGCPoint);
1213 context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, iconGCPoint);
1216 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
1218 if (platformWidget()) {
1219 Widget::paint(context, rect);
1223 if (context->paintingDisabled() && !context->updatingControlTints())
1226 notifyPageThatContentAreaWillPaint();
1228 IntRect documentDirtyRect = rect;
1229 if (!paintsEntireContents()) {
1230 IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect(LegacyIOSDocumentVisibleRect).size());
1231 documentDirtyRect.intersect(visibleAreaWithoutScrollbars);
1234 if (!documentDirtyRect.isEmpty()) {
1235 GraphicsContextStateSaver stateSaver(*context);
1237 context->translate(x(), y());
1238 documentDirtyRect.moveBy(-location());
1240 if (!paintsEntireContents()) {
1241 context->translate(-scrollX(), -scrollY());
1242 documentDirtyRect.moveBy(scrollPosition());
1244 context->clip(visibleContentRect(LegacyIOSDocumentVisibleRect));
1247 paintContents(context, documentDirtyRect);
1250 #if ENABLE(RUBBER_BANDING)
1251 if (!layerForOverhangAreas())
1252 calculateAndPaintOverhangAreas(context, rect);
1254 calculateAndPaintOverhangAreas(context, rect);
1257 // Now paint the scrollbars.
1258 if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
1259 GraphicsContextStateSaver stateSaver(*context);
1260 IntRect scrollViewDirtyRect = rect;
1261 IntRect visibleAreaWithScrollbars(location(), unobscuredContentRectIncludingScrollbars().size());
1262 scrollViewDirtyRect.intersect(visibleAreaWithScrollbars);
1263 context->translate(x(), y());
1264 scrollViewDirtyRect.moveBy(-location());
1265 context->clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size()));
1267 paintScrollbars(context, scrollViewDirtyRect);
1270 // Paint the panScroll Icon
1271 if (m_drawPanScrollIcon)
1272 paintPanScrollIcon(context);
1275 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1277 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1278 ? verticalScrollbar()->width() : 0;
1279 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1280 ? horizontalScrollbar()->height() : 0;
1282 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
1283 if (physicalScrollY < 0) {
1284 horizontalOverhangRect = frameRect();
1285 horizontalOverhangRect.setHeight(-physicalScrollY);
1286 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1287 } else if (totalContentsSize().height() && physicalScrollY > totalContentsSize().height() - visibleHeight()) {
1288 int height = physicalScrollY - (totalContentsSize().height() - visibleHeight());
1289 horizontalOverhangRect = frameRect();
1290 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
1291 horizontalOverhangRect.setHeight(height);
1292 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
1295 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
1296 if (physicalScrollX < 0) {
1297 verticalOverhangRect.setWidth(-physicalScrollX);
1298 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1299 verticalOverhangRect.setX(frameRect().x());
1300 if (horizontalOverhangRect.y() == frameRect().y())
1301 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1303 verticalOverhangRect.setY(frameRect().y());
1304 } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
1305 int width = physicalScrollX - (contentsWidth() - visibleWidth());
1306 verticalOverhangRect.setWidth(width);
1307 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
1308 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
1309 if (horizontalOverhangRect.y() == frameRect().y())
1310 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1312 verticalOverhangRect.setY(frameRect().y());
1316 void ScrollView::updateOverhangAreas()
1318 HostWindow* window = hostWindow();
1322 IntRect horizontalOverhangRect;
1323 IntRect verticalOverhangRect;
1324 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1325 if (!horizontalOverhangRect.isEmpty())
1326 window->invalidateContentsAndRootView(horizontalOverhangRect);
1327 if (!verticalOverhangRect.isEmpty())
1328 window->invalidateContentsAndRootView(verticalOverhangRect);
1331 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
1333 ScrollbarTheme::theme()->paintOverhangAreas(this, context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1336 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const IntRect& dirtyRect)
1338 IntRect horizontalOverhangRect;
1339 IntRect verticalOverhangRect;
1340 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1342 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect))
1343 paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect);
1346 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1348 if (!scrollbarCornerPresent())
1351 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1353 if (m_horizontalScrollbar) {
1354 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1355 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1356 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1358 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1361 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1362 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1363 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1365 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1368 bool ScrollView::scrollbarCornerPresent() const
1370 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
1371 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
1374 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1376 // Scrollbars won't be transformed within us
1377 IntRect newRect = localRect;
1378 newRect.moveBy(scrollbar->location());
1382 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1384 IntRect newRect = parentRect;
1385 // Scrollbars won't be transformed within us
1386 newRect.moveBy(-scrollbar->location());
1390 // FIXME: test these on windows
1391 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1393 // Scrollbars won't be transformed within us
1394 IntPoint newPoint = localPoint;
1395 newPoint.moveBy(scrollbar->location());
1399 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1401 IntPoint newPoint = parentPoint;
1402 // Scrollbars won't be transformed within us
1403 newPoint.moveBy(-scrollbar->location());
1407 void ScrollView::setParentVisible(bool visible)
1409 if (isParentVisible() == visible)
1412 Widget::setParentVisible(visible);
1414 if (!isSelfVisible())
1417 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1418 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1419 (*it)->setParentVisible(visible);
1422 void ScrollView::show()
1424 if (!isSelfVisible()) {
1425 setSelfVisible(true);
1426 if (isParentVisible()) {
1427 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1428 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1429 (*it)->setParentVisible(true);
1436 void ScrollView::hide()
1438 if (isSelfVisible()) {
1439 if (isParentVisible()) {
1440 HashSet<RefPtr<Widget>>::iterator end = m_children.end();
1441 for (HashSet<RefPtr<Widget>>::iterator it = m_children.begin(); it != end; ++it)
1442 (*it)->setParentVisible(false);
1444 setSelfVisible(false);
1450 bool ScrollView::isOffscreen() const
1452 if (platformWidget())
1453 return platformIsOffscreen();
1458 // FIXME: Add a HostWindow::isOffscreen method here. Since only Mac implements this method
1459 // currently, we can add the method when the other platforms decide to implement this concept.
1464 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1466 HostWindow* window = hostWindow();
1469 m_drawPanScrollIcon = true;
1470 m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1471 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1474 void ScrollView::removePanScrollIcon()
1476 HostWindow* window = hostWindow();
1479 m_drawPanScrollIcon = false;
1480 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
1483 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1485 if (scrollOrigin() == origin)
1488 ScrollableArea::setScrollOrigin(origin);
1490 if (platformWidget()) {
1491 platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1495 // Update if the scroll origin changes, since our position will be different if the content size did not change.
1496 if (updatePositionAtAll && updatePositionSynchronously)
1497 updateScrollbars(scrollOffset());
1500 void ScrollView::styleDidChange()
1502 if (m_horizontalScrollbar)
1503 m_horizontalScrollbar->styleChanged();
1505 if (m_verticalScrollbar)
1506 m_verticalScrollbar->styleChanged();
1509 #if !PLATFORM(COCOA)
1511 void ScrollView::platformAddChild(Widget*)
1515 void ScrollView::platformRemoveChild(Widget*)
1521 #if !PLATFORM(COCOA)
1523 void ScrollView::platformSetScrollbarsSuppressed(bool)
1527 void ScrollView::platformSetScrollOrigin(const IntPoint&, bool, bool)
1531 void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle)
1537 #if !PLATFORM(COCOA)
1539 void ScrollView::platformSetScrollbarModes()
1543 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1545 horizontal = ScrollbarAuto;
1546 vertical = ScrollbarAuto;
1549 void ScrollView::platformSetCanBlitOnScroll(bool)
1553 bool ScrollView::platformCanBlitOnScroll() const
1558 IntRect ScrollView::platformVisibleContentRect(bool) const
1563 float ScrollView::platformTopContentInset() const
1568 void ScrollView::platformSetTopContentInset(float)
1572 IntSize ScrollView::platformVisibleContentSize(bool) const
1577 IntRect ScrollView::platformVisibleContentRectIncludingObscuredArea(bool) const
1582 IntSize ScrollView::platformVisibleContentSizeIncludingObscuredArea(bool) const
1587 void ScrollView::platformSetContentsSize()
1591 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1596 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1601 void ScrollView::platformSetScrollPosition(const IntPoint&)
1605 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1610 void ScrollView::platformRepaintContentRectangle(const IntRect&)
1614 bool ScrollView::platformIsOffscreen() const