diff options
author | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-14 22:38:26 +0000 |
---|---|---|
committer | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-14 22:38:26 +0000 |
commit | 92b34f71dff1fdd493194acde42a225aecf4cc2f (patch) | |
tree | d9b6ccf88c35f6a1867e5233c13aa603e46e4c29 /chrome | |
parent | 8eb93ed662dcbc6c4414b9524099b80760831d48 (diff) | |
download | chromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.zip chromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.tar.gz chromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.tar.bz2 |
Add ShellWindowContents and AppWindow/Panel implementations.
This CL:
* Adds ShellWindowRenderInterface to abstract creating and observing
web contents and passing messages to the extensions system
* Moves related ShellWindow to AppWindowRenderInterface
* Adds AshPanelRenderInterface for v1 ash panel specific impl
* Hooks up chrome.windows.create(type = panel) to use Ash Panels.
BUG=160645
Review URL: https://codereview.chromium.org/12209028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182559 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
17 files changed, 808 insertions, 250 deletions
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc new file mode 100644 index 0000000..cb21550 --- /dev/null +++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc @@ -0,0 +1,221 @@ +// Copyright 2013 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/api/tabs/ash_panel_contents.h" + +#include "base/values.h" +#include "chrome/browser/extensions/api/tabs/tabs_constants.h" +#include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" +#include "chrome/browser/extensions/api/tabs/windows_event_router.h" +#include "chrome/browser/extensions/extension_tab_util.h" +#include "chrome/browser/extensions/window_controller_list.h" +#include "chrome/browser/ui/extensions/native_app_window.h" +#include "chrome/browser/ui/extensions/shell_window.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_messages.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" + +// AshPanelWindowController ---------------------------------------------------- + +// This class enables a ShellWindow instance to be accessed (to a limited +// extent) via the chrome.windows and chrome.tabs API. This is a temporary +// bridge to support instantiating ShellWindows from v1 apps, specifically +// for creating Panels in Ash. See crbug.com/160645. +class AshPanelWindowController : public extensions::WindowController { + public: + AshPanelWindowController(ShellWindow* window, Profile* profile); + virtual ~AshPanelWindowController(); + + void NativeWindowChanged(); + + // Overridden from extensions::WindowController. + virtual int GetWindowId() const OVERRIDE; + virtual std::string GetWindowTypeText() const OVERRIDE; + virtual base::DictionaryValue* CreateWindowValueWithTabs( + const extensions::Extension* extension) const OVERRIDE; + virtual base::DictionaryValue* CreateTabValue( + const extensions::Extension* extension, int tab_index) const OVERRIDE; + virtual bool CanClose(Reason* reason) const OVERRIDE; + virtual void SetFullscreenMode(bool is_fullscreen, + const GURL& extension_url) const OVERRIDE; + virtual bool IsVisibleToExtension( + const extensions::Extension* extension) const OVERRIDE; + + private: + ShellWindow* shell_window_; // Weak pointer; this is owned by shell_window_ + bool is_active_; + + DISALLOW_COPY_AND_ASSIGN(AshPanelWindowController); +}; + +AshPanelWindowController::AshPanelWindowController( + ShellWindow* shell_window, Profile* profile) + : extensions::WindowController(shell_window->GetBaseWindow(), profile), + shell_window_(shell_window), + is_active_(shell_window->GetBaseWindow()->IsActive()) { + extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this); +} + +AshPanelWindowController::~AshPanelWindowController() { + extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this); +} + +int AshPanelWindowController::GetWindowId() const { + return static_cast<int>(shell_window_->session_id().id()); +} + +std::string AshPanelWindowController::GetWindowTypeText() const { + return extensions::tabs_constants::kWindowTypeValuePanel; +} + +base::DictionaryValue* AshPanelWindowController::CreateWindowValueWithTabs( + const extensions::Extension* extension) const { + DCHECK(IsVisibleToExtension(extension)); + base::DictionaryValue* result = CreateWindowValue(); + DictionaryValue* tab_value = CreateTabValue(extension, 0); + if (tab_value) { + base::ListValue* tab_list = new ListValue(); + tab_list->Append(tab_value); + result->Set(extensions::tabs_constants::kTabsKey, tab_list); + } + return result; +} + +base::DictionaryValue* AshPanelWindowController::CreateTabValue( + const extensions::Extension* extension, int tab_index) const { + if ((extension && !IsVisibleToExtension(extension)) || + (tab_index > 0)) { + return NULL; + } + content::WebContents* web_contents = shell_window_->web_contents(); + if (!web_contents) + return NULL; + + DictionaryValue* tab_value = new DictionaryValue(); + tab_value->SetInteger(extensions::tabs_constants::kIdKey, + SessionID::IdForTab(web_contents)); + tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0); + const int window_id = GetWindowId(); + tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id); + tab_value->SetString( + extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec()); + tab_value->SetString( + extensions::tabs_constants::kStatusKey, + ExtensionTabUtil::GetTabStatusText(web_contents->IsLoading())); + tab_value->SetBoolean( + extensions::tabs_constants::kActiveKey, + shell_window_->GetBaseWindow()->IsActive()); + // ShellWindow only ever contains one tab, so that tab is always effectively + // selcted and highlighted (for purposes of the chrome.tabs API). + tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id); + tab_value->SetInteger(extensions::tabs_constants::kIdKey, window_id); + tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true); + tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true); + tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false); + tab_value->SetString( + extensions::tabs_constants::kTitleKey, web_contents->GetTitle()); + tab_value->SetBoolean( + extensions::tabs_constants::kIncognitoKey, + web_contents->GetBrowserContext()->IsOffTheRecord()); + return tab_value; +} + +bool AshPanelWindowController::CanClose(Reason* reason) const { + return true; +} + +void AshPanelWindowController::SetFullscreenMode( + bool is_fullscreen, const GURL& extension_url) const { + // Do nothing. Panels cannot be fullscreen. +} + +bool AshPanelWindowController::IsVisibleToExtension( + const extensions::Extension* extension) const { + return shell_window_->extension() && + extension->id() == shell_window_->extension()->id(); +} + +void AshPanelWindowController::NativeWindowChanged() { + bool active = shell_window_->GetBaseWindow()->IsActive(); + if (active == is_active_) + return; + is_active_ = active; + // Let the extension API know that the active window changed. + extensions::TabsWindowsAPI* tabs_windows_api = + extensions::TabsWindowsAPI::Get(profile()); + if (!tabs_windows_api) + return; + tabs_windows_api->windows_event_router()->OnActiveWindowChanged( + active ? this : NULL); +} + +// AshPanelContents ----------------------------------------------------- + +AshPanelContents::AshPanelContents(ShellWindow* host) + : host_(host) { +} + +AshPanelContents::~AshPanelContents() { +} + +void AshPanelContents::Initialize(Profile* profile, const GURL& url) { + url_ = url; + + extension_function_dispatcher_.reset( + new ExtensionFunctionDispatcher(profile, this)); + + web_contents_.reset(content::WebContents::Create( + content::WebContents::CreateParams( + profile, content::SiteInstance::CreateForURL(profile, url_)))); + + content::WebContentsObserver::Observe(web_contents_.get()); +} + +void AshPanelContents::LoadContents(int32 creator_process_id) { + // This must be created after the native window has been created. + window_controller_.reset( + new AshPanelWindowController(host_, host_->profile())); + + web_contents_->GetController().LoadURL( + url_, content::Referrer(), content::PAGE_TRANSITION_LINK, + std::string()); +} + +void AshPanelContents::NativeWindowChanged(NativeAppWindow* native_app_window) { + if (window_controller_) + window_controller_->NativeWindowChanged(); +} + +void AshPanelContents::NativeWindowClosed() { +} + +content::WebContents* AshPanelContents::GetWebContents() const { + return web_contents_.get(); +} + +bool AshPanelContents::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +extensions::WindowController* +AshPanelContents::GetExtensionWindowController() const { + return window_controller_.get(); +} + +content::WebContents* AshPanelContents::GetAssociatedWebContents() const { + return web_contents_.get(); +} + +void AshPanelContents::OnRequest( + const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_->Dispatch( + params, web_contents_->GetRenderViewHost()); +} diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.h b/chrome/browser/extensions/api/tabs/ash_panel_contents.h new file mode 100644 index 0000000..871139b --- /dev/null +++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.h @@ -0,0 +1,66 @@ +// Copyright 2013 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_API_TABS_ASH_PANEL_CONTENTS_H_ +#define CHROME_BROWSER_EXTENSIONS_API_TABS_ASH_PANEL_CONTENTS_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" +#include "chrome/browser/ui/extensions/shell_window.h" +#include "content/public/browser/web_contents_observer.h" + +class AshPanelWindowController; +class GURL; + +namespace content { +class RenderViewHost; +} + +namespace extensions { +struct DraggableRegion; +} + +// ShellWindowContents class specific to panel windows created by v1 +// extenstions. This class maintains a WebContents instance and observes it for +// the purpose of passing messages to the extensions system. It also creates +// an extensions::WindowController instance for interfacing with the v1 +// extensions API. +class AshPanelContents : public ShellWindowContents, + public content::WebContentsObserver, + public ExtensionFunctionDispatcher::Delegate { + public: + explicit AshPanelContents(ShellWindow* host); + virtual ~AshPanelContents(); + + // ShellWindowContents + virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE; + virtual void LoadContents(int32 creator_process_id) OVERRIDE; + virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE; + virtual void NativeWindowClosed() OVERRIDE; + virtual content::WebContents* GetWebContents() const OVERRIDE; + + // ExtensionFunctionDispatcher::Delegate + virtual extensions::WindowController* GetExtensionWindowController() const + OVERRIDE; + virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE; + + private: + // content::WebContentsObserver + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + void OnRequest(const ExtensionHostMsg_Request_Params& params); + + ShellWindow* host_; + GURL url_; + scoped_ptr<content::WebContents> web_contents_; + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + scoped_ptr<AshPanelWindowController> window_controller_; + + DISALLOW_COPY_AND_ASSIGN(AshPanelContents); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_API_TABS_ASH_PANEL_CONTENTS_H_ diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index b227e6d..44e732f 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc @@ -88,6 +88,12 @@ #include "win8/util/win8_util.h" #endif // OS_WIN +#if defined(USE_ASH) +#include "ash/ash_switches.h" +#include "chrome/browser/extensions/api/tabs/ash_panel_contents.h" +#include "chrome/browser/extensions/shell_window_registry.h" +#endif + namespace Get = extensions::api::windows::Get; namespace GetAll = extensions::api::windows::GetAll; namespace GetCurrent = extensions::api::windows::GetCurrent; @@ -516,8 +522,8 @@ bool WindowsCreateFunction::RunImpl() { #endif if (use_panels) { window_type = Browser::TYPE_PANEL; -#if !defined(OS_CHROMEOS) - // Non-ChromeOS has both docked and detached panel types. +#if !defined(USE_ASH) + // Non-Ash has both docked and detached panel types. if (type_str == keys::kWindowTypeValueDetachedPanel) panel_create_mode = PanelManager::CREATE_AS_DETACHED; #endif @@ -531,15 +537,8 @@ bool WindowsCreateFunction::RunImpl() { } // Initialize default window bounds according to window type. - // In ChromiumOS the default popup bounds is 0x0 which indicates default - // window sizes in PanelBrowserView. In other OSs use the same default - // bounds as windows. -#if !defined(OS_CHROMEOS) if (Browser::TYPE_TABBED == window_type || Browser::TYPE_POPUP == window_type) { -#else - if (Browser::TYPE_TABBED == window_type) { -#endif // Try to position the new browser relative to its originating // browser window. The call offsets the bounds by kWindowTilePixels // (defined in WindowSizer to be 10). @@ -594,8 +593,28 @@ bool WindowsCreateFunction::RunImpl() { } } -#if !defined(OS_CHROMEOS) if (window_type == Browser::TYPE_PANEL) { +#if defined(USE_ASH) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels) && + PanelManager::ShouldUsePanels(extension_id)) { + ShellWindow::CreateParams create_params; + create_params.window_type = ShellWindow::WINDOW_TYPE_PANEL; + create_params.bounds = window_bounds; + create_params.minimum_size = window_bounds.size(); + create_params.maximum_size = window_bounds.size(); + ShellWindow* shell_window = + new ShellWindow(window_profile, GetExtension()); + AshPanelContents* ash_panel_contents = new AshPanelContents(shell_window); + shell_window->Init(urls[0], ash_panel_contents, create_params); + SetResult(ash_panel_contents->GetExtensionWindowController()-> + CreateWindowValueWithTabs(GetExtension())); + // Add the panel to the shell window registry so that it shows up in + // the launcher and as an active render process. + extensions::ShellWindowRegistry::Get(window_profile)->AddShellWindow( + shell_window); + return true; + } +#else std::string title = web_app::GenerateApplicationNameFromExtensionId(extension_id); // Note: Panels ignore all but the first url provided. @@ -612,8 +631,8 @@ bool WindowsCreateFunction::RunImpl() { panel->extension_window_controller()->CreateWindowValueWithTabs( GetExtension())); return true; - } #endif + } // Create a new BrowserWindow. chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop(); diff --git a/chrome/browser/extensions/app_window_contents.cc b/chrome/browser/extensions/app_window_contents.cc new file mode 100644 index 0000000..88be3e6 --- /dev/null +++ b/chrome/browser/extensions/app_window_contents.cc @@ -0,0 +1,172 @@ +// Copyright 2013 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/app_window_contents.h" + +#include "chrome/browser/ui/extensions/native_app_window.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/api/app_window.h" +#include "chrome/common/extensions/extension_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_dispatcher_host.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/renderer_preferences.h" + +namespace app_window = extensions::api::app_window; + +AppWindowContents::AppWindowContents(ShellWindow* host) + : host_(host) { +} + +AppWindowContents::~AppWindowContents() { +} + +void AppWindowContents::Initialize(Profile* profile, const GURL& url) { + url_ = url; + + extension_function_dispatcher_.reset( + new ExtensionFunctionDispatcher(profile, this)); + + web_contents_.reset(content::WebContents::Create( + content::WebContents::CreateParams( + profile, content::SiteInstance::CreateForURL(profile, url_)))); + + content::WebContentsObserver::Observe(web_contents_.get()); + web_contents_->GetMutableRendererPrefs()-> + browser_handles_all_top_level_requests = true; + web_contents_->GetRenderViewHost()->SyncRendererPrefs(); +} + +void AppWindowContents::LoadContents(int32 creator_process_id) { + // If the new view is in the same process as the creator, block the created + // RVH from loading anything until the background page has had a chance to + // do any initialization it wants. If it's a different process, the new RVH + // shouldn't communicate with the background page anyway (e.g. sandboxed). + if (web_contents_->GetRenderViewHost()->GetProcess()->GetID() == + creator_process_id) { + SuspendRenderViewHost(web_contents_->GetRenderViewHost()); + } else { + VLOG(1) << "ShellWindow created in new process (" + << web_contents_->GetRenderViewHost()->GetProcess()->GetID() + << ") != creator (" << creator_process_id + << "). Routing disabled."; + } + + // TODO(jeremya): there's a bug where navigating a web contents to an + // extension URL causes it to create a new RVH and discard the old + // (perfectly usable) one. To work around this, we watch for a RVH_CHANGED + // message from the web contents (which will be sent during LoadURL) and + // suspend resource requests on the new RVH to ensure that we block the new + // RVH from loading anything. It should be okay to remove the + // NOTIFICATION_RVH_CHANGED registration once http://crbug.com/123007 is + // fixed. + registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, + content::Source<content::NavigationController>( + &web_contents()->GetController())); + web_contents_->GetController().LoadURL( + url_, content::Referrer(), content::PAGE_TRANSITION_LINK, + std::string()); + registrar_.RemoveAll(); +} + +void AppWindowContents::NativeWindowChanged( + NativeAppWindow* native_app_window) { + ListValue args; + DictionaryValue* dictionary = new DictionaryValue(); + args.Append(dictionary); + + gfx::Rect bounds = native_app_window->GetBounds(); + bounds.Inset(native_app_window->GetFrameInsets()); + app_window::Bounds update; + update.left.reset(new int(bounds.x())); + update.top.reset(new int(bounds.y())); + update.width.reset(new int(bounds.width())); + update.height.reset(new int(bounds.height())); + dictionary->Set("bounds", update.ToValue().release()); + dictionary->SetBoolean("minimized", native_app_window->IsMinimized()); + dictionary->SetBoolean("maximized", native_app_window->IsMaximized()); + + content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); + rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(), + host_->extension()->id(), + "updateAppWindowProperties", + args, + GURL(), + false)); + +} + +void AppWindowContents::NativeWindowClosed() { + content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); + rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID())); +} + +content::WebContents* AppWindowContents::GetWebContents() const { + return web_contents_.get(); +} + +void AppWindowContents::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: { + // TODO(jeremya): once http://crbug.com/123007 is fixed, we'll no longer + // need to suspend resource requests here (the call in the constructor + // should be enough). + content::Details<std::pair<content::RenderViewHost*, + content::RenderViewHost*> > + host_details(details); + if (host_details->first) + SuspendRenderViewHost(host_details->second); + break; + } + default: + NOTREACHED() << "Received unexpected notification"; + } +} + +bool AppWindowContents::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AppWindowContents, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_UpdateDraggableRegions, + UpdateDraggableRegions) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +extensions::WindowController* +AppWindowContents::GetExtensionWindowController() const { + return NULL; +} + +content::WebContents* AppWindowContents::GetAssociatedWebContents() const { + return web_contents_.get(); +} + +void AppWindowContents::OnRequest( + const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_->Dispatch( + params, web_contents_->GetRenderViewHost()); +} + +void AppWindowContents::UpdateDraggableRegions( + const std::vector<extensions::DraggableRegion>& regions) { + host_->UpdateDraggableRegions(regions); +} + +void AppWindowContents::SuspendRenderViewHost( + content::RenderViewHost* rvh) { + DCHECK(rvh); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&content::ResourceDispatcherHost::BlockRequestsForRoute, + base::Unretained(content::ResourceDispatcherHost::Get()), + rvh->GetProcess()->GetID(), rvh->GetRoutingID())); +} diff --git a/chrome/browser/extensions/app_window_contents.h b/chrome/browser/extensions/app_window_contents.h new file mode 100644 index 0000000..3cf2a32 --- /dev/null +++ b/chrome/browser/extensions/app_window_contents.h @@ -0,0 +1,73 @@ +// Copyright 2013 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_APP_WINDOW_CONTENTS_H_ +#define CHROME_BROWSER_EXTENSIONS_APP_WINDOW_CONTENTS_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" +#include "chrome/browser/ui/extensions/shell_window.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/web_contents_observer.h" + +class GURL; + +namespace content { +class RenderViewHost; +} + +namespace extensions { +struct DraggableRegion; +} + +// ShellWindowContents class specific to app windows. It maintains a +// WebContents instance and observes it for the purpose of passing +// messages to the extensions system. +class AppWindowContents : public ShellWindowContents, + public content::NotificationObserver, + public content::WebContentsObserver, + public ExtensionFunctionDispatcher::Delegate { + public: + explicit AppWindowContents(ShellWindow* host); + virtual ~AppWindowContents(); + + // ShellWindowContents + virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE; + virtual void LoadContents(int32 creator_process_id) OVERRIDE; + virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE; + virtual void NativeWindowClosed() OVERRIDE; + virtual content::WebContents* GetWebContents() const OVERRIDE; + + private: + // content::NotificationObserver + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // content::WebContentsObserver + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // ExtensionFunctionDispatcher::Delegate + virtual extensions::WindowController* GetExtensionWindowController() const + OVERRIDE; + virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE; + + void OnRequest(const ExtensionHostMsg_Request_Params& params); + void UpdateDraggableRegions( + const std::vector<extensions::DraggableRegion>& regions); + void SuspendRenderViewHost(content::RenderViewHost* rvh); + + ShellWindow* host_; // This class is owned by |host_| + GURL url_; + content::NotificationRegistrar registrar_; + scoped_ptr<content::WebContents> web_contents_; + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(AppWindowContents); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_APP_WINDOW_CONTENTS_H_ diff --git a/chrome/browser/extensions/browser_extension_window_controller.cc b/chrome/browser/extensions/browser_extension_window_controller.cc index 665c5ad..9e50e50 100644 --- a/chrome/browser/extensions/browser_extension_window_controller.cc +++ b/chrome/browser/extensions/browser_extension_window_controller.cc @@ -12,6 +12,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/extensions/extension.h" BrowserExtensionWindowController::BrowserExtensionWindowController( @@ -58,6 +59,14 @@ BrowserExtensionWindowController::CreateWindowValueWithTabs( return result; } +base::DictionaryValue* BrowserExtensionWindowController::CreateTabValue( + const extensions::Extension* extension, int tab_index) const { + TabStripModel* tab_strip = browser_->tab_strip_model(); + DictionaryValue* result = ExtensionTabUtil::CreateTabValue( + tab_strip->GetWebContentsAt(tab_index), tab_strip, tab_index); + return result; +} + bool BrowserExtensionWindowController::CanClose(Reason* reason) const { // Don't let an extension remove the window if the user is dragging tabs // in that window. diff --git a/chrome/browser/extensions/browser_extension_window_controller.h b/chrome/browser/extensions/browser_extension_window_controller.h index a1e220a..2dfb3d4 100644 --- a/chrome/browser/extensions/browser_extension_window_controller.h +++ b/chrome/browser/extensions/browser_extension_window_controller.h @@ -24,6 +24,8 @@ class BrowserExtensionWindowController : public extensions::WindowController { virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE; virtual base::DictionaryValue* CreateWindowValueWithTabs( const extensions::Extension* extension) const OVERRIDE; + virtual base::DictionaryValue* CreateTabValue( + const extensions::Extension* extension, int tab_index) const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const OVERRIDE; diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index 2ed787d..5e89316 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc @@ -5,8 +5,10 @@ #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" +#include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/extensions/window_controller.h" +#include "chrome/browser/extensions/window_controller_list.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_id.h" @@ -14,6 +16,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_iterator.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/extensions/extension.h" @@ -33,6 +36,25 @@ using content::WebContents; using extensions::APIPermission; using extensions::Extension; +namespace { + +extensions::WindowController* GetShellWindowController( + const WebContents* contents) { + Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); + extensions::ShellWindowRegistry* registry = + extensions::ShellWindowRegistry::Get(profile); + if (!registry) + return NULL; + ShellWindow* shell_window = + registry->GetShellWindowForRenderViewHost(contents->GetRenderViewHost()); + if (!shell_window) + return NULL; + return extensions::WindowControllerList::GetInstance()-> + FindWindowById(shell_window->session_id().id()); +} + +} // namespace + int ExtensionTabUtil::GetWindowId(const Browser* browser) { return browser->session_id().id(); } @@ -63,6 +85,13 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue( TabStripModel* tab_strip, int tab_index, const Extension* extension) { + // If we have a matching ShellWindow with a controller, get the tab value + // from its controller instead. + extensions::WindowController* controller = GetShellWindowController(contents); + if (controller && + (!extension || controller->IsVisibleToExtension(extension))) { + return controller->CreateTabValue(extension, tab_index); + } DictionaryValue *result = CreateTabValue(contents, tab_strip, tab_index); ScrubTabValueForExtension(contents, extension, result); return result; @@ -87,6 +116,12 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue( const WebContents* contents, TabStripModel* tab_strip, int tab_index) { + // If we have a matching ShellWindow with a controller, get the tab value + // from its controller instead. + extensions::WindowController* controller = GetShellWindowController(contents); + if (controller) + return controller->CreateTabValue(NULL, tab_index); + if (!tab_strip) ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index); diff --git a/chrome/browser/extensions/window_controller.h b/chrome/browser/extensions/window_controller.h index ec9f6e2..48a881e 100644 --- a/chrome/browser/extensions/window_controller.h +++ b/chrome/browser/extensions/window_controller.h @@ -60,6 +60,9 @@ class WindowController { virtual base::DictionaryValue* CreateWindowValueWithTabs( const extensions::Extension* extension) const = 0; + virtual base::DictionaryValue* CreateTabValue( + const extensions::Extension* extension, int tab_index) const = 0; + // Returns false if the window is in a state where closing the window is not // permitted and sets |reason| if not NULL. virtual bool CanClose(Reason* reason) const = 0; diff --git a/chrome/browser/extensions/window_controller_list.cc b/chrome/browser/extensions/window_controller_list.cc index 0dfdffa..257c680b 100644 --- a/chrome/browser/extensions/window_controller_list.cc +++ b/chrome/browser/extensions/window_controller_list.cc @@ -52,17 +52,24 @@ void WindowControllerList::RemoveObserver( observers_.RemoveObserver(observer); } -WindowController* WindowControllerList::FindWindowForFunctionById( - const UIThreadExtensionFunction* function, - int id) const { +WindowController* WindowControllerList::FindWindowById(int id) const { for (ControllerList::const_iterator iter = windows().begin(); iter != windows().end(); ++iter) { - if (function->CanOperateOnWindow(*iter) && (*iter)->GetWindowId() == id) + if ((*iter)->GetWindowId() == id) return *iter; } return NULL; } +WindowController* WindowControllerList::FindWindowForFunctionById( + const UIThreadExtensionFunction* function, + int id) const { + WindowController* controller = FindWindowById(id); + if (controller && function->CanOperateOnWindow(controller)) + return controller; + return NULL; +} + WindowController* WindowControllerList::CurrentWindowForFunction( const UIThreadExtensionFunction* function) const { WindowController* result = NULL; diff --git a/chrome/browser/extensions/window_controller_list.h b/chrome/browser/extensions/window_controller_list.h index a32baf6..4b9b934 100644 --- a/chrome/browser/extensions/window_controller_list.h +++ b/chrome/browser/extensions/window_controller_list.h @@ -33,6 +33,9 @@ class WindowControllerList { void AddObserver(WindowControllerListObserver* observer); void RemoveObserver(WindowControllerListObserver* observer); + // Returns a window matching |id|. + WindowController* FindWindowById(int id) const; + // Returns a window matching the context the function was invoked in. WindowController* FindWindowForFunctionById( const UIThreadExtensionFunction* function, diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc index cac1d4c..b448aee 100644 --- a/chrome/browser/extensions/window_open_apitest.cc +++ b/chrome/browser/extensions/window_open_apitest.cc @@ -26,6 +26,15 @@ #include "net/base/mock_host_resolver.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(USE_ASH) +#include "chrome/browser/extensions/shell_window_registry.h" +#endif + +#if defined(USE_ASH) && !defined(OS_WIN) +// TODO(stevenjb): Figure out the correct behavior for Ash + Win +#define USE_ASH_PANELS +#endif + using content::OpenURLParams; using content::Referrer; using content::WebContents; @@ -41,7 +50,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpen) { EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } -void WaitForTabsAndPopups(Browser* browser, +int GetPanelCount(Browser* browser) { +#if defined(USE_ASH_PANELS) + return static_cast<int>(extensions::ShellWindowRegistry::Get( + browser->profile())->shell_windows().size()); +#else + return PanelManager::GetInstance()->num_panels(); +#endif +} + +bool WaitForTabsAndPopups(Browser* browser, int num_tabs, int num_popups, int num_panels) { @@ -52,12 +70,12 @@ void WaitForTabsAndPopups(Browser* browser, ++num_tabs; size_t num_browsers = static_cast<size_t>(num_popups) + 1; - const base::TimeDelta kWaitTime = base::TimeDelta::FromSeconds(15); + const base::TimeDelta kWaitTime = base::TimeDelta::FromSeconds(10); base::TimeTicks end_time = base::TimeTicks::Now() + kWaitTime; while (base::TimeTicks::Now() < end_time) { if (chrome::GetBrowserCount(browser->profile()) == num_browsers && browser->tab_strip_model()->count() == num_tabs && - PanelManager::GetInstance()->num_panels() == num_panels) + GetPanelCount(browser) == num_panels) break; content::RunAllPendingInMessageLoop(); @@ -65,7 +83,7 @@ void WaitForTabsAndPopups(Browser* browser, EXPECT_EQ(num_browsers, chrome::GetBrowserCount(browser->profile())); EXPECT_EQ(num_tabs, browser->tab_strip_model()->count()); - EXPECT_EQ(num_panels, PanelManager::GetInstance()->num_panels()); + EXPECT_EQ(num_panels, GetPanelCount(browser)); int num_popups_seen = 0; for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) { @@ -73,10 +91,8 @@ void WaitForTabsAndPopups(Browser* browser, continue; // Check for TYPE_POPUP. -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) - // On Ash, panel windows open as popup windows. +#if defined(USE_ASH_PANELS) + // On Ash, panel windows may open as popup windows. EXPECT_TRUE((*iter)->is_type_popup() || (*iter)->is_type_panel()); #else EXPECT_TRUE((*iter)->is_type_popup()); @@ -84,6 +100,11 @@ void WaitForTabsAndPopups(Browser* browser, ++num_popups_seen; } EXPECT_EQ(num_popups, num_popups_seen); + + return ((num_browsers == chrome::GetBrowserCount(browser->profile())) && + (num_tabs == browser->tab_strip_model()->count()) && + (num_panels == GetPanelCount(browser)) && + (num_popups == num_popups_seen)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) { @@ -92,7 +113,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) { ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("window_open").AppendASCII("browser_is_app"))); - WaitForTabsAndPopups(browser(), 0, 2, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 0, 2, 0)); for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) { if (*iter == browser()) @@ -109,7 +130,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupDefault) { const int num_tabs = 1; const int num_popups = 0; - WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) { @@ -120,7 +141,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) { // On other systems this should open a new popup window. const int num_tabs = 0; const int num_popups = 1; - WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) { @@ -132,7 +153,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) { // On other systems this should open a new popup window. const int num_tabs = 0; const int num_popups = 1; - WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingExtension) { @@ -143,7 +164,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingExtension) { test_data_dir_.AppendASCII("window_open").AppendASCII("popup_blocking") .AppendASCII("extension"))); - WaitForTabsAndPopups(browser(), 5, 3, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 5, 3, 0)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingHostedApp) { @@ -178,7 +199,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingHostedApp) { open_popup, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_TYPED, false)); - WaitForTabsAndPopups(browser(), 3, 1, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 3, 1, 0)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowArgumentsOverflow) { @@ -205,9 +226,7 @@ class WindowOpenPanelTest : public ExtensionApiTest { } }; -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) +#if defined(USE_ASH_PANELS) // On Ash, this currently fails because we're currently opening new panel // windows as popup windows instead. #define MAYBE_WindowOpenPanel DISABLED_WindowOpenPanel @@ -218,9 +237,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanel) { ASSERT_TRUE(RunExtensionTest("window_open/panel")) << message_; } -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) +#if defined(USE_ASH_PANELS) // On Ash, this currently fails because we're currently opening new panel // windows as popup windows instead. #define MAYBE_WindowOpenPanelDetached DISABLED_WindowOpenPanelDetached @@ -233,12 +250,16 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanelDetached) { IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, CloseNonExtensionPanelsOnUninstall) { -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) +#if defined(USE_ASH_PANELS) // On Ash, new panel windows open as popup windows instead. - int num_popups = 4; - int num_panels = 0; + int num_popups, num_panels; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) { + num_popups = 2; + num_panels = 2; + } else { + num_popups = 4; + num_panels = 0; + } #else int num_popups = 2; int num_panels = 2; @@ -266,7 +287,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, // Two tabs. One in extension domain and one in non-extension domain. // Two popups - one in extension domain and one in non-extension domain. // Two panels - one in extension domain and one in non-extension domain. - WaitForTabsAndPopups(browser(), 2, num_popups, num_panels); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels)); // Wait on test messages to make sure the pages loaded. for (size_t i = 0; i < listeners.size(); ++i) @@ -276,16 +297,15 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, // Wait for the tabs and popups in non-extension domain to stay open. // Expect everything else, including panels, to close. -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) - // On Ash, new panel windows open as popup windows instead, so there are 2 - // extension domain popups that will close (instead of 1 popup on non-Ash). - num_popups -= 2; -#else num_popups -= 1; +#if defined(USE_ASH_PANELS) + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) { + // On Ash, new panel windows open as popup windows instead, so there are 2 + // extension domain popups that will close (instead of 1 popup on non-Ash). + num_popups -= 1; + } #endif - WaitForTabsAndPopups(browser(), 1, num_popups, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, num_popups, 0)); } #if defined(OS_CHROMEOS) @@ -297,9 +317,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, #define MAYBE_ClosePanelsOnExtensionCrash ClosePanelsOnExtensionCrash #endif IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) { -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) +#if defined(USE_ASH_PANELS) // On Ash, new panel windows open as popup windows instead. int num_popups = 4; int num_panels = 0; @@ -330,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) { // Two tabs. One in extension domain and one in non-extension domain. // Two popups - one in extension domain and one in non-extension domain. // Two panels - one in extension domain and one in non-extension domain. - WaitForTabsAndPopups(browser(), 2, num_popups, num_panels); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels)); // Wait on test messages to make sure the pages loaded. for (size_t i = 0; i < listeners.size(); ++i) @@ -346,14 +364,12 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) { WaitForExtensionCrash(extension->id()); // Only expect panels to close. The rest stay open to show a sad-tab. - WaitForTabsAndPopups(browser(), 2, num_popups, 0); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, 0)); } -// TODO: this ifdef will have to be updated when we have win ash bots running -// browser_tests. -#if defined(USE_ASH) && !defined(OS_WIN) -// This test is not applicable on Ash. Ash opens panel windows as popup -// windows. The modified window.open behavior only applies to panel windows. +#if defined(USE_ASH_PANELS) +// This test is not applicable on Ash. The modified window.open behavior only +// applies to non-Ash panel windows. #define MAYBE_WindowOpenFromPanel DISABLED_WindowOpenFromPanel #else #define MAYBE_WindowOpenFromPanel WindowOpenFromPanel @@ -368,7 +384,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenFromPanel) { // Expect one panel (opened by extension) and one tab (from the panel calling // window.open). Panels modify the WindowOpenDisposition in window.open // to always open in a tab. - WaitForTabsAndPopups(browser(), 1, 0, 1); + EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, 0, 1)); } IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpener) { diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc index bdc53b2..bd1e950 100644 --- a/chrome/browser/ui/extensions/shell_window.cc +++ b/chrome/browser/ui/extensions/shell_window.cc @@ -6,13 +6,13 @@ #include "base/utf_string_conversions.h" #include "base/values.h" +#include "chrome/browser/extensions/app_window_contents.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/image_loader.h" #include "chrome/browser/extensions/shell_window_geometry_cache.h" #include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/extensions/suggest_permission_util.h" -#include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/favicon/favicon_tab_helper.h" #include "chrome/browser/file_select_helper.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -27,25 +27,20 @@ #include "chrome/browser/ui/web_contents_modal_dialog_manager.h" #include "chrome/browser/view_type_utils.h" #include "chrome/common/chrome_notification_types.h" -#include "chrome/common/extensions/api/app_window.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/request_media_access_permission_helper.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" -#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" -#include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/media_stream_request.h" -#include "content/public/common/renderer_preferences.h" #include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/image/image_skia.h" @@ -54,13 +49,7 @@ #include "ash/launcher/launcher_types.h" #endif -namespace app_window = extensions::api::app_window; - -using content::BrowserThread; using content::ConsoleMessageLevel; -using content::RenderViewHost; -using content::ResourceDispatcherHost; -using content::SiteInstance; using content::WebContents; using extensions::APIPermission; using extensions::RequestMediaAccessPermissionHelper; @@ -76,14 +65,6 @@ const int kPreferredIconSize = ash::kLauncherPreferredSize; const int kPreferredIconSize = extension_misc::EXTENSION_ICON_SMALL; #endif -void SuspendRenderViewHost(RenderViewHost* rvh) { - DCHECK(rvh); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&ResourceDispatcherHost::BlockRequestsForRoute, - base::Unretained(ResourceDispatcherHost::Get()), - rvh->GetProcess()->GetID(), rvh->GetRoutingID())); -} - } // namespace ShellWindow::CreateParams::CreateParams() @@ -103,7 +84,7 @@ ShellWindow* ShellWindow::Create(Profile* profile, const CreateParams& params) { // This object will delete itself when the window is closed. ShellWindow* window = new ShellWindow(profile, extension); - window->Init(url, params); + window->Init(url, new AppWindowContents(window), params); extensions::ShellWindowRegistry::Get(profile)->AddShellWindow(window); return window; } @@ -112,29 +93,26 @@ ShellWindow::ShellWindow(Profile* profile, const extensions::Extension* extension) : profile_(profile), extension_(extension), - web_contents_(NULL), window_type_(WINDOW_TYPE_DEFAULT), - ALLOW_THIS_IN_INITIALIZER_LIST( - extension_function_dispatcher_(profile, this)), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_ptr_factory_(this)) { } void ShellWindow::Init(const GURL& url, + ShellWindowContents* shell_window_contents, const ShellWindow::CreateParams& params) { - window_type_ = params.window_type; + // Initialize the render interface and web contents + shell_window_contents_.reset(shell_window_contents); + shell_window_contents_->Initialize(profile(), url); + WebContents* web_contents = shell_window_contents_->GetWebContents(); + WebContentsModalDialogManager::CreateForWebContents(web_contents); + FaviconTabHelper::CreateForWebContents(web_contents); - web_contents_.reset(WebContents::Create(WebContents::CreateParams( - profile(), SiteInstance::CreateForURL(profile(), url)))); - WebContentsModalDialogManager::CreateForWebContents(web_contents_.get()); - FaviconTabHelper::CreateForWebContents(web_contents_.get()); + web_contents->SetDelegate(this); + chrome::SetViewType(web_contents, chrome::VIEW_TYPE_APP_SHELL); - content::WebContentsObserver::Observe(web_contents_.get()); - web_contents_->SetDelegate(this); - chrome::SetViewType(web_contents_.get(), chrome::VIEW_TYPE_APP_SHELL); - web_contents_->GetMutableRendererPrefs()-> - browser_handles_all_top_level_requests = true; - web_contents_->GetRenderViewHost()->SyncRendererPrefs(); + // Initialize the window + window_type_ = params.window_type; gfx::Rect bounds = params.bounds; @@ -192,34 +170,7 @@ void ShellWindow::Init(const GURL& url, GetBaseWindow()->Show(); } - // If the new view is in the same process as the creator, block the created - // RVH from loading anything until the background page has had a chance to do - // any initialization it wants. If it's a different process, the new RVH - // shouldn't communicate with the background page anyway (e.g. sandboxed). - if (web_contents_->GetRenderViewHost()->GetProcess()->GetID() == - params.creator_process_id) { - SuspendRenderViewHost(web_contents_->GetRenderViewHost()); - } else { - VLOG(1) << "ShellWindow created in new process (" - << web_contents_->GetRenderViewHost()->GetProcess()->GetID() - << ") != creator (" << params.creator_process_id - << "). Routing disabled."; - } - - // TODO(jeremya): there's a bug where navigating a web contents to an - // extension URL causes it to create a new RVH and discard the old (perfectly - // usable) one. To work around this, we watch for a RVH_CHANGED message from - // the web contents (which will be sent during LoadURL) and suspend resource - // requests on the new RVH to ensure that we block the new RVH from loading - // anything. It should be okay to remove the NOTIFICATION_RVH_CHANGED - // registration once http://crbug.com/123007 is fixed. - registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<content::NavigationController>( - &web_contents_->GetController())); - web_contents_->GetController().LoadURL( - url, content::Referrer(), content::PAGE_TRANSITION_LINK, - std::string()); - registrar_.RemoveAll(); + shell_window_contents_->LoadContents(params.creator_process_id); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, content::Source<Profile>(profile_)); @@ -262,8 +213,6 @@ void ShellWindow::RequestMediaAccessPermission( WebContents* ShellWindow::OpenURLFromTab(WebContents* source, const content::OpenURLParams& params) { - DCHECK(source == web_contents_); - // Don't allow the current tab to be navigated. It would be nice to map all // anchor tags (even those without target="_blank") to new tabs, but right // now we can't distinguish between those and <meta> refreshes or window.href @@ -311,7 +260,6 @@ void ShellWindow::AddNewContents(WebContents* source, const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) { - DCHECK(source == web_contents_); DCHECK(Profile::FromBrowserContext(new_contents->GetBrowserContext()) == profile_); Browser* browser = @@ -327,7 +275,6 @@ void ShellWindow::AddNewContents(WebContents* source, void ShellWindow::HandleKeyboardEvent( WebContents* source, const content::NativeWebKeyboardEvent& event) { - DCHECK_EQ(source, web_contents_); native_app_window_->HandleKeyboardEvent(event); } @@ -344,37 +291,15 @@ void ShellWindow::RequestToLockMouse(WebContents* web_contents, void ShellWindow::OnNativeClose() { extensions::ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this); - content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); - rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID())); + if (shell_window_contents_) + shell_window_contents_->NativeWindowClosed(); delete this; } void ShellWindow::OnNativeWindowChanged() { SaveWindowPosition(); - if (!native_app_window_ || !web_contents_) - return; - ListValue args; - DictionaryValue* dictionary = new DictionaryValue(); - args.Append(dictionary); - - gfx::Rect bounds = native_app_window_->GetBounds(); - bounds.Inset(native_app_window_->GetFrameInsets()); - app_window::Bounds update; - update.left.reset(new int(bounds.x())); - update.top.reset(new int(bounds.y())); - update.width.reset(new int(bounds.width())); - update.height.reset(new int(bounds.height())); - dictionary->Set("bounds", update.ToValue().release()); - dictionary->SetBoolean("minimized", native_app_window_->IsMinimized()); - dictionary->SetBoolean("maximized", native_app_window_->IsMaximized()); - - content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); - rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(), - extension_->id(), - "updateAppWindowProperties", - args, - GURL(), - false)); + if (shell_window_contents_ && native_app_window_) + shell_window_contents_->NativeWindowChanged(native_app_window_.get()); } gfx::Image* ShellWindow::GetAppListIcon() { @@ -392,6 +317,10 @@ gfx::Image* ShellWindow::GetAppListIcon() { return new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)); } +content::WebContents* ShellWindow::web_contents() const { + return shell_window_contents_->GetWebContents(); +} + NativeAppWindow* ShellWindow::GetBaseWindow() { return native_app_window_.get(); } @@ -420,25 +349,14 @@ void ShellWindow::SetAppIconUrl(const GURL& url) { weak_ptr_factory_.GetWeakPtr())); } -//------------------------------------------------------------------------------ -// Private methods - -bool ShellWindow::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ShellWindow, message) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_UpdateDraggableRegions, - UpdateDraggableRegions) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - void ShellWindow::UpdateDraggableRegions( const std::vector<extensions::DraggableRegion>& regions) { native_app_window_->UpdateDraggableRegions(regions); } +//------------------------------------------------------------------------------ +// Private methods + void ShellWindow::OnImageLoaded(const gfx::Image& image) { UpdateAppIcon(image); } @@ -486,7 +404,6 @@ void ShellWindow::UpdateExtensionAppIcon() { } void ShellWindow::CloseContents(WebContents* contents) { - DCHECK(contents == web_contents_); native_app_window_->Close(); } @@ -500,18 +417,15 @@ void ShellWindow::RunFileChooser(WebContents* tab, } bool ShellWindow::IsPopupOrPanel(const WebContents* source) const { - DCHECK(source == web_contents_.get()); return true; } void ShellWindow::MoveContents(WebContents* source, const gfx::Rect& pos) { - DCHECK(source == web_contents_.get()); native_app_window_->SetBounds(pos); } void ShellWindow::NavigationStateChanged( const content::WebContents* source, unsigned changed_flags) { - DCHECK(source == web_contents_.get()); if (changed_flags & content::INVALIDATE_TYPE_TITLE) native_app_window_->UpdateWindowTitle(); else if (changed_flags & content::INVALIDATE_TYPE_TAB) @@ -520,14 +434,10 @@ void ShellWindow::NavigationStateChanged( void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source, bool enter_fullscreen) { - DCHECK(source == web_contents_.get()); - if (source != web_contents_.get()) - return; - bool has_permission = IsExtensionWithPermissionOrSuggestInConsole( APIPermission::kFullscreen, extension_, - web_contents_->GetRenderViewHost()); + source->GetRenderViewHost()); if (has_permission) native_app_window_->SetFullscreen(enter_fullscreen); @@ -535,7 +445,6 @@ void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source, bool ShellWindow::IsFullscreenForTabOrPending( const content::WebContents* source) const { - DCHECK(source == web_contents_.get()); return native_app_window_->IsFullscreenOrPending(); } @@ -544,13 +453,6 @@ void ShellWindow::Observe(int type, const content::NotificationDetails& details) { switch (type) { case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: { - // TODO(jeremya): once http://crbug.com/123007 is fixed, we'll no longer - // need to suspend resource requests here (the call in the constructor - // should be enough). - content::Details<std::pair<RenderViewHost*, RenderViewHost*> > - host_details(details); - if (host_details->first) - SuspendRenderViewHost(host_details->second); // TODO(jianli): once http://crbug.com/123007 is fixed, we'll no longer // need to make the native window (ShellWindowViews specially) update // the clickthrough region for the new RVH. @@ -573,29 +475,15 @@ void ShellWindow::Observe(int type, } } -extensions::WindowController* -ShellWindow::GetExtensionWindowController() const { - return NULL; -} - -content::WebContents* ShellWindow::GetAssociatedWebContents() const { - return web_contents_.get(); -} - extensions::ActiveTabPermissionGranter* ShellWindow::GetActiveTabPermissionGranter() { // Shell windows don't support the activeTab permission. return NULL; } -void ShellWindow::OnRequest(const ExtensionHostMsg_Request_Params& params) { - extension_function_dispatcher_.Dispatch(params, - web_contents_->GetRenderViewHost()); -} - void ShellWindow::AddMessageToDevToolsConsole(ConsoleMessageLevel level, const std::string& message) { - content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); rvh->Send(new ExtensionMsg_AddMessageToConsole( rvh->GetRoutingID(), level, message)); } diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h index 981c725..4d66ae0 100644 --- a/chrome/browser/ui/extensions/shell_window.h +++ b/chrome/browser/ui/extensions/shell_window.h @@ -6,14 +6,13 @@ #define CHROME_BROWSER_UI_EXTENSIONS_SHELL_WINDOW_H_ #include "base/memory/scoped_ptr.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/extensions/extension_keybinding_registry.h" #include "chrome/browser/sessions/session_id.h" #include "chrome/browser/ui/base_window.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_delegate.h" -#include "content/public/browser/web_contents_observer.h" #include "content/public/common/console_message_level.h" #include "ui/gfx/image/image.h" #include "ui/gfx/rect.h" @@ -34,12 +33,37 @@ class WindowController; struct DraggableRegion; } +// Manages the web contents for Shell Windows. The implementation for this +// class should create and maintain the WebContents for the window, and handle +// any message passing between the web contents and the extension system or +// native window. +class ShellWindowContents { + public: + ShellWindowContents() {} + virtual ~ShellWindowContents() {} + + // Called to initialize the WebContents, before the app window is created. + virtual void Initialize(Profile* profile, const GURL& url) = 0; + + // Called to load the contents, after the app window is created. + virtual void LoadContents(int32 creator_process_id) = 0; + + // Called when the native window changes. + virtual void NativeWindowChanged(NativeAppWindow* native_app_window) = 0; + + // Called when the native window closes. + virtual void NativeWindowClosed() = 0; + + virtual content::WebContents* GetWebContents() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellWindowContents); +}; + // ShellWindow is the type of window used by platform apps. Shell windows // have a WebContents but none of the chrome of normal browser windows. class ShellWindow : public content::NotificationObserver, public content::WebContentsDelegate, - public content::WebContentsObserver, - public ExtensionFunctionDispatcher::Delegate, public extensions::ExtensionKeybindingRegistry::Delegate { public: enum WindowType { @@ -78,6 +102,7 @@ class ShellWindow : public content::NotificationObserver, bool hidden; }; + // Helper function for creating and intiailizing a v2 app window. static ShellWindow* Create(Profile* profile, const extensions::Extension* extension, const GURL& url, @@ -88,10 +113,22 @@ class ShellWindow : public content::NotificationObserver, static SkRegion* RawDraggableRegionsToSkRegion( const std::vector<extensions::DraggableRegion>& regions); + // The constructor and Init methods are public for constructing a ShellWindow + // with a non-standard render interface (e.g. v1 apps using Ash Panels). + // Normally ShellWindow::Create should be used. + ShellWindow(Profile* profile, const extensions::Extension* extension); + + // Initializes the render interface, web contents, and native window. + // |shell_window_contents| will become owned by ShellWindow. + void Init(const GURL& url, + ShellWindowContents* shell_window_contents, + const CreateParams& params); + + const std::string& window_key() const { return window_key_; } const SessionID& session_id() const { return session_id_; } const extensions::Extension* extension() const { return extension_; } - content::WebContents* web_contents() const { return web_contents_.get(); } + content::WebContents* web_contents() const; WindowType window_type() const { return window_type_; } Profile* profile() const { return profile_; } const gfx::Image& app_icon() const { return app_icon_; } @@ -107,7 +144,7 @@ class ShellWindow : public content::NotificationObserver, // NativeAppWindows should call this to determine what the window's title // is on startup and from within UpdateWindowTitle(). - virtual string16 GetTitle() const; + string16 GetTitle() const; // Call to notify ShellRegistry and delete the window. Subclasses should // invoke this method instead of using "delete this". @@ -120,22 +157,17 @@ class ShellWindow : public content::NotificationObserver, // Specifies a url for the launcher icon. void SetAppIconUrl(const GURL& icon_url); + // Called from the render interface to modify the draggable regions. + void UpdateDraggableRegions( + const std::vector<extensions::DraggableRegion>& regions); + protected: - ShellWindow(Profile* profile, - const extensions::Extension* extension); virtual ~ShellWindow(); private: // PlatformAppBrowserTest needs access to web_contents() friend class extensions::PlatformAppBrowserTest; - // Instantiates a platform-specific ShellWindow subclass (one implementation - // per platform). Public users of ShellWindow should use ShellWindow::Create. - void Init(const GURL& url, const CreateParams& params); - - // content::WebContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - // content::WebContentsDelegate implementation. virtual void CloseContents(content::WebContents* contents) OVERRIDE; virtual bool ShouldSuppressDialogs() OVERRIDE; @@ -177,14 +209,6 @@ class ShellWindow : public content::NotificationObserver, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; - // ExtensionFunctionDispatcher::Delegate implementation. - virtual extensions::WindowController* GetExtensionWindowController() const - OVERRIDE; - virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE; - - // Message handlers. - void OnRequest(const ExtensionHostMsg_Request_Params& params); - // Helper method to add a message to the renderer's DevTools console. void AddMessageToDevToolsConsole(content::ConsoleMessageLevel level, const std::string& message); @@ -192,9 +216,6 @@ class ShellWindow : public content::NotificationObserver, // Saves the window geometry/position. void SaveWindowPosition(); - virtual void UpdateDraggableRegions( - const std::vector<extensions::DraggableRegion>& regions); - // Load the app's image, firing a load state change when loaded. void UpdateExtensionAppIcon(); @@ -222,10 +243,8 @@ class ShellWindow : public content::NotificationObserver, std::string window_key_; const SessionID session_id_; - scoped_ptr<content::WebContents> web_contents_; WindowType window_type_; content::NotificationRegistrar registrar_; - ExtensionFunctionDispatcher extension_function_dispatcher_; // Icon shown in the task bar. gfx::Image app_icon_; @@ -235,6 +254,7 @@ class ShellWindow : public content::NotificationObserver, GURL app_icon_url_; scoped_ptr<NativeAppWindow> native_app_window_; + scoped_ptr<ShellWindowContents> shell_window_contents_; base::WeakPtrFactory<ShellWindow> weak_ptr_factory_; diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc index c63aac8..77ec909 100644 --- a/chrome/browser/ui/panels/panel.cc +++ b/chrome/browser/ui/panels/panel.cc @@ -54,6 +54,8 @@ class PanelExtensionWindowController : public extensions::WindowController { virtual std::string GetWindowTypeText() const OVERRIDE; virtual base::DictionaryValue* CreateWindowValueWithTabs( const extensions::Extension* extension) const OVERRIDE; + virtual base::DictionaryValue* CreateTabValue( + const extensions::Extension* extension, int tab_index) const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const OVERRIDE; @@ -90,29 +92,8 @@ PanelExtensionWindowController::CreateWindowValueWithTabs( base::DictionaryValue* result = CreateWindowValue(); DCHECK(IsVisibleToExtension(extension)); - content::WebContents* web_contents = panel_->GetWebContents(); - if (web_contents) { - DictionaryValue* tab_value = new DictionaryValue(); - tab_value->SetInteger(extensions::tabs_constants::kIdKey, - SessionID::IdForTab(web_contents)); - tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0); - tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, - SessionID::IdForWindowContainingTab(web_contents)); - tab_value->SetString( - extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec()); - tab_value->SetString(extensions::tabs_constants::kStatusKey, - ExtensionTabUtil::GetTabStatusText(web_contents->IsLoading())); - tab_value->SetBoolean( - extensions::tabs_constants::kActiveKey, panel_->IsActive()); - tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true); - tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true); - tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false); - tab_value->SetString( - extensions::tabs_constants::kTitleKey, web_contents->GetTitle()); - tab_value->SetBoolean( - extensions::tabs_constants::kIncognitoKey, - web_contents->GetBrowserContext()->IsOffTheRecord()); - + DictionaryValue* tab_value = CreateTabValue(extension, 0); + if (tab_value) { base::ListValue* tab_list = new ListValue(); tab_list->Append(tab_value); result->Set(extensions::tabs_constants::kTabsKey, tab_list); @@ -120,6 +101,40 @@ PanelExtensionWindowController::CreateWindowValueWithTabs( return result; } +base::DictionaryValue* PanelExtensionWindowController::CreateTabValue( + const extensions::Extension* extension, int tab_index) const { + if (tab_index > 0) + return NULL; + + content::WebContents* web_contents = panel_->GetWebContents(); + if (!web_contents) + return NULL; + + DCHECK(IsVisibleToExtension(extension)); + DictionaryValue* tab_value = new DictionaryValue(); + tab_value->SetInteger(extensions::tabs_constants::kIdKey, + SessionID::IdForTab(web_contents)); + tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0); + tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, + SessionID::IdForWindowContainingTab(web_contents)); + tab_value->SetString( + extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec()); + tab_value->SetString(extensions::tabs_constants::kStatusKey, + ExtensionTabUtil::GetTabStatusText( + web_contents->IsLoading())); + tab_value->SetBoolean( + extensions::tabs_constants::kActiveKey, panel_->IsActive()); + tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true); + tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true); + tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false); + tab_value->SetString( + extensions::tabs_constants::kTitleKey, web_contents->GetTitle()); + tab_value->SetBoolean( + extensions::tabs_constants::kIncognitoKey, + web_contents->GetBrowserContext()->IsOffTheRecord()); + return tab_value; +} + bool PanelExtensionWindowController::CanClose(Reason* reason) const { return true; } diff --git a/chrome/browser/ui/views/extensions/native_app_window_views.h b/chrome/browser/ui/views/extensions/native_app_window_views.h index f59184c..1fc797a 100644 --- a/chrome/browser/ui/views/extensions/native_app_window_views.h +++ b/chrome/browser/ui/views/extensions/native_app_window_views.h @@ -9,6 +9,7 @@ #include "chrome/browser/ui/extensions/native_app_window.h" #include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/browser/ui/views/unhandled_keyboard_event_handler.h" +#include "content/public/browser/web_contents_observer.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/rect.h" diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index b78dbce..88f9a34 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -468,6 +468,8 @@ 'browser/extensions/app_sync_bundle.h', 'browser/extensions/app_sync_data.cc', 'browser/extensions/app_sync_data.h', + 'browser/extensions/app_window_contents.cc', + 'browser/extensions/app_window_contents.h', 'browser/extensions/blacklist.cc', 'browser/extensions/blacklist.h', 'browser/extensions/blocked_actions.cc', @@ -743,6 +745,12 @@ 'browser/extensions/api/terminal/terminal_private_api.h', ], }], + ['use_ash==1', { + 'sources': [ + 'browser/extensions/api/tabs/ash_panel_contents.cc', + 'browser/extensions/api/tabs/ash_panel_contents.h', + ], + }], ['enable_extensions==0', { 'sources/': [ # Handle files in browser/extensions/api. Exclude everything by default, white list |