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