Home | History | Annotate | Download | only in pepper
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/pepper/ppb_scrollbar_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "content/renderer/pepper/common.h"
     11 #include "content/renderer/pepper/event_conversion.h"
     12 #include "content/renderer/pepper/host_globals.h"
     13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
     14 #include "content/renderer/pepper/plugin_module.h"
     15 #include "content/renderer/pepper/ppb_image_data_impl.h"
     16 #include "ppapi/c/dev/ppp_scrollbar_dev.h"
     17 #include "ppapi/thunk/thunk.h"
     18 #include "skia/ext/platform_canvas.h"
     19 #include "third_party/WebKit/public/platform/WebCanvas.h"
     20 #include "third_party/WebKit/public/platform/WebRect.h"
     21 #include "third_party/WebKit/public/platform/WebVector.h"
     22 #include "third_party/WebKit/public/web/WebInputEvent.h"
     23 #include "third_party/WebKit/public/web/WebPluginScrollbar.h"
     24 
     25 #if defined(OS_WIN)
     26 #include "base/win/windows_version.h"
     27 #endif
     28 
     29 using ppapi::thunk::PPB_Scrollbar_API;
     30 using WebKit::WebInputEvent;
     31 using WebKit::WebRect;
     32 using WebKit::WebScrollbar;
     33 using WebKit::WebPluginScrollbar;
     34 
     35 namespace content {
     36 
     37 // static
     38 PP_Resource PPB_Scrollbar_Impl::Create(PP_Instance instance,
     39                                        bool vertical) {
     40   scoped_refptr<PPB_Scrollbar_Impl> scrollbar(
     41       new PPB_Scrollbar_Impl(instance));
     42   scrollbar->Init(vertical);
     43   return scrollbar->GetReference();
     44 }
     45 
     46 PPB_Scrollbar_Impl::PPB_Scrollbar_Impl(PP_Instance instance)
     47     : PPB_Widget_Impl(instance),
     48       weak_ptr_factory_(this) {
     49 }
     50 
     51 PPB_Scrollbar_Impl::~PPB_Scrollbar_Impl() {
     52 }
     53 
     54 void PPB_Scrollbar_Impl::Init(bool vertical) {
     55   PepperPluginInstanceImpl* plugin_instance =
     56       HostGlobals::Get()->GetInstance(pp_instance());
     57   if (!plugin_instance)
     58     return;
     59   scrollbar_.reset(WebPluginScrollbar::createForPlugin(
     60       vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal,
     61       plugin_instance->container(),
     62       static_cast<WebKit::WebPluginScrollbarClient*>(this)));
     63 }
     64 
     65 PPB_Scrollbar_API* PPB_Scrollbar_Impl::AsPPB_Scrollbar_API() {
     66   return this;
     67 }
     68 
     69 void PPB_Scrollbar_Impl::InstanceWasDeleted() {
     70   scrollbar_.reset();
     71 }
     72 
     73 uint32_t PPB_Scrollbar_Impl::GetThickness() {
     74   return WebPluginScrollbar::defaultThickness();
     75 }
     76 
     77 bool PPB_Scrollbar_Impl::IsOverlay() {
     78   return scrollbar_->isOverlay();
     79 }
     80 
     81 uint32_t PPB_Scrollbar_Impl::GetValue() {
     82   return scrollbar_->value();
     83 }
     84 
     85 void PPB_Scrollbar_Impl::SetValue(uint32_t value) {
     86   if (scrollbar_)
     87     scrollbar_->setValue(value);
     88 }
     89 
     90 void PPB_Scrollbar_Impl::SetDocumentSize(uint32_t size) {
     91   if (scrollbar_)
     92     scrollbar_->setDocumentSize(size);
     93 }
     94 
     95 void PPB_Scrollbar_Impl::SetTickMarks(const PP_Rect* tick_marks,
     96                                       uint32_t count) {
     97   if (!scrollbar_)
     98     return;
     99   tickmarks_.resize(count);
    100   for (uint32 i = 0; i < count; ++i) {
    101     tickmarks_[i] = WebRect(tick_marks[i].point.x,
    102                             tick_marks[i].point.y,
    103                             tick_marks[i].size.width,
    104                             tick_marks[i].size.height);;
    105   }
    106   PP_Rect rect = location();
    107   Invalidate(&rect);
    108 }
    109 
    110 void PPB_Scrollbar_Impl::ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) {
    111   if (!scrollbar_)
    112     return;
    113 
    114   WebScrollbar::ScrollDirection direction = multiplier >= 0 ?
    115       WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward;
    116   float fmultiplier = 1.0;
    117 
    118   WebScrollbar::ScrollGranularity granularity;
    119   if (unit == PP_SCROLLBY_LINE) {
    120     granularity = WebScrollbar::ScrollByLine;
    121   } else if (unit == PP_SCROLLBY_PAGE) {
    122     granularity = WebScrollbar::ScrollByPage;
    123   } else if (unit == PP_SCROLLBY_DOCUMENT) {
    124     granularity = WebScrollbar::ScrollByDocument;
    125   } else {
    126     granularity = WebScrollbar::ScrollByPixel;
    127     fmultiplier = static_cast<float>(multiplier);
    128     if (fmultiplier < 0)
    129       fmultiplier *= -1;
    130   }
    131   scrollbar_->scroll(direction, granularity, fmultiplier);
    132 }
    133 
    134 PP_Bool PPB_Scrollbar_Impl::PaintInternal(const gfx::Rect& rect,
    135                                           PPB_ImageData_Impl* image) {
    136   ImageDataAutoMapper mapper(image);
    137   skia::PlatformCanvas* canvas = image->GetPlatformCanvas();
    138   if (!canvas || !scrollbar_)
    139     return PP_FALSE;
    140   canvas->save();
    141   canvas->scale(scale(), scale());
    142   scrollbar_->paint(canvas, rect);
    143   canvas->restore();
    144 
    145 #if defined(OS_WIN)
    146   if (base::win::GetVersion() == base::win::VERSION_XP)
    147     skia::MakeOpaque(canvas, rect.x(), rect.y(), rect.width(), rect.height());
    148 #endif
    149 
    150   return PP_TRUE;
    151 }
    152 
    153 PP_Bool PPB_Scrollbar_Impl::HandleEventInternal(
    154     const ppapi::InputEventData& data) {
    155   scoped_ptr<WebInputEvent> web_input_event(CreateWebInputEvent(data));
    156   if (!web_input_event.get() || !scrollbar_)
    157     return PP_FALSE;
    158 
    159   return PP_FromBool(scrollbar_->handleInputEvent(*web_input_event.get()));
    160 }
    161 
    162 void PPB_Scrollbar_Impl::SetLocationInternal(const PP_Rect* location) {
    163   if (!scrollbar_)
    164     return;
    165   scrollbar_->setLocation(WebRect(location->point.x,
    166                                   location->point.y,
    167                                   location->size.width,
    168                                   location->size.height));
    169 }
    170 
    171 void PPB_Scrollbar_Impl::valueChanged(WebKit::WebPluginScrollbar* scrollbar) {
    172   PluginModule* plugin_module =
    173       HostGlobals::Get()->GetInstance(pp_instance())->module();
    174   if (!plugin_module)
    175     return;
    176 
    177   const PPP_Scrollbar_Dev* ppp_scrollbar =
    178       static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
    179           PPP_SCROLLBAR_DEV_INTERFACE));
    180   if (!ppp_scrollbar) {
    181     // Try the old version. This is ok because the old interface is a subset of
    182     // the new one, and ValueChanged didn't change.
    183     ppp_scrollbar =
    184         static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
    185             PPP_SCROLLBAR_DEV_INTERFACE_0_2));
    186     if (!ppp_scrollbar)
    187       return;
    188   }
    189   ppp_scrollbar->ValueChanged(pp_instance(), pp_resource(),
    190                               scrollbar_->value());
    191 }
    192 
    193 void PPB_Scrollbar_Impl::overlayChanged(WebPluginScrollbar* scrollbar) {
    194   PluginModule* plugin_module =
    195       HostGlobals::Get()->GetInstance(pp_instance())->module();
    196   if (!plugin_module)
    197     return;
    198 
    199   const PPP_Scrollbar_Dev* ppp_scrollbar =
    200       static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
    201           PPP_SCROLLBAR_DEV_INTERFACE));
    202   if (!ppp_scrollbar)
    203     return;
    204   ppp_scrollbar->OverlayChanged(pp_instance(), pp_resource(),
    205                                 PP_FromBool(IsOverlay()));
    206 }
    207 
    208 void PPB_Scrollbar_Impl::invalidateScrollbarRect(
    209     WebKit::WebPluginScrollbar* scrollbar,
    210     const WebKit::WebRect& rect) {
    211   gfx::Rect gfx_rect(rect.x,
    212                      rect.y,
    213                      rect.width,
    214                      rect.height);
    215   dirty_.Union(gfx_rect);
    216   // Can't call into the client to tell them about the invalidate right away,
    217   // since the PPB_Scrollbar_Impl code is still in the middle of updating its
    218   // internal state.
    219   // Note: we use a WeakPtrFactory here so that a lingering callback can not
    220   // modify the lifetime of this object. Otherwise, WebKit::WebPluginScrollbar
    221   // could outlive WebKit::WebPluginContainer, which is against its contract.
    222   base::MessageLoop::current()->PostTask(
    223       FROM_HERE,
    224       base::Bind(&PPB_Scrollbar_Impl::NotifyInvalidate,
    225                  weak_ptr_factory_.GetWeakPtr()));
    226 }
    227 
    228 void PPB_Scrollbar_Impl::getTickmarks(
    229     WebKit::WebPluginScrollbar* scrollbar,
    230     WebKit::WebVector<WebKit::WebRect>* tick_marks) const {
    231   if (tickmarks_.empty()) {
    232     WebRect* rects = NULL;
    233     tick_marks->assign(rects, 0);
    234   } else {
    235     tick_marks->assign(&tickmarks_[0], tickmarks_.size());
    236   }
    237 }
    238 
    239 void PPB_Scrollbar_Impl::NotifyInvalidate() {
    240   if (dirty_.IsEmpty())
    241     return;
    242   PP_Rect pp_rect;
    243   pp_rect.point.x = dirty_.x();
    244   pp_rect.point.y = dirty_.y();
    245   pp_rect.size.width = dirty_.width();
    246   pp_rect.size.height = dirty_.height();
    247   dirty_ = gfx::Rect();
    248   Invalidate(&pp_rect);
    249 }
    250 
    251 }  // namespace content
    252