diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-29 22:24:31 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-29 22:24:31 +0000 |
commit | c64631651a4267994dbdd336243e06b64e4e7a5f (patch) | |
tree | 23700eae496a6cf3cda0beea3742f12656c8cd4b /chrome | |
parent | 45671618a6690a8501f01905a4ed6d19cfcdc0b1 (diff) | |
download | chromium_src-c64631651a4267994dbdd336243e06b64e4e7a5f.zip chromium_src-c64631651a4267994dbdd336243e06b64e4e7a5f.tar.gz chromium_src-c64631651a4267994dbdd336243e06b64e4e7a5f.tar.bz2 |
Refactor ExtensionView to support a UI-less extension instance.
- Introduce ExtensionHost, which is the guy that talks to the RenderViewHost.
- ExtensionView holds an ExtensionHost, and also renders its contents in an
HWND.
- Added code to load a page optionally specified in the manifest as a
background process whenever it exists.
Review URL: http://codereview.chromium.org/92043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14902 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
20 files changed, 529 insertions, 238 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index 96114e4..88150e2 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -1958,6 +1958,14 @@ > </File> <File + RelativePath=".\extensions\extension_host.cc" + > + </File> + <File + RelativePath=".\extensions\extension_host.h" + > + </File> + <File RelativePath=".\extensions\extension_message_service.cc" > </File> diff --git a/chrome/browser/browser_list.cc b/chrome/browser/browser_list.cc index ca2963f..c1676c0 100644 --- a/chrome/browser/browser_list.cc +++ b/chrome/browser/browser_list.cc @@ -223,6 +223,23 @@ Browser* BrowserList::FindBrowserWithType(Profile* p, Browser::Type t) { } // static +Browser* BrowserList::FindBrowserWithProfile(Profile* p) { + Browser* last_active = GetLastActive(); + if (last_active && last_active->profile() == p) + return last_active; + + BrowserList::const_iterator i; + for (i = BrowserList::begin(); i != BrowserList::end(); ++i) { + if (*i == last_active) + continue; + + if ((*i)->profile() == p) + return *i; + } + return NULL; +} + +// static Browser* BrowserList::FindBrowserWithID(SessionID::id_type desired_id) { BrowserList::const_iterator i; for (i = BrowserList::begin(); i != BrowserList::end(); ++i) { diff --git a/chrome/browser/browser_list.h b/chrome/browser/browser_list.h index 2488a09..faa2f64 100644 --- a/chrome/browser/browser_list.h +++ b/chrome/browser/browser_list.h @@ -59,6 +59,11 @@ class BrowserList { // is returned. Returns NULL if no such browser currently exists. static Browser* FindBrowserWithType(Profile* p, Browser::Type t); + // Find an existing browser window with the provided profile. If the last + // active has the right profile, it is returned. Returns NULL if no such + // browser currently exists. + static Browser* FindBrowserWithProfile(Profile* p); + // Find an existing browser with the provided ID. Returns NULL if no such // browser currently exists. static Browser* FindBrowserWithID(SessionID::id_type desired_id); diff --git a/chrome/browser/extensions/extension.cc b/chrome/browser/extensions/extension.cc index 1aeaeaa..6b2bb3e 100644 --- a/chrome/browser/extensions/extension.cc +++ b/chrome/browser/extensions/extension.cc @@ -24,6 +24,7 @@ const wchar_t* Extension::kMatchesKey = L"matches"; const wchar_t* Extension::kNameKey = L"name"; const wchar_t* Extension::kPermissionsKey = L"permissions"; const wchar_t* Extension::kPluginsDirKey = L"plugins_dir"; +const wchar_t* Extension::kBackgroundKey = L"background"; const wchar_t* Extension::kRunAtKey = L"run_at"; const wchar_t* Extension::kThemeKey = L"theme"; const wchar_t* Extension::kToolstripsKey = L"toolstrips"; @@ -75,6 +76,8 @@ const char* Extension::kInvalidPermissionSchemeError = "allowed."; const char* Extension::kInvalidPluginsDirError = "Invalid value for 'plugins_dir'."; +const char* Extension::kInvalidBackgroundError = + "Invalid value for 'background'."; const char* Extension::kInvalidRunAtError = "Invalid value for 'content_scripts[*].run_at'."; const char* Extension::kInvalidToolstripError = @@ -403,6 +406,16 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id, plugins_dir_ = path_.AppendASCII(plugins_dir); } + // Initialize background url (optional). + if (source.HasKey(kBackgroundKey)) { + std::string background_str; + if (!source.GetString(kBackgroundKey, &background_str)) { + *error = kInvalidBackgroundError; + return false; + } + background_url_ = GetResourceURL(background_str); + } + // Initialize toolstrips (optional). if (source.HasKey(kToolstripsKey)) { ListValue* list_value; diff --git a/chrome/browser/extensions/extension.h b/chrome/browser/extensions/extension.h index 2f59115..95f04bb 100644 --- a/chrome/browser/extensions/extension.h +++ b/chrome/browser/extensions/extension.h @@ -38,6 +38,7 @@ class Extension { static const wchar_t* kNameKey; static const wchar_t* kPermissionsKey; static const wchar_t* kPluginsDirKey; + static const wchar_t* kBackgroundKey; static const wchar_t* kRunAtKey; static const wchar_t* kThemeKey; static const wchar_t* kToolstripsKey; @@ -63,6 +64,7 @@ class Extension { static const char* kInvalidMatchesError; static const char* kInvalidNameError; static const char* kInvalidPluginsDirError; + static const char* kInvalidBackgroundError; static const char* kInvalidRunAtError; static const char* kInvalidToolstripError; static const char* kInvalidToolstripsError; @@ -122,6 +124,7 @@ class Extension { const std::string& description() const { return description_; } const UserScriptList& content_scripts() const { return content_scripts_; } const FilePath& plugins_dir() const { return plugins_dir_; } + const GURL& background_url() const { return background_url_; } const std::vector<std::string>& toolstrips() const { return toolstrips_; } const std::vector<URLPattern>& permissions() const { return permissions_; } @@ -163,6 +166,10 @@ class Extension { // contains. FilePath plugins_dir_; + // Optional URL to a master page of which a single instance should be always + // loaded in the background. + GURL background_url_; + // Paths to HTML files to be displayed in the toolbar. std::vector<std::string> toolstrips_; @@ -174,6 +181,7 @@ class Extension { // A map of resource id's to relative file paths. std::map<const std::wstring, std::string> theme_paths_; + // The sites this extension has permission to talk to (using XHR, etc). std::vector<URLPattern> permissions_; // We implement copy, but not assign. diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc new file mode 100755 index 0000000..16d55e8 --- /dev/null +++ b/chrome/browser/extensions/extension_host.cc @@ -0,0 +1,171 @@ +// Copyright (c) 2006-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_host.h" + +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/extensions/extension.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/extensions/extension_view.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/tab_contents/site_instance.h" +#include "chrome/browser/tab_contents/web_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/common/resource_bundle.h" + +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" + +#include "webkit/glue/context_menu.h" + +ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance) + : extension_(extension), view_(NULL), did_stop_loading_(false) { + render_view_host_ = new RenderViewHost( + site_instance, this, MSG_ROUTING_NONE, NULL); + render_view_host_->AllowExtensionBindings(); +} + +ExtensionHost::~ExtensionHost() { + render_view_host_->Shutdown(); // deletes render_view_host +} + +SiteInstance* ExtensionHost::site_instance() const { + return render_view_host_->site_instance(); +} + +void ExtensionHost::CreateRenderView(const GURL& url, + RenderWidgetHostView* host_view) { + render_view_host_->set_view(host_view); + render_view_host_->CreateRenderView(); + render_view_host_->NavigateToURL(url); +} + +void ExtensionHost::DidContentsPreferredWidthChange(const int pref_width) { + if (view_) + view_->DidContentsPreferredWidthChange(pref_width); +} + +void ExtensionHost::RenderViewCreated(RenderViewHost* rvh) { + URLRequestContext* context = rvh->process()->profile()->GetRequestContext(); + ExtensionMessageService::GetInstance(context)->RegisterExtension( + extension_->id(), rvh->process()->pid()); +} + +WebPreferences ExtensionHost::GetWebkitPrefs() { + PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); + const bool kIsDomUI = true; + return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, kIsDomUI); +} + +void ExtensionHost::RunJavaScriptMessage( + const std::wstring& message, + const std::wstring& default_prompt, + const GURL& frame_url, + const int flags, + IPC::Message* reply_msg, + bool* did_suppress_message) { + // Automatically cancel the javascript alert (otherwise the renderer hangs + // indefinitely). + *did_suppress_message = true; + render_view_host()->JavaScriptMessageBoxClosed(reply_msg, true, L""); +} + +void ExtensionHost::DidStartLoading(RenderViewHost* render_view_host) { + static const StringPiece toolstrip_css( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_EXTENSIONS_TOOLSTRIP_CSS)); + render_view_host->InsertCSSInWebFrame(L"", toolstrip_css.as_string()); +} + +void ExtensionHost::DidStopLoading(RenderViewHost* render_view_host) { + render_view_host->WasResized(); + did_stop_loading_ = true; + if (view_) + view_->ShowIfCompletelyLoaded(); +} + +ExtensionFunctionDispatcher* ExtensionHost:: + CreateExtensionFunctionDispatcher(RenderViewHost *render_view_host, + const std::string& extension_id) { + return new ExtensionFunctionDispatcher(render_view_host, GetBrowser(), + extension_id); +} + +RenderViewHostDelegate::View* ExtensionHost::GetViewDelegate() const { + // TODO(erikkay) this is unfortunate. The interface declares that this method + // must be const (no good reason for it as far as I can tell) which means you + // can't return self without doing this const_cast. Either we need to change + // the interface, or we need to split out the view delegate into another + // object (which is how WebContents works). + return const_cast<ExtensionHost*>(this); +} + +void ExtensionHost::CreateNewWindow(int route_id, + base::WaitableEvent* modal_dialog_event) { + delegate_view_helper_.CreateNewWindow( + route_id, modal_dialog_event, render_view_host()->process()->profile(), + site_instance()); +} + +void ExtensionHost::CreateNewWidget(int route_id, bool activatable) { + delegate_view_helper_.CreateNewWidget(route_id, activatable, + site_instance()->GetProcess()); +} + +void ExtensionHost::ShowCreatedWindow(int route_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + WebContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); + if (contents) { + // TODO(erikkay) is it safe to pass in NULL as source? + GetBrowser()->AddTabContents(contents, disposition, initial_pos, + user_gesture); + } +} + +void ExtensionHost::ShowCreatedWidget(int route_id, + const gfx::Rect& initial_pos) { + RenderWidgetHostView* widget_host_view = + delegate_view_helper_.GetCreatedWidget(route_id); + GetBrowser()->BrowserRenderWidgetShowing(); + // TODO(erikkay): These two lines could be refactored with TabContentsView. + widget_host_view->InitAsPopup(render_view_host()->view(), initial_pos); + widget_host_view->GetRenderWidgetHost()->Init(); +} + +void ExtensionHost::ShowContextMenu(const ContextMenuParams& params) { + // TODO(erikkay) - This is a temporary hack. Show a menu here instead. + render_view_host()->InspectElementAt(params.x, params.y); +} + +void ExtensionHost::StartDragging(const WebDropData& drop_data) { +} + +void ExtensionHost::UpdateDragCursor(bool is_drop_target) { +} + +void ExtensionHost::TakeFocus(bool reverse) { +} + +void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { +} + +Browser* ExtensionHost::GetBrowser() { + if (view_) + return view_->browser(); + Browser* browser = BrowserList::FindBrowserWithProfile( + render_view_host()->process()->profile()); + // TODO(mpcomplete): what this verifies doesn't actually happen yet. + CHECK(browser) << "ExtensionHost running in Profile with no Browser active." + " It should have been deleted."; + return browser; +} diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h new file mode 100755 index 0000000..0c67be8 --- /dev/null +++ b/chrome/browser/extensions/extension_host.h @@ -0,0 +1,100 @@ +// Copyright (c) 2006-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_HOST_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_ + +#include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" + +class Browser; +class Extension; +class ExtensionView; +class RenderWidgetHost; +class RenderWidgetHostView; +class WebContents; +struct WebPreferences; + +// This class is the browser component of an extension component's RenderView. +// 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, + public RenderViewHostDelegate::View { + public: + ExtensionHost(Extension* extension, SiteInstance* site_instance); + ~ExtensionHost(); + + void set_view(ExtensionView* view) { view_ = view; } + ExtensionView* view() const { return view_; } + Extension* extension() { return extension_; } + RenderViewHost* render_view_host() const { return render_view_host_; } + SiteInstance* site_instance() const; + bool did_stop_loading() const { return did_stop_loading_; } + + // Initializes our RenderViewHost by creating its RenderView and navigating + // to the given URL. Uses host_view for the RenderViewHost's view (can be + // NULL). + void CreateRenderView(const GURL& url, RenderWidgetHostView* host_view); + + // RenderViewHostDelegate + // TODO(mpcomplete): GetProfile is unused. + virtual Profile* GetProfile() const { return NULL; } + virtual void RenderViewCreated(RenderViewHost* render_view_host); + virtual void DidContentsPreferredWidthChange(const int pref_width); + virtual WebPreferences GetWebkitPrefs(); + virtual void RunJavaScriptMessage( + const std::wstring& message, + const std::wstring& default_prompt, + const GURL& frame_url, + const int flags, + IPC::Message* reply_msg, + bool* did_suppress_message); + virtual void DidStartLoading(RenderViewHost* render_view_host); + virtual void DidStopLoading(RenderViewHost* render_view_host); + virtual RenderViewHostDelegate::View* GetViewDelegate() const; + virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher( + RenderViewHost *render_view_host, const std::string& extension_id); + + // RenderViewHostDelegate::View + virtual void CreateNewWindow(int route_id, + base::WaitableEvent* modal_dialog_event); + virtual void CreateNewWidget(int route_id, bool activatable); + virtual void ShowCreatedWindow(int route_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture); + virtual void ShowCreatedWidget(int route_id, + const gfx::Rect& initial_pos); + virtual void ShowContextMenu(const ContextMenuParams& params); + virtual void StartDragging(const WebDropData& drop_data); + virtual void UpdateDragCursor(bool is_drop_target); + virtual void TakeFocus(bool reverse); + virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); + + private: + // If this ExtensionHost has a view, this returns the Browser that view is a + // part of. If this is a global background page, we use the active Browser + // instead. + Browser* GetBrowser(); + + // The extension that we're hosting in this view. + Extension* extension_; + + // Optional view that shows the rendered content in the UI. + ExtensionView* view_; + + // The host for our HTML content. + RenderViewHost* render_view_host_; + + // Common implementations of some RenderViewHostDelegate::View methods. + RenderViewHostDelegateViewHelper delegate_view_helper_; + + // Whether the RenderWidget has reported that it has stopped loading. + bool did_stop_loading_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionHost); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_ diff --git a/chrome/browser/extensions/extension_view.cc b/chrome/browser/extensions/extension_view.cc index b394af7..5678e08 100755 --- a/chrome/browser/extensions/extension_view.cc +++ b/chrome/browser/extensions/extension_view.cc @@ -4,65 +4,65 @@ #include "chrome/browser/extensions/extension_view.h" -#include "base/command_line.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/character_encoding.h" -#include "chrome/browser/extensions/extension.h" -#include "chrome/browser/extensions/extension_message_service.h" -#include "chrome/browser/jsmessage_box_handler.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_host.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/tab_contents/site_instance.h" -#include "chrome/browser/tab_contents/web_contents.h" -#include "chrome/browser/tab_contents/tab_contents_view.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" -#include "chrome/common/resource_bundle.h" - -#include "grit/browser_resources.h" -#include "grit/generated_resources.h" - -#include "webkit/glue/context_menu.h" - -ExtensionView::ExtensionView(Extension* extension, - const GURL& url, - SiteInstance* instance, - Browser* browser) - : HWNDHtmlView(url, this, false, instance), - extension_(extension), - browser_(browser), - did_stop_loading_(false), - pending_preferred_width_(0) { +#include "chrome/views/widget/widget.h" + +#if defined(OS_WIN) +#include "chrome/browser/renderer_host/render_widget_host_view_win.h" +#endif + +ExtensionView::ExtensionView(ExtensionHost* host, Browser* browser, + const GURL& content_url) + : host_(host), browser_(browser), content_url_(content_url), + initialized_(false) { + host_->set_view(this); +} + +ExtensionView::~ExtensionView() { + if (GetHWND()) + Detach(); } -ExtensionFunctionDispatcher* ExtensionView:: - CreateExtensionFunctionDispatcher(RenderViewHost *render_view_host, - const std::string& extension_id) { - return new ExtensionFunctionDispatcher(render_view_host, browser_, - extension_id); +void ExtensionView::SetVisible(bool is_visible) { + HWNDView::SetVisible(is_visible); + + // Also tell RenderWidgetHostView the new visibility. Despite its name, it is + // not part of the View heirarchy and does not know about the change unless we + // tell it. + if (render_view_host()->view()) { + if (is_visible) + render_view_host()->view()->Show(); + else + render_view_host()->view()->Hide(); + } +} + +void ExtensionView::DidChangeBounds(const gfx::Rect& previous, + const gfx::Rect& current) { + // Propagate the new size to RenderWidgetHostView. + // We can't send size zero because RenderWidget DCHECKs that. + if (render_view_host()->view() && !current.IsEmpty()) + render_view_host()->view()->SetSize(gfx::Size(width(), height())); } void ExtensionView::ShowIfCompletelyLoaded() { // We wait to show the ExtensionView until it has loaded and our parent has // given us a background. These can happen in different orders. - if (did_stop_loading_ && !render_view_host()->view()->background().empty()) { + if (host_->did_stop_loading() && render_view_host()->view() && + !render_view_host()->view()->background().empty()) { SetVisible(true); DidContentsPreferredWidthChange(pending_preferred_width_); } } void ExtensionView::SetBackground(const SkBitmap& background) { - HWNDHtmlView::SetBackground(background); - ShowIfCompletelyLoaded(); -} - -void ExtensionView::DidStopLoading(RenderViewHost* render_view_host) { - render_view_host->WasResized(); - did_stop_loading_ = true; + if (initialized_ && render_view_host()->view()) { + render_view_host()->view()->SetBackground(background); + } else { + pending_background_ = background; + } ShowIfCompletelyLoaded(); } @@ -87,97 +87,37 @@ void ExtensionView::DidContentsPreferredWidthChange(const int pref_width) { } } -void ExtensionView::CreatingRenderer() { - render_view_host()->AllowExtensionBindings(); - SetVisible(false); -} - -void ExtensionView::RenderViewCreated(RenderViewHost* rvh) { - URLRequestContext* context = rvh->process()->profile()->GetRequestContext(); - ExtensionMessageService::GetInstance(context)->RegisterExtension( - extension_->id(), render_view_host()->process()->pid()); -} - -WebPreferences ExtensionView::GetWebkitPrefs() { - PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); - bool isDomUI = true; - return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, isDomUI); -} - -void ExtensionView::RunJavaScriptMessage( - const std::wstring& message, - const std::wstring& default_prompt, - const GURL& frame_url, - const int flags, - IPC::Message* reply_msg, - bool* did_suppress_message) { - // Automatically cancel the javascript alert (otherwise the renderer hangs - // indefinitely). - *did_suppress_message = true; - render_view_host()->JavaScriptMessageBoxClosed(reply_msg, true, L""); -} - -void ExtensionView::DidStartLoading(RenderViewHost* render_view_host) { - static const StringPiece toolstrip_css( - ResourceBundle::GetSharedInstance().GetRawDataResource( - IDR_EXTENSIONS_TOOLSTRIP_CSS)); - render_view_host->InsertCSSInWebFrame(L"", toolstrip_css.as_string()); -} - -RenderViewHostDelegate::View* ExtensionView::GetViewDelegate() const { - // TODO(erikkay) this is unfortunate. The interface declares that this method - // must be const (no good reason for it as far as I can tell) which means you - // can't return self without doing this const_cast. Either we need to change - // the interface, or we need to split out the view delegate into another - // object (which is how WebContents works). - return const_cast<ExtensionView*>(this); -} - -void ExtensionView::CreateNewWindow(int route_id, - base::WaitableEvent* modal_dialog_event) { - delegate_view_helper_.CreateNewWindow(route_id, modal_dialog_event, - browser_->profile(), site_instance()); -} - -void ExtensionView::CreateNewWidget(int route_id, bool activatable) { - delegate_view_helper_.CreateNewWidget(route_id, activatable, - site_instance()->GetProcess()); -} - -void ExtensionView::ShowCreatedWindow(int route_id, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { - WebContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); - if (contents) { - browser_->AddTabContents(contents, disposition, initial_pos, user_gesture); +void ExtensionView::ViewHierarchyChanged(bool is_add, + views::View *parent, + views::View *child) { + if (is_add && GetWidget() && !initialized_) { + initialized_ = true; + + RenderWidgetHostView* view = RenderWidgetHostView::CreateViewForWidget( + render_view_host()); + + // TODO(mpcomplete): RWHV needs a cross-platform Init function. +#if defined(OS_WIN) + // Create the HWND. Note: + // RenderWidgetHostHWND supports windowed plugins, but if we ever also + // wanted to support constrained windows with this, we would need an + // additional HWND to parent off of because windowed plugin HWNDs cannot + // exist in the same z-order as constrained windows. + RenderWidgetHostViewWin* view_win = + static_cast<RenderWidgetHostViewWin*>(view); + HWND hwnd = view_win->Create(GetWidget()->GetNativeView()); + view_win->ShowWindow(SW_SHOW); + Attach(hwnd); +#else + NOTIMPLEMENTED(); +#endif + + host_->CreateRenderView(content_url_, view); + SetVisible(false); + + if (!pending_background_.empty()) { + render_view_host()->view()->SetBackground(pending_background_); + pending_background_.reset(); + } } } - -void ExtensionView::ShowCreatedWidget(int route_id, - const gfx::Rect& initial_pos) { - RenderWidgetHostView* widget_host_view = - delegate_view_helper_.GetCreatedWidget(route_id); - browser_->BrowserRenderWidgetShowing(); - // TODO(erikkay): These two lines could be refactored with TabContentsView. - widget_host_view->InitAsPopup(render_view_host()->view(), - initial_pos); - widget_host_view->GetRenderWidgetHost()->Init(); -} - -void ExtensionView::ShowContextMenu(const ContextMenuParams& params) { - // TODO(erikkay) - This is a temporary hack. Show a menu here instead. - render_view_host()->InspectElementAt(params.x, params.y); -} - -void ExtensionView::StartDragging(const WebDropData& drop_data) { -} - -void ExtensionView::UpdateDragCursor(bool is_drop_target) { -} - -void ExtensionView::TakeFocus(bool reverse) { -} - -void ExtensionView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { -} diff --git a/chrome/browser/extensions/extension_view.h b/chrome/browser/extensions/extension_view.h index 38e093d..7715c5b 100755 --- a/chrome/browser/extensions/extension_view.h +++ b/chrome/browser/extensions/extension_view.h @@ -5,97 +5,68 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_H_ -#include "chrome/browser/renderer_host/render_view_host_delegate.h" -#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" +#include "build/build_config.h" + +#include "base/scoped_ptr.h" +#include "chrome/browser/extensions/extension_host.h" +#include "googleurl/src/gurl.h" #include "skia/include/SkBitmap.h" // TODO(port): Port these files. #if defined(OS_WIN) -#include "chrome/browser/views/hwnd_html_view.h" +#include "chrome/views/controls/hwnd_view.h" #else +#include "chrome/views/view.h" #include "chrome/common/temp_scaffolding_stubs.h" #endif class Browser; class Extension; -class ExtensionFunctionDispatcher; -class RenderWidgetHost; -class RenderWidgetHostView; -class WebContents; -struct WebPreferences; - -// This class is the browser component of an extension component's RenderView. -// It handles setting up the renderer process, if needed, with special -// priviliges available to extensions. The view may be drawn to the screen or -// hidden. -class ExtensionView : public HWNDHtmlView, - public RenderViewHostDelegate, - public RenderViewHostDelegate::View { - public: - // ExtensionView - ExtensionView(Extension* extension, - const GURL& url, - SiteInstance* instance, - Browser* browser); - - Extension* extension() { return extension_; } - - // HWNDHtmlView - virtual void CreatingRenderer(); - - virtual void SetBackground(const SkBitmap& background); - - // RenderViewHostDelegate - // TODO(mpcomplete): GetProfile is unused. - virtual Profile* GetProfile() const { return NULL; } - virtual ExtensionFunctionDispatcher *CreateExtensionFunctionDispatcher( - RenderViewHost *render_view_host, - const std::string& extension_id); - virtual void RenderViewCreated(RenderViewHost* render_view_host); - virtual void DidContentsPreferredWidthChange(const int pref_width); - virtual void DidStopLoading(RenderViewHost* render_view_host); - virtual WebPreferences GetWebkitPrefs(); - virtual void RunJavaScriptMessage( - const std::wstring& message, - const std::wstring& default_prompt, - const GURL& frame_url, - const int flags, - IPC::Message* reply_msg, - bool* did_suppress_message); - virtual void DidStartLoading(RenderViewHost* render_view_host); - virtual RenderViewHostDelegate::View* GetViewDelegate() const; - - // RenderViewHostDelegate::View - virtual void CreateNewWindow(int route_id, - base::WaitableEvent* modal_dialog_event); - virtual void CreateNewWidget(int route_id, bool activatable); - virtual void ShowCreatedWindow(int route_id, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture); - virtual void ShowCreatedWidget(int route_id, - const gfx::Rect& initial_pos); - virtual void ShowContextMenu(const ContextMenuParams& params); - virtual void StartDragging(const WebDropData& drop_data); - virtual void UpdateDragCursor(bool is_drop_target); - virtual void TakeFocus(bool reverse); - virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); +// This handles the display portion of an ExtensionHost. +class ExtensionView : public views::HWNDView { + public: + ExtensionView(ExtensionHost* host, Browser* browser, const GURL& content_url); + ~ExtensionView(); + + ExtensionHost* host() const { return host_.get(); } + Browser* browser() const { return browser_; } + Extension* extension() { return host_->extension(); } + RenderViewHost* render_view_host() { return host_->render_view_host(); } + + // Notification from ExtensionHost. + void DidContentsPreferredWidthChange(const int pref_width); + + // Set a custom background for the view. The background will be tiled. + void SetBackground(const SkBitmap& background); + + // views::HWNDView + virtual void SetVisible(bool is_visible); + virtual void DidChangeBounds(const gfx::Rect& previous, + const gfx::Rect& current); + virtual void ViewHierarchyChanged(bool is_add, + views::View *parent, views::View *child); private: + friend class ExtensionHost; + // We wait to show the ExtensionView until several things have loaded. void ShowIfCompletelyLoaded(); - // The extension that we're hosting in this view. - Extension* extension_; + // The running extension instance that we're displaying. + scoped_ptr<ExtensionHost> host_; // The browser window that this view is in. Browser* browser_; - // Common implementations of some RenderViewHostDelegate::View methods. - RenderViewHostDelegateViewHelper delegate_view_helper_; + // The URL to navigate the host to upon initialization. + GURL content_url_; + + // True if we've been initialized. + bool initialized_; - // Whether the RenderWidget has reported that it has stopped loading. - bool did_stop_loading_; + // The background the view should have once it is initialized. This is set + // when the view has a custom background, but hasn't been initialized yet. + SkBitmap pending_background_; // What we should set the preferred width to once the ExtensionView has // loaded. diff --git a/chrome/browser/extensions/extension_view_unittest.cc b/chrome/browser/extensions/extension_view_unittest.cc index e1c3d8d..3529022 100755 --- a/chrome/browser/extensions/extension_view_unittest.cc +++ b/chrome/browser/extensions/extension_view_unittest.cc @@ -6,7 +6,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/extension_view.h" +#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/extensions/test_extension_loader.h" #include "chrome/browser/tab_contents/site_instance.h" @@ -28,12 +28,13 @@ const char* kExtensionId = "00123456789abcdef0123456789abcdef0123456"; // This class starts up an extension process and waits until it tries to put // up a javascript alert. -class MockExtensionView : public ExtensionView { +class MockExtensionHost : public ExtensionHost { public: - MockExtensionView(Extension* extension, const GURL& url, - SiteInstance* instance, Browser* browser) - : ExtensionView(extension, url, instance, browser), got_message_(false) { - InitHidden(); + MockExtensionHost(Extension* extension, const GURL& url, + SiteInstance* instance) + : ExtensionHost(extension, instance), + got_message_(false) { + CreateRenderView(url, NULL); MessageLoop::current()->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, kAlertTimeoutMs); ui_test_utils::RunMessageLoop(); @@ -58,7 +59,7 @@ class MockExtensionView : public ExtensionView { MessageLoopForUI::current()->Quit(); // Call super, otherwise we'll leak reply_msg. - ExtensionView::RunJavaScriptMessage( + ExtensionHost::RunJavaScriptMessage( message, default_prompt, frame_url, flags, reply_msg, did_suppress_message); } @@ -100,8 +101,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Index) { GURL url = Extension::GetResourceURL(extension->url(), "toolstrip1.html"); // Start the extension process and wait for it to show a javascript alert. - MockExtensionView view(extension, url, - browser()->profile()->GetExtensionsService()->GetSiteInstanceForURL(url), - browser()); - EXPECT_TRUE(view.got_message()); + MockExtensionHost host(extension, url, + browser()->profile()->GetExtensionsService()->GetSiteInstanceForURL(url)); + EXPECT_TRUE(host.got_message()); } diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index b645dfe..38fb703 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -18,8 +18,9 @@ #include "chrome/browser/extensions/extension.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/user_script_master.h" +#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_view.h" +#include "chrome/browser/extensions/user_script_master.h" #include "chrome/browser/plugin_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/site_instance.h" @@ -27,6 +28,8 @@ #include "chrome/common/notification_service.h" #include "chrome/common/unzip.h" +#include "chrome/browser/browser_list.h" + #if defined(OS_WIN) #include "base/registry.h" #endif @@ -82,6 +85,11 @@ ExtensionsService::ExtensionsService(Profile* profile, } ExtensionsService::~ExtensionsService() { + for (ExtensionHostList::iterator iter = background_hosts_.begin(); + iter != background_hosts_.end(); ++iter) { + delete *iter; + } + for (ExtensionList::iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { delete *iter; @@ -163,6 +171,11 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) { script != scripts.end(); ++script) { user_script_master_->AddLoneScript(*script); } + + // Start the process for the master page, if it exists. + if ((*extension)->background_url().is_valid()) { + CreateBackgroundHost(*extension, (*extension)->background_url()); + } } // Since user scripts may have changed, tell UserScriptMaster to kick off @@ -189,7 +202,16 @@ void ExtensionsService::OnExtensionInstalled(FilePath path, bool update) { ExtensionView* ExtensionsService::CreateView(Extension* extension, const GURL& url, Browser* browser) { - return new ExtensionView(extension, url, GetSiteInstanceForURL(url), browser); + return new ExtensionView( + new ExtensionHost(extension, GetSiteInstanceForURL(url)), browser, url); +} + +void ExtensionsService::CreateBackgroundHost(Extension* extension, + const GURL& url) { + ExtensionHost* host = + new ExtensionHost(extension, GetSiteInstanceForURL(url)); + host->CreateRenderView(url, NULL); // create a RenderViewHost with no view + background_hosts_.push_back(host); } SiteInstance* ExtensionsService::GetSiteInstanceForURL(const GURL& url) { diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 2d075bc..d876f34 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -7,6 +7,7 @@ #include <string> #include <vector> +#include <list> #include "base/file_path.h" #include "base/message_loop.h" @@ -17,6 +18,7 @@ class Browser; class BrowsingInstance; class Extension; +class ExtensionHost; class ExtensionView; class ExtensionsServiceBackend; class GURL; @@ -82,6 +84,10 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface { const GURL& url, Browser* browser); + // Creates a new UI-less extension instance. Like CreateView, but not + // displayed anywhere. + void CreateBackgroundHost(Extension* extension, const GURL& url); + // Returns the SiteInstance that the given URL belongs to. SiteInstance* GetSiteInstanceForURL(const GURL& url); @@ -112,6 +118,10 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface { // controls process grouping. scoped_refptr<BrowsingInstance> browsing_instance_; + // The list of running viewless background extensions. + typedef std::list<ExtensionHost*> ExtensionHostList; + ExtensionHostList background_hosts_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsService); }; diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index 685f914..b4a81c5 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -184,6 +184,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { scripts[0].js_scripts()[0].path().value()); EXPECT_EQ(extension->path().AppendASCII("script2.js").value(), scripts[0].js_scripts()[1].path().value()); + EXPECT_TRUE(extension->plugins_dir().empty()); EXPECT_EQ(1u, scripts[1].url_patterns().size()); EXPECT_EQ("http://*.news.com/*", scripts[1].url_patterns()[0].GetAsString()); EXPECT_EQ(extension->path().AppendASCII("js_files").AppendASCII("script3.js") @@ -204,6 +205,8 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { frontend->extensions()->at(1)->description()); EXPECT_EQ(frontend->extensions()->at(1)->path().AppendASCII("npapi").value(), frontend->extensions()->at(1)->plugins_dir().value()); + EXPECT_EQ(frontend->extensions()->at(1)->GetResourceURL("background.html"), + frontend->extensions()->at(1)->background_url()); ASSERT_EQ(0u, frontend->extensions()->at(1)->content_scripts().size()); EXPECT_EQ(std::string("20123456789abcdef0123456789abcdef0123456"), diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index d778250..3646358 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -160,14 +160,12 @@ bool RenderViewHost::CreateRenderView() { "Couldn't duplicate the modal dialog handle for the renderer."; #endif - DCHECK(view()); - ModalDialogEvent modal_dialog_event; #if defined(OS_WIN) modal_dialog_event.event = modal_dialog_event_handle; #endif - Send(new ViewMsg_New(gfx::IdFromNativeView(view()->GetPluginNativeView()), + Send(new ViewMsg_New(GetPluginNativeViewId(), modal_dialog_event, delegate_->GetWebkitPrefs(), routing_id())); diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 9e07de7..7a2122a 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -4,7 +4,6 @@ #include "chrome/browser/renderer_host/render_widget_host.h" -#include "base/gfx/native_widget_types.h" #include "base/histogram.h" #include "base/message_loop.h" #include "base/keyboard_codes.h" @@ -79,15 +78,19 @@ RenderWidgetHost::~RenderWidgetHost() { process_->Release(routing_id_); } +gfx::NativeViewId RenderWidgetHost::GetPluginNativeViewId() { + if (view_) + return gfx::IdFromNativeView(view_->GetPluginNativeView()); + return NULL; +} + void RenderWidgetHost::Init() { DCHECK(process_->channel()); renderer_initialized_ = true; // Send the ack along with the information on placement. - gfx::NativeView plugin_view = view_->GetPluginNativeView(); - Send(new ViewMsg_CreatingNew_ACK(routing_id_, - gfx::IdFromNativeView(plugin_view))); + Send(new ViewMsg_CreatingNew_ACK(routing_id_, GetPluginNativeViewId())); WasResized(); } @@ -459,7 +462,8 @@ void RenderWidgetHost::OnMsgClose() { void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) { // Note that we ignore the position. - view_->SetSize(pos.size()); + if (view_) + view_->SetSize(pos.size()); } void RenderWidgetHost::OnMsgPaintRect( diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 0e93a84..861152a 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -8,6 +8,7 @@ #include <queue> #include <vector> +#include "base/gfx/native_widget_types.h" #include "base/gfx/size.h" #include "base/scoped_ptr.h" #include "base/timer.h" @@ -267,6 +268,9 @@ class RenderWidgetHost : public IPC::Channel::Listener { // consistent if a new renderer is created. void RendererExited(); + // Retrieves the native view used to contain plugins. + gfx::NativeViewId GetPluginNativeViewId(); + // Called when we an InputEvent was not processed by the renderer. This is // overridden by RenderView to send upwards to its delegate. virtual void UnhandledKeyboardEvent(const NativeWebKeyboardEvent& event) {} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 7820ae4..95bffd2 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -684,6 +684,8 @@ 'browser/extensions/extension_function.h', 'browser/extensions/extension_function_dispatcher.cc', 'browser/extensions/extension_function_dispatcher.h', + 'browser/extensions/extension_host.cc', + 'browser/extensions/extension_host.h', 'browser/extensions/extension_message_service.cc', 'browser/extensions/extension_message_service.h', 'browser/extensions/extension_browser_event_router.cc', diff --git a/chrome/common/temp_scaffolding_stubs.h b/chrome/common/temp_scaffolding_stubs.h index c8d77fb..1b49f76 100644 --- a/chrome/common/temp_scaffolding_stubs.h +++ b/chrome/common/temp_scaffolding_stubs.h @@ -39,6 +39,7 @@ struct ViewHostMsg_DidPrintPage_Params; namespace gfx { class Rect; +class Widget; } namespace IPC { @@ -478,26 +479,38 @@ class BaseDragSource { //--------------------------------------------------------------------------- // These stubs are for extensions -class HWNDHtmlView { +namespace views { +class HWNDView { public: - HWNDHtmlView(const GURL& content_url, RenderViewHostDelegate* delegate, - bool allow_dom_ui_bindings, SiteInstance* instance) { - NOTIMPLEMENTED(); - } - virtual ~HWNDHtmlView() {} - + int width() { NOTIMPLEMENTED(); return 0; } int height() { NOTIMPLEMENTED(); return 0; } - RenderViewHost* render_view_host() { NOTIMPLEMENTED(); return NULL; } void InitHidden() { NOTIMPLEMENTED(); } void set_preferred_size(const gfx::Size& size) { NOTIMPLEMENTED(); } virtual void SetBackground(const SkBitmap&) { NOTIMPLEMENTED(); } virtual void SetVisible(bool flag) { NOTIMPLEMENTED(); } void SizeToPreferredSize() { NOTIMPLEMENTED(); } - HWNDHtmlView* GetParent() const { NOTIMPLEMENTED(); return NULL; } bool IsVisible() const { NOTIMPLEMENTED(); return false; } void Layout() { NOTIMPLEMENTED(); } void SchedulePaint() { NOTIMPLEMENTED(); } + HWNDView* GetParent() const { NOTIMPLEMENTED(); return NULL; } + + gfx::NativeWindow GetHWND() { NOTIMPLEMENTED(); return 0; } + void Detach() { NOTIMPLEMENTED(); } + gfx::Widget* GetWidget() { NOTIMPLEMENTED(); return NULL; } +}; +} // namespace views + +class HWNDHtmlView : public views::HWNDView { + public: + HWNDHtmlView(const GURL& content_url, RenderViewHostDelegate* delegate, + bool allow_dom_ui_bindings, SiteInstance* instance) { + NOTIMPLEMENTED(); + } + virtual ~HWNDHtmlView() {} + + RenderViewHost* render_view_host() { NOTIMPLEMENTED(); return NULL; } SiteInstance* site_instance() { NOTIMPLEMENTED(); return NULL; } }; + #endif // CHROME_COMMON_TEMP_SCAFFOLDING_STUBS_H_ diff --git a/chrome/test/data/extensions/good/extension2/2/background.html b/chrome/test/data/extensions/good/extension2/2/background.html new file mode 100644 index 0000000..741876f --- /dev/null +++ b/chrome/test/data/extensions/good/extension2/2/background.html @@ -0,0 +1 @@ +Dummy file. diff --git a/chrome/test/data/extensions/good/extension2/2/manifest.json b/chrome/test/data/extensions/good/extension2/2/manifest.json index 5e148f3..ba13bb7 100644 --- a/chrome/test/data/extensions/good/extension2/2/manifest.json +++ b/chrome/test/data/extensions/good/extension2/2/manifest.json @@ -2,5 +2,6 @@ "id": "10123456789ABCDEF0123456789ABCDEF0123456", "version": "1.0.0.0", "name": "My extension 2", - "plugins_dir": "npapi" + "plugins_dir": "npapi", + "background": "background.html" } |