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
createForPlugin(Orientation orientation,WebPluginContainer * pluginContainer,WebPluginScrollbarClient * client)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
defaultThickness()56 int WebPluginScrollbar::defaultThickness()
57 {
58 return ScrollbarTheme::theme()->scrollbarThickness();
59 }
60
WebPluginScrollbarImpl(Orientation orientation,ScrollbarGroup * group,WebPluginScrollbarClient * client)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
~WebPluginScrollbarImpl()75 WebPluginScrollbarImpl::~WebPluginScrollbarImpl()
76 {
77 m_group->scrollbarDestroyed(this);
78 }
79
setScrollOffset(int scrollOffset)80 void WebPluginScrollbarImpl::setScrollOffset(int scrollOffset)
81 {
82 m_scrollOffset = scrollOffset;
83 m_client->valueChanged(this);
84 }
85
invalidateScrollbarRect(const IntRect & rect)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
getTickmarks(Vector<IntRect> & tickmarks) const94 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
convertFromContainingViewToScrollbar(const IntPoint & parentPoint) const103 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
scrollbarStyleChanged()109 void WebPluginScrollbarImpl::scrollbarStyleChanged()
110 {
111 m_client->overlayChanged(this);
112 }
113
isOverlay() const114 bool WebPluginScrollbarImpl::isOverlay() const
115 {
116 return m_scrollbar->isOverlayScrollbar();
117 }
118
value() const119 int WebPluginScrollbarImpl::value() const
120 {
121 return m_scrollOffset;
122 }
123
location() const124 WebPoint WebPluginScrollbarImpl::location() const
125 {
126 return m_scrollbar->frameRect().location();
127 }
128
size() const129 WebSize WebPluginScrollbarImpl::size() const
130 {
131 return m_scrollbar->frameRect().size();
132 }
133
enabled() const134 bool WebPluginScrollbarImpl::enabled() const
135 {
136 return m_scrollbar->enabled();
137 }
138
maximum() const139 int WebPluginScrollbarImpl::maximum() const
140 {
141 return m_scrollbar->maximum();
142 }
143
totalSize() const144 int WebPluginScrollbarImpl::totalSize() const
145 {
146 return m_scrollbar->totalSize();
147 }
148
isScrollViewScrollbar() const149 bool WebPluginScrollbarImpl::isScrollViewScrollbar() const
150 {
151 return m_scrollbar->isScrollViewScrollbar();
152 }
153
isScrollableAreaActive() const154 bool WebPluginScrollbarImpl::isScrollableAreaActive() const
155 {
156 return m_scrollbar->isScrollableAreaActive();
157 }
158
getTickmarks(WebVector<WebRect> & tickmarks) const159 void WebPluginScrollbarImpl::getTickmarks(WebVector<WebRect>& tickmarks) const
160 {
161 m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &tickmarks);
162 }
163
controlSize() const164 WebScrollbar::ScrollbarControlSize WebPluginScrollbarImpl::controlSize() const
165 {
166 return static_cast<WebScrollbar::ScrollbarControlSize>(m_scrollbar->controlSize());
167 }
168
pressedPart() const169 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::pressedPart() const
170 {
171 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->pressedPart());
172 }
173
hoveredPart() const174 WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::hoveredPart() const
175 {
176 return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->hoveredPart());
177 }
178
scrollbarOverlayStyle() const179 WebScrollbar::ScrollbarOverlayStyle WebPluginScrollbarImpl::scrollbarOverlayStyle() const
180 {
181 return static_cast<WebScrollbar::ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle());
182 }
183
orientation() const184 WebScrollbar::Orientation WebPluginScrollbarImpl::orientation() const
185 {
186 if (m_scrollbar->orientation() == WebCore::HorizontalScrollbar)
187 return WebScrollbar::Horizontal;
188 return WebScrollbar::Vertical;
189 }
190
isLeftSideVerticalScrollbar() const191 bool WebPluginScrollbarImpl::isLeftSideVerticalScrollbar() const
192 {
193 return false;
194 }
195
isCustomScrollbar() const196 bool WebPluginScrollbarImpl::isCustomScrollbar() const
197 {
198 return m_scrollbar->isCustomScrollbar();
199 }
200
setLocation(const WebRect & rect)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
setValue(int position)213 void WebPluginScrollbarImpl::setValue(int position)
214 {
215 m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position));
216 }
217
setDocumentSize(int size)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
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)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
paint(WebCanvas * canvas,const WebRect & rect)237 void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect)
238 {
239 GraphicsContext context(canvas);
240 m_scrollbar->paint(&context, rect);
241 }
242
handleInputEvent(const WebInputEvent & event)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
isAlphaLocked() const273 bool WebPluginScrollbarImpl::isAlphaLocked() const
274 {
275 return m_scrollbar->isAlphaLocked();
276 }
277
setIsAlphaLocked(bool flag)278 void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag)
279 {
280 return m_scrollbar->setIsAlphaLocked(flag);
281 }
282
onMouseDown(const WebInputEvent & event)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
onMouseUp(const WebInputEvent & event)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
onMouseMove(const WebInputEvent & event)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
onMouseLeave(const WebInputEvent & event)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
onMouseWheel(const WebInputEvent & event)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
onKeyDown(const WebInputEvent & event)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