favicon_tab_helper.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2020 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. #include "weblayer/browser/favicon/favicon_tab_helper.h"
  5. #include "components/favicon/content/content_favicon_driver.h"
  6. #include "content/public/browser/navigation_handle.h"
  7. #include "content/public/browser/web_contents.h"
  8. #include "weblayer/browser/favicon/favicon_service_impl.h"
  9. #include "weblayer/browser/favicon/favicon_service_impl_factory.h"
  10. #include "weblayer/public/favicon_fetcher_delegate.h"
  11. namespace weblayer {
  12. namespace {
  13. bool IsSquareImage(const gfx::Image& image) {
  14. return !image.IsEmpty() && image.Width() == image.Height();
  15. }
  16. // Returns true if |image_a| is better than |image_b|. A value of false means
  17. // |image_a| is not better than |image_b|. Either image may be empty, if both
  18. // are empty false is returned.
  19. bool IsImageBetterThan(const gfx::Image& image_a, const gfx::Image& image_b) {
  20. // Any image is better than an empty image.
  21. if (!image_a.IsEmpty() && image_b.IsEmpty())
  22. return true;
  23. // Prefer square favicons as they will scale much better.
  24. if (IsSquareImage(image_a) && !IsSquareImage(image_b))
  25. return true;
  26. return image_a.Width() > image_b.Width();
  27. }
  28. } // namespace
  29. FaviconTabHelper::ObserverSubscription::ObserverSubscription(
  30. FaviconTabHelper* helper,
  31. FaviconFetcherDelegate* delegate)
  32. : helper_(helper), delegate_(delegate) {
  33. helper_->AddDelegate(delegate_);
  34. }
  35. FaviconTabHelper::ObserverSubscription::~ObserverSubscription() {
  36. helper_->RemoveDelegate(delegate_);
  37. }
  38. FaviconTabHelper::~FaviconTabHelper() {
  39. // All of the ObserverSubscriptions should have been destroyed before this.
  40. DCHECK_EQ(0, observer_count_);
  41. }
  42. std::unique_ptr<FaviconTabHelper::ObserverSubscription>
  43. FaviconTabHelper::RegisterFaviconFetcherDelegate(
  44. FaviconFetcherDelegate* delegate) {
  45. // WrapUnique as constructor is private.
  46. return base::WrapUnique(new ObserverSubscription(this, delegate));
  47. }
  48. FaviconTabHelper::FaviconTabHelper(content::WebContents* contents)
  49. : content::WebContentsUserData<FaviconTabHelper>(*contents),
  50. WebContentsObserver(contents) {}
  51. void FaviconTabHelper::AddDelegate(FaviconFetcherDelegate* delegate) {
  52. delegates_.AddObserver(delegate);
  53. if (++observer_count_ == 1) {
  54. FaviconServiceImpl* favicon_service =
  55. FaviconServiceImplFactory::GetForBrowserContext(
  56. web_contents()->GetBrowserContext());
  57. favicon::ContentFaviconDriver::CreateForWebContents(web_contents(),
  58. favicon_service);
  59. favicon::ContentFaviconDriver::FromWebContents(web_contents())
  60. ->AddObserver(this);
  61. }
  62. }
  63. void FaviconTabHelper::RemoveDelegate(FaviconFetcherDelegate* delegate) {
  64. delegates_.RemoveObserver(delegate);
  65. --observer_count_;
  66. DCHECK_GE(observer_count_, 0);
  67. if (observer_count_ == 0) {
  68. favicon::ContentFaviconDriver::FromWebContents(web_contents())
  69. ->RemoveObserver(this);
  70. // ContentFaviconDriver downloads images, if there are no observers there
  71. // is no need to keep it around. This triggers deleting it.
  72. web_contents()->SetUserData(favicon::ContentFaviconDriver::UserDataKey(),
  73. nullptr);
  74. favicon_ = gfx::Image();
  75. }
  76. }
  77. void FaviconTabHelper::OnFaviconUpdated(
  78. favicon::FaviconDriver* favicon_driver,
  79. NotificationIconType notification_icon_type,
  80. const GURL& icon_url,
  81. bool icon_url_changed,
  82. const gfx::Image& image) {
  83. if (!IsImageBetterThan(image, favicon_))
  84. return;
  85. favicon_ = image;
  86. for (FaviconFetcherDelegate& delegate : delegates_)
  87. delegate.OnFaviconChanged(favicon_);
  88. }
  89. void FaviconTabHelper::PrimaryPageChanged(content::Page& page) {
  90. if (page.GetMainDocument().IsErrorDocument() || favicon_.IsEmpty()) {
  91. return;
  92. }
  93. favicon_ = gfx::Image();
  94. for (FaviconFetcherDelegate& delegate : delegates_)
  95. delegate.OnFaviconChanged(favicon_);
  96. }
  97. WEB_CONTENTS_USER_DATA_KEY_IMPL(FaviconTabHelper);
  98. } // namespace weblayer