普通文本  |  270行  |  8.76 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/notifications/balloon_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/browser_render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/site_instance.h"
#include "content/common/bindings_policy.h"
#include "content/common/notification_service.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
#include "content/common/renderer_preferences.h"
#include "content/common/view_messages.h"
#include "webkit/glue/webpreferences.h"

BalloonHost::BalloonHost(Balloon* balloon)
    : render_view_host_(NULL),
      balloon_(balloon),
      initialized_(false),
      should_notify_on_disconnect_(false),
      enable_web_ui_(false) {
  DCHECK(balloon_);

  // If the notification is for an extension URL, make sure to use the extension
  // process to render it, so that it can communicate with other views in the
  // extension.
  const GURL& balloon_url = balloon_->notification().content_url();
  if (balloon_url.SchemeIs(chrome::kExtensionScheme)) {
    site_instance_ =
      balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL(
          balloon_url);
  } else {
    site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile());
  }
}

void BalloonHost::Shutdown() {
  NotifyDisconnect();
  if (render_view_host_) {
    render_view_host_->Shutdown();
    render_view_host_ = NULL;
  }
}

Browser* BalloonHost::GetBrowser() {
  // Notifications aren't associated with a particular browser.
  return NULL;
}

gfx::NativeView BalloonHost::GetNativeViewOfHost() {
  // TODO(aa): Should this return the native view of the BalloonView*?
  return NULL;
}

TabContents* BalloonHost::associated_tab_contents() const { return NULL; }

const string16& BalloonHost::GetSource() const {
  return balloon_->notification().display_source();
}

WebPreferences BalloonHost::GetWebkitPrefs() {
  WebPreferences web_prefs =
      RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(),
                                                   enable_web_ui_);
  web_prefs.allow_scripts_to_close_windows = true;
  return web_prefs;
}

SiteInstance* BalloonHost::GetSiteInstance() const {
  return site_instance_.get();
}

Profile* BalloonHost::GetProfile() const {
  return balloon_->profile();
}

const GURL& BalloonHost::GetURL() const {
  return balloon_->notification().content_url();
}

void BalloonHost::Close(RenderViewHost* render_view_host) {
  balloon_->CloseByScript();
  NotifyDisconnect();
}

void BalloonHost::RenderViewCreated(RenderViewHost* render_view_host) {
  render_view_host->Send(new ViewMsg_DisableScrollbarsForSmallWindows(
      render_view_host->routing_id(), balloon_->min_scrollbar_size()));
  render_view_host->WasResized();
#if !defined(OS_MACOSX)
  // TODO(levin): Make all of the code that went in originally with this change
  // to be cross-platform. See http://crbug.com/64720
  render_view_host->EnablePreferredSizeChangedMode(
      kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
#endif
}

void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) {
  should_notify_on_disconnect_ = true;
  NotificationService::current()->Notify(
      NotificationType::NOTIFY_BALLOON_CONNECTED,
      Source<BalloonHost>(this), NotificationService::NoDetails());
}

void BalloonHost::RenderViewGone(RenderViewHost* render_view_host,
                                 base::TerminationStatus status,
                                 int error_code) {
  Close(render_view_host);
}

int BalloonHost::GetBrowserWindowID() const {
  return extension_misc::kUnknownWindowId;
}

ViewType::Type BalloonHost::GetRenderViewType() const {
  return ViewType::NOTIFICATION;
}

RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() {
  return this;
}

void BalloonHost::ProcessWebUIMessage(
    const ExtensionHostMsg_DomMessage_Params& params) {
  if (extension_function_dispatcher_.get()) {
    extension_function_dispatcher_->HandleRequest(params);
  }
}

// RenderViewHostDelegate::View methods implemented to allow links to
// open pages in new tabs.
void BalloonHost::CreateNewWindow(
    int route_id,
    const ViewHostMsg_CreateWindow_Params& params) {
  delegate_view_helper_.CreateNewWindow(
      route_id,
      balloon_->profile(),
      site_instance_.get(),
      ChromeWebUIFactory::GetInstance()->GetWebUIType(balloon_->profile(),
          balloon_->notification().content_url()),
      this,
      params.window_container_type,
      params.frame_name);
}

void BalloonHost::ShowCreatedWindow(int route_id,
                                    WindowOpenDisposition disposition,
                                    const gfx::Rect& initial_pos,
                                    bool user_gesture) {
  // Don't allow pop-ups from notifications.
  if (disposition == NEW_POPUP)
    return;

  TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id);
  if (!contents)
    return;
  Browser* browser = BrowserList::GetLastActiveWithProfile(balloon_->profile());
  if (!browser)
    return;

  browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
}

bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
                                         bool* is_keyboard_shortcut) {
  return false;
}

void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) {
  balloon_->SetContentPreferredSize(new_size);
}

void BalloonHost::HandleMouseDown() {
  balloon_->OnClick();
}

RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const {
  RendererPreferences preferences;
  renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
  return preferences;
}

void BalloonHost::Init() {
  DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
  RenderViewHost* rvh = new RenderViewHost(
      site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
  if (GetProfile()->GetExtensionService()) {
    extension_function_dispatcher_.reset(
        ExtensionFunctionDispatcher::Create(
            rvh, this, balloon_->notification().content_url()));
  }
  if (extension_function_dispatcher_.get()) {
    rvh->AllowBindings(BindingsPolicy::EXTENSION);
    rvh->set_is_extension_process(true);
    const Extension* installed_app =
        GetProfile()->GetExtensionService()->GetInstalledApp(
            balloon_->notification().content_url());
    static_cast<BrowserRenderProcessHost*>(rvh->process())->set_installed_app(
        installed_app);
  } else if (enable_web_ui_) {
    rvh->AllowBindings(BindingsPolicy::WEB_UI);
  }

  // Do platform-specific initialization.
  render_view_host_ = rvh;
  InitRenderWidgetHostView();
  DCHECK(render_widget_host_view());

  rvh->set_view(render_widget_host_view());
  rvh->CreateRenderView(string16());
#if defined(OS_MACOSX)
  registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT,
      Source<RenderWidgetHost>(render_view_host_));
#endif
  rvh->NavigateToURL(balloon_->notification().content_url());

  initialized_ = true;
}

void BalloonHost::EnableWebUI() {
  DCHECK(render_view_host_ == NULL) <<
      "EnableWebUI has to be called before a renderer is created.";
  enable_web_ui_ = true;
}

void BalloonHost::UpdateInspectorSetting(const std::string& key,
                                         const std::string& value) {
  RenderViewHostDelegateHelper::UpdateInspectorSetting(
      GetProfile(), key, value);
}

void BalloonHost::ClearInspectorSettings() {
  RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile());
}

void BalloonHost::Observe(NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  if (type == NotificationType::RENDER_WIDGET_HOST_DID_PAINT) {
    registrar_.RemoveAll();
    render_view_host_->EnablePreferredSizeChangedMode(
        kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
  }
}

BalloonHost::~BalloonHost() {
  DCHECK(!render_view_host_);
}

void BalloonHost::NotifyDisconnect() {
  if (!should_notify_on_disconnect_)
    return;

  should_notify_on_disconnect_ = false;
  NotificationService::current()->Notify(
      NotificationType::NOTIFY_BALLOON_DISCONNECTED,
      Source<BalloonHost>(this), NotificationService::NoDetails());
}