Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2010 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WebScrollbarImpl.h"
     33 
     34 #include "GraphicsContext.h"
     35 #include "KeyboardCodes.h"
     36 #include "painting/GraphicsContextBuilder.h"
     37 #include "Scrollbar.h"
     38 #include "ScrollbarTheme.h"
     39 #include "ScrollTypes.h"
     40 #include "WebCanvas.h"
     41 #include "WebInputEvent.h"
     42 #include "WebInputEventConversion.h"
     43 #include "WebRect.h"
     44 #include "WebScrollbarClient.h"
     45 #include "WebVector.h"
     46 #include "WebViewImpl.h"
     47 
     48 using namespace std;
     49 using namespace WebCore;
     50 
     51 namespace WebKit {
     52 
     53 WebScrollbar* WebScrollbar::create(WebScrollbarClient* client, Orientation orientation)
     54 {
     55     return new WebScrollbarImpl(client, orientation);
     56 }
     57 
     58 int WebScrollbar::defaultThickness()
     59 {
     60     return ScrollbarTheme::nativeTheme()->scrollbarThickness();
     61 }
     62 
     63 WebScrollbarImpl::WebScrollbarImpl(WebScrollbarClient* client, Orientation orientation)
     64     : m_client(client)
     65     , m_scrollOffset(0)
     66 {
     67     m_scrollbar = Scrollbar::createNativeScrollbar(
     68         static_cast<ScrollableArea*>(this),
     69         static_cast<ScrollbarOrientation>(orientation),
     70         RegularScrollbar);
     71 }
     72 
     73 WebScrollbarImpl::~WebScrollbarImpl()
     74 {
     75 }
     76 
     77 void WebScrollbarImpl::setLocation(const WebRect& rect)
     78 {
     79     IntRect oldRect = m_scrollbar->frameRect();
     80     m_scrollbar->setFrameRect(rect);
     81     if (WebRect(oldRect) != rect)
     82       m_scrollbar->invalidate();
     83 
     84     int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
     85     int pageStep = max(max(static_cast<int>(static_cast<float>(length) * Scrollbar::minFractionToStepWhenPaging()), length - Scrollbar::maxOverlapBetweenPages()), 1);
     86     m_scrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
     87     m_scrollbar->setEnabled(m_scrollbar->totalSize() > length);
     88     m_scrollbar->setProportion(length, m_scrollbar->totalSize());
     89 }
     90 
     91 int WebScrollbarImpl::value() const
     92 {
     93     return m_scrollOffset;
     94 }
     95 
     96 void WebScrollbarImpl::setValue(int position)
     97 {
     98     ScrollableArea::scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position));
     99 }
    100 
    101 void WebScrollbarImpl::setDocumentSize(int size)
    102 {
    103     int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
    104     m_scrollbar->setEnabled(size > length);
    105     m_scrollbar->setProportion(length, size);
    106 }
    107 
    108 void WebScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
    109 {
    110     WebCore::ScrollDirection dir;
    111     bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar;
    112     if (direction == ScrollForward)
    113         dir = horizontal ? ScrollRight : ScrollDown;
    114     else
    115         dir = horizontal ? ScrollLeft : ScrollUp;
    116 
    117     WebCore::ScrollableArea::scroll(dir, static_cast<WebCore::ScrollGranularity>(granularity), multiplier);
    118 }
    119 
    120 void WebScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect)
    121 {
    122     m_scrollbar->paint(&GraphicsContextBuilder(canvas).context(), rect);
    123 }
    124 
    125 bool WebScrollbarImpl::handleInputEvent(const WebInputEvent& event)
    126 {
    127     switch (event.type) {
    128     case WebInputEvent::MouseDown:
    129         return onMouseDown(event);
    130     case WebInputEvent::MouseUp:
    131         return onMouseUp(event);
    132     case WebInputEvent::MouseMove:
    133         return onMouseMove(event);
    134     case WebInputEvent::MouseLeave:
    135         return onMouseLeave(event);
    136     case WebInputEvent::MouseWheel:
    137         return onMouseWheel(event);
    138     case WebInputEvent::KeyDown:
    139         return onKeyDown(event);
    140     case WebInputEvent::Undefined:
    141     case WebInputEvent::MouseEnter:
    142     case WebInputEvent::RawKeyDown:
    143     case WebInputEvent::KeyUp:
    144     case WebInputEvent::Char:
    145     case WebInputEvent::TouchStart:
    146     case WebInputEvent::TouchMove:
    147     case WebInputEvent::TouchEnd:
    148     case WebInputEvent::TouchCancel:
    149     default:
    150          break;
    151     }
    152     return false;
    153 }
    154 
    155 bool WebScrollbarImpl::onMouseDown(const WebInputEvent& event)
    156 {
    157     WebMouseEvent mousedown = *static_cast<const WebMouseEvent*>(&event);
    158     if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y))
    159         return false;
    160 
    161     mousedown.x -= m_scrollbar->x();
    162     mousedown.y -= m_scrollbar->y();
    163     m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown));
    164     return true;
    165 }
    166 
    167 bool WebScrollbarImpl::onMouseUp(const WebInputEvent& event)
    168 {
    169     if (m_scrollbar->pressedPart() == NoPart)
    170         return false;
    171 
    172     return m_scrollbar->mouseUp();
    173 }
    174 
    175 bool WebScrollbarImpl::onMouseMove(const WebInputEvent& event)
    176 {
    177     WebMouseEvent mousemove = *static_cast<const WebMouseEvent*>(&event);
    178     if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y)
    179         || m_scrollbar->pressedPart() != NoPart) {
    180         mousemove.x -= m_scrollbar->x();
    181         mousemove.y -= m_scrollbar->y();
    182         return m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove));
    183     }
    184 
    185     if (m_scrollbar->hoveredPart() != NoPart)
    186         m_scrollbar->mouseExited();
    187     return false;
    188 }
    189 
    190 bool WebScrollbarImpl::onMouseLeave(const WebInputEvent& event)
    191 {
    192     if (m_scrollbar->hoveredPart() == NoPart)
    193         return false;
    194 
    195     return m_scrollbar->mouseExited();
    196 }
    197 
    198 bool WebScrollbarImpl::onMouseWheel(const WebInputEvent& event)
    199 {
    200     // Same logic as in Scrollview.cpp.  If we can move at all, we'll accept the event.
    201     WebMouseWheelEvent mousewheel = *static_cast<const WebMouseWheelEvent*>(&event);
    202     int maxScrollDelta = m_scrollbar->maximum() - m_scrollbar->value();
    203     float delta = m_scrollbar->orientation() == HorizontalScrollbar ? mousewheel.deltaX : mousewheel.deltaY;
    204     if ((delta < 0 && maxScrollDelta > 0) || (delta > 0 && m_scrollbar->value() > 0)) {
    205         if (mousewheel.scrollByPage) {
    206             ASSERT(m_scrollbar->orientation() == VerticalScrollbar);
    207             bool negative = delta < 0;
    208             delta = max(max(static_cast<float>(m_scrollbar->visibleSize()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(m_scrollbar->visibleSize() - Scrollbar::maxOverlapBetweenPages())), 1.0f);
    209             if (negative)
    210                 delta *= -1;
    211         }
    212         ScrollableArea::scroll((m_scrollbar->orientation() == HorizontalScrollbar) ? WebCore::ScrollLeft : WebCore::ScrollUp, WebCore::ScrollByPixel, delta);
    213         return true;
    214     }
    215 
    216     return false;
    217     }
    218 
    219 bool WebScrollbarImpl::onKeyDown(const WebInputEvent& event)
    220 {
    221     WebKeyboardEvent keyboard = *static_cast<const WebKeyboardEvent*>(&event);
    222     int keyCode;
    223     // We have to duplicate this logic from WebViewImpl because there it uses
    224     // Char and RawKeyDown events, which don't exist at this point.
    225     if (keyboard.windowsKeyCode == VKEY_SPACE)
    226         keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
    227     else {
    228         if (keyboard.modifiers == WebInputEvent::ControlKey) {
    229             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
    230             // key combinations which affect scrolling. Safari is buggy in the
    231             // sense that it scrolls the page for all Ctrl+scrolling key
    232             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
    233             switch (keyboard.windowsKeyCode) {
    234             case VKEY_HOME:
    235             case VKEY_END:
    236                 break;
    237             default:
    238                 return false;
    239             }
    240         }
    241 
    242         if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey))
    243             return false;
    244 
    245         keyCode = keyboard.windowsKeyCode;
    246     }
    247     WebCore::ScrollDirection scrollDirection;
    248     WebCore::ScrollGranularity scrollGranularity;
    249     if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) {
    250         // Will return false if scroll direction wasn't compatible with this scrollbar.
    251         return ScrollableArea::scroll(scrollDirection, scrollGranularity);
    252     }
    253     return false;
    254 }
    255 
    256 int WebScrollbarImpl::scrollSize(WebCore::ScrollbarOrientation orientation) const
    257 {
    258     return (orientation == m_scrollbar->orientation()) ? (m_scrollbar->totalSize() - m_scrollbar->visibleSize()) : 0;
    259 }
    260 
    261 int WebScrollbarImpl::scrollPosition(Scrollbar*) const
    262 {
    263     return m_scrollOffset;
    264 }
    265 
    266 void WebScrollbarImpl::setScrollOffset(const IntPoint& offset)
    267 {
    268     if (m_scrollbar->orientation() == HorizontalScrollbar)
    269         m_scrollOffset = offset.x();
    270     else
    271         m_scrollOffset = offset.y();
    272 
    273     m_client->valueChanged(this);
    274 }
    275 
    276 void WebScrollbarImpl::invalidateScrollbarRect(Scrollbar*, const IntRect& rect)
    277 {
    278     WebRect webrect(rect);
    279     webrect.x += m_scrollbar->x();
    280     webrect.y += m_scrollbar->y();
    281     m_client->invalidateScrollbarRect(this, webrect);
    282 }
    283 
    284 void WebScrollbarImpl::invalidateScrollCornerRect(const IntRect&)
    285 {
    286 }
    287 
    288 bool WebScrollbarImpl::isActive() const
    289 {
    290     return true;
    291 }
    292 
    293 bool WebScrollbarImpl::isScrollCornerVisible() const
    294 {
    295     return false;
    296 }
    297 
    298 void WebScrollbarImpl::getTickmarks(Vector<IntRect>& tickmarks) const
    299 {
    300     WebVector<WebRect> ticks;
    301     m_client->getTickmarks(const_cast<WebScrollbarImpl*>(this), &ticks);
    302     tickmarks.resize(ticks.size());
    303     for (size_t i = 0; i < ticks.size(); ++i)
    304         tickmarks[i] = ticks[i];
    305 }
    306 
    307 Scrollbar* WebScrollbarImpl::horizontalScrollbar() const
    308 {
    309     return m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar.get() : 0;
    310 }
    311 
    312 Scrollbar* WebScrollbarImpl::verticalScrollbar() const
    313 {
    314     return m_scrollbar->orientation() == VerticalScrollbar ? m_scrollbar.get() : 0;
    315 }
    316 
    317 } // namespace WebKit
    318