summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 00:37:31 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 00:37:31 +0000
commit1c1c77a5021be0b902240a4f78009a8d8f71d1ac (patch)
treec1afb46b67de923afaac68340ddb0113b7306193 /chrome/browser/extensions
parent23b3f6c67270a6aff5020c9a7279f4ed84192a02 (diff)
downloadchromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.zip
chromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.tar.gz
chromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.tar.bz2
Submitting change from http://codereview.chromium.org/276029/show
BUG=none TEST=none git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30778 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc4
-rw-r--r--chrome/browser/extensions/extension_host.cc63
-rw-r--r--chrome/browser/extensions/extension_host.h45
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc164
-rw-r--r--chrome/browser/extensions/extension_popup_api.h50
-rw-r--r--chrome/browser/extensions/extension_popup_apitest.cc13
6 files changed, 336 insertions, 3 deletions
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index d7105cb..a3f8a4c 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
+#include "chrome/browser/extensions/extension_popup_api.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
@@ -139,6 +140,9 @@ void FactoryRegistry::ResetFunctions() {
// I18N.
RegisterFunction<GetAcceptLanguagesFunction>();
+ // Popup API.
+ RegisterFunction<PopupShowFunction>();
+
// Test.
RegisterFunction<ExtensionTestPassFunction>();
RegisterFunction<ExtensionTestFailFunction>();
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 2f94612..9435913 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -18,12 +18,16 @@
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
+#include "chrome/browser/extensions/extension_popup_api.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/extensions/extension_popup.h"
+#endif
#include "chrome/common/bindings_policy.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -111,14 +115,25 @@ ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance,
did_stop_loading_(false),
document_element_available_(false),
url_(url),
+#if defined(TOOLKIT_VIEWS)
+ child_popup_(NULL),
+#endif
extension_host_type_(host_type) {
render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE);
render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
if (enable_dom_automation_)
render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION);
+
+#if defined(TOOLKIT_VIEWS)
+ // Listen for view close requests, so that we can dismiss a hosted pop-up
+ // view, if necessary.
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(profile_));
+#endif
}
ExtensionHost::~ExtensionHost() {
+ DismissPopup();
NotificationService::current()->Notify(
NotificationType::EXTENSION_HOST_DESTROYED,
Source<Profile>(profile_),
@@ -208,6 +223,15 @@ void ExtensionHost::Observe(NotificationType type,
NavigateToURL(url_);
} else if (type == NotificationType::BROWSER_THEME_CHANGED) {
InsertThemeCSS();
+#if defined(TOOLKIT_VIEWS)
+ } else if (type == NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE) {
+ // If we aren't the host of the popup, then disregard the notification.
+ if (!child_popup_ ||
+ Details<ExtensionHost>(child_popup_->host()) != details)
+ return;
+
+ DismissPopup();
+#endif
} else {
NOTREACHED();
}
@@ -294,6 +318,38 @@ void ExtensionHost::InsertThemeCSS() {
render_view_host()->InsertCSSInWebFrame(L"", css, "ToolstripThemeCSS");
}
+void ExtensionHost::DismissPopup() {
+#if defined(TOOLKIT_VIEWS)
+ if (child_popup_) {
+ child_popup_->Hide();
+ child_popup_->DetachFromBrowser();
+ delete child_popup_;
+ child_popup_ = NULL;
+
+ PopupEventRouter::OnPopupClosed(GetBrowser()->profile(),
+ view()->render_view_host()->routing_id());
+ }
+#endif
+}
+
+#if defined(TOOLKIT_VIEWS)
+void ExtensionHost::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
+ DismissPopup();
+}
+void ExtensionHost::BubbleBrowserWindowClosing(BrowserBubble* bubble) {
+ DismissPopup();
+}
+
+void ExtensionHost::BubbleGotFocus(BrowserBubble* bubble) {
+}
+
+void ExtensionHost::BubbleLostFocus(BrowserBubble* bubble) {
+ // TODO(twiz): Dismiss the pop-up upon loss of focus of the bubble, but not
+ // if the focus is transitioning to the host which owns the popup!
+ // DismissPopup();
+}
+#endif // defined(TOOLKIT_VIEWS)
+
void ExtensionHost::DidStopLoading() {
bool notify = !did_stop_loading_;
did_stop_loading_ = true;
@@ -325,6 +381,13 @@ void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) {
registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
NotificationService::AllSources());
}
+
+ if (ViewType::EXTENSION_POPUP == GetRenderViewType()) {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_POPUP_VIEW_READY,
+ Source<Profile>(profile_),
+ Details<ExtensionHost>(this));
+ }
}
void ExtensionHost::RunJavaScriptMessage(const std::wstring& message,
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index ea9660d..bf66579 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -12,6 +12,7 @@
#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)
+#include "chrome/browser/views/browser_bubble.h"
#include "chrome/browser/views/extensions/extension_view.h"
#elif defined(OS_LINUX)
#include "chrome/browser/gtk/extension_view_gtk.h"
@@ -20,8 +21,12 @@
#endif
#include "chrome/common/notification_registrar.h"
+
class Browser;
class Extension;
+#if defined(TOOLKIT_VIEWS)
+class ExtensionPopup;
+#endif
class ExtensionProcessManager;
class RenderProcessHost;
class RenderWidgetHost;
@@ -33,7 +38,11 @@ struct WebPreferences;
// It handles setting up the renderer process, if needed, with special
// privileges available to extensions. It may have a view to be shown in the
// in the browser UI, or it may be hidden.
-class ExtensionHost : public RenderViewHostDelegate,
+class ExtensionHost : // NOLINT
+#if defined(TOOLKIT_VIEWS)
+ public BrowserBubble::Delegate,
+#endif
+ public RenderViewHostDelegate,
public RenderViewHostDelegate::View,
public ExtensionFunctionDispatcher::Delegate,
public NotificationObserver {
@@ -72,6 +81,14 @@ class ExtensionHost : public RenderViewHostDelegate,
}
Profile* profile() const { return profile_; }
+#if defined(TOOLKIT_VIEWS)
+ ExtensionPopup* child_popup() const { return child_popup_; }
+ void set_child_popup(ExtensionPopup* popup) { child_popup_ = popup; }
+#endif
+
+ // Dismiss the hosted pop-up, if one is present.
+ void DismissPopup();
+
// Sets the the ViewType of this host (e.g. mole, toolstrip).
void SetRenderViewType(ViewType::Type type);
@@ -89,6 +106,22 @@ class ExtensionHost : public RenderViewHostDelegate,
// Insert the theme CSS for a toolstrip/mole.
void InsertThemeCSS();
+#if defined(TOOLKIT_VIEWS)
+ // BrowserBubble::Delegate implementation.
+ // Called when the Browser Window that this bubble is attached to moves.
+ virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble);
+
+ // Called with the Browser Window that this bubble is attached to is
+ // about to close.
+ virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
+
+ // Called when the bubble became active / got focus.
+ virtual void BubbleGotFocus(BrowserBubble* bubble);
+
+ // Called when the bubble became inactive / lost focus.
+ virtual void BubbleLostFocus(BrowserBubble* bubble);
+#endif // defined(TOOLKIT_VIEWS)
+
// RenderViewHostDelegate implementation.
virtual RenderViewHostDelegate::View* GetViewDelegate();
virtual const GURL& GetURL() const { return url_; }
@@ -192,12 +225,18 @@ class ExtensionHost : public RenderViewHostDelegate,
// The URL being hosted.
GURL url_;
+#if defined(TOOLKIT_VIEWS)
+ // A popup view that is anchored to and owned by this ExtensionHost. However,
+ // the popup contains its own separate ExtensionHost
+ ExtensionPopup* child_popup_;
+#endif
+
NotificationRegistrar registrar_;
scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
- // Only EXTENSION_TOOLSTRIP and EXTENSION_BACKGROUND_PAGE are used here,
- // others are not hostd by ExtensionHost.
+ // Only EXTENSION_TOOLSTRIP, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE
+ // are used here, others are not hosted by ExtensionHost.
ViewType::Type extension_host_type_;
DISALLOW_COPY_AND_ASSIGN(ExtensionHost);
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
new file mode 100644
index 0000000..3059079
--- /dev/null
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2009 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 "chrome/browser/extensions/extension_popup_api.h"
+
+#include "base/gfx/point.h"
+#include "base/json/json_writer.h"
+#include "base/string_util.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/profile.h"
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/extensions/extension_popup.h"
+#include "views/view.h"
+#endif
+
+namespace extension_popup_module_events {
+
+const char kOnPopupClosed[] = "experimental.popup.onClosed.%d";
+
+} // namespace extension_popup_module_events
+
+namespace {
+
+// Errors.
+const char kBadAnchorArgument[] = "Invalid anchor argument.";
+const char kInvalidURLError[] = "Invalid URL.";
+
+// Keys.
+const wchar_t kUrlKey[] = L"url";
+const wchar_t kWidthKey[] = L"width";
+const wchar_t kHeightKey[] = L"height";
+const wchar_t kTopKey[] = L"top";
+const wchar_t kLeftKey[] = L"left";
+
+}; // namespace
+
+PopupShowFunction::PopupShowFunction()
+#if defined (TOOLKIT_VIEWS)
+ : popup_(NULL)
+#endif
+{}
+
+void PopupShowFunction::Run() {
+#if defined(TOOLKIT_VIEWS)
+ if (!RunImpl()) {
+ SendResponse(false);
+ } else {
+ // If the contents of the popup are already available, then immediately
+ // send the response. Otherwise wait for the EXTENSION_POPUP_VIEW_READY
+ // notification.
+ if (popup_->host() && popup_->host()->document_element_available()) {
+ SendResponse(true);
+ } else {
+ AddRef();
+ registrar_.Add(this, NotificationType::EXTENSION_POPUP_VIEW_READY,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
+ NotificationService::AllSources());
+ }
+ }
+#else
+ SendResponse(false);
+#endif
+}
+
+bool PopupShowFunction::RunImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST));
+ const ListValue* args = static_cast<const ListValue*>(args_);
+
+ DictionaryValue* popup_info = NULL;
+ EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(0, &popup_info));
+
+ std::string url_string;
+ EXTENSION_FUNCTION_VALIDATE(popup_info->GetString(kUrlKey,
+ &url_string));
+
+ DictionaryValue* dom_anchor = NULL;
+ EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &dom_anchor));
+
+ int dom_top, dom_left;
+ EXTENSION_FUNCTION_VALIDATE(dom_anchor->GetInteger(kTopKey,
+ &dom_top));
+ EXTENSION_FUNCTION_VALIDATE(dom_anchor->GetInteger(kLeftKey,
+ &dom_left));
+
+ int dom_width, dom_height;
+ EXTENSION_FUNCTION_VALIDATE(dom_anchor->GetInteger(kWidthKey,
+ &dom_width));
+ EXTENSION_FUNCTION_VALIDATE(dom_anchor->GetInteger(kHeightKey,
+ &dom_height));
+ EXTENSION_FUNCTION_VALIDATE(dom_top >= 0 && dom_left >= 0 &&
+ dom_width >= 0 && dom_height >= 0);
+
+ GURL url = dispatcher()->url().Resolve(url_string);
+ if (!url.is_valid()) {
+ error_ = kInvalidURLError;
+ return false;
+ }
+
+ // Disallow non-extension requests, or requests outside of the requesting
+ // extension view's extension.
+ const std::string& extension_id = url.host();
+ if (extension_id != dispatcher()->GetExtension()->id() ||
+ !url.SchemeIs("chrome-extension")) {
+ error_ = kInvalidURLError;
+ return false;
+ }
+
+#if defined(TOOLKIT_VIEWS)
+ views::View* extension_view = dispatcher()->GetExtensionHost()->view();
+ gfx::Point origin(dom_left, dom_top);
+ views::View::ConvertPointToScreen(extension_view, &origin);
+ gfx::Rect rect(origin.x(), origin.y(), dom_width, dom_height);
+
+ popup_ = ExtensionPopup::Show(url, dispatcher()->GetBrowser(), rect,
+ BubbleBorder::BOTTOM_LEFT);
+
+ dispatcher()->GetExtensionHost()->set_child_popup(popup_);
+ popup_->set_delegate(dispatcher()->GetExtensionHost());
+#endif
+ return true;
+}
+
+void PopupShowFunction::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+#if defined(TOOLKIT_VIEWS)
+ DCHECK(type == NotificationType::EXTENSION_POPUP_VIEW_READY ||
+ type == NotificationType::EXTENSION_HOST_DESTROYED);
+ DCHECK(popup_ != NULL);
+
+ if (popup_ && type == NotificationType::EXTENSION_POPUP_VIEW_READY &&
+ Details<ExtensionHost>(popup_->host()) == details) {
+ SendResponse(true);
+ Release(); // Balanced in Run().
+ } else if (popup_ && type == NotificationType::EXTENSION_HOST_DESTROYED &&
+ Details<ExtensionHost>(popup_->host()) == details) {
+ // If the host was destroyed, then report failure, and release the remaining
+ // reference.
+ SendResponse(false);
+ Release(); // Balanced in Run().
+ }
+#endif
+}
+
+// static
+void PopupEventRouter::OnPopupClosed(Profile* profile,
+ int routing_id) {
+ std::string full_event_name = StringPrintf(
+ extension_popup_module_events::kOnPopupClosed,
+ routing_id);
+
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ full_event_name,
+ base::JSONWriter::kEmptyArray);
+}
diff --git a/chrome/browser/extensions/extension_popup_api.h b/chrome/browser/extensions/extension_popup_api.h
new file mode 100644
index 0000000..96d6d53
--- /dev/null
+++ b/chrome/browser/extensions/extension_popup_api.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_API_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_API_H_
+
+#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/notification_registrar.h"
+
+class Profile;
+class ExtensionPopup;
+
+// This extension function shows a pop-up extension view. It is asynchronous
+// because the callback must be invoked only after the associated render
+// process/view has been created and fully initialized.
+class PopupShowFunction : public AsyncExtensionFunction,
+ public NotificationObserver {
+ public:
+ PopupShowFunction();
+
+ virtual void Run();
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.popup.show")
+
+ private:
+ // NotificationObserver methods.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+ NotificationRegistrar registrar_;
+
+#if defined(TOOLKIT_VIEWS)
+ // The pop-up view created by this function, saved for access during
+ // event notification. The pop-up is not owned by the PopupShowFunction
+ // instance.
+ ExtensionPopup* popup_;
+#endif
+};
+
+// Event router class for events related to the chrome.popup.* set of APIs.
+class PopupEventRouter {
+ public:
+ static void OnPopupClosed(Profile* profile,
+ int routing_id);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PopupEventRouter);
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_API_H_
diff --git a/chrome/browser/extensions/extension_popup_apitest.cc b/chrome/browser/extensions/extension_popup_apitest.cc
new file mode 100644
index 0000000..cfd8404
--- /dev/null
+++ b/chrome/browser/extensions/extension_popup_apitest.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2009 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 "base/command_line.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/common/chrome_switches.h"
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Popup) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ ASSERT_TRUE(RunExtensionTest("popup_api")) << message_;
+}