summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/plugin_var_tracker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/proxy/plugin_var_tracker.cc')
-rw-r--r--ppapi/proxy/plugin_var_tracker.cc250
1 files changed, 200 insertions, 50 deletions
diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc
index 6ad396a..42370be 100644
--- a/ppapi/proxy/plugin_var_tracker.cc
+++ b/ppapi/proxy/plugin_var_tracker.cc
@@ -1,13 +1,14 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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 "ppapi/proxy/plugin_var_tracker.h"
#include "base/ref_counted.h"
+#include "base/singleton.h"
#include "ppapi/c/ppb_var.h"
-#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/interface_id.h"
namespace pp {
namespace proxy {
@@ -32,28 +33,52 @@ class RefCountedString : public base::RefCounted<RefCountedString> {
// When running in the plugin, this will convert the string ID to the object
// using casting. No validity checking is done.
-RefCountedString* PluginStringFromID(int64 id) {
+RefCountedString* PluginStringFromID(PluginVarTracker::VarID id) {
return reinterpret_cast<RefCountedString*>(static_cast<intptr_t>(id));
}
} // namespace
-PluginVarTracker::PluginVarTracker(PluginDispatcher* dispatcher)
- : dispatcher_(dispatcher) {
+PluginVarTracker::HostVar::HostVar(Sender* d, VarID i)
+ : channel(d),
+ host_object_id(i) {
}
-PluginVarTracker::~PluginVarTracker() {}
+bool PluginVarTracker::HostVar::operator<(const HostVar& other) const {
+ if (channel < other.channel)
+ return true;
+ if (other.channel < channel)
+ return false;
+ return host_object_id < other.host_object_id;
+}
+
+PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var)
+ : host_var(host_var),
+ ref_count(0),
+ track_with_no_reference_count(0) {
+}
-int64 PluginVarTracker::MakeString(const std::string& str) {
+PluginVarTracker::PluginVarTracker() : last_plugin_object_id_(0) {
+}
+
+PluginVarTracker::~PluginVarTracker() {
+}
+
+PluginVarTracker* PluginVarTracker::GetInstance() {
+ return Singleton<PluginVarTracker>::get();
+}
+
+PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) {
RefCountedString* out = new RefCountedString(str);
out->AddRef();
- return static_cast<int64>(reinterpret_cast<intptr_t>(out));
+ return static_cast<VarID>(reinterpret_cast<intptr_t>(out));
}
-int64 PluginVarTracker::MakeString(const char* str, uint32_t len) {
+PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str,
+ uint32_t len) {
RefCountedString* out = new RefCountedString(str, len);
out->AddRef();
- return static_cast<int64>(reinterpret_cast<intptr_t>(out));
+ return static_cast<VarID>(reinterpret_cast<intptr_t>(out));
}
std::string PluginVarTracker::GetString(const PP_Var& var) const {
@@ -72,16 +97,20 @@ void PluginVarTracker::AddRef(const PP_Var& var) {
if (var.type == PP_VARTYPE_STRING) {
PluginStringFromID(var.value.as_id)->AddRef();
} else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) {
- int& ref_count = object_ref_count_[var.value.as_id];
- ref_count++;
- if (ref_count == 1) {
- // We must handle the case where we got requested to AddRef an object
- // that we've never seen before. This should tell the browser we've
- // taken a ref. This comes up when the browser passes an object as an
- // input param and holds a ref for us. We may not have seen that object
- // and the plugin handler may want to AddRef and release it internally.
- SendAddRefObjectMsg(var.value.as_id);
+ PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id);
+ if (found == plugin_var_info_.end()) {
+ NOTREACHED() << "Requesting to addref an unknown object.";
+ return;
+ }
+
+ PluginVarInfo& info = found->second;
+ if (info.ref_count == 0) {
+ // Got an AddRef for an object we have no existing reference for.
+ // We need to tell the browser we've taken a ref. This comes up when the
+ // browser passes an object as an input param and holds a ref for us.
+ SendAddRefObjectMsg(info.host_var);
}
+ info.ref_count++;
}
}
@@ -89,47 +118,168 @@ void PluginVarTracker::Release(const PP_Var& var) {
if (var.type == PP_VARTYPE_STRING) {
PluginStringFromID(var.value.as_id)->Release();
} else if (var.type == PP_VARTYPE_OBJECT) {
- ObjectRefCount::iterator found = object_ref_count_.find(var.value.as_id);
- if (found == object_ref_count_.end())
- return; // Invalid object.
- found->second--;
-
- if (found->second == 0) {
- // Plugin has released all of its refs, tell the browser.
- object_ref_count_.erase(found);
- SendReleaseObjectMsg(var.value.as_id);
+ PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id);
+ if (found == plugin_var_info_.end()) {
+ NOTREACHED() << "Requesting to release an unknown object.";
+ return;
}
+
+ PluginVarInfo& info = found->second;
+ if (info.ref_count == 0) {
+ NOTREACHED() << "Releasing an object with zero ref.";
+ return;
+ }
+
+ info.ref_count--;
+ if (info.ref_count == 0)
+ SendReleaseObjectMsg(info.host_var);
+ DeletePluginVarInfoIfNecessary(found);
}
}
-void PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var) {
- // We're the plugin and the renderer just sent us a ref. The renderer has
- // addrefed the var in its tracker for us since it's returning it.
- //
- // - If We don't have a reference to this already, then we just add it to
- // our tracker and use that one ref.
- //
- // - If we do already have a reference to it, that means the renderer now
- // has two references on our behalf. We want to transfer that extra
- // reference to our list. This means we addref in the plugin, and release
- // the extra one in the renderer.
- ObjectRefCount::iterator found = object_ref_count_.find(var.value.as_id);
- if (found == object_ref_count_.end()) {
- object_ref_count_[var.value.as_id] = 1;
+PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var,
+ Sender* channel) {
+ DCHECK(var.type == PP_VARTYPE_OBJECT);
+
+ // Find the plugin info.
+ PluginVarInfoMap::iterator found =
+ FindOrMakePluginVarFromHostVar(var, channel);
+ if (found == plugin_var_info_.end()) {
+ // The above code should have always made an entry in the map.
+ NOTREACHED();
+ return PP_MakeUndefined();
+ }
+
+ // Fix up the references. The host (renderer) just sent us a ref. The
+ // renderer has addrefed the var in its tracker for us since it's returning
+ // it.
+ PluginVarInfo& info = found->second;
+ if (info.ref_count == 0) {
+ // We don't have a reference to this already, then we just add it to our
+ // tracker and use that one ref.
+ info.ref_count = 1;
} else {
- SendReleaseObjectMsg(var.value.as_id);
- found->second++;
+ // We already have a reference to it, that means the renderer now has two
+ // references on our behalf. We want to transfer that extra reference to
+ // our list. This means we addref in the plugin, and release the extra one
+ // in the renderer.
+ SendReleaseObjectMsg(info.host_var);
+ info.ref_count++;
}
+
+ PP_Var ret;
+ ret.type = PP_VARTYPE_OBJECT;
+ ret.value.as_id = found->first;
+ return ret;
}
-void PluginVarTracker::SendAddRefObjectMsg(int64_t id) {
- dispatcher_->Send(new PpapiHostMsg_PPBVar_AddRefObject(
- INTERFACE_ID_PPB_VAR_DEPRECATED, id));
+PP_Var PluginVarTracker::TrackObjectWithNoReference(const PP_Var& host_var,
+ Sender* channel) {
+ DCHECK(host_var.type == PP_VARTYPE_OBJECT);
+
+ PluginVarInfoMap::iterator found =
+ FindOrMakePluginVarFromHostVar(host_var, channel);
+ if (found == plugin_var_info_.end()) {
+ // The above code should have always made an entry in the map.
+ NOTREACHED();
+ return PP_MakeUndefined();
+ }
+
+ found->second.track_with_no_reference_count++;
+
+ PP_Var ret;
+ ret.type = PP_VARTYPE_OBJECT;
+ ret.value.as_id = found->first;
+ return ret;
}
-void PluginVarTracker::SendReleaseObjectMsg(int64_t id) {
- dispatcher_->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
- INTERFACE_ID_PPB_VAR_DEPRECATED, id));
+void PluginVarTracker::StopTrackingObjectWithNoReference(
+ const PP_Var& plugin_var) {
+ DCHECK(plugin_var.type == PP_VARTYPE_OBJECT);
+ PluginVarInfoMap::iterator found = plugin_var_info_.find(
+ plugin_var.value.as_id);
+ if (found == plugin_var_info_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ found->second.track_with_no_reference_count--;
+ DeletePluginVarInfoIfNecessary(found);
+}
+
+PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const {
+ DCHECK(plugin_object.type == PP_VARTYPE_OBJECT);
+ PluginVarInfoMap::const_iterator found = plugin_var_info_.find(
+ plugin_object.value.as_id);
+ if (found == plugin_var_info_.end()) {
+ NOTREACHED();
+ return PP_MakeUndefined();
+ }
+ PP_Var ret;
+ ret.type = PP_VARTYPE_OBJECT;
+ ret.value.as_id = found->second.host_var.host_object_id;
+ return ret;
+}
+
+int PluginVarTracker::GetRefCountForObject(const PP_Var& plugin_object) {
+ PluginVarInfoMap::iterator found = plugin_var_info_.find(
+ plugin_object.value.as_id);
+ if (found == plugin_var_info_.end())
+ return -1;
+ return found->second.ref_count;
+}
+
+int PluginVarTracker::GetTrackedWithNoReferenceCountForObject(
+ const PP_Var& plugin_object) {
+ PluginVarInfoMap::iterator found = plugin_var_info_.find(
+ plugin_object.value.as_id);
+ if (found == plugin_var_info_.end())
+ return -1;
+ return found->second.track_with_no_reference_count;
+}
+
+void PluginVarTracker::SendAddRefObjectMsg(const HostVar& host_var) {
+ host_var.channel->Send(new PpapiHostMsg_PPBVar_AddRefObject(
+ INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id));
+}
+
+void PluginVarTracker::SendReleaseObjectMsg(const HostVar& host_var) {
+ host_var.channel->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
+ INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id));
+}
+
+PluginVarTracker::PluginVarInfoMap::iterator
+PluginVarTracker::FindOrMakePluginVarFromHostVar(const PP_Var& var,
+ Sender* channel) {
+ DCHECK(var.type == PP_VARTYPE_OBJECT);
+ HostVar host_var(channel, var.value.as_id);
+
+ HostVarToPluginVarMap::iterator found =
+ host_var_to_plugin_var_.find(host_var);
+ if (found != host_var_to_plugin_var_.end()) {
+ PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second);
+ DCHECK(ret != plugin_var_info_.end());
+ return ret; // Already know about this var return the ID.
+ }
+
+ // Make a new var, adding references to both maps.
+ VarID new_plugin_var_id = ++last_plugin_object_id_;
+ host_var_to_plugin_var_[host_var] = new_plugin_var_id;
+ return plugin_var_info_.insert(
+ std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first;
+}
+
+void PluginVarTracker::DeletePluginVarInfoIfNecessary(
+ PluginVarInfoMap::iterator iter) {
+ if (iter->second.ref_count != 0 ||
+ iter->second.track_with_no_reference_count != 0)
+ return; // Object still alive.
+
+ // Object ref counts are all zero, delete from both maps.
+ DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) !=
+ host_var_to_plugin_var_.end());
+ host_var_to_plugin_var_.erase(iter->second.host_var);
+ plugin_var_info_.erase(iter);
}
} // namesace proxy