Move file chooser from RenderView(Host) to RenderFrame(Host).

The file chooser does not work with out-of-process iframes, since it works through RenderView(Host). It needs to be moved to user RenderFrame(Host) at which point it works for subframes in a process different from its parent.

BUG=615575
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation

[email protected]

Review-Url: https://codereview.chromium.org/2050623005
Cr-Commit-Position: refs/heads/master@{#399373}
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.cc b/content/renderer/pepper/mock_renderer_ppapi_host.cc
index 0a4bc6e..6f39f0fb 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.cc
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/pepper/mock_renderer_ppapi_host.h"
 
+#include "content/public/renderer/render_view.h"
 #include "content/renderer/pepper/fake_pepper_plugin_instance.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -16,7 +17,10 @@
       render_view_(render_view),
       pp_instance_(instance),
       has_user_gesture_(false),
-      plugin_instance_(new FakePepperPluginInstance) {}
+      plugin_instance_(new FakePepperPluginInstance) {
+  if (render_view)
+    render_frame_ = render_view->GetMainRenderFrame();
+}
 
 MockRendererPpapiHost::~MockRendererPpapiHost() {}
 
@@ -35,6 +39,8 @@
 
 RenderFrame* MockRendererPpapiHost::GetRenderFrameForInstance(
     PP_Instance instance) const {
+  if (instance == pp_instance_)
+    return render_frame_;
   return NULL;
 }
 
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.h b/content/renderer/pepper/mock_renderer_ppapi_host.h
index 84e6ff4..30dd766 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.h
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.h
@@ -65,6 +65,7 @@
   ppapi::host::PpapiHost ppapi_host_;
 
   RenderView* render_view_;
+  RenderFrame* render_frame_;
   PP_Instance pp_instance_;
 
   bool has_user_gesture_;
diff --git a/content/renderer/pepper/pepper_file_chooser_host.cc b/content/renderer/pepper/pepper_file_chooser_host.cc
index b70ab83..f2f8be3b 100644
--- a/content/renderer/pepper/pepper_file_chooser_host.cc
+++ b/content/renderer/pepper/pepper_file_chooser_host.cc
@@ -154,9 +154,10 @@
   params.requestor = renderer_ppapi_host_->GetDocumentURL(pp_instance());
 
   handler_ = new CompletionHandler(AsWeakPtr());
-  RenderViewImpl* render_view = static_cast<RenderViewImpl*>(
-      renderer_ppapi_host_->GetRenderViewForInstance(pp_instance()));
-  if (!render_view || !render_view->runFileChooser(params, handler_)) {
+  RenderFrameImpl* render_frame = static_cast<RenderFrameImpl*>(
+      renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance()));
+
+  if (!render_frame || !render_frame->runFileChooser(params, handler_)) {
     delete handler_;
     handler_ = NULL;
     return PP_ERROR_NOACCESS;
diff --git a/content/renderer/pepper/pepper_file_chooser_host_unittest.cc b/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
index 85d8c91..d610636 100644
--- a/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
+++ b/content/renderer/pepper/pepper_file_chooser_host_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "content/common/frame_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/file_chooser_file_info.h"
 #include "content/public/common/file_chooser_params.h"
@@ -92,10 +93,10 @@
   // 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);
+      FrameHostMsg_RunFileChooser::ID);
   ASSERT_TRUE(msg);
-  ViewHostMsg_RunFileChooser::Schema::Param call_msg_param;
-  ASSERT_TRUE(ViewHostMsg_RunFileChooser::Read(msg, &call_msg_param));
+  FrameHostMsg_RunFileChooser::Schema::Param call_msg_param;
+  ASSERT_TRUE(FrameHostMsg_RunFileChooser::Read(msg, &call_msg_param));
   const FileChooserParams& chooser_params = std::get<0>(call_msg_param);
 
   // Basic validation of request.
@@ -110,10 +111,11 @@
   selected_info.file_path = base::FilePath(FILE_PATH_LITERAL("myp\\ath/foo"));
   std::vector<content::FileChooserFileInfo> selected_info_vector;
   selected_info_vector.push_back(selected_info);
-  RenderViewImpl* view_impl = static_cast<RenderViewImpl*>(view_);
-  ViewMsg_RunFileChooserResponse response(view_impl->GetRoutingID(),
-                                          selected_info_vector);
-  EXPECT_TRUE(view_impl->OnMessageReceived(response));
+  RenderFrameImpl* frame_impl =
+      static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame());
+  FrameMsg_RunFileChooserResponse response(frame_impl->GetRoutingID(),
+                                           selected_info_vector);
+  EXPECT_TRUE(frame_impl->OnMessageReceived(response));
 
   // This should have sent the Pepper reply to our test sink.
   ppapi::proxy::ResourceMessageReplyParams reply_params;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 13392d1..06b064f6 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -69,6 +69,8 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/context_menu_params.h"
