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 #ifndef PPAPI_PROXY_ENTER_PROXY_H_
6 #define PPAPI_PROXY_ENTER_PROXY_H_
8 #include "base/logging.h"
9 #include "ppapi/cpp/completion_callback.h"
10 #include "ppapi/proxy/host_dispatcher.h"
11 #include "ppapi/proxy/plugin_dispatcher.h"
12 #include "ppapi/proxy/plugin_globals.h"
13 #include "ppapi/proxy/plugin_resource_tracker.h"
14 #include "ppapi/thunk/enter.h"
20 // Wrapper around EnterResourceNoLock that takes a host resource. This is used
21 // when handling messages in the plugin from the host and we need to convert to
22 // an object in the plugin side corresponding to that.
24 // This never locks since we assume the host Resource is coming from IPC, and
25 // never logs errors since we assume the host is doing reasonable things.
26 template<typename ResourceT
>
27 class EnterPluginFromHostResource
28 : public thunk::EnterResourceNoLock
<ResourceT
> {
30 explicit EnterPluginFromHostResource(const HostResource
& host_resource
)
31 : thunk::EnterResourceNoLock
<ResourceT
>(
32 PluginGlobals::Get()->plugin_resource_tracker()->
33 PluginResourceForHostResource(host_resource
),
35 // Validate that we're in the plugin rather than the host. Otherwise this
36 // object will do the wrong thing. In the plugin, the instance should have
37 // a corresponding plugin dispatcher (assuming the resource is valid).
38 DCHECK(this->failed() ||
39 PluginDispatcher::GetForInstance(host_resource
.instance()));
43 template<typename ResourceT
>
44 class EnterHostFromHostResource
45 : public thunk::EnterResourceNoLock
<ResourceT
> {
47 explicit EnterHostFromHostResource(const HostResource
& host_resource
)
48 : thunk::EnterResourceNoLock
<ResourceT
>(host_resource
.host_resource(),
50 // Validate that we're in the host rather than the plugin. Otherwise this
51 // object will do the wrong thing. In the host, the instance should have
52 // a corresponding host disptacher (assuming the resource is valid).
53 DCHECK(this->failed() ||
54 HostDispatcher::GetForInstance(host_resource
.instance()));
57 EnterHostFromHostResource(const HostResource
& host_resource
,
58 const pp::CompletionCallback
& callback
)
59 : thunk::EnterResourceNoLock
<ResourceT
>(host_resource
.host_resource(),
60 callback
.pp_completion_callback(),
62 // Validate that we're in the host rather than the plugin. Otherwise this
63 // object will do the wrong thing. In the host, the instance should have
64 // a corresponding host disptacher (assuming the resource is valid).
65 DCHECK(this->failed() ||
66 HostDispatcher::GetForInstance(host_resource
.instance()));
70 // Enters a resource and forces a completion callback to be issued.
72 // This is used when implementing the host (renderer) side of a resource
73 // function that issues a completion callback. In all cases, we need to issue
74 // the callback to avoid hanging the plugin.
76 // This class automatically constructs a callback with the given factory
77 // calling the given method. The method will generally be the one that sends
78 // the message to trigger the completion callback in the plugin process.
80 // It will automatically issue the callback with PP_ERROR_NOINTERFACE if the
81 // host resource is invalid (i.e. failed() is set). In all other cases you
82 // should call SetResult(), which will issue the callback immediately if the
83 // result value isn't PP_OK_COMPLETIONPENDING. In the "completion pending"
84 // case, it's assumed the function the proxy is calling will take responsibility
85 // of executing the callback (returned by callback()).
88 // EnterHostFromHostResourceForceCallback<PPB_Foo_API> enter(
89 // resource, callback_factory_, &MyClass::SendResult, resource);
90 // if (enter.failed())
91 // return; // SendResult automatically called with PP_ERROR_BADRESOURCE.
92 // enter.SetResult(enter.object()->DoFoo(enter.callback()));
94 // Where DoFoo's signature looks like this:
95 // int32_t DoFoo(PP_CompletionCallback callback);
96 // And SendResult's implementation looks like this:
97 // void MyClass::SendResult(int32_t result, const HostResource& res) {
98 // Send(new FooMsg_FooComplete(..., result, res));
100 template<typename ResourceT
>
101 class EnterHostFromHostResourceForceCallback
102 : public EnterHostFromHostResource
<ResourceT
> {
104 EnterHostFromHostResourceForceCallback(
105 const HostResource
& host_resource
,
106 const pp::CompletionCallback
& callback
)
107 : EnterHostFromHostResource
<ResourceT
>(host_resource
, callback
),
108 needs_running_(true) {
111 // For callbacks that take no parameters except the "int32_t result". Most
112 // implementations will use the 1-extra-argument constructor below.
113 template<class CallbackFactory
, typename Method
>
114 EnterHostFromHostResourceForceCallback(
115 const HostResource
& host_resource
,
116 CallbackFactory
& factory
,
118 : EnterHostFromHostResource
<ResourceT
>(host_resource
,
119 factory
.NewOptionalCallback(method
)),
120 needs_running_(true) {
122 RunCallback(PP_ERROR_BADRESOURCE
);
125 // For callbacks that take an extra parameter as a closure.
126 template<class CallbackFactory
, typename Method
, typename A
>
127 EnterHostFromHostResourceForceCallback(
128 const HostResource
& host_resource
,
129 CallbackFactory
& factory
,
132 : EnterHostFromHostResource
<ResourceT
>(host_resource
,
133 factory
.NewOptionalCallback(method
, a
)),
134 needs_running_(true) {
136 RunCallback(PP_ERROR_BADRESOURCE
);
139 // For callbacks that take two extra parameters as a closure.
140 template<class CallbackFactory
, typename Method
, typename A
, typename B
>
141 EnterHostFromHostResourceForceCallback(
142 const HostResource
& host_resource
,
143 CallbackFactory
& factory
,
147 : EnterHostFromHostResource
<ResourceT
>(host_resource
,
148 factory
.NewOptionalCallback(method
, a
, b
)),
149 needs_running_(true) {
151 RunCallback(PP_ERROR_BADRESOURCE
);
154 // For callbacks that take three extra parameters as a closure.
155 template<class CallbackFactory
, typename Method
, typename A
, typename B
,
157 EnterHostFromHostResourceForceCallback(
158 const HostResource
& host_resource
,
159 CallbackFactory
& factory
,
164 : EnterHostFromHostResource
<ResourceT
>(host_resource
,
165 factory
.NewOptionalCallback(method
, a
, b
, c
)),
166 needs_running_(true) {
168 RunCallback(PP_ERROR_BADRESOURCE
);
171 ~EnterHostFromHostResourceForceCallback() {
172 if (needs_running_
) {
173 NOTREACHED() << "Should always call SetResult except in the "
174 "initialization failed case.";
175 RunCallback(PP_ERROR_FAILED
);
179 void SetResult(int32_t result
) {
180 DCHECK(needs_running_
) << "Don't call SetResult when there already is one.";
181 if (result
!= PP_OK_COMPLETIONPENDING
)
183 needs_running_
= false;
184 // Either we already ran the callback, or it will be run asynchronously. We
185 // clear the callback so it isn't accidentally run again (and because
186 // EnterBase checks that the callback has been cleared).
187 this->ClearCallback();
191 void RunCallback(int32_t result
) {
192 DCHECK(needs_running_
);
193 needs_running_
= false;
194 this->callback()->Run(result
);
195 this->ClearCallback();
204 #endif // PPAPI_PROXY_ENTER_PROXY_H_