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 "core/platform/ScrollAnimator.h" 35 #include "core/platform/ScrollTypes.h" 36 #include "core/platform/Scrollbar.h" 37 #include "core/platform/ScrollbarTheme.h" 38 #include "core/platform/chromium/KeyboardCodes.h" 39 #include "core/platform/graphics/GraphicsContext.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 WebKit { 48 49 WebPluginScrollbar* WebPluginScrollbar::createForPlugin(Orientation orientation, 50 WebPluginContainer* pluginContainer, 51 WebPluginScrollbarClient* client) 52 { 53 WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(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::createNativeScrollbar( 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::isCustomScrollbar() const 193 { 194 return m_scrollbar->isCustomScrollbar(); 195 } 196 197 void WebPluginScrollbarImpl::setLocation(const WebRect& rect) 198 { 199 IntRect oldRect = m_scrollbar->frameRect(); 200 m_scrollbar->setFrameRect(rect); 201 if (WebRect(oldRect) != rect) 202 m_scrollbar->invalidate(); 203 204 int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height(); 205 m_scrollbar->setEnabled(m_scrollbar->totalSize() > length); 206 m_scrollbar->setProportion(length, m_scrollbar->totalSize()); 207 } 208 209 void WebPluginScrollbarImpl::setValue(int position) 210 { 211 m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position)); 212 } 213 214 void WebPluginScrollbarImpl::setDocumentSize(int size) 215 { 216 int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height(); 217 m_scrollbar->setEnabled(size > length); 218 m_scrollbar->setProportion(length, size); 219 } 220 221 void WebPluginScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) 222 { 223 WebCore::ScrollDirection dir; 224 bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar; 225 if (direction == ScrollForward) 226 dir = horizontal ? ScrollRight : ScrollDown; 227 else 228 dir = horizontal ? ScrollLeft : ScrollUp; 229 230 m_group->scroll(dir, static_cast<WebCore::ScrollGranularity>(granularity), multiplier); 231 } 232 233 void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect) 234 { 235 GraphicsContext context(canvas); 236 m_scrollbar->paint(&context, rect); 237 } 238 239 bool WebPluginScrollbarImpl::handleInputEvent(const WebInputEvent& event) 240 { 241 switch (event.type) { 242 case WebInputEvent::MouseDown: 243 return onMouseDown(event); 244 case WebInputEvent::MouseUp: 245 return onMouseUp(event); 246 case WebInputEvent::MouseMove: 247 return onMouseMove(event); 248 case WebInputEvent::MouseLeave: 249 return onMouseLeave(event); 250 case WebInputEvent::MouseWheel: 251 return onMouseWheel(event); 252 case WebInputEvent::KeyDown: 253 return onKeyDown(event); 254 case WebInputEvent::Undefined: 255 case WebInputEvent::MouseEnter: 256 case WebInputEvent::RawKeyDown: 257 case WebInputEvent::KeyUp: 258 case WebInputEvent::Char: 259 case WebInputEvent::TouchStart: 260 case WebInputEvent::TouchMove: 261 case WebInputEvent::TouchEnd: 262 case WebInputEvent::TouchCancel: 263 default: 264 break; 265 } 266 return false; 267 } 268 269 bool WebPluginScrollbarImpl::isAlphaLocked() const 270 { 271 return m_scrollbar->isAlphaLocked(); 272 } 273 274 void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag) 275 { 276 return m_scrollbar->setIsAlphaLocked(flag); 277 } 278 279 bool WebPluginScrollbarImpl::onMouseDown(const WebInputEvent& event) 280 { 281 WebMouseEvent mousedown = *static_cast<const WebMouseEvent*>(&event); 282 if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y)) 283 return false; 284 285 mousedown.x -= m_scrollbar->x(); 286 mousedown.y -= m_scrollbar->y(); 287 m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown)); 288 return true; 289 } 290 291 bool WebPluginScrollbarImpl::onMouseUp(const WebInputEvent& event) 292 { 293 WebMouseEvent mouseup = *static_cast<const WebMouseEvent*>(&event); 294 if (m_scrollbar->pressedPart() == WebCore::NoPart) 295 return false; 296 297 m_scrollbar->mouseUp(PlatformMouseEventBuilder(m_scrollbar.get(), mouseup)); 298 return true; 299 } 300 301 bool WebPluginScrollbarImpl::onMouseMove(const WebInputEvent& event) 302 { 303 WebMouseEvent mousemove = *static_cast<const WebMouseEvent*>(&event); 304 if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y) 305 || m_scrollbar->pressedPart() != WebCore::NoPart) { 306 mousemove.x -= m_scrollbar->x(); 307 mousemove.y -= m_scrollbar->y(); 308 m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove)); 309 return true; 310 } 311 312 if (m_scrollbar->hoveredPart() != WebCore::NoPart && !m_scrollbar->isOverlayScrollbar()) 313 m_scrollbar->mouseExited(); 314 return false; 315 } 316 317 bool WebPluginScrollbarImpl::onMouseLeave(const WebInputEvent& event) 318 { 319 if (m_scrollbar->hoveredPart() != WebCore::NoPart) 320 m_scrollbar->mouseExited(); 321 322 return false; 323 } 324 325 bool WebPluginScrollbarImpl::onMouseWheel(const WebInputEvent& event) 326 { 327 WebMouseWheelEvent mousewheel = *static_cast<const WebMouseWheelEvent*>(&event); 328 PlatformWheelEventBuilder platformEvent(m_scrollbar.get(), mousewheel); 329 return m_group->handleWheelEvent(platformEvent); 330 } 331 332 bool WebPluginScrollbarImpl::onKeyDown(const WebInputEvent& event) 333 { 334 WebKeyboardEvent keyboard = *static_cast<const WebKeyboardEvent*>(&event); 335 int keyCode; 336 // We have to duplicate this logic from WebViewImpl because there it uses 337 // Char and RawKeyDown events, which don't exist at this point. 338 if (keyboard.windowsKeyCode == VKEY_SPACE) 339 keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); 340 else { 341 if (keyboard.modifiers == WebInputEvent::ControlKey) { 342 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl 343 // key combinations which affect scrolling. Safari is buggy in the 344 // sense that it scrolls the page for all Ctrl+scrolling key 345 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. 346 switch (keyboard.windowsKeyCode) { 347 case VKEY_HOME: 348 case VKEY_END: 349 break; 350 default: 351 return false; 352 } 353 } 354 355 if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey)) 356 return false; 357 358 keyCode = keyboard.windowsKeyCode; 359 } 360 WebCore::ScrollDirection scrollDirection; 361 WebCore::ScrollGranularity scrollGranularity; 362 if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) { 363 // Will return false if scroll direction wasn't compatible with this scrollbar. 364 return m_group->scroll(scrollDirection, scrollGranularity); 365 } 366 return false; 367 } 368 369 } // namespace WebKit 370