+#include "content/public/common/file_chooser_file_info.h"
+#include "content/public/common/file_chooser_params.h"
 #include "content/public/common/isolated_world_ids.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/resource_response.h"
@@ -151,6 +153,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_util.h"
 #include "storage/common/data_element.h"
+#include "third_party/WebKit/public/platform/FilePathConversion.h"
 #include "third_party/WebKit/public/platform/URLConversion.h"
 #include "third_party/WebKit/public/platform/WebCachePolicy.h"
 #include "third_party/WebKit/public/platform/WebData.h"
@@ -851,6 +854,14 @@
 
 }  // namespace
 
+struct RenderFrameImpl::PendingFileChooser {
+  PendingFileChooser(const FileChooserParams& p,
+                     blink::WebFileChooserCompletion* c)
+      : params(p), completion(c) {}
+  FileChooserParams params;
+  blink::WebFileChooserCompletion* completion;  // MAY BE NULL to skip callback.
+};
+
 // static
 RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view,
                                          int32_t routing_id) {
@@ -1114,6 +1125,15 @@
 }
 
 RenderFrameImpl::~RenderFrameImpl() {
+  // If file chooser is still waiting for answer, dispatch empty answer.
+  while (!file_chooser_completions_.empty()) {
+    if (file_chooser_completions_.front()->completion) {
+      file_chooser_completions_.front()->completion->didChooseFile(
+          WebVector<WebString>());
+    }
+    file_chooser_completions_.pop_front();
+  }
+
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone());
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct());
 
@@ -1505,6 +1525,7 @@
     IPC_MESSAGE_HANDLER(FrameMsg_EnableViewSourceMode, OnEnableViewSourceMode)
     IPC_MESSAGE_HANDLER(FrameMsg_SuppressFurtherDialogs,
                         OnSuppressFurtherDialogs)
+    IPC_MESSAGE_HANDLER(FrameMsg_RunFileChooserResponse, OnFileChooserResponse)
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(FrameMsg_ActivateNearestFindResult,
                         OnActivateNearestFindResult)
@@ -2218,6 +2239,31 @@
   return success;
 }
 
+bool RenderFrameImpl::ScheduleFileChooser(
+    const FileChooserParams& params,
+    blink::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(
+      base::WrapUnique(new PendingFileChooser(params, completion)));
+  if (file_chooser_completions_.size() == 1) {
+    // Actually show the browse dialog when this is the first request.
+    Send(new FrameHostMsg_RunFileChooser(routing_id_, params));
+  }
+  return true;
+}
+
 void RenderFrameImpl::LoadNavigationErrorPage(
     const WebURLRequest& failed_request,
     const WebURLError& error,
@@ -3744,6 +3790,37 @@
   return success;
 }
 
