cached_image_fetcher.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2017 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 "components/ntp_snippets/remote/cached_image_fetcher.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/location.h"
  8. #include "components/image_fetcher/core/image_decoder.h"
  9. #include "components/image_fetcher/core/image_fetcher.h"
  10. #include "components/ntp_snippets/remote/remote_suggestions_database.h"
  11. #include "net/traffic_annotation/network_traffic_annotation.h"
  12. #include "ui/gfx/geometry/size.h"
  13. #include "ui/gfx/image/image.h"
  14. namespace ntp_snippets {
  15. namespace {
  16. constexpr char kImageFetcherUmaClientName[] = "NtpSnippets";
  17. constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
  18. net::DefineNetworkTrafficAnnotation("remote_suggestions_provider", R"(
  19. semantics {
  20. sender: "Content Suggestion Thumbnail Fetch"
  21. description:
  22. "Retrieves thumbnails for content suggestions, for display on the "
  23. "New Tab page or Chrome Home."
  24. trigger:
  25. "Triggered when the user looks at a content suggestion (and its "
  26. "thumbnail isn't cached yet)."
  27. data: "None."
  28. destination: GOOGLE_OWNED_SERVICE
  29. }
  30. policy {
  31. cookies_allowed: NO
  32. setting: "Currently not available, but in progress: crbug.com/703684"
  33. chrome_policy {
  34. NTPContentSuggestionsEnabled {
  35. policy_options {mode: MANDATORY}
  36. NTPContentSuggestionsEnabled: false
  37. }
  38. }
  39. })");
  40. } // namespace
  41. CachedImageFetcher::CachedImageFetcher(
  42. std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
  43. PrefService* pref_service,
  44. RemoteSuggestionsDatabase* database)
  45. : image_fetcher_(std::move(image_fetcher)),
  46. database_(database),
  47. thumbnail_requests_throttler_(
  48. pref_service,
  49. RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) {}
  50. CachedImageFetcher::~CachedImageFetcher() {}
  51. void CachedImageFetcher::FetchSuggestionImage(
  52. const ContentSuggestion::ID& suggestion_id,
  53. const GURL& url,
  54. ImageDataFetchedCallback image_data_callback,
  55. ImageFetchedCallback image_callback) {
  56. database_->LoadImage(
  57. suggestion_id.id_within_category(),
  58. base::BindOnce(&CachedImageFetcher::OnImageFetchedFromDatabase,
  59. weak_ptr_factory_.GetWeakPtr(),
  60. std::move(image_data_callback), std::move(image_callback),
  61. suggestion_id, url));
  62. }
  63. void CachedImageFetcher::OnImageDecodingDone(
  64. ImageFetchedCallback callback,
  65. const std::string& id_within_category,
  66. const gfx::Image& image,
  67. const image_fetcher::RequestMetadata& metadata) {
  68. std::move(callback).Run(image);
  69. }
  70. void CachedImageFetcher::OnImageFetchingDone(
  71. ImageFetchedCallback callback,
  72. const gfx::Image& image,
  73. const image_fetcher::RequestMetadata& metadata) {
  74. std::move(callback).Run(image);
  75. }
  76. void CachedImageFetcher::OnImageFetchedFromDatabase(
  77. ImageDataFetchedCallback image_data_callback,
  78. ImageFetchedCallback image_callback,
  79. const ContentSuggestion::ID& suggestion_id,
  80. const GURL& url,
  81. std::string data) { // SnippetImageCallback requires by-value.
  82. if (data.empty()) {
  83. // Fetching from the DB failed; start a network fetch.
  84. FetchImageFromNetwork(suggestion_id, url, std::move(image_data_callback),
  85. std::move(image_callback));
  86. return;
  87. }
  88. if (image_data_callback) {
  89. std::move(image_data_callback).Run(data);
  90. }
  91. if (image_callback) {
  92. image_fetcher_->GetImageDecoder()->DecodeImage(
  93. data,
  94. // We're not dealing with multi-frame images.
  95. /*desired_image_frame_size=*/gfx::Size(),
  96. /*data_decoder=*/nullptr,
  97. base::BindOnce(&CachedImageFetcher::OnImageDecodedFromDatabase,
  98. weak_ptr_factory_.GetWeakPtr(),
  99. std::move(image_callback), suggestion_id, url));
  100. }
  101. }
  102. void CachedImageFetcher::OnImageDecodedFromDatabase(
  103. ImageFetchedCallback callback,
  104. const ContentSuggestion::ID& suggestion_id,
  105. const GURL& url,
  106. const gfx::Image& image) {
  107. if (!image.IsEmpty()) {
  108. std::move(callback).Run(image);
  109. return;
  110. }
  111. // If decoding the image failed, delete the DB entry.
  112. database_->DeleteImage(suggestion_id.id_within_category());
  113. FetchImageFromNetwork(suggestion_id, url, ImageDataFetchedCallback(),
  114. std::move(callback));
  115. }
  116. void CachedImageFetcher::FetchImageFromNetwork(
  117. const ContentSuggestion::ID& suggestion_id,
  118. const GURL& url,
  119. ImageDataFetchedCallback image_data_callback,
  120. ImageFetchedCallback image_callback) {
  121. if (url.is_empty() || !thumbnail_requests_throttler_.DemandQuotaForRequest(
  122. /*interactive_request=*/true)) {
  123. // Return an empty image. Directly, this is never synchronous with the
  124. // original FetchSuggestionImage() call - an asynchronous database query has
  125. // happened in the meantime.
  126. if (image_data_callback) {
  127. std::move(image_data_callback).Run(std::string());
  128. }
  129. if (image_callback) {
  130. std::move(image_callback).Run(gfx::Image());
  131. }
  132. return;
  133. }
  134. // Image decoding callback only set when requested.
  135. image_fetcher::ImageFetcherCallback decode_callback;
  136. if (image_callback) {
  137. decode_callback = base::BindOnce(&CachedImageFetcher::OnImageFetchingDone,
  138. weak_ptr_factory_.GetWeakPtr(),
  139. std::move(image_callback));
  140. }
  141. image_fetcher::ImageFetcherParams params(kTrafficAnnotation,
  142. kImageFetcherUmaClientName);
  143. image_fetcher_->FetchImageAndData(
  144. url,
  145. base::BindOnce(&CachedImageFetcher::SaveImageAndInvokeDataCallback,
  146. weak_ptr_factory_.GetWeakPtr(),
  147. suggestion_id.id_within_category(),
  148. std::move(image_data_callback)),
  149. std::move(decode_callback), std::move(params));
  150. }
  151. void CachedImageFetcher::SaveImageAndInvokeDataCallback(
  152. const std::string& id_within_category,
  153. ImageDataFetchedCallback callback,
  154. const std::string& image_data,
  155. const image_fetcher::RequestMetadata& request_metadata) {
  156. if (!image_data.empty()) {
  157. database_->SaveImage(id_within_category, image_data);
  158. }
  159. if (callback) {
  160. std::move(callback).Run(image_data);
  161. }
  162. }
  163. } // namespace ntp_snippets