1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/tab_contents/background_contents.h" 6 7#include "chrome/browser/background_contents_service.h" 8#include "chrome/browser/extensions/extension_message_service.h" 9#include "chrome/browser/profiles/profile.h" 10#include "chrome/browser/renderer_preferences_util.h" 11#include "chrome/browser/ui/webui/chrome_web_ui_factory.h" 12#include "chrome/common/extensions/extension_constants.h" 13#include "chrome/common/extensions/extension_messages.h" 14#include "chrome/common/url_constants.h" 15#include "chrome/common/view_types.h" 16#include "content/browser/browsing_instance.h" 17#include "content/browser/renderer_host/render_view_host.h" 18#include "content/browser/site_instance.h" 19#include "content/common/notification_service.h" 20#include "content/common/view_messages.h" 21#include "ui/gfx/rect.h" 22 23//////////////// 24// BackgroundContents 25 26BackgroundContents::BackgroundContents(SiteInstance* site_instance, 27 int routing_id, 28 Delegate* delegate) 29 : delegate_(delegate) { 30 Profile* profile = site_instance->browsing_instance()->profile(); 31 32 // TODO(rafaelw): Implement correct session storage. 33 render_view_host_ = new RenderViewHost(site_instance, this, routing_id, NULL); 34 35 // Close ourselves when the application is shutting down. 36 registrar_.Add(this, NotificationType::APP_TERMINATING, 37 NotificationService::AllSources()); 38 39 // Register for our parent profile to shutdown, so we can shut ourselves down 40 // as well (should only be called for OTR profiles, as we should receive 41 // APP_TERMINATING before non-OTR profiles are destroyed). 42 registrar_.Add(this, NotificationType::PROFILE_DESTROYED, 43 Source<Profile>(profile)); 44} 45 46// Exposed to allow creating mocks. 47BackgroundContents::BackgroundContents() 48 : delegate_(NULL), 49 render_view_host_(NULL) { 50} 51 52BackgroundContents::~BackgroundContents() { 53 if (!render_view_host_) // Will be null for unit tests. 54 return; 55 Profile* profile = render_view_host_->process()->profile(); 56 NotificationService::current()->Notify( 57 NotificationType::BACKGROUND_CONTENTS_DELETED, 58 Source<Profile>(profile), 59 Details<BackgroundContents>(this)); 60 render_view_host_->Shutdown(); // deletes render_view_host 61} 62 63BackgroundContents* BackgroundContents::GetAsBackgroundContents() { 64 return this; 65} 66 67RenderViewHostDelegate::View* BackgroundContents::GetViewDelegate() { 68 return this; 69} 70 71const GURL& BackgroundContents::GetURL() const { 72 return url_; 73} 74 75ViewType::Type BackgroundContents::GetRenderViewType() const { 76 return ViewType::BACKGROUND_CONTENTS; 77} 78 79int BackgroundContents::GetBrowserWindowID() const { 80 return extension_misc::kUnknownWindowId; 81} 82 83void BackgroundContents::DidNavigate( 84 RenderViewHost* render_view_host, 85 const ViewHostMsg_FrameNavigate_Params& params) { 86 // We only care when the outer frame changes. 87 if (!PageTransition::IsMainFrame(params.transition)) 88 return; 89 90 // Note: because BackgroundContents are only available to extension apps, 91 // navigation is limited to urls within the app's extent. This is enforced in 92 // RenderView::decidePolicyForNaviation. If BackgroundContents become 93 // available as a part of the web platform, it probably makes sense to have 94 // some way to scope navigation of a background page to its opener's security 95 // origin. Note: if the first navigation is to a URL outside the app's 96 // extent a background page will be opened but will remain at about:blank. 97 url_ = params.url; 98 99 Profile* profile = render_view_host->process()->profile(); 100 NotificationService::current()->Notify( 101 NotificationType::BACKGROUND_CONTENTS_NAVIGATED, 102 Source<Profile>(profile), 103 Details<BackgroundContents>(this)); 104} 105 106void BackgroundContents::RunJavaScriptMessage( 107 const std::wstring& message, 108 const std::wstring& default_prompt, 109 const GURL& frame_url, 110 const int flags, 111 IPC::Message* reply_msg, 112 bool* did_suppress_message) { 113 // TODO(rafaelw): Implement, The JavaScriptModalDialog needs to learn about 114 // BackgroundContents. 115 *did_suppress_message = true; 116} 117 118bool BackgroundContents::PreHandleKeyboardEvent( 119 const NativeWebKeyboardEvent& event, 120 bool* is_keyboard_shortcut) { 121 return false; 122} 123 124void BackgroundContents::Observe(NotificationType type, 125 const NotificationSource& source, 126 const NotificationDetails& details) { 127 // TODO(rafaelw): Implement pagegroup ref-counting so that non-persistent 128 // background pages are closed when the last referencing frame is closed. 129 switch (type.value) { 130 case NotificationType::PROFILE_DESTROYED: 131 case NotificationType::APP_TERMINATING: { 132 delete this; 133 break; 134 } 135 default: 136 NOTREACHED() << "Unexpected notification sent."; 137 break; 138 } 139} 140 141void BackgroundContents::OnMessageBoxClosed(IPC::Message* reply_msg, 142 bool success, 143 const std::wstring& prompt) { 144 render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt); 145} 146 147gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() { 148 NOTIMPLEMENTED(); 149 return NULL; 150} 151 152TabContents* BackgroundContents::AsTabContents() { 153 return NULL; 154} 155 156ExtensionHost* BackgroundContents::AsExtensionHost() { 157 return NULL; 158} 159 160void BackgroundContents::UpdateInspectorSetting(const std::string& key, 161 const std::string& value) { 162 Profile* profile = render_view_host_->process()->profile(); 163 RenderViewHostDelegateHelper::UpdateInspectorSetting(profile, key, value); 164} 165 166void BackgroundContents::ClearInspectorSettings() { 167 Profile* profile = render_view_host_->process()->profile(); 168 RenderViewHostDelegateHelper::ClearInspectorSettings(profile); 169} 170 171void BackgroundContents::Close(RenderViewHost* render_view_host) { 172 Profile* profile = render_view_host->process()->profile(); 173 NotificationService::current()->Notify( 174 NotificationType::BACKGROUND_CONTENTS_CLOSED, 175 Source<Profile>(profile), 176 Details<BackgroundContents>(this)); 177 delete this; 178} 179 180void BackgroundContents::RenderViewGone(RenderViewHost* rvh, 181 base::TerminationStatus status, 182 int error_code) { 183 Profile* profile = rvh->process()->profile(); 184 NotificationService::current()->Notify( 185 NotificationType::BACKGROUND_CONTENTS_TERMINATED, 186 Source<Profile>(profile), 187 Details<BackgroundContents>(this)); 188 189 // Our RenderView went away, so we should go away also, so killing the process 190 // via the TaskManager doesn't permanently leave a BackgroundContents hanging 191 // around the system, blocking future instances from being created 192 // (http://crbug.com/65189). 193 delete this; 194} 195 196RendererPreferences BackgroundContents::GetRendererPrefs( 197 Profile* profile) const { 198 RendererPreferences preferences; 199 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 200 return preferences; 201} 202 203WebPreferences BackgroundContents::GetWebkitPrefs() { 204 // TODO(rafaelw): Consider enabling the webkit_prefs.dom_paste_enabled for 205 // apps. 206 Profile* profile = render_view_host_->process()->profile(); 207 return RenderViewHostDelegateHelper::GetWebkitPrefs(profile, 208 false); // is_web_ui 209} 210 211void BackgroundContents::ProcessWebUIMessage( 212 const ExtensionHostMsg_DomMessage_Params& params) { 213 // TODO(rafaelw): It may make sense for extensions to be able to open 214 // BackgroundContents to chrome-extension://<id> pages. Consider implementing. 215 render_view_host_->Send(new ExtensionMsg_Response( 216 render_view_host_->routing_id(), params.request_id, false, 217 std::string(), "Access to extension API denied.")); 218} 219 220void BackgroundContents::CreateNewWindow( 221 int route_id, 222 const ViewHostMsg_CreateWindow_Params& params) { 223 delegate_view_helper_.CreateNewWindow( 224 route_id, 225 render_view_host_->process()->profile(), 226 render_view_host_->site_instance(), 227 ChromeWebUIFactory::GetInstance()->GetWebUIType( 228 render_view_host_->process()->profile(), url_), 229 this, 230 params.window_container_type, 231 params.frame_name); 232} 233 234void BackgroundContents::CreateNewWidget(int route_id, 235 WebKit::WebPopupType popup_type) { 236 NOTREACHED(); 237} 238 239void BackgroundContents::CreateNewFullscreenWidget(int route_id) { 240 NOTREACHED(); 241} 242 243void BackgroundContents::ShowCreatedWindow(int route_id, 244 WindowOpenDisposition disposition, 245 const gfx::Rect& initial_pos, 246 bool user_gesture) { 247 TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); 248 if (contents) 249 delegate_->AddTabContents(contents, disposition, initial_pos, user_gesture); 250} 251 252void BackgroundContents::ShowCreatedWidget(int route_id, 253 const gfx::Rect& initial_pos) { 254 NOTIMPLEMENTED(); 255} 256 257void BackgroundContents::ShowCreatedFullscreenWidget(int route_id) { 258 NOTIMPLEMENTED(); 259} 260 261// static 262BackgroundContents* 263BackgroundContents::GetBackgroundContentsByID(int render_process_id, 264 int render_view_id) { 265 RenderViewHost* render_view_host = 266 RenderViewHost::FromID(render_process_id, render_view_id); 267 if (!render_view_host) 268 return NULL; 269 270 return render_view_host->delegate()->GetAsBackgroundContents(); 271} 272