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 "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