Index: ppapi/proxy/plugin_var_tracker.cc |
=================================================================== |
--- ppapi/proxy/plugin_var_tracker.cc (revision 71973) |
+++ ppapi/proxy/plugin_var_tracker.cc (working copy) |
@@ -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 @@ |
// 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; |
+} |
-int64 PluginVarTracker::MakeString(const std::string& str) { |
+PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) |
+ : host_var(host_var), |
+ ref_count(0), |
+ track_with_no_reference_count(0) { |
+} |
+ |
+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 @@ |
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,48 +118,169 @@ |
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--; |
+ 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; |
+ } |
- if (found->second == 0) { |
- // Plugin has released all of its refs, tell the browser. |
- object_ref_count_.erase(found); |
- SendReleaseObjectMsg(var.value.as_id); |
+ 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 |
} // namespace pp |