| // Copyright (c) 2012 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. | |
| #ifndef PPAPI_PROXY_ENTER_PROXY_H_ | |
| #define PPAPI_PROXY_ENTER_PROXY_H_ | |
| #include <stdint.h> | |
| #include "base/logging.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."; | |
| RunCallback(PP_ERROR_FAILED); | |
| } | |
| } | |
| 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_ |