1 /* 2 * Copyright (C) 2012 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 6 * are met: 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. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 #include "WebPluginScrollbarImpl.h" 27 28 #include "ScrollbarGroup.h" 29 #include "WebInputEvent.h" 30 #include "WebInputEventConversion.h" 31 #include "WebPluginContainerImpl.h" 32 #include "WebPluginScrollbarClient.h" 33 #include "WebViewImpl.h" 34 #include "platform/KeyboardCodes.h" 35 #include "platform/scroll/ScrollAnimator.h" 36 #include "platform/scroll/Scrollbar.h" 37 #include "platform/scroll/ScrollbarTheme.h" 38 #include "platform/graphics/GraphicsContext.h" 39 #include "platform/scroll/ScrollTypes.h" 40 #include "public/platform/WebCanvas.h" 41 #include "public/platform/WebRect.h" 42 #include "public/platform/WebVector.h" 43 44 using namespace std; 45 using namespace WebCore; 46 47 namespace blink { 48 49 WebPluginScrollbar* WebPluginScrollbar::createForPlugin(Orientation orientation, 50 WebPluginContainer* pluginContainer, 51 WebPluginScrollbarClient* client) 52 { 53 WebPluginContainerImpl* plugin = toPluginContainerImpl(pluginContainer); 54 return new WebPluginScrollbarImpl(orientation, plugin->scrollbarGroup(), client); 55 } 56 57 int WebPluginScrollbar::defaultThickness() 58 { 59 return ScrollbarTheme::theme()->scrollbarThickness(); 60 } 61 62 WebPluginScrollbarImpl::WebPluginScrollbarImpl(Orientation orientation, 63 ScrollbarGroup* group, 64 WebPluginScrollbarClient* client) 65 : m_group(group) 66 , m_client(client) 67 , m_scrollOffset(0) 68 { 69 m_scrollbar = Scrollbar::create( 70 static_cast<ScrollableArea*>(m_group), 71 static_cast<WebCore::ScrollbarOrientation>(orientation), 72 WebCore::RegularScrollbar); 73 m_group->scrollbarCreated(this); 74 } 75 76 WebPluginScrollbarImpl::~WebPluginScrollbarImpl() 77 { 78 m_group->scrollbarDestroyed(this); 79 } 80 81 void WebPluginScrollbarImpl::setScrollOffset(int scrollOffset) 82 { 83 m_scrollOffset = scrollOffset; 84 m_client->valueChanged(this); 85 } 86 87 void WebPluginScrollbarImpl::invalidateScrollbarRect(const IntRect& rect) 88 { 89 WebRect webrect(rect); 90 webrect.x += m_scrollbar->x(); 91 webrect.y += m_scrollbar->y(); 92 m_client->invalidateScrollbarRect(this, webrect); 93 } 94 95 void WebPluginScrollbarImpl::getTickmarks(Vector<IntRect>& tickmarks) const 96 { 97 WebVector<WebRect> ticks; 98 m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &ticks); 99 tickmarks.resize(ticks.size()); 100 for (size_t i = 0; i < ticks.size(); ++i) 101 tickmarks[i] = ticks[i]; 102 } 103 104 IntPoint WebPluginScrollbarImpl::convertFromContainingViewToScrollbar(const IntPoint& parentPoint) const 105 { 106 IntPoint offset(parentPoint.x() - m_scrollbar->x(), parentPoint.y() - m_scrollbar->y()); 107 return m_scrollbar->Widget::convertFromContainingView(offset); 108 } 109 110 void WebPluginScrollbarImpl::scrollbarStyleChanged() 111 { 112 m_client->overlayChanged(this); 113 } 114 115 bool WebPluginScrollbarImpl::isOverlay() const 116 { 117 return m_scrollbar->isOverlayScrollbar(); 118 } 119 120 int WebPluginScrollbarImpl::value() const 121 { 122 return m_scrollOffset; 123 } 124 125 WebPoint WebPluginScrollbarImpl::location() const 126 { 127 return m_scrollbar->frameRect().location(); 128 } 129 130 WebSize WebPluginScrollbarImpl::size() const 131 { 132 return m_scrollbar->frameRect().size(); 133 } 134 135 bool WebPluginScrollbarImpl::enabled() const 136 { 137 return m_scrollbar->enabled(); 138 } 139 140 int WebPluginScrollbarImpl::maximum() const 141 { 142 return m_scrollbar->maximum(); 143 } 144 145 int WebPluginScrollbarImpl::totalSize() const 146 { 147 return m_scrollbar->totalSize(); 148 } 149 150 bool WebPluginScrollbarImpl::isScrollViewScrollbar() const 151 { 152 return m_scrollbar->isScrollViewScrollbar(); 153 } 154 155 bool WebPluginScrollbarImpl::isScrollableAreaActive() const 156 { 157 return m_scrollbar->isScrollableAreaActive(); 158 } 159 160 void WebPluginScrollbarImpl::getTickmarks(WebVector<WebRect>& tickmarks) const 161 { 162 m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &tickmarks); 163 } 164 165 WebScrollbar::ScrollbarControlSize WebPluginScrollbarImpl::controlSize() const 166 { 167 return static_cast<WebScrollbar::ScrollbarControlSize>(m_scrollbar->controlSize()); 168 } 169 170 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::pressedPart() const 171 { 172 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->pressedPart()); 173 } 174 175 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::hoveredPart() const 176 { 177 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->hoveredPart()); 178 } 179 180 WebScrollbar::ScrollbarOverlayStyle WebPluginScrollbarImpl::scrollbarOverlayStyle() const 181 { 182 return static_cast<WebScrollbar::ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle()); 183 } 184 185 WebScrollbar::Orientation WebPluginScrollbarImpl::orientation() const 186 { 187 if (m_scrollbar->orientation() == WebCore::HorizontalScrollbar) 188 return WebScrollbar::Horizontal; 189 return WebScrollbar::Vertical; 190 } 191 192 bool WebPluginScrollbarImpl::isLeftSideVerticalScrollbar() const 193 { 194 return false; 195 } 196 197 bool WebPluginScrollbarImpl::isCustomScrollbar() const 198 { 199 return m_scrollbar->isCustomScrollbar(); 200 } 201 202 void WebPluginScrollbarImpl::setLocation(const WebRect& rect) 203 { 204 IntRect oldRect = m_scrollbar->frameRect(); 205 m_scrollbar->setFrameRect(rect); 206 if (WebRect(oldRect) != rect) 207 m_scrollbar->invalidate(); 208 209 int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height(); 210 m_scrollbar->setEnabled(m_scrollbar->totalSize() > length); 211 m_scrollbar->setProportion(length, m_scrollbar->totalSize()); 212 } 213 214 void WebPluginScrollbarImpl::setValue(int position) 215 { 216 m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position)); 217 } 218 219 void WebPluginScrollbarImpl::setDocumentSize(int size) 220 { 221 int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height(); 222 m_scrollbar->setEnabled(size > length); 223 m_scrollbar->setProportion(length, size); 224 } 225 226 void WebPluginScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) 227 { 228 WebCore::ScrollDirection dir; 229 bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar; 230 if (direction == ScrollForward) 231 dir = horizontal ? ScrollRight : ScrollDown; 232 else 233 dir = horizontal ? ScrollLeft : ScrollUp; 234 235 m_group->scroll(dir, static_cast<WebCore::ScrollGranularity>(granularity), multiplier); 236 } 237 238 void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect) 239 { 240 GraphicsContext context(canvas); 241 m_scrollbar->paint(&context, rect); 242 } 243 244 bool WebPluginScrollbarImpl::handleInputEvent(const WebInputEvent& event) 245 { 246 switch (event.type) { 247 case WebInputEvent::MouseDown: 248 return onMouseDown(event); 249 case WebInputEvent::MouseUp: 250 return onMouseUp(event); 251 case WebInputEvent::MouseMove: 252 return onMouseMove(event); 253 case WebInputEvent::MouseLeave: 254 return onMouseLeave(event); 255 case WebInputEvent::MouseWheel: 256 return onMouseWheel(event); 257 case WebInputEvent::KeyDown: 258 return onKeyDown(event); 259 case WebInputEvent::Undefined: 260 case WebInputEvent::MouseEnter: 261 case WebInputEvent::RawKeyDown: 262 case WebInputEvent::KeyUp: 263 case WebInputEvent::Char: 264 case WebInputEvent::TouchStart: 265 case WebInputEvent::TouchMove: 266 case WebInputEvent::TouchEnd: 267 case WebInputEvent::TouchCancel: 268 default: 269 break; 270 } 271 return false; 272 } 273 274 bool WebPluginScrollbarImpl::isAlphaLocked() const 275 { 276 return m_scrollbar->isAlphaLocked(); 277 } 278 279 void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag) 280 { 281 return m_scrollbar->setIsAlphaLocked(flag); 282 } 283 284 bool WebPluginScrollbarImpl::onMouseDown(const WebInputEvent& event) 285 { 286 WebMouseEvent mousedown = *static_cast<const WebMouseEvent*>(&event); 287 if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y)) 288 return false; 289 290 mousedown.x -= m_scrollbar->x(); 291 mousedown.y -= m_scrollbar->y(); 292 m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown)); 293 return true; 294 } 295 296 bool WebPluginScrollbarImpl::onMouseUp(const WebInputEvent& event) 297 { 298 WebMouseEvent mouseup = *static_cast<const WebMouseEvent*>(&event); 299 if (m_scrollbar->pressedPart() == WebCore::NoPart) 300 return false; 301 302 m_scrollbar->mouseUp(PlatformMouseEventBuilder(m_scrollbar.get(), mouseup)); 303 return true; 304 } 305 306 bool WebPluginScrollbarImpl::onMouseMove(const WebInputEvent& event) 307 { 308 WebMouseEvent mousemove = *static_cast<const WebMouseEvent*>(&event); 309 if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y) 310 || m_scrollbar->pressedPart() != WebCore::NoPart) { 311 mousemove.x -= m_scrollbar->x(); 312 mousemove.y -= m_scrollbar->y(); 313 m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove)); 314 return true; 315 } 316 317 if (m_scrollbar->hoveredPart() != WebCore::NoPart && !m_scrollbar->isOverlayScrollbar()) 318 m_scrollbar->mouseExited(); 319 return false; 320 } 321 322 bool WebPluginScrollbarImpl::onMouseLeave(const WebInputEvent& event) 323 { 324 if (m_scrollbar->hoveredPart() != WebCore::NoPart) 325 m_scrollbar->mouseExited(); 326 327 return false; 328 } 329 330 bool WebPluginScrollbarImpl::onMouseWheel(const WebInputEvent& event) 331 { 332 WebMouseWheelEvent mousewheel = *static_cast<const WebMouseWheelEvent*>(&event); 333 PlatformWheelEventBuilder platformEvent(m_scrollbar.get(), mousewheel); 334 return m_group->handleWheelEvent(platformEvent); 335 } 336 337 bool WebPluginScrollbarImpl::onKeyDown(const WebInputEvent& event) 338 { 339 WebKeyboardEvent keyboard = *static_cast<const WebKeyboardEvent*>(&event); 340 int keyCode; 341 // We have to duplicate this logic from WebViewImpl because there it uses 342 // Char and RawKeyDown events, which don't exist at this point. 343 if (keyboard.windowsKeyCode == VKEY_SPACE) 344 keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); 345 else { 346 if (keyboard.modifiers == WebInputEvent::ControlKey) { 347 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl 348 // key combinations which affect scrolling. Safari is buggy in the 349 // sense that it scrolls the page for all Ctrl+scrolling key 350 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. 351 switch (keyboard.windowsKeyCode) { 352 case VKEY_HOME: 353 case VKEY_END: 354 break; 355 default: 356 return false; 357 } 358 } 359 360 if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey)) 361 return false; 362 363 keyCode = keyboard.windowsKeyCode; 364 } 365 WebCore::ScrollDirection scrollDirection; 366 WebCore::ScrollGranularity scrollGranularity; 367 if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) { 368 // Will return false if scroll direction wasn't compatible with this scrollbar. 369 return m_group->scroll(scrollDirection, scrollGranularity); 370 } 371 return false; 372 } 373 374 } // namespace blink 375