cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / ppapi / proxy / plugin_var_tracker.cc
blobee299852514c865e85e08b5554db8c6251334f68
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/proxy/plugin_var_tracker.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/singleton.h"
9 #include "ppapi/c/dev/ppp_class_deprecated.h"
10 #include "ppapi/c/ppb_var.h"
11 #include "ppapi/proxy/plugin_array_buffer_var.h"
12 #include "ppapi/proxy/plugin_dispatcher.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/proxy_object_var.h"
15 #include "ppapi/shared_impl/api_id.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/var.h"
19 namespace ppapi {
20 namespace proxy {
22 PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i)
23 : dispatcher(d),
24 host_object_id(i) {
27 bool PluginVarTracker::HostVar::operator<(const HostVar& other) const {
28 if (dispatcher < other.dispatcher)
29 return true;
30 if (other.dispatcher < dispatcher)
31 return false;
32 return host_object_id < other.host_object_id;
35 PluginVarTracker::PluginVarTracker() : VarTracker(THREAD_SAFE) {
38 PluginVarTracker::~PluginVarTracker() {
41 PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var,
42 PluginDispatcher* dispatcher) {
43 CheckThreadingPreconditions();
44 DCHECK(host_var.type == PP_VARTYPE_OBJECT);
46 // Get the object.
47 scoped_refptr<ProxyObjectVar> object(
48 FindOrMakePluginVarFromHostVar(host_var, dispatcher));
50 // Actually create the PP_Var, this will add all the tracking info but not
51 // adjust any refcounts.
52 PP_Var ret = GetOrCreateObjectVarID(object.get());
54 VarInfo& info = GetLiveVar(ret)->second;
55 if (info.ref_count > 0) {
56 // We already had a reference to it before. That means the renderer now has
57 // two references on our behalf. We want to transfer that extra reference
58 // to our list. This means we addref in the plugin, and release the extra
59 // one in the renderer.
60 SendReleaseObjectMsg(*object.get());
62 info.ref_count++;
63 return ret;
66 PP_Var PluginVarTracker::TrackObjectWithNoReference(
67 const PP_Var& host_var,
68 PluginDispatcher* dispatcher) {
69 CheckThreadingPreconditions();
70 DCHECK(host_var.type == PP_VARTYPE_OBJECT);
72 // Get the object.
73 scoped_refptr<ProxyObjectVar> object(
74 FindOrMakePluginVarFromHostVar(host_var, dispatcher));
76 // Actually create the PP_Var, this will add all the tracking info but not
77 // adjust any refcounts.
78 PP_Var ret = GetOrCreateObjectVarID(object.get());
80 VarInfo& info = GetLiveVar(ret)->second;
81 info.track_with_no_reference_count++;
82 return ret;
85 void PluginVarTracker::StopTrackingObjectWithNoReference(
86 const PP_Var& plugin_var) {
87 CheckThreadingPreconditions();
88 DCHECK(plugin_var.type == PP_VARTYPE_OBJECT);
90 VarMap::iterator found = GetLiveVar(plugin_var);
91 if (found == live_vars_.end()) {
92 NOTREACHED();
93 return;
96 DCHECK(found->second.track_with_no_reference_count > 0);
97 found->second.track_with_no_reference_count--;
98 DeleteObjectInfoIfNecessary(found);
101 PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const {
102 CheckThreadingPreconditions();
103 if (plugin_object.type != PP_VARTYPE_OBJECT) {
104 NOTREACHED();
105 return PP_MakeUndefined();
108 Var* var = GetVar(plugin_object);
109 ProxyObjectVar* object = var->AsProxyObjectVar();
110 if (!object) {
111 NOTREACHED();
112 return PP_MakeUndefined();
115 // Make a var with the host ID.
116 PP_Var ret = { PP_VARTYPE_OBJECT };
117 ret.value.as_id = object->host_var_id();
118 return ret;
121 PluginDispatcher* PluginVarTracker::DispatcherForPluginObject(
122 const PP_Var& plugin_object) const {
123 CheckThreadingPreconditions();
124 if (plugin_object.type != PP_VARTYPE_OBJECT)
125 return NULL;
127 VarMap::const_iterator found = GetLiveVar(plugin_object);
128 if (found == live_vars_.end())
129 return NULL;
131 ProxyObjectVar* object = found->second.var->AsProxyObjectVar();
132 if (!object)
133 return NULL;
134 return object->dispatcher();
137 void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher,
138 const PP_Var& host_object) {
139 CheckThreadingPreconditions();
140 DCHECK(host_object.type == PP_VARTYPE_OBJECT);
142 // Convert the host object to a normal var valid in the plugin.
143 HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find(
144 HostVar(dispatcher, static_cast<int32>(host_object.value.as_id)));
145 if (found == host_var_to_plugin_var_.end()) {
146 NOTREACHED();
147 return;
150 // Now just release the object given the plugin var ID.
151 ReleaseVar(found->second);
154 void PluginVarTracker::DidDeleteInstance(PP_Instance instance) {
155 // Calling the destructors on plugin objects may in turn release other
156 // objects which will mutate the map out from under us. So do a two-step
157 // process of identifying the ones to delete, and then delete them.
159 // See the comment above user_data_to_plugin_ in the header file. We assume
160 // there aren't that many objects so a brute-force search is reasonable.
161 std::vector<void*> user_data_to_delete;
162 for (UserDataToPluginImplementedVarMap::const_iterator i =
163 user_data_to_plugin_.begin();
164 i != user_data_to_plugin_.end();
165 ++i) {
166 if (i->second.instance == instance)
167 user_data_to_delete.push_back(i->first);
170 for (size_t i = 0; i < user_data_to_delete.size(); i++) {
171 UserDataToPluginImplementedVarMap::iterator found =
172 user_data_to_plugin_.find(user_data_to_delete[i]);
173 if (found == user_data_to_plugin_.end())
174 continue; // Object removed from list while we were iterating.
176 if (!found->second.plugin_object_id) {
177 // This object is for the freed instance and the plugin is not holding
178 // any references to it. Deallocate immediately.
179 CallWhileUnlocked(found->second.ppp_class->Deallocate, found->first);
180 user_data_to_plugin_.erase(found);
181 } else {
182 // The plugin is holding refs to this object. We don't want to call
183 // Deallocate since the plugin may be depending on those refs to keep
184 // its data alive. To avoid crashes in this case, just clear out the
185 // instance to mark it and continue. When the plugin refs go to 0,
186 // we'll notice there is no instance and call Deallocate.
187 found->second.instance = 0;
192 void PluginVarTracker::DidDeleteDispatcher(PluginDispatcher* dispatcher) {
193 for (VarMap::iterator it = live_vars_.begin();
194 it != live_vars_.end();
195 ++it) {
196 if (it->second.var.get() == NULL)
197 continue;
198 ProxyObjectVar* object = it->second.var->AsProxyObjectVar();
199 if (object && object->dispatcher() == dispatcher)
200 object->clear_dispatcher();
204 ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
205 return new PluginArrayBufferVar(size_in_bytes);
208 ArrayBufferVar* PluginVarTracker::CreateShmArrayBuffer(
209 uint32 size_in_bytes,
210 base::SharedMemoryHandle handle) {
211 return new PluginArrayBufferVar(size_in_bytes, handle);
214 void PluginVarTracker::PluginImplementedObjectCreated(
215 PP_Instance instance,
216 const PP_Var& created_var,
217 const PPP_Class_Deprecated* ppp_class,
218 void* ppp_class_data) {
219 PluginImplementedVar p;
220 p.ppp_class = ppp_class;
221 p.instance = instance;
222 p.plugin_object_id = created_var.value.as_id;
223 user_data_to_plugin_[ppp_class_data] = p;
225 // Link the user data to the object.
226 ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar();
227 object->set_user_data(ppp_class_data);
230 void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) {
231 UserDataToPluginImplementedVarMap::iterator found =
232 user_data_to_plugin_.find(user_data);
233 if (found == user_data_to_plugin_.end()) {
234 NOTREACHED();
235 return;
237 user_data_to_plugin_.erase(found);
240 bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) {
241 return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end();
244 bool PluginVarTracker::ValidatePluginObjectCall(
245 const PPP_Class_Deprecated* ppp_class,
246 void* user_data) {
247 UserDataToPluginImplementedVarMap::iterator found =
248 user_data_to_plugin_.find(user_data);
249 if (found == user_data_to_plugin_.end())
250 return false;
251 return found->second.ppp_class == ppp_class;
254 int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
255 // Normal adding.
256 int32 new_id = VarTracker::AddVarInternal(var, mode);
258 // Need to add proxy objects to the host var map.
259 ProxyObjectVar* proxy_object = var->AsProxyObjectVar();
260 if (proxy_object) {
261 HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id());
262 DCHECK(host_var_to_plugin_var_.find(host_var) ==
263 host_var_to_plugin_var_.end()); // Adding an object twice, use
264 // FindOrMakePluginVarFromHostVar.
265 host_var_to_plugin_var_[host_var] = new_id;
267 return new_id;
270 void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) {
271 ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
272 if (!object) {
273 NOTREACHED();
274 return;
277 DCHECK(iter->second.ref_count == 0);
279 // Got an AddRef for an object we have no existing reference for.
280 // We need to tell the browser we've taken a ref. This comes up when the
281 // browser passes an object as an input param and holds a ref for us.
282 // This must be a sync message since otherwise the "addref" will actually
283 // occur after the return to the browser of the sync function that
284 // presumably sent the object.
285 SendAddRefObjectMsg(*object);
288 void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
289 ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
290 if (!object) {
291 NOTREACHED();
292 return;
295 // Notify the host we're no longer holding our ref.
296 DCHECK(iter->second.ref_count == 0);
297 SendReleaseObjectMsg(*object);
299 UserDataToPluginImplementedVarMap::iterator found =
300 user_data_to_plugin_.find(object->user_data());
301 if (found != user_data_to_plugin_.end()) {
302 // This object is implemented in the plugin.
303 if (found->second.instance == 0) {
304 // Instance is destroyed. This means that we'll never get a Deallocate
305 // call from the renderer and we should do so now.
306 found->second.ppp_class->Deallocate(found->first);
307 user_data_to_plugin_.erase(found);
308 } else {
309 // The plugin is releasing its last reference to an object it implements.
310 // Clear the tracking data that links our "plugin implemented object" to
311 // the var. If the instance is destroyed and there is no ID, we know that
312 // we should just call Deallocate on the object data.
314 // See the plugin_object_id declaration for more info.
315 found->second.plugin_object_id = 0;
319 // This will optionally delete the info from live_vars_.
320 VarTracker::ObjectGettingZeroRef(iter);
323 bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
324 // Get the info before calling the base class's version of this function,
325 // which may delete the object.
326 ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
327 HostVar host_var(object->dispatcher(), object->host_var_id());
329 if (!VarTracker::DeleteObjectInfoIfNecessary(iter))
330 return false;
332 // Clean up the host var mapping.
333 DCHECK(host_var_to_plugin_var_.find(host_var) !=
334 host_var_to_plugin_var_.end());
335 host_var_to_plugin_var_.erase(host_var);
336 return true;
339 PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) {
340 // We can't use object->GetPPVar() because we don't want to affect the
341 // refcount, so we have to add everything manually here.
342 int32 var_id = object->GetExistingVarID();
343 if (!var_id) {
344 var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE);
345 object->AssignVarID(var_id);
348 PP_Var ret = { PP_VARTYPE_OBJECT };
349 ret.value.as_id = var_id;
350 return ret;
353 void PluginVarTracker::SendAddRefObjectMsg(
354 const ProxyObjectVar& proxy_object) {
355 int unused;
356 if (proxy_object.dispatcher()) {
357 proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject(
358 API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused));
362 void PluginVarTracker::SendReleaseObjectMsg(
363 const ProxyObjectVar& proxy_object) {
364 if (proxy_object.dispatcher()) {
365 proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
366 API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id()));
370 scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar(
371 const PP_Var& var,
372 PluginDispatcher* dispatcher) {
373 DCHECK(var.type == PP_VARTYPE_OBJECT);
374 HostVar host_var(dispatcher, var.value.as_id);
376 HostVarToPluginVarMap::iterator found =
377 host_var_to_plugin_var_.find(host_var);
378 if (found == host_var_to_plugin_var_.end()) {
379 // Create a new object.
380 return scoped_refptr<ProxyObjectVar>(
381 new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id)));
384 // Have this host var, look up the object.
385 VarMap::iterator ret = live_vars_.find(found->second);
386 DCHECK(ret != live_vars_.end());
388 // All objects should be proxy objects.
389 DCHECK(ret->second.var->AsProxyObjectVar());
390 return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar());
393 int PluginVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
394 base::SharedMemoryHandle handle,
395 uint32 size_in_bytes) {
396 NOTREACHED();
397 return -1;
400 bool PluginVarTracker::StopTrackingSharedMemoryHandle(
401 int id,
402 PP_Instance instance,
403 base::SharedMemoryHandle* handle,
404 uint32* size_in_bytes) {
405 NOTREACHED();
406 return false;
409 } // namesace proxy
410 } // namespace ppapi