Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Unified Diff: content/renderer/browser_plugin/browser_plugin.cc

Issue 10830072: Browser Plugin: New Implementation (Renderer Side) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed leaky Persistents in BrowserPlugin Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..384ec1d5eab4bd47ea0d5ceba8b83143c2317c4a
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -0,0 +1,413 @@
+// 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 kNavigation[] = "navigation";
Charlie Reis 2012/08/01 23:20:51 Please make it clear what this is used for. And w
+}
+
+static const char* kSrcAttribute = "src";
+
+BrowserPlugin::BrowserPlugin(
+ int instance_id,
+ RenderViewImpl* render_view,
+ int routing_id,
+ WebKit::WebFrame* frame,
+ const WebPluginParams& params)
+ : instance_id_(instance_id),
+ render_view_(render_view),
+ routing_id_(routing_id),
+ 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;
+ ParseSrcAttribute(params, &src);
+ SetSrcAttribute(src);
+}
+
+BrowserPlugin::~BrowserPlugin() {
+ if (damage_buffer_) {
+ // This is a virtual method call and so it's potentially unsafe
+ // but given its use in MockBrowserPlugin (it doesn't access this), this
+ // should work fine in practice.
Charlie Reis 2012/08/01 23:20:51 Could you have MockBrowserPlugin call Cleanup inst
Fady Samuel 2012/08/02 18:32:47 No longer doing a virtual method call after iterat
+ FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+ RemoveEventListeners();
+ BrowserPluginManager::Get()->RemoveBrowserPlugin(instance_id_);
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_PluginDestroyed(
+ routing_id_,
+ instance_id_));
+}
+
+void BrowserPlugin::Cleanup() {
+ if (damage_buffer_) {
+ FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+}
+
+std::string BrowserPlugin::GetSrcAttribute() const {
+ if (guest_crashed_)
+ return std::string();
Charlie Reis 2012/08/01 23:20:51 I don't see why we wouldn't return src_ after a cr
Fady Samuel 2012/08/02 18:32:47 Removed.
+ return src_;
+}
+
+void BrowserPlugin::SetSrcAttribute(const std::string& src) {
+ // TODO(fsamuel): What if the BrowserPlugin element's parent frame
+ // changes?
+ if (src == src_ && !guest_crashed_)
+ return;
Charlie Reis 2012/08/01 23:20:51 This prevents using SetSrcAttribute for doing a re
Fady Samuel 2012/08/02 18:32:47 Actually, it's the exact opposite. If guest_crashe
Charlie Reis 2012/08/03 18:06:02 Yes, but why would you want to prevent reload if t
+ if (!src.empty()) {
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_NavigateFromEmbedder(
+ routing_id_,
+ instance_id_,
+ parent_frame_,
+ src));
+ }
+ src_ = src;
+ guest_crashed_ = false;
+}
+
+void BrowserPlugin::ParseSrcAttribute(
Charlie Reis 2012/08/01 23:20:51 There's no way to tell if this succeeded or failed
Fady Samuel 2012/08/02 18:32:47 Done.
+ 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();
+ break;
+ }
+ }
+}
+
+TransportDIB* BrowserPlugin::CreateTransportDIB(size_t size) {
+ return static_cast<RenderProcessImpl*>(RenderProcess::current())->
+ CreateTransportDIB(size);
+}
+
+void BrowserPlugin::FreeTransportDIB(TransportDIB* dib) {
+ static_cast<RenderProcessImpl*>(RenderProcess::current())->
+ FreeTransportDIB(dib);
+}
+
+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(
+ routing_id_,
+ instance_id_,
+ message_id,
+ gfx::Size(width(), height())));
+ return;
+ }
+ if (params.is_resize_ack) {
+ resize_pending_ = false;
+ backing_store_.reset(
+ new BrowserPluginBackingStore(gfx::Size(width(), height())));
+ }
+
+ // 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(
+ routing_id_,
+ instance_id_,
+ message_id,
+ gfx::Size()));
+}
+
+void BrowserPlugin::GuestCrashed() {
+ guest_crashed_ = true;
+ src_.clear();
Charlie Reis 2012/08/01 23:20:51 Again, I don't think we should clear this.
Fady Samuel 2012/08/02 18:32:47 Done.
+ container_->invalidate();
+}
+
+bool BrowserPlugin::HasListeners(const std::string& event_name) {
+ return event_listener_map_.find(event_name) != event_listener_map_.end();
+}
+
+void BrowserPlugin::UpdateURL(const GURL& url) {
+ src_ = url.spec();
+ if (!HasListeners(kNavigation))
+ return;
+
+ EventListeners& listeners = event_listener_map_[kNavigation];
+ 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,
Charlie Reis 2012/08/01 23:20:51 Is this common practice? I'm surprised we would c
Fady Samuel 2012/08/02 18:32:47 That's what I've seen done elsewhere, but there mi
+ v8::Object::New(),
+ 1,
+ &param);
+ }
+}
+
+void BrowserPlugin::AdvanceFocus(bool reverse) {
+ // We do not have a RenderView when we are testing.
+ if (render_view_)
+ render_view_->GetWebView()->advanceFocus(reverse);
+}
+
+void BrowserPlugin::PostMessage(const string16& message,
+ const string16& target_origin) {
+ BrowserPluginHostMsg_PostMessage_Params params;
+ params.data = message;
+ params.target_origin = target_origin;
+ params.source_routing_id = instance_id_;
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_RouteMessageEvent(
+ routing_id_, params));
+}
+
+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.
+ sad_guest_ = content::GetContentClient()->renderer()->
+ GetSadPluginBitmap();
+ webkit::PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
Charlie Reis 2012/08/01 23:20:51 While this is technically implemented as a plugin,
Fady Samuel 2012/08/02 18:32:47 Done.
+ 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.
+ 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;
+ 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;
+
+ const size_t stride = skia::PlatformCanvas::StrideForWidth(window_rect.width);
+ const size_t size = window_rect.height * stride;
+
+ // Don't drop the old damage buffer until after we've made sure that the
+ // browser process has dropped it.
+ TransportDIB* new_damage_buffer = CreateTransportDIB(size);
+ DCHECK(new_damage_buffer);
+
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest(
+ routing_id_,
+ instance_id_,
+ new_damage_buffer->id(),
+ window_rect.width,
+ window_rect.height,
+ resize_pending_));
+ resize_pending_ = true;
+
+ if (damage_buffer_) {
+ FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+ damage_buffer_ = new_damage_buffer;
+}
+
+void BrowserPlugin::updateFocus(bool focused) {
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus(
+ routing_id_,
+ 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(
+ routing_id_,
+ &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

Powered by Google App Engine
This is Rietveld 408576698