// 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_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ #include "ppapi/cpp/completion_callback.h" #include "ppapi/utility/completion_callback_factory_thread_traits.h" /// @file /// This file defines the API to create CompletionCallback objects that are /// bound to member functions. namespace pp { // TypeUnwrapper -------------------------------------------------------------- namespace internal { // The TypeUnwrapper converts references and const references to the // underlying type used for storage and passing as an argument. It is for // internal use only. template <typename T> struct TypeUnwrapper { typedef T StorageType; }; template <typename T> struct TypeUnwrapper<T&> { typedef T StorageType; }; template <typename T> struct TypeUnwrapper<const T&> { typedef T StorageType; }; } // namespace internal // ---------------------------------------------------------------------------- /// CompletionCallbackFactory<T> may be used to create CompletionCallback /// objects that are bound to member functions. /// /// If a factory is destroyed, then any pending callbacks will be cancelled /// preventing any bound member functions from being called. The CancelAll() /// method allows pending callbacks to be cancelled without destroying the /// factory. /// /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't /// thread safe, but it is somewhat thread-friendly when used with a /// thread-safe traits class as the second template element. However, it /// only guarantees safety for creating a callback from another thread, the /// callback itself needs to execute on the same thread as the thread that /// creates/destroys the factory. With this restriction, it is safe to create /// the <code>CompletionCallbackFactory</code> on the main thread, create /// callbacks from any thread and pass them to CallOnMainThread(). /// /// <strong>Example: </strong> /// /// @code /// class MyClass { /// public: /// // If an compiler warns on following using |this| in the initializer /// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro. /// MyClass() : factory_(this) { /// } /// /// void OpenFile(const pp::FileRef& file) { /// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen); /// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc); /// CHECK(rv == PP_OK_COMPLETIONPENDING); /// } /// /// private: /// void DidOpen(int32_t result) { /// if (result == PP_OK) { /// // The file is open, and we can begin reading. /// // ... /// } else { /// // Failed to open the file with error given by 'result'. /// } /// } /// /// pp::CompletionCallbackFactory<MyClass> factory_; /// }; /// @endcode /// /// <strong>Passing additional parameters to your callback</strong> /// /// As a convenience, the <code>CompletionCallbackFactory</code> can optionally /// create a closure with up to three bound parameters that it will pass to /// your callback function. This can be useful for passing information about /// the request to your callback function, which is especially useful if your /// class has multiple asynchronous callbacks pending. /// /// For the above example, of opening a file, let's say you want to keep some /// description associated with your request, you might implement your OpenFile /// and DidOpen callback as follows: /// /// @code /// void OpenFile(const pp::FileRef& file) { /// std::string message = "Opening file!"; /// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen, /// message); /// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc); /// CHECK(rv == PP_OK_COMPLETIONPENDING); /// } /// void DidOpen(int32_t result, const std::string& message) { /// // "message" will be "Opening file!". /// ... /// } /// @endcode /// /// <strong>Optional versus required callbacks</strong> /// /// When you create an "optional" callback, the browser may return the results /// synchronously if they are available. This can allow for higher performance /// in some cases if data is available quickly (for example, for network loads /// where there may be a lot of data coming quickly). In this case, the /// callback will never be run. /// /// When creating a new callback with the factory, there will be data allocated /// on the heap that tracks the callback information and any bound arguments. /// This data is freed when the callback executes. In the case of optional /// callbacks, since the browser will never issue the callback, the internal /// tracking data will be leaked. /// /// Therefore, if you use optional callbacks, it's important to manually /// issue the callback to free up this data. The typical pattern is: /// /// @code /// pp::CompletionCallback callback = callback_factory.NewOptionalCallback( /// &MyClass::OnDataReady); /// int32_t result = interface->GetData(callback); /// if (result != PP_OK_COMPLETIONPENDING) /// callback.Run(result); /// @endcode /// /// Because of this additional complexity, it's generally recommended that /// you not use optional callbacks except when performance is more important /// (such as loading large resources from the network). In most other cases, /// the performance difference will not be worth the additional complexity, /// and most functions may never actually have the ability to complete /// synchronously. /// /// <strong>Completion callbacks with output</strong> /// /// For some API calls, the browser returns data to the caller via an output /// parameter. These can be difficult to manage since the output parameter /// must remain valid for as long as the callback is pending. Note also that /// CancelAll (or destroying the callback factory) does <i>not</i> cancel the /// callback from the browser's perspective, only the execution of the callback /// in the plugin code, and the output parameter will still be written to! /// This means that you can't use class members as output parameters without /// risking crashes. /// /// To make this case easier, the CompletionCallbackFactory can allocate and /// manage the output data for you and pass it to your callback function. This /// makes such calls more natural and less error-prone. /// /// To create such a callback, use NewCallbackWithOutput and specify a callback /// function that takes the output parameter as its second argument. Let's say /// you're calling a function GetFile which asynchronously returns a /// pp::FileRef. GetFile's signature will be <code>int32_t GetFile(const /// CompletionCallbackWithOutput<pp::FileRef>& callback);</code> and your /// calling code would look like this: /// /// @code /// void RequestFile() { /// file_interface->GetFile(callback_factory_.NewCallbackWithOutput( /// &MyClass::GotFile)); /// } /// void GotFile(int32_t result, const pp::FileRef& file) { /// if (result == PP_OK) { /// ...use file... /// } else { /// ...handle error... /// } /// } /// @endcode /// /// As with regular completion callbacks, you can optionally add up to three /// bound arguments. These are passed following the output argument. /// /// Your callback may take the output argument as a copy (common for small /// types like integers, a const reference (common for structures and /// resources to avoid an extra copy), or as a non-const reference. One /// optimization you can do if your callback function may take large arrays /// is to accept your output argument as a non-const reference and to swap() /// the argument with a vector of your own to store it. This means you don't /// have to copy the buffer to consume it. /// /// NewExtCallbackWithOutput is similar to NewCallbackWithOutput. It creates /// ext::ExtCompletionCallbackWithOutput instances which are used by APIs within /// the pp::ext namespace. template <typename T, typename ThreadTraits = ThreadSafeThreadTraits> class CompletionCallbackFactory { public: /// This constructor creates a <code>CompletionCallbackFactory</code> /// bound to an object. If the constructor is called without an argument, /// the default value of <code>NULL</code> is used. The user then must call /// Initialize() to initialize the object. /// /// param[in] object Optional parameter. An object whose member functions /// are to be bound to CompletionCallbacks created by this /// <code>CompletionCallbackFactory</code>. The default value of this /// parameter is <code>NULL</code>. explicit CompletionCallbackFactory(T* object = NULL) : object_(object) { // Assume that we don't need to lock since construction should be complete // before the pointer is used on another thread. InitBackPointer(); } /// Destructor. ~CompletionCallbackFactory() { // Assume that we don't need to lock since this object should not be used // from multiple threads during destruction. ResetBackPointer(); } /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from /// this factory. void CancelAll() { typename ThreadTraits::AutoLock lock(lock_); ResetBackPointer(); InitBackPointer(); } /// Initialize() binds the <code>CallbackFactory</code> to a particular /// object. Use this when the object is not available at /// <code>CallbackFactory</code> creation, and the <code>NULL</code> default /// is passed to the constructor. The object may only be initialized once, /// either by the constructor, or by a call to Initialize(). /// /// This class may not be used on any thread until initialization is complete. /// /// @param[in] object The object whose member functions are to be bound to /// the <code>CompletionCallback</code> created by this /// <code>CompletionCallbackFactory</code>. void Initialize(T* object) { PP_DCHECK(object); PP_DCHECK(!object_); // May only initialize once! object_ = object; } /// GetObject() returns the object that was passed at initialization to /// Intialize(). /// /// @return the object passed to the constructor or Intialize(). T* GetObject() { return object_; } /// NewCallback allocates a new, single-use <code>CompletionCallback</code>. /// The <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param[in] method The method to be invoked upon completion of the /// operation. /// /// @return A <code>CompletionCallback</code>. template <typename Method> CompletionCallback NewCallback(Method method) { return NewCallbackHelper(new Dispatcher0<Method>(method)); } /// NewOptionalCallback() allocates a new, single-use /// <code>CompletionCallback</code> that might not run if the method /// taking it can complete synchronously. Thus, if after passing the /// CompletionCallback to a Pepper method, the method does not return /// PP_OK_COMPLETIONPENDING, then you should manually call the /// CompletionCallback's Run method, or memory will be leaked. /// /// @param[in] method The method to be invoked upon completion of the /// operation. /// /// @return A <code>CompletionCallback</code>. template <typename Method> CompletionCallback NewOptionalCallback(Method method) { CompletionCallback cc = NewCallback(method); cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); return cc; } /// NewCallbackWithOutput() allocates a new, single-use /// <code>CompletionCallback</code> where the browser will pass an additional /// parameter containing the result of the request. The /// <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param[in] method The method to be invoked upon completion of the /// operation. /// /// @return A <code>CompletionCallback</code>. template <typename Output> CompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewCallbackWithOutput(void (T::*method)(int32_t, Output)) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef CompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput0< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output)> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method)); } /// Similar to NewCallbackWithOutput(), but returns an /// <code>ext::ExtCompletionCallbackWithOutput</code>. template <typename Output> ext::ExtCompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewExtCallbackWithOutput(void (T::*method)(int32_t, Output)) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef ext::ExtCompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput0< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output)> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method)); } /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>. /// The <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param[in] method The method to be invoked upon completion of the /// operation. Method should be of type: /// <code>void (T::*)(int32_t result, const A& a)</code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A> CompletionCallback NewCallback(Method method, const A& a) { return NewCallbackHelper(new Dispatcher1<Method, A>(method, a)); } /// NewOptionalCallback() allocates a new, single-use /// <code>CompletionCallback</code> that might not run if the method /// taking it can complete synchronously. Thus, if after passing the /// CompletionCallback to a Pepper method, the method does not return /// PP_OK_COMPLETIONPENDING, then you should manually call the /// CompletionCallback's Run method, or memory will be leaked. /// /// @param[in] method The method to be invoked upon completion of the /// operation. Method should be of type: /// <code>void (T::*)(int32_t result, const A& a)</code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A> CompletionCallback NewOptionalCallback(Method method, const A& a) { CompletionCallback cc = NewCallback(method, a); cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); return cc; } /// NewCallbackWithOutput() allocates a new, single-use /// <code>CompletionCallback</code> where the browser will pass an additional /// parameter containing the result of the request. The /// <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param[in] method The method to be invoked upon completion of the /// operation. /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Output, typename A> CompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewCallbackWithOutput(void (T::*method)(int32_t, Output, A), const A& a) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef CompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput1< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A), typename internal::TypeUnwrapper<A>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a)); } /// Similar to NewCallbackWithOutput(), but returns an /// <code>ext::ExtCompletionCallbackWithOutput</code>. template <typename Output, typename A> ext::ExtCompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewExtCallbackWithOutput(void (T::*method)(int32_t, Output, A), const A& a) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef ext::ExtCompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput1< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A), typename internal::TypeUnwrapper<A>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a)); } /// NewCallback() allocates a new, single-use /// <code>CompletionCallback</code>. /// The <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param method The method taking the callback. Method should be of type: /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A, typename B> CompletionCallback NewCallback(Method method, const A& a, const B& b) { return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b)); } /// NewOptionalCallback() allocates a new, single-use /// <code>CompletionCallback</code> that might not run if the method /// taking it can complete synchronously. Thus, if after passing the /// CompletionCallback to a Pepper method, the method does not return /// PP_OK_COMPLETIONPENDING, then you should manually call the /// CompletionCallback's Run method, or memory will be leaked. /// /// @param[in] method The method taking the callback. Method should be of /// type: /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A, typename B> CompletionCallback NewOptionalCallback(Method method, const A& a, const B& b) { CompletionCallback cc = NewCallback(method, a, b); cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); return cc; } /// NewCallbackWithOutput() allocates a new, single-use /// <code>CompletionCallback</code> where the browser will pass an additional /// parameter containing the result of the request. The /// <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param[in] method The method to be invoked upon completion of the /// operation. /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Output, typename A, typename B> CompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B), const A& a, const B& b) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef CompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput2< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A, B), typename internal::TypeUnwrapper<A>::StorageType, typename internal::TypeUnwrapper<B>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a, b)); } /// Similar to NewCallbackWithOutput(), but returns an /// <code>ext::ExtCompletionCallbackWithOutput</code>. template <typename Output, typename A, typename B> ext::ExtCompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewExtCallbackWithOutput(void (T::*method)(int32_t, Output, A, B), const A& a, const B& b) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef ext::ExtCompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput2< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A, B), typename internal::TypeUnwrapper<A>::StorageType, typename internal::TypeUnwrapper<B>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a, b)); } /// NewCallback() allocates a new, single-use /// <code>CompletionCallback</code>. /// The <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param method The method taking the callback. Method should be of type: /// <code> /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) /// </code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] c Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A, typename B, typename C> CompletionCallback NewCallback(Method method, const A& a, const B& b, const C& c) { return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c)); } /// NewOptionalCallback() allocates a new, single-use /// <code>CompletionCallback</code> that might not run if the method /// taking it can complete synchronously. Thus, if after passing the /// CompletionCallback to a Pepper method, the method does not return /// PP_OK_COMPLETIONPENDING, then you should manually call the /// CompletionCallback's Run method, or memory will be leaked. /// /// @param[in] method The method taking the callback. Method should be of /// type: /// <code> /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) /// </code> /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] c Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Method, typename A, typename B, typename C> CompletionCallback NewOptionalCallback(Method method, const A& a, const B& b, const C& c) { CompletionCallback cc = NewCallback(method, a, b, c); cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); return cc; } /// NewCallbackWithOutput() allocates a new, single-use /// <code>CompletionCallback</code> where the browser will pass an additional /// parameter containing the result of the request. The /// <code>CompletionCallback</code> must be run in order for the memory /// allocated by the methods to be freed. /// /// @param method The method to be run. /// /// @param[in] a Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] b Passed to <code>method</code> when the completion callback /// runs. /// /// @param[in] c Passed to <code>method</code> when the completion callback /// runs. /// /// @return A <code>CompletionCallback</code>. template <typename Output, typename A, typename B, typename C> CompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B, C), const A& a, const B& b, const C& c) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef CompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput3< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A, B, C), typename internal::TypeUnwrapper<A>::StorageType, typename internal::TypeUnwrapper<B>::StorageType, typename internal::TypeUnwrapper<C>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a, b, c)); } /// Similar to NewCallbackWithOutput(), but returns an /// <code>ext::ExtCompletionCallbackWithOutput</code>. template <typename Output, typename A, typename B, typename C> ext::ExtCompletionCallbackWithOutput< typename internal::TypeUnwrapper<Output>::StorageType> NewExtCallbackWithOutput(void (T::*method)(int32_t, Output, A, B, C), const A& a, const B& b, const C& c) { typedef typename internal::TypeUnwrapper<Output>::StorageType OutputStorageType; typedef ext::ExtCompletionCallbackWithOutput<OutputStorageType> CallbackType; typedef DispatcherWithOutput3< typename CallbackType::TraitsType, OutputStorageType, void (T::*)(int32_t, Output, A, B, C), typename internal::TypeUnwrapper<A>::StorageType, typename internal::TypeUnwrapper<B>::StorageType, typename internal::TypeUnwrapper<C>::StorageType> DispatcherType; return NewCallbackWithOutputHelper<CallbackType>( new DispatcherType(method, a, b, c)); } private: class BackPointer { public: typedef CompletionCallbackFactory<T, ThreadTraits> FactoryType; explicit BackPointer(FactoryType* factory) : factory_(factory) { } void AddRef() { ref_.AddRef(); } void Release() { if (ref_.Release() == 0) delete this; } void DropFactory() { factory_ = NULL; } T* GetObject() { return factory_ ? factory_->GetObject() : NULL; } private: typename ThreadTraits::RefCount ref_; FactoryType* factory_; }; template <typename Dispatcher> class CallbackData { public: // Takes ownership of the given dispatcher pointer. CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher) : back_pointer_(back_pointer), dispatcher_(dispatcher) { back_pointer_->AddRef(); } ~CallbackData() { back_pointer_->Release(); delete dispatcher_; } Dispatcher* dispatcher() { return dispatcher_; } static void Thunk(void* user_data, int32_t result) { Self* self = static_cast<Self*>(user_data); T* object = self->back_pointer_->GetObject(); // Please note that |object| may be NULL at this point. But we still need // to call into Dispatcher::operator() in that case, so that it can do // necessary cleanup. (*self->dispatcher_)(object, result); delete self; } private: typedef CallbackData<Dispatcher> Self; BackPointer* back_pointer_; // We own a ref to this refcounted object. Dispatcher* dispatcher_; // We own this pointer. // Disallow copying & assignment. CallbackData(const CallbackData<Dispatcher>&); CallbackData<Dispatcher>& operator=(const CallbackData<Dispatcher>&); }; template <typename Method> class Dispatcher0 { public: Dispatcher0() : method_(NULL) {} explicit Dispatcher0(Method method) : method_(method) { } void operator()(T* object, int32_t result) { if (object) (object->*method_)(result); } private: Method method_; }; template <typename Traits, typename Output, typename Method> class DispatcherWithOutput0 { public: typedef Output OutputType; DispatcherWithOutput0() : method_(NULL), output_() { Traits::Initialize(&output_); } DispatcherWithOutput0(Method method) : method_(method), output_() { Traits::Initialize(&output_); } void operator()(T* object, int32_t result) { // We must call Traits::StorageToPluginArg() even if we don't need to call // the callback anymore, otherwise we may leak resource or var references. if (object) (object->*method_)(result, Traits::StorageToPluginArg(output_)); else Traits::StorageToPluginArg(output_); } typename Traits::StorageType* output() { return &output_; } private: Method method_; typename Traits::StorageType output_; }; template <typename Method, typename A> class Dispatcher1 { public: Dispatcher1() : method_(NULL), a_() { } Dispatcher1(Method method, const A& a) : method_(method), a_(a) { } void operator()(T* object, int32_t result) { if (object) (object->*method_)(result, a_); } private: Method method_; A a_; }; template <typename Traits, typename Output, typename Method, typename A> class DispatcherWithOutput1 { public: typedef Output OutputType; DispatcherWithOutput1() : method_(NULL), a_(), output_() { Traits::Initialize(&output_); } DispatcherWithOutput1(Method method, const A& a) : method_(method), a_(a), output_() { Traits::Initialize(&output_); } void operator()(T* object, int32_t result) { // We must call Traits::StorageToPluginArg() even if we don't need to call // the callback anymore, otherwise we may leak resource or var references. if (object) (object->*method_)(result, Traits::StorageToPluginArg(output_), a_); else Traits::StorageToPluginArg(output_); } typename Traits::StorageType* output() { return &output_; } private: Method method_; A a_; typename Traits::StorageType output_; }; template <typename Method, typename A, typename B> class Dispatcher2 { public: Dispatcher2() : method_(NULL), a_(), b_() { } Dispatcher2(Method method, const A& a, const B& b) : method_(method), a_(a), b_(b) { } void operator()(T* object, int32_t result) { if (object) (object->*method_)(result, a_, b_); } private: Method method_; A a_; B b_; }; template <typename Traits, typename Output, typename Method, typename A, typename B> class DispatcherWithOutput2 { public: typedef Output OutputType; DispatcherWithOutput2() : method_(NULL), a_(), b_(), output_() { Traits::Initialize(&output_); } DispatcherWithOutput2(Method method, const A& a, const B& b) : method_(method), a_(a), b_(b), output_() { Traits::Initialize(&output_); } void operator()(T* object, int32_t result) { // We must call Traits::StorageToPluginArg() even if we don't need to call // the callback anymore, otherwise we may leak resource or var references. if (object) (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_); else Traits::StorageToPluginArg(output_); } typename Traits::StorageType* output() { return &output_; } private: Method method_; A a_; B b_; typename Traits::StorageType output_; }; template <typename Method, typename A, typename B, typename C> class Dispatcher3 { public: Dispatcher3() : method_(NULL), a_(), b_(), c_() { } Dispatcher3(Method method, const A& a, const B& b, const C& c) : method_(method), a_(a), b_(b), c_(c) { } void operator()(T* object, int32_t result) { if (object) (object->*method_)(result, a_, b_, c_); } private: Method method_; A a_; B b_; C c_; }; template <typename Traits, typename Output, typename Method, typename A, typename B, typename C> class DispatcherWithOutput3 { public: typedef Output OutputType; DispatcherWithOutput3() : method_(NULL), a_(), b_(), c_(), output_() { Traits::Initialize(&output_); } DispatcherWithOutput3(Method method, const A& a, const B& b, const C& c) : method_(method), a_(a), b_(b), c_(c), output_() { Traits::Initialize(&output_); } void operator()(T* object, int32_t result) { // We must call Traits::StorageToPluginArg() even if we don't need to call // the callback anymore, otherwise we may leak resource or var references. if (object) { (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_, c_); } else { Traits::StorageToPluginArg(output_); } } typename Traits::StorageType* output() { return &output_; } private: Method method_; A a_; B b_; C c_; typename Traits::StorageType output_; }; // Creates the back pointer object and takes a reference to it. This assumes // either that the lock is held or that it is not needed. void InitBackPointer() { back_pointer_ = new BackPointer(this); back_pointer_->AddRef(); } // Releases our reference to the back pointer object and clears the pointer. // This assumes either that the lock is held or that it is not needed. void ResetBackPointer() { back_pointer_->DropFactory(); back_pointer_->Release(); back_pointer_ = NULL; } // Takes ownership of the dispatcher pointer, which should be heap allocated. template <typename Dispatcher> CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) { typename ThreadTraits::AutoLock lock(lock_); PP_DCHECK(object_); // Expects a non-null object! return CompletionCallback( &CallbackData<Dispatcher>::Thunk, new CallbackData<Dispatcher>(back_pointer_, dispatcher)); } // Takes ownership of the dispatcher pointer, which should be heap allocated. template <typename Callback, typename Dispatcher> Callback NewCallbackWithOutputHelper(Dispatcher* dispatcher) { typename ThreadTraits::AutoLock lock(lock_); PP_DCHECK(object_); // Expects a non-null object! CallbackData<Dispatcher>* data = new CallbackData<Dispatcher>(back_pointer_, dispatcher); return Callback(&CallbackData<Dispatcher>::Thunk, data, data->dispatcher()->output()); } // Disallowed: CompletionCallbackFactory(const CompletionCallbackFactory&); CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); // Never changed once initialized so does not need protection by the lock. T* object_; // Protects the back pointer. typename ThreadTraits::Lock lock_; // Protected by the lock. This will get reset when you do CancelAll, for // example. BackPointer* back_pointer_; }; } // namespace pp #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_