diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-26 22:21:59 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-26 22:21:59 +0000 |
commit | 11f515acdda3473200ff0cc4106a0020a7d4dc74 (patch) | |
tree | cdfd9713928d6f0fa73b5cd7bedbd965fc93e329 /ppapi | |
parent | f60d96e82acd547ac834b93cd68865b66ab5b4da (diff) | |
download | chromium_src-11f515acdda3473200ff0cc4106a0020a7d4dc74.zip chromium_src-11f515acdda3473200ff0cc4106a0020a7d4dc74.tar.gz chromium_src-11f515acdda3473200ff0cc4106a0020a7d4dc74.tar.bz2 |
New file chooser interface that uses the new PP_ArrayOutput feature. This also changes PP_ArrayOutput to be pass-by-value.
This keeps backwards compat for the old interface. It fixes some bugs in the callback system that I found when working on the patch and adds some new machinery for doing array output in the proxy. It also re-enables the file chooser feature which was recently broken.
BUG=118857
Review URL: https://chromiumcodereview.appspot.com/9728001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129022 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
28 files changed, 797 insertions, 172 deletions
diff --git a/ppapi/api/dev/ppb_file_chooser_dev.idl b/ppapi/api/dev/ppb_file_chooser_dev.idl index 980df57..425154b 100644 --- a/ppapi/api/dev/ppb_file_chooser_dev.idl +++ b/ppapi/api/dev/ppb_file_chooser_dev.idl @@ -9,7 +9,8 @@ */ label Chrome { - M16 = 0.5 + M16 = 0.5, + M19 = 0.6 }; /** @@ -80,6 +81,7 @@ interface PPB_FileChooser_Dev { * @return PP_OK_COMPLETIONPENDING if request to show the dialog was * successful, another error code from pp_errors.h on failure. */ + [deprecate=0.6] int32_t Show( [in] PP_Resource chooser, [in] PP_CompletionCallback callback); @@ -96,7 +98,33 @@ interface PPB_FileChooser_Dev { * @return A <code>PP_Resource</code> containing the next file chosen by the * user, or 0 if there are no more files. */ + [deprecate=0.6] PP_Resource GetNextChosenFile( [in] PP_Resource chooser); + + /** + * This function displays a previously created file chooser resource as a + * dialog box, prompting the user to choose a file or files. This function + * must be called in response to a user gesture, such as a mouse click or + * touch event. The callback is called with PP_OK on successful completion + * with a file (or files) selected, PP_ERROR_USERCANCEL if the user selected + * no file, or another error code from pp_errors.h on failure. + * + * @param[in] chooser The file chooser resource. + * + * @param[in] output An output array which will receive PP_Resource(s) + * identifying the <code>PPB_FileRef</code> objects that the user selected on + * success. + * + * @param[in] callback A <code>CompletionCallback</code> to be called after + * the user has closed the file chooser dialog. + * + * @return PP_OK_COMPLETIONPENDING if request to show the dialog was + * successful, another error code from pp_errors.h on failure. + */ + [version=0.6] + int32_t Show([in] PP_Resource chooser, + [in] PP_ArrayOutput output, + [in] PP_CompletionCallback callback); }; diff --git a/ppapi/api/pp_array_output.idl b/ppapi/api/pp_array_output.idl index 46411d8..b3b508a 100644 --- a/ppapi/api/pp_array_output.idl +++ b/ppapi/api/pp_array_output.idl @@ -75,6 +75,7 @@ typedef mem_t PP_ArrayOutput_GetDataBuffer([inout] mem_t user_data, * } * @endcode */ +[passByValue] struct PP_ArrayOutput { /** * A pointer to the allocation function that the browser implements. diff --git a/ppapi/api/trusted/ppb_file_chooser_trusted.idl b/ppapi/api/trusted/ppb_file_chooser_trusted.idl index d921c81..3d9aea0 100644 --- a/ppapi/api/trusted/ppb_file_chooser_trusted.idl +++ b/ppapi/api/trusted/ppb_file_chooser_trusted.idl @@ -9,7 +9,8 @@ */ label Chrome { - M16 = 0.5 + M16 = 0.5, + M20 = 0.6 }; [macro="PPB_FILECHOOSER_TRUSTED_INTERFACE"] @@ -32,10 +33,37 @@ interface PPB_FileChooserTrusted { * @return PP_OK_COMPLETIONPENDING if request to show the dialog was * successful, another error code from pp_errors.h on failure. */ + [deprecate=0.6] int32_t ShowWithoutUserGesture( [in] PP_Resource chooser, [in] PP_Bool save_as, [in] PP_Var suggested_file_name, [in] PP_CompletionCallback callback); + + /** + * This function displays a previously created file chooser resource as a + * dialog box, prompting the user to choose a file or files to open, or a + * single file for saving. The callback is called with PP_OK on successful + * completion with a file (or files) selected or PP_ERROR_USERCANCEL if the + * user selected no file. + * + * @param[in] chooser The file chooser resource. + * @param[in] save_as A <code>PP_Bool</code> value indicating if this dialog + * is choosing a file for saving. + * @param[in] suggested_file_name If saving, the suggested name for the + * file, otherwise, null or undefined. + * @param[in] callback A <code>CompletionCallback</code> to be called after + * the user has closed the file chooser dialog. + * + * @return PP_OK_COMPLETIONPENDING if request to show the dialog was + * successful, another error code from pp_errors.h on failure. + */ + [version=0.6] + int32_t ShowWithoutUserGesture( + [in] PP_Resource chooser, + [in] PP_Bool save_as, + [in] PP_Var suggested_file_name, + [in] PP_ArrayOutput output, + [in] PP_CompletionCallback callback); }; diff --git a/ppapi/c/dev/ppb_file_chooser_dev.h b/ppapi/c/dev/ppb_file_chooser_dev.h index a2ef7ce..81e8f52 100644 --- a/ppapi/c/dev/ppb_file_chooser_dev.h +++ b/ppapi/c/dev/ppb_file_chooser_dev.h @@ -3,11 +3,12 @@ * found in the LICENSE file. */ -/* From dev/ppb_file_chooser_dev.idl modified Mon Nov 14 10:36:01 2011. */ +/* From dev/ppb_file_chooser_dev.idl modified Thu Mar 15 09:29:39 2012. */ #ifndef PPAPI_C_DEV_PPB_FILE_CHOOSER_DEV_H_ #define PPAPI_C_DEV_PPB_FILE_CHOOSER_DEV_H_ +#include "ppapi/c/pp_array_output.h" #include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_completion_callback.h" #include "ppapi/c/pp_instance.h" @@ -17,7 +18,8 @@ #include "ppapi/c/pp_var.h" #define PPB_FILECHOOSER_DEV_INTERFACE_0_5 "PPB_FileChooser(Dev);0.5" -#define PPB_FILECHOOSER_DEV_INTERFACE PPB_FILECHOOSER_DEV_INTERFACE_0_5 +#define PPB_FILECHOOSER_DEV_INTERFACE_0_6 "PPB_FileChooser(Dev);0.6" +#define PPB_FILECHOOSER_DEV_INTERFACE PPB_FILECHOOSER_DEV_INTERFACE_0_6 /** * @file @@ -52,7 +54,7 @@ PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_FileChooserMode_Dev, 4); * @addtogroup Interfaces * @{ */ -struct PPB_FileChooser_Dev_0_5 { +struct PPB_FileChooser_Dev_0_6 { /** * This function creates a file chooser dialog resource. The chooser is * associated with a particular instance, so that it may be positioned on the @@ -94,29 +96,32 @@ struct PPB_FileChooser_Dev_0_5 { * no file, or another error code from pp_errors.h on failure. * * @param[in] chooser The file chooser resource. + * + * @param[in] output An output array which will receive PP_Resource(s) + * identifying the <code>PPB_FileRef</code> objects that the user selected on + * success. + * * @param[in] callback A <code>CompletionCallback</code> to be called after * the user has closed the file chooser dialog. * * @return PP_OK_COMPLETIONPENDING if request to show the dialog was * successful, another error code from pp_errors.h on failure. */ + int32_t (*Show)(PP_Resource chooser, + struct PP_ArrayOutput output, + struct PP_CompletionCallback callback); +}; + +typedef struct PPB_FileChooser_Dev_0_6 PPB_FileChooser_Dev; + +struct PPB_FileChooser_Dev_0_5 { + PP_Resource (*Create)(PP_Instance instance, + PP_FileChooserMode_Dev mode, + struct PP_Var accept_mime_types); + PP_Bool (*IsFileChooser)(PP_Resource resource); int32_t (*Show)(PP_Resource chooser, struct PP_CompletionCallback callback); - /** - * After a successful completion callback call from Show, this method may be - * used to query the chosen files. It should be called in a loop until it - * returns 0. Their file system type will be PP_FileSystemType_External. If - * the user chose no files or canceled the dialog, then this method will - * simply return 0 the first time it is called. - * - * @param[in] chooser The file chooser resource. - * - * @return A <code>PP_Resource</code> containing the next file chosen by the - * user, or 0 if there are no more files. - */ PP_Resource (*GetNextChosenFile)(PP_Resource chooser); }; - -typedef struct PPB_FileChooser_Dev_0_5 PPB_FileChooser_Dev; /** * @} */ diff --git a/ppapi/c/trusted/ppb_file_chooser_trusted.h b/ppapi/c/trusted/ppb_file_chooser_trusted.h index 85187a7..048639a 100644 --- a/ppapi/c/trusted/ppb_file_chooser_trusted.h +++ b/ppapi/c/trusted/ppb_file_chooser_trusted.h @@ -4,12 +4,13 @@ */ /* From trusted/ppb_file_chooser_trusted.idl, - * modified Wed Jan 4 11:09:00 2012. + * modified Fri Mar 16 10:00:48 2012. */ #ifndef PPAPI_C_TRUSTED_PPB_FILE_CHOOSER_TRUSTED_H_ #define PPAPI_C_TRUSTED_PPB_FILE_CHOOSER_TRUSTED_H_ +#include "ppapi/c/pp_array_output.h" #include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_completion_callback.h" #include "ppapi/c/pp_macros.h" @@ -18,7 +19,8 @@ #include "ppapi/c/pp_var.h" #define PPB_FILECHOOSER_TRUSTED_INTERFACE_0_5 "PPB_FileChooserTrusted;0.5" -#define PPB_FILECHOOSER_TRUSTED_INTERFACE PPB_FILECHOOSER_TRUSTED_INTERFACE_0_5 +#define PPB_FILECHOOSER_TRUSTED_INTERFACE_0_6 "PPB_FileChooserTrusted;0.6" +#define PPB_FILECHOOSER_TRUSTED_INTERFACE PPB_FILECHOOSER_TRUSTED_INTERFACE_0_6 /** * @file @@ -30,7 +32,7 @@ * @addtogroup Interfaces * @{ */ -struct PPB_FileChooserTrusted_0_5 { +struct PPB_FileChooserTrusted_0_6 { /** * This function displays a previously created file chooser resource as a * dialog box, prompting the user to choose a file or files to open, or a @@ -52,10 +54,18 @@ struct PPB_FileChooserTrusted_0_5 { int32_t (*ShowWithoutUserGesture)(PP_Resource chooser, PP_Bool save_as, struct PP_Var suggested_file_name, + struct PP_ArrayOutput output, struct PP_CompletionCallback callback); }; -typedef struct PPB_FileChooserTrusted_0_5 PPB_FileChooserTrusted; +typedef struct PPB_FileChooserTrusted_0_6 PPB_FileChooserTrusted; + +struct PPB_FileChooserTrusted_0_5 { + int32_t (*ShowWithoutUserGesture)(PP_Resource chooser, + PP_Bool save_as, + struct PP_Var suggested_file_name, + struct PP_CompletionCallback callback); +}; /** * @} */ diff --git a/ppapi/cpp/array_output.h b/ppapi/cpp/array_output.h index 4441386..7081507 100644 --- a/ppapi/cpp/array_output.h +++ b/ppapi/cpp/array_output.h @@ -47,7 +47,7 @@ class ArrayOutputAdapterBase { } virtual ~ArrayOutputAdapterBase() {} - PP_ArrayOutput* pp_array_output() { return &pp_array_output_; } + const PP_ArrayOutput& pp_array_output() { return pp_array_output_; } protected: virtual void* GetDataBuffer(uint32_t element_count, @@ -92,6 +92,8 @@ class ArrayOutputAdapter : public ArrayOutputAdapterBase { // ArrayOutputAdapterBase implementation. virtual void* GetDataBuffer(uint32_t element_count, uint32_t element_size) { + if (element_count == 0) + return NULL; PP_DCHECK(element_size == sizeof(T)); if (element_size != sizeof(T)) return NULL; @@ -140,6 +142,8 @@ class ResourceArrayOutputAdapter : public ArrayOutputAdapterBase { // ArrayOutputAdapterBase implementation. virtual void* GetDataBuffer(uint32_t element_count, uint32_t element_size) { + if (element_count == 0) + return NULL; PP_DCHECK(element_size == sizeof(PP_Resource)); if (element_size != sizeof(PP_Resource)) return NULL; diff --git a/ppapi/cpp/completion_callback.h b/ppapi/cpp/completion_callback.h index f1a20b3..3d142e8 100644 --- a/ppapi/cpp/completion_callback.h +++ b/ppapi/cpp/completion_callback.h @@ -185,6 +185,8 @@ class CompletionCallbackWithOutput : public CompletionCallback { /// specializations for all of these cases. typedef typename internal::CallbackOutputTraits<T>::StorageType OutputStorageType; + typedef typename internal::CallbackOutputTraits<T>::APIArgType + APIArgType; /// The default constructor will create a blocking /// <code>CompletionCallback</code> that references the given output @@ -237,7 +239,9 @@ class CompletionCallbackWithOutput : public CompletionCallback { output_(output) { } - OutputStorageType* output() const { return output_; } + APIArgType output() const { + return internal::CallbackOutputTraits<T>::StorageToAPIArg(*output_); + } private: OutputStorageType* output_; diff --git a/ppapi/cpp/dev/file_chooser_dev.cc b/ppapi/cpp/dev/file_chooser_dev.cc index 7987f48..a773def 100644 --- a/ppapi/cpp/dev/file_chooser_dev.cc +++ b/ppapi/cpp/dev/file_chooser_dev.cc @@ -4,6 +4,8 @@ #include "ppapi/cpp/dev/file_chooser_dev.h" +#include <string.h> + #include "ppapi/c/dev/ppb_file_chooser_dev.h" #include "ppapi/c/pp_errors.h" #include "ppapi/cpp/completion_callback.h" @@ -16,8 +18,12 @@ namespace pp { namespace { -template <> const char* interface_name<PPB_FileChooser_Dev>() { - return PPB_FILECHOOSER_DEV_INTERFACE; +template <> const char* interface_name<PPB_FileChooser_Dev_0_5>() { + return PPB_FILECHOOSER_DEV_INTERFACE_0_5; +} + +template <> const char* interface_name<PPB_FileChooser_Dev_0_6>() { + return PPB_FILECHOOSER_DEV_INTERFACE_0_6; } } // namespace @@ -25,28 +31,72 @@ template <> const char* interface_name<PPB_FileChooser_Dev>() { FileChooser_Dev::FileChooser_Dev(const InstanceHandle& instance, PP_FileChooserMode_Dev mode, const Var& accept_mime_types) { - if (!has_interface<PPB_FileChooser_Dev>()) - return; - PassRefFromConstructor(get_interface<PPB_FileChooser_Dev>()->Create( - instance.pp_instance(), mode, accept_mime_types.pp_var())); + if (has_interface<PPB_FileChooser_Dev_0_6>()) { + PassRefFromConstructor(get_interface<PPB_FileChooser_Dev_0_6>()->Create( + instance.pp_instance(), mode, accept_mime_types.pp_var())); + } else if (has_interface<PPB_FileChooser_Dev_0_5>()) { + PassRefFromConstructor(get_interface<PPB_FileChooser_Dev_0_5>()->Create( + instance.pp_instance(), mode, accept_mime_types.pp_var())); + } } FileChooser_Dev::FileChooser_Dev(const FileChooser_Dev& other) : Resource(other) { } -int32_t FileChooser_Dev::Show(const CompletionCallback& cc) { - if (!has_interface<PPB_FileChooser_Dev>()) - return cc.MayForce(PP_ERROR_NOINTERFACE); - return get_interface<PPB_FileChooser_Dev>()->Show( - pp_resource(), cc.pp_completion_callback()); +int32_t FileChooser_Dev::Show( + const CompletionCallbackWithOutput< std::vector<FileRef> >& callback) { + if (has_interface<PPB_FileChooser_Dev_0_6>()) { + return get_interface<PPB_FileChooser_Dev_0_6>()->Show( + pp_resource(), + callback.output(), + callback.pp_completion_callback()); + } + if (has_interface<PPB_FileChooser_Dev_0_5>()) { + // Data for our callback wrapper. The callback handler will delete it. + ChooseCallbackData0_5* data = new ChooseCallbackData0_5; + data->file_chooser = pp_resource(); + data->output = callback.output(); + data->original_callback = callback.pp_completion_callback(); + + return get_interface<PPB_FileChooser_Dev_0_5>()->Show( + pp_resource(), PP_MakeCompletionCallback(&CallbackConverter, data)); + } + return callback.MayForce(PP_ERROR_NOINTERFACE); } -FileRef FileChooser_Dev::GetNextChosenFile() const { - if (!has_interface<PPB_FileChooser_Dev>()) - return FileRef(); - return FileRef(PASS_REF, - get_interface<PPB_FileChooser_Dev>()->GetNextChosenFile(pp_resource())); +// static +void FileChooser_Dev::CallbackConverter(void* user_data, int32_t result) { + ChooseCallbackData0_5* data = static_cast<ChooseCallbackData0_5*>(user_data); + + // Get all of the selected file resources using the iterator API. + std::vector<PP_Resource> selected_files; + if (result == PP_OK) { + const PPB_FileChooser_Dev_0_5* chooser = + get_interface<PPB_FileChooser_Dev_0_5>(); + while (PP_Resource cur = chooser->GetNextChosenFile(data->file_chooser)) + selected_files.push_back(cur); + } + + // Need to issue the "GetDataBuffer" even for error cases & when the + // number of items is 0. + void* output_buf = data->output.GetDataBuffer( + data->output.user_data, + selected_files.size(), sizeof(PP_Resource)); + if (output_buf) { + if (!selected_files.empty()) { + memcpy(output_buf, &selected_files[0], + sizeof(PP_Resource) * selected_files.size()); + } + } else { + // Error allocating, need to free the resource IDs. + for (size_t i = 0; i < selected_files.size(); i++) + Module::Get()->core()->ReleaseResource(selected_files[i]); + } + + // Now execute the original callback. + PP_RunCompletionCallback(&data->original_callback, result); + delete data; } } // namespace pp diff --git a/ppapi/cpp/dev/file_chooser_dev.h b/ppapi/cpp/dev/file_chooser_dev.h index c2abc70..b588ac85 100644 --- a/ppapi/cpp/dev/file_chooser_dev.h +++ b/ppapi/cpp/dev/file_chooser_dev.h @@ -5,7 +5,11 @@ #ifndef PPAPI_CPP_DEV_FILE_CHOOSER_DEV_H_ #define PPAPI_CPP_DEV_FILE_CHOOSER_DEV_H_ +#include <vector> + #include "ppapi/c/dev/ppb_file_chooser_dev.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/file_ref.h" #include "ppapi/cpp/resource.h" namespace pp { @@ -49,23 +53,47 @@ class FileChooser_Dev : public Resource { FileChooser_Dev(const FileChooser_Dev& other); /// This function displays a previously created file chooser resource as a - /// dialog box, prompting the user to choose a file or files. The callback is - /// called with PP_OK on successful completion with a file (or files) selected - /// or PP_ERROR_USERCANCEL if the user selected no file. + /// dialog box, prompting the user to choose a file or files. This function + /// must be called in response to a user gesture, such as a mouse click or + /// touch event. The callback is called with PP_OK on successful completion + /// with a file (or files) selected, PP_ERROR_USERCANCEL if the user selected + /// no file, or another error code from pp_errors.h on failure. + /// + /// @param callback The completion callback that will be executed. On success, + /// the selected files will be passed to the given function. + /// + /// Normally you would use a CompletionCallbackFactory to allow callbacks to + /// be bound to your class. See completion_callback_factory.h for more + /// discussion on how to use this. Your callback will generally look like: + /// + /// @code + /// void OnFilesSelected(int32_t result, + /// const std::vector<pp::FileRef>& files) { + /// if (result == PP_OK) + /// // use files... + /// } + /// @endcode /// /// @return PP_OK_COMPLETIONPENDING if request to show the dialog was /// successful, another error code from pp_errors.h on failure. - virtual int32_t Show(const CompletionCallback& cc); + virtual int32_t Show( + const CompletionCallbackWithOutput< std::vector<FileRef> >& callback); + + protected: + // Heap-allocated data passed to the CallbackConverter for backwards compat. + struct ChooseCallbackData0_5 { + PP_Resource file_chooser; + PP_ArrayOutput output; + PP_CompletionCallback original_callback; + }; - /// After a successful completion callback call from Show, this method may be - /// used to query the chosen files. It should be called in a loop until it - /// returns an is_null() FileRef. Depending on the PP_ChooseFileMode - /// requested when the FileChooser was created, the file refs will either - /// be readable or writable. Their file system type will be - /// PP_FileSystemType_External. If the user chose no files or cancelled the - /// dialog, then this method will simply return an is_null() FileRef the - /// first time it is called. - virtual FileRef GetNextChosenFile() const; + // Provide backwards-compatability for older versions. Converts the old-style + // 0.5 "iterator" interface to the new-style 0.6 "array output" interface that + // the caller is expecting. + // + // This takes a heap-allocated ChooseCallbackData0_5 struct passed as the + // user data and deletes it when the call completes. + static void CallbackConverter(void* user_data, int32_t result); }; } // namespace pp diff --git a/ppapi/cpp/output_traits.h b/ppapi/cpp/output_traits.h index 6326c32..237b0bc 100644 --- a/ppapi/cpp/output_traits.h +++ b/ppapi/cpp/output_traits.h @@ -149,7 +149,7 @@ struct CallbackOutputTraits<Var> { template<typename T> struct GenericVectorCallbackOutputTraits { // All arrays are output via a PP_ArrayOutput type. - typedef PP_ArrayOutput* APIArgType; + 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. @@ -177,7 +177,7 @@ struct GenericVectorCallbackOutputTraits { // class of pp::Resource. template<typename T> struct ResourceVectorCallbackOutputTraits { - typedef PP_ArrayOutput* APIArgType; + typedef PP_ArrayOutput APIArgType; typedef ResourceArrayOutputAdapterWithStorage<T> StorageType; static inline APIArgType StorageToAPIArg(StorageType& t) { @@ -207,7 +207,7 @@ struct CallbackOutputTraits< std::vector<T> > template<> struct CallbackOutputTraits< std::vector<pp::Var> > { // All arrays are output via a PP_ArrayOutput type. - typedef PP_ArrayOutput* APIArgType; + 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. diff --git a/ppapi/cpp/trusted/file_chooser_trusted.cc b/ppapi/cpp/trusted/file_chooser_trusted.cc index a5f6879..d925518 100644 --- a/ppapi/cpp/trusted/file_chooser_trusted.cc +++ b/ppapi/cpp/trusted/file_chooser_trusted.cc @@ -15,8 +15,12 @@ namespace pp { namespace { -template <> const char* interface_name<PPB_FileChooserTrusted>() { - return PPB_FILECHOOSER_TRUSTED_INTERFACE; +template <> const char* interface_name<PPB_FileChooserTrusted_0_5>() { + return PPB_FILECHOOSER_TRUSTED_INTERFACE_0_5; +} + +template <> const char* interface_name<PPB_FileChooserTrusted_0_6>() { + return PPB_FILECHOOSER_TRUSTED_INTERFACE_0_6; } } // namespace @@ -48,14 +52,29 @@ FileChooser_Trusted& FileChooser_Trusted::operator=( return *this; } -int32_t FileChooser_Trusted::Show(const CompletionCallback& cc) { - if (!has_interface<PPB_FileChooserTrusted>()) - return cc.MayForce(PP_ERROR_NOINTERFACE); - return get_interface<PPB_FileChooserTrusted>()->ShowWithoutUserGesture( - pp_resource(), - PP_FromBool(save_as_), - Var(suggested_file_name_).pp_var(), - cc.pp_completion_callback()); +int32_t FileChooser_Trusted::Show( + const CompletionCallbackWithOutput< std::vector<FileRef> >& callback) { + if (has_interface<PPB_FileChooserTrusted_0_6>()) { + return get_interface<PPB_FileChooserTrusted_0_6>()->ShowWithoutUserGesture( + pp_resource(), + PP_FromBool(save_as_), + Var(suggested_file_name_).pp_var(), + callback.output(), + callback.pp_completion_callback()); + } + if (has_interface<PPB_FileChooserTrusted_0_5>()) { + // Data for our callback. The callback handler will delete it. + ChooseCallbackData0_5* data = new ChooseCallbackData0_5; + data->file_chooser = pp_resource(); + data->output = callback.output(); + + return get_interface<PPB_FileChooserTrusted_0_5>()->ShowWithoutUserGesture( + pp_resource(), + PP_FromBool(save_as_), + Var(suggested_file_name_).pp_var(), + PP_MakeCompletionCallback(&CallbackConverter, data)); + } + return callback.MayForce(PP_ERROR_NOINTERFACE); } } // namespace pp diff --git a/ppapi/cpp/trusted/file_chooser_trusted.h b/ppapi/cpp/trusted/file_chooser_trusted.h index d730dbf..6b3c1c1 100644 --- a/ppapi/cpp/trusted/file_chooser_trusted.h +++ b/ppapi/cpp/trusted/file_chooser_trusted.h @@ -28,7 +28,8 @@ class FileChooser_Trusted : public FileChooser_Dev { // Overrides of method in superclass. This shows without requiring a user // gesture (and can also show save dialogs). - virtual int32_t Show(const CompletionCallback& cc); + virtual int32_t Show( + const CompletionCallbackWithOutput< std::vector<FileRef> >& callback); private: bool save_as_; diff --git a/ppapi/examples/file_chooser/file_chooser.cc b/ppapi/examples/file_chooser/file_chooser.cc index 136ff31..959e649 100644 --- a/ppapi/examples/file_chooser/file_chooser.cc +++ b/ppapi/examples/file_chooser/file_chooser.cc @@ -49,19 +49,16 @@ class MyInstance : public pp::InstancePrivate { std::string accept_mime_types = (multi_select ? "" : "plain/text"); chooser_ = pp::FileChooser_Dev(this, mode, accept_mime_types); - chooser_.Show(callback_factory_.NewCallback( + chooser_.Show(callback_factory_.NewCallbackWithOutput( &MyInstance::ShowSelectedFileNames)); } - void ShowSelectedFileNames(int32_t result) { - if (!result != PP_OK) + void ShowSelectedFileNames(int32_t result, + const std::vector<pp::FileRef>& files) { + if (result != PP_OK) return; - - pp::FileRef file_ref = chooser_.GetNextChosenFile(); - while (!file_ref.is_null()) { - Log(file_ref.GetName()); - file_ref = chooser_.GetNextChosenFile(); - } + for (size_t i = 0; i < files.size(); i++) + Log(files[i].GetName()); } void RecreateConsole() { diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index 84913e0..17850f1 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -28,6 +28,15 @@ '../..', # For nacl includes to work. ], 'sources': [ + # Take some standalong files from the C++ wrapper allowing us to more + # easily make async callbacks in the proxy. We can't depend on the + # full C++ wrappers at this layer since the C++ wrappers expect + # symbols defining the globals for "being a plugin" which we are not. + # These callback files are standalone. + 'cpp/completion_callback.cc', + 'cpp/completion_callback.h', + 'utility/completion_callback_factory.h', + 'proxy/broker_dispatcher.cc', 'proxy/broker_dispatcher.h', 'proxy/dispatcher.cc', @@ -151,6 +160,8 @@ 'proxy/ppp_text_input_proxy.h', 'proxy/ppp_video_decoder_proxy.cc', 'proxy/ppp_video_decoder_proxy.h', + 'proxy/proxy_array_output.cc', + 'proxy/proxy_array_output.h', 'proxy/proxy_channel.cc', 'proxy/proxy_channel.h', 'proxy/proxy_module.cc', diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index 48180c6..f1621e2 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -52,6 +52,8 @@ }], ], 'sources': [ + 'shared_impl/array_writer.cc', + 'shared_impl/array_writer.h', 'shared_impl/callback_tracker.cc', 'shared_impl/callback_tracker.h', 'shared_impl/file_type_conversion.cc', diff --git a/ppapi/proxy/DEPS b/ppapi/proxy/DEPS index a159be3..1bfd52f 100644 --- a/ppapi/proxy/DEPS +++ b/ppapi/proxy/DEPS @@ -8,8 +8,9 @@ include_rules = [ # We don't want the proxy to depend on the C++ layer, which is appropriate # for plugins only. However, the completion callback factory is a very useful # tool that we would otherwise have to duplicate, and has no other - # dependencies, so we allow that. + # dependencies, so we allow that (and the output traits it depends on). "-ppapi/cpp", - "+ppapi/cpp/completion_callback.h" + "+ppapi/cpp/completion_callback.h", + "+ppapi/cpp/output_traits.h" ] diff --git a/ppapi/proxy/enter_proxy.h b/ppapi/proxy/enter_proxy.h index 5306a80..86ee7a0 100644 --- a/ppapi/proxy/enter_proxy.h +++ b/ppapi/proxy/enter_proxy.h @@ -89,6 +89,14 @@ template<typename ResourceT> class EnterHostFromHostResourceForceCallback : public EnterHostFromHostResource<ResourceT> { public: + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + const pp::CompletionCallback& callback) + : EnterHostFromHostResource<ResourceT>(host_resource), + needs_running_(true), + callback_(callback) { + } + // For callbacks that take no parameters except the "int32_t result". Most // implementations will use the 1-extra-argument constructor below. template<class CallbackFactory, typename Method> @@ -168,42 +176,12 @@ template<typename FunctionT> class EnterHostFunctionForceCallback : public thunk::EnterFunctionNoLock<FunctionT> { public: - // For callbacks that take no parameters except the "int32_t result". Most - // implementations will use the 1-extra-argument constructor below. - template<class CallbackFactory, typename Method> - EnterHostFunctionForceCallback(PP_Instance instance, - CallbackFactory& factory, - Method method) + EnterHostFunctionForceCallback( + PP_Instance instance, + const pp::CompletionCallback& callback) : thunk::EnterFunctionNoLock<FunctionT>(instance, false), needs_running_(true), - callback_(factory.NewOptionalCallback(method)) { - if (this->failed()) - RunCallback(PP_ERROR_BADARGUMENT); - } - - // For callbacks that take an extra parameter as a closure. - template<class CallbackFactory, typename Method, typename A> - EnterHostFunctionForceCallback(PP_Instance instance, - CallbackFactory& factory, - Method method, - const A& a) - : thunk::EnterFunctionNoLock<FunctionT>(instance, false), - needs_running_(true), - callback_(factory.NewOptionalCallback(method, a)) { - if (this->failed()) - RunCallback(PP_ERROR_BADARGUMENT); - } - - // For callbacks that take two extra parameters as a closure. - template<class CallbackFactory, typename Method, typename A, typename B> - EnterHostFunctionForceCallback(PP_Instance instance, - CallbackFactory& factory, - Method method, - const A& a, - const B& b) - : thunk::EnterFunctionNoLock<FunctionT>(instance), - needs_running_(true), - callback_(factory.NewOptionalCallback(method, a, b)) { + callback_(callback) { if (this->failed()) RunCallback(PP_ERROR_BADARGUMENT); } diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 1043f59..dc46b5a 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -702,8 +702,8 @@ IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFileChooser_Create, ppapi::HostResource /* result */) IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBFileChooser_Show, ppapi::HostResource /* file_chooser */, - bool /* save_as */, - std::string /* suggested_file_name */, + PP_Bool /* save_as */, + ppapi::proxy::SerializedVar /* suggested_file_name */, bool /* require_user_gesture */) // PPB_FileIO. diff --git a/ppapi/proxy/ppb_file_chooser_proxy.cc b/ppapi/proxy/ppb_file_chooser_proxy.cc index fa8df55..47ea3a7 100644 --- a/ppapi/proxy/ppb_file_chooser_proxy.cc +++ b/ppapi/proxy/ppb_file_chooser_proxy.cc @@ -17,6 +17,7 @@ #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppb_file_ref_proxy.h" #include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/array_writer.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/resource_tracker.h" #include "ppapi/shared_impl/tracked_callback.h" @@ -44,11 +45,18 @@ class FileChooser : public Resource, virtual PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; // PPB_FileChooser_API implementation. - virtual int32_t Show(const PP_CompletionCallback& callback) OVERRIDE; - virtual PP_Resource GetNextChosenFile() OVERRIDE; + virtual int32_t Show(const PP_ArrayOutput& output, + const PP_CompletionCallback& callback) OVERRIDE; virtual int32_t ShowWithoutUserGesture( - bool save_as, - const char* suggested_file_name, + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + const PP_CompletionCallback& callback); + virtual int32_t Show0_5(const PP_CompletionCallback& callback) OVERRIDE; + virtual PP_Resource GetNextChosenFile() OVERRIDE; + virtual int32_t ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, const PP_CompletionCallback& callback) OVERRIDE; // Handles the choose complete notification from the host. @@ -58,16 +66,19 @@ class FileChooser : public Resource, private: int32_t Show(bool require_user_gesture, - bool save_as, - const char* suggested_file_name, + PP_Bool save_as, + PP_Var suggested_file_name, const PP_CompletionCallback& callback); + // When using v0.6 of the API, contains the array output info. + ArrayWriter output_; + scoped_refptr<TrackedCallback> current_show_callback_; - // All files returned by the current show callback that haven't yet been - // given to the plugin. The plugin will repeatedly call us to get the next - // file, and we'll vend those out of this queue, removing them when ownership - // has transferred to the plugin. + // When using v0.5 of the API, contains all files returned by the current + // show callback that haven't yet been given to the plugin. The plugin will + // repeatedly call us to get the next file, and we'll vend those out of this + // queue, removing them when ownership has transferred to the plugin. std::queue<PP_Resource> file_queue_; DISALLOW_COPY_AND_ASSIGN(FileChooser); @@ -91,20 +102,39 @@ PPB_FileChooser_API* FileChooser::AsPPB_FileChooser_API() { return this; } -int32_t FileChooser::Show(const PP_CompletionCallback& callback) { - return Show(true, false, NULL, callback); +int32_t FileChooser::Show(const PP_ArrayOutput& output, + const PP_CompletionCallback& callback) { + int32_t result = Show(true, PP_FALSE, PP_MakeUndefined(), callback); + if (result == PP_OK_COMPLETIONPENDING) + output_.set_pp_array_output(output); + return result; } int32_t FileChooser::ShowWithoutUserGesture( - bool save_as, - const char* suggested_file_name, + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + const PP_CompletionCallback& callback) { + int32_t result = Show(false, save_as, PP_MakeUndefined(), callback); + if (result == PP_OK_COMPLETIONPENDING) + output_.set_pp_array_output(output); + return result; +} + +int32_t FileChooser::Show0_5(const PP_CompletionCallback& callback) { + return Show(true, PP_FALSE, PP_MakeUndefined(), callback); +} + +int32_t FileChooser::ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, const PP_CompletionCallback& callback) { return Show(false, save_as, suggested_file_name, callback); } int32_t FileChooser::Show(bool require_user_gesture, - bool save_as, - const char* suggested_file_name, + PP_Bool save_as, + PP_Var suggested_file_name, const PP_CompletionCallback& callback) { if (!callback.func) return PP_ERROR_BLOCKS_MAIN_THREAD; @@ -113,12 +143,13 @@ int32_t FileChooser::Show(bool require_user_gesture, return PP_ERROR_INPROGRESS; // Can't show more than once. current_show_callback_ = new TrackedCallback(this, callback); - PluginDispatcher::GetForResource(this)->Send( + PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); + dispatcher->Send( new PpapiHostMsg_PPBFileChooser_Show( API_ID_PPB_FILE_CHOOSER, host_resource(), save_as, - suggested_file_name ? suggested_file_name : "", + SerializedVarSendInput(dispatcher, suggested_file_name), require_user_gesture)); return PP_OK_COMPLETIONPENDING; } @@ -138,11 +169,21 @@ PP_Resource FileChooser::GetNextChosenFile() { void FileChooser::ChooseComplete( int32_t result_code, const std::vector<PPB_FileRef_CreateInfo>& chosen_files) { - // Convert each of the passed in file infos to resources. These will be owned - // by the FileChooser object until they're passed to the plugin. - DCHECK(file_queue_.empty()); - for (size_t i = 0; i < chosen_files.size(); i++) - file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); + if (output_.is_valid()) { + // Using v0.6 of the API with the output array. + std::vector<PP_Resource> files; + for (size_t i = 0; i < chosen_files.size(); i++) + files.push_back(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); + output_.StoreResourceVector(files); + } else { + // Convert each of the passed in file infos to resources. These will be + // owned by the FileChooser object until they're passed to the plugin. + DCHECK(file_queue_.empty()); + for (size_t i = 0; i < chosen_files.size(); i++) { + file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef( + chosen_files[i])); + } + } // Notify the plugin of the new data. TrackedCallback::ClearAndRun(¤t_show_callback_, result_code); @@ -223,19 +264,24 @@ void PPB_FileChooser_Proxy::OnMsgCreate( void PPB_FileChooser_Proxy::OnMsgShow( const HostResource& chooser, - bool save_as, - std::string suggested_file_name, + PP_Bool save_as, + SerializedVarReceiveInput suggested_file_name, bool require_user_gesture) { + scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output( + new RefCountedArrayOutputAdapter<PP_Resource>); EnterHostFromHostResourceForceCallback<PPB_FileChooser_API> enter( - chooser, callback_factory_, &PPB_FileChooser_Proxy::OnShowCallback, - chooser); + chooser, + callback_factory_.NewOptionalCallback( + &PPB_FileChooser_Proxy::OnShowCallback, output, chooser)); if (enter.succeeded()) { if (require_user_gesture) { - enter.SetResult(enter.object()->Show(enter.callback())); + enter.SetResult(enter.object()->Show(output->pp_array_output(), + enter.callback())); } else { enter.SetResult(enter.object()->ShowWithoutUserGesture( save_as, - suggested_file_name.c_str(), + suggested_file_name.Get(dispatcher()), + output->pp_array_output(), enter.callback())); } } @@ -252,8 +298,11 @@ void PPB_FileChooser_Proxy::OnMsgChooseComplete( } } -void PPB_FileChooser_Proxy::OnShowCallback(int32_t result, - const HostResource& chooser) { +void PPB_FileChooser_Proxy::OnShowCallback( + int32_t result, + scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > + output, + HostResource chooser) { EnterHostFromHostResource<PPB_FileChooser_API> enter(chooser); std::vector<PPB_FileRef_CreateInfo> files; @@ -262,11 +311,14 @@ void PPB_FileChooser_Proxy::OnShowCallback(int32_t result, dispatcher()->GetInterfaceProxy(API_ID_PPB_FILE_REF)); // Convert the returned files to the serialized info. - while (PP_Resource cur_file_resource = - enter.object()->GetNextChosenFile()) { + ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); + for (size_t i = 0; i < output->output().size(); i++) { PPB_FileRef_CreateInfo cur_create_info; - file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info); + file_ref_proxy->SerializeFileRef(output->output()[i], &cur_create_info); files.push_back(cur_create_info); + + // Done with this resource, caller gave us a ref. + tracker->ReleaseResource(output->output()[i]); } } diff --git a/ppapi/proxy/ppb_file_chooser_proxy.h b/ppapi/proxy/ppb_file_chooser_proxy.h index da45a2c..530aec3 100644 --- a/ppapi/proxy/ppb_file_chooser_proxy.h +++ b/ppapi/proxy/ppb_file_chooser_proxy.h @@ -11,8 +11,11 @@ #include "base/basictypes.h" #include "ppapi/c/pp_instance.h" #include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_array_output.h" #include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" +#include "ppapi/proxy/serialized_var.h" #include "ppapi/thunk/ppb_file_chooser_api.h" +#include "ppapi/cpp/output_traits.h" #include "ppapi/utility/completion_callback_factory.h" namespace ppapi { @@ -46,8 +49,8 @@ class PPB_FileChooser_Proxy : public InterfaceProxy { std::string accept_mime_types, ppapi::HostResource* result); void OnMsgShow(const ppapi::HostResource& chooser, - bool save_as, - std::string suggested_file_name, + PP_Bool save_as, + SerializedVarReceiveInput suggested_file_name, bool require_user_gesture); // Host -> plugin message handlers. @@ -58,7 +61,10 @@ class PPB_FileChooser_Proxy : public InterfaceProxy { // Called when the show is complete in the host. This will notify the plugin // via IPC and OnMsgChooseComplete will be called there. - void OnShowCallback(int32_t result, const ppapi::HostResource& chooser); + void OnShowCallback( + int32_t result, + scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output, + HostResource chooser); pp::CompletionCallbackFactory<PPB_FileChooser_Proxy, ProxyNonThreadSafeRefCount> callback_factory_; diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc index 7f29c66..758e67f 100644 --- a/ppapi/proxy/ppb_instance_proxy.cc +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -573,8 +573,10 @@ void PPB_Instance_Proxy::OnHostMsgPostMessage( void PPB_Instance_Proxy::OnHostMsgLockMouse(PP_Instance instance) { EnterHostFunctionForceCallback<PPB_Instance_FunctionAPI> enter( - instance, callback_factory_, - &PPB_Instance_Proxy::MouseLockCompleteInHost, instance); + instance, + callback_factory_.NewCallback( + &PPB_Instance_Proxy::MouseLockCompleteInHost, + instance)); if (enter.succeeded()) enter.SetResult(enter.functions()->LockMouse(instance, enter.callback())); } diff --git a/ppapi/proxy/proxy_array_output.cc b/ppapi/proxy/proxy_array_output.cc new file mode 100644 index 0000000..e550b1c --- /dev/null +++ b/ppapi/proxy/proxy_array_output.cc @@ -0,0 +1,21 @@ +// 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/proxy/proxy_array_output.h" + +#include "base/logging.h" + +namespace ppapi { +namespace proxy { + +// 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); +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/proxy_array_output.h b/ppapi/proxy/proxy_array_output.h new file mode 100644 index 0000000..d717909 --- /dev/null +++ b/ppapi/proxy/proxy_array_output.h @@ -0,0 +1,138 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ +#define PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ + +#include <vector> + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_array_output.h" + +// Like ppapi/cpp/array_output.h file in the C++ wrappers but for use in the +// proxy where we can't link to the C++ wrappers. This also adds a refcounted +// version. +// +// Use ArrayOutputAdapter when calling a function that synchronously returns +// an array of data. Use RefCountedArrayOutputAdapterWithStorage for +// asynchronous returns: +// +// void OnCallbackComplete( +// int32_t result, +// scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output) { +// // Vector is in output->output(). +// } +// +// void ScheduleCallback() { +// base::scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output; +// +// callback = factory.NewOptionalCallback(&OnCallbackComplete, output); +// DoSomethingAsynchronously(output->pp_array_output(), +// callback.PP_CompletionCallback()); +// ... +namespace ppapi { +namespace proxy { + +// 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() {} + + const 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) { + DCHECK(element_size == sizeof(T)); + if (element_count == 0 || element_size != sizeof(T)) + return NULL; + output_->resize(element_count); + return &(*output_)[0]; + } + + private: + std::vector<T>* output_; +}; + +template<typename T> +class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> { + public: + ArrayOutputAdapterWithStorage() { + // Note: "this->" is required due to two-phase name lookup where it isn't + // allowed to look in the base class during parsing. + this->set_output(&output_storage_); + } + + std::vector<T>& output() { return output_storage_; } + + private: + std::vector<T> output_storage_; +}; + +// A reference counted version of ArrayOutputAdapterWithStorage. Since it +// doesn't make much sense to heap-allocate one without storage, we don't +// call it "with storage" to keep the name length under control. +template<typename T> +class RefCountedArrayOutputAdapter + : public ArrayOutputAdapterWithStorage<T>, + public base::RefCounted<RefCountedArrayOutputAdapter<T> > { + public: + RefCountedArrayOutputAdapter() + : ArrayOutputAdapterWithStorage<T>() { + } +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ diff --git a/ppapi/shared_impl/array_writer.cc b/ppapi/shared_impl/array_writer.cc new file mode 100644 index 0000000..957ff77 --- /dev/null +++ b/ppapi/shared_impl/array_writer.cc @@ -0,0 +1,79 @@ +// 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/shared_impl/array_writer.h" + +#include <algorithm> + +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/resource_tracker.h" + +namespace ppapi { + +ArrayWriter::ArrayWriter() { + Reset(); +} + +ArrayWriter::ArrayWriter(const PP_ArrayOutput& output) + : pp_array_output_(output) { +} + +ArrayWriter::~ArrayWriter() { +} + +void ArrayWriter::Reset() { + pp_array_output_.GetDataBuffer = NULL; + pp_array_output_.user_data = NULL; +} + +bool ArrayWriter::StoreResourceVector( + const std::vector< scoped_refptr<Resource> >& input) { + // Always call the alloc function, even on 0 array size. + void* dest = pp_array_output_.GetDataBuffer( + pp_array_output_.user_data, + static_cast<uint32_t>(input.size()), + sizeof(PP_Resource)); + + // Regardless of success, we clear the output to prevent future calls on + // this same output object. + Reset(); + + if (input.empty()) + return true; // Allow plugin to return NULL on 0 elements. + if (!dest) + return false; + + // Convert to PP_Resources. + PP_Resource* dest_resources = static_cast<PP_Resource*>(dest); + for (size_t i = 0; i < input.size(); i++) + dest_resources[i] = input[i]->GetReference(); + return true; +} + +bool ArrayWriter::StoreResourceVector(const std::vector<PP_Resource>& input) { + // Always call the alloc function, even on 0 array size. + void* dest = pp_array_output_.GetDataBuffer( + pp_array_output_.user_data, + static_cast<uint32_t>(input.size()), + sizeof(PP_Resource)); + + // Regardless of success, we clear the output to prevent future calls on + // this same output object. + Reset(); + + if (input.empty()) + return true; // Allow plugin to return NULL on 0 elements. + if (!dest) { + // Free the resources. + for (size_t i = 0; i < input.size(); i++) + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(input[i]); + return false; + } + + std::copy(input.begin(), input.end(), static_cast<PP_Resource*>(dest)); + return true; +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/array_writer.h b/ppapi/shared_impl/array_writer.h new file mode 100644 index 0000000..cabd0af --- /dev/null +++ b/ppapi/shared_impl/array_writer.h @@ -0,0 +1,98 @@ +// 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_SHARED_IMPL_ARRAY_WRITER_H_ +#define PPAPI_SHARED_IMPL_ARRAY_WRITER_H_ + +#include <string.h> + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_array_output.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/ppapi_shared_export.h" + +namespace ppapi { + +class Resource; + +// Holds a PP_ArrayWriter and provides helper functions for writing arrays +// to it. It also handles 0-initialization of the raw C struct and attempts +// to prevent you from writing the array twice. +class PPAPI_SHARED_EXPORT ArrayWriter { + public: + ArrayWriter(); // Creates an is_null() object + ArrayWriter(const PP_ArrayOutput& output); + ~ArrayWriter(); + + bool is_valid() const { return !!pp_array_output_.GetDataBuffer; } + bool is_null() const { return !is_valid(); } + + void set_pp_array_output(const PP_ArrayOutput& output) { + pp_array_output_ = output; + } + + // Sets the array output back to its is_null() state. + void Reset(); + + // Copies the given vector of data to the plugin output array. + // + // Returns true on success, false if the plugin reported allocation failure. + // In either case, the object will become is_null() immediately after the + // call since one output function should only be issued once. + // + // THIS IS DESIGNED FOR POD ONLY. For the case of resources, for example, we + // want to transfer a reference only on success. Likewise, if you have a + // structure of PP_Vars or a struct that contains a PP_Resource, we need to + // make sure that the right thing happens with the ref on success and failure. + template<typename T> + bool StoreVector(const std::vector<T>& input) { + // Always call the alloc function, even on 0 array size. + void* dest = pp_array_output_.GetDataBuffer( + pp_array_output_.user_data, + static_cast<uint32_t>(input.size()), + sizeof(T)); + + // Regardless of success, we clear the output to prevent future calls on + // this same output object. + Reset(); + + if (input.empty()) + return true; // Allow plugin to return NULL on 0 elements. + if (!dest) + return false; + + memcpy(dest, &input[0], sizeof(T) * input.size()); + return true; + } + + // Stores the given vector of resources as PP_Resources to the output vector, + // adding one reference to each. + // + // On failure this returns false, nothing will be copied, and the resource + // refcounts will be unchanged. In either case, the object will become + // is_null() immediately after the call since one output function should only + // be issued once. + // + // Note: potentially this could be a template in case you have a vector of + // FileRef objects, for example. However, this saves code since there's only + // one instantiation and is sufficient for now. + bool StoreResourceVector( + const std::vector< scoped_refptr<Resource> >& input); + + // Like the above version but takes an array of AddRed'ed PP_Resources. On + // storage failure, this will release each resource. + bool StoreResourceVector(const std::vector<PP_Resource>& input); + + private: + PP_ArrayOutput pp_array_output_; + + DISALLOW_COPY_AND_ASSIGN(ArrayWriter); +}; + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_ARRAY_WRITER_H_ diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h index 72de91e..0296a2d 100644 --- a/ppapi/thunk/interfaces_ppb_public_dev.h +++ b/ppapi/thunk/interfaces_ppb_public_dev.h @@ -41,6 +41,8 @@ UNPROXIED_IFACE(PPB_DirectoryReader, PPB_DIRECTORYREADER_DEV_INTERFACE_0_5, UNPROXIED_IFACE(PPB_Find, PPB_FIND_DEV_INTERFACE_0_3, PPB_Find_Dev_0_3) PROXIED_IFACE(PPB_FileChooser, PPB_FILECHOOSER_DEV_INTERFACE_0_5, PPB_FileChooser_Dev_0_5) +PROXIED_IFACE(PPB_FileChooser, PPB_FILECHOOSER_DEV_INTERFACE_0_6, + PPB_FileChooser_Dev_0_6) PROXIED_IFACE(PPB_Instance, PPB_CHAR_SET_DEV_INTERFACE_0_4, PPB_CharSet_Dev_0_4) PROXIED_IFACE(PPB_Instance, PPB_CONSOLE_DEV_INTERFACE_0_1, PPB_Console_Dev_0_1) PROXIED_IFACE(PPB_Instance, PPB_URLUTIL_DEV_INTERFACE_0_6, PPB_URLUtil_Dev_0_6) diff --git a/ppapi/thunk/ppb_file_chooser_api.h b/ppapi/thunk/ppb_file_chooser_api.h index 494f7bd..ed94782 100644 --- a/ppapi/thunk/ppb_file_chooser_api.h +++ b/ppapi/thunk/ppb_file_chooser_api.h @@ -14,13 +14,24 @@ class PPB_FileChooser_API { public: virtual ~PPB_FileChooser_API() {} - virtual int32_t Show(const PP_CompletionCallback& callback) = 0; - virtual PP_Resource GetNextChosenFile() = 0; + virtual int32_t Show(const PP_ArrayOutput& output, + const PP_CompletionCallback& callback) = 0; // Trusted API. virtual int32_t ShowWithoutUserGesture( - bool save_as, - const char* suggested_file_name, + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + const PP_CompletionCallback& callback) = 0; + + // Version 0.5 API. + virtual int32_t Show0_5(const PP_CompletionCallback& callback) = 0; + virtual PP_Resource GetNextChosenFile() = 0; + + // Trusted version 0.5 API. + virtual int32_t ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, const PP_CompletionCallback& callback) = 0; }; diff --git a/ppapi/thunk/ppb_file_chooser_thunk.cc b/ppapi/thunk/ppb_file_chooser_thunk.cc index b43b06a..4e590c7 100644 --- a/ppapi/thunk/ppb_file_chooser_thunk.cc +++ b/ppapi/thunk/ppb_file_chooser_thunk.cc @@ -34,53 +34,102 @@ PP_Bool IsFileChooser(PP_Resource resource) { return PP_FromBool(enter.succeeded()); } -int32_t Show(PP_Resource chooser, PP_CompletionCallback callback) { +int32_t Show0_5(PP_Resource chooser, PP_CompletionCallback callback) { EnterResource<PPB_FileChooser_API> enter(chooser, callback, true); if (enter.failed()) return enter.retval(); - return enter.SetResult(enter.object()->Show(callback)); + return enter.SetResult(enter.object()->Show0_5(callback)); } -PP_Resource GetNextChosenFile(PP_Resource chooser) { +PP_Resource GetNextChosenFile0_5(PP_Resource chooser) { EnterResource<PPB_FileChooser_API> enter(chooser, true); if (enter.failed()) return 0; return enter.object()->GetNextChosenFile(); } +int32_t Show(PP_Resource chooser, + PP_ArrayOutput output, + PP_CompletionCallback callback) { + EnterResource<PPB_FileChooser_API> enter(chooser, callback, true); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.object()->Show(output, callback)); +} + + int32_t ShowWithoutUserGesture(PP_Resource chooser, PP_Bool save_as, PP_Var suggested_file_name, + const PP_ArrayOutput* output, PP_CompletionCallback callback) { EnterResource<PPB_FileChooser_API> enter(chooser, callback, true); if (enter.failed()) return enter.retval(); - scoped_refptr<StringVar> string_var = - StringVar::FromPPVar(suggested_file_name); - std::string str = string_var ? string_var->value() : std::string(); return enter.SetResult(enter.object()->ShowWithoutUserGesture( - save_as == PP_TRUE, str.c_str(), callback)); + save_as, suggested_file_name, *output, callback)); } -const PPB_FileChooser_Dev g_ppb_file_chooser_thunk = { +int32_t ShowWithoutUserGesture0_5(PP_Resource chooser, + PP_Bool save_as, + PP_Var suggested_file_name, + PP_CompletionCallback callback) { + EnterResource<PPB_FileChooser_API> enter(chooser, callback, true); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.object()->ShowWithoutUserGesture0_5( + save_as, suggested_file_name, callback)); +} + +int32_t ShowWithoutUserGesture0_6(PP_Resource chooser, + PP_Bool save_as, + PP_Var suggested_file_name, + PP_ArrayOutput output, + PP_CompletionCallback callback) { + EnterResource<PPB_FileChooser_API> enter(chooser, callback, true); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.object()->ShowWithoutUserGesture( + save_as, suggested_file_name, output, callback)); +} + +const PPB_FileChooser_Dev_0_5 g_ppb_file_chooser_0_5_thunk = { + &Create, + &IsFileChooser, + &Show0_5, + &GetNextChosenFile0_5 +}; + +const PPB_FileChooser_Dev_0_6 g_ppb_file_chooser_0_6_thunk = { &Create, &IsFileChooser, - &Show, - &GetNextChosenFile + &Show +}; + +const PPB_FileChooserTrusted_0_5 g_ppb_file_chooser_trusted_0_5_thunk = { + &ShowWithoutUserGesture0_5 }; -const PPB_FileChooserTrusted g_ppb_file_chooser_trusted_thunk = { - &ShowWithoutUserGesture +const PPB_FileChooserTrusted_0_6 g_ppb_file_chooser_trusted_0_6_thunk = { + &ShowWithoutUserGesture0_6 }; } // namespace const PPB_FileChooser_Dev_0_5* GetPPB_FileChooser_Dev_0_5_Thunk() { - return &g_ppb_file_chooser_thunk; + return &g_ppb_file_chooser_0_5_thunk; +} + +const PPB_FileChooser_Dev_0_6* GetPPB_FileChooser_Dev_0_6_Thunk() { + return &g_ppb_file_chooser_0_6_thunk; } const PPB_FileChooserTrusted_0_5* GetPPB_FileChooser_Trusted_0_5_Thunk() { - return &g_ppb_file_chooser_trusted_thunk; + return &g_ppb_file_chooser_trusted_0_5_thunk; +} + +const PPB_FileChooserTrusted_0_6* GetPPB_FileChooser_Trusted_0_6_Thunk() { + return &g_ppb_file_chooser_trusted_0_6_thunk; } } // namespace thunk |