1 // Copyright 2014 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/ui/apps/chrome_app_window_delegate.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/favicon/favicon_tab_helper.h"
10 #include "chrome/browser/file_select_helper.h"
11 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
12 #include "chrome/browser/platform_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/shell_integration.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_dialogs.h"
17 #include "chrome/browser/ui/browser_tabstrip.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
20 #include "chrome/common/render_messages.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_delegate.h"
25 #include "extensions/common/constants.h"
26
27 #if defined(USE_ASH)
28 #include "ash/shelf/shelf_constants.h"
29 #endif
30
31 #if defined(ENABLE_PRINTING)
32 #if defined(ENABLE_FULL_PRINTING)
33 #include "chrome/browser/printing/print_preview_message_handler.h"
34 #include "chrome/browser/printing/print_view_manager.h"
35 #else
36 #include "chrome/browser/printing/print_view_manager_basic.h"
37 #endif // defined(ENABLE_FULL_PRINTING)
38 #endif // defined(ENABLE_PRINTING)
39
40 namespace {
41
42 bool disable_external_open_for_testing_ = false;
43
44 // Opens a URL with Chromium (not external browser) with the right profile.
OpenURLFromTabInternal(content::BrowserContext * context,const content::OpenURLParams & params)45 content::WebContents* OpenURLFromTabInternal(
46 content::BrowserContext* context,
47 const content::OpenURLParams& params) {
48 // Force all links to open in a new tab, even if they were trying to open a
49 // window.
50 chrome::NavigateParams new_tab_params(
51 static_cast<Browser*>(NULL), params.url, params.transition);
52 if (params.disposition == NEW_BACKGROUND_TAB) {
53 new_tab_params.disposition = NEW_BACKGROUND_TAB;
54 } else {
55 new_tab_params.disposition = NEW_FOREGROUND_TAB;
56 new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
57 }
58
59 new_tab_params.initiating_profile = Profile::FromBrowserContext(context);
60 chrome::Navigate(&new_tab_params);
61
62 return new_tab_params.target_contents;
63 }
64
65 // Helper class that opens a URL based on if this browser instance is the
66 // default system browser. If it is the default, open the URL directly instead
67 // of asking the system to open it.
68 class OpenURLFromTabBasedOnBrowserDefault
69 : public ShellIntegration::DefaultWebClientObserver {
70 public:
OpenURLFromTabBasedOnBrowserDefault(scoped_ptr<content::WebContents> source,const content::OpenURLParams & params)71 OpenURLFromTabBasedOnBrowserDefault(scoped_ptr<content::WebContents> source,
72 const content::OpenURLParams& params)
73 : source_(source.Pass()), params_(params) {}
74
75 // Opens a URL when called with the result of if this is the default system
76 // browser or not.
SetDefaultWebClientUIState(ShellIntegration::DefaultWebClientUIState state)77 virtual void SetDefaultWebClientUIState(
78 ShellIntegration::DefaultWebClientUIState state) OVERRIDE {
79 Profile* profile =
80 Profile::FromBrowserContext(source_->GetBrowserContext());
81 DCHECK(profile);
82 if (!profile)
83 return;
84 switch (state) {
85 case ShellIntegration::STATE_PROCESSING:
86 break;
87 case ShellIntegration::STATE_IS_DEFAULT:
88 OpenURLFromTabInternal(profile, params_);
89 break;
90 case ShellIntegration::STATE_NOT_DEFAULT:
91 case ShellIntegration::STATE_UNKNOWN:
92 platform_util::OpenExternal(profile, params_.url);
93 break;
94 }
95 }
96
IsOwnedByWorker()97 virtual bool IsOwnedByWorker() OVERRIDE { return true; }
98
99 private:
100 scoped_ptr<content::WebContents> source_;
101 const content::OpenURLParams params_;
102 };
103
104 } // namespace
105
106 class ChromeAppWindowDelegate::NewWindowContentsDelegate
107 : public content::WebContentsDelegate {
108 public:
NewWindowContentsDelegate()109 NewWindowContentsDelegate() {}
~NewWindowContentsDelegate()110 virtual ~NewWindowContentsDelegate() {}
111
112 virtual content::WebContents* OpenURLFromTab(
113 content::WebContents* source,
114 const content::OpenURLParams& params) OVERRIDE;
115
116 private:
117 DISALLOW_COPY_AND_ASSIGN(NewWindowContentsDelegate);
118 };
119
120 content::WebContents*
OpenURLFromTab(content::WebContents * source,const content::OpenURLParams & params)121 ChromeAppWindowDelegate::NewWindowContentsDelegate::OpenURLFromTab(
122 content::WebContents* source,
123 const content::OpenURLParams& params) {
124 if (source) {
125 // This NewWindowContentsDelegate was given ownership of the incoming
126 // WebContents by being assigned as its delegate within
127 // ChromeAppWindowDelegate::AddNewContents, but this is the first time
128 // NewWindowContentsDelegate actually sees the WebContents.
129 // Here it is captured for deletion.
130 scoped_ptr<content::WebContents> owned_source(source);
131 scoped_refptr<ShellIntegration::DefaultWebClientWorker>
132 check_if_default_browser_worker =
133 new ShellIntegration::DefaultBrowserWorker(
134 new OpenURLFromTabBasedOnBrowserDefault(owned_source.Pass(),
135 params));
136 // Object lifetime notes: The OpenURLFromTabBasedOnBrowserDefault is owned
137 // by check_if_default_browser_worker. StartCheckIsDefault() takes lifetime
138 // ownership of check_if_default_browser_worker and will clean up after
139 // the asynchronous tasks.
140 check_if_default_browser_worker->StartCheckIsDefault();
141 }
142 return NULL;
143 }
144
ChromeAppWindowDelegate()145 ChromeAppWindowDelegate::ChromeAppWindowDelegate()
146 : new_window_contents_delegate_(new NewWindowContentsDelegate()) {}
147
~ChromeAppWindowDelegate()148 ChromeAppWindowDelegate::~ChromeAppWindowDelegate() {}
149
DisableExternalOpenForTesting()150 void ChromeAppWindowDelegate::DisableExternalOpenForTesting() {
151 disable_external_open_for_testing_ = true;
152 }
153
InitWebContents(content::WebContents * web_contents)154 void ChromeAppWindowDelegate::InitWebContents(
155 content::WebContents* web_contents) {
156 FaviconTabHelper::CreateForWebContents(web_contents);
157
158 #if defined(ENABLE_PRINTING)
159 #if defined(ENABLE_FULL_PRINTING)
160 printing::PrintViewManager::CreateForWebContents(web_contents);
161 printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
162 #else
163 printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
164 #endif // defined(ENABLE_FULL_PRINTING)
165 #endif // defined(ENABLE_PRINTING)
166 }
167
CreateNativeAppWindow(apps::AppWindow * window,const apps::AppWindow::CreateParams & params)168 apps::NativeAppWindow* ChromeAppWindowDelegate::CreateNativeAppWindow(
169 apps::AppWindow* window,
170 const apps::AppWindow::CreateParams& params) {
171 return CreateNativeAppWindowImpl(window, params);
172 }
173
OpenURLFromTab(content::BrowserContext * context,content::WebContents * source,const content::OpenURLParams & params)174 content::WebContents* ChromeAppWindowDelegate::OpenURLFromTab(
175 content::BrowserContext* context,
176 content::WebContents* source,
177 const content::OpenURLParams& params) {
178 return OpenURLFromTabInternal(context, params);
179 }
180
AddNewContents(content::BrowserContext * context,content::WebContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture,bool * was_blocked)181 void ChromeAppWindowDelegate::AddNewContents(content::BrowserContext* context,
182 content::WebContents* new_contents,
183 WindowOpenDisposition disposition,
184 const gfx::Rect& initial_pos,
185 bool user_gesture,
186 bool* was_blocked) {
187 if (!disable_external_open_for_testing_) {
188 // We don't really want to open a window for |new_contents|, but we need to
189 // capture its intended navigation. Here we give ownership to the
190 // NewWindowContentsDelegate, which will dispose of the contents once
191 // a navigation is captured.
192 new_contents->SetDelegate(new_window_contents_delegate_.get());
193 return;
194 }
195 chrome::ScopedTabbedBrowserDisplayer displayer(
196 Profile::FromBrowserContext(context), chrome::GetActiveDesktop());
197 // Force all links to open in a new tab, even if they were trying to open a
198 // new window.
199 disposition =
200 disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
201 chrome::AddWebContents(displayer.browser(), NULL, new_contents, disposition,
202 initial_pos, user_gesture, was_blocked);
203 }
204
ShowColorChooser(content::WebContents * web_contents,SkColor initial_color)205 content::ColorChooser* ChromeAppWindowDelegate::ShowColorChooser(
206 content::WebContents* web_contents,
207 SkColor initial_color) {
208 return chrome::ShowColorChooser(web_contents, initial_color);
209 }
210
RunFileChooser(content::WebContents * tab,const content::FileChooserParams & params)211 void ChromeAppWindowDelegate::RunFileChooser(
212 content::WebContents* tab,
213 const content::FileChooserParams& params) {
214 FileSelectHelper::RunFileChooser(tab, params);
215 }
216
RequestMediaAccessPermission(content::WebContents * web_contents,const content::MediaStreamRequest & request,const content::MediaResponseCallback & callback,const extensions::Extension * extension)217 void ChromeAppWindowDelegate::RequestMediaAccessPermission(
218 content::WebContents* web_contents,
219 const content::MediaStreamRequest& request,
220 const content::MediaResponseCallback& callback,
221 const extensions::Extension* extension) {
222 MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
223 web_contents, request, callback, extension);
224 }
225
PreferredIconSize()226 int ChromeAppWindowDelegate::PreferredIconSize() {
227 #if defined(USE_ASH)
228 return ash::kShelfSize;
229 #else
230 return extension_misc::EXTENSION_ICON_SMALL;
231 #endif
232 }
233
SetWebContentsBlocked(content::WebContents * web_contents,bool blocked)234 void ChromeAppWindowDelegate::SetWebContentsBlocked(
235 content::WebContents* web_contents,
236 bool blocked) {
237 // RenderViewHost may be NULL during shutdown.
238 content::RenderViewHost* host = web_contents->GetRenderViewHost();
239 if (host) {
240 host->Send(new ChromeViewMsg_SetVisuallyDeemphasized(
241 host->GetRoutingID(), blocked));
242 }
243 }
244
IsWebContentsVisible(content::WebContents * web_contents)245 bool ChromeAppWindowDelegate::IsWebContentsVisible(
246 content::WebContents* web_contents) {
247 return platform_util::IsVisible(web_contents->GetNativeView());
248 }
249