1/* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "ScrollAnimator.h" 33 34#include "FloatPoint.h" 35#include "PlatformWheelEvent.h" 36#include "ScrollableArea.h" 37#include <algorithm> 38#include <wtf/PassOwnPtr.h> 39 40using namespace std; 41 42namespace WebCore { 43 44#if !ENABLE(SMOOTH_SCROLLING) 45PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea) 46{ 47 return adoptPtr(new ScrollAnimator(scrollableArea)); 48} 49#endif 50 51ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea) 52 : m_scrollableArea(scrollableArea) 53 , m_currentPosX(0) 54 , m_currentPosY(0) 55{ 56} 57 58ScrollAnimator::~ScrollAnimator() 59{ 60} 61 62bool ScrollAnimator::scroll(ScrollbarOrientation orientation, ScrollGranularity, float step, float multiplier) 63{ 64 float* currentPos = (orientation == HorizontalScrollbar) ? &m_currentPosX : &m_currentPosY; 65 float newPos = std::max(std::min(*currentPos + (step * multiplier), static_cast<float>(m_scrollableArea->scrollSize(orientation))), 0.0f); 66 float delta = *currentPos - newPos; 67 if (*currentPos == newPos) 68 return false; 69 *currentPos = newPos; 70 71 notifyPositionChanged(orientation == HorizontalScrollbar ? FloatSize(delta, 0) : FloatSize(0, delta)); 72 73 return true; 74} 75 76void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset) 77{ 78 FloatSize delta = FloatSize(offset.x() - m_currentPosX, offset.y() - m_currentPosY); 79 m_currentPosX = offset.x(); 80 m_currentPosY = offset.y(); 81 notifyPositionChanged(delta); 82} 83 84bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e) 85{ 86 Scrollbar* horizontalScrollbar = m_scrollableArea->horizontalScrollbar(); 87 Scrollbar* verticalScrollbar = m_scrollableArea->verticalScrollbar(); 88 89 // Accept the event if we have a scrollbar in that direction and can still 90 // scroll any further. 91 float deltaX = horizontalScrollbar ? e.deltaX() : 0; 92 float deltaY = verticalScrollbar ? e.deltaY() : 0; 93 94 bool handled = false; 95 96 ScrollGranularity granularity = ScrollByPixel; 97 IntSize maxForwardScrollDelta = m_scrollableArea->maximumScrollPosition() - m_scrollableArea->scrollPosition(); 98 IntSize maxBackwardScrollDelta = m_scrollableArea->scrollPosition() - m_scrollableArea->minimumScrollPosition(); 99 if ((deltaX < 0 && maxForwardScrollDelta.width() > 0) 100 || (deltaX > 0 && maxBackwardScrollDelta.width() > 0) 101 || (deltaY < 0 && maxForwardScrollDelta.height() > 0) 102 || (deltaY > 0 && maxBackwardScrollDelta.height() > 0)) { 103 handled = true; 104 105 if (deltaY) { 106 if (e.granularity() == ScrollByPageWheelEvent) { 107 bool negative = deltaY < 0; 108 deltaY = max(max(static_cast<float>(m_scrollableArea->visibleHeight()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(m_scrollableArea->visibleHeight() - Scrollbar::maxOverlapBetweenPages())), 1.0f); 109 if (negative) 110 deltaY = -deltaY; 111 } 112 scroll(VerticalScrollbar, granularity, verticalScrollbar->pixelStep(), -deltaY); 113 } 114 115 if (deltaX) { 116 if (e.granularity() == ScrollByPageWheelEvent) { 117 bool negative = deltaX < 0; 118 deltaX = max(max(static_cast<float>(m_scrollableArea->visibleWidth()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(m_scrollableArea->visibleWidth() - Scrollbar::maxOverlapBetweenPages())), 1.0f); 119 if (negative) 120 deltaX = -deltaX; 121 } 122 scroll(HorizontalScrollbar, granularity, horizontalScrollbar->pixelStep(), -deltaX); 123 } 124 } 125 return handled; 126} 127 128void ScrollAnimator::setCurrentPosition(const FloatPoint& position) 129{ 130 m_currentPosX = position.x(); 131 m_currentPosY = position.y(); 132} 133 134FloatPoint ScrollAnimator::currentPosition() const 135{ 136 return FloatPoint(m_currentPosX, m_currentPosY); 137} 138 139void ScrollAnimator::notifyPositionChanged(const FloatSize& delta) 140{ 141 UNUSED_PARAM(delta); 142 m_scrollableArea->setScrollOffsetFromAnimation(IntPoint(m_currentPosX, m_currentPosY)); 143} 144 145} // namespace WebCore 146