Home | History | Annotate | Download | only in web
      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