text: /*
   * Copyright (C) 2012 Google Inc. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1.  Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   * 2.  Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include "config.h"
  #include "web/WebPluginScrollbarImpl.h"
  
  #include "platform/KeyboardCodes.h"
  #include "platform/graphics/GraphicsContext.h"
  #include "platform/scroll/ScrollAnimator.h"
  #include "platform/scroll/ScrollTypes.h"
  #include "platform/scroll/Scrollbar.h"
  #include "platform/scroll/ScrollbarTheme.h"
  #include "public/platform/WebCanvas.h"
  #include "public/platform/WebRect.h"
  #include "public/platform/WebVector.h"
  #include "public/web/WebInputEvent.h"
  #include "public/web/WebPluginScrollbarClient.h"
  #include "web/ScrollbarGroup.h"
  #include "web/WebInputEventConversion.h"
  #include "web/WebPluginContainerImpl.h"
  #include "web/WebViewImpl.h"
  
  namespace blink {
  
  WebPluginScrollbar* WebPluginScrollbar::createForPlugin(Orientation orientation,
                                                          WebPluginContainer* pluginContainer,
                                                          WebPluginScrollbarClient* client)
  {
      WebPluginContainerImpl* plugin = toWebPluginContainerImpl(pluginContainer);
      return new WebPluginScrollbarImpl(orientation, plugin->scrollbarGroup(), client);
  }
  
  int WebPluginScrollbar::defaultThickness()
  {
      return ScrollbarTheme::theme()->scrollbarThickness();
  }
  
  WebPluginScrollbarImpl::WebPluginScrollbarImpl(Orientation orientation,
                                     ScrollbarGroup* group,
                                     WebPluginScrollbarClient* client)
      : m_group(group)
      , m_client(client)
      , m_scrollOffset(0)
  {
      m_scrollbar = Scrollbar::create(
          static_cast<ScrollableArea*>(m_group),
          static_cast<ScrollbarOrientation>(orientation),
          blink::RegularScrollbar);
      m_group->scrollbarCreated(this);
  }
  
  WebPluginScrollbarImpl::~WebPluginScrollbarImpl()
  {
      m_group->scrollbarDestroyed(this);
  }
  
  void WebPluginScrollbarImpl::setScrollOffset(int scrollOffset)
  {
      m_scrollOffset = scrollOffset;
      m_client->valueChanged(this);
  }
  
  void WebPluginScrollbarImpl::invalidateScrollbarRect(const IntRect& rect)
  {
      WebRect webrect(rect);
      webrect.x += m_scrollbar->x();
      webrect.y += m_scrollbar->y();
      m_client->invalidateScrollbarRect(this, webrect);
  }
  
  void WebPluginScrollbarImpl::getTickmarks(Vector<IntRect>& tickmarks) const
  {
      WebVector<WebRect> ticks;
      m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &ticks);
      tickmarks.resize(ticks.size());
      for (size_t i = 0; i < ticks.size(); ++i)
          tickmarks[i] = ticks[i];
  }
  
  IntPoint WebPluginScrollbarImpl::convertFromContainingViewToScrollbar(const IntPoint& parentPoint) const
  {
      IntPoint offset(parentPoint.x() - m_scrollbar->x(), parentPoint.y() - m_scrollbar->y());
      return m_scrollbar->Widget::convertFromContainingView(offset);
  }
  
  void WebPluginScrollbarImpl::scrollbarStyleChanged()
  {
      m_client->overlayChanged(this);
  }
  
  bool WebPluginScrollbarImpl::isOverlay() const
  {
      return m_scrollbar->isOverlayScrollbar();
  }
  
  int WebPluginScrollbarImpl::value() const
  {
      return m_scrollOffset;
  }
  
  WebPoint WebPluginScrollbarImpl::location() const
  {
      return m_scrollbar->frameRect().location();
  }
  
  WebSize WebPluginScrollbarImpl::size() const
  {
      return m_scrollbar->frameRect().size();
  }
  
  bool WebPluginScrollbarImpl::enabled() const
  {
      return m_scrollbar->enabled();
  }
  
  int WebPluginScrollbarImpl::maximum() const
  {
      return m_scrollbar->maximum();
  }
  
  int WebPluginScrollbarImpl::totalSize() const
  {
      return m_scrollbar->totalSize();
  }
  
  bool WebPluginScrollbarImpl::isScrollViewScrollbar() const
  {
      return m_scrollbar->isScrollViewScrollbar();
  }
  
  bool WebPluginScrollbarImpl::isScrollableAreaActive() const
  {
      return m_scrollbar->isScrollableAreaActive();
  }
  
  void WebPluginScrollbarImpl::getTickmarks(WebVector<WebRect>& tickmarks) const
  {
      m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &tickmarks);
  }
  
  WebScrollbar::ScrollbarControlSize WebPluginScrollbarImpl::controlSize() const
  {
      return static_cast<WebScrollbar::ScrollbarControlSize>(m_scrollbar->controlSize());
  }
  
  WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::pressedPart() const
  {
      return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->pressedPart());
  }
  
  WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::hoveredPart() const
  {
      return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->hoveredPart());
  }
  
  WebScrollbar::ScrollbarOverlayStyle WebPluginScrollbarImpl::scrollbarOverlayStyle() const
  {
      return static_cast<WebScrollbar::ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle());
  }
  
  WebScrollbar::Orientation WebPluginScrollbarImpl::orientation() const
  {
      if (m_scrollbar->orientation() == HorizontalScrollbar)
          return WebScrollbar::Horizontal;
      return WebScrollbar::Vertical;
  }
  
  bool WebPluginScrollbarImpl::isLeftSideVerticalScrollbar() const
  {
      return false;
  }
  
  bool WebPluginScrollbarImpl::isCustomScrollbar() const
  {
      return m_scrollbar->isCustomScrollbar();
  }
  
  void WebPluginScrollbarImpl::setLocation(const WebRect& rect)
  {
      IntRect oldRect = m_scrollbar->frameRect();
      m_scrollbar->setFrameRect(rect);
      if (WebRect(oldRect) != rect)
        m_scrollbar->invalidate();
  
      int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
      m_scrollbar->setEnabled(m_scrollbar->totalSize() > length);
      m_scrollbar->setProportion(length, m_scrollbar->totalSize());
  }
  
  void WebPluginScrollbarImpl::setValue(int position)
  {
      m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position));
  }
  
  void WebPluginScrollbarImpl::setDocumentSize(int size)
  {
      int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
      m_scrollbar->setEnabled(size > length);
      m_scrollbar->setProportion(length, size);
  }
  
  void WebPluginScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
  {
      blink::ScrollDirection dir;
      bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar;
      if (direction == ScrollForward)
          dir = horizontal ? ScrollRight : ScrollDown;
      else
          dir = horizontal ? ScrollLeft : ScrollUp;
  
      m_group->scroll(dir, static_cast<blink::ScrollGranularity>(granularity), multiplier);
  }
  
  void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect)
  {
      GraphicsContext context(canvas);
      m_scrollbar->paint(&context, rect);
  }
  
  bool WebPluginScrollbarImpl::handleInputEvent(const WebInputEvent& event)
  {
      switch (event.type) {
      case WebInputEvent::MouseDown:
          return onMouseDown(event);
      case WebInputEvent::MouseUp:
          return onMouseUp(event);
      case WebInputEvent::MouseMove:
          return onMouseMove(event);
      case WebInputEvent::MouseLeave:
          return onMouseLeave(event);
      case WebInputEvent::MouseWheel:
          return onMouseWheel(event);
      case WebInputEvent::KeyDown:
          return onKeyDown(event);
      case WebInputEvent::Undefined:
      case WebInputEvent::MouseEnter:
      case WebInputEvent::RawKeyDown:
      case WebInputEvent::KeyUp:
      case WebInputEvent::Char:
      case WebInputEvent::TouchStart:
      case WebInputEvent::TouchMove:
      case WebInputEvent::TouchEnd:
      case WebInputEvent::TouchCancel:
      default:
           break;
      }
      return false;
  }
  
  bool WebPluginScrollbarImpl::isAlphaLocked() const
  {
      return m_scrollbar->isAlphaLocked();
  }
  
  void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag)
  {
      return m_scrollbar->setIsAlphaLocked(flag);
  }
  
  bool WebPluginScrollbarImpl::onMouseDown(const WebInputEvent& event)
  {
      WebMouseEvent mousedown = static_cast<const WebMouseEvent&>(event);
      if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y))
          return false;
  
      mousedown.x -= m_scrollbar->x();
      mousedown.y -= m_scrollbar->y();
      m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown));
      return true;
  }
  
  bool WebPluginScrollbarImpl::onMouseUp(const WebInputEvent& event)
  {
      WebMouseEvent mouseup = static_cast<const WebMouseEvent&>(event);
      if (m_scrollbar->pressedPart() == blink::NoPart)
          return false;
  
      m_scrollbar->mouseUp(PlatformMouseEventBuilder(m_scrollbar.get(), mouseup));
      return true;
  }
  
  bool WebPluginScrollbarImpl::onMouseMove(const WebInputEvent& event)
  {
      WebMouseEvent mousemove = static_cast<const WebMouseEvent&>(event);
      if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y)
          || m_scrollbar->pressedPart() != blink::NoPart) {
          mousemove.x -= m_scrollbar->x();
          mousemove.y -= m_scrollbar->y();
          m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove));
          return true;
      }
  
      if (m_scrollbar->hoveredPart() != blink::NoPart && !m_scrollbar->isOverlayScrollbar())
          m_scrollbar->mouseExited();
      return false;
  }
  
  bool WebPluginScrollbarImpl::onMouseLeave(const WebInputEvent& event)
  {
      if (m_scrollbar->hoveredPart() != blink::NoPart)
          m_scrollbar->mouseExited();
  
      return false;
  }
  
  bool WebPluginScrollbarImpl::onMouseWheel(const WebInputEvent& event)
  {
      WebMouseWheelEvent mousewheel = static_cast<const WebMouseWheelEvent&>(event);
      PlatformWheelEventBuilder platformEvent(m_scrollbar.get(), mousewheel);
      return m_group->handleWheelEvent(platformEvent);
  }
  
  bool WebPluginScrollbarImpl::onKeyDown(const WebInputEvent& event)
  {
      WebKeyboardEvent keyboard = static_cast<const WebKeyboardEvent&>(event);
      int keyCode;
      // We have to duplicate this logic from WebViewImpl because there it uses
      // Char and RawKeyDown events, which don't exist at this point.
      if (keyboard.windowsKeyCode == VKEY_SPACE)
          keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
      else {
          if (keyboard.modifiers == WebInputEvent::ControlKey) {
              // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
              // key combinations which affect scrolling. Safari is buggy in the
              // sense that it scrolls the page for all Ctrl+scrolling key
              // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
              switch (keyboard.windowsKeyCode) {
              case VKEY_HOME:
              case VKEY_END:
                  break;
              default:
                  return false;
              }
          }
  
          if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey))
              return false;
  
          keyCode = keyboard.windowsKeyCode;
      }
      blink::ScrollDirection scrollDirection;
      blink::ScrollGranularity scrollGranularity;
      if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) {
          // Will return false if scroll direction wasn't compatible with this scrollbar.
          return m_group->scroll(scrollDirection, scrollGranularity);
      }
      return false;
  }
  
  } // namespace blink
  