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