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 26 BackgroundContents::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. 47 BackgroundContents::BackgroundContents() 48 : delegate_(NULL), 49 render_view_host_(NULL) { 50 } 51 52 BackgroundContents::~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 63 BackgroundContents* BackgroundContents::GetAsBackgroundContents() { 64 return this; 65 } 66 67 RenderViewHostDelegate::View* BackgroundContents::GetViewDelegate() { 68 return this; 69 } 70 71 const GURL& BackgroundContents::GetURL() const { 72 return url_; 73 } 74 75 ViewType::Type BackgroundContents::GetRenderViewType() const { 76 return ViewType::BACKGROUND_CONTENTS; 77 } 78 79 int BackgroundContents::GetBrowserWindowID() const { 80 return extension_misc::kUnknownWindowId; 81 } 82 83 void 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 106 void 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 118 bool BackgroundContents::PreHandleKeyboardEvent( 119 const NativeWebKeyboardEvent& event, 120 bool* is_keyboard_shortcut) { 121 return false; 122 } 123 124 void 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 141 void 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 147 gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() { 148 NOTIMPLEMENTED(); 149 return NULL; 150 } 151 152 TabContents* BackgroundContents::AsTabContents() { 153 return NULL; 154 } 155 156 ExtensionHost* BackgroundContents::AsExtensionHost() { 157 return NULL; 158 } 159 160 void 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 166 void BackgroundContents::ClearInspectorSettings() { 167 Profile* profile = render_view_host_->process()->profile(); 168 RenderViewHostDelegateHelper::ClearInspectorSettings(profile); 169 } 170 171 void 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 180 void 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 196 RendererPreferences BackgroundContents::GetRendererPrefs( 197 Profile* profile) const { 198 RendererPreferences preferences; 199 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 200 return preferences; 201 } 202 203 WebPreferences 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 211 void 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 220 void 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 234 void BackgroundContents::CreateNewWidget(int route_id, 235 WebKit::WebPopupType popup_type) { 236 NOTREACHED(); 237 } 238 239 void BackgroundContents::CreateNewFullscreenWidget(int route_id) { 240 NOTREACHED(); 241 } 242 243 void 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 252 void BackgroundContents::ShowCreatedWidget(int route_id, 253 const gfx::Rect& initial_pos) { 254 NOTIMPLEMENTED(); 255 } 256 257 void BackgroundContents::ShowCreatedFullscreenWidget(int route_id) { 258 NOTIMPLEMENTED(); 259 } 260 261 // static 262 BackgroundContents* 263 BackgroundContents::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