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