diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-14 15:43:42 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-14 15:43:42 +0000 |
commit | eccf8031b30e3f8cf85b1e0dc82e69966afa30d5 (patch) | |
tree | 6c10625135c1fd95eb316fdbf496c5a5ee220c6e | |
parent | 1c7fa0a26fed6f48fbb2a7fe5724c5f9143610ff (diff) | |
download | chromium_src-eccf8031b30e3f8cf85b1e0dc82e69966afa30d5.zip chromium_src-eccf8031b30e3f8cf85b1e0dc82e69966afa30d5.tar.gz chromium_src-eccf8031b30e3f8cf85b1e0dc82e69966afa30d5.tar.bz2 |
This implements the PPB_FileChooser resource as a new-style IPC-only resource.
Note that the new file name is file_chooser_resource in the proxy. I decided to drop the ppb_ prefix for the "new-style" files to help differentiate them, and also because it's technically wrong. PPB is an interface, and a resource "object" may support multiple interfaces. I think FooResource is easier to type and read.
Review URL: https://chromiumcodereview.appspot.com/10544089
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146737 0039d316-1c4b-4281-b951-d872f2087c98
49 files changed, 1296 insertions, 928 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 0dc741e..570e48c 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -145,12 +145,17 @@ 'renderer/notification_provider.h', 'renderer/paint_aggregator.cc', 'renderer/paint_aggregator.h', + 'renderer/pepper/pepper_instance_state_accessor.h', + 'renderer/pepper/pepper_instance_state_accessor_impl.cc', + 'renderer/pepper/pepper_instance_state_accessor_impl.h', 'renderer/pepper/content_renderer_pepper_host_factory.cc', 'renderer/pepper/content_renderer_pepper_host_factory.h', 'renderer/pepper/pepper_broker_impl.cc', 'renderer/pepper/pepper_broker_impl.h', 'renderer/pepper/pepper_device_enumeration_event_handler.cc', 'renderer/pepper/pepper_device_enumeration_event_handler.h', + 'renderer/pepper/pepper_file_chooser_host.cc', + 'renderer/pepper/pepper_file_chooser_host.h', 'renderer/pepper/pepper_hung_plugin_filter.cc', 'renderer/pepper/pepper_hung_plugin_filter.h', 'renderer/pepper/pepper_in_process_resource_creation.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 520031b..0320e1f 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -521,7 +521,12 @@ 'content_shell_lib', 'test_support_content', '../base/base.gyp:test_support_base', + '../ipc/ipc.gyp:test_support_ipc', '../net/net.gyp:net_test_support', + '../ppapi/ppapi_internal.gyp:ppapi_host', + '../ppapi/ppapi_internal.gyp:ppapi_proxy', + '../ppapi/ppapi_internal.gyp:ppapi_shared', + '../ppapi/ppapi_internal.gyp:ppapi_unittest_shared', '../skia/skia.gyp:skia', '../testing/gtest.gyp:gtest', '../ui/ui.gyp:ui', @@ -537,6 +542,7 @@ 'test/content_browser_test.h', 'test/content_browser_test.cc', 'test/content_test_launcher.cc', + 'renderer/pepper/pepper_file_chooser_host_browsertest.cc', ], 'conditions': [ ['OS=="win"', { diff --git a/content/renderer/pepper/content_renderer_pepper_host_factory.cc b/content/renderer/pepper/content_renderer_pepper_host_factory.cc index de7cf75..ec7e7ca 100644 --- a/content/renderer/pepper/content_renderer_pepper_host_factory.cc +++ b/content/renderer/pepper/content_renderer_pepper_host_factory.cc @@ -4,6 +4,8 @@ #include "content/renderer/pepper/content_renderer_pepper_host_factory.h" +#include "content/renderer/pepper/pepper_instance_state_accessor.h" +#include "content/renderer/pepper/pepper_file_chooser_host.h" #include "ppapi/host/resource_host.h" #include "ppapi/proxy/ppapi_messages.h" @@ -12,8 +14,12 @@ using ppapi::host::ResourceHost; namespace content { ContentRendererPepperHostFactory::ContentRendererPepperHostFactory( - RenderViewImpl* render_view) - : render_view_(render_view) { + RenderViewImpl* render_view, + const ppapi::PpapiPermissions& permissions, + PepperInstanceStateAccessor* state) + : render_view_(render_view), + permissions_(permissions), + instance_state_(state) { } ContentRendererPepperHostFactory::~ContentRendererPepperHostFactory() { @@ -24,7 +30,21 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost( const ppapi::proxy::ResourceMessageCallParams& params, PP_Instance instance, const IPC::Message& message) { - // TODO(brettw) host creation goes here. + // Make sure the plugin is giving us a valid instance for this resource. + if (!instance_state_->IsValidInstance(instance)) + return scoped_ptr<ResourceHost>(); + + // Resources for dev interfaces. + // TODO(brettw) when we support any public or private interfaces, put them in + // a separate switch above. + if (permissions_.HasPermission(ppapi::PERMISSION_DEV)) { + switch (message.type()) { + case PpapiHostMsg_FileChooser_Create::ID: + return scoped_ptr<ResourceHost>(new PepperFileChooserHost( + host, instance, params.pp_resource(), render_view_, + instance_state_)); + } + } return scoped_ptr<ResourceHost>(); } diff --git a/content/renderer/pepper/content_renderer_pepper_host_factory.h b/content/renderer/pepper/content_renderer_pepper_host_factory.h index dbb36af..ad92f5b 100644 --- a/content/renderer/pepper/content_renderer_pepper_host_factory.h +++ b/content/renderer/pepper/content_renderer_pepper_host_factory.h @@ -7,14 +7,20 @@ #include "base/compiler_specific.h" #include "ppapi/host/host_factory.h" +#include "ppapi/shared_impl/ppapi_permissions.h" class RenderViewImpl; namespace content { +class PepperInstanceStateAccessor; + class ContentRendererPepperHostFactory : public ppapi::host::HostFactory { public: - explicit ContentRendererPepperHostFactory(RenderViewImpl* render_view); + explicit ContentRendererPepperHostFactory( + RenderViewImpl* render_view, + const ppapi::PpapiPermissions& permissions, + PepperInstanceStateAccessor* state); virtual ~ContentRendererPepperHostFactory(); virtual scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost( @@ -24,7 +30,9 @@ class ContentRendererPepperHostFactory : public ppapi::host::HostFactory { const IPC::Message& message) OVERRIDE; private: - RenderViewImpl* render_view_; + RenderViewImpl* render_view_; // Non-owning. + ppapi::PpapiPermissions permissions_; + PepperInstanceStateAccessor* instance_state_; // Non-owning. DISALLOW_COPY_AND_ASSIGN(ContentRendererPepperHostFactory); }; diff --git a/content/renderer/pepper/pepper_file_chooser_host.cc b/content/renderer/pepper/pepper_file_chooser_host.cc new file mode 100644 index 0000000..79c825f --- /dev/null +++ b/content/renderer/pepper/pepper_file_chooser_host.cc @@ -0,0 +1,176 @@ +// 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 "content/renderer/pepper/pepper_file_chooser_host.h" + +#include "base/file_path.h" +#include "base/utf_string_conversions.h" +#include "content/renderer/pepper/pepper_instance_state_accessor.h" +#include "content/renderer/render_view_impl.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" + +namespace content { + +class PepperFileChooserHost::CompletionHandler + : public WebKit::WebFileChooserCompletion { + public: + CompletionHandler(const base::WeakPtr<PepperFileChooserHost>& host) + : host_(host) { + } + + virtual ~CompletionHandler() {} + + virtual void didChooseFile( + const WebKit::WebVector<WebKit::WebString>& file_names) { + if (host_) { + std::vector<PepperFileChooserHost::ChosenFileInfo> files; + for (size_t i = 0; i < file_names.size(); i++) { + files.push_back(PepperFileChooserHost::ChosenFileInfo( + file_names[i].utf8(), std::string())); + } + host_->StoreChosenFiles(files); + } + + // It is the responsibility of this method to delete the instance. + delete this; + } + virtual void didChooseFile( + const WebKit::WebVector<SelectedFileInfo>& file_names) { + if (host_) { + std::vector<PepperFileChooserHost::ChosenFileInfo> files; + for (size_t i = 0; i < file_names.size(); i++) { + files.push_back(PepperFileChooserHost::ChosenFileInfo( + file_names[i].path.utf8(), + file_names[i].displayName.utf8())); + } + host_->StoreChosenFiles(files); + } + + // It is the responsibility of this method to delete the instance. + delete this; + } + + private: + base::WeakPtr<PepperFileChooserHost> host_; + + DISALLOW_COPY_AND_ASSIGN(CompletionHandler); +}; + +PepperFileChooserHost::ChosenFileInfo::ChosenFileInfo( + const std::string& path, + const std::string& display_name) + : path(path), + display_name(display_name) { +} + + +PepperFileChooserHost::PepperFileChooserHost( + ppapi::host::PpapiHost* host, + PP_Instance instance, + PP_Resource resource, + RenderViewImpl* render_view, + PepperInstanceStateAccessor* state) + : ResourceHost(host, instance, resource), + render_view_(render_view), + instance_state_(state), + handler_(NULL) { +} + +PepperFileChooserHost::~PepperFileChooserHost() { +} + +int32_t PepperFileChooserHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + IPC_BEGIN_MESSAGE_MAP(PepperFileChooserHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileChooser_Show, + OnMsgShow) + IPC_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +void PepperFileChooserHost::StoreChosenFiles( + const std::vector<ChosenFileInfo>& files) { + std::vector<ppapi::PPB_FileRef_CreateInfo> chosen_files; + for (size_t i = 0; i < files.size(); i++) { +#if defined(OS_WIN) + FilePath file_path(UTF8ToWide(files[i].path)); +#else + FilePath file_path(files[i].path); +#endif + + webkit::ppapi::PPB_FileRef_Impl* ref = + webkit::ppapi::PPB_FileRef_Impl::CreateExternal( + pp_instance(), file_path, files[i].display_name); + ppapi::PPB_FileRef_CreateInfo create_info; + ppapi::proxy::PPB_FileRef_Proxy::SerializeFileRef(ref->GetReference(), + &create_info); + chosen_files.push_back(create_info); + } + + reply_params_.set_result((chosen_files.size() > 0) ? PP_OK + : PP_ERROR_USERCANCEL); + host()->SendReply(reply_params_, + PpapiPluginMsg_FileChooser_ShowReply(chosen_files)); + + reply_params_ = ppapi::proxy::ResourceMessageReplyParams(); + handler_ = NULL; // Handler deletes itself. +} + +int32_t PepperFileChooserHost::OnMsgShow( + ppapi::host::HostMessageContext* context, + bool save_as, + bool open_multiple, + const std::string& suggested_file_name, + const std::vector<std::string>& accept_mime_types) { + if (handler_) + return PP_ERROR_INPROGRESS; // Already pending. + + if (!host()->permissions().HasPermission( + ppapi::PERMISSION_BYPASS_USER_GESTURE) && + !instance_state_->HasUserGesture(pp_instance())) { + return PP_ERROR_NO_USER_GESTURE; + } + + WebKit::WebFileChooserParams params; + if (save_as) { + params.saveAs = true; + params.initialValue = WebKit::WebString::fromUTF8( + suggested_file_name.data(), suggested_file_name.size()); + } else { + params.multiSelect = open_multiple; + } + std::vector<WebKit::WebString> mine_types(accept_mime_types.size()); + for (size_t i = 0; i < accept_mime_types.size(); i++) { + mine_types[i] = WebKit::WebString::fromUTF8( + accept_mime_types[i].data(), accept_mime_types[i].size()); + } + params.acceptTypes = mine_types; + params.directory = false; + + handler_ = new CompletionHandler(AsWeakPtr()); + if (!render_view_->runFileChooser(params, handler_)) { + delete handler_; + handler_ = NULL; + return PP_ERROR_NOACCESS; + } + + reply_params_ = ppapi::proxy::ResourceMessageReplyParams( + context->params.pp_resource(), + context->params.sequence()); + return PP_OK_COMPLETIONPENDING; +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_file_chooser_host.h b/content/renderer/pepper/pepper_file_chooser_host.h new file mode 100644 index 0000000..8dbc4e3 --- /dev/null +++ b/content/renderer/pepper/pepper_file_chooser_host.h @@ -0,0 +1,68 @@ +// 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 CONTENT_RENDERER_PEPPER_PEPPER_FILE_CHOOSER_HOST_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_FILE_CHOOSER_HOST_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/resource_message_params.h" + +class RenderViewImpl; + +namespace content { + +class PepperInstanceStateAccessor; + +class CONTENT_EXPORT PepperFileChooserHost + : public ppapi::host::ResourceHost, + public base::SupportsWeakPtr<PepperFileChooserHost> { + public: + // Structure to store the information about chosen files. + struct ChosenFileInfo { + ChosenFileInfo(const std::string& path, const std::string& display_name); + std::string path; + std::string display_name; // May be empty. + }; + + PepperFileChooserHost(ppapi::host::PpapiHost* host, + PP_Instance instance, + PP_Resource resource, + RenderViewImpl* render_view, + PepperInstanceStateAccessor* state); + virtual ~PepperFileChooserHost(); + + virtual int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) OVERRIDE; + + void StoreChosenFiles(const std::vector<ChosenFileInfo>& files); + + private: + class CompletionHandler; + + int32_t OnMsgShow(ppapi::host::HostMessageContext* context, + bool save_as, + bool open_multiple, + const std::string& suggested_file_name, + const std::vector<std::string>& accept_mime_types); + + // Non-owning pointers. + RenderViewImpl* render_view_; + PepperInstanceStateAccessor* instance_state_; + + ppapi::proxy::ResourceMessageReplyParams reply_params_; + CompletionHandler* handler_; + + DISALLOW_COPY_AND_ASSIGN(PepperFileChooserHost); +}; + +} // namespace ppapi + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_FILE_CHOOSER_HOST_H_ diff --git a/content/renderer/pepper/pepper_file_chooser_host_browsertest.cc b/content/renderer/pepper/pepper_file_chooser_host_browsertest.cc new file mode 100644 index 0000000..6a482d3 --- /dev/null +++ b/content/renderer/pepper/pepper_file_chooser_host_browsertest.cc @@ -0,0 +1,175 @@ +// 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 "base/file_path.h" +#include "base/utf_string_conversions.h" +#include "content/public/test/render_view_test.h" +#include "content/common/view_messages.h" +#include "content/public/common/file_chooser_params.h" +#include "content/renderer/pepper/pepper_file_chooser_host.h" +#include "content/renderer/pepper/pepper_instance_state_accessor.h" +#include "content/renderer/render_view_impl.h" +#include "content/test/test_content_client.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/resource_message_test_sink.h" +#include "ppapi/shared_impl/ppapi_permissions.h" +#include "ppapi/shared_impl/ppb_file_ref_shared.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/test_globals.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/dialogs/selected_file_info.h" + +namespace content { + +namespace { + +class PepperFileChooserHostTest : public RenderViewTest { + public: + PepperFileChooserHostTest() : pp_instance_(123456) {} + + virtual void SetUp() { + SetContentClient(&client_); + RenderViewTest::SetUp(); + + globals_.GetResourceTracker()->DidCreateInstance(pp_instance_); + } + virtual void TearDown() { + globals_.GetResourceTracker()->DidDeleteInstance(pp_instance_); + + RenderViewTest::TearDown(); + SetContentClient(NULL); + } + + PP_Instance pp_instance() const { return pp_instance_; } + + private: + PP_Instance pp_instance_; + + ppapi::TestGlobals globals_; + TestContentClient client_; +}; + +// For testing to convert our hardcoded file paths to 8-bit. +std::string FilePathToUTF8(const FilePath::StringType& path) { +#if defined(OS_WIN) + return UTF16ToUTF8(path); +#else + return path; +#endif +} + +class MockInstanceState : public PepperInstanceStateAccessor { + public: + MockInstanceState() : has_user_gesture_(true) {} + virtual ~MockInstanceState() {} + + void set_has_user_gesture(bool has) { has_user_gesture_ = has; } + + // PepperInstanceStateAccessor. + virtual bool IsValidInstance(PP_Instance instance) OVERRIDE { + return true; + } + virtual bool HasUserGesture(PP_Instance instance) OVERRIDE { + return has_user_gesture_; + } + + private: + bool has_user_gesture_; +}; + +} // namespace + +TEST_F(PepperFileChooserHostTest, Show) { + PP_Resource pp_resource = 123; + + MockInstanceState state; + ppapi::proxy::ResourceMessageTestSink sink; + ppapi::host::PpapiHost host(&sink, NULL, ppapi::PpapiPermissions()); + RenderViewImpl* view_impl = static_cast<RenderViewImpl*>(view_); + PepperFileChooserHost chooser(&host, pp_instance(), pp_resource, view_impl, + &state); + + std::vector<std::string> accept; + accept.push_back("text/plain"); + PpapiHostMsg_FileChooser_Show show_msg(false, false, std::string(), accept); + + ppapi::proxy::ResourceMessageCallParams call_params(pp_resource, 0); + ppapi::host::HostMessageContext context(call_params); + int32 result = chooser.OnResourceMessageReceived(show_msg, &context); + EXPECT_EQ(PP_OK_COMPLETIONPENDING, result); + + // The render view should have sent a chooser request to the browser + // (caught by the render thread's test message sink). + const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( + ViewHostMsg_RunFileChooser::ID); + ASSERT_TRUE(msg); + ViewHostMsg_RunFileChooser::Schema::Param call_msg_param; + ASSERT_TRUE(ViewHostMsg_RunFileChooser::Read(msg, &call_msg_param)); + const FileChooserParams& chooser_params = call_msg_param.a; + + // Basic validation of request. + EXPECT_EQ(FileChooserParams::Open, chooser_params.mode); + ASSERT_EQ(1u, chooser_params.accept_types.size()); + EXPECT_EQ(accept[0], UTF16ToUTF8(chooser_params.accept_types[0])); + + // Send a chooser reply to the render view. Note our reply path has to have a + // path separator so we include both a Unix and a Windows one. + ui::SelectedFileInfo selected_info; + selected_info.display_name = FILE_PATH_LITERAL("Hello, world"); + selected_info.path = FilePath(FILE_PATH_LITERAL("myp\\ath/foo")); + std::vector<ui::SelectedFileInfo> selected_info_vector; + selected_info_vector.push_back(selected_info); + ViewMsg_RunFileChooserResponse response(view_impl->routing_id(), + selected_info_vector); + EXPECT_TRUE(view_impl->OnMessageReceived(response)); + + // This should have sent the Pepper reply to our test sink. + ppapi::proxy::ResourceMessageReplyParams reply_params; + IPC::Message reply_msg; + ASSERT_TRUE(sink.GetFirstResourceReplyMatching( + PpapiPluginMsg_FileChooser_ShowReply::ID, &reply_params, &reply_msg)); + + // Basic validation of reply. + EXPECT_EQ(call_params.sequence(), reply_params.sequence()); + EXPECT_EQ(PP_OK, reply_params.result()); + PpapiPluginMsg_FileChooser_ShowReply::Schema::Param reply_msg_param; + ASSERT_TRUE(PpapiPluginMsg_FileChooser_ShowReply::Read(&reply_msg, + &reply_msg_param)); + const std::vector<ppapi::PPB_FileRef_CreateInfo>& chooser_results = + reply_msg_param.a; + ASSERT_EQ(1u, chooser_results.size()); + // Note path is empty because this is an external filesystem. + EXPECT_EQ(std::string(), chooser_results[0].path); + EXPECT_EQ(FilePathToUTF8(selected_info.display_name), + chooser_results[0].name); +} + +TEST_F(PepperFileChooserHostTest, NoUserGesture) { + PP_Resource pp_resource = 123; + + MockInstanceState state; + ppapi::proxy::ResourceMessageTestSink sink; + ppapi::host::PpapiHost host(&sink, NULL, ppapi::PpapiPermissions()); + RenderViewImpl* view_impl = static_cast<RenderViewImpl*>(view_); + PepperFileChooserHost chooser(&host, pp_instance(), pp_resource, view_impl, + &state); + + // Say there's no user gesture. + state.set_has_user_gesture(false); + + std::vector<std::string> accept; + accept.push_back("text/plain"); + PpapiHostMsg_FileChooser_Show show_msg(false, false, std::string(), accept); + + ppapi::proxy::ResourceMessageCallParams call_params(pp_resource, 0); + ppapi::host::HostMessageContext context(call_params); + int32 result = chooser.OnResourceMessageReceived(show_msg, &context); + EXPECT_EQ(PP_ERROR_NO_USER_GESTURE, result); +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.cc b/content/renderer/pepper/pepper_in_process_resource_creation.cc index 3371f75..af3e0e7 100644 --- a/content/renderer/pepper/pepper_in_process_resource_creation.cc +++ b/content/renderer/pepper/pepper_in_process_resource_creation.cc @@ -11,10 +11,12 @@ #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" #include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/file_chooser_resource.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/ppapi_permissions.h" #include "ppapi/shared_impl/resource_tracker.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" // Note that the code in the creation functions in this file should generally // be the same as that in ppapi/proxy/resource_creation_proxy.cc. See @@ -26,6 +28,7 @@ class PepperInProcessResourceCreation::PluginToHostRouter : public IPC::Sender { public: PluginToHostRouter(RenderViewImpl* render_view, + PepperInstanceStateAccessor* state, IPC::Sender* host_to_plugin_sender, const ppapi::PpapiPermissions& perms); virtual ~PluginToHostRouter() {} @@ -46,10 +49,11 @@ class PepperInProcessResourceCreation::PluginToHostRouter PepperInProcessResourceCreation::PluginToHostRouter::PluginToHostRouter( RenderViewImpl* render_view, + PepperInstanceStateAccessor* state, IPC::Sender* host_to_plugin_sender, const ppapi::PpapiPermissions& perms) : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), - factory_(render_view), + factory_(render_view, perms, state), host_(host_to_plugin_sender, &factory_, perms) { } @@ -136,13 +140,24 @@ PepperInProcessResourceCreation::PepperInProcessResourceCreation( webkit::ppapi::PluginInstance* instance, const ppapi::PpapiPermissions& perms) : ResourceCreationImpl(instance), + instance_state_(instance->module()), host_to_plugin_router_(new HostToPluginRouter), plugin_to_host_router_( - new PluginToHostRouter(render_view, host_to_plugin_router_.get(), + new PluginToHostRouter(render_view, &instance_state_, + host_to_plugin_router_.get(), perms)) { } PepperInProcessResourceCreation::~PepperInProcessResourceCreation() { } +PP_Resource PepperInProcessResourceCreation::CreateFileChooser( + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const char* accept_types) { + return (new ppapi::proxy::FileChooserResource( + plugin_to_host_router_.get(), + instance, mode, accept_types))->GetReference(); +} + } // namespace content diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.h b/content/renderer/pepper/pepper_in_process_resource_creation.h index 0f01b81..78216b2 100644 --- a/content/renderer/pepper/pepper_in_process_resource_creation.h +++ b/content/renderer/pepper/pepper_in_process_resource_creation.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" +#include "content/renderer/pepper/pepper_instance_state_accessor_impl.h" #include "webkit/plugins/ppapi/resource_creation_impl.h" class RenderViewImpl; @@ -42,7 +43,15 @@ class PepperInProcessResourceCreation const ppapi::PpapiPermissions& perms); virtual ~PepperInProcessResourceCreation(); + // ResourceCreation_API implementation. + virtual PP_Resource CreateFileChooser( + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const char* accept_types) OVERRIDE; + private: + PepperInstanceStateAccessorImpl instance_state_; + class HostToPluginRouter; scoped_ptr<HostToPluginRouter> host_to_plugin_router_; diff --git a/content/renderer/pepper/pepper_instance_state_accessor.h b/content/renderer/pepper/pepper_instance_state_accessor.h new file mode 100644 index 0000000..120640c --- /dev/null +++ b/content/renderer/pepper/pepper_instance_state_accessor.h @@ -0,0 +1,33 @@ +// 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 CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_H_
+
+#include "base/basictypes.h"
+#include "ppapi/c/pp_instance.h"
+
+namespace content {
+
+// This interface provides functions for querying instance state for resource
+// host implementations. It allows us to mock out some of these interactions
+// for testing, as well as limit the dependencies on the webkit layer.
+class PepperInstanceStateAccessor {
+ public:
+ virtual ~PepperInstanceStateAccessor() {}
+
+ // Returns true if the given instance is valid for the host.
+ virtual bool IsValidInstance(PP_Instance instance) = 0;
+
+ // Returns true if the given instance is considered to be currently
+ // processing a user gesture or the plugin module has the "override user
+ // gesture" flag set (in which case it can always do things normally
+ // restricted by user gestures). Returns false if the instance is invalid or
+ // if there is no current user gesture.
+ virtual bool HasUserGesture(PP_Instance instance) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_H_
diff --git a/content/renderer/pepper/pepper_instance_state_accessor_impl.cc b/content/renderer/pepper/pepper_instance_state_accessor_impl.cc new file mode 100644 index 0000000..376d3aa --- /dev/null +++ b/content/renderer/pepper/pepper_instance_state_accessor_impl.cc @@ -0,0 +1,50 @@ +// 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 "content/renderer/pepper/pepper_instance_state_accessor_impl.h"
+
+#include "ppapi/shared_impl/ppapi_permissions.h"
+#include "webkit/plugins/ppapi/host_globals.h"
+#include "webkit/plugins/ppapi/plugin_module.h"
+#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
+
+using webkit::ppapi::HostGlobals;
+using webkit::ppapi::PluginInstance;
+
+namespace content {
+
+PepperInstanceStateAccessorImpl::PepperInstanceStateAccessorImpl(
+ webkit::ppapi::PluginModule* module)
+ : module_(module) {
+}
+
+PepperInstanceStateAccessorImpl::~PepperInstanceStateAccessorImpl() {
+}
+
+bool PepperInstanceStateAccessorImpl::IsValidInstance(PP_Instance instance) {
+ return !!GetAndValidateInstance(instance);
+}
+
+bool PepperInstanceStateAccessorImpl::HasUserGesture(PP_Instance pp_instance) {
+ PluginInstance* instance = GetAndValidateInstance(pp_instance);
+ if (!instance)
+ return false;
+
+ if (instance->module()->permissions().HasPermission(
+ ppapi::PERMISSION_BYPASS_USER_GESTURE))
+ return true;
+ return instance->IsProcessingUserGesture();
+}
+
+PluginInstance* PepperInstanceStateAccessorImpl::GetAndValidateInstance(
+ PP_Instance pp_instance) {
+ PluginInstance* instance = HostGlobals::Get()->GetInstance(pp_instance);
+ if (!instance)
+ return NULL;
+ if (instance->module() != module_)
+ return NULL;
+ return instance;
+}
+
+} // namespace content
diff --git a/content/renderer/pepper/pepper_instance_state_accessor_impl.h b/content/renderer/pepper/pepper_instance_state_accessor_impl.h new file mode 100644 index 0000000..108686e --- /dev/null +++ b/content/renderer/pepper/pepper_instance_state_accessor_impl.h @@ -0,0 +1,45 @@ +// 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 CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_IMPL_H
+#define CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_IMPL_H
+
+#include "base/compiler_specific.h"
+#include "content/renderer/pepper/pepper_instance_state_accessor.h"
+
+namespace webkit {
+namespace ppapi {
+class PluginInstance;
+class PluginModule;
+}
+}
+
+namespace content {
+
+class PepperInstanceStateAccessorImpl : public PepperInstanceStateAccessor {
+ public:
+ PepperInstanceStateAccessorImpl(webkit::ppapi::PluginModule* module);
+ virtual ~PepperInstanceStateAccessorImpl();
+
+ // PepperInstanceStateAccessor implmentation.
+ virtual bool IsValidInstance(PP_Instance instance) OVERRIDE;
+ virtual bool HasUserGesture(PP_Instance pp_instance) OVERRIDE;
+
+ private:
+ // Retrieves the plugin instance object associated with the given PP_Instance
+ // and validates that it is one of the instances associated with our module.
+ // Returns NULL on failure.
+ //
+ // We use this to security check the PP_Instance values sent from a plugin to
+ // make sure it's not trying to spoof another instance.
+ webkit::ppapi::PluginInstance* GetAndValidateInstance(PP_Instance instance);
+
+ webkit::ppapi::PluginModule* module_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperInstanceStateAccessorImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_INSTANCE_STATE_ACCESSOR_IMPL_H
diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index ec8057d..f66b4b3 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -41,10 +41,12 @@ #include "content/renderer/media/pepper_platform_video_decoder_impl.h" #include "content/renderer/p2p/p2p_transport_impl.h" #include "content/renderer/p2p/socket_dispatcher.h" +#include "content/renderer/pepper/content_renderer_pepper_host_factory.h" #include "content/renderer/pepper/pepper_broker_impl.h" #include "content/renderer/pepper/pepper_device_enumeration_event_handler.h" #include "content/renderer/pepper/pepper_hung_plugin_filter.h" #include "content/renderer/pepper/pepper_in_process_resource_creation.h" +#include "content/renderer/pepper/pepper_instance_state_accessor.h" #include "content/renderer/pepper/pepper_platform_audio_input_impl.h" #include "content/renderer/pepper/pepper_platform_audio_output_impl.h" #include "content/renderer/pepper/pepper_platform_context_3d_impl.h" @@ -63,6 +65,7 @@ #include "ppapi/c/dev/pp_video_dev.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_flash.h" +#include "ppapi/host/ppapi_host.h" #include "ppapi/proxy/host_dispatcher.h" #include "ppapi/proxy/pepper_file_messages.h" #include "ppapi/proxy/ppapi_messages.h" @@ -75,8 +78,6 @@ #include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" @@ -105,13 +106,19 @@ namespace { class HostDispatcherWrapper : public webkit::ppapi::PluginDelegate::OutOfProcessProxy { public: - HostDispatcherWrapper() {} + HostDispatcherWrapper(RenderViewImpl* rv, + webkit::ppapi::PluginModule* module, + const ppapi::PpapiPermissions& perms) + : module_(module), + instance_state_(module), + host_factory_(rv, perms, &instance_state_) { + } virtual ~HostDispatcherWrapper() {} bool Init(const IPC::ChannelHandle& channel_handle, - PP_Module pp_module, PP_GetInterface_Func local_get_interface, const ppapi::Preferences& preferences, + const ppapi::PpapiPermissions& permissions, PepperHungPluginFilter* filter) { if (channel_handle.name.empty()) return false; @@ -124,7 +131,11 @@ class HostDispatcherWrapper dispatcher_delegate_.reset(new PepperProxyChannelDelegateImpl); dispatcher_.reset(new ppapi::proxy::HostDispatcher( - pp_module, local_get_interface, filter)); + module_->pp_module(), local_get_interface, filter)); + + host_.reset(new ppapi::host::PpapiHost(dispatcher_.get(), &host_factory_, + permissions)); + dispatcher_->AddFilter(host_.get()); if (!dispatcher_->InitHostWithChannel(dispatcher_delegate_.get(), channel_handle, @@ -151,6 +162,12 @@ class HostDispatcherWrapper } private: + webkit::ppapi::PluginModule* module_; + PepperInstanceStateAccessorImpl instance_state_; + ContentRendererPepperHostFactory host_factory_; + + scoped_ptr<ppapi::host::PpapiHost> host_; + scoped_ptr<ppapi::proxy::HostDispatcher> dispatcher_; scoped_ptr<ppapi::proxy::ProxyChannel::Delegate> dispatcher_delegate_; }; @@ -325,12 +342,13 @@ PepperPluginDelegateImpl::CreatePepperPluginModule( PepperPluginRegistry::GetInstance(), permissions); PepperPluginRegistry::GetInstance()->AddLiveModule(path, module); - scoped_ptr<HostDispatcherWrapper> dispatcher(new HostDispatcherWrapper); + scoped_ptr<HostDispatcherWrapper> dispatcher( + new HostDispatcherWrapper(render_view_, module, permissions)); if (!dispatcher->Init( channel_handle, - module->pp_module(), webkit::ppapi::PluginModule::GetLocalGetInterfaceFunc(), GetPreferences(), + permissions, hung_filter.get())) return scoped_refptr<webkit::ppapi::PluginModule>(); module->InitAsProxied(dispatcher.release()); @@ -348,6 +366,8 @@ scoped_refptr<webkit::ppapi::PluginModule> if (module) return module; + ppapi::PpapiPermissions permissions; + FilePath path(kBrowserPluginPath); scoped_refptr<PepperHungPluginFilter> hung_filter( new PepperHungPluginFilter(path, @@ -358,15 +378,16 @@ scoped_refptr<webkit::ppapi::PluginModule> module = new webkit::ppapi::PluginModule(kBrowserPluginName, path, registry, - ppapi::PpapiPermissions()); + permissions); RenderThreadImpl::current()->browser_plugin_registry()->AddModule( guest_process_id, module); - scoped_ptr<HostDispatcherWrapper> dispatcher(new HostDispatcherWrapper); + scoped_ptr<HostDispatcherWrapper> dispatcher( + new HostDispatcherWrapper(render_view_, module, permissions)); if (!dispatcher->Init( channel_handle, - module->pp_module(), webkit::ppapi::PluginModule::GetLocalGetInterfaceFunc(), GetPreferences(), + permissions, hung_filter.get())) return scoped_refptr<webkit::ppapi::PluginModule>(); module->InitAsProxied(dispatcher.release()); @@ -786,12 +807,6 @@ PepperPluginDelegateImpl::ConnectToBroker( return broker; } -bool PepperPluginDelegateImpl::RunFileChooser( - const WebKit::WebFileChooserParams& params, - WebKit::WebFileChooserCompletion* chooser_completion) { - return render_view_->runFileChooser(params, chooser_completion); -} - bool PepperPluginDelegateImpl::AsyncOpenFile( const FilePath& path, int flags, diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h index d7d367b..984ae12 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h @@ -58,11 +58,9 @@ class PluginModule; } namespace WebKit { -class WebFileChooserCompletion; class WebGamepads; class WebMouseEvent; struct WebCompositionUnderline; -struct WebFileChooserParams; } namespace content { @@ -209,9 +207,6 @@ class PepperPluginDelegateImpl int total, bool final_result) OVERRIDE; virtual void SelectedFindResultChanged(int identifier, int index) OVERRIDE; - virtual bool RunFileChooser( - const WebKit::WebFileChooserParams& params, - WebKit::WebFileChooserCompletion* chooser_completion) OVERRIDE; virtual bool AsyncOpenFile(const FilePath& path, int flags, const AsyncOpenFileCallback& callback) OVERRIDE; diff --git a/ppapi/host/dispatch_host_message.h b/ppapi/host/dispatch_host_message.h new file mode 100644 index 0000000..3e60e57 --- /dev/null +++ b/ppapi/host/dispatch_host_message.h @@ -0,0 +1,78 @@ +// 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 "ipc/ipc_message_macros.h" + +// This file provides infrastructure for dispatching host resource call +// messages. Normal IPC message handlers can't take extra parameters or +// return values. We want to take a HostMessageContext as a parameter and +// also return the int32_t return value to the caller. + +#include "base/profiler/scoped_profile.h" // For TRACK_RUN_IN_IPC_HANDLER. +#include "ppapi/c/pp_errors.h" + +namespace ppapi { +namespace host { + +struct HostMessageContext; + +template <class ObjT, class Method> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple0& arg) { + return (obj->*method)(context); +} + +template <class ObjT, class Method, class A> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple1<A>& arg) { + return (obj->*method)(context, arg.a); +} + +template<class ObjT, class Method, class A, class B> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple2<A, B>& arg) { + return (obj->*method)(context, arg.a, arg.b); +} + +template<class ObjT, class Method, class A, class B, class C> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple3<A, B, C>& arg) { + return (obj->*method)(context, arg.a, arg.b, arg.c); +} + +template<class ObjT, class Method, class A, class B, class C, class D> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple4<A, B, C, D>& arg) { + return (obj->*method)(context, arg.a, arg.b, arg.c, arg.d); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E> +inline int32_t DispatchResourceCall(ObjT* obj, Method method, + HostMessageContext* context, + const Tuple5<A, B, C, D, E>& arg) { + return (obj->*method)(context, arg.a, arg.b, arg.c, arg.d, arg.e); +} + +#define PPAPI_DISPATCH_HOST_RESOURCE_CALL(msg_class, member_func) \ + case msg_class::ID: { \ + TRACK_RUN_IN_IPC_HANDLER(member_func); \ + msg_class::Schema::Param p; \ + if (msg_class::Read(&ipc_message__, &p)) { \ + return ppapi::host::DispatchResourceCall( \ + this, \ + &_IpcMessageHandlerClass::member_func, \ + context, p); \ + } else { \ + return PP_ERROR_FAILED; \ + } \ + } \ + break; + +} // namespace host +} // namespace ppapi diff --git a/ppapi/ppapi_host.gypi b/ppapi/ppapi_host.gypi index bc99538..c2f9ff8 100644 --- a/ppapi/ppapi_host.gypi +++ b/ppapi/ppapi_host.gypi @@ -19,6 +19,7 @@ 'PPAPI_HOST_IMPLEMENTATION', ], 'sources': [ + 'host/dispatch_host_message.h', 'host/host_factory.h', 'host/host_message_context.h', 'host/ppapi_host.cc', diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index 7a21f15..d6ed428 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -24,6 +24,8 @@ 'proxy/dispatcher.cc', 'proxy/dispatcher.h', 'proxy/enter_proxy.h', + 'proxy/file_chooser_resource.cc', + 'proxy/file_chooser_resource.h', 'proxy/host_dispatcher.cc', 'proxy/host_dispatcher.h', 'proxy/host_var_serialization_rules.cc', @@ -43,6 +45,8 @@ 'proxy/plugin_main_nacl.cc', 'proxy/plugin_message_filter.cc', 'proxy/plugin_message_filter.h', + 'proxy/plugin_resource.cc', + 'proxy/plugin_resource.h', 'proxy/plugin_resource_tracker.cc', 'proxy/plugin_resource_tracker.h', 'proxy/plugin_var_serialization_rules.cc', @@ -65,8 +69,6 @@ 'proxy/ppb_buffer_proxy.h', 'proxy/ppb_core_proxy.cc', 'proxy/ppb_core_proxy.h', - 'proxy/ppb_file_chooser_proxy.cc', - 'proxy/ppb_file_chooser_proxy.h', 'proxy/ppb_file_io_proxy.cc', 'proxy/ppb_file_io_proxy.h', 'proxy/ppb_file_ref_proxy.cc', diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index 32682c1..0f52b17 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi @@ -140,6 +140,7 @@ 'sources': [ 'proxy/run_all_unittests.cc', + 'proxy/file_chooser_resource_unittest.cc', 'proxy/mock_resource.cc', 'proxy/mock_resource.h', 'proxy/plugin_dispatcher_unittest.cc', diff --git a/ppapi/proxy/file_chooser_resource.cc b/ppapi/proxy/file_chooser_resource.cc new file mode 100644 index 0000000..f4e21ec --- /dev/null +++ b/ppapi/proxy/file_chooser_resource.cc @@ -0,0 +1,149 @@ +// 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/file_chooser_resource.h" + +#include "base/string_split.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +FileChooserResource::FileChooserResource(IPC::Sender* sender, + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const std::string& accept_types) + : PluginResource(sender, instance), + mode_(mode) { + PopulateAcceptTypes(accept_types, &accept_types_); +} + +FileChooserResource::~FileChooserResource() { +} + +thunk::PPB_FileChooser_API* FileChooserResource::AsPPB_FileChooser_API() { + return this; +} + +int32_t FileChooserResource::Show(const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + return ShowWithoutUserGesture(PP_FALSE, PP_MakeUndefined(), output, callback); +} + +int32_t FileChooserResource::ShowWithoutUserGesture( + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + int32_t result = ShowInternal(PP_FALSE, suggested_file_name, callback); + if (result == PP_OK_COMPLETIONPENDING) + output_.set_pp_array_output(output); + return result; +} + +int32_t FileChooserResource::Show0_5(scoped_refptr<TrackedCallback> callback) { + return ShowInternal(PP_FALSE, PP_MakeUndefined(), callback); +} + +PP_Resource FileChooserResource::GetNextChosenFile() { + if (file_queue_.empty()) + return 0; + + // Return the next resource in the queue. It will already have been addrefed + // (they're currently owned by the FileChooser) and returning it transfers + // ownership of that reference to the plugin. + PP_Resource next = file_queue_.front(); + file_queue_.pop(); + return next; +} + +int32_t FileChooserResource::ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, + scoped_refptr<TrackedCallback> callback) { + return ShowInternal(save_as, suggested_file_name, callback); +} + +// static +void FileChooserResource::PopulateAcceptTypes( + const std::string& input, + std::vector<std::string>* output) { + if (input.empty()) + return; + + std::vector<std::string> type_list; + base::SplitString(input, ',', &type_list); + output->reserve(type_list.size()); + + for (size_t i = 0; i < type_list.size(); ++i) { + std::string type = type_list[i]; + TrimWhitespaceASCII(type, TRIM_ALL, &type); + + // If the type is a single character, it definitely cannot be valid. In the + // case of a file extension it would be a single ".". In the case of a MIME + // type it would just be a "/". + if (type.length() < 2) + continue; + if (type.find_first_of('/') == std::string::npos && type[0] != '.') + continue; + StringToLowerASCII(&type); + output->push_back(type); + } +} + +void FileChooserResource::OnReplyReceived(int /* sequence */, + int32_t result, + const IPC::Message& msg) { + PpapiPluginMsg_FileChooser_ShowReply::Schema::Param param; + PpapiPluginMsg_FileChooser_ShowReply::Read(&msg, ¶m); + const std::vector<ppapi::PPB_FileRef_CreateInfo>& chosen_files = param.a; + + 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(&callback_, PP_OK); + // DANGER: May delete |this|! +} + +int32_t FileChooserResource::ShowInternal( + PP_Bool save_as, + const PP_Var& suggested_file_name, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(callback_)) + return PP_ERROR_INPROGRESS; + + if (!sent_create_to_renderer()) + SendCreateToRenderer(PpapiHostMsg_FileChooser_Create()); + + callback_ = callback; + StringVar* sugg_str = StringVar::FromPPVar(suggested_file_name); + + CallRenderer(PpapiHostMsg_FileChooser_Show( + PP_ToBool(save_as), + mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE, + sugg_str ? sugg_str->value() : std::string(), + accept_types_)); + return PP_OK_COMPLETIONPENDING; +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/file_chooser_resource.h b/ppapi/proxy/file_chooser_resource.h new file mode 100644 index 0000000..adb20a4 --- /dev/null +++ b/ppapi/proxy/file_chooser_resource.h @@ -0,0 +1,89 @@ +// 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_FILE_CHOOSER_RESOURCE_H_ +#define PPAPI_PROXY_FILE_CHOOSER_RESOURCE_H_ + +#include <queue> +#include <string> +#include <vector> + +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_file_chooser_api.h" + +namespace ppapi { + +struct PPB_FileRef_CreateInfo; + +namespace proxy { + +class PPAPI_PROXY_EXPORT FileChooserResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_FileChooser_API) { + public: + FileChooserResource(IPC::Sender* sender, + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const std::string& accept_types); + virtual ~FileChooserResource(); + + // Resource overrides. + virtual thunk::PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; + + // PPB_FileChooser_API. + virtual int32_t Show(const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ShowWithoutUserGesture( + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Show0_5(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Resource GetNextChosenFile() OVERRIDE; + virtual int32_t ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + // Parses the accept string into the given vector. + static void PopulateAcceptTypes(const std::string& input, + std::vector<std::string>* output); + + private: + // PluginResource override. + virtual void OnReplyReceived(int sequence, + int32_t result, + const IPC::Message& msg) OVERRIDE; + + void OnPluginMsgShowReply( + const std::vector<ppapi::PPB_FileRef_CreateInfo>& chosen_files); + + int32_t ShowInternal(PP_Bool save_as, + const PP_Var& suggested_file_name, + scoped_refptr<TrackedCallback> callback); + + PP_FileChooserMode_Dev mode_; + std::vector<std::string> accept_types_; + + // When using v0.6 of the API, contains the array output info. + ArrayWriter output_; + + // 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_; + + scoped_refptr<TrackedCallback> callback_; + + DISALLOW_COPY_AND_ASSIGN(FileChooserResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FILE_CHOOSER_RESOURCE_H_ diff --git a/ppapi/proxy/file_chooser_resource_unittest.cc b/ppapi/proxy/file_chooser_resource_unittest.cc new file mode 100644 index 0000000..10ac0b3 --- /dev/null +++ b/ppapi/proxy/file_chooser_resource_unittest.cc @@ -0,0 +1,140 @@ +// 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 "base/message_loop.h" +#include "ppapi/c/dev/ppb_file_chooser_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/file_chooser_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/thunk/thunk.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest FileChooserResourceTest; + +void* GetFileRefDataBuffer(void* user_data, + uint32_t element_count, + uint32_t element_size) { + EXPECT_TRUE(element_size == sizeof(PP_Resource)); + std::vector<PP_Resource>* output = + static_cast<std::vector<PP_Resource>*>(user_data); + output->resize(element_count); + if (element_count > 0) + return &(*output)[0]; + return NULL; +} + +void DoNothingCallback(void* user_data, int32_t result) { +} + +// Calls PopulateAcceptTypes and verifies that the resulting array contains +// the given values. The values may be NULL if there aren't expected to be +// that many results. +bool CheckParseAcceptType(const std::string& input, + const char* expected1, + const char* expected2) { + std::vector<std::string> output; + FileChooserResource::PopulateAcceptTypes(input, &output); + + const size_t kCount = 2; + const char* expected[kCount] = { expected1, expected2 }; + + for (size_t i = 0; i < kCount; i++) { + if (!expected[i]) + return i == output.size(); + if (output.size() <= i) + return false; + if (output[i] != expected[i]) + return false; + } + + return output.size() == kCount; +} + +} // namespace + +// Does a full test of Show() and reply functionality in the plugin side using +// the public C interfaces. +TEST_F(FileChooserResourceTest, Show) { + const PPB_FileChooser_Dev_0_6* chooser_iface = + thunk::GetPPB_FileChooser_Dev_0_6_Thunk(); + ScopedPPResource res(ScopedPPResource::PassRef(), + chooser_iface->Create(pp_instance(), PP_FILECHOOSERMODE_OPEN, + PP_MakeUndefined())); + + std::vector<PP_Resource> dest; + PP_ArrayOutput output; + output.GetDataBuffer = &GetFileRefDataBuffer; + output.user_data = &dest; + + int32_t result = chooser_iface->Show( + res, output, PP_MakeCompletionCallback(&DoNothingCallback, NULL)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + // Should have sent a "show" message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_FileChooser_Show::ID, ¶ms, &msg)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(PP_OK); + + // Synthesize a response with one file ref in it. Note that it must have a + // host resource value set or deserialization will fail. Since there isn't + // actually a host, this can be whatever we want. + std::vector<PPB_FileRef_CreateInfo> create_info_array; + PPB_FileRef_CreateInfo create_info; + create_info.resource.SetHostResource(pp_instance(), 123); + create_info.path = "foo/bar"; + create_info.name = "baz"; + create_info_array.push_back(create_info); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(reply_params, + PpapiPluginMsg_FileChooser_ShowReply(create_info_array)))); + + // Should have populated our vector. + ASSERT_EQ(1u, dest.size()); + ScopedPPResource dest_deletor(dest[0]); // Ensure it's cleaned up. + + const PPB_FileRef_1_0* file_ref_iface = thunk::GetPPB_FileRef_1_0_Thunk(); + EXPECT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, + file_ref_iface->GetFileSystemType(dest[0])); + + ScopedPPVar name_var(ScopedPPVar::PassRef(), + file_ref_iface->GetName(dest[0])); + EXPECT_VAR_IS_STRING(create_info.name, name_var.get()); + + // Path should be undefined since it's external filesystem. + ScopedPPVar path_var(ScopedPPVar::PassRef(), + file_ref_iface->GetPath(dest[0])); + EXPECT_EQ(PP_VARTYPE_UNDEFINED, path_var.get().type); +} + +TEST_F(FileChooserResourceTest, PopulateAcceptTypes) { + EXPECT_TRUE(CheckParseAcceptType(std::string(), NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType("/", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType(".", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType(",, , ", NULL, NULL)); + + EXPECT_TRUE(CheckParseAcceptType("app/txt", "app/txt", NULL)); + EXPECT_TRUE(CheckParseAcceptType("app/txt,app/pdf", "app/txt", "app/pdf")); + EXPECT_TRUE(CheckParseAcceptType(" app/txt , app/pdf ", + "app/txt", "app/pdf")); + + // No dot or slash ones should be skipped. + EXPECT_TRUE(CheckParseAcceptType("foo", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType("foo,.txt", ".txt", NULL)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index f9d3471..21dc269 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -183,6 +183,11 @@ bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { BoolRestorer restorer(&allow_plugin_reentrancy_); allow_plugin_reentrancy_ = false; + for (size_t i = 0; i < filters_.size(); i++) { + if (filters_[i]->OnMessageReceived(msg)) + return true; + } + bool handled = true; IPC_BEGIN_MESSAGE_MAP(HostDispatcher, msg) IPC_MESSAGE_HANDLER(PpapiHostMsg_LogWithSource, OnHostMsgLogWithSource) diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index ffed09f..72a99b3 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -80,7 +80,6 @@ #include "ppapi/proxy/ppb_broker_proxy.h" #include "ppapi/proxy/ppb_buffer_proxy.h" #include "ppapi/proxy/ppb_core_proxy.h" -#include "ppapi/proxy/ppb_file_chooser_proxy.h" #include "ppapi/proxy/ppb_file_io_proxy.h" #include "ppapi/proxy/ppb_file_ref_proxy.h" #include "ppapi/proxy/ppb_file_system_proxy.h" diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index 9cf606e..9314713 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -23,6 +23,8 @@ #include "ppapi/proxy/ppb_instance_proxy.h" #include "ppapi/proxy/ppp_class_proxy.h" #include "ppapi/proxy/resource_creation_proxy.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/resource.h" @@ -189,10 +191,12 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", "Class", IPC_MESSAGE_ID_CLASS(msg.type()), "Line", IPC_MESSAGE_ID_LINE(msg.type())); + if (msg.routing_id() == MSG_ROUTING_CONTROL) { // Handle some plugin-specific control messages. bool handled = true; IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply) IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) IPC_MESSAGE_UNHANDLED(handled = false); @@ -271,6 +275,19 @@ void PluginDispatcher::ForceFreeAllInstances() { } } +void PluginDispatcher::OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg) { + Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource( + reply_params.pp_resource()); + if (!resource) { + NOTREACHED(); + return; + } + resource->OnReplyReceived(reply_params.sequence(), reply_params.result(), + nested_msg); +} + void PluginDispatcher::OnMsgSupportsInterface( const std::string& interface_name, bool* result) { diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 5dd6725..d7c118e 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -34,6 +34,8 @@ class ResourceCreationAPI; namespace proxy { +class ResourceMessageReplyParams; + // Used to keep track of per-instance data. struct InstanceData { InstanceData(); @@ -142,6 +144,9 @@ class PPAPI_PROXY_EXPORT PluginDispatcher void ForceFreeAllInstances(); // IPC message handlers. + void OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg); void OnMsgSupportsInterface(const std::string& interface_name, bool* result); void OnMsgSetPreferences(const Preferences& prefs); diff --git a/ppapi/proxy/plugin_resource.cc b/ppapi/proxy/plugin_resource.cc new file mode 100644 index 0000000..6e387bb --- /dev/null +++ b/ppapi/proxy/plugin_resource.cc @@ -0,0 +1,52 @@ +// 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/plugin_resource.h" + +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" + +namespace ppapi { +namespace proxy { + +PluginResource::PluginResource(IPC::Sender* sender, PP_Instance instance) + : Resource(OBJECT_IS_PROXY, instance), + sender_(sender), + next_sequence_number_(0), + sent_create_to_renderer_(false) { +} + +PluginResource::~PluginResource() { + if (sent_create_to_renderer_) + Send(new PpapiHostMsg_ResourceDestroyed(pp_resource())); +} + +bool PluginResource::Send(IPC::Message* message) { + return sender_->Send(message); +} + +void PluginResource::SendCreateToRenderer(const IPC::Message& msg) { + DCHECK(!sent_create_to_renderer_); + sent_create_to_renderer_ = true; + ResourceMessageCallParams params(pp_resource(), + next_sequence_number_++); + Send(new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg)); +} + +void PluginResource::PostToRenderer(const IPC::Message& msg) { + ResourceMessageCallParams params(pp_resource(), + next_sequence_number_++); + Send(new PpapiHostMsg_ResourceCall(params, msg)); +} + +int32_t PluginResource::CallRenderer(const IPC::Message& msg) { + ResourceMessageCallParams params(pp_resource(), + next_sequence_number_++); + params.set_has_callback(); + Send(new PpapiHostMsg_ResourceCall(params, msg)); + return params.sequence(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h new file mode 100644 index 0000000..28d1274 --- /dev/null +++ b/ppapi/proxy/plugin_resource.h @@ -0,0 +1,64 @@ +// 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_PLUGIN_RESOURCE_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_H_ + +#include "base/compiler_specific.h" +#include "ipc/ipc_sender.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/resource.h" + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class PluginDispatcher; + +class PPAPI_PROXY_EXPORT PluginResource : public Resource, + public IPC::Sender { + public: + PluginResource(IPC::Sender* sender, + PP_Instance instance); + virtual ~PluginResource(); + + // IPC::Sender implementation. + virtual bool Send(IPC::Message* message) OVERRIDE; + + bool sent_create_to_renderer() const { return sent_create_to_renderer_; } + + protected: + // Sends a create message to the renderer for the current resource. + void SendCreateToRenderer(const IPC::Message& msg); + + // Sends the given IPC message as a resource request to the host + // corresponding to this resource object and does not expect a reply. + void PostToRenderer(const IPC::Message& msg); + + // Like PostToRenderer but expects a response. + // + // Returns the new request's sequence number which can be used to identify + // the callback. The host will reply and ppapi::Resource::OnReplyReceived + // will be called. + // + // Note that all integers (including 0 and -1) are valid request IDs. + int32_t CallRenderer(const IPC::Message& msg); + + private: + IPC::Sender* sender_; + + int32_t next_sequence_number_; + + bool sent_create_to_renderer_; + + DISALLOW_COPY_AND_ASSIGN(PluginResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_H_ diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index e7881a6..b57e8eb 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -561,13 +561,6 @@ IPC_MESSAGE_ROUTED3( IPC::PlatformFileForTransit /* handle */, int32_t /* result */) -// PPB_FileChooser. -IPC_MESSAGE_ROUTED3( - PpapiMsg_PPBFileChooser_ChooseComplete, - ppapi::HostResource /* chooser */, - int32_t /* result_code (will be != PP_OK on failure */, - std::vector<ppapi::PPB_FileRef_CreateInfo> /* chosen_files */) - // PPB_NetworkMonitor_Private. IPC_MESSAGE_ROUTED2(PpapiMsg_PPBNetworkMonitor_NetworkList, uint32 /* plugin_dispatcher_id */, @@ -1123,18 +1116,6 @@ IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBBuffer_Create, ppapi::HostResource /* result_resource */, base::SharedMemoryHandle /* result_shm_handle */) -// PPB_FileChooser. -IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFileChooser_Create, - PP_Instance /* instance */, - int /* mode */, - std::string /* accept_types */, - ppapi::HostResource /* result */) -IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBFileChooser_Show, - ppapi::HostResource /* file_chooser */, - PP_Bool /* save_as */, - ppapi::proxy::SerializedVar /* suggested_file_name */, - bool /* require_user_gesture */) - // PPB_NetworkMonitor_Private. IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBNetworkMonitor_Start, uint32 /* plugin_dispatcher_id */) @@ -1442,3 +1423,16 @@ IPC_MESSAGE_CONTROL2( PpapiPluginMsg_ResourceReply, ppapi::proxy::ResourceMessageReplyParams /* reply_params */, IPC::Message /* nested_msg */) + +//----------------------------------------------------------------------------- +// Messages for resources using call/reply above. + +// File chooser. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileChooser_Create) +IPC_MESSAGE_CONTROL4(PpapiHostMsg_FileChooser_Show, + bool /* save_as */, + bool /* open_multiple */, + std::string /* suggested_file_name */, + std::vector<std::string> /* accept_mime_types */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileChooser_ShowReply, + std::vector<ppapi::PPB_FileRef_CreateInfo> /* files */) diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc index 1e68afc..9f0422e 100644 --- a/ppapi/proxy/ppapi_proxy_test.cc +++ b/ppapi/proxy/ppapi_proxy_test.cc @@ -410,6 +410,5 @@ void TwoWayTest::TearDown() { io_thread_.Stop(); } - } // namespace proxy } // namespace ppapi diff --git a/ppapi/proxy/ppapi_proxy_test.h b/ppapi/proxy/ppapi_proxy_test.h index b4ad1b5..782b8c4 100644 --- a/ppapi/proxy/ppapi_proxy_test.h +++ b/ppapi/proxy/ppapi_proxy_test.h @@ -9,7 +9,6 @@ #include "base/memory/scoped_ptr.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" -#include "ipc/ipc_test_sink.h" #include "ppapi/c/pp_instance.h" #include "ppapi/proxy/host_dispatcher.h" #include "ppapi/proxy/plugin_dispatcher.h" @@ -17,6 +16,7 @@ #include "ppapi/proxy/plugin_proxy_delegate.h" #include "ppapi/proxy/plugin_resource_tracker.h" #include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/resource_message_test_sink.h" #include "ppapi/shared_impl/test_globals.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,7 +32,7 @@ class ProxyTestHarnessBase { PP_Module pp_module() const { return pp_module_; } PP_Instance pp_instance() const { return pp_instance_; } - IPC::TestSink& sink() { return sink_; } + ResourceMessageTestSink& sink() { return sink_; } virtual PpapiGlobals* GetGlobals() = 0; // Returns either the plugin or host dispatcher, depending on the test. @@ -65,7 +65,7 @@ class ProxyTestHarnessBase { private: // Destination for IPC messages sent by the test. - IPC::TestSink sink_; + ResourceMessageTestSink sink_; // The module and instance ID associated with the plugin dispatcher. PP_Module pp_module_; @@ -271,5 +271,16 @@ class TwoWayTest : public testing::Test { base::WaitableEvent shutdown_event_; }; +// Used during Gtests when you have a PP_Var that you want to EXPECT is equal +// to a certain constant string value: +// +// EXPECT_VAR_IS_STRING("foo", my_var); +#define EXPECT_VAR_IS_STRING(str, var) { \ + StringVar* sv = StringVar::FromPPVar(var); \ + EXPECT_TRUE(sv); \ + if (sv) \ + EXPECT_EQ(str, sv->value()); \ +} + } // namespace proxy } // namespace ppapi diff --git a/ppapi/proxy/ppb_file_chooser_proxy.cc b/ppapi/proxy/ppb_file_chooser_proxy.cc deleted file mode 100644 index 26ab430..0000000 --- a/ppapi/proxy/ppb_file_chooser_proxy.cc +++ /dev/null @@ -1,311 +0,0 @@ -// 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/ppb_file_chooser_proxy.h" - -#include <queue> - -#include "base/bind.h" -#include "ppapi/c/dev/ppb_file_chooser_dev.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/private/ppb_proxy_private.h" -#include "ppapi/c/trusted/ppb_file_chooser_trusted.h" -#include "ppapi/proxy/enter_proxy.h" -#include "ppapi/proxy/host_dispatcher.h" -#include "ppapi/proxy/plugin_dispatcher.h" -#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" -#include "ppapi/shared_impl/var.h" -#include "ppapi/thunk/resource_creation_api.h" -#include "ppapi/thunk/thunk.h" - -using ppapi::thunk::PPB_FileChooser_API; - -namespace ppapi { -namespace proxy { - -namespace { -InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher) { - return new PPB_FileChooser_Proxy(dispatcher); -} - -class FileChooser : public Resource, - public PPB_FileChooser_API { - public: - FileChooser(const HostResource& resource); - virtual ~FileChooser(); - - // Resource overrides. - virtual PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; - - // PPB_FileChooser_API implementation. - virtual int32_t Show(const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual int32_t ShowWithoutUserGesture( - PP_Bool save_as, - PP_Var suggested_file_name, - const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> callback); - virtual int32_t Show0_5(scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual PP_Resource GetNextChosenFile() OVERRIDE; - virtual int32_t ShowWithoutUserGesture0_5( - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr<TrackedCallback> callback) OVERRIDE; - - // Handles the choose complete notification from the host. - void ChooseComplete( - int32_t result_code, - const std::vector<PPB_FileRef_CreateInfo>& chosen_files); - - private: - int32_t Show(bool require_user_gesture, - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr<TrackedCallback> callback); - - // When using v0.6 of the API, contains the array output info. - ArrayWriter output_; - - scoped_refptr<TrackedCallback> current_show_callback_; - - // 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); -}; - -FileChooser::FileChooser(const HostResource& resource) - : Resource(OBJECT_IS_PROXY, resource) { -} - -FileChooser::~FileChooser() { - // Any existing files we haven't transferred ownership to the plugin need - // to be freed. - ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); - while (!file_queue_.empty()) { - tracker->ReleaseResource(file_queue_.front()); - file_queue_.pop(); - } -} - -PPB_FileChooser_API* FileChooser::AsPPB_FileChooser_API() { - return this; -} - -int32_t FileChooser::Show(const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> 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( - PP_Bool save_as, - PP_Var suggested_file_name, - const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> callback) { - int32_t result = Show(false, save_as, suggested_file_name, callback); - if (result == PP_OK_COMPLETIONPENDING) - output_.set_pp_array_output(output); - return result; -} - -int32_t FileChooser::Show0_5(scoped_refptr<TrackedCallback> callback) { - return Show(true, PP_FALSE, PP_MakeUndefined(), callback); -} - -int32_t FileChooser::ShowWithoutUserGesture0_5( - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr<TrackedCallback> callback) { - return Show(false, save_as, suggested_file_name, callback); -} - -int32_t FileChooser::Show(bool require_user_gesture, - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr<TrackedCallback> callback) { - if (TrackedCallback::IsPending(current_show_callback_)) - return PP_ERROR_INPROGRESS; // Can't show more than once. - - current_show_callback_ = callback; - PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); - dispatcher->Send( - new PpapiHostMsg_PPBFileChooser_Show( - API_ID_PPB_FILE_CHOOSER, - host_resource(), - save_as, - SerializedVarSendInput(dispatcher, suggested_file_name), - require_user_gesture)); - return PP_OK_COMPLETIONPENDING; -} - -PP_Resource FileChooser::GetNextChosenFile() { - if (file_queue_.empty()) - return 0; - - // Return the next resource in the queue. These resource have already been - // addrefed (they're currently owned by the FileChooser) and returning them - // transfers ownership of that reference to the plugin. - PP_Resource next = file_queue_.front(); - file_queue_.pop(); - return next; -} - -void FileChooser::ChooseComplete( - int32_t result_code, - const std::vector<PPB_FileRef_CreateInfo>& chosen_files) { - 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); - // DANGER: May delete |this|! -} - -} // namespace - -PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher) - : InterfaceProxy(dispatcher), - callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { -} - -PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() { -} - -// static -PP_Resource PPB_FileChooser_Proxy::CreateProxyResource( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types) { - Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); - if (!dispatcher) - return 0; - - HostResource result; - dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create( - API_ID_PPB_FILE_CHOOSER, instance, - mode, - accept_types ? accept_types : "", - &result)); - - if (result.is_null()) - return 0; - return (new FileChooser(result))->GetReference(); -} - -bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg) - // Plugin -> host messages. - IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate) - IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow) - - // Host -> plugin messages. - IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete, - OnMsgChooseComplete) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PPB_FileChooser_Proxy::OnMsgCreate( - PP_Instance instance, - int mode, - std::string accept_types, - HostResource* result) { - thunk::EnterResourceCreation enter(instance); - if (enter.succeeded()) { - result->SetHostResource(instance, enter.functions()->CreateFileChooser( - instance, - static_cast<PP_FileChooserMode_Dev>(mode), - accept_types.c_str())); - } -} - -void PPB_FileChooser_Proxy::OnMsgShow( - const HostResource& chooser, - 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_.NewOptionalCallback( - &PPB_FileChooser_Proxy::OnShowCallback, output, chooser)); - if (enter.succeeded()) { - if (require_user_gesture) { - enter.SetResult(enter.object()->Show(output->pp_array_output(), - enter.callback())); - } else { - enter.SetResult(enter.object()->ShowWithoutUserGesture( - save_as, - suggested_file_name.Get(dispatcher()), - output->pp_array_output(), - enter.callback())); - } - } -} - -void PPB_FileChooser_Proxy::OnMsgChooseComplete( - const HostResource& chooser, - int32_t result_code, - const std::vector<PPB_FileRef_CreateInfo>& chosen_files) { - EnterPluginFromHostResource<PPB_FileChooser_API> enter(chooser); - if (enter.succeeded()) { - static_cast<FileChooser*>(enter.object())->ChooseComplete( - result_code, chosen_files); - } -} - -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; - if (enter.succeeded() && result == PP_OK) { - PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>( - dispatcher()->GetInterfaceProxy(API_ID_PPB_FILE_REF)); - - // Convert the returned files to the serialized info. - for (size_t i = 0; i < output->output().size(); i++) { - PPB_FileRef_CreateInfo cur_create_info; - file_ref_proxy->SerializeFileRef(output->output()[i], &cur_create_info); - files.push_back(cur_create_info); - } - } - - dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete( - API_ID_PPB_FILE_CHOOSER, chooser, result, files)); -} - -} // namespace proxy -} // namespace ppapi diff --git a/ppapi/proxy/ppb_file_chooser_proxy.h b/ppapi/proxy/ppb_file_chooser_proxy.h deleted file mode 100644 index 1dc0921..0000000 --- a/ppapi/proxy/ppb_file_chooser_proxy.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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_PPB_FILE_CHOOSER_PROXY_H_ -#define PPAPI_PROXY_PPB_FILE_CHOOSER_PROXY_H_ - -#include <string> -#include <vector> - -#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_completion_callback_factory.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 { - -class HostResource; -struct PPB_FileRef_CreateInfo; - -namespace proxy { - -class PPB_FileChooser_Proxy : public InterfaceProxy { - public: - explicit PPB_FileChooser_Proxy(Dispatcher* dispatcher); - virtual ~PPB_FileChooser_Proxy(); - - static PP_Resource CreateProxyResource( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types); - - // InterfaceProxy implementation. - virtual bool OnMessageReceived(const IPC::Message& msg); - - static const ApiID kApiID = API_ID_PPB_FILE_CHOOSER; - - private: - // Plugin -> host message handlers. - void OnMsgCreate(PP_Instance instance, - int mode, - std::string accept_types, - ppapi::HostResource* result); - void OnMsgShow(const ppapi::HostResource& chooser, - PP_Bool save_as, - SerializedVarReceiveInput suggested_file_name, - bool require_user_gesture); - - // Host -> plugin message handlers. - void OnMsgChooseComplete( - const ppapi::HostResource& chooser, - int32_t result_code, - const std::vector<PPB_FileRef_CreateInfo>& chosen_files); - - // 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, - scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output, - HostResource chooser); - - ProxyCompletionCallbackFactory<PPB_FileChooser_Proxy> callback_factory_; - - DISALLOW_COPY_AND_ASSIGN(PPB_FileChooser_Proxy); -}; - -} // namespace proxy -} // namespace ppapi - -#endif // PPAPI_PROXY_PPB_FILE_CHOOSER_PROXY_H_ diff --git a/ppapi/proxy/ppb_file_ref_proxy.cc b/ppapi/proxy/ppb_file_ref_proxy.cc index d8ffde6..3889c77 100644 --- a/ppapi/proxy/ppb_file_ref_proxy.cc +++ b/ppapi/proxy/ppb_file_ref_proxy.cc @@ -217,6 +217,7 @@ bool PPB_FileRef_Proxy::OnMessageReceived(const IPC::Message& msg) { return handled; } +// static void PPB_FileRef_Proxy::SerializeFileRef(PP_Resource file_ref, PPB_FileRef_CreateInfo* result) { EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, false); diff --git a/ppapi/proxy/ppb_file_ref_proxy.h b/ppapi/proxy/ppb_file_ref_proxy.h index 64febfa..e4a412e 100644 --- a/ppapi/proxy/ppb_file_ref_proxy.h +++ b/ppapi/proxy/ppb_file_ref_proxy.h @@ -12,6 +12,7 @@ #include "ppapi/c/pp_resource.h" #include "ppapi/c/pp_time.h" #include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" #include "ppapi/proxy/proxy_completion_callback_factory.h" #include "ppapi/utility/completion_callback_factory.h" @@ -24,7 +25,8 @@ namespace proxy { class SerializedVarReturnValue; -class PPB_FileRef_Proxy : public InterfaceProxy { +class PPAPI_PROXY_EXPORT PPB_FileRef_Proxy + : public NON_EXPORTED_BASE(InterfaceProxy) { public: explicit PPB_FileRef_Proxy(Dispatcher* dispatcher); virtual ~PPB_FileRef_Proxy(); @@ -41,13 +43,10 @@ class PPB_FileRef_Proxy : public InterfaceProxy { // "create info" for reconstitution in the plugin. This struct contains all // the necessary information about the file ref. // - // This function is not static because it needs access to the particular - // dispatcher and host interface. - // // Various PPAPI functions return file refs from various interfaces, so this // function is public so anybody can send a file ref. - void SerializeFileRef(PP_Resource file_ref, - PPB_FileRef_CreateInfo* result); + static void SerializeFileRef(PP_Resource file_ref, + PPB_FileRef_CreateInfo* result); // Creates a plugin resource from the given CreateInfo sent from the host. // The value will be the result of calling SerializeFileRef on the host. diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc index 7cbab75..51dd334 100644 --- a/ppapi/proxy/resource_creation_proxy.cc +++ b/ppapi/proxy/resource_creation_proxy.cc @@ -7,6 +7,7 @@ #include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_size.h" #include "ppapi/c/trusted/ppb_image_data_trusted.h" +#include "ppapi/proxy/file_chooser_resource.h" #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/plugin_resource_tracker.h" #include "ppapi/proxy/ppapi_messages.h" @@ -14,7 +15,6 @@ #include "ppapi/proxy/ppb_audio_proxy.h" #include "ppapi/proxy/ppb_buffer_proxy.h" #include "ppapi/proxy/ppb_broker_proxy.h" -#include "ppapi/proxy/ppb_file_chooser_proxy.h" #include "ppapi/proxy/ppb_file_io_proxy.h" #include "ppapi/proxy/ppb_file_ref_proxy.h" #include "ppapi/proxy/ppb_file_system_proxy.h" @@ -241,8 +241,8 @@ PP_Resource ResourceCreationProxy::CreateFileChooser( PP_Instance instance, PP_FileChooserMode_Dev mode, const char* accept_types) { - return PPB_FileChooser_Proxy::CreateProxyResource(instance, mode, - accept_types); + return (new FileChooserResource(dispatcher(), instance, mode, + accept_types))->GetReference(); } PP_Resource ResourceCreationProxy::CreateFlashDeviceID(PP_Instance instance) { diff --git a/ppapi/shared_impl/ppb_file_ref_shared.cc b/ppapi/shared_impl/ppb_file_ref_shared.cc index b273364..a47cdb8 100644 --- a/ppapi/shared_impl/ppb_file_ref_shared.cc +++ b/ppapi/shared_impl/ppb_file_ref_shared.cc @@ -17,7 +17,6 @@ PPB_FileRef_Shared::PPB_FileRef_Shared(ResourceObjectType type, // Resource's constructor assigned a PP_Resource, so we can fill out our // host resource now. create_info_.resource = host_resource(); - DCHECK(!create_info_.resource.is_null()); } } diff --git a/ppapi/thunk/interfaces_ppb_private.h b/ppapi/thunk/interfaces_ppb_private.h index d2378b4..50d3ea4 100644 --- a/ppapi/thunk/interfaces_ppb_private.h +++ b/ppapi/thunk/interfaces_ppb_private.h @@ -23,9 +23,9 @@ PROXIED_IFACE(PPB_Instance, PPB_BROWSERFONT_TRUSTED_INTERFACE_1_0, PPB_BrowserFont_Trusted_1_0) PROXIED_IFACE(PPB_Instance, PPB_CHARSET_TRUSTED_INTERFACE_1_0, PPB_CharSet_Trusted_1_0) -PROXIED_IFACE(PPB_FileChooser, PPB_FILECHOOSER_TRUSTED_INTERFACE_0_5, +PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_TRUSTED_INTERFACE_0_5, PPB_FileChooserTrusted_0_5) -PROXIED_IFACE(PPB_FileChooser, PPB_FILECHOOSER_TRUSTED_INTERFACE_0_6, +PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_TRUSTED_INTERFACE_0_6, PPB_FileChooserTrusted_0_6) PROXIED_IFACE(PPB_FileRef, PPB_FILEREFPRIVATE_INTERFACE_0_1, PPB_FileRefPrivate_0_1) diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h index a204d22..418326b 100644 --- a/ppapi/thunk/interfaces_ppb_public_dev.h +++ b/ppapi/thunk/interfaces_ppb_public_dev.h @@ -10,7 +10,6 @@ PROXIED_API(PPB_AudioInput) PROXIED_API(PPB_Buffer) UNPROXIED_API(PPB_DirectoryReader) -PROXIED_API(PPB_FileChooser) PROXIED_API(PPB_Graphics3D) UNPROXIED_API(PPB_LayerCompositor) UNPROXIED_API(PPB_Scrollbar) @@ -38,9 +37,9 @@ PROXIED_IFACE(NoAPIName, PPB_DEVICEREF_DEV_INTERFACE_0_1, PPB_DeviceRef_Dev_0_1) UNPROXIED_IFACE(PPB_DirectoryReader, PPB_DIRECTORYREADER_DEV_INTERFACE_0_5, PPB_DirectoryReader_Dev_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, +PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_DEV_INTERFACE_0_5, PPB_FileChooser_Dev_0_5) -PROXIED_IFACE(PPB_FileChooser, PPB_FILECHOOSER_DEV_INTERFACE_0_6, +PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_DEV_INTERFACE_0_6, PPB_FileChooser_Dev_0_6) PROXIED_IFACE(NoAPIName, PPB_GRAPHICS2D_DEV_INTERFACE_0_1, PPB_Graphics2D_Dev_0_1) diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index e471305..9edf509 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -263,8 +263,6 @@ '../plugins/ppapi/ppb_buffer_impl.h', '../plugins/ppapi/ppb_directory_reader_impl.cc', '../plugins/ppapi/ppb_directory_reader_impl.h', - '../plugins/ppapi/ppb_file_chooser_impl.cc', - '../plugins/ppapi/ppb_file_chooser_impl.h', '../plugins/ppapi/ppb_file_io_impl.cc', '../plugins/ppapi/ppb_file_io_impl.h', '../plugins/ppapi/ppb_file_ref_impl.cc', diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index 08f4f2a..69279f7 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -130,12 +130,6 @@ void MockPluginDelegate::NumberOfFindResultsChanged(int identifier, void MockPluginDelegate::SelectedFindResultChanged(int identifier, int index) { } -bool MockPluginDelegate::RunFileChooser( - const WebKit::WebFileChooserParams& params, - WebKit::WebFileChooserCompletion* chooser_completion) { - return false; -} - bool MockPluginDelegate::AsyncOpenFile(const FilePath& path, int flags, const AsyncOpenFileCallback& callback) { diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index 2c7d6e2..9d74c2b 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -61,9 +61,6 @@ class MockPluginDelegate : public PluginDelegate { int total, bool final_result); virtual void SelectedFindResultChanged(int identifier, int index); - virtual bool RunFileChooser( - const WebKit::WebFileChooserParams& params, - WebKit::WebFileChooserCompletion* chooser_completion); virtual bool AsyncOpenFile(const FilePath& path, int flags, const AsyncOpenFileCallback& callback); diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index 7ba136e..9c3e38c 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -73,12 +73,10 @@ class PlatformCanvas; } namespace WebKit { -class WebFileChooserCompletion; class WebGamepads; class WebPlugin; struct WebCompositionUnderline; struct WebCursorInfo; -struct WebFileChooserParams; } namespace webkit_glue { @@ -417,11 +415,6 @@ class PluginDelegate { // Notifies that the index of the currently selected item has been updated. virtual void SelectedFindResultChanged(int identifier, int index) = 0; - // Runs a file chooser. - virtual bool RunFileChooser( - const WebKit::WebFileChooserParams& params, - WebKit::WebFileChooserCompletion* chooser_completion) = 0; - // Sends an async IPC to open a local file. typedef base::Callback<void (base::PlatformFileError, base::PassPlatformFile)> AsyncOpenFileCallback; diff --git a/webkit/plugins/ppapi/ppb_file_chooser_impl.cc b/webkit/plugins/ppapi/ppb_file_chooser_impl.cc deleted file mode 100644 index 40ef147..0000000 --- a/webkit/plugins/ppapi/ppb_file_chooser_impl.cc +++ /dev/null @@ -1,288 +0,0 @@ -// 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 "webkit/plugins/ppapi/ppb_file_chooser_impl.h" - -#include <string> -#include <vector> - -#include "base/logging.h" -#include "base/string_split.h" -#include "base/string_util.h" -#include "base/sys_string_conversions.h" -#include "ppapi/c/pp_completion_callback.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/shared_impl/tracked_callback.h" -#include "ppapi/shared_impl/var.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" -#include "webkit/glue/webkit_glue.h" -#include "webkit/plugins/ppapi/common.h" -#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" -#include "webkit/plugins/ppapi/plugin_delegate.h" -#include "webkit/plugins/ppapi/plugin_module.h" -#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" -#include "webkit/plugins/ppapi/resource_helper.h" - -using ppapi::StringVar; -using ppapi::thunk::PPB_FileChooser_API; -using ppapi::TrackedCallback; -using WebKit::WebCString; -using WebKit::WebFileChooserCompletion; -using WebKit::WebFileChooserParams; -using WebKit::WebString; -using WebKit::WebVector; - -namespace webkit { -namespace ppapi { - -namespace { - -class FileChooserCompletionImpl : public WebFileChooserCompletion { - public: - FileChooserCompletionImpl(PPB_FileChooser_Impl* file_chooser) - : file_chooser_(file_chooser) { - DCHECK(file_chooser_); - } - - virtual ~FileChooserCompletionImpl() {} - - virtual void didChooseFile(const WebVector<WebString>& file_names) { - std::vector<PPB_FileChooser_Impl::ChosenFileInfo> files; - for (size_t i = 0; i < file_names.size(); i++) { - files.push_back( - PPB_FileChooser_Impl::ChosenFileInfo(file_names[i].utf8(), - std::string())); - } - - file_chooser_->StoreChosenFiles(files); - - // It is the responsibility of this method to delete the instance. - delete this; - } - virtual void didChooseFile(const WebVector<SelectedFileInfo>& file_names) { - std::vector<PPB_FileChooser_Impl::ChosenFileInfo> files; - for (size_t i = 0; i < file_names.size(); i++) { - files.push_back( - PPB_FileChooser_Impl::ChosenFileInfo( - file_names[i].path.utf8(), - file_names[i].displayName.utf8())); - } - - file_chooser_->StoreChosenFiles(files); - - // It is the responsibility of this method to delete the instance. - delete this; - } - - private: - scoped_refptr<PPB_FileChooser_Impl> file_chooser_; -}; - -} // namespace - -PPB_FileChooser_Impl::ChosenFileInfo::ChosenFileInfo( - const std::string& path, - const std::string& display_name) - : path(path), - display_name(display_name) { -} - -PPB_FileChooser_Impl::PPB_FileChooser_Impl( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types) - : Resource(::ppapi::OBJECT_IS_IMPL, instance), - mode_(mode), - next_chosen_file_index_(0) { - if (accept_types) - accept_types_ = std::string(accept_types); -} - -PPB_FileChooser_Impl::~PPB_FileChooser_Impl() { -} - -// static -PP_Resource PPB_FileChooser_Impl::Create( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types) { - if (mode != PP_FILECHOOSERMODE_OPEN && - mode != PP_FILECHOOSERMODE_OPENMULTIPLE) - return 0; - return (new PPB_FileChooser_Impl(instance, mode, - accept_types))->GetReference(); -} - -PPB_FileChooser_Impl* PPB_FileChooser_Impl::AsPPB_FileChooser_Impl() { - return this; -} - -PPB_FileChooser_API* PPB_FileChooser_Impl::AsPPB_FileChooser_API() { - return this; -} - -void PPB_FileChooser_Impl::StoreChosenFiles( - const std::vector<ChosenFileInfo>& files) { - next_chosen_file_index_ = 0; - - // It is possible that |callback_| has been run: before the user takes action - // on the file chooser, the page navigates away and causes the plugin module - // (whose instance requested to show the file chooser) to be destroyed. In - // that case, |callback_| has been aborted when we get here. - if (!TrackedCallback::IsPending(callback_)) { - // To be cautious, reset our internal state. - output_.Reset(); - chosen_files_.clear(); - return; - } - - std::vector< scoped_refptr<Resource> > chosen_files; - for (std::vector<ChosenFileInfo>::const_iterator it = files.begin(); - it != files.end(); ++it) { -#if defined(OS_WIN) - FilePath file_path(base::SysUTF8ToWide(it->path)); -#else - FilePath file_path(it->path); -#endif - - chosen_files.push_back(scoped_refptr<Resource>( - PPB_FileRef_Impl::CreateExternal(pp_instance(), - file_path, - it->display_name))); - } - - int32_t result_code = (chosen_files.size() > 0) ? PP_OK : PP_ERROR_USERCANCEL; - if (output_.is_valid()) - output_.StoreResourceVector(chosen_files); - else // v0.5 API. - chosen_files_.swap(chosen_files); - RunCallback(result_code); -} - -int32_t PPB_FileChooser_Impl::ValidateCallback( - scoped_refptr<TrackedCallback> callback) { - if (TrackedCallback::IsPending(callback_)) - return PP_ERROR_INPROGRESS; - - return PP_OK; -} - -void PPB_FileChooser_Impl::RegisterCallback( - scoped_refptr<TrackedCallback> callback) { - DCHECK(!TrackedCallback::IsPending(callback_)); - - PluginModule* plugin_module = ResourceHelper::GetPluginModule(this); - if (!plugin_module) - return; - - callback_ = callback; -} - -void PPB_FileChooser_Impl::RunCallback(int32_t result) { - TrackedCallback::ClearAndRun(&callback_, result); -} - -int32_t PPB_FileChooser_Impl::Show(const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> callback) { - int32_t result = Show0_5(callback); - if (result == PP_OK_COMPLETIONPENDING) - output_.set_pp_array_output(output); - return result; -} - -int32_t PPB_FileChooser_Impl::ShowWithoutUserGesture( - PP_Bool save_as, - PP_Var suggested_file_name, - const PP_ArrayOutput& output, - scoped_refptr<TrackedCallback> callback) { - int32_t result = ShowWithoutUserGesture0_5(save_as, suggested_file_name, - callback); - if (result == PP_OK_COMPLETIONPENDING) - output_.set_pp_array_output(output); - return result; -} - -int32_t PPB_FileChooser_Impl::Show0_5(scoped_refptr<TrackedCallback> callback) { - PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this); - if (!plugin_instance) - return PP_ERROR_FAILED; - if (!plugin_instance->IsProcessingUserGesture()) - return PP_ERROR_NO_USER_GESTURE; - return ShowWithoutUserGesture0_5(PP_FALSE, PP_MakeUndefined(), callback); -} - -int32_t PPB_FileChooser_Impl::ShowWithoutUserGesture0_5( - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr<TrackedCallback> callback) { - int32_t rv = ValidateCallback(callback); - if (rv != PP_OK) - return rv; - - DCHECK((mode_ == PP_FILECHOOSERMODE_OPEN) || - (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE)); - - WebFileChooserParams params; - if (save_as) { - params.saveAs = true; - StringVar* str = StringVar::FromPPVar(suggested_file_name); - if (str) - params.initialValue = WebString::fromUTF8(str->value().c_str()); - } else { - params.multiSelect = (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE); - } - params.acceptTypes = ParseAcceptValue(accept_types_); - params.directory = false; - - PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); - if (!plugin_delegate) - return PP_ERROR_FAILED; - - if (!plugin_delegate->RunFileChooser(params, - new FileChooserCompletionImpl(this))) - return PP_ERROR_FAILED; - - RegisterCallback(callback); - return PP_OK_COMPLETIONPENDING; -} - -PP_Resource PPB_FileChooser_Impl::GetNextChosenFile() { - if (next_chosen_file_index_ >= chosen_files_.size()) - return 0; - - return chosen_files_[next_chosen_file_index_++]->GetReference(); -} - -std::vector<WebString> PPB_FileChooser_Impl::ParseAcceptValue( - const std::string& accept_types) { - if (accept_types.empty()) - return std::vector<WebString>(); - std::vector<std::string> type_list; - base::SplitString(accept_types, ',', &type_list); - std::vector<WebString> normalized_type_list; - normalized_type_list.reserve(type_list.size()); - for (size_t i = 0; i < type_list.size(); ++i) { - std::string type = type_list[i]; - TrimWhitespaceASCII(type, TRIM_ALL, &type); - - // If the type is a single character, it definitely cannot be valid. In the - // case of a file extension it would be a single ".". In the case of a MIME - // type it would just be a "/". - if (type.length() < 2) - continue; - if (type.find_first_of('/') == std::string::npos && type[0] != '.') - continue; - StringToLowerASCII(&type); - normalized_type_list.push_back(WebString::fromUTF8(type.data(), - type.size())); - } - return normalized_type_list; -} - -} // namespace ppapi -} // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_file_chooser_impl.h b/webkit/plugins/ppapi/ppb_file_chooser_impl.h deleted file mode 100644 index 59de2ac..0000000 --- a/webkit/plugins/ppapi/ppb_file_chooser_impl.h +++ /dev/null @@ -1,114 +0,0 @@ -// 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 WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ -#define WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ - -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "ppapi/c/dev/ppb_file_chooser_dev.h" -#include "ppapi/shared_impl/array_writer.h" -#include "ppapi/shared_impl/resource.h" -#include "ppapi/thunk/ppb_file_chooser_api.h" -#include "webkit/plugins/webkit_plugins_export.h" - -namespace ppapi { -class TrackedCallback; -} - -namespace WebKit { -class WebString; -} - -namespace webkit { -namespace ppapi { - -class PPB_FileRef_Impl; - -class PPB_FileChooser_Impl : public ::ppapi::Resource, - public ::ppapi::thunk::PPB_FileChooser_API { - public: - // Structure to store the information of chosen files. - struct ChosenFileInfo { - ChosenFileInfo(const std::string& path, const std::string& display_name); - std::string path; - // |display_name| may be empty. - std::string display_name; - }; - - PPB_FileChooser_Impl(PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types); - virtual ~PPB_FileChooser_Impl(); - - static PP_Resource Create(PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types); - - // Resource overrides. - virtual PPB_FileChooser_Impl* AsPPB_FileChooser_Impl(); - - // Resource overrides. - virtual ::ppapi::thunk::PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; - - // Stores the list of selected files. - void StoreChosenFiles(const std::vector<ChosenFileInfo>& files); - - // Check that |callback| is valid (only non-blocking operation is supported) - // and that no callback is already pending. Returns |PP_OK| if okay, else - // |PP_ERROR_...| to be returned to the plugin. - int32_t ValidateCallback(scoped_refptr< ::ppapi::TrackedCallback> callback); - - // Sets up |callback| as the pending callback. This should only be called once - // it is certain that |PP_OK_COMPLETIONPENDING| will be returned. - void RegisterCallback(scoped_refptr< ::ppapi::TrackedCallback> callback); - - void RunCallback(int32_t result); - - // PPB_FileChooser_API implementation. - virtual int32_t Show( - const PP_ArrayOutput& output, - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual int32_t ShowWithoutUserGesture( - PP_Bool save_as, - PP_Var suggested_file_name, - const PP_ArrayOutput& output, - scoped_refptr< ::ppapi::TrackedCallback> callback); - virtual int32_t Show0_5( - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual PP_Resource GetNextChosenFile() OVERRIDE; - virtual int32_t ShowWithoutUserGesture0_5( - PP_Bool save_as, - PP_Var suggested_file_name, - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - - // Splits a comma-separated MIME type/extension list |accept_types|, trims the - // resultant split types, makes them lowercase, and returns them. - // Though this should be private, this is public for testing. - WEBKIT_PLUGINS_EXPORT static std::vector<WebKit::WebString> ParseAcceptValue( - const std::string& accept_types); - - private: - PP_FileChooserMode_Dev mode_; - std::string accept_types_; - scoped_refptr< ::ppapi::TrackedCallback> callback_; - - // When using the v0.6 of the API, this will contain the output for the - // resources when the show command is complete. When using 0.5, this - // object will be is_null() and the chosen_files_ will be used instead. - ::ppapi::ArrayWriter output_; - - // Used to store and iterate over the results when using 0.5 of the API. - // These are valid when we get a file result and output_ is not null. - std::vector< scoped_refptr<Resource> > chosen_files_; - size_t next_chosen_file_index_; -}; - -} // namespace ppapi -} // namespace webkit - -#endif // WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_file_chooser_impl_unittest.cc b/webkit/plugins/ppapi/ppb_file_chooser_impl_unittest.cc deleted file mode 100644 index 129566f..0000000 --- a/webkit/plugins/ppapi/ppb_file_chooser_impl_unittest.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" -#include "webkit/plugins/ppapi/ppb_file_chooser_impl.h" - -using WebKit::WebString; - -namespace webkit { -namespace ppapi { - -TEST(PPB_FileChooser_ImplTest, ParseAcceptValue) { - std::vector<WebString> parsed; - - parsed = PPB_FileChooser_Impl::ParseAcceptValue(""); - EXPECT_EQ(0U, parsed.size()); - - parsed = PPB_FileChooser_Impl::ParseAcceptValue(" "); - EXPECT_EQ(0U, parsed.size()); - - parsed = PPB_FileChooser_Impl::ParseAcceptValue("a"); - EXPECT_EQ(0U, parsed.size()); - - parsed = PPB_FileChooser_Impl::ParseAcceptValue(",, "); - EXPECT_EQ(0U, parsed.size()); - - parsed = PPB_FileChooser_Impl::ParseAcceptValue( - "IMAGE/*,,!!,,text/plain, audio /(*) "); - EXPECT_EQ(3U, parsed.size()); - EXPECT_EQ("image/*", parsed[0]); - EXPECT_EQ("text/plain", parsed[1]); - // We don't need to reject invalid MIME tokens strictly. - EXPECT_EQ("audio /(*)", parsed[2]); -} - -} // namespace ppapi -} // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_file_ref_impl.h b/webkit/plugins/ppapi/ppb_file_ref_impl.h index 9b33758..d7bb8c5 100644 --- a/webkit/plugins/ppapi/ppb_file_ref_impl.h +++ b/webkit/plugins/ppapi/ppb_file_ref_impl.h @@ -12,6 +12,7 @@ #include "ppapi/c/ppb_file_ref.h" #include "ppapi/shared_impl/ppb_file_ref_shared.h" #include "ppapi/shared_impl/var.h" +#include "webkit/glue/webkit_glue_export.h" namespace webkit { namespace ppapi { @@ -20,7 +21,8 @@ using ::ppapi::StringVar; class PPB_FileSystem_Impl; -class PPB_FileRef_Impl : public ::ppapi::PPB_FileRef_Shared { +class WEBKIT_GLUE_EXPORT PPB_FileRef_Impl + : public ::ppapi::PPB_FileRef_Shared { public: PPB_FileRef_Impl(const ::ppapi::PPB_FileRef_CreateInfo& info, PPB_FileSystem_Impl* file_system); diff --git a/webkit/plugins/ppapi/resource_creation_impl.cc b/webkit/plugins/ppapi/resource_creation_impl.cc index 8636056..3d4fd0a 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.cc +++ b/webkit/plugins/ppapi/resource_creation_impl.cc @@ -16,7 +16,6 @@ #include "webkit/plugins/ppapi/ppb_broker_impl.h" #include "webkit/plugins/ppapi/ppb_buffer_impl.h" #include "webkit/plugins/ppapi/ppb_directory_reader_impl.h" -#include "webkit/plugins/ppapi/ppb_file_chooser_impl.h" #include "webkit/plugins/ppapi/ppb_file_io_impl.h" #include "webkit/plugins/ppapi/ppb_file_ref_impl.h" #include "webkit/plugins/ppapi/ppb_file_system_impl.h" @@ -115,13 +114,6 @@ PP_Resource ResourceCreationImpl::CreateDirectoryReader( return PPB_DirectoryReader_Impl::Create(directory_ref); } -PP_Resource ResourceCreationImpl::CreateFileChooser( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types) { - return PPB_FileChooser_Impl::Create(instance, mode, accept_types); -} - PP_Resource ResourceCreationImpl::CreateFileIO(PP_Instance instance) { return (new PPB_FileIO_Impl(instance))->GetReference(); } diff --git a/webkit/plugins/ppapi/resource_creation_impl.h b/webkit/plugins/ppapi/resource_creation_impl.h index 9c5a97c..42796ed 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.h +++ b/webkit/plugins/ppapi/resource_creation_impl.h @@ -43,10 +43,6 @@ class WEBKIT_PLUGINS_EXPORT ResourceCreationImpl virtual PP_Resource CreateBuffer(PP_Instance instance, uint32_t size) OVERRIDE; virtual PP_Resource CreateDirectoryReader(PP_Resource directory_ref) OVERRIDE; - virtual PP_Resource CreateFileChooser( - PP_Instance instance, - PP_FileChooserMode_Dev mode, - const char* accept_types) OVERRIDE; virtual PP_Resource CreateFileIO(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateFileRef(PP_Resource file_system, const char* path) OVERRIDE; diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index 76299c6f..2ac3fae 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -389,7 +389,6 @@ '../../plugins/ppapi/mock_resource.h', '../../plugins/ppapi/ppapi_unittest.cc', '../../plugins/ppapi/ppapi_unittest.h', - '../../plugins/ppapi/ppb_file_chooser_impl_unittest.cc', '../../plugins/ppapi/quota_file_io_unittest.cc', '../../plugins/ppapi/time_conversion_unittest.cc', '../../plugins/ppapi/url_request_info_unittest.cc', |