blob: c994fad1707416a4e41e2e5a5d8febb36e6f14d5 [file] [log] [blame]
// Copyright (c) 2011 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/background_contents_service.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/view_types.h"
#include "content/browser/browsing_instance.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/site_instance.h"
#include "content/common/notification_service.h"
#include "content/common/view_messages.h"
#include "ui/gfx/rect.h"
////////////////
// BackgroundContents
BackgroundContents::BackgroundContents(SiteInstance* site_instance,
int routing_id,
Delegate* delegate)
: delegate_(delegate) {
Profile* profile = site_instance->browsing_instance()->profile();
// TODO(rafaelw): Implement correct session storage.
render_view_host_ = new RenderViewHost(site_instance, this, routing_id, NULL);
// Close ourselves when the application is shutting down.
registrar_.Add(this, NotificationType::APP_TERMINATING,
NotificationService::AllSources());
// Register for our parent profile to shutdown, so we can shut ourselves down
// as well (should only be called for OTR profiles, as we should receive
// APP_TERMINATING before non-OTR profiles are destroyed).
registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile));
}
// Exposed to allow creating mocks.
BackgroundContents::BackgroundContents()
: delegate_(NULL),
render_view_host_(NULL) {
}
BackgroundContents::~BackgroundContents() {
if (!render_view_host_) // Will be null for unit tests.
return;
Profile* profile = render_view_host_->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_DELETED,
Source<Profile>(profile),
Details<BackgroundContents>(this));
render_view_host_->Shutdown(); // deletes render_view_host
}
BackgroundContents* BackgroundContents::GetAsBackgroundContents() {
return this;
}
RenderViewHostDelegate::View* BackgroundContents::GetViewDelegate() {
return this;
}
const GURL& BackgroundContents::GetURL() const {
return url_;
}
ViewType::Type BackgroundContents::GetRenderViewType() const {
return ViewType::BACKGROUND_CONTENTS;
}
int BackgroundContents::GetBrowserWindowID() const {
return extension_misc::kUnknownWindowId;
}
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;
Profile* profile = render_view_host->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
Source<Profile>(profile),
Details<BackgroundContents>(this));
}
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;
}
bool BackgroundContents::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
return false;
}
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) {
case NotificationType::PROFILE_DESTROYED:
case NotificationType::APP_TERMINATING: {
delete this;
break;
}
default:
NOTREACHED() << "Unexpected notification sent.";
break;
}
}
void BackgroundContents::OnMessageBoxClosed(IPC::Message* reply_msg,
bool success,
const std::wstring& prompt) {
render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt);
}
gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() {
NOTIMPLEMENTED();
return NULL;
}
TabContents* BackgroundContents::AsTabContents() {
return NULL;
}
ExtensionHost* BackgroundContents::AsExtensionHost() {
return NULL;
}
void BackgroundContents::UpdateInspectorSetting(const std::string& key,
const std::string& value) {
Profile* profile = render_view_host_->process()->profile();
RenderViewHostDelegateHelper::UpdateInspectorSetting(profile, key, value);
}
void BackgroundContents::ClearInspectorSettings() {
Profile* profile = render_view_host_->process()->profile();
RenderViewHostDelegateHelper::ClearInspectorSettings(profile);
}
void BackgroundContents::Close(RenderViewHost* render_view_host) {
Profile* profile = render_view_host->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_CLOSED,
Source<Profile>(profile),
Details<BackgroundContents>(this));
delete this;
}
void BackgroundContents::RenderViewGone(RenderViewHost* rvh,
base::TerminationStatus status,
int error_code) {
Profile* profile = rvh->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_TERMINATED,
Source<Profile>(profile),
Details<BackgroundContents>(this));
// Our RenderView went away, so we should go away also, so killing the process
// via the TaskManager doesn't permanently leave a BackgroundContents hanging
// around the system, blocking future instances from being created
// (http://crbug.com/65189).
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_web_ui
}
void BackgroundContents::ProcessWebUIMessage(
const ExtensionHostMsg_DomMessage_Params& params) {
// TODO(rafaelw): It may make sense for extensions to be able to open
// BackgroundContents to chrome-extension://<id> pages. Consider implementing.
render_view_host_->Send(new ExtensionMsg_Response(
render_view_host_->routing_id(), params.request_id, false,
std::string(), "Access to extension API denied."));
}
void BackgroundContents::CreateNewWindow(
int route_id,
const ViewHostMsg_CreateWindow_Params& params) {
delegate_view_helper_.CreateNewWindow(
route_id,
render_view_host_->process()->profile(),
render_view_host_->site_instance(),
ChromeWebUIFactory::GetInstance()->GetWebUIType(
render_view_host_->process()->profile(), url_),
this,
params.window_container_type,
params.frame_name);
}
void BackgroundContents::CreateNewWidget(int route_id,
WebKit::WebPopupType popup_type) {
NOTREACHED();
}
void BackgroundContents::CreateNewFullscreenWidget(int route_id) {
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)
delegate_->AddTabContents(contents, disposition, initial_pos, user_gesture);
}
void BackgroundContents::ShowCreatedWidget(int route_id,
const gfx::Rect& initial_pos) {
NOTIMPLEMENTED();
}
void BackgroundContents::ShowCreatedFullscreenWidget(int route_id) {
NOTIMPLEMENTED();
}
// static
BackgroundContents*
BackgroundContents::GetBackgroundContentsByID(int render_process_id,
int render_view_id) {
RenderViewHost* render_view_host =
RenderViewHost::FromID(render_process_id, render_view_id);
if (!render_view_host)
return NULL;
return render_view_host->delegate()->GetAsBackgroundContents();
}