+bool RenderFrameImpl::runFileChooser(
+    const blink::WebFileChooserParams& params,
+    blink::WebFileChooserCompletion* chooser_completion) {
+  // Do not open the file dialog in a hidden RenderView.
+  if (render_view_->is_hidden())
+    return false;
+
+  FileChooserParams ipc_params;
+  if (params.directory)
+    ipc_params.mode = FileChooserParams::UploadFolder;
+  else if (params.multiSelect)
+    ipc_params.mode = FileChooserParams::OpenMultiple;
+  else if (params.saveAs)
+    ipc_params.mode = FileChooserParams::Save;
+  else
+    ipc_params.mode = FileChooserParams::Open;
+  ipc_params.title = params.title;
+  ipc_params.default_file_name =
+      blink::WebStringToFilePath(params.initialValue).BaseName();
+  ipc_params.accept_types.reserve(params.acceptTypes.size());
+  for (const auto& type : params.acceptTypes)
+    ipc_params.accept_types.push_back(type);
+  ipc_params.need_local_path = params.needLocalPath;
+#if defined(OS_ANDROID)
+  ipc_params.capture = params.useMediaCapture;
+#endif
+  ipc_params.requestor = params.requestor;
+
+  return ScheduleFileChooser(ipc_params, chooser_completion);
+}
+
 void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
   ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
   blink::WebRect position_in_window(params.x, params.y, 0, 0);
@@ -5129,6 +5206,43 @@
   suppress_further_dialogs_ = true;
 }
 
+void RenderFrameImpl::OnFileChooserResponse(
+    const std::vector<content::FileChooserFileInfo>& files) {
+  // This could happen if we navigated to a different page before the user
+  // closed the chooser.
+  if (file_chooser_completions_.empty())
+    return;
+
+  // Convert Chrome's SelectedFileInfo list to WebKit's.
+  WebVector<blink::WebFileChooserCompletion::SelectedFileInfo> selected_files(
+      files.size());
+  for (size_t i = 0; i < files.size(); ++i) {
+    blink::WebFileChooserCompletion::SelectedFileInfo selected_file;
+    selected_file.path = files[i].file_path.AsUTF16Unsafe();
+    selected_file.displayName =
+        base::FilePath(files[i].display_name).AsUTF16Unsafe();
+    if (files[i].file_system_url.is_valid()) {
+      selected_file.fileSystemURL = files[i].file_system_url;
+      selected_file.length = files[i].length;
+      selected_file.modificationTime = files[i].modification_time.ToDoubleT();
+      selected_file.isDirectory = files[i].is_directory;
+    }
+    selected_files[i] = selected_file;
+  }
+
+  if (file_chooser_completions_.front()->completion) {
+    file_chooser_completions_.front()->completion->didChooseFile(
+        selected_files);
+  }
+  file_chooser_completions_.pop_front();
+
+  // If there are more pending file chooser requests, schedule one now.
+  if (!file_chooser_completions_.empty()) {
+    Send(new FrameHostMsg_RunFileChooser(
+        routing_id_, file_chooser_completions_.front()->params));
+  }
+}
+
 #if defined(OS_ANDROID)
 void RenderFrameImpl::OnActivateNearestFindResult(int request_id,
                                                   float x,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 261ed1c2..a53eb87 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -152,6 +152,8 @@
 class WakeLockDispatcher;
 struct CommonNavigationParams;
 struct CustomContextMenuContext;
+struct FileChooserFileInfo;
+struct FileChooserParams;
 struct FrameReplicationState;
 struct NavigationParams;
 struct RequestNavigationParams;
@@ -541,6 +543,9 @@
                             const blink::WebString& default_value,
                             blink::WebString* actual_value) override;
   bool runModalBeforeUnloadDialog(bool is_reload) override;
