Convert geolocation code to use RenderFrame instead of RenderView.

BUG=304341
[email protected]

Review URL: https://codereview.chromium.org/303503008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274339 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/geolocation/geolocation_dispatcher_host.cc b/content/browser/geolocation/geolocation_dispatcher_host.cc
index 34b9e84..aec21709 100644
--- a/content/browser/geolocation/geolocation_dispatcher_host.cc
+++ b/content/browser/geolocation/geolocation_dispatcher_host.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_message_filter.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -64,15 +65,15 @@
 }
 
 void SendGeolocationPermissionResponse(int render_process_id,
-                                       int render_view_id,
+                                       int render_frame_id,
                                        int bridge_id,
                                        bool allowed) {
-  RenderViewHostImpl* render_view_host =
-      RenderViewHostImpl::FromID(render_process_id, render_view_id);
-  if (!render_view_host)
+  RenderFrameHost* render_frame_host =
+      RenderFrameHost::FromID(render_process_id, render_frame_id);
+  if (!render_frame_host)
     return;
-  render_view_host->Send(
-      new GeolocationMsg_PermissionSet(render_view_id, bridge_id, allowed));
+  render_frame_host->Send(
+      new GeolocationMsg_PermissionSet(render_frame_id, bridge_id, allowed));
 
   if (allowed)
     GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices();
@@ -83,9 +84,7 @@
 GeolocationDispatcherHost::GeolocationDispatcherHost(
     WebContents* web_contents)
     : WebContentsObserver(web_contents),
-      watching_requested_(false),
-      paused_(false),
-      high_accuracy_(false) {
+      paused_(false) {
   // This is initialized by WebContentsImpl. Do not add any non-trivial
   // initialization here, defer to OnStartUpdating which is triggered whenever
   // a javascript geolocation object is actually initialized.
@@ -94,21 +93,28 @@
 GeolocationDispatcherHost::~GeolocationDispatcherHost() {
 }
 
+void GeolocationDispatcherHost::RenderFrameDeleted(
+    RenderFrameHost* render_frame_host) {
+  OnStopUpdating(render_frame_host);
+}
+
 void GeolocationDispatcherHost::RenderViewHostChanged(
     RenderViewHost* old_host,
     RenderViewHost* new_host) {
-  watching_requested_ = false;
+  updating_frames_.clear();
   paused_ = false;
   geolocation_subscription_.reset();
 }
 
-bool GeolocationDispatcherHost::OnMessageReceived(const IPC::Message& msg) {
+bool GeolocationDispatcherHost::OnMessageReceived(
+    const IPC::Message& msg, RenderFrameHost* render_frame_host) {
   bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcherHost, msg)
-    IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest,
-                        OnCancelPermissionRequest)
+  IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(GeolocationDispatcherHost, msg,
+                                   render_frame_host)
     IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission,
                         OnRequestPermission)
+    IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest,
+                        OnCancelPermissionRequest)
     IPC_MESSAGE_HANDLER(GeolocationHostMsg_StartUpdating, OnStartUpdating)
     IPC_MESSAGE_HANDLER(GeolocationHostMsg_StopUpdating, OnStopUpdating)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -121,18 +127,25 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   RecordGeopositionErrorCode(geoposition.error_code);
-  if (!paused_)
-    Send(new GeolocationMsg_PositionUpdated(routing_id(), geoposition));
+  if (paused_)
+    return;
+
+  for (std::map<RenderFrameHost*, bool>::iterator i = updating_frames_.begin();
+       i != updating_frames_.end(); ++i) {
+    i->first->Send(new GeolocationMsg_PositionUpdated(
+        i->first->GetRoutingID(), geoposition));
+  }
 }
 
 void GeolocationDispatcherHost::OnRequestPermission(
+    RenderFrameHost* render_frame_host,
     int bridge_id,
     const GURL& requesting_frame,
     bool user_gesture) {
   GeolocationPermissionContext* context =
       web_contents()->GetBrowserContext()->GetGeolocationPermissionContext();
-  int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
-  int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+  int render_process_id = render_frame_host->GetProcess()->GetID();
+  int render_frame_id = render_frame_host->GetRoutingID();
   if (context) {
     context->RequestGeolocationPermission(
         web_contents(),
@@ -141,15 +154,16 @@
         user_gesture,
         base::Bind(&SendGeolocationPermissionResponse,
                    render_process_id,
-                   render_view_id,
+                   render_frame_id,
                    bridge_id));
   } else {
     SendGeolocationPermissionResponse(
-        render_process_id, render_view_id, bridge_id, true);
+        render_process_id, render_frame_id, bridge_id, true);
   }
 }
 
 void GeolocationDispatcherHost::OnCancelPermissionRequest(
+    RenderFrameHost* render_frame_host,
     int bridge_id,
     const GURL& requesting_frame) {
   GeolocationPermissionContext* context =
@@ -161,6 +175,7 @@
 }
 
 void GeolocationDispatcherHost::OnStartUpdating(
+    RenderFrameHost* render_frame_host,
     const GURL& requesting_frame,
     bool enable_high_accuracy) {
   // StartUpdating() can be invoked as a result of high-accuracy mode
@@ -169,13 +184,13 @@
       "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
       enable_high_accuracy);
 
