1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/panels/panel_host.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
12 #include "chrome/browser/extensions/window_controller.h"
13 #include "chrome/browser/favicon/favicon_tab_helper.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sessions/session_tab_helper.h"
16 #include "chrome/browser/ui/browser_navigator.h"
17 #include "chrome/browser/ui/panels/panel.h"
18 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
19 #include "components/ui/zoom/page_zoom.h"
20 #include "components/ui/zoom/zoom_controller.h"
21 #include "content/public/browser/invalidate_type.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/site_instance.h"
28 #include "content/public/browser/user_metrics.h"
29 #include "content/public/browser/web_contents.h"
30 #include "extensions/browser/view_type_utils.h"
31 #include "extensions/common/extension_messages.h"
32 #include "ipc/ipc_message.h"
33 #include "ipc/ipc_message_macros.h"
34 #include "ui/gfx/geometry/rect.h"
35 #include "ui/gfx/image/image.h"
37 using base::UserMetricsAction
;
39 PanelHost::PanelHost(Panel
* panel
, Profile
* profile
)
42 extension_function_dispatcher_(profile
, this),
46 PanelHost::~PanelHost() {
49 void PanelHost::Init(const GURL
& url
) {
53 content::WebContents::CreateParams
create_params(
54 profile_
, content::SiteInstance::CreateForURL(profile_
, url
));
55 web_contents_
.reset(content::WebContents::Create(create_params
));
56 extensions::SetViewType(web_contents_
.get(), extensions::VIEW_TYPE_PANEL
);
57 web_contents_
->SetDelegate(this);
58 // web_contents_ may be passed to PageZoom::Zoom(), so it needs
60 ui_zoom::ZoomController::CreateForWebContents(web_contents_
.get());
61 content::WebContentsObserver::Observe(web_contents_
.get());
63 // Needed to give the web contents a Tab ID. Extension APIs
64 // expect web contents to have a Tab ID.
65 SessionTabHelper::CreateForWebContents(web_contents_
.get());
66 SessionTabHelper::FromWebContents(web_contents_
.get())->SetWindowID(
67 panel_
->session_id());
69 FaviconTabHelper::CreateForWebContents(web_contents_
.get());
70 PrefsTabHelper::CreateForWebContents(web_contents_
.get());
71 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
74 web_contents_
->GetController().LoadURL(
75 url
, content::Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
78 void PanelHost::DestroyWebContents() {
79 // Cannot do a web_contents_.reset() because web_contents_.get() will
80 // still return the pointer when we CHECK in WebContentsDestroyed (or if
81 // we get called back in the middle of web contents destruction, which
82 // WebView might do when it detects the web contents is destroyed).
83 content::WebContents
* contents
= web_contents_
.release();
87 gfx::Image
PanelHost::GetPageIcon() const {
88 if (!web_contents_
.get())
91 FaviconTabHelper
* favicon_tab_helper
=
92 FaviconTabHelper::FromWebContents(web_contents_
.get());
93 CHECK(favicon_tab_helper
);
94 return favicon_tab_helper
->GetFavicon();
97 content::WebContents
* PanelHost::OpenURLFromTab(
98 content::WebContents
* source
,
99 const content::OpenURLParams
& params
) {
100 // These dispositions aren't really navigations.
101 if (params
.disposition
== SUPPRESS_OPEN
||
102 params
.disposition
== SAVE_TO_DISK
||
103 params
.disposition
== IGNORE_ACTION
)
106 // Only allow clicks on links.
107 if (params
.transition
!= ui::PAGE_TRANSITION_LINK
)
110 // Force all links to open in a new tab.
111 chrome::NavigateParams
navigate_params(profile_
,
114 switch (params
.disposition
) {
115 case NEW_BACKGROUND_TAB
:
118 navigate_params
.disposition
= params
.disposition
;
121 navigate_params
.disposition
= NEW_FOREGROUND_TAB
;
124 chrome::Navigate(&navigate_params
);
125 return navigate_params
.target_contents
;
128 void PanelHost::NavigationStateChanged(content::WebContents
* source
,
129 content::InvalidateTypes changed_flags
) {
130 // Only need to update the title if the title changed while not loading,
131 // because the title is also updated when loading state changes.
132 if ((changed_flags
& content::INVALIDATE_TYPE_TAB
) ||
133 ((changed_flags
& content::INVALIDATE_TYPE_TITLE
) &&
134 !source
->IsLoading()))
135 panel_
->UpdateTitleBar();
138 void PanelHost::AddNewContents(content::WebContents
* source
,
139 content::WebContents
* new_contents
,
140 WindowOpenDisposition disposition
,
141 const gfx::Rect
& initial_rect
,
144 chrome::NavigateParams
navigate_params(profile_
, new_contents
->GetURL(),
145 ui::PAGE_TRANSITION_LINK
);
146 navigate_params
.target_contents
= new_contents
;
148 // Force all links to open in a new tab, even if they were trying to open a
150 navigate_params
.disposition
=
151 disposition
== NEW_BACKGROUND_TAB
? disposition
: NEW_FOREGROUND_TAB
;
153 navigate_params
.window_bounds
= initial_rect
;
154 navigate_params
.user_gesture
= user_gesture
;
155 navigate_params
.extension_app_id
= panel_
->extension_id();
156 chrome::Navigate(&navigate_params
);
159 void PanelHost::ActivateContents(content::WebContents
* contents
) {
163 void PanelHost::DeactivateContents(content::WebContents
* contents
) {
164 panel_
->Deactivate();
167 void PanelHost::LoadingStateChanged(content::WebContents
* source
,
168 bool to_different_document
) {
169 bool is_loading
= source
->IsLoading() && to_different_document
;
170 panel_
->LoadingStateChanged(is_loading
);
173 void PanelHost::CloseContents(content::WebContents
* source
) {
177 void PanelHost::MoveContents(content::WebContents
* source
,
178 const gfx::Rect
& pos
) {
179 panel_
->SetBounds(pos
);
182 bool PanelHost::IsPopupOrPanel(const content::WebContents
* source
) const {
186 void PanelHost::ContentsZoomChange(bool zoom_in
) {
187 Zoom(zoom_in
? content::PAGE_ZOOM_IN
: content::PAGE_ZOOM_OUT
);
190 void PanelHost::HandleKeyboardEvent(
191 content::WebContents
* source
,
192 const content::NativeWebKeyboardEvent
& event
) {
193 return panel_
->HandleKeyboardEvent(event
);
196 void PanelHost::WebContentsFocused(content::WebContents
* contents
) {
197 panel_
->WebContentsFocused(contents
);
200 void PanelHost::ResizeDueToAutoResize(content::WebContents
* web_contents
,
201 const gfx::Size
& new_size
) {
202 panel_
->OnContentsAutoResized(new_size
);
205 void PanelHost::RenderViewCreated(content::RenderViewHost
* render_view_host
) {
206 extensions::WindowController
* window
= GetExtensionWindowController();
207 render_view_host
->Send(new ExtensionMsg_UpdateBrowserWindowId(
208 render_view_host
->GetRoutingID(), window
->GetWindowId()));
211 void PanelHost::RenderProcessGone(base::TerminationStatus status
) {
212 CloseContents(web_contents_
.get());
215 void PanelHost::WebContentsDestroyed() {
216 // Web contents should only be destroyed by us.
217 CHECK(!web_contents_
.get());
219 // Close the panel after we return to the message loop (not immediately,
220 // otherwise, it may destroy this object before the stack has a chance
221 // to cleanly unwind.)
222 base::MessageLoop::current()->PostTask(
224 base::Bind(&PanelHost::ClosePanel
, weak_factory_
.GetWeakPtr()));
227 void PanelHost::ClosePanel() {
231 bool PanelHost::OnMessageReceived(const IPC::Message
& message
) {
233 IPC_BEGIN_MESSAGE_MAP(PanelHost
, message
)
234 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request
, OnRequest
)
235 IPC_MESSAGE_UNHANDLED(handled
= false)
236 IPC_END_MESSAGE_MAP()
240 void PanelHost::OnRequest(const ExtensionHostMsg_Request_Params
& params
) {
241 if (!web_contents_
.get())
244 extension_function_dispatcher_
.Dispatch(params
,
245 web_contents_
->GetRenderViewHost());
248 extensions::WindowController
* PanelHost::GetExtensionWindowController() const {
249 return panel_
->extension_window_controller();
252 content::WebContents
* PanelHost::GetAssociatedWebContents() const {
253 return web_contents_
.get();
256 void PanelHost::Reload() {
257 content::RecordAction(UserMetricsAction("Reload"));
258 web_contents_
->GetController().Reload(true);
261 void PanelHost::ReloadIgnoringCache() {
262 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
263 web_contents_
->GetController().ReloadIgnoringCache(true);
266 void PanelHost::StopLoading() {
267 content::RecordAction(UserMetricsAction("Stop"));
268 web_contents_
->Stop();
271 void PanelHost::Zoom(content::PageZoom zoom
) {
272 ui_zoom::PageZoom::Zoom(web_contents_
.get(), zoom
);