+  bool runFileChooser(
+      const blink::WebFileChooserParams& params,
+      blink::WebFileChooserCompletion* chooser_completion) override;
   void showContextMenu(const blink::WebContextMenuData& data) override;
   void willSendRequest(blink::WebLocalFrame* frame,
                        unsigned identifier,
@@ -822,6 +827,8 @@
   void OnStopFinding(StopFindAction action);
   void OnEnableViewSourceMode();
   void OnSuppressFurtherDialogs();
+  void OnFileChooserResponse(
+      const std::vector<content::FileChooserFileInfo>& files);
 #if defined(OS_ANDROID)
   void OnActivateNearestFindResult(int request_id, float x, float y);
   void OnGetNearestFindResult(int request_id, float x, float y);
@@ -893,6 +900,15 @@
                             const GURL& frame_url,
                             base::string16* result);
 
+  // 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 FileChooserParams& params,
+                           blink::WebFileChooserCompletion* completion);
+
   // Loads the appropriate error page for the specified failure into the frame.
   void LoadNavigationErrorPage(const blink::WebURLRequest& failed_request,
                                const blink::WebURLError& error,
@@ -1229,6 +1245,13 @@
   // stack that interferes with swapping out.
   bool suppress_further_dialogs_;
 
+  // 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<std::unique_ptr<PendingFileChooser>> file_chooser_completions_;
+
 #if defined(USE_EXTERNAL_POPUP_MENU)
   // The external popup for the currently showing select popup.
   std::unique_ptr<ExternalPopupMenu> external_popup_menu_;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index b0a36e27..c2537c9 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -61,8 +61,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/drop_data.h"
 #include "content/public/common/favicon_url.h"
-#include "content/public/common/file_chooser_file_info.h"
-#include "content/public/common/file_chooser_params.h"
 #include "content/public/common/page_importance_signals.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/page_zoom.h"
@@ -392,15 +390,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-struct RenderViewImpl::PendingFileChooser {
-  PendingFileChooser(const FileChooserParams& p, WebFileChooserCompletion* c)
-      : params(p),
-        completion(c) {
-  }
-  FileChooserParams params;
-  WebFileChooserCompletion* completion;  // MAY BE NULL to skip callback.
-};
-
 namespace {
 
 WebDragData DropDataToWebDragData(const DropData& drop_data) {
@@ -809,15 +798,6 @@
        ++it)
     delete it->second;
 
-  // If file chooser is still waiting for answer, dispatch empty answer.
-  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_ANDROID)
   // The date/time picker client is both a std::unique_ptr member of this class
   // and a RenderViewObserver. Reset it to prevent double deletion.
@@ -1277,7 +1257,6 @@
     IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
     IPC_MESSAGE_HANDLER(ViewMsg_EnumerateDirectoryResponse,
                         OnEnumerateDirectoryResponse)
-    IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
     IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
     IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
     IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted)
@@ -1668,36 +1647,6 @@
   return did_execute_command;
 }
 
-bool RenderViewImpl::runFileChooser(
-    const blink::WebFileChooserParams& params,
-    WebFileChooserCompletion* chooser_completion) {
-  // Do not open the file dialog in a hidden RenderView.
-  if (is_hidden())
-    return false;
-  FileChooserParams ipc_params;
-  if (params.directory)
-    ipc_params.mode = FileChooserParams::UploadFolder;
-  else if (params.multiSelect)
-    ipc_params.mode = FileChooserParams::OpenMultiple;
-  else if (params.saveAs)
-    ipc_params.mode = FileChooserParams::Save;
-  else
-    ipc_params.mode = FileChooserParams::Open;
-  ipc_params.title = params.title;
-  ipc_params.default_file_name =
-      blink::WebStringToFilePath(params.initialValue).BaseName();
-  ipc_params.accept_types.reserve(params.acceptTypes.size());
-  for (size_t i = 0; i < params.acceptTypes.size(); ++i)
-    ipc_params.accept_types.push_back(params.acceptTypes[i]);
-  ipc_params.need_local_path = params.needLocalPath;
-#if defined(OS_ANDROID)
-  ipc_params.capture = params.useMediaCapture;
-#endif
-  ipc_params.requestor = params.requestor;
-
-  return ScheduleFileChooser(ipc_params, chooser_completion);
-}
-
 void RenderViewImpl::SetValidationMessageDirection(
     base::string16* wrapped_main_text,
     blink::WebTextDirection main_text_hint,
@@ -2444,42 +2393,6 @@
   enumeration_completions_.erase(id);
 }
 
