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 blink::WebInputEvent; 31 using blink::WebRect; 32 using blink::WebScrollbar; 33 using blink::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<blink::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(blink::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 blink::WebPluginScrollbar* scrollbar, 210 const blink::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, blink::WebPluginScrollbar 221 // could outlive blink::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 blink::WebPluginScrollbar* scrollbar, 230 blink::WebVector<blink::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