diff options
Diffstat (limited to 'chrome/browser/tab_contents')
6 files changed, 399 insertions, 19 deletions
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc new file mode 100644 index 0000000..c61802d --- /dev/null +++ b/chrome/browser/tab_contents/background_contents.cc @@ -0,0 +1,192 @@ +// Copyright (c) 2010 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/tab_contents/background_contents.h" + +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browsing_instance.h" +#include "chrome/browser/in_process_webkit/dom_storage_context.h" +#include "chrome/browser/in_process_webkit/webkit_context.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/renderer_preferences_util.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/view_types.h" +#include "chrome/common/render_messages.h" + + +//////////////// +// BackgroundContents + +BackgroundContents::BackgroundContents(SiteInstance* site_instance, + int routing_id) { + Profile* profile = site_instance->browsing_instance()->profile(); + + // TODO(rafaelw): Implement correct session storage. + int64 session_storage_namespace_id = profile->GetWebKitContext()-> + dom_storage_context()->AllocateSessionStorageNamespaceId(); + render_view_host_ = new RenderViewHost(site_instance, this, routing_id, + session_storage_namespace_id); + render_view_host_->AllowScriptToClose(true); + +#if defined(OS_WIN) || defined(OS_LINUX) + registrar_.Add(this, NotificationType::BROWSER_CLOSED, + NotificationService::AllSources()); +#elif defined(OS_MACOSX) + registrar_.Add(this, NotificationType::APP_TERMINATING, + NotificationService::AllSources()); +#endif +} + +void BackgroundContents::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + // TODO(rafaelw): Implement pagegroup ref-counting so that non-persistent + // background pages are closed when the last referencing frame is closed. + switch (type.value) { +#if defined(OS_WIN) || defined(OS_LINUX) + case NotificationType::BROWSER_CLOSED: { + bool app_closing = *Details<bool>(details).ptr(); + if (app_closing) + delete this; + break; + } +#elif defined(OS_MACOSX) + case NotificationType::APP_TERMINATING: { + delete this; + break; + } +#endif + default: + NOTREACHED() << "Unexpected notification sent."; + break; + } +} + +BackgroundContents::~BackgroundContents() { + NotificationService::current()->Notify( + NotificationType::BACKGROUND_CONTENTS_DELETED, + Source<BackgroundContents>(this), + Details<RenderViewHost>(render_view_host_)); + render_view_host_->Shutdown(); // deletes render_view_host +} + +void BackgroundContents::DidNavigate( + RenderViewHost* render_view_host, + const ViewHostMsg_FrameNavigate_Params& params) { + // We only care when the outer frame changes. + if (!PageTransition::IsMainFrame(params.transition)) + return; + + // Note: because BackgroundContents are only available to extension apps, + // navigation is limited to urls within the app's extent. This is enforced in + // RenderView::decidePolicyForNaviation. If BackgroundContents become + // available as a part of the web platform, it probably makes sense to have + // some way to scope navigation of a background page to its opener's security + // origin. Note: if the first navigation is to a URL outside the app's + // extent a background page will be opened but will remain at about:blank. + url_ = params.url; + + NotificationService::current()->Notify( + NotificationType::BACKGROUND_CONTENTS_NAVIGATED, + Source<BackgroundContents>(this), + Details<RenderViewHost>(render_view_host_)); +} + +void BackgroundContents::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) { + // TODO(rafaelw): Implement, The JavaScriptModalDialog needs to learn about + // BackgroundContents. + *did_suppress_message = true; +} + +std::wstring BackgroundContents::GetMessageBoxTitle(const GURL& frame_url, + bool is_alert) { + NOTIMPLEMENTED(); + return L""; +} + +gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() { + NOTIMPLEMENTED(); + return NULL; +} + +void BackgroundContents::OnMessageBoxClosed(IPC::Message* reply_msg, + bool success, + const std::wstring& prompt) { + render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt); +} + +void BackgroundContents::Close(RenderViewHost* render_view_host) { + delete this; +} + +RendererPreferences BackgroundContents::GetRendererPrefs( + Profile* profile) const { + RendererPreferences preferences; + renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); + return preferences; +} + +WebPreferences BackgroundContents::GetWebkitPrefs() { + // TODO(rafaelw): Consider enabling the webkit_prefs.dom_paste_enabled for + // apps. + Profile* profile = render_view_host_->process()->profile(); + return RenderViewHostDelegateHelper::GetWebkitPrefs(profile, + false); // is_dom_ui +} + +void BackgroundContents::ProcessDOMUIMessage(const std::string& message, + const Value* content, + const GURL& source_url, + int request_id, + bool has_callback) { + // TODO(rafaelw): It may make sense for extensions to be able to open + // BackgroundContents to chrome-extension://<id> pages. Consider implementing. + render_view_host_->BlockExtensionRequest(request_id); +} + +void BackgroundContents::CreateNewWindow( + int route_id, + WindowContainerType window_container_type) { + delegate_view_helper_.CreateNewWindow(route_id, + render_view_host_->process()->profile(), + render_view_host_->site_instance(), + DOMUIFactory::GetDOMUIType(url_), + this, + window_container_type); +} + +void BackgroundContents::CreateNewWidget(int route_id, + WebKit::WebPopupType popup_type) { + NOTREACHED(); +} + +void BackgroundContents::ShowCreatedWindow(int route_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); + if (!contents) + return; + Browser* browser = BrowserList::GetLastActiveWithProfile( + render_view_host_->process()->profile()); + if (!browser) + return; + + browser->AddTabContents(contents, disposition, initial_pos, user_gesture); +} + +void BackgroundContents::ShowCreatedWidget(int route_id, + const gfx::Rect& initial_pos) { + NOTIMPLEMENTED(); +} + diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h new file mode 100644 index 0000000..348b28a --- /dev/null +++ b/chrome/browser/tab_contents/background_contents.h @@ -0,0 +1,126 @@ +// Copyright (c) 2010 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_TAB_CONTENTS_BACKGROUND_CONTENTS_H_ +#define CHROME_BROWSER_TAB_CONTENTS_BACKGROUND_CONTENTS_H_ + +#include <string> + +#include "chrome/browser/jsmessage_box_client.h" +#include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/view_types.h" +#include "chrome/common/window_container_type.h" + +class RenderWidgetHost; +class RenderWidgetHostView; +class TabContents; +struct WebPreferences; + +// This class is a peer of TabContents. It can host a renderer, but does not +// have any visible display. Its navigation is not managed by a +// NavigationController because is has no facility for navigating (other than +// programatically view window.location.href) or RenderViewHostManager because +// it is never allowed to navigate across a SiteInstance boundary. +class BackgroundContents : public RenderViewHostDelegate, + public RenderViewHostDelegate::View, + public NotificationObserver, + public JavaScriptMessageBoxClient { + public: + BackgroundContents(SiteInstance* site_instance, + int routing_id); + ~BackgroundContents(); + + // Provide access to the RenderViewHost for the + // RenderViewHostDelegateViewHelper + RenderViewHost* render_view_host() { return render_view_host_; } + + // RenderViewHostDelegate implementation. + virtual RenderViewHostDelegate::View* GetViewDelegate() { return this; } + virtual const GURL& GetURL() const { return url_; } + virtual ViewType::Type GetRenderViewType() const { + return ViewType::BACKGROUND_CONTENTS; + } + virtual int GetBrowserWindowID() const { + return extension_misc::kUnknownWindowId; + } + virtual void DidNavigate(RenderViewHost* render_view_host, + const ViewHostMsg_FrameNavigate_Params& params); + virtual WebPreferences GetWebkitPrefs(); + virtual void ProcessDOMUIMessage(const std::string& message, + const Value* content, + const GURL& source_url, + int request_id, + bool has_callback); + 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 Close(RenderViewHost* render_view_host); + virtual RendererPreferences GetRendererPrefs(Profile* profile) const; + + // RenderViewHostDelegate::View + virtual void CreateNewWindow( + int route_id, + WindowContainerType window_container_type); + virtual void CreateNewWidget(int route_id, WebKit::WebPopupType popup_type); + 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, + WebKit::WebDragOperationsMask allowed_operations, + const SkBitmap& image, + const gfx::Point& image_offset) {} + virtual void UpdateDragCursor(WebKit::WebDragOperation operation) {} + virtual void GotFocus() {} + virtual void TakeFocus(bool reverse) {} + virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, + bool* is_keyboard_shortcut) { + return false; + } + virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {} + virtual void HandleMouseEvent() {} + virtual void HandleMouseLeave() {} + virtual void UpdatePreferredSize(const gfx::Size& new_size) {} + + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // JavaScriptMessageBoxClient + virtual std::wstring GetMessageBoxTitle(const GURL& frame_url, + bool is_alert); + virtual gfx::NativeWindow GetMessageBoxRootWindow(); + virtual void OnMessageBoxClosed(IPC::Message* reply_msg, + bool success, + const std::wstring& prompt); + virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) {} + virtual TabContents* AsTabContents() { return NULL; } + virtual ExtensionHost* AsExtensionHost() { return NULL; } + + private: + // The host for our HTML content. + RenderViewHost* render_view_host_; + + // Common implementations of some RenderViewHostDelegate::View methods. + RenderViewHostDelegateViewHelper delegate_view_helper_; + + // The URL being hosted. + GURL url_; + + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundContents); +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_BACKGROUND_CONTENTS_H_ diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc index 5fe2208..a1f7f01 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc @@ -8,6 +8,7 @@ #include "base/string_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/character_encoding.h" +#include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" @@ -15,26 +16,63 @@ #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/tab_contents/background_contents.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/user_style_sheet_watcher.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" +bool RenderViewHostDelegateViewHelper::ShouldOpenBackgroundContents( + WindowContainerType window_container_type, + GURL opener_url, + RenderProcessHost* opener_process, + Profile* profile) { + ExtensionsService* extensions_service = profile->GetExtensionsService(); + if (window_container_type != WINDOW_CONTAINER_TYPE_BACKGROUND || + !opener_url.is_valid() || + !extensions_service || + !extensions_service->is_ready()) + return false; + + Extension* extension = extensions_service->GetExtensionByURL(opener_url); + if (!extension) + extension = extensions_service->GetExtensionByWebExtent(opener_url); + if (!extension || + !extension->HasApiPermission(Extension::kBackgroundPermission)) + return false; + + ExtensionProcessManager* process_manager = + profile->GetExtensionProcessManager(); + if (!opener_process || !process_manager || + opener_process != process_manager->GetExtensionProcess(opener_url)) + return false; + + return true; +} TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow( int route_id, Profile* profile, SiteInstance* site, DOMUITypeID domui_type, - TabContents* old_tab_contents, + RenderViewHostDelegate* opener, WindowContainerType window_container_type) { + if (ShouldOpenBackgroundContents(window_container_type, + opener->GetURL(), + site->GetProcess(), + profile)) { + BackgroundContents* contents = new BackgroundContents(site, route_id); + pending_contents_[route_id] = contents->render_view_host(); + return NULL; + } + // Create the new web contents. This will automatically create the new // TabContentsView. In the future, we may want to create the view separately. TabContents* new_contents = new TabContents(profile, site, route_id, - old_tab_contents); + opener->GetAsTabContents()); new_contents->set_opener_dom_ui_type(domui_type); TabContentsView* new_view = new_contents->view(); @@ -43,7 +81,7 @@ TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow( new_view->CreateViewForWidget(new_contents->render_view_host()); // Save the created window associated with the route so we can show it later. - pending_contents_[route_id] = new_contents; + pending_contents_[route_id] = new_contents->render_view_host(); return new_contents; } @@ -67,19 +105,17 @@ TabContents* RenderViewHostDelegateViewHelper::GetCreatedWindow(int route_id) { return NULL; } - TabContents* new_tab_contents = iter->second; + RenderViewHost* new_rvh = iter->second; pending_contents_.erase(route_id); - if (!new_tab_contents->render_view_host()->view() || - !new_tab_contents->GetRenderProcessHost()->HasConnection()) { - // The view has gone away or the renderer crashed. Nothing to do. + // The renderer crashed or it is a TabContents and has no view. + if (!new_rvh->process()->HasConnection() || + (new_rvh->delegate()->GetAsTabContents() && !new_rvh->view())) return NULL; - } // TODO(brettw) this seems bogus to reach into here and initialize the host. - new_tab_contents->render_view_host()->Init(); - - return new_tab_contents; + new_rvh->Init(); + return new_rvh->delegate()->GetAsTabContents(); } RenderWidgetHostView* RenderViewHostDelegateViewHelper::GetCreatedWidget( diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.h b/chrome/browser/tab_contents/render_view_host_delegate_helper.h index 351e036..084762d 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.h +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.h @@ -17,10 +17,12 @@ #include "webkit/glue/window_open_disposition.h" class Browser; +class ExtensionsService; class PrefService; class Profile; class RenderProcessHost; class RenderViewHost; +class RenderViewHostDelegate; class RenderWidgetHost; class RenderWidgetHostView; class SiteInstance; @@ -32,24 +34,47 @@ class RenderViewHostDelegateViewHelper { public: RenderViewHostDelegateViewHelper() {} + // Creates a new renderer for window.open. This will either be a + // BackgroundContents (if the window_container_type == + // WINDOW_CONTAINER_TYPE_BACKGROUND and permissions allow) or a TabContents. + // If a TabContents is created, it is returned. Otherwise NULL is returned. virtual TabContents* CreateNewWindow( int route_id, Profile* profile, SiteInstance* site, DOMUITypeID domui_type, - TabContents* old_tab_contents, + RenderViewHostDelegate* opener, WindowContainerType window_container_type); + + // Creates a new RenderWidgetHost and saves it for later retrieval by + // GetCreatedWidget. virtual RenderWidgetHostView* CreateNewWidget(int route_id, WebKit::WebPopupType popup_type, RenderProcessHost* process); - virtual TabContents* GetCreatedWindow(int route_id); + + // Finds the new RenderWidgetHost and returns it. Note that this can only be + // called once as this call also removes it from the internal map. virtual RenderWidgetHostView* GetCreatedWidget(int route_id); + + // Finds the new RenderViewHost/Delegate by route_id, initializes it for + // for renderer-initiated creation, and returns the TabContents that needs + // to be shown, if there is one (i.e. not a BackgroundContents). Note that + // this can only be called once as this call also removes it from the internal + // map. + virtual TabContents* GetCreatedWindow(int route_id); + + // Removes |host| from the internal map of pending RenderWidgets. void RenderWidgetHostDestroyed(RenderWidgetHost* host); private: - // Tracks created TabContents objects that have not been shown yet. They are - // identified by the route ID passed to CreateNewWindow. - typedef std::map<int, TabContents*> PendingContents; + bool ShouldOpenBackgroundContents(WindowContainerType window_container_type, + GURL opener_url, + RenderProcessHost* opener_process, + Profile* profile); + + // Tracks created RenderViewHost objects that have not been shown yet. + // They are identified by the route ID passed to CreateNewWindow. + typedef std::map<int, RenderViewHost*> PendingContents; PendingContents pending_contents_; // These maps hold on to the widgets that we created on behalf of the diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 2f3e743..9d2fd42 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -946,7 +946,7 @@ void TabContents::PopupNotificationVisibilityChanged(bool visible) { if (is_being_destroyed_) return; if (!dont_notify_render_view_) - render_view_host()->PopupNotificationVisibilityChanged(visible); + render_view_host()->AllowScriptToClose(!visible); if (delegate_) delegate_->OnContentSettingsChange(this); } diff --git a/chrome/browser/tab_contents/tab_contents_view.cc b/chrome/browser/tab_contents/tab_contents_view.cc index 935b96d..0fb400e 100644 --- a/chrome/browser/tab_contents/tab_contents_view.cc +++ b/chrome/browser/tab_contents/tab_contents_view.cc @@ -7,6 +7,7 @@ #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_widget_host.h" +#include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" @@ -28,12 +29,12 @@ void TabContentsView::RenderViewCreated(RenderViewHost* host) { void TabContentsView::CreateNewWindow( int route_id, WindowContainerType window_container_type) { - TabContents* new_contents = delegate_view_helper_.CreateNewWindow( + TabContents* new_contents = delegate_view_helper_.CreateNewWindow( route_id, tab_contents_->profile(), tab_contents_->GetSiteInstance(), DOMUIFactory::GetDOMUIType(tab_contents_->GetURL()), tab_contents_, window_container_type); - if (tab_contents_->delegate()) + if (new_contents && tab_contents_->delegate()) tab_contents_->delegate()->TabContentsCreated(new_contents); } |