OLD | NEW |
(Empty) | |
| 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/browser_plugin/browser_plugin.h" |
| 6 |
| 7 #include "base/message_loop.h" |
| 8 #include "base/string_util.h" |
| 9 #include "content/common/browser_plugin_messages.h" |
| 10 #include "content/public/common/content_client.h" |
| 11 #include "content/public/renderer/content_renderer_client.h" |
| 12 #include "content/renderer/browser_plugin/browser_plugin_bindings.h" |
| 13 #include "content/renderer/browser_plugin/browser_plugin_manager.h" |
| 14 #include "content/renderer/render_process_impl.h" |
| 15 #include "content/renderer/render_thread_impl.h" |
| 16 #include "skia/ext/platform_canvas.h" |
| 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h" |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
| 25 #include "webkit/plugins/sad_plugin.h" |
| 26 |
| 27 using WebKit::WebCanvas; |
| 28 using WebKit::WebPlugin; |
| 29 using WebKit::WebPluginContainer; |
| 30 using WebKit::WebPluginParams; |
| 31 using WebKit::WebPoint; |
| 32 using WebKit::WebString; |
| 33 using WebKit::WebRect; |
| 34 using WebKit::WebURL; |
| 35 using WebKit::WebVector; |
| 36 |
| 37 namespace content { |
| 38 |
| 39 namespace { |
| 40 const char kNavigationEventName[] = "navigation"; |
| 41 const char* kSrcAttribute = "src"; |
| 42 } |
| 43 |
| 44 BrowserPlugin::BrowserPlugin( |
| 45 int instance_id, |
| 46 RenderViewImpl* render_view, |
| 47 WebKit::WebFrame* frame, |
| 48 const WebPluginParams& params) |
| 49 : instance_id_(instance_id), |
| 50 render_view_(render_view), |
| 51 container_(NULL), |
| 52 damage_buffer_(NULL), |
| 53 sad_guest_(NULL), |
| 54 guest_crashed_(false), |
| 55 resize_pending_(false), |
| 56 parent_frame_(frame->identifier()) { |
| 57 BrowserPluginManager::Get()->AddBrowserPlugin(instance_id, this); |
| 58 bindings_.reset(new BrowserPluginBindings(this)); |
| 59 |
| 60 std::string src; |
| 61 if (ParseSrcAttribute(params, &src)) |
| 62 SetSrcAttribute(src); |
| 63 } |
| 64 |
| 65 BrowserPlugin::~BrowserPlugin() { |
| 66 if (damage_buffer_) { |
| 67 RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| 68 damage_buffer_ = NULL; |
| 69 } |
| 70 RemoveEventListeners(); |
| 71 BrowserPluginManager::Get()->RemoveBrowserPlugin(instance_id_); |
| 72 BrowserPluginManager::Get()->Send( |
| 73 new BrowserPluginHostMsg_PluginDestroyed( |
| 74 render_view_->GetRoutingID(), |
| 75 instance_id_)); |
| 76 } |
| 77 |
| 78 void BrowserPlugin::Cleanup() { |
| 79 if (damage_buffer_) { |
| 80 RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| 81 damage_buffer_ = NULL; |
| 82 } |
| 83 } |
| 84 |
| 85 std::string BrowserPlugin::GetSrcAttribute() const { |
| 86 return src_; |
| 87 } |
| 88 |
| 89 void BrowserPlugin::SetSrcAttribute(const std::string& src) { |
| 90 if (src == src_ && !guest_crashed_) |
| 91 return; |
| 92 if (!src.empty()) { |
| 93 BrowserPluginManager::Get()->Send( |
| 94 new BrowserPluginHostMsg_NavigateOrCreateGuest( |
| 95 render_view_->GetRoutingID(), |
| 96 instance_id_, |
| 97 parent_frame_, |
| 98 src)); |
| 99 } |
| 100 src_ = src; |
| 101 guest_crashed_ = false; |
| 102 } |
| 103 |
| 104 bool BrowserPlugin::ParseSrcAttribute( |
| 105 const WebKit::WebPluginParams& params, |
| 106 std::string* src) { |
| 107 // Get the src attribute from the attributes vector |
| 108 for (unsigned i = 0; i < params.attributeNames.size(); ++i) { |
| 109 std::string attributeName = params.attributeNames[i].utf8(); |
| 110 if (LowerCaseEqualsASCII(attributeName, kSrcAttribute)) { |
| 111 *src = params.attributeValues[i].utf8(); |
| 112 return true; |
| 113 } |
| 114 } |
| 115 return false; |
| 116 } |
| 117 |
| 118 float BrowserPlugin::GetDeviceScaleFactor() const { |
| 119 if (!render_view_) |
| 120 return 1.0f; |
| 121 return render_view_->GetWebView()->deviceScaleFactor(); |
| 122 } |
| 123 |
| 124 void BrowserPlugin::RemoveEventListeners() { |
| 125 EventListenerMap::iterator event_listener_map_iter = |
| 126 event_listener_map_.begin(); |
| 127 for (; event_listener_map_iter != event_listener_map_.end(); |
| 128 ++event_listener_map_iter) { |
| 129 EventListeners& listeners = |
| 130 event_listener_map_[event_listener_map_iter->first]; |
| 131 EventListeners::iterator it = listeners.begin(); |
| 132 for (; it != listeners.end(); ++it) { |
| 133 it->Dispose(); |
| 134 } |
| 135 } |
| 136 event_listener_map_.clear(); |
| 137 } |
| 138 |
| 139 void BrowserPlugin::UpdateRect( |
| 140 int message_id, |
| 141 const BrowserPluginMsg_UpdateRect_Params& params) { |
| 142 if (width() != params.view_size.width() || |
| 143 height() != params.view_size.height()) { |
| 144 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK( |
| 145 render_view_->GetRoutingID(), |
| 146 instance_id_, |
| 147 message_id, |
| 148 gfx::Size(width(), height()))); |
| 149 return; |
| 150 } |
| 151 |
| 152 float backing_store_scale_factor = |
| 153 backing_store_.get() ? backing_store_->GetScaleFactor() : 1.0f; |
| 154 |
| 155 if (params.is_resize_ack || |
| 156 backing_store_scale_factor != params.scale_factor) { |
| 157 resize_pending_ = !params.is_resize_ack; |
| 158 backing_store_.reset( |
| 159 new BrowserPluginBackingStore(gfx::Size(width(), height()), |
| 160 params.scale_factor)); |
| 161 } |
| 162 |
| 163 // Update the backing store. |
| 164 if (!params.scroll_rect.IsEmpty()) { |
| 165 backing_store_->ScrollBackingStore(params.dx, |
| 166 params.dy, |
| 167 params.scroll_rect, |
| 168 params.view_size); |
| 169 } |
| 170 for (unsigned i = 0; i < params.copy_rects.size(); i++) { |
| 171 backing_store_->PaintToBackingStore(params.bitmap_rect, |
| 172 params.copy_rects, |
| 173 damage_buffer_); |
| 174 } |
| 175 // Invalidate the container. |
| 176 container_->invalidate(); |
| 177 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK( |
| 178 render_view_->GetRoutingID(), |
| 179 instance_id_, |
| 180 message_id, |
| 181 gfx::Size())); |
| 182 } |
| 183 |
| 184 void BrowserPlugin::GuestCrashed() { |
| 185 guest_crashed_ = true; |
| 186 container_->invalidate(); |
| 187 } |
| 188 |
| 189 void BrowserPlugin::DidNavigate(const GURL& url) { |
| 190 src_ = url.spec(); |
| 191 if (!HasListeners(kNavigationEventName)) |
| 192 return; |
| 193 |
| 194 EventListeners& listeners = event_listener_map_[kNavigationEventName]; |
| 195 EventListeners::iterator it = listeners.begin(); |
| 196 for (; it != listeners.end(); ++it) { |
| 197 v8::Context::Scope context_scope(v8::Context::New()); |
| 198 v8::HandleScope handle_scope; |
| 199 v8::Local<v8::Value> param = |
| 200 v8::Local<v8::Value>::New(v8::String::New(src_.c_str())); |
| 201 container()->element().document().frame()-> |
| 202 callFunctionEvenIfScriptDisabled(*it, |
| 203 v8::Object::New(), |
| 204 1, |
| 205 ¶m); |
| 206 } |
| 207 } |
| 208 |
| 209 void BrowserPlugin::AdvanceFocus(bool reverse) { |
| 210 // We do not have a RenderView when we are testing. |
| 211 if (render_view_) |
| 212 render_view_->GetWebView()->advanceFocus(reverse); |
| 213 } |
| 214 |
| 215 bool BrowserPlugin::HasListeners(const std::string& event_name) { |
| 216 return event_listener_map_.find(event_name) != event_listener_map_.end(); |
| 217 } |
| 218 |
| 219 bool BrowserPlugin::AddEventListener(const std::string& event_name, |
| 220 v8::Local<v8::Function> function) { |
| 221 EventListeners& listeners = event_listener_map_[event_name]; |
| 222 for (unsigned int i = 0; i < listeners.size(); ++i) { |
| 223 if (listeners[i] == function) |
| 224 return false; |
| 225 } |
| 226 v8::Persistent<v8::Function> persistent_function = |
| 227 v8::Persistent<v8::Function>::New(function); |
| 228 listeners.push_back(persistent_function); |
| 229 return true; |
| 230 } |
| 231 |
| 232 bool BrowserPlugin::RemoveEventListener(const std::string& event_name, |
| 233 v8::Local<v8::Function> function) { |
| 234 if (event_listener_map_.find(event_name) == event_listener_map_.end()) |
| 235 return false; |
| 236 |
| 237 EventListeners& listeners = event_listener_map_[event_name]; |
| 238 EventListeners::iterator it = listeners.begin(); |
| 239 for (; it != listeners.end(); ++it) { |
| 240 if (*it == function) { |
| 241 it->Dispose(); |
| 242 listeners.erase(it); |
| 243 return true; |
| 244 } |
| 245 } |
| 246 return false; |
| 247 } |
| 248 |
| 249 WebKit::WebPluginContainer* BrowserPlugin::container() const { |
| 250 return container_; |
| 251 } |
| 252 |
| 253 bool BrowserPlugin::initialize(WebPluginContainer* container) { |
| 254 container_ = container; |
| 255 return true; |
| 256 } |
| 257 |
| 258 void BrowserPlugin::destroy() { |
| 259 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 260 } |
| 261 |
| 262 NPObject* BrowserPlugin::scriptableObject() { |
| 263 NPObject* browser_plugin_np_object(bindings_->np_object()); |
| 264 // The object is expected to be retained before it is returned. |
| 265 WebKit::WebBindings::retainObject(browser_plugin_np_object); |
| 266 return browser_plugin_np_object; |
| 267 } |
| 268 |
| 269 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) { |
| 270 if (guest_crashed_) { |
| 271 if (!sad_guest_) // Lazily initialize bitmap. |
| 272 sad_guest_ = content::GetContentClient()->renderer()-> |
| 273 GetSadPluginBitmap(); |
| 274 // TODO(fsamuel): Do we want to paint something other than a sad plugin |
| 275 // on crash? See http://www.crbug.com/140266. |
| 276 webkit::PaintSadPlugin(canvas, plugin_rect_, *sad_guest_); |
| 277 return; |
| 278 } |
| 279 SkAutoCanvasRestore auto_restore(canvas, true); |
| 280 canvas->translate(plugin_rect_.x(), plugin_rect_.y()); |
| 281 SkRect image_data_rect = SkRect::MakeXYWH( |
| 282 SkIntToScalar(0), |
| 283 SkIntToScalar(0), |
| 284 SkIntToScalar(plugin_rect_.width()), |
| 285 SkIntToScalar(plugin_rect_.height())); |
| 286 canvas->clipRect(image_data_rect); |
| 287 // Paint white in case we have nothing in our backing store or we need to |
| 288 // show a gutter. |
| 289 SkPaint paint; |
| 290 paint.setStyle(SkPaint::kFill_Style); |
| 291 paint.setColor(SK_ColorWHITE); |
| 292 canvas->drawRect(image_data_rect, paint); |
| 293 // Stay at white if we have no src set, or we don't yet have a backing store. |
| 294 if (!backing_store_.get() || src_.empty()) |
| 295 return; |
| 296 float inverse_scale_factor = 1.0f / backing_store_->GetScaleFactor(); |
| 297 canvas->scale(inverse_scale_factor, inverse_scale_factor); |
| 298 canvas->drawBitmap(backing_store_->GetBitmap(), 0, 0); |
| 299 } |
| 300 |
| 301 void BrowserPlugin::updateGeometry( |
| 302 const WebRect& window_rect, |
| 303 const WebRect& clip_rect, |
| 304 const WebVector<WebRect>& cut_outs_rects, |
| 305 bool is_visible) { |
| 306 int old_width = width(); |
| 307 int old_height = height(); |
| 308 plugin_rect_ = window_rect; |
| 309 if (old_width == window_rect.width && |
| 310 old_height == window_rect.height) |
| 311 return; |
| 312 |
| 313 const size_t stride = skia::PlatformCanvas::StrideForWidth(window_rect.width); |
| 314 const size_t size = window_rect.height * |
| 315 stride * |
| 316 GetDeviceScaleFactor() * |
| 317 GetDeviceScaleFactor(); |
| 318 |
| 319 // Don't drop the old damage buffer until after we've made sure that the |
| 320 // browser process has dropped it. |
| 321 TransportDIB* new_damage_buffer = |
| 322 RenderProcess::current()->CreateTransportDIB(size); |
| 323 DCHECK(new_damage_buffer); |
| 324 |
| 325 BrowserPluginHostMsg_ResizeGuest_Params params; |
| 326 params.damage_buffer_id = new_damage_buffer->id(); |
| 327 params.width = window_rect.width; |
| 328 params.height = window_rect.height; |
| 329 params.resize_pending = resize_pending_; |
| 330 params.scale_factor = GetDeviceScaleFactor(); |
| 331 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest( |
| 332 render_view_->GetRoutingID(), |
| 333 instance_id_, |
| 334 params)); |
| 335 resize_pending_ = true; |
| 336 |
| 337 if (damage_buffer_) { |
| 338 RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| 339 damage_buffer_ = NULL; |
| 340 } |
| 341 damage_buffer_ = new_damage_buffer; |
| 342 } |
| 343 |
| 344 void BrowserPlugin::updateFocus(bool focused) { |
| 345 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus( |
| 346 render_view_->GetRoutingID(), |
| 347 instance_id_, |
| 348 focused)); |
| 349 } |
| 350 |
| 351 void BrowserPlugin::updateVisibility(bool visible) { |
| 352 } |
| 353 |
| 354 bool BrowserPlugin::acceptsInputEvents() { |
| 355 return true; |
| 356 } |
| 357 |
| 358 bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event, |
| 359 WebKit::WebCursorInfo& cursor_info) { |
| 360 if (guest_crashed_ || src_.empty()) |
| 361 return false; |
| 362 bool handled = false; |
| 363 WebCursor cursor; |
| 364 IPC::Message* message = |
| 365 new BrowserPluginHostMsg_HandleInputEvent( |
| 366 render_view_->GetRoutingID(), |
| 367 &handled, |
| 368 &cursor); |
| 369 message->WriteInt(instance_id_); |
| 370 message->WriteData(reinterpret_cast<const char*>(&plugin_rect_), |
| 371 sizeof(gfx::Rect)); |
| 372 message->WriteData(reinterpret_cast<const char*>(&event), event.size); |
| 373 BrowserPluginManager::Get()->Send(message); |
| 374 cursor.GetCursorInfo(&cursor_info); |
| 375 return handled; |
| 376 } |
| 377 |
| 378 void BrowserPlugin::didReceiveResponse( |
| 379 const WebKit::WebURLResponse& response) { |
| 380 } |
| 381 |
| 382 void BrowserPlugin::didReceiveData(const char* data, int data_length) { |
| 383 } |
| 384 |
| 385 void BrowserPlugin::didFinishLoading() { |
| 386 } |
| 387 |
| 388 void BrowserPlugin::didFailLoading(const WebKit::WebURLError& error) { |
| 389 } |
| 390 |
| 391 void BrowserPlugin::didFinishLoadingFrameRequest(const WebKit::WebURL& url, |
| 392 void* notify_data) { |
| 393 } |
| 394 |
| 395 void BrowserPlugin::didFailLoadingFrameRequest( |
| 396 const WebKit::WebURL& url, |
| 397 void* notify_data, |
| 398 const WebKit::WebURLError& error) { |
| 399 } |
| 400 |
| 401 } // namespace content |
OLD | NEW |