| // 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 <stdint.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. |
| 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)) { |
| return NewCallbackWithOutputHelper(new DispatcherWithOutput0< |
| typename internal::TypeUnwrapper<Output>::StorageType, |
| void (T::*)(int32_t, Output)>(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) { |
| return NewCallbackWithOutputHelper(new DispatcherWithOutput1< |
| typename internal::TypeUnwrapper<Output>::StorageType, |
| void (T::*)(int32_t, Output, A), |
| typename internal::TypeUnwrapper<A>::StorageType>(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) { |
| return NewCallbackWithOutputHelper(new DispatcherWithOutput2< |
| typename internal::TypeUnwrapper<Output>::StorageType, |
| void (T::*)(int32_t, Output, A, B), |
| typename internal::TypeUnwrapper<A>::StorageType, |
| typename internal::TypeUnwrapper<B>::StorageType>(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) { |
| return NewCallbackWithOutputHelper(new DispatcherWithOutput3< |
| typename internal::TypeUnwrapper<Output>::StorageType, |
| void (T::*)(int32_t, Output, A, B, C), |
| typename internal::TypeUnwrapper<A>::StorageType, |
| typename internal::TypeUnwrapper<B>::StorageType, |
| typename internal::TypeUnwrapper<C>::StorageType>(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 Output, typename Method> |
| class DispatcherWithOutput0 { |
| public: |
| typedef Output OutputType; |
| typedef internal::CallbackOutputTraits<Output> Traits; |
| |
| 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 Output, typename Method, typename A> |
| class DispatcherWithOutput1 { |
| public: |
| typedef Output OutputType; |
| typedef internal::CallbackOutputTraits<Output> Traits; |
| |
| 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 Output, typename Method, typename A, typename B> |
| class DispatcherWithOutput2 { |
| public: |
| typedef Output OutputType; |
| typedef internal::CallbackOutputTraits<Output> Traits; |
| |
| 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 Output, typename Method, typename A, typename B, |
| typename C> |
| class DispatcherWithOutput3 { |
| public: |
| typedef Output OutputType; |
| typedef internal::CallbackOutputTraits<Output> Traits; |
| |
| 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 Dispatcher> CompletionCallbackWithOutput< |
| typename internal::TypeUnwrapper< |
| typename Dispatcher::OutputType>::StorageType> |
| 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 CompletionCallbackWithOutput<typename Dispatcher::OutputType>( |
| &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_ |