cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / ppapi / host / ppapi_host.cc
blobcbb989b5dc0c1fd4ba2822d90451577f11e98075
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/host/ppapi_host.h"
7 #include "base/logging.h"
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/host/host_factory.h"
10 #include "ppapi/host/host_message_context.h"
11 #include "ppapi/host/instance_message_filter.h"
12 #include "ppapi/host/resource_host.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/resource_message_params.h"
15 #include "ppapi/shared_impl/host_resource.h"
17 namespace ppapi {
18 namespace host {
20 namespace {
22 // Put a cap on the maximum number of resources so we don't explode if the
23 // renderer starts spamming us.
24 const size_t kMaxResourcesPerPlugin = 1 << 14;
26 } // namespace
28 PpapiHost::PpapiHost(IPC::Sender* sender,
29 const PpapiPermissions& perms)
30 : sender_(sender),
31 permissions_(perms),
32 next_pending_resource_host_id_(1) {
35 PpapiHost::~PpapiHost() {
36 // Delete these explicitly before destruction since then the host is still
37 // technically alive in case one of the filters accesses us from the
38 // destructor.
39 instance_message_filters_.clear();
41 // The resources may also want to use us in their destructors.
42 resources_.clear();
43 pending_resource_hosts_.clear();
46 bool PpapiHost::Send(IPC::Message* msg) {
47 return sender_->Send(msg);
50 bool PpapiHost::OnMessageReceived(const IPC::Message& msg) {
51 bool handled = true;
52 IPC_BEGIN_MESSAGE_MAP(PpapiHost, msg)
53 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCall,
54 OnHostMsgResourceCall)
55 IPC_MESSAGE_HANDLER(PpapiHostMsg_InProcessResourceCall,
56 OnHostMsgInProcessResourceCall)
57 IPC_MESSAGE_HANDLER_DELAY_REPLY(PpapiHostMsg_ResourceSyncCall,
58 OnHostMsgResourceSyncCall)
59 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCreated,
60 OnHostMsgResourceCreated)
61 IPC_MESSAGE_HANDLER(PpapiHostMsg_AttachToPendingHost,
62 OnHostMsgAttachToPendingHost)
63 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceDestroyed,
64 OnHostMsgResourceDestroyed)
65 IPC_MESSAGE_UNHANDLED(handled = false)
66 IPC_END_MESSAGE_MAP()
68 if (!handled) {
69 for (size_t i = 0; i < instance_message_filters_.size(); i++) {
70 if (instance_message_filters_[i]->OnInstanceMessageReceived(msg)) {
71 handled = true;
72 break;
77 return handled;
80 void PpapiHost::SendReply(const ReplyMessageContext& context,
81 const IPC::Message& msg) {
82 TRACE_EVENT2("ppapi proxy", "PpapiHost::SendReply",
83 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
84 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
85 if (context.sync_reply_msg) {
86 PpapiHostMsg_ResourceSyncCall::WriteReplyParams(context.sync_reply_msg,
87 context.params, msg);
88 Send(context.sync_reply_msg);
89 } else {
90 if (context.routing_id != MSG_ROUTING_NONE) {
91 Send(new PpapiHostMsg_InProcessResourceReply(context.routing_id,
92 context.params,
93 msg));
94 } else {
95 Send(new PpapiPluginMsg_ResourceReply(context.params, msg));
100 void PpapiHost::SendUnsolicitedReply(PP_Resource resource,
101 const IPC::Message& msg) {
102 TRACE_EVENT2("ppapi proxy", "PpapiHost::SendUnsolicitedReply",
103 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
104 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
105 DCHECK(resource); // If this fails, host is probably pending.
106 proxy::ResourceMessageReplyParams params(resource, 0);
107 Send(new PpapiPluginMsg_ResourceReply(params, msg));
110 scoped_ptr<ResourceHost> PpapiHost::CreateResourceHost(
111 const proxy::ResourceMessageCallParams& params,
112 PP_Instance instance,
113 const IPC::Message& nested_msg) {
114 scoped_ptr<ResourceHost> resource_host;
115 DCHECK(!host_factory_filters_.empty()); // Caller forgot to add a factory.
116 for (size_t i = 0; i < host_factory_filters_.size(); i++) {
117 resource_host = host_factory_filters_[i]->CreateResourceHost(
118 this, params, instance, nested_msg).Pass();
119 if (resource_host.get())
120 break;
122 return resource_host.Pass();
125 int PpapiHost::AddPendingResourceHost(scoped_ptr<ResourceHost> resource_host) {
126 // The resource ID should not be assigned.
127 if (!resource_host.get() || resource_host->pp_resource() != 0) {
128 NOTREACHED();
129 return 0;
132 if (pending_resource_hosts_.size() + resources_.size()
133 >= kMaxResourcesPerPlugin) {
134 return 0;
137 int pending_id = next_pending_resource_host_id_++;
138 pending_resource_hosts_[pending_id] =
139 linked_ptr<ResourceHost>(resource_host.release());
140 return pending_id;
143 void PpapiHost::AddHostFactoryFilter(scoped_ptr<HostFactory> filter) {
144 host_factory_filters_.push_back(filter.release());
147 void PpapiHost::AddInstanceMessageFilter(
148 scoped_ptr<InstanceMessageFilter> filter) {
149 instance_message_filters_.push_back(filter.release());
152 void PpapiHost::OnHostMsgResourceCall(
153 const proxy::ResourceMessageCallParams& params,
154 const IPC::Message& nested_msg) {
155 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCall",
156 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
157 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
158 HostMessageContext context(params);
159 HandleResourceCall(params, nested_msg, &context);
162 void PpapiHost::OnHostMsgInProcessResourceCall(
163 int routing_id,
164 const proxy::ResourceMessageCallParams& params,
165 const IPC::Message& nested_msg) {
166 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgInProcessResourceCall",
167 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
168 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
169 HostMessageContext context(routing_id, params);
170 HandleResourceCall(params, nested_msg, &context);
173 void PpapiHost::OnHostMsgResourceSyncCall(
174 const proxy::ResourceMessageCallParams& params,
175 const IPC::Message& nested_msg,
176 IPC::Message* reply_msg) {
177 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceSyncCall",
178 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
179 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
180 // Sync messages should always have callback set because they always expect
181 // a reply from the host.
182 DCHECK(params.has_callback());
183 // Stash the |reply_msg| in the context so that it can be used to reply
184 // to the sync message.
185 HostMessageContext context(params, reply_msg);
186 HandleResourceCall(params, nested_msg, &context);
189 void PpapiHost::HandleResourceCall(
190 const proxy::ResourceMessageCallParams& params,
191 const IPC::Message& nested_msg,
192 HostMessageContext* context) {
193 ResourceHost* resource_host = GetResourceHost(params.pp_resource());
194 if (resource_host) {
195 // CAUTION: Handling the message may cause the destruction of this object.
196 resource_host->HandleMessage(nested_msg, context);
197 } else {
198 if (context->params.has_callback()) {
199 ReplyMessageContext reply_context = context->MakeReplyMessageContext();
200 reply_context.params.set_result(PP_ERROR_BADRESOURCE);
201 SendReply(reply_context, context->reply_msg);
206 void PpapiHost::OnHostMsgResourceCreated(
207 const proxy::ResourceMessageCallParams& params,
208 PP_Instance instance,
209 const IPC::Message& nested_msg) {
210 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCreated",
211 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
212 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
214 if (pending_resource_hosts_.size() + resources_.size()
215 >= kMaxResourcesPerPlugin) {
216 return;
219 // Run through all filters until one grabs this message.
220 scoped_ptr<ResourceHost> resource_host = CreateResourceHost(params, instance,
221 nested_msg);
223 if (!resource_host.get()) {
224 NOTREACHED();
225 return;
228 // Resource should have been assigned a nonzero PP_Resource.
229 DCHECK(resource_host->pp_resource());
231 resources_[params.pp_resource()] =
232 linked_ptr<ResourceHost>(resource_host.release());
235 void PpapiHost::OnHostMsgAttachToPendingHost(PP_Resource pp_resource,
236 int pending_host_id) {
237 PendingHostResourceMap::iterator found =
238 pending_resource_hosts_.find(pending_host_id);
239 if (found == pending_resource_hosts_.end()) {
240 // Plugin sent a bad ID.
241 NOTREACHED();
242 return;
244 found->second->SetPPResourceForPendingHost(pp_resource);
245 resources_[pp_resource] = found->second;
246 pending_resource_hosts_.erase(found);
249 void PpapiHost::OnHostMsgResourceDestroyed(PP_Resource resource) {
250 ResourceMap::iterator found = resources_.find(resource);
251 if (found == resources_.end()) {
252 NOTREACHED();
253 return;
255 // Invoking the HostResource destructor might result in looking up the
256 // PP_Resource in resources_. std::map is not well specified as to whether the
257 // element will be there or not. Therefore, we delay destruction of the
258 // HostResource until after we've made sure the map no longer contains
259 // |resource|.
260 linked_ptr<ResourceHost> delete_at_end_of_scope(found->second);
261 resources_.erase(found);
264 ResourceHost* PpapiHost::GetResourceHost(PP_Resource resource) const {
265 ResourceMap::const_iterator found = resources_.find(resource);
266 return found == resources_.end() ? NULL : found->second.get();
269 } // namespace host
270 } // namespace ppapi