summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.cc6
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc20
-rw-r--r--chrome/browser/renderer_host/render_view_host.h16
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h6
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h1
-rw-r--r--chrome/browser/renderer_host/test/site_instance_unittest.cc2
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc34
-rw-r--r--chrome/browser/tab_contents/tab_contents.h7
-rw-r--r--chrome/common/render_messages.h64
-rw-r--r--chrome/common/render_messages_internal.h6
-rw-r--r--chrome/renderer/render_view.cc113
-rw-r--r--chrome/renderer/render_view.h21
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.cc60
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.h31
-rw-r--r--third_party/npapi/bindings/npapi_extensions.h59
-rw-r--r--webkit/glue/plugins/npapi_extension_thunk.cc22
-rw-r--r--webkit/glue/plugins/webplugin_file_delegate.h35
-rw-r--r--webkit/glue/webplugin_delegate.h6
18 files changed, 416 insertions, 93 deletions
diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc
index b18cc50..21fa34d 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.cc
+++ b/chrome/browser/renderer_host/mock_render_process_host.cc
@@ -4,13 +4,19 @@
#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/child_process_security_policy.h"
+
MockRenderProcessHost::MockRenderProcessHost(Profile* profile)
: RenderProcessHost(profile),
transport_dib_(NULL),
bad_msg_count_(0) {
+ // Child process security operations can't be unit tested unless we add
+ // ourselves as an existing child process.
+ ChildProcessSecurityPolicy::GetInstance()->Add(id());
}
MockRenderProcessHost::~MockRenderProcessHost() {
+ ChildProcessSecurityPolicy::GetInstance()->Remove(id());
delete transport_dib_;
}
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index c8c4df0..ddc754f 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -657,16 +657,9 @@ void RenderViewHost::InstallMissingPlugin() {
Send(new ViewMsg_InstallMissingPlugin(routing_id()));
}
-void RenderViewHost::FileSelected(const FilePath& path) {
- ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
- process()->id(), path);
- std::vector<FilePath> files;
- files.push_back(path);
- Send(new ViewMsg_RunFileChooserResponse(routing_id(), files));
-}
-
-void RenderViewHost::MultiFilesSelected(
- const std::vector<FilePath>& files) {
+void RenderViewHost::FilesSelectedInChooser(
+ const std::vector<FilePath>& files) {
+ // Grant the security access requested to the given files.
for (std::vector<FilePath>::const_iterator file = files.begin();
file != files.end(); ++file) {
ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
@@ -1316,10 +1309,9 @@ void RenderViewHost::OnMsgSelectionChanged(const std::string& text) {
view()->SelectionChanged(text);
}
-void RenderViewHost::OnMsgRunFileChooser(bool multiple_files,
- const string16& title,
- const FilePath& default_file) {
- delegate_->RunFileChooser(multiple_files, title, default_file);
+void RenderViewHost::OnMsgRunFileChooser(
+ const ViewHostMsg_RunFileChooser_Params& params) {
+ delegate_->RunFileChooser(params);
}
void RenderViewHost::OnMsgRunJavaScriptMessage(
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index d628a79..831c446 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -34,6 +34,7 @@ struct ContextMenuParams;
struct MediaPlayerAction;
struct ThumbnailScore;
struct ViewHostMsg_DidPrintPage_Params;
+struct ViewHostMsg_RunFileChooser_Params;
struct ViewMsg_Navigate_Params;
struct WebDropData;
struct WebPreferences;
@@ -355,13 +356,9 @@ class RenderViewHost : public RenderWidgetHost {
const std::vector<FilePath>& local_paths,
const FilePath& local_directory_name);
- // Notifies the RenderViewHost that a file has been chosen by the user from
- // an Open File dialog for the form.
- void FileSelected(const FilePath& path);
-
- // Notifies the Listener that many files have been chosen by the user from
- // an Open File dialog for the form.
- void MultiFilesSelected(const std::vector<FilePath>& files);
+ // Notifies the Listener that one or more files have been chosen by the user
+ // from an Open File dialog for the form.
+ void FilesSelectedInChooser(const std::vector<FilePath>& files);
// Notifies the RenderViewHost that its load state changed.
void LoadStateChanged(const GURL& url, net::LoadState load_state,
@@ -531,9 +528,7 @@ class RenderViewHost : public RenderWidgetHost {
WebKit::WebTextDirection text_direction_hint);
void OnMsgSelectionChanged(const std::string& text);
void OnMsgPasteFromSelectionClipboard();
- void OnMsgRunFileChooser(bool multiple_files,
- const string16& title,
- const FilePath& default_file);
+ void OnMsgRunFileChooser(const ViewHostMsg_RunFileChooser_Params& params);
void OnMsgRunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
const GURL& frame_url,
@@ -621,7 +616,6 @@ class RenderViewHost : public RenderWidgetHost {
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
-
void OnContentBlocked(ContentSettingsType type);
private:
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 8c9127b..1f93d31 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -39,6 +39,7 @@ struct ThumbnailScore;
class Value;
struct ViewHostMsg_DidPrintPage_Params;
struct ViewHostMsg_FrameNavigate_Params;
+struct ViewHostMsg_RunFileChooser_Params;
struct WebDropData;
class WebKeyboardEvent;
struct WebPreferences;
@@ -556,9 +557,8 @@ class RenderViewHostDelegate {
const std::string& target) {}
// A file chooser should be shown.
- virtual void RunFileChooser(bool multiple_files,
- const string16& title,
- const FilePath& default_file) {}
+ virtual void RunFileChooser(
+ const ViewHostMsg_RunFileChooser_Params& params) {}
// A javascript message, confirmation or prompt should be shown.
virtual void RunJavaScriptMessage(const std::wstring& message,
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index a69fd78..4c6e2e6 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -325,7 +325,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
const std::string& extension_id,
const std::string& default_locale,
IPC::Message* reply_msg);
-
void OnTranslateText(ViewHostMsg_TranslateTextParam param);
void OnEstablishGpuChannel();
diff --git a/chrome/browser/renderer_host/test/site_instance_unittest.cc b/chrome/browser/renderer_host/test/site_instance_unittest.cc
index 7206476..2c99835 100644
--- a/chrome/browser/renderer_host/test/site_instance_unittest.cc
+++ b/chrome/browser/renderer_host/test/site_instance_unittest.cc
@@ -425,7 +425,6 @@ TEST_F(SiteInstanceTest, ProcessSharingByType) {
// Create some extension instances and make sure they share a process.
scoped_refptr<SiteInstance> extension1_instance(
CreateSiteInstance(&rph_factory, GURL("chrome-extension://foo/bar")));
- policy->Add(extension1_instance->GetProcess()->id());
policy->GrantExtensionBindings(extension1_instance->GetProcess()->id());
scoped_refptr<SiteInstance> extension2_instance(
@@ -439,7 +438,6 @@ TEST_F(SiteInstanceTest, ProcessSharingByType) {
// Create some DOMUI instances and make sure they share a process.
scoped_refptr<SiteInstance> dom1_instance(
CreateSiteInstance(&rph_factory, GURL("chrome://newtab")));
- policy->Add(dom1_instance->GetProcess()->id());
policy->GrantDOMUIBindings(dom1_instance->GetProcess()->id());
scoped_refptr<SiteInstance> dom2_instance(
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 3bbbbf9..55eaadd 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -2468,15 +2468,27 @@ void TabContents::ProcessExternalHostMessage(const std::string& message,
delegate()->ForwardMessageToExternalHost(message, origin, target);
}
-void TabContents::RunFileChooser(bool multiple_files,
- const string16& title,
- const FilePath& default_file) {
+void TabContents::RunFileChooser(
+ const ViewHostMsg_RunFileChooser_Params &params) {
if (!select_file_dialog_.get())
select_file_dialog_ = SelectFileDialog::Create(this);
- SelectFileDialog::Type dialog_type =
- multiple_files ? SelectFileDialog::SELECT_OPEN_MULTI_FILE :
- SelectFileDialog::SELECT_OPEN_FILE;
- select_file_dialog_->SelectFile(dialog_type, title, default_file,
+
+ SelectFileDialog::Type dialog_type;
+ switch (params.mode) {
+ case ViewHostMsg_RunFileChooser_Params::Open:
+ dialog_type = SelectFileDialog::SELECT_OPEN_FILE;
+ break;
+ case ViewHostMsg_RunFileChooser_Params::OpenMultiple:
+ dialog_type = SelectFileDialog::SELECT_OPEN_MULTI_FILE;
+ break;
+ case ViewHostMsg_RunFileChooser_Params::Save:
+ dialog_type = SelectFileDialog::SELECT_SAVEAS_FILE;
+ break;
+ default:
+ NOTREACHED();
+ }
+ select_file_dialog_->SelectFile(dialog_type, params.title,
+ params.default_file_name,
NULL, 0, FILE_PATH_LITERAL(""),
view_->GetTopLevelNativeWindow(), NULL);
}
@@ -2732,18 +2744,20 @@ void TabContents::FocusedNodeChanged() {
void TabContents::FileSelected(const FilePath& path,
int index, void* params) {
- render_view_host()->FileSelected(path);
+ std::vector<FilePath> files;
+ files.push_back(path);
+ render_view_host()->FilesSelectedInChooser(files);
}
void TabContents::MultiFilesSelected(const std::vector<FilePath>& files,
void* params) {
- render_view_host()->MultiFilesSelected(files);
+ render_view_host()->FilesSelectedInChooser(files);
}
void TabContents::FileSelectionCanceled(void* params) {
// If the user cancels choosing a file to upload we pass back an
// empty vector.
- render_view_host()->MultiFilesSelected(std::vector<FilePath>());
+ render_view_host()->FilesSelectedInChooser(std::vector<FilePath>());
}
void TabContents::BeforeUnloadFiredFromRenderManager(
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 385ed6d..62547d6 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -87,8 +87,9 @@ class SiteInstance;
class TabContents;
class TabContentsView;
struct ThumbnailScore;
-struct ViewHostMsg_FrameNavigate_Params;
struct ViewHostMsg_DidPrintPage_Params;
+struct ViewHostMsg_FrameNavigate_Params;
+struct ViewHostMsg_RunFileChooser_Params;
// Describes what goes in the main content area of a tab. TabContents is
// the only type of TabContents, and these should be merged together.
@@ -916,9 +917,7 @@ class TabContents : public PageNavigator,
virtual void ProcessExternalHostMessage(const std::string& message,
const std::string& origin,
const std::string& target);
- virtual void RunFileChooser(bool multiple_files,
- const string16& title,
- const FilePath& default_file);
+ virtual void RunFileChooser(const ViewHostMsg_RunFileChooser_Params& params);
virtual void RunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
const GURL& frame_url,
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 808f668..46cd37b 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -631,6 +631,29 @@ struct ViewHostMsg_TranslateTextParam {
bool secure;
};
+struct ViewHostMsg_RunFileChooser_Params {
+ enum Mode {
+ // Requires that the file exists before allowing the user to pick it.
+ Open,
+
+ // Like Open, but allows picking multiple files to open.
+ OpenMultiple,
+
+ // Allows picking a nonexistant file, and prompts to overwrite if the file
+ // already exists.
+ Save,
+ };
+
+ Mode mode;
+
+ // Title to be used for the dialog. This may be empty for the default title,
+ // which will be either "Open" or "Save" depending on the mode.
+ string16 title;
+
+ // Default file name to select in the dialog.
+ FilePath default_file_name;
+};
+
namespace IPC {
template <>
@@ -2666,6 +2689,47 @@ struct SimilarTypeTraits<TranslateErrors::Type> {
typedef int Type;
};
+template<>
+struct ParamTraits<ViewHostMsg_RunFileChooser_Params> {
+ typedef ViewHostMsg_RunFileChooser_Params param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.mode));
+ WriteParam(m, p.title);
+ WriteParam(m, p.default_file_name);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int mode;
+ if (!ReadParam(m, iter, &mode))
+ return false;
+ if (mode != param_type::Open &&
+ mode != param_type::OpenMultiple &&
+ mode != param_type::Save)
+ return false;
+ p->mode = static_cast<param_type::Mode>(mode);
+ return
+ ReadParam(m, iter, &p->title) &&
+ ReadParam(m, iter, &p->default_file_name);
+ };
+ static void Log(const param_type& p, std::wstring* l) {
+ switch (p.mode) {
+ case param_type::Open:
+ l->append(L"(Open, ");
+ break;
+ case param_type::OpenMultiple:
+ l->append(L"(OpenMultiple, ");
+ break;
+ case param_type::Save:
+ l->append(L"(Save, ");
+ break;
+ default:
+ l->append(L"(UNKNOWN, ");
+ }
+ LogParam(p.title, l);
+ l->append(L", ");
+ LogParam(p.default_file_name, l);
+ }
+};
+
} // namespace IPC
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 94f2fcb..bf2ac2b 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1428,10 +1428,8 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Asks the browser to display the file chooser. The result is returned in a
// ViewHost_RunFileChooserResponse message.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_RunFileChooser,
- bool /* multiple_files */,
- string16 /* title */,
- FilePath /* Default file name */)
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser,
+ ViewHostMsg_RunFileChooser_Params)
// Notification that forms have been seen that are candidates for
// filling/submitting by the AutoFillManager.
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 9698299..bff25a9 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -155,6 +155,7 @@ using WebKit::WebDragData;
using WebKit::WebDragOperation;
using WebKit::WebDragOperationsMask;
using WebKit::WebEditingAction;
+using WebKit::WebFileChooserCompletion;
using WebKit::WebFindOptions;
using WebKit::WebFormElement;
using WebKit::WebFrame;
@@ -293,6 +294,16 @@ static double CalculateBoringScore(SkBitmap* bitmap) {
int32 RenderView::next_page_id_ = 1;
+struct RenderView::PendingFileChooser {
+ PendingFileChooser(const ViewHostMsg_RunFileChooser_Params& p,
+ WebFileChooserCompletion* c)
+ : params(p),
+ completion(c) {
+ }
+ ViewHostMsg_RunFileChooser_Params params;
+ WebFileChooserCompletion* completion; // MAY BE NULL to skip callback.
+};
+
RenderView::RenderView(RenderThreadBase* render_thread,
const WebPreferences& webkit_preferences,
int64 session_storage_namespace_id)
@@ -309,7 +320,6 @@ RenderView::RenderView(RenderThreadBase* render_thread,
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
devtools_agent_(NULL),
devtools_client_(NULL),
- file_chooser_completion_(NULL),
history_list_offset_(-1),
history_list_length_(0),
has_unload_listener_(false),
@@ -349,8 +359,13 @@ RenderView::~RenderView() {
}
// If file chooser is still waiting for answer, dispatch empty answer.
- if (file_chooser_completion_)
- file_chooser_completion_->didChooseFile(WebVector<WebString>());
+ while (!file_chooser_completions_.empty()) {
+ if (file_chooser_completions_.front()->completion) {
+ file_chooser_completions_.front()->completion->didChooseFile(
+ WebVector<WebString>());
+ }
+ file_chooser_completions_.pop_front();
+ }
#if defined(OS_MACOSX)
// Tell the spellchecker that the document is closed.
@@ -1743,21 +1758,16 @@ void RenderView::updateSpellingUIWithMisspelledWord(const WebString& word) {
bool RenderView::runFileChooser(
const WebKit::WebFileChooserParams& params,
- WebKit::WebFileChooserCompletion* chooser_completion) {
- if (file_chooser_completion_) {
- // TODO(brettw): bug 1235154: This should be a synchronous message to deal
- // with the fact that web pages can programatically trigger this. With the
- // asnychronous messages, we can get an additional call when one is pending,
- // which this test is for. For now, we just ignore the additional file
- // chooser request. WebKit doesn't do anything to expect the callback, so
- // we can just ignore calling it.
- return false;
- }
- file_chooser_completion_ = chooser_completion;
- Send(new ViewHostMsg_RunFileChooser(
- routing_id_, params.multiSelect, params.title,
- webkit_glue::WebStringToFilePath(params.initialValue)));
- return true;
+ WebFileChooserCompletion* chooser_completion) {
+ ViewHostMsg_RunFileChooser_Params ipc_params;
+ ipc_params.mode = params.multiSelect ?
+ ViewHostMsg_RunFileChooser_Params::OpenMultiple :
+ ViewHostMsg_RunFileChooser_Params::Open;
+ ipc_params.title = params.title;
+ ipc_params.default_file_name =
+ webkit_glue::WebStringToFilePath(params.initialValue);
+
+ return ScheduleFileChooser(ipc_params, chooser_completion);
}
void RenderView::runModalAlertDialog(
@@ -3656,6 +3666,24 @@ void RenderView::OnPepperPluginDestroy(
return;
}
current_pepper_plugins_.erase(found_pepper);
+
+ // The plugin could have been destroyed while it was waiting for a file
+ // choose callback, so check all pending completion callbacks and NULL them.
+ for (std::deque< linked_ptr<PendingFileChooser> >::iterator i =
+ file_chooser_completions_.begin();
+ i != file_chooser_completions_.end(); /* nothing */) {
+ if ((*i)->completion == pepper_plugin) {
+ // We NULL the first one instead of deleting it because the plugin might
+ // be the one waiting for a file choose callback. If the callback later
+ // comes, we don't want to send the result to the next callback in line.
+ if (i == file_chooser_completions_.begin())
+ (*i)->completion = NULL;
+ else
+ i = file_chooser_completions_.erase(i);
+ } else {
+ ++i;
+ }
+ }
}
void RenderView::OnScriptEvalRequest(const std::wstring& frame_xpath,
@@ -3785,21 +3813,25 @@ void RenderView::OnInstallMissingPlugin() {
first_default_plugin_->InstallMissingPlugin();
}
-void RenderView::OnFileChooserResponse(
- const std::vector<FilePath>& file_names) {
+void RenderView::OnFileChooserResponse(const std::vector<FilePath>& paths) {
// This could happen if we navigated to a different page before the user
// closed the chooser.
- if (!file_chooser_completion_)
+ if (file_chooser_completions_.empty())
return;
- WebVector<WebString> ws_file_names(file_names.size());
- for (size_t i = 0; i < file_names.size(); ++i) {
- ws_file_names[i] = webkit_glue::FilePathToWebString(file_names[i]);
- }
+ WebVector<WebString> ws_file_names(paths.size());
+ for (size_t i = 0; i < paths.size(); ++i)
+ ws_file_names[i] = webkit_glue::FilePathToWebString(paths[i]);
+
+ if (file_chooser_completions_.front()->completion)
+ file_chooser_completions_.front()->completion->didChooseFile(ws_file_names);
+ file_chooser_completions_.pop_front();
- file_chooser_completion_->didChooseFile(ws_file_names);
- // Reset the chooser pointer
- file_chooser_completion_ = NULL;
+ // If there are more pending file chooser requests, schedule one now.
+ if (!file_chooser_completions_.empty()) {
+ Send(new ViewHostMsg_RunFileChooser(routing_id_,
+ file_chooser_completions_.front()->params));
+ }
}
void RenderView::OnEnableViewSourceMode() {
@@ -4889,6 +4921,31 @@ void RenderView::AcceleratedSurfaceBuffersSwapped(
}
#endif
+bool RenderView::ScheduleFileChooser(
+ const ViewHostMsg_RunFileChooser_Params& params,
+ WebFileChooserCompletion* completion) {
+ static const size_t kMaximumPendingFileChooseRequests = 4;
+ if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) {
+ // This sanity check prevents too many file choose requests from getting
+ // queued which could DoS the user. Getting these is most likely a
+ // programming error (there are many ways to DoS the user so it's not
+ // considered a "real" security check), either in JS requesting many file
+ // choosers to pop up, or in a plugin.
+ //
+ // TODO(brettw) we might possibly want to require a user gesture to open
+ // a file picker, which will address this issue in a better way.
+ return false;
+ }
+
+ file_chooser_completions_.push_back(linked_ptr<PendingFileChooser>(
+ new PendingFileChooser(params, completion)));
+ if (file_chooser_completions_.size() == 1) {
+ // Actually show the browse dialog when this is the first request.
+ Send(new ViewHostMsg_RunFileChooser(routing_id_, params));
+ }
+ return true;
+}
+
WebKit::WebGeolocationServiceInterface* RenderView::getGeolocationService() {
if (!geolocation_dispatcher_.get())
geolocation_dispatcher_.reset(new GeolocationDispatcher(this));
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 5ef764c..c390a09 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -5,6 +5,7 @@
#ifndef CHROME_RENDERER_RENDER_VIEW_H_
#define CHROME_RENDERER_RENDER_VIEW_H_
+#include <deque>
#include <map>
#include <set>
#include <string>
@@ -507,6 +508,15 @@ class RenderView : public RenderWidget,
void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window);
#endif
+ // Adds the given file chooser request to the file_chooser_completion_ queue
+ // (see that var for more) and requests the chooser be displayed if there are
+ // no other waiting items in the queue.
+ //
+ // Returns true if the chooser was successfully scheduled. False means we
+ // didn't schedule anything.
+ bool ScheduleFileChooser(const ViewHostMsg_RunFileChooser_Params& params,
+ WebKit::WebFileChooserCompletion* completion);
+
protected:
// RenderWidget overrides:
virtual void Close();
@@ -697,7 +707,7 @@ class RenderView : public RenderWidget,
WebKit::WebDragOperation drag_operation);
void OnDragSourceSystemDragEnded();
void OnInstallMissingPlugin();
- void OnFileChooserResponse(const std::vector<FilePath>& file_names);
+ void OnFileChooserResponse(const std::vector<FilePath>& paths);
void OnEnableViewSourceMode();
void OnEnablePreferredSizeChangedMode();
void OnDisableScrollbarsForSmallWindows(
@@ -1009,9 +1019,12 @@ class RenderView : public RenderWidget,
// render views.
scoped_ptr<DevToolsClient> devtools_client_;
- // A pointer to a file chooser completion object. When not empty, file
- // choosing operation is underway.
- WebKit::WebFileChooserCompletion* file_chooser_completion_;
+ // The current and pending file chooser completion objects. If the queue is
+ // nonempty, the first item represents the currently running file chooser
+ // callback, and the remaining elements are the other file chooser completion
+ // still waiting to be run (in order).
+ struct PendingFileChooser;
+ std::deque< linked_ptr<PendingFileChooser> > file_chooser_completions_;
int history_list_offset_;
int history_list_length_;
diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc
index 37b169d..9c4db6c 100644
--- a/chrome/renderer/webplugin_delegate_pepper.cc
+++ b/chrome/renderer/webplugin_delegate_pepper.cc
@@ -146,6 +146,30 @@ WebPluginDelegatePepper* WebPluginDelegatePepper::Create(
instance.get());
}
+void WebPluginDelegatePepper::didChooseFile(
+ const WebKit::WebVector<WebKit::WebString>& file_names) {
+ if (file_names.isEmpty()) {
+ current_choose_file_callback_(NULL, 0, current_choose_file_user_data_);
+ } else {
+ // Construct a bunch of 8-bit strings for the callback.
+ std::vector<std::string> file_strings;
+ file_strings.resize(file_names.size());
+ for (size_t i = 0; i < file_names.size(); i++)
+ file_strings[i] = file_names[0].utf8();
+
+ // Construct an array of pointers to each of the strings.
+ std::vector<const char*> pointers_to_strings;
+ pointers_to_strings.resize(file_strings.size());
+ for (size_t i = 0; i < file_strings.size(); i++)
+ pointers_to_strings[i] = file_strings[i].c_str();
+
+ current_choose_file_callback_(
+ &pointers_to_strings[0],
+ static_cast<int>(pointers_to_strings.size()),
+ current_choose_file_user_data_);
+ }
+}
+
bool WebPluginDelegatePepper::Initialize(
const GURL& url,
const std::vector<std::string>& arg_names,
@@ -368,6 +392,38 @@ void WebPluginDelegatePepper::Zoom(int factor) {
extensions->zoom(instance()->npp(), factor);
}
+bool WebPluginDelegatePepper::ChooseFile(const char* mime_types,
+ int mode,
+ NPChooseFileCallback callback,
+ void* user_data) {
+ if (!render_view_ || !callback)
+ return false;
+
+ if (current_choose_file_callback_)
+ return false; // Reentrant call to browse, only one can be outstanding
+ // per plugin.
+
+ // TODO(brettw) do something with the mime types!
+ current_choose_file_callback_ = callback;
+ current_choose_file_user_data_ = user_data;
+
+ ViewHostMsg_RunFileChooser_Params ipc_params;
+ switch (mode) {
+ case NPChooseFile_Open:
+ ipc_params.mode = ViewHostMsg_RunFileChooser_Params::Open;
+ break;
+ case NPChooseFile_OpenMultiple:
+ ipc_params.mode = ViewHostMsg_RunFileChooser_Params::OpenMultiple;
+ break;
+ case NPChooseFile_Save:
+ ipc_params.mode = ViewHostMsg_RunFileChooser_Params::Save;
+ break;
+ default:
+ return false;
+ }
+ return render_view_->ScheduleFileChooser(ipc_params, this);
+}
+
NPError WebPluginDelegatePepper::Device2DQueryCapability(int32 capability,
int32* value) {
return NPERR_GENERIC_ERROR;
@@ -1045,7 +1101,9 @@ WebPluginDelegatePepper::WebPluginDelegatePepper(
command_buffer_(NULL),
#endif
find_identifier_(-1),
- method_factory3d_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ method_factory3d_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ current_choose_file_callback_(NULL),
+ current_choose_file_user_data_(NULL) {
// For now we keep a window struct, although it isn't used.
memset(&window_, 0, sizeof(window_));
// All Pepper plugins are windowless and transparent.
diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h
index 1ffc457..ce57940 100644
--- a/chrome/renderer/webplugin_delegate_pepper.h
+++ b/chrome/renderer/webplugin_delegate_pepper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -22,6 +22,7 @@
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFileChooserCompletion.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webplugin_delegate.h"
@@ -30,7 +31,8 @@ class PluginInstance;
}
// An implementation of WebPluginDelegate for Pepper in-process plugins.
-class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
+class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate,
+ public WebKit::WebFileChooserCompletion {
public:
static WebPluginDelegatePepper* Create(
const FilePath& filename,
@@ -39,6 +41,10 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
NPAPI::PluginInstance* instance() { return instance_.get(); }
+ // WebKit::WebFileChooserCompletion implementation.
+ virtual void didChooseFile(
+ const WebKit::WebVector<WebKit::WebString>& file_names);
+
// WebPluginDelegate implementation
virtual bool Initialize(const GURL& url,
const std::vector<std::string>& arg_names,
@@ -83,6 +89,10 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
virtual void NumberOfFindResultsChanged(int total, bool final_result);
virtual void SelectedFindResultChanged(int index);
virtual void Zoom(int factor);
+ virtual bool ChooseFile(const char* mime_types,
+ int mode,
+ NPChooseFileCallback callback,
+ void* user_data);
// WebPlugin2DDeviceDelegate implementation.
virtual NPError Device2DQueryCapability(int32 capability, int32* value);
@@ -221,6 +231,12 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
void* user_data);
#endif
+ // Tells the browser out-of-band where the nested delegate lives on
+ // the page.
+ void SendNestedDelegateGeometryToBrowser(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect);
+
+
base::WeakPtr<RenderView> render_view_;
webkit_glue::WebPlugin* plugin_;
@@ -258,13 +274,14 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
// The id of the current find operation, or -1 if none is in process.
int find_identifier_;
- // Tells the browser out-of-band where the nested delegate lives on
- // the page.
- void SendNestedDelegateGeometryToBrowser(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect);
-
// Runnable methods that must be cancelled when the 3D context is destroyed.
ScopedRunnableMethodFactory<WebPluginDelegatePepper> method_factory3d_;
+
+ // When a choose file operation is outstanding, this will contain a
+ // pointer to the callback specified by the plugin. Will be NULL otherwise.
+ NPChooseFileCallback current_choose_file_callback_;
+ void* current_choose_file_user_data_;
+
DISALLOW_COPY_AND_ASSIGN(WebPluginDelegatePepper);
};
diff --git a/third_party/npapi/bindings/npapi_extensions.h b/third_party/npapi/bindings/npapi_extensions.h
index f7ac489..f8c05f4 100644
--- a/third_party/npapi/bindings/npapi_extensions.h
+++ b/third_party/npapi/bindings/npapi_extensions.h
@@ -197,6 +197,63 @@ typedef void (*NPSelectedFindResultChangedPtr)(
NPP instance,
int index);
+/* Supports opening files anywhere on the system after prompting the user to
+ * pick one.
+ *
+ * This API is asynchronous. It will return immediately and the user will be
+ * prompted in parallel to pick a file. The plugin may continue to receive
+ * events while the open file dialog is up, and may continue to paint. Plugins
+ * may want to ignore input events between the call and the callback to avoid
+ * reentrant behavior. If the return value is not NPERR_NO_ERROR, the callback
+ * will NOT be executed.
+ *
+ * It is an error to call BrowseForFile before a previous call has executed
+ * the callback.
+ *
+ * Setting the flags to "Open" requires that the file exist to allow picking.
+ * Setting the flags to "Save" allows selecting nonexistant files (which will
+ * then be created), and will prompt the user if they want to overwrite an
+ * existing file if it exists.
+ *
+ * The plugin may specify a comma-separated list of possible mime types in
+ * the "extensions" parameter. If no extensions are specified, the dialog box
+ * will default to allowing all extensions. The first extension in the list
+ * will be the default.
+ *
+ * TODO(brettw) On Windows the extensions traditionally include a text
+ * description with the extension in the popup, do we want to allow this?
+ * We should probably also allow the ability to put "All files" in the
+ * list on Windows.
+ *
+ * Once the user has picked a file or has canceled the dialog box, the given
+ * callback will be called with the results of the operation and the passed in
+ * "user data" pointer. If the user successfully picked a file, the filename
+ * will be non-NULL and will contain a pointer to an array of strings, one for
+ * each file picked (the first file will be file_paths[0]). This buffer will
+ * become invalid as soon as the call completes, so it is the plugin's
+ * responsibility to copy the filename(sp if it needs future access to them.
+ * A NULL file_paths in the callback means the user canceled the dialog box.
+ *
+ * The filename will be in UTF-8. It may not actually correspond to the actual
+ * file on disk on a Linux system, because we'll do our best to convert it from
+ * the filesystem's locale to UTF-8. Instead, the string will be appropriate for
+ * displaying to the user which file they picked.
+ * */
+typedef enum {
+ NPChooseFile_Open = 1,
+ NPChooseFile_OpenMultiple = 2,
+ NPChooseFile_Save = 3,
+} NPChooseFileMode;
+typedef void (*NPChooseFileCallback)(const char** filePaths,
+ uint32 pathCount,
+ void* userData);
+typedef NPError (*NPChooseFilePtr)(
+ NPP instance,
+ const char* mimeTypes,
+ NPChooseFileMode mode,
+ NPChooseFileCallback callback,
+ void* userData);
+
/* Pepper extensions */
struct NPNExtensions {
/* Device interface acquisition */
@@ -206,6 +263,8 @@ struct NPNExtensions {
/* Find */
NPNumberOfFindResultsChangedPtr numberOfFindResultsChanged;
NPSelectedFindResultChangedPtr selectedFindResultChanged;
+ /* File I/O extensions */
+ NPChooseFilePtr chooseFile;
};
/* Events -------------------------------------------------------------------*/
diff --git a/webkit/glue/plugins/npapi_extension_thunk.cc b/webkit/glue/plugins/npapi_extension_thunk.cc
index d653b35..0c25655 100644
--- a/webkit/glue/plugins/npapi_extension_thunk.cc
+++ b/webkit/glue/plugins/npapi_extension_thunk.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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/glue/plugins/npapi_extension_thunk.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "third_party/npapi/bindings/npapi_extensions.h"
#include "webkit/glue/plugins/plugin_instance.h"
@@ -13,7 +14,6 @@
#include "webkit/glue/webplugin.h"
#include "webkit/glue/webplugin_delegate.h"
-
// FindInstance()
// Finds a PluginInstance from an NPP.
// The caller must take a reference if needed.
@@ -414,6 +414,23 @@ static void CopyTextToClipboard(NPP id, const char* content) {
scw.WriteText(UTF8ToUTF16(content));
}
+static NPError ChooseFile(NPP id,
+ const char* mime_types,
+ NPChooseFileMode mode,
+ NPChooseFileCallback callback,
+ void* user_data) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin)
+ return NPERR_GENERIC_ERROR;
+
+ if (!plugin->webplugin()->delegate()->ChooseFile(mime_types,
+ static_cast<int>(mode),
+ callback, user_data))
+ return NPERR_GENERIC_ERROR;
+
+ return NPERR_NO_ERROR;
+}
+
static void NumberOfFindResultsChanged(NPP id, int total, bool final_result) {
scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
if (plugin) {
@@ -436,6 +453,7 @@ NPError GetPepperExtensionsFunctions(void* value) {
&CopyTextToClipboard,
&NumberOfFindResultsChanged,
&SelectedFindResultChanged,
+ &ChooseFile,
};
// Return a pointer to the canonical function table.
diff --git a/webkit/glue/plugins/webplugin_file_delegate.h b/webkit/glue/plugins/webplugin_file_delegate.h
new file mode 100644
index 0000000..162516c
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_file_delegate.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2010 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_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
+#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "third_party/npapi/bindings/npapi_extensions.h"
+
+namespace webkit_glue {
+
+// Interface for the NPAPI file extensions. This class implements "NOP"
+// versions of all these functions so it can be used seamlessly by the
+// "regular" plugin delegate while being overridden by the "pepper" one.
+class WebPluginFileDelegate {
+ public:
+ // See NPChooseFilePtr in npapi_extensions.h. Returns true on success, on
+ // cancel, returns true but *filename will be filled with an empty FilePath
+ // and *handle will be 0.
+ virtual bool ChooseFile(const char* mime_types,
+ int mode,
+ NPChooseFileCallback callback,
+ void* user_data) {
+ return false;
+ }
+
+ protected:
+ WebPluginFileDelegate() {}
+ virtual ~WebPluginFileDelegate() {}
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h
index 31ebe19..0b08c9e 100644
--- a/webkit/glue/webplugin_delegate.h
+++ b/webkit/glue/webplugin_delegate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -17,6 +17,7 @@
#include "webkit/glue/plugins/webplugin_2d_device_delegate.h"
#include "webkit/glue/plugins/webplugin_3d_device_delegate.h"
#include "webkit/glue/plugins/webplugin_audio_device_delegate.h"
+#include "webkit/glue/plugins/webplugin_file_delegate.h"
#include "webkit/glue/plugins/webplugin_print_delegate.h"
@@ -42,7 +43,8 @@ class WebPluginResourceClient;
class WebPluginDelegate : public WebPlugin2DDeviceDelegate,
public WebPlugin3DDeviceDelegate,
public WebPluginAudioDeviceDelegate,
- public WebPluginPrintDelegate {
+ public WebPluginPrintDelegate,
+ public WebPluginFileDelegate {
public:
virtual ~WebPluginDelegate() {}