summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/ScrollView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/ScrollView.cpp')
-rw-r--r--WebCore/platform/ScrollView.cpp878
1 files changed, 878 insertions, 0 deletions
diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp
new file mode 100644
index 0000000..9eb6ce7
--- /dev/null
+++ b/WebCore/platform/ScrollView.cpp
@@ -0,0 +1,878 @@
+
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollView.h"
+
+#include "GraphicsContext.h"
+#include "HostWindow.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#include "Scrollbar.h"
+#include "ScrollbarTheme.h"
+
+using std::max;
+
+namespace WebCore {
+
+ScrollView::ScrollView()
+ : m_horizontalScrollbarMode(ScrollbarAuto)
+ , m_verticalScrollbarMode(ScrollbarAuto)
+ , m_prohibitsScrolling(false)
+ , m_canBlitOnScroll(true)
+ , m_scrollbarsAvoidingResizer(0)
+ , m_scrollbarsSuppressed(false)
+ , m_inUpdateScrollbars(false)
+ , m_drawPanScrollIcon(false)
+{
+ platformInit();
+ if (platformWidget())
+ platformSetCanBlitOnScroll();
+}
+
+ScrollView::~ScrollView()
+{
+ platformDestroy();
+}
+
+void ScrollView::addChild(Widget* child)
+{
+ ASSERT(child != this && !child->parent());
+ child->setParent(this);
+ m_children.add(child);
+ if (child->platformWidget())
+ platformAddChild(child);
+}
+
+void ScrollView::removeChild(Widget* child)
+{
+ ASSERT(child->parent() == this);
+ child->setParent(0);
+ m_children.remove(child);
+ if (child->platformWidget())
+ platformRemoveChild(child);
+}
+
+void ScrollView::setHasHorizontalScrollbar(bool hasBar)
+{
+ if (hasBar && !m_horizontalScrollbar && !platformHasHorizontalAdjustment()) {
+ m_horizontalScrollbar = Scrollbar::createNativeScrollbar(this, HorizontalScrollbar, RegularScrollbar);
+ addChild(m_horizontalScrollbar.get());
+ } else if (!hasBar && m_horizontalScrollbar) {
+ removeChild(m_horizontalScrollbar.get());
+ m_horizontalScrollbar = 0;
+ }
+}
+
+void ScrollView::setHasVerticalScrollbar(bool hasBar)
+{
+ if (hasBar && !m_verticalScrollbar && !platformHasVerticalAdjustment()) {
+ m_verticalScrollbar = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, RegularScrollbar);
+ addChild(m_verticalScrollbar.get());
+ } else if (!hasBar && m_verticalScrollbar) {
+ removeChild(m_verticalScrollbar.get());
+ m_verticalScrollbar = 0;
+ }
+}
+
+void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
+{
+ if (horizontalMode == horizontalScrollbarMode() && verticalMode == verticalScrollbarMode())
+ return;
+ m_horizontalScrollbarMode = horizontalMode;
+ m_verticalScrollbarMode = verticalMode;
+ if (platformWidget())
+ platformSetScrollbarModes();
+ else
+ updateScrollbars(scrollOffset());
+}
+
+void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
+{
+ if (platformWidget()) {
+ platformScrollbarModes(horizontalMode, verticalMode);
+ return;
+ }
+ horizontalMode = m_horizontalScrollbarMode;
+ verticalMode = m_verticalScrollbarMode;
+}
+
+void ScrollView::setCanHaveScrollbars(bool canScroll)
+{
+ ScrollbarMode newHorizontalMode;
+ ScrollbarMode newVerticalMode;
+
+ scrollbarModes(newHorizontalMode, newVerticalMode);
+
+ if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
+ newVerticalMode = ScrollbarAuto;
+ else if (!canScroll)
+ newVerticalMode = ScrollbarAlwaysOff;
+
+ if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
+ newHorizontalMode = ScrollbarAuto;
+ else if (!canScroll)
+ newHorizontalMode = ScrollbarAlwaysOff;
+
+ setScrollbarModes(newHorizontalMode, newVerticalMode);
+}
+
+void ScrollView::setCanBlitOnScroll(bool b)
+{
+ if (m_canBlitOnScroll == b)
+ return;
+ m_canBlitOnScroll = b;
+ if (platformWidget())
+ platformSetCanBlitOnScroll();
+}
+
+IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
+{
+ if (platformWidget())
+ return platformVisibleContentRect(includeScrollbars);
+ return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
+ IntSize(max(0, width() - (verticalScrollbar() && !includeScrollbars ? verticalScrollbar()->width() : 0)),
+ max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0))));
+}
+
+IntSize ScrollView::contentsSize() const
+{
+ if (platformWidget())
+ return platformContentsSize();
+ return m_contentsSize;
+}
+
+void ScrollView::setContentsSize(const IntSize& newSize)
+{
+ if (contentsSize() == newSize)
+ return;
+ m_contentsSize = newSize;
+ if (platformWidget())
+ platformSetContentsSize();
+ else
+ updateScrollbars(scrollOffset());
+}
+
+IntPoint ScrollView::maximumScrollPosition() const
+{
+ IntSize maximumOffset = contentsSize() - visibleContentRect().size();
+ maximumOffset.clampNegativeToZero();
+ return IntPoint(maximumOffset.width(), maximumOffset.height());
+}
+
+void ScrollView::valueChanged(Scrollbar* scrollbar)
+{
+ // Figure out if we really moved.
+ IntSize newOffset = m_scrollOffset;
+ if (scrollbar) {
+ if (scrollbar == m_horizontalScrollbar)
+ newOffset.setWidth(scrollbar->value());
+ else if (scrollbar == m_verticalScrollbar)
+ newOffset.setHeight(scrollbar->value());
+ }
+
+ IntSize scrollDelta = newOffset - m_scrollOffset;
+ if (scrollDelta == IntSize())
+ return;
+ m_scrollOffset = newOffset;
+
+ if (scrollbarsSuppressed())
+ return;
+
+ scrollContents(scrollDelta);
+}
+
+void ScrollView::scrollRectIntoViewRecursively(const IntRect& r)
+{
+#if PLATFORM(ANDROID)
+ if (platformProhibitsScrolling())
+ return;
+#endif
+ if (prohibitsScrolling())
+ return;
+
+ IntPoint p(max(0, r.x()), max(0, r.y()));
+ ScrollView* view = this;
+ while (view) {
+ view->setScrollPosition(p);
+ p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height());
+ view = view->parent();
+ }
+}
+
+void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
+{
+ if (prohibitsScrolling())
+ return;
+
+ if (platformWidget()) {
+ platformSetScrollPosition(scrollPoint);
+ return;
+ }
+
+ IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
+ newScrollPosition.clampNegativeToZero();
+
+ if (newScrollPosition == scrollPosition())
+ return;
+
+ updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
+}
+
+bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
+{
+ if (platformWidget())
+ return platformScroll(direction, granularity);
+
+ if (direction == ScrollUp || direction == ScrollDown) {
+ if (m_verticalScrollbar)
+ return m_verticalScrollbar->scroll(direction, granularity);
+ } else {
+ if (m_horizontalScrollbar)
+ return m_horizontalScrollbar->scroll(direction, granularity);
+ }
+ return false;
+}
+
+void ScrollView::updateScrollbars(const IntSize& desiredOffset)
+{
+ // Don't allow re-entrancy into this function.
+ if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
+ return;
+
+ m_inUpdateScrollbars = true;
+
+ bool hasVerticalScrollbar = m_verticalScrollbar;
+ bool hasHorizontalScrollbar = m_horizontalScrollbar;
+ bool oldHasVertical = hasVerticalScrollbar;
+ bool oldHasHorizontal = hasHorizontalScrollbar;
+ ScrollbarMode hScroll = m_horizontalScrollbarMode;
+ ScrollbarMode vScroll = m_verticalScrollbarMode;
+
+ const int scrollbarThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
+
+ for (int pass = 0; pass < 2; pass++) {
+ bool scrollsVertically;
+ bool scrollsHorizontally;
+
+ if (!m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
+ // Do a layout if pending before checking if scrollbars are needed.
+ if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
+ visibleContentsResized();
+
+ scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
+ if (scrollsVertically)
+ scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + scrollbarThickness > width());
+ else {
+ scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
+ if (scrollsHorizontally)
+ scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + scrollbarThickness > height());
+ }
+ } else {
+ scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
+ scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
+ }
+
+ if (hasVerticalScrollbar != scrollsVertically) {
+ setHasVerticalScrollbar(scrollsVertically);
+ hasVerticalScrollbar = scrollsVertically;
+ }
+
+ if (hasHorizontalScrollbar != scrollsHorizontally) {
+ setHasHorizontalScrollbar(scrollsHorizontally);
+ hasHorizontalScrollbar = scrollsHorizontally;
+ }
+ }
+
+ // Set up the range (and page step/line step).
+ IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
+ IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
+ scroll.clampNegativeToZero();
+
+ if (!platformHandleHorizontalAdjustment(scroll) && m_horizontalScrollbar) {
+ int clientWidth = visibleWidth();
+ m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
+ int pageStep = (clientWidth - cAmountToKeepWhenPaging);
+ if (pageStep < 0)
+ pageStep = clientWidth;
+ IntRect oldRect(m_horizontalScrollbar->frameRect());
+ IntRect hBarRect = IntRect(0,
+ height() - m_horizontalScrollbar->height(),
+ width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
+ m_horizontalScrollbar->height());
+ m_horizontalScrollbar->setFrameRect(hBarRect);
+ if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
+ m_horizontalScrollbar->invalidate();
+
+ if (m_scrollbarsSuppressed)
+ m_horizontalScrollbar->setSuppressInvalidation(true);
+ m_horizontalScrollbar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
+ m_horizontalScrollbar->setValue(scroll.width());
+ if (m_scrollbarsSuppressed)
+ m_horizontalScrollbar->setSuppressInvalidation(false);
+ }
+
+ if (!platformHandleVerticalAdjustment(scroll) && m_verticalScrollbar) {
+ int clientHeight = visibleHeight();
+ m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
+ int pageStep = (clientHeight - cAmountToKeepWhenPaging);
+ if (pageStep < 0)
+ pageStep = clientHeight;
+ IntRect oldRect(m_verticalScrollbar->frameRect());
+ IntRect vBarRect = IntRect(width() - m_verticalScrollbar->width(),
+ 0,
+ m_verticalScrollbar->width(),
+ height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
+ m_verticalScrollbar->setFrameRect(vBarRect);
+ if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
+ m_verticalScrollbar->invalidate();
+
+ if (m_scrollbarsSuppressed)
+ m_verticalScrollbar->setSuppressInvalidation(true);
+ m_verticalScrollbar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
+ m_verticalScrollbar->setValue(scroll.height());
+ if (m_scrollbarsSuppressed)
+ m_verticalScrollbar->setSuppressInvalidation(false);
+ }
+
+ if (oldHasVertical != (m_verticalScrollbar != 0) || oldHasHorizontal != (m_horizontalScrollbar != 0))
+ frameRectsChanged();
+
+ // See if our offset has changed in a situation where we might not have scrollbars.
+ // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
+ // It can also happen when maximizing a window that has scrollbars (but the new maximized result
+ // does not).
+ IntSize scrollDelta = scroll - m_scrollOffset;
+ if (scrollDelta != IntSize()) {
+ m_scrollOffset = scroll;
+ scrollContents(scrollDelta);
+ }
+
+ m_inUpdateScrollbars = false;
+}
+
+const int panIconSizeLength = 20;
+
+void ScrollView::scrollContents(const IntSize& scrollDelta)
+{
+ // Since scrolling is double buffered, we will be blitting the scroll view's intersection
+ // with the clip rect every time to keep it smooth.
+ IntRect clipRect = windowClipRect();
+ IntRect scrollViewRect = convertToContainingWindow(IntRect(0, 0, visibleWidth(), visibleHeight()));
+ IntRect updateRect = clipRect;
+ updateRect.intersect(scrollViewRect);
+
+ // Invalidate the window (not the backing store).
+ hostWindow()->repaint(updateRect, false);
+
+ if (m_drawPanScrollIcon) {
+ int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
+ IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
+ IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
+ panScrollIconDirtyRect.intersect(clipRect);
+ hostWindow()->repaint(panScrollIconDirtyRect, true, true);
+ }
+
+ if (canBlitOnScroll() && !rootPreventsBlitting()) { // The main frame can just blit the WebView window
+ // FIXME: Find a way to blit subframes without blitting overlapping content
+ hostWindow()->scroll(-scrollDelta, scrollViewRect, clipRect);
+ } else {
+ // We need to go ahead and repaint the entire backing store. Do it now before moving the
+ // plugins.
+ hostWindow()->repaint(updateRect, true, false, true); // Invalidate the backing store and repaint it synchronously
+ }
+
+ // This call will move children with native widgets (plugins) and invalidate them as well.
+ frameRectsChanged();
+
+ // Now update the window (which should do nothing but a blit of the backing store's updateRect and so should
+ // be very fast).
+ hostWindow()->paint();
+}
+
+IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
+{
+ IntPoint viewPoint = convertFromContainingWindow(windowPoint);
+ return viewPoint + scrollOffset();
+}
+
+IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
+{
+ IntPoint viewPoint = contentsPoint - scrollOffset();
+ return convertToContainingWindow(viewPoint);
+}
+
+IntRect ScrollView::windowToContents(const IntRect& windowRect) const
+{
+ IntRect viewRect = convertFromContainingWindow(windowRect);
+ viewRect.move(scrollOffset());
+ return viewRect;
+}
+
+IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
+{
+ IntRect viewRect = contentsRect;
+ viewRect.move(-scrollOffset());
+ return convertToContainingWindow(viewRect);
+}
+
+IntRect ScrollView::contentsToScreen(const IntRect& rect) const
+{
+ if (platformWidget())
+ return platformContentsToScreen(rect);
+ return hostWindow()->windowToScreen(contentsToWindow(rect));
+}
+
+IntPoint ScrollView::screenToContents(const IntPoint& point) const
+{
+ if (platformWidget())
+ return platformScreenToContents(point);
+ return windowToContents(hostWindow()->screenToWindow(point));
+}
+
+bool ScrollView::containsScrollbarsAvoidingResizer() const
+{
+ return !m_scrollbarsAvoidingResizer;
+}
+
+void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
+{
+ int oldCount = m_scrollbarsAvoidingResizer;
+ m_scrollbarsAvoidingResizer += overlapDelta;
+ if (parent())
+ parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
+ else if (!scrollbarsSuppressed()) {
+ // If we went from n to 0 or from 0 to n and we're the outermost view,
+ // we need to invalidate the windowResizerRect(), since it will now need to paint
+ // differently.
+ if (oldCount > 0 && m_scrollbarsAvoidingResizer == 0 ||
+ oldCount == 0 && m_scrollbarsAvoidingResizer > 0)
+ invalidateRect(windowResizerRect());
+ }
+}
+
+void ScrollView::setParent(ScrollView* parentView)
+{
+ if (parentView == parent())
+ return;
+
+ if (m_scrollbarsAvoidingResizer && parent())
+ parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
+
+ Widget::setParent(parentView);
+
+ if (m_scrollbarsAvoidingResizer && parent())
+ parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
+}
+
+void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
+{
+ if (suppressed == m_scrollbarsSuppressed)
+ return;
+
+ m_scrollbarsSuppressed = suppressed;
+
+ if (platformWidget())
+ platformSetScrollbarsSuppressed(repaintOnUnsuppress);
+ else if (repaintOnUnsuppress && !suppressed) {
+ if (m_horizontalScrollbar)
+ m_horizontalScrollbar->invalidate();
+ if (m_verticalScrollbar)
+ m_verticalScrollbar->invalidate();
+
+ // Invalidate the scroll corner too on unsuppress.
+ IntRect hCorner;
+ if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
+ hCorner = IntRect(m_horizontalScrollbar->width(),
+ height() - m_horizontalScrollbar->height(),
+ width() - m_horizontalScrollbar->width(),
+ m_horizontalScrollbar->height());
+ invalidateRect(hCorner);
+ }
+
+ if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
+ IntRect vCorner(width() - m_verticalScrollbar->width(),
+ m_verticalScrollbar->height(),
+ m_verticalScrollbar->width(),
+ height() - m_verticalScrollbar->height());
+ if (vCorner != hCorner)
+ invalidateRect(vCorner);
+ }
+ }
+}
+
+Scrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent)
+{
+ if (platformWidget())
+ return 0;
+
+ IntPoint viewPoint = convertFromContainingWindow(mouseEvent.pos());
+ if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint))
+ return m_horizontalScrollbar.get();
+ if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint))
+ return m_verticalScrollbar.get();
+ return 0;
+}
+
+void ScrollView::wheelEvent(PlatformWheelEvent& e)
+{
+ // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
+ if (!canHaveScrollbars() || platformWidget())
+ return;
+
+ // Determine how much we want to scroll. If we can move at all, we will accept the event.
+ IntSize maxScrollDelta = maximumScrollPosition() - scrollPosition();
+ if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
+ (e.deltaX() > 0 && scrollOffset().width() > 0) ||
+ (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
+ (e.deltaY() > 0 && scrollOffset().height() > 0)) {
+ e.accept();
+ float deltaX = e.deltaX();
+ float deltaY = e.deltaY();
+ if (e.granularity() == ScrollByLineWheelEvent) {
+ deltaX *= cMouseWheelPixelsPerLineStep;
+ deltaY *= cMouseWheelPixelsPerLineStep;
+ } else if (e.granularity() == ScrollByPageWheelEvent) {
+ ASSERT(deltaX == 0);
+ bool negative = deltaY < 0;
+ deltaY = max(0, visibleHeight() - cAmountToKeepWhenPaging);
+ if (negative)
+ deltaY = -deltaY;
+ }
+ scrollBy(IntSize(-deltaX, -deltaY));
+ }
+}
+
+void ScrollView::setFrameRect(const IntRect& newRect)
+{
+ IntRect oldRect = frameRect();
+
+ if (newRect == oldRect)
+ return;
+
+ Widget::setFrameRect(newRect);
+
+ if (platformWidget())
+ return;
+
+ if (newRect.width() != oldRect.width() || newRect.height() != oldRect.height()) {
+ updateScrollbars(m_scrollOffset);
+ contentsResized();
+ }
+
+ frameRectsChanged();
+}
+
+void ScrollView::frameRectsChanged() const
+{
+ if (platformWidget())
+ return;
+
+ HashSet<Widget*>::const_iterator end = m_children.end();
+ for (HashSet<Widget*>::const_iterator current = m_children.begin(); current != end; ++current)
+ (*current)->frameRectsChanged();
+}
+
+void ScrollView::repaintContentRectangle(const IntRect& rect, bool now)
+{
+ if (rect.isEmpty())
+ return;
+
+ if (platformWidget()) {
+ platformRepaintContentRectangle(rect, now);
+ return;
+ }
+
+ hostWindow()->repaint(contentsToWindow(rect), true, now);
+}
+
+void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (platformWidget()) {
+ Widget::paint(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled() && !context->updatingControlTints())
+ return;
+
+ IntRect documentDirtyRect = rect;
+ documentDirtyRect.intersect(frameRect());
+
+ context->save();
+
+ context->translate(x(), y());
+ documentDirtyRect.move(-x(), -y());
+
+ context->translate(-scrollX(), -scrollY());
+ documentDirtyRect.move(scrollX(), scrollY());
+
+ context->clip(visibleContentRect());
+
+ paintContents(context, documentDirtyRect);
+
+ context->restore();
+
+ // Now paint the scrollbars.
+ if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
+ context->save();
+ IntRect scrollViewDirtyRect = rect;
+ scrollViewDirtyRect.intersect(frameRect());
+ context->translate(x(), y());
+ scrollViewDirtyRect.move(-x(), -y());
+ if (m_horizontalScrollbar)
+ m_horizontalScrollbar->paint(context, scrollViewDirtyRect);
+ if (m_verticalScrollbar)
+ m_verticalScrollbar->paint(context, scrollViewDirtyRect);
+
+ IntRect hCorner;
+ if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
+ hCorner = IntRect(m_horizontalScrollbar->width(),
+ height() - m_horizontalScrollbar->height(),
+ width() - m_horizontalScrollbar->width(),
+ m_horizontalScrollbar->height());
+ if (hCorner.intersects(scrollViewDirtyRect))
+ ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, hCorner);
+ }
+
+ if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
+ IntRect vCorner(width() - m_verticalScrollbar->width(),
+ m_verticalScrollbar->height(),
+ m_verticalScrollbar->width(),
+ height() - m_verticalScrollbar->height());
+ if (vCorner != hCorner && vCorner.intersects(scrollViewDirtyRect))
+ ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, vCorner);
+ }
+
+ context->restore();
+ }
+
+ // Paint the panScroll Icon
+ static RefPtr<Image> panScrollIcon;
+ if (m_drawPanScrollIcon) {
+ if (!panScrollIcon)
+ panScrollIcon = Image::loadPlatformResource("panIcon");
+ context->drawImage(panScrollIcon.get(), m_panScrollIconPoint);
+ }
+}
+
+bool ScrollView::scrollbarCornerPresent() const
+{
+ return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) ||
+ (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
+}
+
+void ScrollView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (!isVisible())
+ return;
+
+ HashSet<Widget*>::iterator end = m_children.end();
+ for (HashSet<Widget*>::iterator it = m_children.begin(); it != end; ++it)
+ (*it)->setParentVisible(visible);
+}
+
+void ScrollView::show()
+{
+ if (!isSelfVisible()) {
+ setSelfVisible(true);
+ if (isParentVisible()) {
+ HashSet<Widget*>::iterator end = m_children.end();
+ for (HashSet<Widget*>::iterator it = m_children.begin(); it != end; ++it)
+ (*it)->setParentVisible(true);
+ }
+ }
+
+ Widget::show();
+}
+
+void ScrollView::hide()
+{
+ if (isSelfVisible()) {
+ if (isParentVisible()) {
+ HashSet<Widget*>::iterator end = m_children.end();
+ for (HashSet<Widget*>::iterator it = m_children.begin(); it != end; ++it)
+ (*it)->setParentVisible(false);
+ }
+ setSelfVisible(false);
+ }
+
+ Widget::hide();
+}
+
+bool ScrollView::isOffscreen() const
+{
+ if (platformWidget())
+ return platformIsOffscreen();
+
+ if (!isVisible())
+ return true;
+
+ // FIXME: Add a HostWindow::isOffscreen method here. Since only Mac implements this method
+ // currently, we can add the method when the other platforms decide to implement this concept.
+ return false;
+}
+
+
+void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
+{
+ m_drawPanScrollIcon = true;
+ m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
+ hostWindow()->repaint(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength,panIconSizeLength)), true, true);
+}
+
+void ScrollView::removePanScrollIcon()
+{
+ m_drawPanScrollIcon = false;
+ hostWindow()->repaint(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true, true);
+}
+
+#if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT)
+void ScrollView::platformInit()
+{
+}
+
+void ScrollView::platformDestroy()
+{
+}
+#endif
+
+#if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC)
+void ScrollView::platformAddChild(Widget*)
+{
+}
+
+void ScrollView::platformRemoveChild(Widget*)
+{
+}
+#endif
+
+#if !PLATFORM(MAC)
+void ScrollView::platformSetCanBlitOnScroll()
+{
+}
+
+void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress)
+{
+}
+#endif
+
+#if !PLATFORM(MAC) && !PLATFORM(WX)
+void ScrollView::platformSetScrollbarModes()
+{
+}
+
+#if !PLATFORM(ANDROID)
+void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
+{
+}
+
+IntRect ScrollView::platformVisibleContentRect(bool) const
+{
+ return IntRect();
+}
+
+IntSize ScrollView::platformContentsSize() const
+{
+ return IntSize();
+}
+#endif
+
+void ScrollView::platformSetContentsSize()
+{
+}
+
+IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
+{
+ return rect;
+}
+
+IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
+{
+ return point;
+}
+
+#if !PLATFORM(ANDROID)
+void ScrollView::platformSetScrollPosition(const IntPoint&)
+{
+}
+#endif
+
+bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
+{
+ return true;
+}
+
+#if !PLATFORM(ANDROID)
+void ScrollView::platformRepaintContentRectangle(const IntRect&, bool now)
+{
+}
+
+#ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
+void ScrollView::platformOffscreenContentRectangle(const IntRect& )
+{
+}
+#endif
+#endif
+
+bool ScrollView::platformIsOffscreen() const
+{
+ return false;
+}
+#endif
+
+#if !PLATFORM(GTK)
+bool ScrollView::platformHandleHorizontalAdjustment(const IntSize&)
+{
+ return false;
+}
+
+bool ScrollView::platformHandleVerticalAdjustment(const IntSize&)
+{
+ return false;
+}
+
+bool ScrollView::platformHasHorizontalAdjustment() const
+{
+ return false;
+}
+
+bool ScrollView::platformHasVerticalAdjustment() const
+{
+ return false;
+}
+
+#endif
+
+}
+