Index: ppapi/proxy/enter_proxy.h |
=================================================================== |
--- ppapi/proxy/enter_proxy.h (revision 94913) |
+++ ppapi/proxy/enter_proxy.h (working copy) |
@@ -6,6 +6,7 @@ |
#define PPAPI_PROXY_ENTER_PROXY_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_resource_tracker.h" |
@@ -52,6 +53,95 @@ |
} |
}; |
+// 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: |
+ // 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), |
+ needs_running_(true), |
+ callback_(factory.NewOptionalCallback(method)) { |
+ 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), |
+ needs_running_(true), |
+ callback_(factory.NewOptionalCallback(method, a)) { |
+ 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) |
+ callback_.Run(result); |
+ } |
+ |
+ PP_CompletionCallback callback() { |
+ return callback_.pp_completion_callback(); |
+ } |
+ |
+ private: |
+ void RunCallback(int32_t result) { |
+ DCHECK(needs_running_); |
+ needs_running_ = false; |
+ callback_.Run(result); |
+ } |
+ |
+ bool needs_running_; |
+ pp::CompletionCallback callback_; |
+}; |
+ |
} // namespace proxy |
} // namespace pp |