summaryrefslogtreecommitdiffstats
path: root/chrome/browser/file_select_helper.cc
diff options
context:
space:
mode:
authorbbudge@chromium.org <bbudge@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 19:13:45 +0000
committerbbudge@chromium.org <bbudge@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 19:13:45 +0000
commit9f054aa1ed3502d46224c63fb30167976fddfbbc (patch)
treed39c9a503ed47469b6ed39f29a9bcbb6cd883bd5 /chrome/browser/file_select_helper.cc
parentb00274f8b9c012f696582352efa93d037de7ba3a (diff)
downloadchromium_src-9f054aa1ed3502d46224c63fb30167976fddfbbc.zip
chromium_src-9f054aa1ed3502d46224c63fb30167976fddfbbc.tar.gz
chromium_src-9f054aa1ed3502d46224c63fb30167976fddfbbc.tar.bz2
Fix crash when running the file chooser dialog from PPAPI.BUG=97637TEST=manual
Review URL: http://codereview.chromium.org/7994015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103325 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/file_select_helper.cc')
-rw-r--r--chrome/browser/file_select_helper.cc120
1 files changed, 94 insertions, 26 deletions
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 391d1318..f656e10 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/bind.h"
#include "base/file_util.h"
#include "base/string_split.h"
#include "base/string_util.h"
@@ -45,7 +46,9 @@ struct FileSelectHelper::ActiveDirectoryEnumeration {
FileSelectHelper::FileSelectHelper(Profile* profile)
: profile_(profile),
render_view_host_(NULL),
+ tab_contents_(NULL),
select_file_dialog_(),
+ select_file_types_(),
dialog_type_(SelectFileDialog::SELECT_OPEN_FILE) {
}
@@ -81,10 +84,9 @@ void FileSelectHelper::FileSelected(const FilePath& path,
std::vector<FilePath> files;
files.push_back(path);
render_view_host_->FilesSelectedInChooser(files);
- // We are done with this showing of the dialog.
- render_view_host_ = NULL;
+
// No members should be accessed from here on.
- delete this;
+ RunFileChooserEnd();
}
void FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
@@ -95,10 +97,9 @@ void FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
return;
render_view_host_->FilesSelectedInChooser(files);
- // We are done with this showing of the dialog.
- render_view_host_ = NULL;
+
// No members should be accessed from here on.
- delete this;
+ RunFileChooserEnd();
}
void FileSelectHelper::FileSelectionCanceled(void* params) {
@@ -109,10 +110,8 @@ void FileSelectHelper::FileSelectionCanceled(void* params) {
// empty vector.
render_view_host_->FilesSelectedInChooser(std::vector<FilePath>());
- // We are done with this showing of the dialog.
- render_view_host_ = NULL;
// No members should be accessed from here on.
- delete this;
+ RunFileChooserEnd();
}
void FileSelectHelper::StartNewEnumeration(const FilePath& path,
@@ -164,8 +163,8 @@ void FileSelectHelper::OnListDone(int id, int error) {
entry->rvh_->FilesSelectedInChooser(entry->results_);
else
entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
- // No members should be accessed from here on.
- delete this;
+
+ EnumerateDirectoryEnd();
}
SelectFileDialog::FileTypeInfo* FileSelectHelper::GetFileTypesFromAcceptType(
@@ -243,11 +242,43 @@ void FileSelectHelper::RunFileChooser(
TabContents* tab_contents,
const ViewHostMsg_RunFileChooser_Params& params) {
DCHECK(!render_view_host_);
+ DCHECK(!tab_contents_);
render_view_host_ = render_view_host;
+ tab_contents_ = tab_contents;
notification_registrar_.RemoveAll();
notification_registrar_.Add(
this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
- Source<RenderWidgetHost>(render_view_host));
+ Source<RenderWidgetHost>(render_view_host_));
+ notification_registrar_.Add(
+ this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params));
+
+ // Because this class returns notifications to the RenderViewHost, it is
+ // difficult for callers to know how long to keep a reference to this
+ // instance. We AddRef() here to keep the instance alive after we return
+ // to the caller, until the last callback is received from the file dialog.
+ // At that point, we must call RunFileChooserEnd().
+ AddRef();
+}
+
+void FileSelectHelper::RunFileChooserOnFileThread(
+ const ViewHostMsg_RunFileChooser_Params& params) {
+ select_file_types_.reset(
+ GetFileTypesFromAcceptType(params.accept_types));
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&FileSelectHelper::RunFileChooserOnUIThread, this, params));
+}
+
+void FileSelectHelper::RunFileChooserOnUIThread(
+ const ViewHostMsg_RunFileChooser_Params& params) {
+ if (!render_view_host_ || !tab_contents_)
+ return;
if (!select_file_dialog_.get())
select_file_dialog_ = SelectFileDialog::Create(this);
@@ -269,8 +300,6 @@ void FileSelectHelper::RunFileChooser(
dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; // Prevent warning.
NOTREACHED();
}
- scoped_ptr<SelectFileDialog::FileTypeInfo> file_types(
- GetFileTypesFromAcceptType(params.accept_types));
FilePath default_file_name = params.default_file_name;
if (default_file_name.empty())
default_file_name = profile_->last_selected_directory();
@@ -278,29 +307,68 @@ void FileSelectHelper::RunFileChooser(
gfx::NativeWindow owning_window =
platform_util::GetTopLevel(render_view_host_->view()->GetNativeView());
- select_file_dialog_->SelectFile(dialog_type_,
- params.title,
- default_file_name,
- file_types.get(),
- file_types.get() ? 1 : 0, // 1-based index.
- FILE_PATH_LITERAL(""),
- tab_contents,
- owning_window,
- NULL);
+ select_file_dialog_->SelectFile(
+ dialog_type_,
+ params.title,
+ default_file_name,
+ select_file_types_.get(),
+ select_file_types_.get() ? 1 : 0, // 1-based index.
+ FILE_PATH_LITERAL(""),
+ tab_contents_,
+ owning_window,
+ NULL);
+
+ select_file_types_.reset();
+}
+
+// This method is called when we receive the last callback from the file
+// chooser dialog. Perform any cleanup and release the reference we added
+// in RunFileChooser().
+void FileSelectHelper::RunFileChooserEnd() {
+ render_view_host_ = NULL;
+ tab_contents_ = NULL;
+ Release();
}
void FileSelectHelper::EnumerateDirectory(int request_id,
RenderViewHost* render_view_host,
const FilePath& path) {
DCHECK_NE(kFileSelectEnumerationId, request_id);
+
+ // Because this class returns notifications to the RenderViewHost, it is
+ // difficult for callers to know how long to keep a reference to this
+ // instance. We AddRef() here to keep the instance alive after we return
+ // to the caller, until the last callback is received from the enumeration
+ // code. At that point, we must call EnumerateDirectoryEnd().
+ AddRef();
StartNewEnumeration(path, request_id, render_view_host);
}
+// This method is called when we receive the last callback from the enumeration
+// code. Perform any cleanup and release the reference we added in
+// EnumerateDirectory().
+void FileSelectHelper::EnumerateDirectoryEnd() {
+ Release();
+}
+
void FileSelectHelper::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type == content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED);
- DCHECK(Source<RenderWidgetHost>(source).ptr() == render_view_host_);
- render_view_host_ = NULL;
+ switch (type) {
+ case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
+ DCHECK(Source<RenderWidgetHost>(source).ptr() == render_view_host_);
+ render_view_host_ = NULL;
+ break;
+ }
+
+ case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: {
+ DCHECK(Source<TabContents>(source).ptr() == tab_contents_);
+ tab_contents_ = NULL;
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
}