| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/web_applications/web_app.h" | 5 #include "chrome/browser/web_applications/web_app.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) |
| 8 #include <ShellAPI.h> |
| 9 #endif // defined(OS_WIN) |
| 10 |
| 7 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/md5.h" |
| 8 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 9 #include "base/path_service.h" | 14 #include "base/path_service.h" |
| 10 #include "base/thread.h" | 15 #include "base/thread.h" |
| 16 #include "base/scoped_ptr.h" |
| 11 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 12 #include "chrome/browser/browser_process.h" | 18 #include "chrome/browser/chrome_thread.h" |
| 19 #include "chrome/browser/profile.h" |
| 20 #include "chrome/browser/tab_contents/tab_contents.h" |
| 21 #include "chrome/common/chrome_constants.h" |
| 13 #include "chrome/common/chrome_paths.h" | 22 #include "chrome/common/chrome_paths.h" |
| 14 #include "chrome/common/chrome_plugin_util.h" | 23 #include "chrome/common/chrome_plugin_util.h" |
| 24 #include "chrome/common/notification_registrar.h" |
| 25 #include "chrome/common/notification_service.h" |
| 15 #include "chrome/common/url_constants.h" | 26 #include "chrome/common/url_constants.h" |
| 27 #include "webkit/glue/dom_operations.h" |
| 16 | 28 |
| 17 #if defined(OS_WIN) | 29 #if defined(OS_WIN) |
| 18 #include "app/gfx/icon_util.h" | 30 #include "app/gfx/icon_util.h" |
| 19 #include "base/win_util.h" | 31 #include "base/win_util.h" |
| 20 #endif // defined(OS_WIN) | 32 #endif // defined(OS_WIN) |
| 21 | 33 |
| 22 namespace { | 34 namespace { |
| 23 | 35 |
| 36 const FilePath::CharType kIconChecksumFileExt[] = FILE_PATH_LITERAL(".ico.md5"); |
| 37 |
| 24 // Returns true if |ch| is in visible ASCII range and not one of | 38 // Returns true if |ch| is in visible ASCII range and not one of |
| 25 // "/ \ : * ? " < > | ; ,". | 39 // "/ \ : * ? " < > | ; ,". |
| 26 bool IsValidFilePathChar(char16 c) { | 40 bool IsValidFilePathChar(char16 c) { |
| 27 if (c < 32) | 41 if (c < 32) |
| 28 return false; | 42 return false; |
| 29 | 43 |
| 30 switch (c) { | 44 switch (c) { |
| 31 case '/': | 45 case '/': |
| 32 case '\\': | 46 case '\\': |
| 33 case ':': | 47 case ':': |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 | 95 |
| 82 return FilePath(host).Append(scheme_port); | 96 return FilePath(host).Append(scheme_port); |
| 83 } | 97 } |
| 84 | 98 |
| 85 // Returns data directory for given web app url | 99 // Returns data directory for given web app url |
| 86 FilePath GetWebAppDataDirectory(const FilePath& root_dir, | 100 FilePath GetWebAppDataDirectory(const FilePath& root_dir, |
| 87 const GURL& url) { | 101 const GURL& url) { |
| 88 return root_dir.Append(GetWebAppDir(url)); | 102 return root_dir.Append(GetWebAppDir(url)); |
| 89 } | 103 } |
| 90 | 104 |
| 105 // Predicator for sorting images from largest to smallest. |
| 106 bool IconPrecedes( |
| 107 const webkit_glue::WebApplicationInfo::IconInfo& left, |
| 108 const webkit_glue::WebApplicationInfo::IconInfo& right) { |
| 109 return left.width < right.width; |
| 110 } |
| 111 |
| 112 // Calculates image checksum using MD5. |
| 113 void GetImageCheckSum(const SkBitmap& image, MD5Digest* digest) { |
| 114 DCHECK(digest); |
| 115 |
| 116 SkAutoLockPixels image_lock(image); |
| 117 MD5Sum(image.getPixels(), image.getSize(), digest); |
| 118 } |
| 119 |
| 120 #if defined(OS_WIN) |
| 121 // Saves |image| as an |icon_file| with the checksum. |
| 122 bool SaveIconWithCheckSum(const FilePath& icon_file, const SkBitmap& image) { |
| 123 if (!IconUtil::CreateIconFileFromSkBitmap(image, icon_file.value())) |
| 124 return false; |
| 125 |
| 126 MD5Digest digest; |
| 127 GetImageCheckSum(image, &digest); |
| 128 |
| 129 FilePath cheksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt)); |
| 130 return file_util::WriteFile(cheksum_file, |
| 131 reinterpret_cast<const char*>(&digest), |
| 132 sizeof(digest)) == sizeof(digest); |
| 133 } |
| 134 |
| 135 // Returns true if |icon_file| is missing or different from |image|. |
| 136 bool ShouldUpdateIcon(const FilePath& icon_file, const SkBitmap& image) { |
| 137 FilePath checksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt)); |
| 138 |
| 139 // Returns true if icon_file or checksum file is missing. |
| 140 if (!file_util::PathExists(icon_file) || |
| 141 !file_util::PathExists(checksum_file)) |
| 142 return true; |
| 143 |
| 144 MD5Digest persisted_image_checksum; |
| 145 if (sizeof(persisted_image_checksum) != file_util::ReadFile(checksum_file, |
| 146 reinterpret_cast<char*>(&persisted_image_checksum), |
| 147 sizeof(persisted_image_checksum))) |
| 148 return true; |
| 149 |
| 150 MD5Digest downloaded_image_checksum; |
| 151 GetImageCheckSum(image, &downloaded_image_checksum); |
| 152 |
| 153 // Update icon if checksums are not equal. |
| 154 return memcmp(&persisted_image_checksum, &downloaded_image_checksum, |
| 155 sizeof(MD5Digest)) != 0; |
| 156 } |
| 157 |
| 158 // Saves |image| to |icon_file| if the file is outdated and refresh shell's |
| 159 // icon cache to ensure correct icon is displayed. Returns true if icon_file |
| 160 // is up to date or successfully updated. |
| 161 bool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image) { |
| 162 if (ShouldUpdateIcon(icon_file, image)) { |
| 163 if (SaveIconWithCheckSum(icon_file, image)) { |
| 164 // Refresh shell's icon cache. This call is quite disruptive as user would |
| 165 // see explorer rebuilding the icon cache. It would be great that we find |
| 166 // a better way to achieve this. |
| 167 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, |
| 168 NULL, NULL); |
| 169 } else { |
| 170 return false; |
| 171 } |
| 172 } |
| 173 |
| 174 return true; |
| 175 } |
| 176 |
| 177 #endif // defined(OS_WIN) |
| 178 |
| 91 // Represents a task that creates web application shortcut. This runs on | 179 // Represents a task that creates web application shortcut. This runs on |
| 92 // file thread and schedules the callback (if any) on the calling thread | 180 // file thread and schedules the callback (if any) on the calling thread |
| 93 // when finished (either success or failure). | 181 // when finished (either success or failure). |
| 94 class CreateShortcutTask : public Task { | 182 class CreateShortcutTask : public Task { |
| 95 public: | 183 public: |
| 96 CreateShortcutTask(const FilePath& root_dir, | 184 CreateShortcutTask(const FilePath& root_dir, |
| 97 const ShellIntegration::ShortcutInfo& shortcut_info, | 185 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 98 web_app::CreateShortcutCallback* callback); | 186 web_app::CreateShortcutCallback* callback); |
| 99 | 187 |
| 100 private: | 188 private: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 115 web_app::CreateShortcutCallback* callback_; | 203 web_app::CreateShortcutCallback* callback_; |
| 116 bool success_; | 204 bool success_; |
| 117 }; | 205 }; |
| 118 | 206 |
| 119 // Overridden from Task: | 207 // Overridden from Task: |
| 120 virtual void Run(); | 208 virtual void Run(); |
| 121 | 209 |
| 122 // Returns true if shortcut is created successfully. | 210 // Returns true if shortcut is created successfully. |
| 123 bool CreateShortcut(); | 211 bool CreateShortcut(); |
| 124 | 212 |
| 125 // Path to store persisted data for web_app. | 213 // Path to store persisted data for web app. |
| 126 FilePath web_app_path_; | 214 FilePath web_app_path_; |
| 127 | 215 |
| 128 // Our copy of short cut data. | 216 // Our copy of short cut data. |
| 129 ShellIntegration::ShortcutInfo shortcut_info_; | 217 ShellIntegration::ShortcutInfo shortcut_info_; |
| 130 | 218 |
| 131 // Callback when task is finished. | 219 // Callback when task is finished. |
| 132 web_app::CreateShortcutCallback* callback_; | 220 web_app::CreateShortcutCallback* callback_; |
| 133 MessageLoop* message_loop_; | 221 MessageLoop* message_loop_; |
| 222 |
| 223 DISALLOW_COPY_AND_ASSIGN(CreateShortcutTask); |
| 134 }; | 224 }; |
| 135 | 225 |
| 136 CreateShortcutTask::CreateShortcutTask( | 226 CreateShortcutTask::CreateShortcutTask( |
| 137 const FilePath& root_dir, | 227 const FilePath& root_dir, |
| 138 const ShellIntegration::ShortcutInfo& shortcut_info, | 228 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 139 web_app::CreateShortcutCallback* callback) | 229 web_app::CreateShortcutCallback* callback) |
| 140 : web_app_path_(GetWebAppDataDirectory(root_dir, shortcut_info.url)), | 230 : web_app_path_(GetWebAppDataDirectory(root_dir, shortcut_info.url)), |
| 141 shortcut_info_(shortcut_info), | 231 shortcut_info_(shortcut_info), |
| 142 callback_(callback), | 232 callback_(callback), |
| 143 message_loop_(MessageLoop::current()) { | 233 message_loop_(MessageLoop::current()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 169 { | 259 { |
| 170 shortcut_info_.create_on_desktop, | 260 shortcut_info_.create_on_desktop, |
| 171 chrome::DIR_USER_DESKTOP, | 261 chrome::DIR_USER_DESKTOP, |
| 172 NULL | 262 NULL |
| 173 }, { | 263 }, { |
| 174 shortcut_info_.create_in_applications_menu, | 264 shortcut_info_.create_in_applications_menu, |
| 175 base::DIR_START_MENU, | 265 base::DIR_START_MENU, |
| 176 NULL | 266 NULL |
| 177 }, { | 267 }, { |
| 178 shortcut_info_.create_in_quick_launch_bar, | 268 shortcut_info_.create_in_quick_launch_bar, |
| 179 // For Win7, create_in_quick_launch_bar means pining to taskbar. Use | 269 // For Win7, create_in_quick_launch_bar means pinning to taskbar. Use |
| 180 // base::PATH_START as a flag for this case. | 270 // base::PATH_START as a flag for this case. |
| 181 (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? | 271 (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? |
| 182 base::PATH_START : base::DIR_APP_DATA, | 272 base::PATH_START : base::DIR_APP_DATA, |
| 183 (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? | 273 (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? |
| 184 NULL : L"Microsoft\\Internet Explorer\\Quick Launch" | 274 NULL : L"Microsoft\\Internet Explorer\\Quick Launch" |
| 185 } | 275 } |
| 186 }; | 276 }; |
| 187 | 277 |
| 188 // Populate shortcut_paths. | 278 // Populate shortcut_paths. |
| 189 for (int i = 0; i < arraysize(locations); ++i) { | 279 for (int i = 0; i < arraysize(locations); ++i) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 NOTREACHED(); | 319 NOTREACHED(); |
| 230 return false; | 320 return false; |
| 231 } | 321 } |
| 232 | 322 |
| 233 // Generates file name to use with persisted ico and shortcut file. | 323 // Generates file name to use with persisted ico and shortcut file. |
| 234 FilePath file_name = GetSanitizedFileName(shortcut_info_.title); | 324 FilePath file_name = GetSanitizedFileName(shortcut_info_.title); |
| 235 | 325 |
| 236 // Creates an ico file to use with shortcut. | 326 // Creates an ico file to use with shortcut. |
| 237 FilePath icon_file = web_app_path_.Append(file_name).ReplaceExtension( | 327 FilePath icon_file = web_app_path_.Append(file_name).ReplaceExtension( |
| 238 FILE_PATH_LITERAL(".ico")); | 328 FILE_PATH_LITERAL(".ico")); |
| 239 if (!IconUtil::CreateIconFileFromSkBitmap(shortcut_info_.favicon, | 329 if (!CheckAndSaveIcon(icon_file, shortcut_info_.favicon)) { |
| 240 icon_file.value())) { | |
| 241 NOTREACHED(); | 330 NOTREACHED(); |
| 242 return false; | 331 return false; |
| 243 } | 332 } |
| 244 | 333 |
| 245 std::wstring chrome_exe; | 334 std::wstring chrome_exe; |
| 246 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 335 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 247 NOTREACHED(); | 336 NOTREACHED(); |
| 248 return false; | 337 return false; |
| 249 } | 338 } |
| 250 | 339 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 281 success &= file_util::TaskbarPinShortcutLink(shortcut_file.value().c_str()); | 370 success &= file_util::TaskbarPinShortcutLink(shortcut_file.value().c_str()); |
| 282 } | 371 } |
| 283 | 372 |
| 284 return success; | 373 return success; |
| 285 #else | 374 #else |
| 286 NOTIMPLEMENTED(); | 375 NOTIMPLEMENTED(); |
| 287 return false; | 376 return false; |
| 288 #endif | 377 #endif |
| 289 } | 378 } |
| 290 | 379 |
| 380 #if defined(OS_WIN) |
| 381 // UpdateShortcutWorker holds all context data needed for update shortcut. |
| 382 // It schedules a pre-update check to find all shortcuts that needs to be |
| 383 // updated. If there are such shortcuts, it schedules icon download and |
| 384 // update them when icons are downloaded. It observes TAB_CLOSING notification |
| 385 // and cancels all the work when the underlying tab is closing. |
| 386 class UpdateShortcutWorker : public NotificationObserver { |
| 387 public: |
| 388 explicit UpdateShortcutWorker(TabContents* tab_contents); |
| 389 |
| 390 void Run(); |
| 391 |
| 392 private: |
| 393 // Overridden from NotificationObserver: |
| 394 virtual void Observe(NotificationType type, |
| 395 const NotificationSource& source, |
| 396 const NotificationDetails& details); |
| 397 |
| 398 // Downloads icon via TabContents. |
| 399 void DownloadIcon(); |
| 400 |
| 401 // Callback when icon downloaded. |
| 402 void OnIconDownloaded(int download_id, bool errored, const SkBitmap& image); |
| 403 |
| 404 // Checks if shortcuts exists on desktop, start menu and quick launch. |
| 405 void CheckExistingShortcuts(); |
| 406 |
| 407 // Update shortcut files and icons. |
| 408 void UpdateShortcuts(); |
| 409 void UpdateShortcutsOnFileThread(); |
| 410 |
| 411 // Callback after shortcuts are updated. |
| 412 void OnShortcutsUpdated(bool); |
| 413 |
| 414 // Deletes the worker on UI thread where it gets created. |
| 415 void DeleteMe(); |
| 416 void DeleteMeOnUIThread(); |
| 417 |
| 418 NotificationRegistrar registrar_; |
| 419 |
| 420 // Underlying TabContents whose shortcuts will be updated. |
| 421 TabContents* tab_contents_; |
| 422 |
| 423 // Icons info from tab_contents_'s web app data. |
| 424 web_app::IconInfoList unprocessed_icons_; |
| 425 |
| 426 // Cached shortcut data from the tab_contents_. |
| 427 ShellIntegration::ShortcutInfo shortcut_info_; |
| 428 |
| 429 // Root dir of web app data. |
| 430 FilePath root_dir_; |
| 431 |
| 432 // File name of shortcut/ico file based on app title. |
| 433 FilePath file_name_; |
| 434 |
| 435 // Existing shortcuts. |
| 436 std::vector<FilePath> shortcut_files_; |
| 437 |
| 438 DISALLOW_COPY_AND_ASSIGN(UpdateShortcutWorker); |
| 439 }; |
| 440 |
| 441 UpdateShortcutWorker::UpdateShortcutWorker(TabContents* tab_contents) |
| 442 : tab_contents_(tab_contents), |
| 443 root_dir_(web_app::GetDataDir(tab_contents->profile())) { |
| 444 web_app::GetShortcutInfoForTab(tab_contents_, &shortcut_info_); |
| 445 web_app::GetIconsInfo(tab_contents_->web_app_info(), &unprocessed_icons_); |
| 446 file_name_ = GetSanitizedFileName(shortcut_info_.title); |
| 447 |
| 448 registrar_.Add(this, NotificationType::TAB_CLOSING, |
| 449 Source<NavigationController>(&tab_contents_->controller())); |
| 450 } |
| 451 |
| 452 void UpdateShortcutWorker::Run() { |
| 453 // Starting by downloading app icon. |
| 454 DownloadIcon(); |
| 455 } |
| 456 |
| 457 void UpdateShortcutWorker::Observe(NotificationType type, |
| 458 const NotificationSource& source, |
| 459 const NotificationDetails& details) { |
| 460 if (type == NotificationType::TAB_CLOSING && |
| 461 Source<NavigationController>(source).ptr() == |
| 462 &tab_contents_->controller()) { |
| 463 // Underlying tab is closing. |
| 464 tab_contents_ = NULL; |
| 465 } |
| 466 } |
| 467 |
| 468 void UpdateShortcutWorker::DownloadIcon() { |
| 469 // FetchIcon must run on UI thread because it relies on TabContents |
| 470 // to download the icon. |
| 471 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 472 |
| 473 if (tab_contents_ == NULL) { |
| 474 DeleteMe(); // We are done if underlying TabContents is gone. |
| 475 return; |
| 476 } |
| 477 |
| 478 if (unprocessed_icons_.empty()) { |
| 479 // No app icon. Just use the favicon from TabContents. |
| 480 UpdateShortcuts(); |
| 481 return; |
| 482 } |
| 483 |
| 484 tab_contents_->fav_icon_helper().DownloadImage( |
| 485 unprocessed_icons_.back().url, |
| 486 std::max(unprocessed_icons_.back().width, |
| 487 unprocessed_icons_.back().height), |
| 488 NewCallback(this, &UpdateShortcutWorker::OnIconDownloaded)); |
| 489 unprocessed_icons_.pop_back(); |
| 490 } |
| 491 |
| 492 void UpdateShortcutWorker::OnIconDownloaded(int download_id, |
| 493 bool errored, |
| 494 const SkBitmap& image) { |
| 495 if (tab_contents_ == NULL) { |
| 496 DeleteMe(); // We are done if underlying TabContents is gone. |
| 497 return; |
| 498 } |
| 499 |
| 500 if (!errored && !image.isNull()) { |
| 501 // Update icon with download image and update shortcut. |
| 502 shortcut_info_.favicon = image; |
| 503 UpdateShortcuts(); |
| 504 } else { |
| 505 // Try the next icon otherwise. |
| 506 DownloadIcon(); |
| 507 } |
| 508 } |
| 509 |
| 510 void UpdateShortcutWorker::CheckExistingShortcuts() { |
| 511 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 512 |
| 513 // Locations to check to shortcut_paths. |
| 514 struct { |
| 515 bool& use_this_location; |
| 516 int location_id; |
| 517 const wchar_t* sub_dir; |
| 518 } locations[] = { |
| 519 { |
| 520 shortcut_info_.create_on_desktop, |
| 521 chrome::DIR_USER_DESKTOP, |
| 522 NULL |
| 523 }, { |
| 524 shortcut_info_.create_in_applications_menu, |
| 525 base::DIR_START_MENU, |
| 526 NULL |
| 527 }, { |
| 528 shortcut_info_.create_in_quick_launch_bar, |
| 529 // For Win7, create_in_quick_launch_bar means pinning to taskbar. |
| 530 base::DIR_APP_DATA, |
| 531 (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? |
| 532 L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar" : |
| 533 L"Microsoft\\Internet Explorer\\Quick Launch" |
| 534 } |
| 535 }; |
| 536 |
| 537 for (int i = 0; i < arraysize(locations); ++i) { |
| 538 locations[i].use_this_location = false; |
| 539 |
| 540 FilePath path; |
| 541 if (!PathService::Get(locations[i].location_id, &path)) { |
| 542 NOTREACHED(); |
| 543 continue; |
| 544 } |
| 545 |
| 546 if (locations[i].sub_dir != NULL) |
| 547 path = path.Append(locations[i].sub_dir); |
| 548 |
| 549 FilePath shortcut_file = path.Append(file_name_). |
| 550 ReplaceExtension(FILE_PATH_LITERAL(".lnk")); |
| 551 if (file_util::PathExists(shortcut_file)) { |
| 552 locations[i].use_this_location = true; |
| 553 shortcut_files_.push_back(shortcut_file); |
| 554 } |
| 555 } |
| 556 } |
| 557 |
| 558 void UpdateShortcutWorker::UpdateShortcuts() { |
| 559 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 560 NewRunnableMethod(this, |
| 561 &UpdateShortcutWorker::UpdateShortcutsOnFileThread)); |
| 562 } |
| 563 |
| 564 void UpdateShortcutWorker::UpdateShortcutsOnFileThread() { |
| 565 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 566 |
| 567 FilePath web_app_path = GetWebAppDataDirectory(root_dir_, shortcut_info_.url); |
| 568 FilePath icon_file = web_app_path.Append(file_name_).ReplaceExtension( |
| 569 FILE_PATH_LITERAL(".ico")); |
| 570 CheckAndSaveIcon(icon_file, shortcut_info_.favicon); |
| 571 |
| 572 CheckExistingShortcuts(); |
| 573 if (shortcut_files_.empty()) { |
| 574 // No shortcuts to update. |
| 575 OnShortcutsUpdated(true); |
| 576 } else { |
| 577 // Re-create shortcuts to make sure application url, name and description |
| 578 // are up to date |
| 579 web_app::CreateShortcut(root_dir_, shortcut_info_, |
| 580 NewCallback(this, &UpdateShortcutWorker::OnShortcutsUpdated)); |
| 581 } |
| 582 } |
| 583 |
| 584 void UpdateShortcutWorker::OnShortcutsUpdated(bool) { |
| 585 DeleteMe(); // We are done. |
| 586 } |
| 587 |
| 588 void UpdateShortcutWorker::DeleteMe() { |
| 589 if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { |
| 590 DeleteMeOnUIThread(); |
| 591 } else { |
| 592 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 593 NewRunnableMethod(this, &UpdateShortcutWorker::DeleteMeOnUIThread)); |
| 594 } |
| 595 } |
| 596 |
| 597 void UpdateShortcutWorker::DeleteMeOnUIThread() { |
| 598 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 599 delete this; |
| 600 } |
| 601 #endif // defined(OS_WIN) |
| 602 |
| 291 }; // namespace | 603 }; // namespace |
| 292 | 604 |
| 605 // Allows UpdateShortcutWorker without adding refcounting. UpdateShortcutWorker |
| 606 // manages its own life time and will delete itself when it's done. |
| 607 template <> |
| 608 struct RunnableMethodTraits<UpdateShortcutWorker> { |
| 609 void RetainCallee(UpdateShortcutWorker* worker) {} |
| 610 void ReleaseCallee(UpdateShortcutWorker* worker) {} |
| 611 }; |
| 612 |
| 293 namespace web_app { | 613 namespace web_app { |
| 294 | 614 |
| 295 std::wstring GenerateApplicationNameFromURL(const GURL& url) { | 615 std::wstring GenerateApplicationNameFromURL(const GURL& url) { |
| 296 std::string t; | 616 std::string t; |
| 297 t.append(url.host()); | 617 t.append(url.host()); |
| 298 t.append("_"); | 618 t.append("_"); |
| 299 t.append(url.path()); | 619 t.append(url.path()); |
| 300 return UTF8ToWide(t); | 620 return UTF8ToWide(t); |
| 301 } | 621 } |
| 302 | 622 |
| 303 void CreateShortcut( | 623 void CreateShortcut( |
| 304 const FilePath& data_dir, | 624 const FilePath& data_dir, |
| 305 const ShellIntegration::ShortcutInfo& shortcut_info, | 625 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 306 CreateShortcutCallback* callback) { | 626 CreateShortcutCallback* callback) { |
| 307 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 627 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 308 new CreateShortcutTask(data_dir, shortcut_info, callback)); | 628 new CreateShortcutTask(data_dir, shortcut_info, callback)); |
| 309 } | 629 } |
| 310 | 630 |
| 311 bool IsValidUrl(const GURL& url) { | 631 bool IsValidUrl(const GURL& url) { |
| 312 static const char* const kValidUrlSchemes[] = { | 632 static const char* const kValidUrlSchemes[] = { |
| 313 chrome::kFileScheme, | 633 chrome::kFileScheme, |
| 314 chrome::kFtpScheme, | 634 chrome::kFtpScheme, |
| 315 chrome::kHttpScheme, | 635 chrome::kHttpScheme, |
| 316 chrome::kHttpsScheme, | 636 chrome::kHttpsScheme, |
| 317 }; | 637 }; |
| 318 | 638 |
| 319 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) { | 639 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) { |
| 320 if (url.SchemeIs(kValidUrlSchemes[i])) | 640 if (url.SchemeIs(kValidUrlSchemes[i])) |
| 321 return true; | 641 return true; |
| 322 } | 642 } |
| 323 | 643 |
| 324 return false; | 644 return false; |
| 325 } | 645 } |
| 326 | 646 |
| 647 FilePath GetDataDir(Profile* profile) { |
| 648 DCHECK(profile); |
| 649 return profile->GetPath().Append(chrome::kWebAppDirname); |
| 650 } |
| 651 |
| 652 void GetIconsInfo(const webkit_glue::WebApplicationInfo& app_info, |
| 653 IconInfoList* icons) { |
| 654 DCHECK(icons); |
| 655 |
| 656 icons->clear(); |
| 657 for (size_t i = 0; i < app_info.icons.size(); ++i) { |
| 658 // We only take square shaped icons (i.e. width == height). |
| 659 if (app_info.icons[i].width == app_info.icons[i].height) { |
| 660 icons->push_back(app_info.icons[i]); |
| 661 } |
| 662 } |
| 663 |
| 664 std::sort(icons->begin(), icons->end(), &IconPrecedes); |
| 665 } |
| 666 |
| 667 void GetShortcutInfoForTab(TabContents* tab_contents, |
| 668 ShellIntegration::ShortcutInfo* info) { |
| 669 DCHECK(info); // Must provide a valid info. |
| 670 |
| 671 const webkit_glue::WebApplicationInfo& app_info = |
| 672 tab_contents->web_app_info(); |
| 673 |
| 674 info->url = app_info.app_url.is_empty() ? tab_contents->GetURL() : |
| 675 app_info.app_url; |
| 676 info->title = app_info.title.empty() ? |
| 677 (tab_contents->GetTitle().empty() ? UTF8ToUTF16(info->url.spec()) : |
| 678 tab_contents->GetTitle()) : |
| 679 app_info.title; |
| 680 info->description = app_info.description; |
| 681 info->favicon = tab_contents->GetFavIcon(); |
| 682 } |
| 683 |
| 684 void UpdateShortcutForTabContents(TabContents* tab_contents) { |
| 685 #if defined(OS_WIN) |
| 686 // UpdateShortcutWorker will delete itself when it's done. |
| 687 UpdateShortcutWorker* worker = new UpdateShortcutWorker(tab_contents); |
| 688 worker->Run(); |
| 689 #endif // defined(OS_WIN) |
| 690 } |
| 691 |
| 327 }; // namespace web_app | 692 }; // namespace web_app |
| OLD | NEW |