-  watching_requested_ = true;
-  high_accuracy_ = enable_high_accuracy;
+  updating_frames_[render_frame_host] = enable_high_accuracy;
   RefreshGeolocationOptions();
 }
 
-void GeolocationDispatcherHost::OnStopUpdating() {
-  watching_requested_ = false;
+void GeolocationDispatcherHost::OnStopUpdating(
+    RenderFrameHost* render_frame_host) {
+  updating_frames_.erase(render_frame_host);
   RefreshGeolocationOptions();
 }
 
@@ -188,15 +203,24 @@
 void GeolocationDispatcherHost::RefreshGeolocationOptions() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  if (watching_requested_ && !paused_) {
-    geolocation_subscription_ = GeolocationProvider::GetInstance()->
-        AddLocationUpdateCallback(
-            base::Bind(&GeolocationDispatcherHost::OnLocationUpdate,
-                       base::Unretained(this)),
-            high_accuracy_);
-  } else {
+  if (updating_frames_.empty() || paused_) {
     geolocation_subscription_.reset();
+    return;
   }
+
+  bool high_accuracy = false;
+  for (std::map<RenderFrameHost*, bool>::iterator i =
+            updating_frames_.begin(); i != updating_frames_.end(); ++i) {
+    if (i->second) {
+      high_accuracy = true;
+      break;
+    }
+  }
+  geolocation_subscription_ = GeolocationProvider::GetInstance()->
+      AddLocationUpdateCallback(
+          base::Bind(&GeolocationDispatcherHost::OnLocationUpdate,
+                      base::Unretained(this)),
+          high_accuracy);
 }
 
 }  // namespace content
diff --git a/content/browser/geolocation/geolocation_dispatcher_host.h b/content/browser/geolocation/geolocation_dispatcher_host.h
index a73487f0..151ed46 100644
--- a/content/browser/geolocation/geolocation_dispatcher_host.h
+++ b/content/browser/geolocation/geolocation_dispatcher_host.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
 #define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
 
+#include <map>
+
 #include "content/browser/geolocation/geolocation_provider_impl.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -29,19 +31,24 @@
 
  private:
   // WebContentsObserver
+  virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
   virtual void RenderViewHostChanged(RenderViewHost* old_host,
                                      RenderViewHost* new_host) OVERRIDE;
-  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+  virtual bool OnMessageReceived(
+      const IPC::Message& msg, RenderFrameHost* render_frame_host) OVERRIDE;
 
   // Message handlers:
