Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / web_applications / web_app.cc
blob313e261886555939c2a2b6fec826a81f97149743
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/web_applications/web_app.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/i18n/file_util_icu.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread.h"
15 #include "chrome/browser/extensions/image_loader.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/favicon/favicon_tab_helper.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_version_info.h"
21 #include "chrome/common/extensions/api/file_handlers/file_handlers_parser.h"
22 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "extensions/common/constants.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/manifest_handlers/icons_handler.h"
29 #include "grit/theme_resources.h"
30 #include "skia/ext/image_operations.h"
31 #include "third_party/skia/include/core/SkBitmap.h"
32 #include "ui/base/resource/resource_bundle.h"
33 #include "ui/gfx/image/image.h"
34 #include "ui/gfx/image/image_family.h"
35 #include "ui/gfx/image/image_skia.h"
37 #if defined(OS_WIN)
38 #include "ui/gfx/icon_util.h"
39 #endif
41 using content::BrowserThread;
43 namespace {
45 typedef base::Callback<void(const web_app::ShortcutInfo&,
46 const extensions::FileHandlersInfo&)> InfoCallback;
48 #if defined(OS_MACOSX)
49 const int kDesiredSizes[] = {16, 32, 128, 256, 512};
50 const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
51 #elif defined(OS_LINUX)
52 // Linux supports icons of any size. FreeDesktop Icon Theme Specification states
53 // that "Minimally you should install a 48x48 icon in the hicolor theme."
54 const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
55 const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
56 #elif defined(OS_WIN)
57 const int* kDesiredSizes = IconUtil::kIconDimensions;
58 const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
59 #else
60 const int kDesiredSizes[] = {32};
61 const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
62 #endif
64 #if defined(TOOLKIT_VIEWS)
65 // Predicator for sorting images from largest to smallest.
66 bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
67 const WebApplicationInfo::IconInfo& right) {
68 return left.width < right.width;
70 #endif
72 bool CreateShortcutsWithInfoOnFileThread(
73 web_app::ShortcutCreationReason reason,
74 const web_app::ShortcutLocations& locations,
75 const web_app::ShortcutInfo& shortcut_info,
76 const extensions::FileHandlersInfo& file_handlers_info) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
79 base::FilePath shortcut_data_dir =
80 web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
81 shortcut_info.extension_id,
82 shortcut_info.url);
83 return web_app::internals::CreatePlatformShortcuts(
84 shortcut_data_dir, shortcut_info, file_handlers_info, locations, reason);
87 void DeleteShortcutsOnFileThread(
88 const web_app::ShortcutInfo& shortcut_info) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
91 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
92 shortcut_info.profile_path, shortcut_info.extension_id, GURL());
93 return web_app::internals::DeletePlatformShortcuts(
94 shortcut_data_dir, shortcut_info);
97 void UpdateShortcutsOnFileThread(
98 const base::string16& old_app_title,
99 const web_app::ShortcutInfo& shortcut_info,
100 const extensions::FileHandlersInfo& file_handlers_info) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
103 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
104 shortcut_info.profile_path, shortcut_info.extension_id, GURL());
105 return web_app::internals::UpdatePlatformShortcuts(
106 shortcut_data_dir, old_app_title, shortcut_info, file_handlers_info);
109 void CreateShortcutsWithInfo(
110 web_app::ShortcutCreationReason reason,
111 const web_app::ShortcutLocations& locations,
112 const web_app::ShortcutInfo& shortcut_info,
113 const extensions::FileHandlersInfo& file_handlers_info) {
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
116 BrowserThread::PostTask(
117 BrowserThread::FILE,
118 FROM_HERE,
119 base::Bind(
120 base::IgnoreResult(&CreateShortcutsWithInfoOnFileThread),
121 reason, locations, shortcut_info, file_handlers_info));
124 void UpdateAllShortcutsForShortcutInfo(
125 const base::string16& old_app_title,
126 const web_app::ShortcutInfo& shortcut_info,
127 const extensions::FileHandlersInfo& file_handlers_info) {
128 BrowserThread::PostTask(
129 BrowserThread::FILE,
130 FROM_HERE,
131 base::Bind(&UpdateShortcutsOnFileThread,
132 old_app_title, shortcut_info, file_handlers_info));
135 void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
136 extensions::FileHandlersInfo file_handlers_info,
137 InfoCallback callback,
138 const gfx::ImageFamily& image_family) {
139 // If the image failed to load (e.g. if the resource being loaded was empty)
140 // use the standard application icon.
141 if (image_family.empty()) {
142 gfx::Image default_icon =
143 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
144 int size = kDesiredSizes[kNumDesiredSizes - 1];
145 SkBitmap bmp = skia::ImageOperations::Resize(
146 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
147 size, size);
148 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
149 // We are on the UI thread, and this image is needed from the FILE thread,
150 // for creating shortcut icon files.
151 image_skia.MakeThreadSafe();
152 shortcut_info.favicon.Add(gfx::Image(image_skia));
153 } else {
154 shortcut_info.favicon = image_family;
157 callback.Run(shortcut_info, file_handlers_info);
160 void GetInfoForApp(const extensions::Extension* extension,
161 Profile* profile,
162 const InfoCallback& callback) {
163 web_app::ShortcutInfo shortcut_info =
164 web_app::ShortcutInfoForExtensionAndProfile(extension, profile);
165 extensions::FileHandlersInfo file_handlers_info;
166 const std::vector<extensions::FileHandlerInfo>* file_handlers =
167 extensions::FileHandlers::GetFileHandlers(extension);
168 if (file_handlers)
169 file_handlers_info.handlers = *file_handlers;
171 std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
172 for (size_t i = 0; i < kNumDesiredSizes; ++i) {
173 int size = kDesiredSizes[i];
174 extensions::ExtensionResource resource =
175 extensions::IconsInfo::GetIconResource(
176 extension, size, ExtensionIconSet::MATCH_EXACTLY);
177 if (!resource.empty()) {
178 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
179 resource,
180 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
181 gfx::Size(size, size),
182 ui::SCALE_FACTOR_100P));
186 if (info_list.empty()) {
187 size_t i = kNumDesiredSizes - 1;
188 int size = kDesiredSizes[i];
190 // If there is no icon at the desired sizes, we will resize what we can get.
191 // Making a large icon smaller is preferred to making a small icon larger,
192 // so look for a larger icon first:
193 extensions::ExtensionResource resource =
194 extensions::IconsInfo::GetIconResource(
195 extension, size, ExtensionIconSet::MATCH_BIGGER);
196 if (resource.empty()) {
197 resource = extensions::IconsInfo::GetIconResource(
198 extension, size, ExtensionIconSet::MATCH_SMALLER);
200 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
201 resource,
202 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
203 gfx::Size(size, size),
204 ui::SCALE_FACTOR_100P));
207 // |info_list| may still be empty at this point, in which case
208 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty
209 // image and exit immediately.
210 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync(
211 extension,
212 info_list,
213 base::Bind(&OnImageLoaded, shortcut_info, file_handlers_info, callback));
216 void IgnoreFileHandlersInfo(
217 const web_app::ShortcutInfoCallback& shortcut_info_callback,
218 const web_app::ShortcutInfo& shortcut_info,
219 const extensions::FileHandlersInfo& file_handlers_info) {
220 shortcut_info_callback.Run(shortcut_info);
223 } // namespace
225 namespace web_app {
227 // The following string is used to build the directory name for
228 // shortcuts to chrome applications (the kind which are installed
229 // from a CRX). Application shortcuts to URLs use the {host}_{path}
230 // for the name of this directory. Hosts can't include an underscore.
231 // By starting this string with an underscore, we ensure that there
232 // are no naming conflicts.
233 static const char* kCrxAppPrefix = "_crx_";
235 namespace internals {
237 base::FilePath GetSanitizedFileName(const base::string16& name) {
238 #if defined(OS_WIN)
239 base::string16 file_name = name;
240 #else
241 std::string file_name = base::UTF16ToUTF8(name);
242 #endif
243 file_util::ReplaceIllegalCharactersInPath(&file_name, '_');
244 return base::FilePath(file_name);
247 bool CreateShortcutsOnFileThread(
248 ShortcutCreationReason reason,
249 const web_app::ShortcutLocations& locations,
250 const web_app::ShortcutInfo& shortcut_info) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
253 return CreateShortcutsWithInfoOnFileThread(
254 reason, locations, shortcut_info, extensions::FileHandlersInfo());
257 } // namespace internals
259 web_app::ShortcutInfo::ShortcutInfo()
260 : is_platform_app(false) {
263 web_app::ShortcutInfo::~ShortcutInfo() {}
265 web_app::ShortcutLocations::ShortcutLocations()
266 : on_desktop(false),
267 applications_menu_location(APP_MENU_LOCATION_NONE),
268 in_quick_launch_bar(false)
269 #if defined(OS_POSIX)
270 , hidden(false)
271 #endif
275 void GetShortcutInfoForTab(content::WebContents* web_contents,
276 web_app::ShortcutInfo* info) {
277 DCHECK(info); // Must provide a valid info.
279 const FaviconTabHelper* favicon_tab_helper =
280 FaviconTabHelper::FromWebContents(web_contents);
281 const extensions::TabHelper* extensions_tab_helper =
282 extensions::TabHelper::FromWebContents(web_contents);
283 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
285 info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
286 app_info.app_url;
287 info->title = app_info.title.empty() ?
288 (web_contents->GetTitle().empty() ? base::UTF8ToUTF16(info->url.spec()) :
289 web_contents->GetTitle()) :
290 app_info.title;
291 info->description = app_info.description;
292 info->favicon.Add(favicon_tab_helper->GetFavicon());
294 Profile* profile =
295 Profile::FromBrowserContext(web_contents->GetBrowserContext());
296 info->profile_path = profile->GetPath();
299 #if !defined(OS_WIN)
300 void UpdateShortcutForTabContents(content::WebContents* web_contents) {}
301 #endif
303 web_app::ShortcutInfo ShortcutInfoForExtensionAndProfile(
304 const extensions::Extension* app, Profile* profile) {
305 web_app::ShortcutInfo shortcut_info;
306 shortcut_info.extension_id = app->id();
307 shortcut_info.is_platform_app = app->is_platform_app();
308 shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
309 shortcut_info.title = base::UTF8ToUTF16(app->name());
310 shortcut_info.description = base::UTF8ToUTF16(app->description());
311 shortcut_info.extension_path = app->path();
312 shortcut_info.profile_path = profile->GetPath();
313 shortcut_info.profile_name =
314 profile->GetPrefs()->GetString(prefs::kProfileName);
315 return shortcut_info;
318 void UpdateShortcutInfoAndIconForApp(
319 const extensions::Extension* extension,
320 Profile* profile,
321 const web_app::ShortcutInfoCallback& callback) {
322 GetInfoForApp(extension,
323 profile,
324 base::Bind(&IgnoreFileHandlersInfo, callback));
327 base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
328 const std::string& extension_id,
329 const GURL& url) {
330 DCHECK(!profile_path.empty());
331 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
333 if (!extension_id.empty()) {
334 return app_data_dir.AppendASCII(
335 GenerateApplicationNameFromExtensionId(extension_id));
338 std::string host(url.host());
339 std::string scheme(url.has_scheme() ? url.scheme() : "http");
340 std::string port(url.has_port() ? url.port() : "80");
341 std::string scheme_port(scheme + "_" + port);
343 #if defined(OS_WIN)
344 base::FilePath::StringType host_path(base::UTF8ToUTF16(host));
345 base::FilePath::StringType scheme_port_path(base::UTF8ToUTF16(scheme_port));
346 #elif defined(OS_POSIX)
347 base::FilePath::StringType host_path(host);
348 base::FilePath::StringType scheme_port_path(scheme_port);
349 #endif
351 return app_data_dir.Append(host_path).Append(scheme_port_path);
354 base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
355 const extensions::Extension& extension) {
356 return GetWebAppDataDirectory(
357 profile_path,
358 extension.id(),
359 GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
362 std::string GenerateApplicationNameFromInfo(
363 const web_app::ShortcutInfo& shortcut_info) {
364 if (!shortcut_info.extension_id.empty()) {
365 return web_app::GenerateApplicationNameFromExtensionId(
366 shortcut_info.extension_id);
367 } else {
368 return web_app::GenerateApplicationNameFromURL(
369 shortcut_info.url);
373 std::string GenerateApplicationNameFromURL(const GURL& url) {
374 std::string t;
375 t.append(url.host());
376 t.append("_");
377 t.append(url.path());
378 return t;
381 std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
382 std::string t(web_app::kCrxAppPrefix);
383 t.append(id);
384 return t;
387 std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
388 std::string prefix(kCrxAppPrefix);
389 if (app_name.substr(0, prefix.length()) != prefix)
390 return std::string();
391 return app_name.substr(prefix.length());
394 void CreateShortcutsForShortcutInfo(
395 web_app::ShortcutCreationReason reason,
396 const web_app::ShortcutLocations& locations,
397 const web_app::ShortcutInfo& shortcut_info) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400 BrowserThread::PostTask(
401 BrowserThread::FILE,
402 FROM_HERE,
403 base::Bind(
404 base::IgnoreResult(&web_app::internals::CreateShortcutsOnFileThread),
405 reason, locations, shortcut_info));
408 void CreateShortcuts(
409 ShortcutCreationReason reason,
410 const web_app::ShortcutLocations& locations,
411 Profile* profile,
412 const extensions::Extension* app) {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415 GetInfoForApp(app,
416 profile,
417 base::Bind(&CreateShortcutsWithInfo, reason, locations));
420 void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
421 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423 BrowserThread::PostTask(
424 BrowserThread::FILE,
425 FROM_HERE,
426 base::Bind(&DeleteShortcutsOnFileThread,
427 web_app::ShortcutInfoForExtensionAndProfile(app, profile)));
430 void UpdateAllShortcuts(const base::string16& old_app_title,
431 Profile* profile,
432 const extensions::Extension* app) {
433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
435 GetInfoForApp(app,
436 profile,
437 base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
440 bool IsValidUrl(const GURL& url) {
441 static const char* const kValidUrlSchemes[] = {
442 content::kFileScheme,
443 content::kFileSystemScheme,
444 content::kFtpScheme,
445 content::kHttpScheme,
446 content::kHttpsScheme,
447 extensions::kExtensionScheme,
450 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
451 if (url.SchemeIs(kValidUrlSchemes[i]))
452 return true;
455 return false;
458 #if defined(TOOLKIT_VIEWS)
459 void GetIconsInfo(const WebApplicationInfo& app_info,
460 IconInfoList* icons) {
461 DCHECK(icons);
463 icons->clear();
464 for (size_t i = 0; i < app_info.icons.size(); ++i) {
465 // We only take square shaped icons (i.e. width == height).
466 if (app_info.icons[i].width == app_info.icons[i].height) {
467 icons->push_back(app_info.icons[i]);
471 std::sort(icons->begin(), icons->end(), &IconPrecedes);
473 #endif
475 #if defined(OS_LINUX)
476 std::string GetWMClassFromAppName(std::string app_name) {
477 file_util::ReplaceIllegalCharactersInPath(&app_name, '_');
478 base::TrimString(app_name, "_", &app_name);
479 return app_name;
481 #endif
483 } // namespace web_app