普通文本  |  272行  |  9.59 KB

// 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();
}