In this episode, we implement the DOMUI interface for extension views that are rendered in the main tab contents area. This gets us loaded and unloaded at the right place and removes many special cases for extensions from the RenderViewHost and RenderViewHostDelegate hierarchy.
BUG=13936
Review URL: http://codereview.chromium.org/126137
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19717 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc
new file mode 100644
index 0000000..0d24345
--- /dev/null
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -0,0 +1,31 @@
+#include "chrome/browser/extensions/extension_dom_ui.h"
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/bindings_policy.h"
+
+ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents)
+ : DOMUI(tab_contents) {
+ // TODO(aa): It would be cool to show the extension's icon in here.
+ hide_favicon_ = true;
+ should_hide_url_ = true;
+ bindings_ = BindingsPolicy::EXTENSION;
+}
+
+void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) {
+ extension_function_dispatcher_.reset(
+ new ExtensionFunctionDispatcher(render_view_host, this,
+ tab_contents()->GetURL()));
+}
+
+void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
+ const std::string& content,
+ int request_id,
+ bool has_callback) {
+ extension_function_dispatcher_->HandleRequest(message, content, request_id,
+ has_callback);
+}
+
+Browser* ExtensionDOMUI::GetBrowser() {
+ return static_cast<Browser*>(tab_contents()->delegate());
+}
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
new file mode 100644
index 0000000..2de94cf
--- /dev/null
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -0,0 +1,33 @@
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+
+// This class implements DOMUI for extensions and allows extensions to put UI in
+// the main tab contents area.
+class ExtensionDOMUI
+ : public DOMUI,
+ public ExtensionFunctionDispatcher::Delegate {
+ public:
+ explicit ExtensionDOMUI(TabContents* tab_contents);
+ ExtensionFunctionDispatcher* extension_function_dispatcher() const {
+ return extension_function_dispatcher_.get();
+ }
+
+ // DOMUI
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+ virtual void ProcessDOMUIMessage(const std::string& message,
+ const std::string& content,
+ int request_id,
+ bool has_callback);
+
+ // ExtensionFunctionDispatcher::Delegate
+ virtual Browser* GetBrowser();
+
+ private:
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 7b873a5..24eacf20 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -168,23 +168,31 @@
FactoryRegistry::instance()->ResetFunctions();
}
+std::set<ExtensionFunctionDispatcher*>*
+ ExtensionFunctionDispatcher::all_instances() {
+ static std::set<ExtensionFunctionDispatcher*> instances;
+ return &instances;
+}
+
ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
RenderViewHost* render_view_host,
Delegate* delegate,
- const std::string& extension_id)
+ const GURL& url)
: render_view_host_(render_view_host),
delegate_(delegate),
- extension_id_(extension_id),
+ url_(url),
ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) {
+ all_instances()->insert(this);
RenderProcessHost* process = render_view_host_->process();
ExtensionMessageService* message_service =
ExtensionMessageService::GetInstance(profile()->GetRequestContext());
DCHECK(process);
DCHECK(message_service);
- message_service->RegisterExtension(extension_id, process->pid());
+ message_service->RegisterExtension(extension_id(), process->pid());
}
ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
+ all_instances()->erase(this);
peer_->dispatcher_ = NULL;
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index b59e2563..0e798825 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -6,9 +6,11 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DISPATCHER_H_
#include <string>
+#include <set>
#include <vector>
#include "base/ref_counted.h"
+#include "googleurl/src/gurl.h"
class Browser;
class ExtensionFunction;
@@ -47,9 +49,12 @@
// Resets all functions to their initial implementation.
static void ResetFunctions();
+ // Retrieves a vector of all EFD instances.
+ static std::set<ExtensionFunctionDispatcher*>* all_instances();
+
ExtensionFunctionDispatcher(RenderViewHost* render_view_host,
Delegate* delegate,
- const std::string& extension_id);
+ const GURL& url);
~ExtensionFunctionDispatcher();
// Handle a request to execute an extension function.
@@ -67,18 +72,24 @@
// the renderer.
void HandleBadMessage(ExtensionFunction* api);
+ // Gets the URL for the view we're displaying.
+ const GURL& url() { return url_; }
+
// Gets the ID for this extension.
- std::string extension_id() { return extension_id_; }
+ const std::string extension_id() { return url_.host(); }
// The profile that this dispatcher is associated with.
Profile* profile();
+ // The RenderViewHost this dispatcher is associated with.
+ RenderViewHost* render_view_host() { return render_view_host_; }
+
private:
RenderViewHost* render_view_host_;
Delegate* delegate_;
- std::string extension_id_;
+ GURL url_;
scoped_refptr<Peer> peer_;
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 94b759d5..669dbdd 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/common/bindings_policy.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -84,7 +85,7 @@
url_(url) {
render_view_host_ = new RenderViewHost(
site_instance, this, MSG_ROUTING_NONE, NULL);
- render_view_host_->AllowExtensionBindings();
+ render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
}
ExtensionHost::~ExtensionHost() {
@@ -196,12 +197,6 @@
#endif
}
-ExtensionFunctionDispatcher* ExtensionHost::
- CreateExtensionFunctionDispatcher(RenderViewHost *render_view_host,
- const std::string& extension_id) {
- return new ExtensionFunctionDispatcher(render_view_host, this, extension_id);
-}
-
RenderViewHostDelegate::View* ExtensionHost::GetViewDelegate() const {
// TODO(erikkay) this is unfortunate. The interface declares that this method
// must be const (no good reason for it as far as I can tell) which means you
@@ -303,3 +298,16 @@
// is available. http://code.google.com/p/chromium/issues/detail?id=13284
return browser;
}
+
+void ExtensionHost::ProcessDOMUIMessage(const std::string& message,
+ const std::string& content,
+ int request_id,
+ bool has_callback) {
+ extension_function_dispatcher_->HandleRequest(message, content, request_id,
+ has_callback);
+}
+
+void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
+ extension_function_dispatcher_.reset(
+ new ExtensionFunctionDispatcher(render_view_host_, this, url_));
+}
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index a7ca899..e54fc39 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/scoped_ptr.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
#if defined(TOOLKIT_VIEWS)
@@ -63,6 +64,7 @@
// RenderViewHostDelegate
virtual const GURL& GetURL() const { return url_; }
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual void RenderViewGone(RenderViewHost* render_view_host);
virtual WebPreferences GetWebkitPrefs();
virtual void RunJavaScriptMessage(
@@ -74,9 +76,11 @@
bool* did_suppress_message);
virtual void DidStopLoading(RenderViewHost* render_view_host);
virtual RenderViewHostDelegate::View* GetViewDelegate() const;
- virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
- RenderViewHost *render_view_host, const std::string& extension_id);
virtual void DidInsertCSS();
+ virtual void ProcessDOMUIMessage(const std::string& message,
+ const std::string& content,
+ int request_id,
+ bool has_callback);
// RenderViewHostDelegate::View
virtual void CreateNewWindow(int route_id,
@@ -129,6 +133,8 @@
// The URL being hosted.
GURL url_;
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionHost);
};
diff --git a/chrome/browser/extensions/extension_startup_unittest.cc b/chrome/browser/extensions/extension_startup_unittest.cc
index ce9b885..a9c494a 100644
--- a/chrome/browser/extensions/extension_startup_unittest.cc
+++ b/chrome/browser/extensions/extension_startup_unittest.cc
@@ -152,12 +152,22 @@
&result);
EXPECT_TRUE(result);
+ result = false;
ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetSelectedTabContents(), L"",
L"window.domAutomationController.send(document.title == 'Modified')",
&result);
EXPECT_TRUE(result);
+ // Load an extension page into the tab area to make sure it works.
+ result = false;
+ ui_test_utils::NavigateToURL(
+ browser(),
+ GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html"));
+ ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ browser()->GetSelectedTabContents(), L"", L"testTabsAPI()", &result);
+ EXPECT_TRUE(result);
+
// TODO(aa): Move the stuff in ExtensionBrowserTest here?
}
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 7ad40cc3..62fb559 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -226,29 +226,16 @@
std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
const std::string& extension_id) {
std::vector<ExtensionPage> result;
+ std::set<ExtensionFunctionDispatcher*>* all_instances =
+ ExtensionFunctionDispatcher::all_instances();
- ExtensionMessageService* ems = ExtensionMessageService::GetInstance(
- dom_ui_->GetProfile()->GetOriginalProfile()->GetRequestContext());
- RenderProcessHost* process_host = ems->GetProcessForExtension(extension_id);
- if (!process_host)
- return result;
-
- RenderProcessHost::listeners_iterator iter;
- for (iter = process_host->listeners_begin();
- iter != process_host->listeners_end(); ++iter) {
- // NOTE: This is a bit dangerous. We know that for now, listeners are
- // always RenderWidgetHosts. But in theory, they don't have to be.
- RenderWidgetHost* widget = static_cast<RenderWidgetHost*>(iter->second);
- if (!widget->IsRenderView())
- continue;
-
- RenderViewHost* view = static_cast<RenderViewHost*>(widget);
- ExtensionFunctionDispatcher* efd = view->extension_function_dispatcher();
- if (efd && efd->extension_id() == extension_id) {
- ExtensionPage page(view->delegate()->GetURL(),
- process_host->pid(),
- view->routing_id());
- result.push_back(page);
+ for (std::set<ExtensionFunctionDispatcher*>::iterator iter =
+ all_instances->begin(); iter != all_instances->end(); ++iter) {
+ RenderViewHost* view = (*iter)->render_view_host();
+ if ((*iter)->extension_id() == extension_id && view) {
+ result.push_back(ExtensionPage((*iter)->url(),
+ view->process()->pid(),
+ view->routing_id()));
}
}