| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/web_applications/web_app_ui.h" | 5 #include "chrome/browser/ui/web_applications/web_app_ui.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
| 11 #include "base/prefs/pref_service.h" | |
| 12 #include "base/strings/string16.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 14 #include "chrome/browser/chrome_notification_types.h" | 12 #include "chrome/browser/chrome_notification_types.h" |
| 15 #include "chrome/browser/extensions/image_loader.h" | |
| 16 #include "chrome/browser/extensions/tab_helper.h" | 13 #include "chrome/browser/extensions/tab_helper.h" |
| 17 #include "chrome/browser/favicon/favicon_tab_helper.h" | 14 #include "chrome/browser/favicon/favicon_tab_helper.h" |
| 18 #include "chrome/browser/history/select_favicon_frames.h" | 15 #include "chrome/browser/history/select_favicon_frames.h" |
| 19 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 20 #include "chrome/browser/web_applications/web_app.h" | 17 #include "chrome/browser/web_applications/web_app.h" |
| 21 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | |
| 22 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" | |
| 23 #include "chrome/common/pref_names.h" | |
| 24 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 25 #include "content/public/browser/notification_details.h" | 19 #include "content/public/browser/notification_details.h" |
| 26 #include "content/public/browser/notification_registrar.h" | 20 #include "content/public/browser/notification_registrar.h" |
| 27 #include "content/public/browser/notification_source.h" | 21 #include "content/public/browser/notification_source.h" |
| 28 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
| 29 #include "extensions/common/extension.h" | |
| 30 #include "grit/theme_resources.h" | |
| 31 #include "skia/ext/image_operations.h" | |
| 32 #include "third_party/skia/include/core/SkBitmap.h" | |
| 33 #include "ui/base/resource/resource_bundle.h" | |
| 34 #include "ui/gfx/image/image.h" | |
| 35 #include "ui/gfx/image/image_family.h" | |
| 36 #include "ui/gfx/image/image_skia.h" | |
| 37 #include "url/gurl.h" | 23 #include "url/gurl.h" |
| 38 | 24 |
| 39 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 25 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| 40 #include "base/environment.h" | 26 #include "base/environment.h" |
| 41 #endif | 27 #endif |
| 42 | 28 |
| 43 #if defined(OS_WIN) | 29 #if defined(OS_WIN) |
| 44 #include "base/win/shortcut.h" | 30 #include "base/win/shortcut.h" |
| 45 #include "base/win/windows_version.h" | 31 #include "base/win/windows_version.h" |
| 46 #include "chrome/browser/web_applications/web_app_win.h" | 32 #include "chrome/browser/web_applications/web_app_win.h" |
| 47 #include "ui/gfx/icon_util.h" | 33 #include "ui/gfx/icon_util.h" |
| 48 #endif | 34 #endif |
| 49 | 35 |
| 50 using content::BrowserThread; | 36 using content::BrowserThread; |
| 51 using content::NavigationController; | 37 using content::NavigationController; |
| 52 using content::WebContents; | 38 using content::WebContents; |
| 53 | 39 |
| 54 namespace { | 40 namespace { |
| 55 | 41 |
| 56 #if defined(OS_MACOSX) | 42 // TODO(jackhou): Move all win-specific code to web_app_win. |
| 57 const int kDesiredSizes[] = {16, 32, 128, 256, 512}; | |
| 58 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); | |
| 59 #elif defined(OS_LINUX) | |
| 60 // Linux supports icons of any size. FreeDesktop Icon Theme Specification states | |
| 61 // that "Minimally you should install a 48x48 icon in the hicolor theme." | |
| 62 const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512}; | |
| 63 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); | |
| 64 #elif defined(OS_WIN) | |
| 65 const int* kDesiredSizes = IconUtil::kIconDimensions; | |
| 66 const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions; | |
| 67 #else | |
| 68 const int kDesiredSizes[] = {32}; | |
| 69 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); | |
| 70 #endif | |
| 71 | |
| 72 #if defined(OS_WIN) | 43 #if defined(OS_WIN) |
| 73 // UpdateShortcutWorker holds all context data needed for update shortcut. | 44 // UpdateShortcutWorker holds all context data needed for update shortcut. |
| 74 // It schedules a pre-update check to find all shortcuts that needs to be | 45 // It schedules a pre-update check to find all shortcuts that needs to be |
| 75 // updated. If there are such shortcuts, it schedules icon download and | 46 // updated. If there are such shortcuts, it schedules icon download and |
| 76 // update them when icons are downloaded. It observes TAB_CLOSING notification | 47 // update them when icons are downloaded. It observes TAB_CLOSING notification |
| 77 // and cancels all the work when the underlying tab is closing. | 48 // and cancels all the work when the underlying tab is closing. |
| 78 class UpdateShortcutWorker : public content::NotificationObserver { | 49 class UpdateShortcutWorker : public content::NotificationObserver { |
| 79 public: | 50 public: |
| 80 explicit UpdateShortcutWorker(WebContents* web_contents); | 51 explicit UpdateShortcutWorker(WebContents* web_contents); |
| 81 | 52 |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 base::Unretained(this))); | 307 base::Unretained(this))); |
| 337 } | 308 } |
| 338 } | 309 } |
| 339 | 310 |
| 340 void UpdateShortcutWorker::DeleteMeOnUIThread() { | 311 void UpdateShortcutWorker::DeleteMeOnUIThread() { |
| 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 342 delete this; | 313 delete this; |
| 343 } | 314 } |
| 344 #endif // defined(OS_WIN) | 315 #endif // defined(OS_WIN) |
| 345 | 316 |
| 346 void OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info, | |
| 347 web_app::ShortcutInfoCallback callback, | |
| 348 const gfx::ImageFamily& image_family) { | |
| 349 // If the image failed to load (e.g. if the resource being loaded was empty) | |
| 350 // use the standard application icon. | |
| 351 if (image_family.empty()) { | |
| 352 gfx::Image default_icon = | |
| 353 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON); | |
| 354 int size = kDesiredSizes[kNumDesiredSizes - 1]; | |
| 355 SkBitmap bmp = skia::ImageOperations::Resize( | |
| 356 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, | |
| 357 size, size); | |
| 358 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp); | |
| 359 // We are on the UI thread, and this image is needed from the FILE thread, | |
| 360 // for creating shortcut icon files. | |
| 361 image_skia.MakeThreadSafe(); | |
| 362 shortcut_info.favicon.Add(gfx::Image(image_skia)); | |
| 363 } else { | |
| 364 shortcut_info.favicon = image_family; | |
| 365 } | |
| 366 | |
| 367 callback.Run(shortcut_info); | |
| 368 } | |
| 369 | |
| 370 } // namespace | 317 } // namespace |
| 371 | 318 |
| 372 namespace web_app { | 319 namespace web_app { |
| 373 | 320 |
| 374 ShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile( | |
| 375 const extensions::Extension* extension, Profile* profile) { | |
| 376 ShellIntegration::ShortcutInfo shortcut_info; | |
| 377 web_app::UpdateShortcutInfoForApp(*extension, profile, &shortcut_info); | |
| 378 return shortcut_info; | |
| 379 } | |
| 380 | |
| 381 void GetShortcutInfoForTab(WebContents* web_contents, | 321 void GetShortcutInfoForTab(WebContents* web_contents, |
| 382 ShellIntegration::ShortcutInfo* info) { | 322 ShellIntegration::ShortcutInfo* info) { |
| 383 DCHECK(info); // Must provide a valid info. | 323 DCHECK(info); // Must provide a valid info. |
| 384 | 324 |
| 385 const FaviconTabHelper* favicon_tab_helper = | 325 const FaviconTabHelper* favicon_tab_helper = |
| 386 FaviconTabHelper::FromWebContents(web_contents); | 326 FaviconTabHelper::FromWebContents(web_contents); |
| 387 const extensions::TabHelper* extensions_tab_helper = | 327 const extensions::TabHelper* extensions_tab_helper = |
| 388 extensions::TabHelper::FromWebContents(web_contents); | 328 extensions::TabHelper::FromWebContents(web_contents); |
| 389 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info(); | 329 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info(); |
| 390 | 330 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 403 } | 343 } |
| 404 | 344 |
| 405 void UpdateShortcutForTabContents(WebContents* web_contents) { | 345 void UpdateShortcutForTabContents(WebContents* web_contents) { |
| 406 #if defined(OS_WIN) | 346 #if defined(OS_WIN) |
| 407 // UpdateShortcutWorker will delete itself when it's done. | 347 // UpdateShortcutWorker will delete itself when it's done. |
| 408 UpdateShortcutWorker* worker = new UpdateShortcutWorker(web_contents); | 348 UpdateShortcutWorker* worker = new UpdateShortcutWorker(web_contents); |
| 409 worker->Run(); | 349 worker->Run(); |
| 410 #endif // defined(OS_WIN) | 350 #endif // defined(OS_WIN) |
| 411 } | 351 } |
| 412 | 352 |
| 413 void UpdateShortcutInfoForApp(const extensions::Extension& app, | |
| 414 Profile* profile, | |
| 415 ShellIntegration::ShortcutInfo* shortcut_info) { | |
| 416 shortcut_info->extension_id = app.id(); | |
| 417 shortcut_info->is_platform_app = app.is_platform_app(); | |
| 418 shortcut_info->url = extensions::AppLaunchInfo::GetLaunchWebURL(&app); | |
| 419 shortcut_info->title = base::UTF8ToUTF16(app.name()); | |
| 420 shortcut_info->description = base::UTF8ToUTF16(app.description()); | |
| 421 shortcut_info->extension_path = app.path(); | |
| 422 shortcut_info->profile_path = profile->GetPath(); | |
| 423 shortcut_info->profile_name = | |
| 424 profile->GetPrefs()->GetString(prefs::kProfileName); | |
| 425 } | |
| 426 | |
| 427 void UpdateShortcutInfoAndIconForApp( | |
| 428 const extensions::Extension* extension, | |
| 429 Profile* profile, | |
| 430 const web_app::ShortcutInfoCallback& callback) { | |
| 431 ShellIntegration::ShortcutInfo shortcut_info = | |
| 432 ShortcutInfoForExtensionAndProfile(extension, profile); | |
| 433 | |
| 434 std::vector<extensions::ImageLoader::ImageRepresentation> info_list; | |
| 435 for (size_t i = 0; i < kNumDesiredSizes; ++i) { | |
| 436 int size = kDesiredSizes[i]; | |
| 437 extensions::ExtensionResource resource = | |
| 438 extensions::IconsInfo::GetIconResource( | |
| 439 extension, size, ExtensionIconSet::MATCH_EXACTLY); | |
| 440 if (!resource.empty()) { | |
| 441 info_list.push_back(extensions::ImageLoader::ImageRepresentation( | |
| 442 resource, | |
| 443 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, | |
| 444 gfx::Size(size, size), | |
| 445 ui::SCALE_FACTOR_100P)); | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 if (info_list.empty()) { | |
| 450 size_t i = kNumDesiredSizes - 1; | |
| 451 int size = kDesiredSizes[i]; | |
| 452 | |
| 453 // If there is no icon at the desired sizes, we will resize what we can get. | |
| 454 // Making a large icon smaller is preferred to making a small icon larger, | |
| 455 // so look for a larger icon first: | |
| 456 extensions::ExtensionResource resource = | |
| 457 extensions::IconsInfo::GetIconResource( | |
| 458 extension, size, ExtensionIconSet::MATCH_BIGGER); | |
| 459 if (resource.empty()) { | |
| 460 resource = extensions::IconsInfo::GetIconResource( | |
| 461 extension, size, ExtensionIconSet::MATCH_SMALLER); | |
| 462 } | |
| 463 info_list.push_back(extensions::ImageLoader::ImageRepresentation( | |
| 464 resource, | |
| 465 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, | |
| 466 gfx::Size(size, size), | |
| 467 ui::SCALE_FACTOR_100P)); | |
| 468 } | |
| 469 | |
| 470 // |info_list| may still be empty at this point, in which case | |
| 471 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty | |
| 472 // image and exit immediately. | |
| 473 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync( | |
| 474 extension, | |
| 475 info_list, | |
| 476 base::Bind(&OnImageLoaded, shortcut_info, callback)); | |
| 477 } | |
| 478 | |
| 479 } // namespace web_app | 353 } // namespace web_app |
| OLD | NEW |