Chromium Code Reviews| Index: content/renderer/browser_plugin/browser_plugin.cc |
| diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6414d5dfd54fe1036d27fe29e73237aa22d9be56 |
| --- /dev/null |
| +++ b/content/renderer/browser_plugin/browser_plugin.cc |
| @@ -0,0 +1,407 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/renderer/browser_plugin/browser_plugin.h" |
| + |
| +#include "base/message_loop.h" |
| +#include "base/string_util.h" |
| +#include "content/common/browser_plugin_messages.h" |
| +#include "content/public/common/content_client.h" |
| +#include "content/public/renderer/content_renderer_client.h" |
| +#include "content/renderer/browser_plugin/browser_plugin_bindings.h" |
| +#include "content/renderer/browser_plugin/browser_plugin_manager.h" |
| +#include "content/renderer/render_process_impl.h" |
| +#include "content/renderer/render_thread_impl.h" |
| +#include "skia/ext/platform_canvas.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h" |
| +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
| +#include "webkit/plugins/sad_plugin.h" |
| + |
| +using WebKit::WebCanvas; |
| +using WebKit::WebPlugin; |
| +using WebKit::WebPluginContainer; |
| +using WebKit::WebPluginParams; |
| +using WebKit::WebPoint; |
| +using WebKit::WebString; |
| +using WebKit::WebRect; |
| +using WebKit::WebURL; |
| +using WebKit::WebVector; |
| + |
| +namespace content { |
| +namespace browser_plugin { |
| + |
| +namespace { |
| +const char kNavigationEventName[] = "navigation"; |
| +const char* kSrcAttribute = "src"; |
| +} |
| + |
| +BrowserPlugin::BrowserPlugin( |
| + int instance_id, |
| + RenderViewImpl* render_view, |
| + WebKit::WebFrame* frame, |
| + const WebPluginParams& params) |
| + : instance_id_(instance_id), |
| + render_view_(render_view), |
| + container_(NULL), |
| + damage_buffer_(NULL), |
| + sad_guest_(NULL), |
| + guest_crashed_(false), |
| + resize_pending_(false), |
| + parent_frame_(frame->identifier()) { |
| + BrowserPluginManager::Get()->AddBrowserPlugin(instance_id, this); |
| + bindings_.reset(new BrowserPluginBindings(this)); |
| + |
| + std::string src; |
| + if (ParseSrcAttribute(params, &src)) |
| + SetSrcAttribute(src); |
| +} |
| + |
| +BrowserPlugin::~BrowserPlugin() { |
| + if (damage_buffer_) { |
| + RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| + damage_buffer_ = NULL; |
| + } |
| + RemoveEventListeners(); |
| + BrowserPluginManager::Get()->RemoveBrowserPlugin(instance_id_); |
| + BrowserPluginManager::Get()->Send( |
| + new BrowserPluginHostMsg_PluginDestroyed( |
| + render_view_->GetRoutingID(), |
| + instance_id_)); |
| +} |
| + |
| +void BrowserPlugin::Cleanup() { |
| + if (damage_buffer_) { |
| + RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| + damage_buffer_ = NULL; |
| + } |
| +} |
| + |
| +std::string BrowserPlugin::GetSrcAttribute() const { |
| + return src_; |
| +} |
| + |
| +void BrowserPlugin::SetSrcAttribute(const std::string& src) { |
| + if (src == src_ && !guest_crashed_) |
| + return; |
| + if (!src.empty()) { |
| + BrowserPluginManager::Get()->Send( |
| + new BrowserPluginHostMsg_NavigateOrCreateGuest( |
| + render_view_->GetRoutingID(), |
| + instance_id_, |
| + parent_frame_, |
| + src)); |
| + } |
| + src_ = src; |
| + guest_crashed_ = false; |
| +} |
| + |
| +bool BrowserPlugin::ParseSrcAttribute( |
| + const WebKit::WebPluginParams& params, |
| + std::string* src) { |
| + // Get the src attribute from the attributes vector |
| + for (unsigned i = 0; i < params.attributeNames.size(); ++i) { |
| + std::string attributeName = params.attributeNames[i].utf8(); |
| + if (LowerCaseEqualsASCII(attributeName, kSrcAttribute)) { |
| + *src = params.attributeValues[i].utf8(); |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +float BrowserPlugin::GetDeviceScaleFactor() const { |
| + if (!render_view_) |
| + return 1.0f; |
| + return render_view_->GetWebView()->deviceScaleFactor(); |
| +} |
| + |
| +void BrowserPlugin::RemoveEventListeners() { |
| + EventListenerMap::iterator event_listener_map_iter = |
| + event_listener_map_.begin(); |
| + for (; event_listener_map_iter != event_listener_map_.end(); |
| + ++event_listener_map_iter) { |
| + EventListeners& listeners = |
| + event_listener_map_[event_listener_map_iter->first]; |
| + EventListeners::iterator it = listeners.begin(); |
| + for (; it != listeners.end(); ++it) { |
| + it->Dispose(); |
| + } |
| + } |
| + event_listener_map_.clear(); |
| +} |
| + |
| +void BrowserPlugin::UpdateRect( |
| + int message_id, |
| + const BrowserPluginMsg_UpdateRect_Params& params) { |
| + if (width() != params.view_size.width() || |
| + height() != params.view_size.height()) { |
| + BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK( |
| + render_view_->GetRoutingID(), |
| + instance_id_, |
| + message_id, |
| + gfx::Size(width(), height()))); |
| + return; |
| + } |
| + |
| + float backing_store_scale_factor = |
| + backing_store_.get() ? backing_store_->GetScaleFactor() : 1.0f; |
| + |
| + if (params.is_resize_ack || |
| + backing_store_scale_factor != params.scale_factor) { |
| + resize_pending_ = !params.is_resize_ack; |
| + backing_store_.reset( |
| + new BrowserPluginBackingStore(gfx::Size(width(), height()), |
| + params.scale_factor)); |
| + } |
| + |
| + // Update the backing store. |
| + if (!params.scroll_rect.IsEmpty()) { |
| + backing_store_->ScrollBackingStore(params.dx, |
| + params.dy, |
| + params.scroll_rect, |
| + params.view_size); |
| + } |
| + for (unsigned i = 0; i < params.copy_rects.size(); i++) { |
| + backing_store_->PaintToBackingStore(params.bitmap_rect, |
| + params.copy_rects, |
| + damage_buffer_); |
| + } |
| + // Invalidate the container. |
| + container_->invalidate(); |
| + BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK( |
| + render_view_->GetRoutingID(), |
| + instance_id_, |
| + message_id, |
| + gfx::Size())); |
| +} |
| + |
| +void BrowserPlugin::GuestCrashed() { |
| + guest_crashed_ = true; |
| + container_->invalidate(); |
| +} |
| + |
| +void BrowserPlugin::DidNavigate(const GURL& url) { |
| + src_ = url.spec(); |
| + if (!HasListeners(kNavigationEventName)) |
| + return; |
| + |
| + EventListeners& listeners = event_listener_map_[kNavigationEventName]; |
| + EventListeners::iterator it = listeners.begin(); |
| + for (; it != listeners.end(); ++it) { |
| + v8::Context::Scope context_scope(v8::Context::New()); |
| + v8::HandleScope handle_scope; |
| + v8::Local<v8::Value> param = |
| + v8::Local<v8::Value>::New(v8::String::New(src_.c_str())); |
| + container()->element().document().frame()-> |
| + callFunctionEvenIfScriptDisabled(*it, |
| + v8::Object::New(), |
| + 1, |
| + ¶m); |
| + } |
| +} |
| + |
| +void BrowserPlugin::AdvanceFocus(bool reverse) { |
| + // We do not have a RenderView when we are testing. |
| + if (render_view_) |
| + render_view_->GetWebView()->advanceFocus(reverse); |
| +} |
| + |
| +bool BrowserPlugin::HasListeners(const std::string& event_name) { |
| + return event_listener_map_.find(event_name) != event_listener_map_.end(); |
| +} |
| + |
| +bool BrowserPlugin::AddEventListener(const std::string& event_name, |
| + v8::Local<v8::Function> function) { |
| + EventListeners& listeners = event_listener_map_[event_name]; |
| + for (unsigned int i = 0; i < listeners.size(); ++i) { |
| + if (listeners[i] == function) |
| + return false; |
| + } |
| + v8::Persistent<v8::Function> persistent_function = |
| + v8::Persistent<v8::Function>::New(function); |
| + listeners.push_back(persistent_function); |
| + return true; |
| +} |
| + |
| +bool BrowserPlugin::RemoveEventListener(const std::string& event_name, |
| + v8::Local<v8::Function> function) { |
| + if (event_listener_map_.find(event_name) == event_listener_map_.end()) |
| + return false; |
| + |
| + EventListeners& listeners = event_listener_map_[event_name]; |
| + EventListeners::iterator it = listeners.begin(); |
| + for (; it != listeners.end(); ++it) { |
| + if (*it == function) { |
| + it->Dispose(); |
| + listeners.erase(it); |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +WebKit::WebPluginContainer* BrowserPlugin::container() const { |
| + return container_; |
| +} |
| + |
| +bool BrowserPlugin::initialize(WebPluginContainer* container) { |
| + container_ = container; |
| + return true; |
| +} |
| + |
| +void BrowserPlugin::destroy() { |
| + MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| +} |
| + |
| +NPObject* BrowserPlugin::scriptableObject() { |
| + NPObject* browser_plugin_np_object(bindings_->np_object()); |
| + // The object is expected to be retained before it is returned. |
| + WebKit::WebBindings::retainObject(browser_plugin_np_object); |
| + return browser_plugin_np_object; |
| +} |
| + |
| +bool BrowserPlugin::supportsKeyboardFocus() const { |
| + return true; |
| +} |
| + |
| +void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) { |
| + if (guest_crashed_) { |
| + if (!sad_guest_) // Lazily initialize bitmap. |
|
Charlie Reis
2012/08/03 20:01:00
nit: Needs braces, since the code below doesn't fi
Fady Samuel
2012/08/03 22:04:13
Done.
|
| + sad_guest_ = content::GetContentClient()->renderer()-> |
| + GetSadPluginBitmap(); |
| + // TODO(fsamuel): Do we want to paint something other than a sad plugin |
| + // on crash? See http://www.crbug.com/140266. |
| + webkit::PaintSadPlugin(canvas, plugin_rect_, *sad_guest_); |
| + return; |
| + } |
| + SkAutoCanvasRestore auto_restore(canvas, true); |
| + canvas->translate(plugin_rect_.x(), plugin_rect_.y()); |
| + SkRect image_data_rect = SkRect::MakeXYWH( |
| + SkIntToScalar(0), |
| + SkIntToScalar(0), |
| + SkIntToScalar(plugin_rect_.width()), |
| + SkIntToScalar(plugin_rect_.height())); |
| + canvas->clipRect(image_data_rect); |
| + // Paint white in case we have nothing in our backing store or we need to |
| + // show a gutter. |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kFill_Style); |
| + paint.setColor(SK_ColorWHITE); |
| + canvas->drawRect(image_data_rect, paint); |
| + // Stay at white if we have no src set, or we don't yet have a backing store. |
| + if (!backing_store_.get() || src_.empty()) |
| + return; |
| + float inverse_scale_factor = 1.0f / backing_store_->GetScaleFactor(); |
| + canvas->scale(inverse_scale_factor, inverse_scale_factor); |
| + canvas->drawBitmap(backing_store_->GetBitmap(), 0, 0); |
| +} |
| + |
| +void BrowserPlugin::updateGeometry( |
| + const WebRect& window_rect, |
| + const WebRect& clip_rect, |
| + const WebVector<WebRect>& cut_outs_rects, |
| + bool is_visible) { |
| + int old_width = width(); |
| + int old_height = height(); |
| + plugin_rect_ = window_rect; |
| + if (old_width == window_rect.width && |
| + old_height == window_rect.height) |
| + return; |
|
Charlie Reis
2012/08/03 20:01:00
nit: Needs braces, since the conditional doesn't f
Fady Samuel
2012/08/03 22:04:13
Done.
|
| + |
| + const size_t stride = skia::PlatformCanvas::StrideForWidth(window_rect.width); |
| + const size_t size = window_rect.height * |
| + stride * |
| + GetDeviceScaleFactor() * |
| + GetDeviceScaleFactor(); |
| + |
| + // Don't drop the old damage buffer until after we've made sure that the |
| + // browser process has dropped it. |
| + TransportDIB* new_damage_buffer = |
| + RenderProcess::current()->CreateTransportDIB(size); |
| + DCHECK(new_damage_buffer); |
| + |
| + BrowserPluginHostMsg_ResizeGuest_Params params; |
| + params.damage_buffer_id = new_damage_buffer->id(); |
| + params.width = window_rect.width; |
| + params.height = window_rect.height; |
| + params.resize_pending = resize_pending_; |
| + params.scale_factor = GetDeviceScaleFactor(); |
| + BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest( |
| + render_view_->GetRoutingID(), |
| + instance_id_, |
| + params)); |
| + resize_pending_ = true; |
| + |
| + if (damage_buffer_) { |
| + RenderProcess::current()->FreeTransportDIB(damage_buffer_); |
| + damage_buffer_ = NULL; |
| + } |
| + damage_buffer_ = new_damage_buffer; |
| +} |
| + |
| +void BrowserPlugin::updateFocus(bool focused) { |
| + BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus( |
| + render_view_->GetRoutingID(), |
| + instance_id_, |
| + focused)); |
| +} |
| + |
| +void BrowserPlugin::updateVisibility(bool visible) { |
| +} |
| + |
| +bool BrowserPlugin::acceptsInputEvents() { |
| + return true; |
| +} |
| + |
| +bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event, |
| + WebKit::WebCursorInfo& cursor_info) { |
| + if (guest_crashed_ || src_.empty()) |
| + return false; |
| + bool handled = false; |
| + WebCursor cursor; |
| + IPC::Message* message = |
| + new BrowserPluginHostMsg_HandleInputEvent( |
| + render_view_->GetRoutingID(), |
| + &handled, |
| + &cursor); |
| + message->WriteInt(instance_id_); |
| + message->WriteData(reinterpret_cast<const char*>(&plugin_rect_), |
| + sizeof(gfx::Rect)); |
| + message->WriteData(reinterpret_cast<const char*>(&event), event.size); |
| + BrowserPluginManager::Get()->Send(message); |
| + cursor.GetCursorInfo(&cursor_info); |
| + return handled; |
| +} |
| + |
| +void BrowserPlugin::didReceiveResponse( |
| + const WebKit::WebURLResponse& response) { |
| +} |
| + |
| +void BrowserPlugin::didReceiveData(const char* data, int data_length) { |
| +} |
| + |
| +void BrowserPlugin::didFinishLoading() { |
| +} |
| + |
| +void BrowserPlugin::didFailLoading(const WebKit::WebURLError& error) { |
| +} |
| + |
| +void BrowserPlugin::didFinishLoadingFrameRequest(const WebKit::WebURL& url, |
| + void* notify_data) { |
| +} |
| + |
| +void BrowserPlugin::didFailLoadingFrameRequest( |
| + const WebKit::WebURL& url, |
| + void* notify_data, |
| + const WebKit::WebURLError& error) { |
| +} |
| + |
| +} // namespace browser_plugin |
| +} // namespace content |