1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PPAPI_PROXY_ENTER_PROXY_H_
#define PPAPI_PROXY_ENTER_PROXY_H_
#include <stdint.h>
#include "base/check.h"
#include "base/notreached.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/thunk/enter.h"
namespace ppapi {
namespace proxy {
// Wrapper around EnterResourceNoLock that takes a host resource. This is used
// when handling messages in the plugin from the host and we need to convert to
// an object in the plugin side corresponding to that.
//
// This never locks since we assume the host Resource is coming from IPC, and
// never logs errors since we assume the host is doing reasonable things.
template<typename ResourceT>
class EnterPluginFromHostResource
: public thunk::EnterResourceNoLock<ResourceT> {
public:
explicit EnterPluginFromHostResource(const HostResource& host_resource)
: thunk::EnterResourceNoLock<ResourceT>(
PluginGlobals::Get()->plugin_resource_tracker()->
PluginResourceForHostResource(host_resource),
false) {
// Validate that we're in the plugin rather than the host. Otherwise this
// object will do the wrong thing. In the plugin, the instance should have
// a corresponding plugin dispatcher (assuming the resource is valid).
DCHECK(this->failed() ||
PluginDispatcher::GetForInstance(host_resource.instance()));
}
};
template<typename ResourceT>
class EnterHostFromHostResource
: public thunk::EnterResourceNoLock<ResourceT> {
public:
explicit EnterHostFromHostResource(const HostResource& host_resource)
: thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
false) {
// Validate that we're in the host rather than the plugin. Otherwise this
// object will do the wrong thing. In the host, the instance should have
// a corresponding host disptacher (assuming the resource is valid).
DCHECK(this->failed() ||
HostDispatcher::GetForInstance(host_resource.instance()));
}
EnterHostFromHostResource(const HostResource& host_resource,
const pp::CompletionCallback& callback)
: thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
callback.pp_completion_callback(),
false) {
// Validate that we're in the host rather than the plugin. Otherwise this
// object will do the wrong thing. In the host, the instance should have
// a corresponding host disptacher (assuming the resource is valid).
DCHECK(this->failed() ||
HostDispatcher::GetForInstance(host_resource.instance()));
}
};
// Enters a resource and forces a completion callback to be issued.
//
// This is used when implementing the host (renderer) side of a resource
// function that issues a completion callback. In all cases, we need to issue
// the callback to avoid hanging the plugin.
//
// This class automatically constructs a callback with the given factory
// calling the given method. The method will generally be the one that sends
// the message to trigger the completion callback in the plugin process.
//
// It will automatically issue the callback with PP_ERROR_NOINTERFACE if the
// host resource is invalid (i.e. failed() is set). In all other cases you
// should call SetResult(), which will issue the callback immediately if the
// result value isn't PP_OK_COMPLETIONPENDING. In the "completion pending"
// case, it's assumed the function the proxy is calling will take responsibility
// of executing the callback (returned by callback()).
//
// Example:
// EnterHostFromHostResourceForceCallback<PPB_Foo_API> enter(
// resource, callback_factory_, &MyClass::SendResult, resource);
// if (enter.failed())
// return; // SendResult automatically called with PP_ERROR_BADRESOURCE.
// enter.SetResult(enter.object()->DoFoo(enter.callback()));
//
// Where DoFoo's signature looks like this:
// int32_t DoFoo(PP_CompletionCallback callback);
// And SendResult's implementation looks like this:
// void MyClass::SendResult(int32_t result, const HostResource& res) {
// Send(new FooMsg_FooComplete(..., result, res));
// }
template<typename ResourceT>
class EnterHostFromHostResourceForceCallback
: public EnterHostFromHostResource<ResourceT> {
public:
EnterHostFromHostResourceForceCallback(
const HostResource& host_resource,
const pp::CompletionCallback& callback)
: EnterHostFromHostResource<ResourceT>(host_resource, callback),
needs_running_(true) {
}
// For callbacks that take no parameters except the "int32_t result". Most
// implementations will use the 1-extra-argument constructor below.
template<class CallbackFactory, typename Method>
EnterHostFromHostResourceForceCallback(
const HostResource& host_resource,
CallbackFactory& factory,
Method method)
: EnterHostFromHostResource<ResourceT>(host_resource,
factory.NewOptionalCallback(method)),
needs_running_(true) {
if (this->failed())
RunCallback(PP_ERROR_BADRESOURCE);
}
// For callbacks that take an extra parameter as a closure.
template<class CallbackFactory, typename Method, typename A>
EnterHostFromHostResourceForceCallback(
const HostResource& host_resource,
CallbackFactory& factory,
Method method,
const A& a)
: EnterHostFromHostResource<ResourceT>(host_resource,
factory.NewOptionalCallback(method, a)),
needs_running_(true) {
if (this->failed())
RunCallback(PP_ERROR_BADRESOURCE);
}
// For callbacks that take two extra parameters as a closure.
template<class CallbackFactory, typename Method, typename A, typename B>
EnterHostFromHostResourceForceCallback(
const HostResource& host_resource,
CallbackFactory& factory,
Method method,
const A& a,
const B& b)
: EnterHostFromHostResource<ResourceT>(host_resource,
factory.NewOptionalCallback(method, a, b)),
needs_running_(true) {
if (this->failed())
RunCallback(PP_ERROR_BADRESOURCE);
}
// For callbacks that take three extra parameters as a closure.
template<class CallbackFactory, typename Method, typename A, typename B,
typename C>
EnterHostFromHostResourceForceCallback(
const HostResource& host_resource,
CallbackFactory& factory,
Method method,
const A& a,
const B& b,
const C& c)
: EnterHostFromHostResource<ResourceT>(host_resource,
factory.NewOptionalCallback(method, a, b, c)),
needs_running_(true) {
if (this->failed())
RunCallback(PP_ERROR_BADRESOURCE);
}
~EnterHostFromHostResourceForceCallback() {
if (needs_running_) {
NOTREACHED() << "Should always call SetResult except in the "
"initialization failed case.";
}
}
void SetResult(int32_t result) {
DCHECK(needs_running_) << "Don't call SetResult when there already is one.";
if (result != PP_OK_COMPLETIONPENDING)
RunCallback(result);
needs_running_ = false;
// Either we already ran the callback, or it will be run asynchronously. We
// clear the callback so it isn't accidentally run again (and because
// EnterBase checks that the callback has been cleared).
this->ClearCallback();
}
private:
void RunCallback(int32_t result) {
DCHECK(needs_running_);
needs_running_ = false;
this->callback()->Run(result);
this->ClearCallback();
}
bool needs_running_;
};
} // namespace proxy
} // namespace ppapi
#endif // PPAPI_PROXY_ENTER_PROXY_H_
|