| 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
|
|
|