1 /* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 #include "ScrollableArea.h" 34 35 #include "GraphicsContext.h" 36 #include "GraphicsLayer.h" 37 #include "FloatPoint.h" 38 #include "PlatformWheelEvent.h" 39 #include "ScrollAnimator.h" 40 #include "ScrollbarTheme.h" 41 #include <wtf/PassOwnPtr.h> 42 43 namespace WebCore { 44 45 ScrollableArea::ScrollableArea() 46 : m_scrollAnimator(ScrollAnimator::create(this)) 47 , m_constrainsScrollingToContentEdge(true) 48 , m_inLiveResize(false) 49 , m_verticalScrollElasticity(ScrollElasticityNone) 50 , m_horizontalScrollElasticity(ScrollElasticityNone) 51 { 52 } 53 54 ScrollableArea::~ScrollableArea() 55 { 56 } 57 58 bool ScrollableArea::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) 59 { 60 ScrollbarOrientation orientation; 61 Scrollbar* scrollbar; 62 if (direction == ScrollUp || direction == ScrollDown) { 63 orientation = VerticalScrollbar; 64 scrollbar = verticalScrollbar(); 65 } else { 66 orientation = HorizontalScrollbar; 67 scrollbar = horizontalScrollbar(); 68 } 69 70 if (!scrollbar) 71 return false; 72 73 float step = 0; 74 switch (granularity) { 75 case ScrollByLine: 76 step = scrollbar->lineStep(); 77 break; 78 case ScrollByPage: 79 step = scrollbar->pageStep(); 80 break; 81 case ScrollByDocument: 82 step = scrollbar->totalSize(); 83 break; 84 case ScrollByPixel: 85 step = scrollbar->pixelStep(); 86 break; 87 } 88 89 if (direction == ScrollUp || direction == ScrollLeft) 90 multiplier = -multiplier; 91 92 return m_scrollAnimator->scroll(orientation, granularity, step, multiplier); 93 } 94 95 void ScrollableArea::scrollToOffsetWithoutAnimation(const FloatPoint& offset) 96 { 97 m_scrollAnimator->scrollToOffsetWithoutAnimation(offset); 98 } 99 100 void ScrollableArea::scrollToOffsetWithoutAnimation(ScrollbarOrientation orientation, float offset) 101 { 102 if (orientation == HorizontalScrollbar) 103 scrollToXOffsetWithoutAnimation(offset); 104 else 105 scrollToYOffsetWithoutAnimation(offset); 106 } 107 108 void ScrollableArea::scrollToXOffsetWithoutAnimation(float x) 109 { 110 scrollToOffsetWithoutAnimation(FloatPoint(x, m_scrollAnimator->currentPosition().y())); 111 } 112 113 void ScrollableArea::scrollToYOffsetWithoutAnimation(float y) 114 { 115 scrollToOffsetWithoutAnimation(FloatPoint(m_scrollAnimator->currentPosition().x(), y)); 116 } 117 118 void ScrollableArea::handleWheelEvent(PlatformWheelEvent& wheelEvent) 119 { 120 m_scrollAnimator->handleWheelEvent(wheelEvent); 121 } 122 123 #if ENABLE(GESTURE_EVENTS) 124 void ScrollableArea::handleGestureEvent(const PlatformGestureEvent& gestureEvent) 125 { 126 m_scrollAnimator->handleGestureEvent(gestureEvent); 127 } 128 #endif 129 130 void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset) 131 { 132 // Tell the derived class to scroll its contents. 133 setScrollOffset(offset); 134 135 Scrollbar* verticalScrollbar = this->verticalScrollbar(); 136 137 // Tell the scrollbars to update their thumb postions. 138 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { 139 horizontalScrollbar->offsetDidChange(); 140 if (horizontalScrollbar->isOverlayScrollbar()) { 141 if (!verticalScrollbar) 142 horizontalScrollbar->invalidate(); 143 else { 144 // If there is both a horizontalScrollbar and a verticalScrollbar, 145 // then we must also invalidate the corner between them. 146 IntRect boundsAndCorner = horizontalScrollbar->boundsRect(); 147 boundsAndCorner.setWidth(boundsAndCorner.width() + verticalScrollbar->width()); 148 horizontalScrollbar->invalidateRect(boundsAndCorner); 149 } 150 } 151 } 152 if (verticalScrollbar) { 153 verticalScrollbar->offsetDidChange(); 154 if (verticalScrollbar->isOverlayScrollbar()) 155 verticalScrollbar->invalidate(); 156 } 157 } 158 159 void ScrollableArea::willStartLiveResize() 160 { 161 if (m_inLiveResize) 162 return; 163 m_inLiveResize = true; 164 scrollAnimator()->willStartLiveResize(); 165 } 166 167 void ScrollableArea::willEndLiveResize() 168 { 169 if (!m_inLiveResize) 170 return; 171 m_inLiveResize = false; 172 scrollAnimator()->willEndLiveResize(); 173 } 174 175 void ScrollableArea::didAddVerticalScrollbar(Scrollbar* scrollbar) 176 { 177 scrollAnimator()->didAddVerticalScrollbar(scrollbar); 178 } 179 180 void ScrollableArea::willRemoveVerticalScrollbar(Scrollbar* scrollbar) 181 { 182 scrollAnimator()->willRemoveVerticalScrollbar(scrollbar); 183 } 184 185 void ScrollableArea::didAddHorizontalScrollbar(Scrollbar* scrollbar) 186 { 187 scrollAnimator()->didAddHorizontalScrollbar(scrollbar); 188 } 189 190 void ScrollableArea::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) 191 { 192 scrollAnimator()->willRemoveHorizontalScrollbar(scrollbar); 193 } 194 195 bool ScrollableArea::hasOverlayScrollbars() const 196 { 197 return (verticalScrollbar() && verticalScrollbar()->isOverlayScrollbar()) 198 || (horizontalScrollbar() && horizontalScrollbar()->isOverlayScrollbar()); 199 } 200 201 void ScrollableArea::invalidateScrollbar(Scrollbar* scrollbar, const IntRect& rect) 202 { 203 #if USE(ACCELERATED_COMPOSITING) 204 if (scrollbar == horizontalScrollbar()) { 205 if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) { 206 graphicsLayer->setNeedsDisplay(); 207 return; 208 } 209 } else if (scrollbar == verticalScrollbar()) { 210 if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) { 211 graphicsLayer->setNeedsDisplay(); 212 return; 213 } 214 } 215 #endif 216 invalidateScrollbarRect(scrollbar, rect); 217 } 218 219 void ScrollableArea::invalidateScrollCorner() 220 { 221 #if USE(ACCELERATED_COMPOSITING) 222 if (GraphicsLayer* graphicsLayer = layerForScrollCorner()) { 223 graphicsLayer->setNeedsDisplay(); 224 return; 225 } 226 #endif 227 invalidateScrollCornerRect(scrollCornerRect()); 228 } 229 230 } // namespace WebCore 231