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 44 using namespace WebCore; 45 46 namespace blink { 47 48 WebPluginScrollbar* 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 56 int WebPluginScrollbar::defaultThickness() 57 { 58 return ScrollbarTheme::theme()->scrollbarThickness(); 59 } 60 61 WebPluginScrollbarImpl::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 75 WebPluginScrollbarImpl::~WebPluginScrollbarImpl() 76 { 77 m_group->scrollbarDestroyed(this); 78 } 79 80 void WebPluginScrollbarImpl::setScrollOffset(int scrollOffset) 81 { 82 m_scrollOffset = scrollOffset; 83 m_client->valueChanged(this); 84 } 85 86 void 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 94 void 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 103 IntPoint 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 109 void WebPluginScrollbarImpl::scrollbarStyleChanged() 110 { 111 m_client->overlayChanged(this); 112 } 113 114 bool WebPluginScrollbarImpl::isOverlay() const 115 { 116 return m_scrollbar->isOverlayScrollbar(); 117 } 118 119 int WebPluginScrollbarImpl::value() const 120 { 121 return m_scrollOffset; 122 } 123 124 WebPoint WebPluginScrollbarImpl::location() const 125 { 126 return m_scrollbar->frameRect().location(); 127 } 128 129 WebSize WebPluginScrollbarImpl::size() const 130 { 131 return m_scrollbar->frameRect().size(); 132 } 133 134 bool WebPluginScrollbarImpl::enabled() const 135 { 136 return m_scrollbar->enabled(); 137 } 138 139 int WebPluginScrollbarImpl::maximum() const 140 { 141 return m_scrollbar->maximum(); 142 } 143 144 int WebPluginScrollbarImpl::totalSize() const 145 { 146 return m_scrollbar->totalSize(); 147 } 148 149 bool WebPluginScrollbarImpl::isScrollViewScrollbar() const 150 { 151 return m_scrollbar->isScrollViewScrollbar(); 152 } 153 154 bool WebPluginScrollbarImpl::isScrollableAreaActive() const 155 { 156 return m_scrollbar->isScrollableAreaActive(); 157 } 158 159 void WebPluginScrollbarImpl::getTickmarks(WebVector<WebRect>& tickmarks) const 160 { 161 m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &tickmarks); 162 } 163 164 WebScrollbar::ScrollbarControlSize WebPluginScrollbarImpl::controlSize() const 165 { 166 return static_cast<WebScrollbar::ScrollbarControlSize>(m_scrollbar->controlSize()); 167 } 168 169 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::pressedPart() const 170 { 171 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->pressedPart()); 172 } 173 174 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::hoveredPart() const 175 { 176 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->hoveredPart()); 177 } 178 179 WebScrollbar::ScrollbarOverlayStyle WebPluginScrollbarImpl::scrollbarOverlayStyle() const 180 { 181 return static_cast<WebScrollbar::ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle()); 182 } 183 184 WebScrollbar::Orientation WebPluginScrollbarImpl::orientation() const 185 { 186 if (m_scrollbar->orientation() == WebCore::HorizontalScrollbar) 187 return WebScrollbar::Horizontal; 188 return WebScrollbar::Vertical; 189 } 190 191 bool WebPluginScrollbarImpl::isLeftSideVerticalScrollbar() const 192 { 193 return false; 194 } 195 196 bool WebPluginScrollbarImpl::isCustomScrollbar() const 197 { 198 return m_scrollbar->isCustomScrollbar(); 199 } 200 201 void 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 213 void WebPluginScrollbarImpl::setValue(int position) 214 { 215 m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position)); 216 } 217 218 void 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 225 void 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 237 void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect) 238 { 239 GraphicsContext context(canvas); 240 m_scrollbar->paint(&context, rect); 241 } 242 243 bool 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 273 bool WebPluginScrollbarImpl::isAlphaLocked() const 274 { 275 return m_scrollbar->isAlphaLocked(); 276 } 277 278 void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag) 279 { 280 return m_scrollbar->setIsAlphaLocked(flag); 281 } 282 283 bool 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 295 bool 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 305 bool 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 321 bool WebPluginScrollbarImpl::onMouseLeave(const WebInputEvent& event) 322 { 323 if (m_scrollbar->hoveredPart() != WebCore::NoPart) 324 m_scrollbar->mouseExited(); 325 326 return false; 327 } 328 329 bool 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 336 bool 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