balloon_host.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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/notifications/balloon_host.h"
6
7#include "chrome/browser/browser_list.h"
8#include "chrome/browser/extensions/extension_process_manager.h"
9#include "chrome/browser/notifications/balloon.h"
10#include "chrome/browser/notifications/notification.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/renderer_host/render_view_host.h"
13#include "chrome/browser/renderer_host/site_instance.h"
14#include "chrome/browser/renderer_preferences_util.h"
15#include "chrome/common/bindings_policy.h"
16#include "chrome/common/notification_service.h"
17#include "chrome/common/notification_type.h"
18#include "chrome/common/render_messages.h"
19#include "chrome/common/renderer_preferences.h"
20#include "chrome/common/url_constants.h"
21#include "webkit/glue/webpreferences.h"
22
23namespace {
24class BalloonPaintObserver : public RenderWidgetHost::PaintObserver {
25 public:
26  explicit BalloonPaintObserver(BalloonHost* balloon_host)
27      : balloon_host_(balloon_host) {
28  }
29
30  virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rhw) {}
31  virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh);
32
33 private:
34  BalloonHost* balloon_host_;
35
36  DISALLOW_COPY_AND_ASSIGN(BalloonPaintObserver);
37};
38
39void BalloonPaintObserver::RenderWidgetHostDidPaint(RenderWidgetHost* rwh) {
40  balloon_host_->RenderWidgetHostDidPaint();
41  // WARNING: we may have been deleted (if the balloon host cleared the paint
42  // observer).
43}
44
45}  // namespace
46
47BalloonHost::BalloonHost(Balloon* balloon)
48    : render_view_host_(NULL),
49      balloon_(balloon),
50      initialized_(false),
51      should_notify_on_disconnect_(false),
52      enable_dom_ui_(false) {
53  DCHECK(balloon_);
54
55  // If the notification is for an extension URL, make sure to use the extension
56  // process to render it, so that it can communicate with other views in the
57  // extension.
58  const GURL& balloon_url = balloon_->notification().content_url();
59  if (balloon_url.SchemeIs(chrome::kExtensionScheme)) {
60    site_instance_ =
61      balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL(
62          balloon_url);
63  } else {
64    site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile());
65  }
66}
67
68void BalloonHost::Shutdown() {
69  NotifyDisconnect();
70  if (render_view_host_) {
71    render_view_host_->Shutdown();
72    render_view_host_ = NULL;
73  }
74}
75
76Browser* BalloonHost::GetBrowser() const {
77  // Notifications aren't associated with a particular browser.
78  return NULL;
79}
80
81gfx::NativeView BalloonHost::GetNativeViewOfHost() {
82  // TODO(aa): Should this return the native view of the BalloonView*?
83  return NULL;
84}
85
86TabContents* BalloonHost::associated_tab_contents() const { return NULL; }
87
88const string16& BalloonHost::GetSource() const {
89  return balloon_->notification().display_source();
90}
91
92WebPreferences BalloonHost::GetWebkitPrefs() {
93  WebPreferences web_prefs =
94      RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(),
95                                                   enable_dom_ui_);
96  web_prefs.allow_scripts_to_close_windows = true;
97  return web_prefs;
98}
99
100SiteInstance* BalloonHost::GetSiteInstance() const {
101  return site_instance_.get();
102}
103
104Profile* BalloonHost::GetProfile() const {
105  return balloon_->profile();
106}
107
108const GURL& BalloonHost::GetURL() const {
109  return balloon_->notification().content_url();
110}
111
112void BalloonHost::Close(RenderViewHost* render_view_host) {
113  balloon_->CloseByScript();
114  NotifyDisconnect();
115}
116
117void BalloonHost::RenderViewCreated(RenderViewHost* render_view_host) {
118  render_view_host->Send(new ViewMsg_DisableScrollbarsForSmallWindows(
119      render_view_host->routing_id(), balloon_->min_scrollbar_size()));
120  render_view_host->WasResized();
121#if !defined(OS_MACOSX)
122  // TODO(levin): Make all of the code that went in originally with this change
123  // to be cross-platform. See http://crbug.com/64720
124  render_view_host->EnablePreferredSizeChangedMode(
125      kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
126#endif
127}
128
129void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) {
130  should_notify_on_disconnect_ = true;
131  NotificationService::current()->Notify(
132      NotificationType::NOTIFY_BALLOON_CONNECTED,
133      Source<BalloonHost>(this), NotificationService::NoDetails());
134}
135
136void BalloonHost::RenderViewGone(RenderViewHost* render_view_host,
137                                 base::TerminationStatus status,
138                                 int error_code) {
139  Close(render_view_host);
140}
141
142int BalloonHost::GetBrowserWindowID() const {
143  return extension_misc::kUnknownWindowId;
144}
145
146ViewType::Type BalloonHost::GetRenderViewType() const {
147  return ViewType::NOTIFICATION;
148}
149
150RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() {
151  return this;
152}
153
154void BalloonHost::ProcessDOMUIMessage(
155    const ViewHostMsg_DomMessage_Params& params) {
156  if (extension_function_dispatcher_.get()) {
157    extension_function_dispatcher_->HandleRequest(params);
158  }
159}
160
161// RenderViewHostDelegate::View methods implemented to allow links to
162// open pages in new tabs.
163void BalloonHost::CreateNewWindow(
164    int route_id,
165    WindowContainerType window_container_type,
166    const string16& frame_name) {
167  delegate_view_helper_.CreateNewWindow(
168      route_id,
169      balloon_->profile(),
170      site_instance_.get(),
171      DOMUIFactory::GetDOMUIType(balloon_->profile(),
172          balloon_->notification().content_url()),
173      this,
174      window_container_type,
175      frame_name);
176}
177
178void BalloonHost::ShowCreatedWindow(int route_id,
179                                    WindowOpenDisposition disposition,
180                                    const gfx::Rect& initial_pos,
181                                    bool user_gesture) {
182  // Don't allow pop-ups from notifications.
183  if (disposition == NEW_POPUP)
184    return;
185
186  TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id);
187  if (!contents)
188    return;
189  Browser* browser = BrowserList::GetLastActiveWithProfile(balloon_->profile());
190  if (!browser)
191    return;
192
193  browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
194}
195
196bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
197                                         bool* is_keyboard_shortcut) {
198  return false;
199}
200
201void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) {
202  balloon_->SetContentPreferredSize(new_size);
203}
204
205void BalloonHost::HandleMouseDown() {
206  balloon_->OnClick();
207}
208
209RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const {
210  RendererPreferences preferences;
211  renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
212  return preferences;
213}
214
215void BalloonHost::Init() {
216  DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
217  RenderViewHost* rvh = new RenderViewHost(
218      site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
219  if (GetProfile()->GetExtensionService()) {
220    extension_function_dispatcher_.reset(
221        ExtensionFunctionDispatcher::Create(
222            rvh, this, balloon_->notification().content_url()));
223  }
224  if (extension_function_dispatcher_.get()) {
225    rvh->AllowBindings(BindingsPolicy::EXTENSION);
226    rvh->set_is_extension_process(true);
227  } else if (enable_dom_ui_) {
228    rvh->AllowBindings(BindingsPolicy::DOM_UI);
229  }
230
231  // Do platform-specific initialization.
232  render_view_host_ = rvh;
233  InitRenderWidgetHostView();
234  DCHECK(render_widget_host_view());
235
236  rvh->set_view(render_widget_host_view());
237  rvh->CreateRenderView(string16());
238#if defined(OS_MACOSX)
239  rvh->set_paint_observer(new BalloonPaintObserver(this));
240#endif
241  rvh->NavigateToURL(balloon_->notification().content_url());
242
243  initialized_ = true;
244}
245
246void BalloonHost::EnableDOMUI() {
247  DCHECK(render_view_host_ == NULL) <<
248      "EnableDOMUI has to be called before a renderer is created.";
249  enable_dom_ui_ = true;
250}
251
252void BalloonHost::UpdateInspectorSetting(const std::string& key,
253                                         const std::string& value) {
254  RenderViewHostDelegateHelper::UpdateInspectorSetting(
255      GetProfile(), key, value);
256}
257
258void BalloonHost::ClearInspectorSettings() {
259  RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile());
260}
261
262void BalloonHost::RenderWidgetHostDidPaint() {
263  render_view_host_->set_paint_observer(NULL);
264  render_view_host_->EnablePreferredSizeChangedMode(
265      kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
266}
267
268BalloonHost::~BalloonHost() {
269  DCHECK(!render_view_host_);
270}
271
272void BalloonHost::NotifyDisconnect() {
273  if (!should_notify_on_disconnect_)
274    return;
275
276  should_notify_on_disconnect_ = false;
277  NotificationService::current()->Notify(
278      NotificationType::NOTIFY_BALLOON_DISCONNECTED,
279      Source<BalloonHost>(this), NotificationService::NoDetails());
280}
281