-  void OnRequestPermission(int bridge_id,
+  void OnRequestPermission(RenderFrameHost* render_frame_host,
+                           int bridge_id,
                            const GURL& requesting_frame,
                            bool user_gesture);
-  void OnCancelPermissionRequest(int bridge_id,
+  void OnCancelPermissionRequest(RenderFrameHost* render_frame_host,
+                                 int bridge_id,
                                  const GURL& requesting_frame);
-  void OnStartUpdating(const GURL& requesting_frame,
+  void OnStartUpdating(RenderFrameHost* render_frame_host,
+                       const GURL& requesting_frame,
                        bool enable_high_accuracy);
-  void OnStopUpdating();
+  void OnStopUpdating(RenderFrameHost* render_frame_host);
 
   // Updates the geolocation provider with the currently required update
   // options.
@@ -51,9 +58,10 @@
 
   scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
 
-  bool watching_requested_;
+  // A map from the RenderFrameHosts that have requested geolocation updates to
+  // the type of accuracy they requested (true = high accuracy).
+  std::map<RenderFrameHost*, bool> updating_frames_;
   bool paused_;
-  bool high_accuracy_;
 
   scoped_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
 
diff --git a/content/renderer/geolocation_dispatcher.cc b/content/renderer/geolocation_dispatcher.cc
index 7b48ca5..620b057 100644
--- a/content/renderer/geolocation_dispatcher.cc
+++ b/content/renderer/geolocation_dispatcher.cc
@@ -22,8 +22,8 @@
 
 namespace content {
 
-GeolocationDispatcher::GeolocationDispatcher(RenderViewImpl* render_view)
-    : RenderViewObserver(render_view),
+GeolocationDispatcher::GeolocationDispatcher(RenderFrame* render_frame)
+    : RenderFrameObserver(render_frame),
       pending_permissions_(new WebGeolocationPermissionRequestManager()),
       enable_high_accuracy_(false),
       updating_(false) {
diff --git a/content/renderer/geolocation_dispatcher.h b/content/renderer/geolocation_dispatcher.h
index 5a96070..bffa509 100644
--- a/content/renderer/geolocation_dispatcher.h
+++ b/content/renderer/geolocation_dispatcher.h
@@ -6,7 +6,7 @@
 #define CONTENT_RENDERER_GEOLOCATION_DISPATCHER_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_frame_observer.h"
 #include "third_party/WebKit/public/web/WebGeolocationClient.h"
 #include "third_party/WebKit/public/web/WebGeolocationController.h"
 
@@ -18,20 +18,19 @@
 }
 
 namespace content {
-class RenderViewImpl;
 struct Geoposition;
 
 // GeolocationDispatcher is a delegate for Geolocation messages used by
 // WebKit.
-// It's the complement of GeolocationDispatcherHost (owned by RenderViewHost).
-class GeolocationDispatcher : public RenderViewObserver,
+// It's the complement of GeolocationDispatcherHost.
+class GeolocationDispatcher : public RenderFrameObserver,
                               public blink::WebGeolocationClient {
  public:
-  explicit GeolocationDispatcher(RenderViewImpl* render_view);
+  explicit GeolocationDispatcher(RenderFrame* render_frame);
   virtual ~GeolocationDispatcher();
 
  private:
-  // RenderView::Observer implementation.
+  // RenderFrame::Observer implementation.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // WebGeolocationClient
@@ -55,7 +54,7 @@
   // The controller_ is valid for the lifetime of the underlying
   // WebCore::GeolocationController. geolocationDestroyed() is
   // invoked when the underlying object is destroyed.
-  scoped_ptr< blink::WebGeolocationController> controller_;
+  scoped_ptr<blink::WebGeolocationController> controller_;
 
   scoped_ptr<blink::WebGeolocationPermissionRequestManager>
       pending_permissions_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e891bbac..cfce1ee9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -52,6 +52,7 @@
 #include "content/renderer/context_menu_params_builder.h"
 #include "content/renderer/devtools/devtools_agent.h"
 #include "content/renderer/dom_automation_controller.h"
+#include "content/renderer/geolocation_dispatcher.h"
 #include "content/renderer/history_controller.h"
 #include "content/renderer/history_serialization.h"
 #include "content/renderer/image_loading_helper.h"
@@ -412,6 +413,7 @@
       media_player_manager_(NULL),
       cdm_manager_(NULL),
 #endif
+      geolocation_dispatcher_(NULL),
       weak_factory_(this) {
   RenderThread::Get()->AddRoute(routing_id_, this);
 
@@ -2741,7 +2743,9 @@
 }
 
 blink::WebGeolocationClient* RenderFrameImpl::geolocationClient() {
-  return render_view_->geolocationClient();
+  if (!geolocation_dispatcher_)
+    geolocation_dispatcher_ = new GeolocationDispatcher(this);
+  return geolocation_dispatcher_;
 }
 
 void RenderFrameImpl::willStartUsingPeerConnectionHandler(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 7c7cfcb..35e046a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -58,6 +58,7 @@
 namespace content {
 
 class ChildFrameCompositingHelper;
+class GeolocationDispatcher;
 class MediaStreamRendererFactory;
 class NotificationProvider;
 class PepperPluginInstanceImpl;
@@ -616,6 +617,9 @@
   RendererCdmManager* cdm_manager_;
 #endif
 
+  // The geolocation dispatcher attached to this view, lazily initialized.
+  GeolocationDispatcher* geolocation_dispatcher_;
+
   base::WeakPtrFactory<RenderFrameImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameImpl);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 7257b00..5ce68b0 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -683,19 +683,19 @@
   // Ensure we start with a valid next_page_id_ from the browser.
   DCHECK_GE(next_page_id_, 0);
 
-  RenderFrameImpl* main_render_frame = RenderFrameImpl::Create(
-      this, params->main_frame_routing_id);
+  main_render_frame_.reset(RenderFrameImpl::Create(
+      this, params->main_frame_routing_id));
   // The main frame WebLocalFrame object is closed by
   // RenderFrameImpl::frameDetached().
-  WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame);
-  main_render_frame->SetWebFrame(web_frame);
+  WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame_.get());
+  main_render_frame_->SetWebFrame(web_frame);
 
   if (params->proxy_routing_id != MSG_ROUTING_NONE) {
     CHECK(params->swapped_out);
     RenderFrameProxy* proxy =
         RenderFrameProxy::CreateFrameProxy(params->proxy_routing_id,
                                            params->main_frame_routing_id);
-    main_render_frame->set_render_frame_proxy(proxy);
+    main_render_frame_->set_render_frame_proxy(proxy);
   }
 
   webwidget_ = WebView::create(this);
@@ -757,7 +757,6 @@
   webview()->settings()->setAllowConnectingInsecureWebSocket(
       command_line.HasSwitch(switches::kAllowInsecureWebSocketFromHttpsOrigin));
 
-  main_render_frame_.reset(main_render_frame);
   webview()->setMainFrame(main_render_frame_->GetWebFrame());
   main_render_frame_->Initialize();
 
@@ -3636,8 +3635,10 @@
 }
 
 blink::WebGeolocationClient* RenderViewImpl::geolocationClient() {
-  if (!geolocation_dispatcher_)
-    geolocation_dispatcher_ = new GeolocationDispatcher(this);
+  if (!geolocation_dispatcher_) {
+    geolocation_dispatcher_ = new GeolocationDispatcher(
+        main_render_frame_.get());
+  }
   return geolocation_dispatcher_;
 }
 
diff --git a/ui/views/controls/webview/webview_interactive_uitest.cc b/ui/views/controls/webview/webview_interactive_uitest.cc
index c5f65a2..f1179b83 100644
--- a/ui/views/controls/webview/webview_interactive_uitest.cc
+++ b/ui/views/controls/webview/webview_interactive_uitest.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread.h"
 #include "ui/base/ime/text_input_focus_manager.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gl/gl_surface.h"
@@ -18,7 +19,8 @@
 
 class WebViewInteractiveUiTest : public views::test::WidgetTest {
  public:
-  WebViewInteractiveUiTest() {}
+  WebViewInteractiveUiTest()
+      : ui_thread_(content::BrowserThread::UI, base::MessageLoop::current()) {}
 
   virtual void SetUp() OVERRIDE {
     gfx::GLSurface::InitializeOneOffForTests();
@@ -31,6 +33,7 @@
  private:
   content::TestBrowserContext browser_context_;
   views::WebViewTestHelper webview_test_helper_;
+  content::TestBrowserThread ui_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewInteractiveUiTest);
 };