summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 23:17:14 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 23:17:14 +0000
commite10b2b28a02d87eb9903966efd944790e3fc2877 (patch)
tree2c5b2db4d2a5f6421d4a6177dbb1b2265fd8800e
parent88bbd811149fdbe63150a2c7ed86d575c40644a3 (diff)
downloadchromium_src-e10b2b28a02d87eb9903966efd944790e3fc2877.zip
chromium_src-e10b2b28a02d87eb9903966efd944790e3fc2877.tar.gz
chromium_src-e10b2b28a02d87eb9903966efd944790e3fc2877.tar.bz2
Add C++ wrappers for output parameters.
Define helper routines for doing array output using the new PP_OutputArray struct. Define routines in the completion callback factory for doing output parameters as parameters to the callback function. BUG= TEST= Review URL: http://codereview.chromium.org/9651002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126781 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ppapi/cpp/array_output.cc34
-rw-r--r--ppapi/cpp/array_output.h260
-rw-r--r--ppapi/cpp/completion_callback.h97
-rw-r--r--ppapi/cpp/output_traits.h231
-rw-r--r--ppapi/ppapi_sources.gypi3
-rw-r--r--ppapi/utility/completion_callback_factory.h424
6 files changed, 998 insertions, 51 deletions
diff --git a/ppapi/cpp/array_output.cc b/ppapi/cpp/array_output.cc
new file mode 100644
index 0000000..4cb8c85
--- /dev/null
+++ b/ppapi/cpp/array_output.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "ppapi/cpp/array_output.h"
+
+#include "ppapi/cpp/logging.h"
+
+namespace pp {
+
+// static
+void* ArrayOutputAdapterBase::GetDataBufferThunk(void* user_data,
+ uint32_t element_count,
+ uint32_t element_size) {
+ return static_cast<ArrayOutputAdapterBase*>(user_data)->
+ GetDataBuffer(element_count, element_size);
+}
+
+VarArrayOutputAdapterWithStorage::VarArrayOutputAdapterWithStorage()
+ : ArrayOutputAdapter<PP_Var>() {
+ set_output(&temp_storage_);
+}
+
+std::vector<Var>& VarArrayOutputAdapterWithStorage::output() {
+ PP_DCHECK(output_storage_.empty());
+
+ output_storage_.reserve(temp_storage_.size());
+ for (size_t i = 0; i < temp_storage_.size(); i++)
+ output_storage_.push_back(Var(PASS_REF, temp_storage_[i]));
+ temp_storage_.clear();
+ return output_storage_;
+}
+
+} // namespace pp
diff --git a/ppapi/cpp/array_output.h b/ppapi/cpp/array_output.h
new file mode 100644
index 0000000..4441386
--- /dev/null
+++ b/ppapi/cpp/array_output.h
@@ -0,0 +1,260 @@
+// 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_CPP_ARRAY_OUTPUT_H_
+#define PPAPI_CPP_ARRAY_OUTPUT_H_
+
+#include <vector>
+
+#include "ppapi/c/pp_array_output.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/cpp/logging.h"
+#include "ppapi/cpp/pass_ref.h"
+#include "ppapi/cpp/var.h"
+
+namespace pp {
+
+// Converts the given array of PP_Resources into an array of the requested
+// C++ resource types, passing ownership of a reference in the process.
+//
+// This is used to convert output arrays of resources that the browser has
+// generated into the more convenient C++ wrappers for those resources. The
+// initial "PassRef" parameter is there to emphasize what happens to the
+// reference count of the input resource and to match the resource constructors
+// that look the same.
+template<typename ResourceObjectType>
+inline void ConvertPPResourceArrayToObjects(
+ PassRef,
+ const std::vector<PP_Resource>& input,
+ std::vector<ResourceObjectType>* output) {
+ output->resize(0);
+ output->reserve(input.size());
+ for (size_t i = 0; i < input.size(); i++)
+ output->push_back(ResourceObjectType(PASS_REF, input[i]));
+}
+
+// Non-templatized base class for the array output conversion. It provides the
+// C implementation of a PP_ArrayOutput whose callback function is implemented
+// as a virtual call on a derived class. Do not use directly, use one of the
+// derived classes below.
+class ArrayOutputAdapterBase {
+ public:
+ ArrayOutputAdapterBase() {
+ pp_array_output_.GetDataBuffer =
+ &ArrayOutputAdapterBase::GetDataBufferThunk;
+ pp_array_output_.user_data = this;
+ }
+ virtual ~ArrayOutputAdapterBase() {}
+
+ PP_ArrayOutput* pp_array_output() { return &pp_array_output_; }
+
+ protected:
+ virtual void* GetDataBuffer(uint32_t element_count,
+ uint32_t element_size) = 0;
+
+ private:
+ static void* GetDataBufferThunk(void* user_data,
+ uint32_t element_count,
+ uint32_t element_size);
+
+ PP_ArrayOutput pp_array_output_;
+
+ // Disallow copying and assignment. This will do the wrong thing for most
+ // subclasses.
+ ArrayOutputAdapterBase(const ArrayOutputAdapterBase&);
+ ArrayOutputAdapterBase& operator=(const ArrayOutputAdapterBase&);
+};
+
+// This adapter provides functionality for implementing a PP_ArrayOutput
+// structure as writing to a given vector object.
+//
+// This is generally used internally in the C++ wrapper objects to
+// write into an output parameter supplied by the plugin. If the element size
+// that the browser is writing does not match the size of the type we're using
+// this will assert and return NULL (which will cause the browser to fail the
+// call).
+//
+// Example that allows the browser to write into a given vector:
+// void DoFoo(std::vector<int>* results) {
+// ArrayOutputAdapter<int> adapter(results);
+// ppb_foo->DoFoo(adapter.pp_array_output());
+// }
+template<typename T>
+class ArrayOutputAdapter : public ArrayOutputAdapterBase {
+ public:
+ ArrayOutputAdapter(std::vector<T>* output) : output_(output) {}
+
+ protected:
+ // Two-step init for the "with storage" version below.
+ ArrayOutputAdapter() : output_(NULL) {}
+ void set_output(std::vector<T>* output) { output_ = output; }
+
+ // ArrayOutputAdapterBase implementation.
+ virtual void* GetDataBuffer(uint32_t element_count, uint32_t element_size) {
+ PP_DCHECK(element_size == sizeof(T));
+ if (element_size != sizeof(T))
+ return NULL;
+ output_->resize(element_count);
+ return &(*output_)[0];
+ }
+
+ private:
+ std::vector<T>* output_;
+};
+
+// This adapter provides functionality for implementing a PP_ArrayOutput
+// structure as writing resources to a given vector object.
+//
+// When returning an array of resources, the browser will write PP_Resources
+// via a PP_ArrayOutput. This code will automatically convert the PP_Resources
+// to the given wrapper type, (as long as that wrapper type supports the
+// correct constructor). The ownership of the resources that the browser passed
+// to us will be transferred to the C++ wrapper object.
+//
+// Conversion of the PP_Resources to the C++ wrapper object occurs in the
+// destructor. This object is intended to be used on the stack in a C++ wrapper
+// object for a call.
+//
+// Example:
+// void GetFiles(std::vector<pp::FileRef>* results) {
+// ResourceArrayOutputAdapter<pp::FileRef> adapter(results);
+// ppb_foo->DoFoo(adapter.pp_array_output());
+// }
+template<typename T>
+class ResourceArrayOutputAdapter : public ArrayOutputAdapterBase {
+ public:
+ explicit ResourceArrayOutputAdapter(std::vector<T>* output)
+ : output_(output) {
+ output_->resize(0);
+ }
+ virtual ~ResourceArrayOutputAdapter() {
+ ConvertPPResourceArrayToObjects(PASS_REF, intermediate_output_, output_);
+ }
+
+ protected:
+ // Two-step init for the "with storage" version below.
+ ResourceArrayOutputAdapter() : output_(NULL) {}
+ void set_output(T* output) { output_ = output; }
+
+ // ArrayOutputAdapterBase implementation.
+ virtual void* GetDataBuffer(uint32_t element_count,
+ uint32_t element_size) {
+ PP_DCHECK(element_size == sizeof(PP_Resource));
+ if (element_size != sizeof(PP_Resource))
+ return NULL;
+ intermediate_output_.resize(element_count);
+ return &intermediate_output_[0];
+ }
+
+ private:
+ std::vector<PP_Resource> intermediate_output_;
+ std::vector<T>* output_;
+};
+
+// This adapter is like the ArrayOutputAdapter except that it also contains
+// the underlying std::vector that will be populated (rather than writing it to
+// an object passed into the constructor).
+//
+// This is used by the CompletionCallbackFactory system to collect the output
+// parameters from an async function call. The collected data is then passed to
+// the plugins callback function.
+//
+// You can also use it directly if you want to have an array output and aren't
+// using the CompletionCallbackFactory. For example, if you're calling a
+// PPAPI function DoFoo that takes a PP_OutputArray that is supposed to be
+// writing integers, do this:
+//
+// ArrayOutputAdapterWithStorage<int> adapter;
+// ppb_foo->DoFoo(adapter.pp_output_array());
+// const std::vector<int>& result = adapter.output();
+template<typename T>
+class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> {
+ public:
+ ArrayOutputAdapterWithStorage() {
+ set_output(&output_storage_);
+ }
+
+ std::vector<T>& output() { return output_storage_; }
+
+ private:
+ std::vector<T> output_storage_;
+};
+
+// This adapter is like the ArrayOutputAdapterWithStorage except this
+// additionally converts PP_Var structs to pp::Var objects.
+//
+// You can also use it directly if you want to have an array output and aren't
+// using the CompletionCallbackFactory. For example, if you're calling a
+// PPAPI function GetVars that takes a PP_OutputArray that is supposed to be
+// writing PP_Vars, do this:
+//
+// VarArrayOutputAdapterWithStorage adapter;
+// ppb_foo->GetVars(adapter.pp_output_array());
+// const std::vector<pp::Var>& result = adapter.output().
+//
+// This one is non-inline since it's not templatized.
+class VarArrayOutputAdapterWithStorage : public ArrayOutputAdapter<PP_Var> {
+ public:
+ VarArrayOutputAdapterWithStorage();
+
+ // Returns the final array of resource objects, converting the PP_Vars
+ // written by the browser to pp::Var objects.
+ //
+ // This function should only be called once or we would end up converting
+ // the array more than once, which would mess up the refcounting.
+ std::vector<Var>& output();
+
+ private:
+ // The browser will write the PP_Vars into this array.
+ std::vector<PP_Var> temp_storage_;
+
+ // When asked for the output, the resources above will be converted to the
+ // C++ resource objects in this array for passing to the calling code.
+ std::vector<Var> output_storage_;
+};
+
+// This adapter is like the ArrayOutputAdapterWithStorage except this
+// additionally converts PP_Resources to C++ wrapper objects of the given type.
+//
+// You can also use it directly if you want to have an array output and aren't
+// using the CompletionCallbackFactory. For example, if you're calling a
+// PPAPI function GetFiles that takes a PP_OutputArray that is supposed to be
+// writing PP_Resources cooresponding to FileRefs, do this:
+//
+// ResourceArrayOutputAdapterWithStorage<FileRef> adapter;
+// ppb_foo->GetFiles(adapter.pp_output_array());
+// std::vector<FileRef> result = adapter.output().
+template<typename T>
+class ResourceArrayOutputAdapterWithStorage
+ : public ArrayOutputAdapter<PP_Resource> {
+ public:
+ ResourceArrayOutputAdapterWithStorage() {
+ set_output(&temp_storage_);
+ }
+
+ // Returns the final array of resource objects, converting the PP_Resources
+ // written by the browser to resource objects.
+ //
+ // This function should only be called once or we would end up converting
+ // the array more than once, which would mess up the refcounting.
+ std::vector<T>& output() {
+ PP_DCHECK(output_storage_.empty());
+
+ ConvertPPResourceArrayToObjects(PASS_REF, temp_storage_, &output_storage_);
+ temp_storage_.clear();
+ return output_storage_;
+ }
+
+ private:
+ // The browser will write the PP_Resources into this array.
+ std::vector<PP_Resource> temp_storage_;
+
+ // When asked for the output, the resources above will be converted to the
+ // C++ resource objects in this array for passing to the calling code.
+ std::vector<T> output_storage_;
+};
+
+} // namespace pp
+
+#endif // PPAPI_CPP_ARRAY_OUTPUT_H_
diff --git a/ppapi/cpp/completion_callback.h b/ppapi/cpp/completion_callback.h
index b4564e1..f1a20b3 100644
--- a/ppapi/cpp/completion_callback.h
+++ b/ppapi/cpp/completion_callback.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -9,13 +9,23 @@
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/logging.h"
#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/output_traits.h"
+
+struct PP_ArrayOutput;
/// @file
/// This file defines the API to create and run a callback.
namespace pp {
+template<typename T> class AsyncArrayOutputAdapter;
+template<typename T> class AsyncResourceArrayOutputAdapter;
+
/// This API enables you to implement and receive callbacks when
/// Pepper operations complete asynchronously.
+///
+/// You can create these objects yourself, but it is most common to use the
+/// CompletionCallbackFactory to allow the callbacks to call class member
+/// functions.
class CompletionCallback {
public:
/// The default constructor will create a blocking
@@ -148,6 +158,91 @@ class CompletionCallback {
PP_CompletionCallback cc_;
};
+/// A CompletionCallbackWithOutput defines a completion callback that
+/// additionally stores a pointer to some output data. Some C++ wrappers
+/// take a CompletionCallbackWithOutput when the browser is returning a
+/// bit of data as part of the function call. The "output" parameter
+/// stored in the CompletionCallbackWithOutput will receive the data from
+/// the browser.
+///
+/// You can create this yourself, but it is most common to use with the
+/// CompletionCallbackFactory's NewCallbackWithOutput, which manages the
+/// storage for the output parameter for you and passes it as an argument
+/// to your callback function.
+///
+/// Note that this class doesn't actually do anything with the output data,
+/// it just stores a pointer to it. C++ wrapper objects that accept a
+/// CompletionCallbackWithOutput will retrieve this pointer and pass it to
+/// the browser as the output parameter.
+template<typename T>
+class CompletionCallbackWithOutput : public CompletionCallback {
+ public:
+ /// The type that will actually be stored in the completion callback. In the
+ /// common case, this will be equal to the template parameter (for example,
+ /// CompletionCallbackWithOutput<int> would obviously take an int*. However,
+ /// resources are passed as PP_Resource, vars as PP_Var, and arrays as our
+ /// special ArrayOutputAdapter object. The CallbackOutputTraits defines
+ /// specializations for all of these cases.
+ typedef typename internal::CallbackOutputTraits<T>::StorageType
+ OutputStorageType;
+
+ /// The default constructor will create a blocking
+ /// <code>CompletionCallback</code> that references the given output
+ /// data.
+ ///
+ /// @param[in] output A pointer to the data associated with the callback. The
+ /// caller must ensure that this pointer outlives the completion callback.
+ ///
+ /// <strong>Note:</strong> Blocking completion callbacks are only allowed from
+ /// from background threads.
+ CompletionCallbackWithOutput(OutputStorageType* output)
+ : CompletionCallback(),
+ output_(output) {
+ }
+
+ /// A constructor for creating a <code>CompletionCallback</code> that
+ /// references the given output data.
+ ///
+ /// @param[in] user_data The user data to be passed to the callback function.
+ /// This is optional and is typically used to help track state in case of
+ /// multiple pending callbacks.
+ ///
+ /// @param[in] output A pointer to the data associated with the callback. The
+ /// caller must ensure that this pointer outlives the completion callback.
+ CompletionCallbackWithOutput(PP_CompletionCallback_Func func,
+ void* user_data,
+ OutputStorageType* output)
+ : CompletionCallback(func, user_data),
+ output_(output) {
+ }
+
+ /// A constructor for creating a <code>CompletionCallback</code> that
+ /// references the given output data.
+ ///
+ /// @param[in] user_data The user data to be passed to the callback function.
+ /// This is optional and is typically used to help track state in case of
+ /// multiple pending callbacks.
+ ///
+ /// @param[in] flags Bit field combination of
+ /// <code>PP_CompletionCallback_Flag</code> flags used to control how
+ /// non-NULL callbacks are scheduled by asynchronous methods.
+ ///
+ /// @param[in] output A pointer to the data associated with the callback. The
+ /// caller must ensure that this pointer outlives the completion callback.
+ CompletionCallbackWithOutput(PP_CompletionCallback_Func func,
+ void* user_data,
+ int32_t flags,
+ OutputStorageType* output)
+ : CompletionCallback(func, user_data, flags),
+ output_(output) {
+ }
+
+ OutputStorageType* output() const { return output_; }
+
+ private:
+ OutputStorageType* output_;
+};
+
/// BlockUntilComplete() is used in place of an actual completion callback
/// to request blocking behavior. If specified, the calling thread will block
/// until the function completes. Blocking completion callbacks are only
diff --git a/ppapi/cpp/output_traits.h b/ppapi/cpp/output_traits.h
new file mode 100644
index 0000000..6326c32
--- /dev/null
+++ b/ppapi/cpp/output_traits.h
@@ -0,0 +1,231 @@
+// 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_CPP_OUTPUT_TRAITS_H_
+#define PPAPI_CPP_OUTPUT_TRAITS_H_
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/cpp/array_output.h"
+
+/// @file
+/// This file defines internal templates for defining how data is passed to the
+/// browser via output parameters and how to convert that data to the
+/// corresponding C++ object types.
+///
+/// It is used by the callback system, it should not be necessary for end-users
+/// to use these templates directly.
+
+struct PP_Var;
+
+namespace pp {
+
+class Resource;
+class Var;
+
+namespace internal {
+
+// This goop is a trick used to implement a template that can be used to
+// determine if a given class is the base class of another given class. It is
+// used in the resource object partial specialization below.
+template<typename, typename> struct IsSame {
+ static bool const value = false;
+};
+template<typename A> struct IsSame<A, A> {
+ static bool const value = true;
+};
+template<typename Base, typename Derived> struct IsBaseOf {
+ static Derived* CreateDerived();
+ static char (&Check(Base*))[1];
+ static char (&Check(...))[2];
+ static bool const value = sizeof Check(CreateDerived()) == 1 &&
+ !IsSame<Base const, void const>::value;
+};
+
+// Template to optionally derive from a given base class T if the given
+// predicate P is true.
+template <class T, bool P> struct InheritIf {};
+template <class T> struct InheritIf<T, true> : public T {};
+
+// Single output parameters ----------------------------------------------------
+
+// Output traits for all "plain old data" (POD) types. It is implemented to
+// pass a pointer to the browser as an output parameter.
+//
+// This is used as a base class for the general CallbackOutputTraits below in
+// the case where T is not a resource.
+template<typename T>
+struct GenericCallbackOutputTraits {
+ // The type passed to the PPAPI C API for this parameter. For normal out
+ // params, we pass a pointer to the object so the browser can write into it.
+ typedef T* APIArgType;
+
+ // The type used to store the value. This is used internally in asynchronous
+ // callbacks by the CompletionCallbackFactory to have the browser write into
+ // a temporary value associated with the callback, which is passed to the
+ // plugin code when the callback is issued.
+ typedef T StorageType;
+
+ // Converts a "storage type" to a value that can be passed to the browser as
+ // an output parameter. This just takes the address to convert the value to
+ // a pointer.
+ static inline APIArgType StorageToAPIArg(StorageType& t) { return &t; }
+
+ // Converts the "storage type" to the value we pass to the plugin for
+ // callbacks. This doesn't actually need to do anything in this case,
+ // it's needed for some of more complex template specializations below.
+ static inline T& StorageToPluginArg(StorageType& t) { return t; }
+};
+
+// Output traits for all resource types. It is implemented to pass a
+// PP_Resource* as an output parameter to the browser, and convert to the
+// given resource object type T when passing to the plugin.
+//
+// Note that this class is parameterized by the resource object, for example
+// ResourceCallbackOutputTraits<pp::FileRef>. This is used as a base class for
+// CallbackOutputTraits below for the case where T is a derived class of
+// pp::Resource.
+template<typename T>
+struct ResourceCallbackOutputTraits {
+ // To call the browser, we just pass a PP_Resource pointer as the out param.
+ typedef PP_Resource* APIArgType;
+ typedef PP_Resource StorageType;
+
+ static inline APIArgType StorageToAPIArg(StorageType& t) {
+ return &t;
+ }
+
+ // Converts the PP_Resource to a pp::* object, passing any reference counted
+ // object along with it. This must only be called once since there will only
+ // be one reference that the browser has assigned to us for the out param!
+ // When calling into the plugin, convert the PP_Resource into the requested
+ // resource object type.
+ static inline T StorageToPluginArg(StorageType& t) {
+ return T(PASS_REF, t);
+ }
+};
+
+// The general templatized base class for all CallbackOutputTraits. This class
+// covers both resources and POD (ints, structs, etc.) by inheriting from the
+// appropriate base class depending on whether the given type derives from
+// pp::Resource. This trick allows us to do this once rather than writing
+// specializations for every resource object type.
+template<typename T>
+struct CallbackOutputTraits
+ : public InheritIf<GenericCallbackOutputTraits<T>,
+ !IsBaseOf<Resource, T>::value>,
+ public InheritIf<ResourceCallbackOutputTraits<T>,
+ IsBaseOf<Resource, T>::value> {
+};
+
+// A specialization of CallbackOutputTraits for pp::Var output parameters.
+// It passes a PP_Var* to the browser and converts to a pp::Var when passing
+// to the plugin.
+template<>
+struct CallbackOutputTraits<Var> {
+ // To call the browser, we just pass a PP_Var* as an output param.
+ typedef PP_Var* APIArgType;
+ typedef PP_Var StorageType;
+
+ static inline APIArgType StorageToAPIArg(StorageType& t) {
+ return &t;
+ }
+
+ // Converts the PP_Var to a pp::Var object, passing any reference counted
+ // object along with it. This must only be called once since there will only
+ // be one reference that the browser has assigned to us for the out param!
+ static inline pp::Var StorageToPluginArg(StorageType& t) {
+ return Var(PASS_REF, t);
+ }
+};
+
+// Array output parameters -----------------------------------------------------
+
+// Output traits for vectors of all "plain old data" (POD) types. It is
+// implemented to pass a pointer to the browser as an output parameter.
+//
+// This is used as a base class for the general vector CallbackOutputTraits
+// below in the case where T is not a resource.
+template<typename T>
+struct GenericVectorCallbackOutputTraits {
+ // All arrays are output via a PP_ArrayOutput type.
+ typedef PP_ArrayOutput* APIArgType;
+
+ // We store the array as this adapter which combines the PP_ArrayOutput
+ // structure with the underlying std::vector that it will write into.
+ typedef ArrayOutputAdapterWithStorage<T> StorageType;
+
+ // Retrieves the PP_ArrayOutput interface for our vector object that the
+ // browser will use to write into our code.
+ static inline APIArgType StorageToAPIArg(StorageType& t) {
+ return t.pp_array_output();
+ }
+
+ // Retrieves the underlying vector that can be passed to the plugin.
+ static inline std::vector<T>& StorageToPluginArg(StorageType& t) {
+ return t.output();
+ }
+};
+
+// Output traits for all vectors of resource types. It is implemented to pass
+// a PP_Resource* as an output parameter to the browser, and convert to the
+// given resource object type T when passing to the plugin.
+//
+// Note that this class is parameterized by the resource object, for example
+// ResourceVectorCallbackOutputTraits<pp::FileRef>. This is used as a base
+// class for CallbackOutputTraits below for the case where T is a derived
+// class of pp::Resource.
+template<typename T>
+struct ResourceVectorCallbackOutputTraits {
+ typedef PP_ArrayOutput* APIArgType;
+ typedef ResourceArrayOutputAdapterWithStorage<T> StorageType;
+
+ static inline APIArgType StorageToAPIArg(StorageType& t) {
+ return t.pp_array_output();
+ }
+ static inline std::vector<T>& StorageToPluginArg(StorageType& t) {
+ return t.output();
+ }
+};
+
+// Specialization of CallbackOutputTraits for vectors. This struct covers both
+// arrays of resources and arrays of POD (ints, structs, etc.) by inheriting
+// from the appropriate base class depending on whether the given type derives
+// from pp::Resource. This trick allows us to do this once rather than writing
+// specilalizations for every resource object type.
+template<typename T>
+struct CallbackOutputTraits< std::vector<T> >
+ : public InheritIf<GenericVectorCallbackOutputTraits<T>,
+ !IsBaseOf<Resource, T>::value>,
+ public InheritIf<ResourceVectorCallbackOutputTraits<T>,
+ IsBaseOf<Resource, T>::value> {
+};
+
+// A specialization of CallbackOutputTraits to provide the callback system
+// the information on how to handle vectors of pp::Var. Vectors of resources
+// and plain data are handled separately. See the above definition for more.
+template<>
+struct CallbackOutputTraits< std::vector<pp::Var> > {
+ // All arrays are output via a PP_ArrayOutput type.
+ typedef PP_ArrayOutput* APIArgType;
+
+ // We store the array as this adapter which combines the PP_ArrayOutput
+ // structure with the underlying std::vector that it will write into.
+ typedef VarArrayOutputAdapterWithStorage StorageType;
+
+ // Retrieves the PP_ArrayOutput interface for our vector object that the
+ // browser will use to write into our code.
+ static inline APIArgType StorageToAPIArg(StorageType& t) {
+ return t.pp_array_output();
+ }
+
+ // Retrieves the underlying vector that can be passed to the plugin.
+ static inline std::vector<pp::Var>& StorageToPluginArg(StorageType& t) {
+ return t.output();
+ }
+};
+
+} // namespace internal
+} // namespace pp
+
+#endif // PPAPI_CPP_OUTPUT_TRAITS_H_
diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi
index f32e2b6..98cabad 100644
--- a/ppapi/ppapi_sources.gypi
+++ b/ppapi/ppapi_sources.gypi
@@ -126,6 +126,8 @@
'c/trusted/ppp_broker.h',
],
'cpp_source_files': [
+ 'cpp/array_output.cc',
+ 'cpp/array_output.h',
'cpp/audio.cc',
'cpp/audio.h',
'cpp/audio_config.cc',
@@ -162,6 +164,7 @@
'cpp/module_impl.h',
'cpp/mouse_lock.cc',
'cpp/mouse_lock.h',
+ 'cpp/output_traits.h',
'cpp/point.h',
'cpp/rect.cc',
'cpp/rect.h',
diff --git a/ppapi/utility/completion_callback_factory.h b/ppapi/utility/completion_callback_factory.h
index e0b1f37..964cd02 100644
--- a/ppapi/utility/completion_callback_factory.h
+++ b/ppapi/utility/completion_callback_factory.h
@@ -10,6 +10,27 @@
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.
///
@@ -30,68 +51,137 @@ namespace pp {
/// <strong>Example: </strong>
///
/// @code
-///
-/// class MyHandler {
+/// class MyClass {
/// public:
/// // If an compiler warns on following using |this| in the initializer
/// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro.
-/// MyHandler() : factory_(this), offset_(0) {
+/// MyClass() : factory_(this) {
/// }
///
-/// void ProcessFile(const FileRef& file) {
-/// CompletionCallback cc = factory_.NewCallback(
-/// &MyHandler::DidOpen);
-/// int32_t rv = fio_.Open(file, PP_FileOpenFlag_Read, cc);
+/// 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:
-/// CompletionCallback NewCallback() {
-/// return factory_.NewCallback(&MyHandler::DidCompleteIO);
-/// }
-///
/// void DidOpen(int32_t result) {
/// if (result == PP_OK) {
/// // The file is open, and we can begin reading.
-/// offset_ = 0;
-/// ReadMore();
+/// // ...
/// } else {
/// // Failed to open the file with error given by 'result'.
/// }
/// }
///
-/// void DidRead(int32_t result) {
-/// if (result > 0) {
-/// // buf_ now contains 'result' number of bytes from the file.
-/// ProcessBytes(buf_, result);
-/// offset_ += result;
-/// ReadMore();
-/// } else {
-/// // Done reading (possibly with an error given by 'result').
-/// }
-/// }
+/// pp::CompletionCallbackFactory<MyClass> factory_;
+/// };
+/// @endcode
///
-/// void ReadMore() {
-/// CompletionCallback cc =
-/// factory_.NewOptionalCallback(&MyHandler::DidRead);
-/// int32_t rv = fio_.Read(offset_, buf_, sizeof(buf_),
-/// cc.pp_completion_callback());
-/// if (rv != PP_OK_COMPLETIONPENDING)
-/// cc.Run(rv);
-/// }
+/// <strong>Passing additional parameters to your callback</strong>
///
-/// void ProcessBytes(const char* bytes, int32_t length) {
-/// // Do work ...
-/// }
+/// 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.
///
-/// pp::CompletionCallbackFactory<MyHandler> factory_;
-/// pp::FileIO fio_;
-/// char buf_[4096];
-/// int64_t offset_;
-/// };
+/// 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 RefCount = NonThreadSafeRefCount>
class CompletionCallbackFactory {
public:
@@ -155,7 +245,7 @@ class CompletionCallbackFactory {
template <typename Method>
CompletionCallback NewCallback(Method method) {
PP_DCHECK(object_);
- return NewCallbackHelper(Dispatcher0<Method>(method));
+ return NewCallbackHelper(new Dispatcher0<Method>(method));
}
/// NewOptionalCallback() allocates a new, single-use
@@ -176,6 +266,25 @@ class CompletionCallbackFactory {
return cc;
}
+ /// NewCallbackWithOutput() allocates a new, single-use
+ /// <code>CompletionCallback</code> where the browser will pass an additional
+ /// parameter comtaining 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.
@@ -191,7 +300,7 @@ class CompletionCallbackFactory {
template <typename Method, typename A>
CompletionCallback NewCallback(Method method, const A& a) {
PP_DCHECK(object_);
- return NewCallbackHelper(Dispatcher1<Method, A>(method, a));
+ return NewCallbackHelper(new Dispatcher1<Method, A>(method, a));
}
/// NewOptionalCallback() allocates a new, single-use
@@ -216,6 +325,30 @@ class CompletionCallbackFactory {
return cc;
}
+ /// NewCallbackWithOutput() allocates a new, single-use
+ /// <code>CompletionCallback</code> where the browser will pass an additional
+ /// parameter comtaining 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
@@ -234,7 +367,7 @@ class CompletionCallbackFactory {
template <typename Method, typename A, typename B>
CompletionCallback NewCallback(Method method, const A& a, const B& b) {
PP_DCHECK(object_);
- return NewCallbackHelper(Dispatcher2<Method, A, B>(method, a, b));
+ return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
}
/// NewOptionalCallback() allocates a new, single-use
@@ -263,6 +396,35 @@ class CompletionCallbackFactory {
return cc;
}
+ /// NewCallbackWithOutput() allocates a new, single-use
+ /// <code>CompletionCallback</code> where the browser will pass an additional
+ /// parameter comtaining 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
@@ -287,7 +449,7 @@ class CompletionCallbackFactory {
CompletionCallback NewCallback(Method method, const A& a, const B& b,
const C& c) {
PP_DCHECK(object_);
- return NewCallbackHelper(Dispatcher3<Method, A, B, C>(method, a, b, c));
+ return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
}
/// NewOptionalCallback() allocates a new, single-use
@@ -321,12 +483,45 @@ class CompletionCallbackFactory {
return cc;
}
+ /// NewCallbackWithOutput() allocates a new, single-use
+ /// <code>CompletionCallback</code> where the browser will pass an additional
+ /// parameter comtaining 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, RefCount> FactoryType;
- BackPointer(FactoryType* factory)
+ explicit BackPointer(FactoryType* factory)
: factory_(factory) {
}
@@ -355,7 +550,8 @@ class CompletionCallbackFactory {
template <typename Dispatcher>
class CallbackData {
public:
- CallbackData(BackPointer* back_pointer, const Dispatcher& dispatcher)
+ // Takes ownership of the given dispatcher pointer.
+ CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher)
: back_pointer_(back_pointer),
dispatcher_(dispatcher) {
back_pointer_->AddRef();
@@ -363,26 +559,34 @@ class CompletionCallbackFactory {
~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();
if (object)
- self->dispatcher_(object, result);
+ (*self->dispatcher_)(object, result);
delete self;
}
private:
typedef CallbackData<Dispatcher> Self;
- BackPointer* back_pointer_;
- Dispatcher dispatcher_;
+ 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 method) : method_(method) {
+ Dispatcher0() : method_(NULL) {}
+ explicit Dispatcher0(Method method) : method_(method) {
}
void operator()(T* object, int32_t result) {
(object->*method_)(result);
@@ -391,9 +595,31 @@ class CompletionCallbackFactory {
Method method_;
};
+ template <typename Output, typename Method>
+ class DispatcherWithOutput0 {
+ public:
+ typedef Output OutputType;
+ typedef internal::CallbackOutputTraits<Output> Traits;
+
+ DispatcherWithOutput0() : method_(NULL) {}
+ DispatcherWithOutput0(Method method) : method_(method) {
+ }
+ void operator()(T* object, int32_t result) {
+ (object->*method_)(result, 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) {}
Dispatcher1(Method method, const A& a)
: method_(method),
a_(a) {
@@ -406,9 +632,34 @@ class CompletionCallbackFactory {
A a_;
};
+ template <typename Output, typename Method, typename A>
+ class DispatcherWithOutput1 {
+ public:
+ typedef Output OutputType;
+ typedef internal::CallbackOutputTraits<Output> Traits;
+
+ DispatcherWithOutput1() : method_(NULL) {}
+ DispatcherWithOutput1(Method method, const A& a)
+ : method_(method),
+ a_(a) {
+ }
+ void operator()(T* object, int32_t result) {
+ (object->*method_)(result, Traits::StorageToPluginArg(output_), a_);
+ }
+ 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) {}
Dispatcher2(Method method, const A& a, const B& b)
: method_(method),
a_(a),
@@ -423,9 +674,36 @@ class CompletionCallbackFactory {
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) {}
+ DispatcherWithOutput2(Method method, const A& a, const B& b)
+ : method_(method),
+ a_(a),
+ b_(b) {
+ }
+ void operator()(T* object, int32_t result) {
+ (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_);
+ }
+ 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) {}
Dispatcher3(Method method, const A& a, const B& b, const C& c)
: method_(method),
a_(a),
@@ -442,6 +720,36 @@ class CompletionCallbackFactory {
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) {}
+ DispatcherWithOutput3(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) {
+ (object->*method_)(result, Traits::StorageToPluginArg(output_),
+ a_, b_, c_);
+ }
+ typename Traits::StorageType* output() {
+ return &output_;
+ }
+ private:
+ Method method_;
+ A a_;
+ B b_;
+ C c_;
+
+ typename Traits::StorageType output_;
+ };
+
void InitBackPointer() {
back_pointer_ = new BackPointer(this);
back_pointer_->AddRef();
@@ -452,14 +760,30 @@ class CompletionCallbackFactory {
back_pointer_->Release();
}
+ // Takes ownership of the dispatcher pointer, which should be heap allocated.
template <typename Dispatcher>
- CompletionCallback NewCallbackHelper(const Dispatcher& dispatcher) {
+ CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
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) {
+ 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&);