summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_popup_api.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/extension_popup_api.cc')
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc555
1 files changed, 0 insertions, 555 deletions
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
deleted file mode 100644
index 0c3acb2..0000000
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ /dev/null
@@ -1,555 +0,0 @@
-// Copyright (c) 2011 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 <string>
-
-#include "base/json/json_writer.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_web_ui.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_view_host_delegate.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/window_sizer.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/common/url_constants.h"
-#include "ui/gfx/point.h"
-
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/ui/views/bubble_border.h"
-#include "chrome/browser/ui/views/extensions/extension_popup.h"
-#include "views/view.h"
-#include "views/focus/focus_manager.h"
-#endif // TOOLKIT_VIEWS
-
-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.";
-const char kNotAnExtension[] = "Not an extension view.";
-const char kPopupsDisallowed[] =
- "Popups are only supported from tab-contents views.";
-
-// Keys.
-const char kWidthKey[] = "width";
-const char kHeightKey[] = "height";
-const char kTopKey[] = "top";
-const char kLeftKey[] = "left";
-const char kGiveFocusKey[] = "giveFocus";
-const char kDomAnchorKey[] = "domAnchor";
-const char kBorderStyleKey[] = "borderStyle";
-const char kMaxSizeKey[] = "maxSize";
-
-// chrome enumeration values
-const char kRectangleChrome[] = "rectangle";
-
-#if defined(TOOLKIT_VIEWS)
-// Returns an updated arrow location, conditioned on the type of intersection
-// between the popup window, and the screen. |location| is the current position
-// of the arrow on the popup. |intersection| is the rect representing the
-// intersection between the popup view and its working screen. |popup_rect|
-// is the rect of the popup window in screen space coordinates.
-// The returned location will be horizontally or vertically inverted based on
-// if the popup has been clipped horizontally or vertically.
-BubbleBorder::ArrowLocation ToggleArrowLocation(
- BubbleBorder::ArrowLocation location, const gfx::Rect& intersection,
- const gfx::Rect& popup_rect) {
- // If the popup has been clipped horizontally, flip the right-left position
- // of the arrow.
- if (intersection.right() != popup_rect.right() ||
- intersection.x() != popup_rect.x()) {
- location = BubbleBorder::horizontal_mirror(location);
- }
-
- // If the popup has been clipped vertically, flip the bottom-top position
- // of the arrow.
- if (intersection.y() != popup_rect.y() ||
- intersection.bottom() != popup_rect.bottom()) {
- location = BubbleBorder::vertical_mirror(location);
- }
-
- return location;
-}
-#endif // TOOLKIT_VIEWS
-
-}; // namespace
-
-#if defined(TOOLKIT_VIEWS)
-// ExtensionPopupHost objects implement the environment necessary to host
-// an ExtensionPopup views for the popup api. Its main job is to handle
-// its lifetime and to fire the popup-closed event when the popup is closed.
-// Because the close-on-focus-lost behavior is different from page action
-// and browser action, it also manages its own focus change listening. The
-// difference in close-on-focus-lost is that in the page action and browser
-// action cases, the popup closes when the focus leaves the popup or any of its
-// children. In this case, the popup closes when the focus leaves the popups
-// containing view or any of *its* children.
-class ExtensionPopupHost : public ExtensionPopup::Observer,
- public views::WidgetFocusChangeListener,
- public base::RefCounted<ExtensionPopupHost>,
- public NotificationObserver {
- public:
- // Pass |max_popup_size| to specify the maximal size to which the popup
- // will expand. A width or height of 0 will result in the popup making use
- // of the default max width or height, respectively: ExtensionPopup:kMaxWidth,
- // and ExtensionPopup::kMaxHeight.
- explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher,
- const gfx::Size& max_popup_size)
- : dispatcher_(dispatcher), popup_(NULL), max_popup_size_(max_popup_size) {
- AddRef(); // Balanced in DispatchPopupClosedEvent().
- views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this);
- }
-
- ~ExtensionPopupHost() {
- views::FocusManager::GetWidgetFocusManager()->
- RemoveFocusChangeListener(this);
- }
-
- void set_popup(ExtensionPopup* popup) {
- popup_ = popup;
-
- // Now that a popup has been assigned, listen for subsequent popups being
- // created in the same extension - we want to disallow more than one
- // concurrently displayed popup windows.
- registrar_.Add(
- this,
- NotificationType::EXTENSION_HOST_CREATED,
- Source<ExtensionProcessManager>(
- dispatcher_->profile()->GetExtensionProcessManager()));
-
- registrar_.Add(
- this,
- NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
- Source<RenderViewHost>(dispatcher_->render_view_host()));
-
- registrar_.Add(
- this,
- NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
- Source<Profile>(dispatcher_->profile()));
- }
-
- // Overridden from ExtensionPopup::Observer
- virtual void ExtensionPopupIsClosing(ExtensionPopup* popup) {
- // Unregister the automation resource routing registered upon host
- // creation.
- AutomationResourceRoutingDelegate* router =
- GetRoutingFromDispatcher(dispatcher_);
- if (router)
- router->UnregisterRenderViewHost(popup_->host()->render_view_host());
- }
-
- virtual void ExtensionPopupClosed(void* popup_token) {
- if (popup_ == popup_token) {
- popup_ = NULL;
- DispatchPopupClosedEvent();
- }
- }
-
- virtual void ExtensionHostCreated(ExtensionHost* host) {
- // Pop-up views should share the same automation routing configuration as
- // their hosting views, so register the RenderViewHost of the pop-up with
- // the AutomationResourceRoutingDelegate interface of the dispatcher.
- AutomationResourceRoutingDelegate* router =
- GetRoutingFromDispatcher(dispatcher_);
- if (router)
- router->RegisterRenderViewHost(host->render_view_host());
-
- // Extension hosts created for popup contents exist in the same tab
- // contents as the ExtensionFunctionDispatcher that requested the popup.
- // For example, '_blank' link navigation should be routed through the tab
- // contents that requested the popup.
- if (dispatcher_ && dispatcher_->delegate()) {
- host->set_associated_tab_contents(
- dispatcher_->delegate()->associated_tab_contents());
- }
- }
-
- virtual void ExtensionPopupCreated(ExtensionPopup* popup) {
- // The popup has been created, but not yet displayed, so install the max
- // size overrides before the first positioning.
- if (max_popup_size_.width())
- popup->set_max_width(max_popup_size_.width());
-
- if (max_popup_size_.height())
- popup->set_max_height(max_popup_size_.height());
- }
-
- virtual void ExtensionPopupResized(ExtensionPopup* popup) {
- // Reposition the location of the arrow on the popup so that the popup
- // better fits on the working monitor.
- gfx::Rect popup_rect = popup->GetOuterBounds();
- if (popup_rect.IsEmpty())
- return;
-
- scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
- WindowSizer::CreateDefaultMonitorInfoProvider());
- gfx::Rect monitor_bounds(
- monitor_provider->GetMonitorWorkAreaMatching(popup_rect));
- gfx::Rect intersection = monitor_bounds.Intersect(popup_rect);
-
- // If the popup is totally out of the bounds of the monitor, then toggling
- // the arrow location will not result in an un-clipped window.
- if (intersection.IsEmpty())
- return;
-
- if (!intersection.Equals(popup_rect)) {
- // The popup was clipped by the monitor. Toggle the arrow position
- // to see if that improves visibility. Note: The assignment and
- // re-assignment of the arrow-position will not trigger an intermittent
- // display.
- BubbleBorder::ArrowLocation previous_location = popup->arrow_position();
- BubbleBorder::ArrowLocation flipped_location = ToggleArrowLocation(
- previous_location, intersection, popup_rect);
- popup->SetArrowPosition(flipped_location);
-
- // Double check that toggling the position actually improved the
- // situation - the popup will be contained entirely in its working monitor
- // bounds.
- gfx::Rect flipped_bounds = popup->GetOuterBounds();
- gfx::Rect updated_monitor_bounds =
- monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds);
- if (!updated_monitor_bounds.Contains(flipped_bounds))
- popup->SetArrowPosition(previous_location);
- }
- }
-
- // Overridden from views::WidgetFocusChangeListener
- virtual void NativeFocusWillChange(gfx::NativeView focused_before,
- gfx::NativeView focused_now) {
- // If the popup doesn't exist, then do nothing.
- if (!popup_)
- return;
-
- // If no view is to be focused, then Chrome was deactivated, so hide the
- // popup.
- if (focused_now) {
- // On XP, the focus change handler may be invoked when the delegate has
- // already been revoked.
- // TODO(twiz@chromium.org): Resolve the trigger of this behaviour.
- if (!dispatcher_ || !dispatcher_->delegate())
- return;
-
- gfx::NativeView host_view =
- dispatcher_->delegate()->GetNativeViewOfHost();
-
- // If the widget hosting the popup contains the newly focused view, then
- // don't dismiss the pop-up.
- ExtensionView* view = popup_->host()->view();
- if (view) {
- views::Widget* popup_root_widget = view->GetWidget();
- if (popup_root_widget &&
- popup_root_widget->ContainsNativeView(focused_now))
- return;
- }
-
- // If the widget or RenderWidgetHostView hosting the extension that
- // launched the pop-up is receiving focus, then don't dismiss the popup.
- views::Widget* host_widget =
- views::Widget::GetWidgetFromNativeView(host_view);
- if (host_widget && host_widget->ContainsNativeView(focused_now))
- return;
-
- RenderWidgetHostView* render_host_view =
- RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
- host_view);
- if (render_host_view &&
- render_host_view->ContainsNativeView(focused_now))
- return;
- }
-
- // We are careful here to let the current event loop unwind before
- // causing the popup to be closed.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(popup_,
- &ExtensionPopup::Close));
- }
-
- // Overridden from NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (NotificationType::EXTENSION_HOST_CREATED == type) {
- Details<ExtensionHost> details_host(details);
- // Disallow multiple pop-ups from the same extension, by closing
- // the presently opened popup during construction of any new popups.
- if (ViewType::EXTENSION_POPUP == details_host->GetRenderViewType() &&
- popup_->host()->extension() == details_host->extension() &&
- Details<ExtensionHost>(popup_->host()) != details) {
- popup_->Close();
- }
- } else if (NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW ==
- type) {
- if (Source<RenderViewHost>(dispatcher_->render_view_host()) == source) {
- // If the parent render view is about to be closed, signal closure
- // of the popup.
- popup_->Close();
- }
- } else if (NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED ==
- type) {
- // Popups should not outlive the dispatchers that launched them.
- // Normally, long-lived popups will be dismissed in response to the
- // RENDER_VIEW_WILL_CLOSE_BY_RENDER_VIEW_HOST message. Unfortunately,
- // if the hosting view invokes window.close(), there is no communication
- // back to the browser until the entire view has been torn down, at which
- // time the dispatcher will be invoked.
- // Note: The onClosed event will not be fired, but because the hosting
- // view has already been torn down, it is already too late to process it.
- // TODO(twiz): Add a communication path between the renderer and browser
- // for RenderView closure notifications initiatied within the renderer.
- if (Details<ExtensionFunctionDispatcher>(dispatcher_) == details) {
- dispatcher_ = NULL;
- popup_->Close();
- }
- }
- }
-
- private:
- // Returns the AutomationResourceRoutingDelegate interface for |dispatcher|.
- static AutomationResourceRoutingDelegate*
- GetRoutingFromDispatcher(ExtensionFunctionDispatcher* dispatcher) {
- if (!dispatcher)
- return NULL;
-
- RenderViewHost* render_view_host = dispatcher->render_view_host();
- RenderViewHostDelegate* delegate =
- render_view_host ? render_view_host->delegate() : NULL;
-
- return delegate ? delegate->GetAutomationResourceRoutingDelegate() : NULL;
- }
-
- void DispatchPopupClosedEvent() {
- if (dispatcher_) {
- PopupEventRouter::OnPopupClosed(
- dispatcher_->profile(),
- dispatcher_->render_view_host()->routing_id());
- dispatcher_ = NULL;
- }
- Release(); // Balanced in ctor.
- }
-
- // A pointer to the dispatcher that handled the request that opened this
- // popup view.
- ExtensionFunctionDispatcher* dispatcher_;
-
- // A pointer to the popup.
- ExtensionPopup* popup_;
-
- // The maximal size to which the popup is permitted to expand.
- gfx::Size max_popup_size_;
-
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost);
-};
-#endif // TOOLKIT_VIEWS
-
-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() {
- // Popups may only be displayed from TAB_CONTENTS and EXTENSION_INFOBAR.
- ViewType::Type view_type =
- dispatcher()->render_view_host()->delegate()->GetRenderViewType();
- if (ViewType::TAB_CONTENTS != view_type &&
- ViewType::EXTENSION_INFOBAR != view_type) {
- error_ = kPopupsDisallowed;
- return false;
- }
-
- std::string url_string;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url_string));
-
- DictionaryValue* show_details = NULL;
- EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &show_details));
-
- DictionaryValue* dom_anchor = NULL;
- EXTENSION_FUNCTION_VALIDATE(show_details->GetDictionary(kDomAnchorKey,
- &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);
-
- // The default behaviour is to give the focus to the pop-up window.
- bool give_focus = true;
- if (show_details->HasKey(kGiveFocusKey)) {
- EXTENSION_FUNCTION_VALIDATE(show_details->GetBoolean(kGiveFocusKey,
- &give_focus));
- }
-
- int max_width = 0;
- int max_height = 0;
- if (show_details->HasKey(kMaxSizeKey)) {
- DictionaryValue* max_size = NULL;
- EXTENSION_FUNCTION_VALIDATE(show_details->GetDictionary(kMaxSizeKey,
- &max_size));
-
- if (max_size->HasKey(kWidthKey))
- EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kWidthKey, &max_width));
-
- if (max_size->HasKey(kHeightKey))
- EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kHeightKey,
- &max_height));
- }
-
-#if defined(TOOLKIT_VIEWS)
- // The default behaviour is to provide the bubble-chrome to the popup.
- ExtensionPopup::PopupChrome chrome = ExtensionPopup::BUBBLE_CHROME;
- if (show_details->HasKey(kBorderStyleKey)) {
- std::string chrome_string;
- EXTENSION_FUNCTION_VALIDATE(show_details->GetString(kBorderStyleKey,
- &chrome_string));
- if (chrome_string == kRectangleChrome)
- chrome = ExtensionPopup::RECTANGLE_CHROME;
- }
-#endif
-
- 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 != GetExtension()->id() ||
- !url.SchemeIs(chrome::kExtensionScheme)) {
- error_ = kInvalidURLError;
- return false;
- }
-
- gfx::Point origin(dom_left, dom_top);
- if (!dispatcher()->render_view_host()->view()) {
- error_ = kNotAnExtension;
- return false;
- }
-
- gfx::Rect content_bounds =
- dispatcher()->render_view_host()->view()->GetViewBounds();
- origin.Offset(content_bounds.x(), content_bounds.y());
- gfx::Rect rect(origin.x(), origin.y(), dom_width, dom_height);
-
- // Get the correct native window to pass to ExtensionPopup.
- // ExtensionFunctionDispatcher::Delegate may provide a custom implementation
- // of this.
- gfx::NativeWindow window =
- dispatcher()->delegate()->GetCustomFrameNativeWindow();
- if (!window)
- window = GetCurrentBrowser()->window()->GetNativeHandle();
-
-#if defined(TOOLKIT_VIEWS)
- BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT;
-
- // ExtensionPopupHost manages it's own lifetime.
- ExtensionPopupHost* popup_host =
- new ExtensionPopupHost(dispatcher(), gfx::Size(max_width, max_height));
- popup_ = ExtensionPopup::Show(url,
- GetCurrentBrowser(),
- dispatcher()->profile(),
- window,
- rect,
- arrow_location,
- give_focus,
- false, // inspect_with_devtools
- chrome,
- popup_host); // ExtensionPopup::Observer
-
- // popup_host will handle focus change listening and close the popup when
- // focus leaves the containing views hierarchy.
- popup_->set_close_on_lost_focus(false);
- popup_host->set_popup(popup_);
-#endif // defined(TOOLKIT_VIEWS)
-
- 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);
-
- // Wait for notification that the popup view is ready (and onload has been
- // called), before completing the API call.
- 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 // defined(TOOLKIT_VIEWS)
-}
-
-// static
-void PopupEventRouter::OnPopupClosed(Profile* profile,
- int routing_id) {
- std::string full_event_name = base::StringPrintf(
- extension_popup_module_events::kOnPopupClosed,
- routing_id);
-
- profile->GetExtensionEventRouter()->DispatchEventToRenderers(
- full_event_name, base::JSONWriter::kEmptyArray, profile, GURL());
-}