-void RenderViewImpl::OnFileChooserResponse(
-    const std::vector<content::FileChooserFileInfo>& files) {
-  // This could happen if we navigated to a different page before the user
-  // closed the chooser.
-  if (file_chooser_completions_.empty())
-    return;
-
-  // Convert Chrome's SelectedFileInfo list to WebKit's.
-  WebVector<WebFileChooserCompletion::SelectedFileInfo> selected_files(
-      files.size());
-  for (size_t i = 0; i < files.size(); ++i) {
-    WebFileChooserCompletion::SelectedFileInfo selected_file;
-    selected_file.path = files[i].file_path.AsUTF16Unsafe();
-    selected_file.displayName =
-        base::FilePath(files[i].display_name).AsUTF16Unsafe();
-    if (files[i].file_system_url.is_valid()) {
-      selected_file.fileSystemURL = files[i].file_system_url;
-      selected_file.length = files[i].length;
-      selected_file.modificationTime = files[i].modification_time.ToDoubleT();
-      selected_file.isDirectory = files[i].is_directory;
-    }
-    selected_files[i] = selected_file;
-  }
-
-  if (file_chooser_completions_.front()->completion)
-    file_chooser_completions_.front()->completion->didChooseFile(
-        selected_files);
-  file_chooser_completions_.pop_front();
-
-  // If there are more pending file chooser requests, schedule one now.
-  if (!file_chooser_completions_.empty()) {
-    Send(new ViewHostMsg_RunFileChooser(
-        GetRoutingID(), file_chooser_completions_.front()->params));
-  }
-}
-
 void RenderViewImpl::OnEnableAutoResize(const gfx::Size& min_size,
                                         const gfx::Size& max_size) {
   DCHECK(disable_scrollbars_size_limit_.IsEmpty());
@@ -2958,31 +2871,6 @@
   }
 }
 
-bool RenderViewImpl::ScheduleFileChooser(
-    const FileChooserParams& 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(
-      base::WrapUnique(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(GetRoutingID(), params));
-  }
-  return true;
-}
-
 blink::WebSpeechRecognizer* RenderViewImpl::speechRecognizer() {
   if (!speech_recognition_dispatcher_)
     speech_recognition_dispatcher_ = new SpeechRecognitionDispatcher(this);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 636f1c2e4..e60e4c3 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -341,9 +341,6 @@
   void saveImageFromDataURL(const blink::WebString& data_url) override;
   void didCancelCompositionOnSelectionChange() override;
   bool handleCurrentKeyboardEvent() override;
-  bool runFileChooser(
-      const blink::WebFileChooserParams& params,
-      blink::WebFileChooserCompletion* chooser_completion) override;
   void SetValidationMessageDirection(base::string16* main_text,
                                      blink::WebTextDirection main_text_hint,
                                      base::string16* sub_text,
@@ -637,8 +634,6 @@
   void OnDisableAutoResize(const gfx::Size& new_size);
   void OnEnumerateDirectoryResponse(int id,
                                     const std::vector<base::FilePath>& paths);
-  void OnFileChooserResponse(
-      const std::vector<content::FileChooserFileInfo>& files);
   void OnMediaPlayerActionAt(const gfx::Point& location,
                              const blink::WebMediaPlayerAction& action);
   void OnPluginActionAt(const gfx::Point& location,
@@ -910,13 +905,6 @@
 
   // Misc ----------------------------------------------------------------------
 
-  // 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<std::unique_ptr<PendingFileChooser>> file_chooser_completions_;
-
   // The current directory enumeration callback
   std::map<int, blink::WebFileChooserCompletion*> enumeration_completions_;
   int enumeration_completion_id_;