Revert "[blink/renderer] Fix image download logic in renderer to filter instead"

This reverts commit 45351855e193fbb7caee43ab2da8178a490a41d6.

Reason for revert: likely causes crashes on perf bots (crbug/1352191)

Original change's description:
> [blink/renderer] Fix image download logic in renderer to filter instead
> of resize
>
> This CL introduces logic in blink/renderer to filter out images instead
> of resizing the smallest image in case no images are found about a
> specific max size. This also moves the filter logic into the callsites
> instead of renderer, so that this is handler on a use-case basis.
>
> Doc: go/blink_image
>
> Bug: 1176678, 1348264
> Change-Id: If1cae73c5f5bfb2146156a6872dac5d4b41aa577
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3781583
> Commit-Queue: Dibyajyoti Pal <[email protected]>
> Reviewed-by: Daniel Cheng <[email protected]>
> Reviewed-by: Dominick Ng <[email protected]>
> Reviewed-by: Avi Drissman <[email protected]>
> Reviewed-by: Nate Fischer <[email protected]>
> Reviewed-by: Scott Violet <[email protected]>
> Reviewed-by: Yaron Friedman <[email protected]>
> Cr-Commit-Position: refs/heads/main@{#1033659}

Bug: 1176678, 1348264
Bug: 1352191
Change-Id: I50dc02aa3411f9e921dda59bad5f7da3daa55406
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3825876
Bot-Commit: Rubber Stamper <[email protected]>
Reviewed-by: Dibyajyoti Pal <[email protected]>
Auto-Submit: Eric Seckler <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Owners-Override: Avi Drissman <[email protected]>
Commit-Queue: Avi Drissman <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1034081}
diff --git a/android_webview/browser/icon_helper.cc b/android_webview/browser/icon_helper.cc
index 8247e795..7e3b3b1 100644
--- a/android_webview/browser/icon_helper.cc
+++ b/android_webview/browser/icon_helper.cc
@@ -4,8 +4,6 @@
 
 #include "android_webview/browser/icon_helper.h"
 
-#include <vector>
-
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/check_op.h"
@@ -18,7 +16,6 @@
 #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/image/image_util.h"
 
 using content::BrowserThread;
 using content::WebContents;
@@ -55,13 +52,7 @@
     return;
   }
 
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_bitmap_sizes;
-  gfx::FilterAndResizeImagesForMaximalSize(
-      bitmaps, kLargestIconSize, filtered_images, filtered_bitmap_sizes);
-  DCHECK_EQ(filtered_images.size(), filtered_bitmap_sizes.size());
-
-  if (filtered_images.size() == 0) {
+  if (bitmaps.size() == 0) {
     return;
   }
 
@@ -71,13 +62,13 @@
 
   if (listener_) {
     std::vector<size_t> best_indices;
-    SelectFaviconFrameIndices(filtered_bitmap_sizes,
+    SelectFaviconFrameIndices(original_bitmap_sizes,
                               std::vector<int>(1U, kLargestIconSize),
                               &best_indices, nullptr);
 
     listener_->OnReceivedIcon(
         image_url,
-        filtered_images[best_indices.size() == 0 ? 0 : best_indices.front()]);
+        bitmaps[best_indices.size() == 0 ? 0 : best_indices.front()]);
   }
 }
 
@@ -98,10 +89,10 @@
         }
         web_contents()->DownloadImage(
             candidate->icon_url,
-            true,         // Is a favicon
-            gfx::Size(),  // No preferred size
-            0,            // Max bitmap size - 0 means unlimited
-            false,        // Normal cache policy
+            true,              // Is a favicon
+            gfx::Size(),       // No preferred size
+            kLargestIconSize,  // Max bitmap size
+            false,             // Normal cache policy
             base::BindOnce(&IconHelper::DownloadFaviconCallback,
                            base::Unretained(this)));
         break;
diff --git a/components/favicon/content/content_favicon_driver.cc b/components/favicon/content/content_favicon_driver.cc
index f185a4f..13025e8 100644
--- a/components/favicon/content/content_favicon_driver.cc
+++ b/components/favicon/content/content_favicon_driver.cc
@@ -96,15 +96,15 @@
 }
 
 int ContentFaviconDriver::DownloadImage(const GURL& url,
-                                        int preferred_size,
+                                        int max_image_size,
                                         ImageDownloadCallback callback) {
   bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
   bypass_cache_page_url_ = GURL();
 
-  const gfx::Size preferred_size_constraints(preferred_size, preferred_size);
-  return web_contents()->DownloadImage(url, true, preferred_size_constraints,
-                                       /*max_image_size = */ 0, bypass_cache,
-                                       std::move(callback));
+  const gfx::Size preferred_size(max_image_size, max_image_size);
+  return web_contents()->DownloadImage(url, true, preferred_size,
+                                       /*max_bitmap_size=*/max_image_size,
+                                       bypass_cache, std::move(callback));
 }
 
 void ContentFaviconDriver::DownloadManifest(const GURL& url,
diff --git a/components/favicon/content/content_favicon_driver.h b/components/favicon/content/content_favicon_driver.h
index 6cf0a23..000ac24 100644
--- a/components/favicon/content/content_favicon_driver.h
+++ b/components/favicon/content/content_favicon_driver.h
@@ -74,7 +74,7 @@
 
   // FaviconHandler::Delegate implementation.
   int DownloadImage(const GURL& url,
-                    int preferred_size,
+                    int max_image_size,
                     ImageDownloadCallback callback) override;
   void DownloadManifest(const GURL& url,
                         ManifestDownloadCallback callback) override;
diff --git a/components/favicon/core/favicon_handler.cc b/components/favicon/core/favicon_handler.cc
index 2bea93f..56f54be5 100644
--- a/components/favicon/core/favicon_handler.cc
+++ b/components/favicon/core/favicon_handler.cc
@@ -22,7 +22,6 @@
 #include "components/favicon_base/favicon_util.h"
 #include "components/favicon_base/select_favicon_frames.h"
 #include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_util.h"
@@ -714,8 +713,9 @@
   image_download_request_.Reset(
       base::BindOnce(&FaviconHandler::OnDidDownloadFavicon,
                      base::Unretained(this), icon_type));
-  // The maximal icon size is passed in to set the preferred size for vector
-  // images. See FaviconHandler::Delegate::DownloadImage() for more info.
+  // A max bitmap size is specified to avoid receiving huge bitmaps in
+  // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
+  // for more details about the max bitmap size.
   const int download_id = delegate_->DownloadImage(
       image_url, GetMaximalIconSize(handler_type_, !manifest_url_.is_empty()),
       image_download_request_.callback());
diff --git a/components/favicon/core/favicon_handler.h b/components/favicon/core/favicon_handler.h
index 7e2dc5f..2be71b2 100644
--- a/components/favicon/core/favicon_handler.h
+++ b/components/favicon/core/favicon_handler.h
@@ -93,14 +93,12 @@
     // is called with the results. Returns the unique id of the download
     // request, which will also be passed to the callback. In case of error, 0
     // is returned and no callback will be called.
-    // For vector images, |preferred_size| will serve as a viewport into which
-    // the image will be rendered. This would usually be the dimensions of the
-    // rectangle where the bitmap will be rendered. If |preferred_size| is
-    // empty, any existing intrinsic dimensions of the image will be used. All
-    // images are downloaded (without filtering by size), and all filtering is
-    // handled by the utility functions inside select_favicon_frames.cc.
+    // Bitmaps with pixel sizes larger than |max_bitmap_size| are filtered out
+    // from the bitmap results. If there are no bitmap results <=
+    // |max_bitmap_size|, the smallest bitmap is resized to |max_bitmap_size|
+    // and is the only result. A |max_bitmap_size| of 0 means unlimited.
     virtual int DownloadImage(const GURL& url,
-                              int preferred_size,
+                              int max_image_size,
                               ImageDownloadCallback callback) = 0;
 
     // Downloads a WebManifest and returns the favicons listed there.
diff --git a/components/favicon/core/favicon_handler_unittest.cc b/components/favicon/core/favicon_handler_unittest.cc
index 5736a55..7530efa 100644
--- a/components/favicon/core/favicon_handler_unittest.cc
+++ b/components/favicon/core/favicon_handler_unittest.cc
@@ -134,12 +134,21 @@
   // Implementation of FaviconHalder::Delegate's DownloadImage(). If a given
   // URL is not known (i.e. not previously added via Add()), it produces 404s.
   int DownloadImage(const GURL& url,
-                    int preferred_size,
+                    int max_image_size,
                     FaviconHandler::Delegate::ImageDownloadCallback callback) {
     downloads_->push_back(url);
 
     Response response = responses_[url];
     DCHECK_EQ(response.bitmaps.size(), response.original_bitmap_sizes.size());
+    // Apply maximum image size.
+    for (size_t i = 0; i < response.bitmaps.size(); ++i) {
+      if (response.bitmaps[i].width() > max_image_size ||
+          response.bitmaps[i].height() > max_image_size) {
+        response.bitmaps[i] = skia::ImageOperations::Resize(
+            response.bitmaps[i], skia::ImageOperations::RESIZE_LANCZOS3,
+            max_image_size, max_image_size);
+      }
+    }
 
     int download_id = next_download_id_++;
     base::OnceClosure bound_callback = base::BindOnce(
@@ -290,9 +299,9 @@
   }
 
   int DownloadImage(const GURL& url,
-                    int preferred_size,
+                    int max_image_size,
                     ImageDownloadCallback callback) override {
-    return fake_image_downloader_.DownloadImage(url, preferred_size,
+    return fake_image_downloader_.DownloadImage(url, max_image_size,
                                                 std::move(callback));
   }
 
@@ -1718,7 +1727,7 @@
   EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL2));
 }
 
-TEST_F(FaviconHandlerTest, TestFaviconNotScaledButSelectedCorrectly) {
+TEST_F(FaviconHandlerTest, TestFaviconWasScaledAfterDownload) {
   const int kMaximalSize = FaviconHandler::GetMaximalIconSize(
       FaviconDriverObserver::NON_TOUCH_LARGEST,
       /*candidates_from_web_manifest=*/false);
@@ -1735,10 +1744,10 @@
                                         SK_ColorBLUE);
 
   // Verify the best bitmap was selected (although smaller than |kIconURL2|)
-  // and that it was downloaded without any scaling.
+  // and that it was scaled down to |kMaximalSize|.
   EXPECT_CALL(delegate_,
               OnFaviconUpdated(_, _, kIconURL1, _,
-                               ImageSizeIs(kOriginalSize1, kOriginalSize1)));
+                               ImageSizeIs(kMaximalSize, kMaximalSize)));
 
   RunHandlerWithCandidates(
       FaviconDriverObserver::NON_TOUCH_LARGEST,
diff --git a/components/favicon/ios/web_favicon_driver.h b/components/favicon/ios/web_favicon_driver.h
index 9657294..84bbb2a 100644
--- a/components/favicon/ios/web_favicon_driver.h
+++ b/components/favicon/ios/web_favicon_driver.h
@@ -41,7 +41,7 @@
 
   // FaviconHandler::Delegate implementation.
   int DownloadImage(const GURL& url,
-                    int preferred_size,
+                    int max_image_size,
                     ImageDownloadCallback callback) override;
   void DownloadManifest(const GURL& url,
                         ManifestDownloadCallback callback) override;
diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm
index 150c776..00ca6e83 100644
--- a/components/favicon/ios/web_favicon_driver.mm
+++ b/components/favicon/ios/web_favicon_driver.mm
@@ -48,7 +48,7 @@
 }
 
 int WebFaviconDriver::DownloadImage(const GURL& url,
-                                    int preferred_size,
+                                    int max_image_size,
                                     ImageDownloadCallback callback) {
   static int downloaded_image_count = 0;
   int local_download_id = ++downloaded_image_count;
@@ -65,10 +65,7 @@
         std::vector<SkBitmap> frames;
         std::vector<gfx::Size> sizes;
         if (data) {
-          // From FaviconHandler::ScheduleImageDownload, the preferred_size
-          // contains the maximal size while the max_image_size is set to 0 to
-          // allow all files to be downloaded by the blink renderer.
-          frames = skia::ImageDataToSkBitmapsWithMaxSize(data, preferred_size);
+          frames = skia::ImageDataToSkBitmapsWithMaxSize(data, max_image_size);
           for (const auto& frame : frames) {
             sizes.push_back(gfx::Size(frame.width(), frame.height()));
           }
diff --git a/components/webapps/browser/installable/installable_manager.cc b/components/webapps/browser/installable/installable_manager.cc
index c85ce7a..8af8c3d6 100644
--- a/components/webapps/browser/installable/installable_manager.cc
+++ b/components/webapps/browser/installable/installable_manager.cc
@@ -922,12 +922,14 @@
                                ? kMinimumScreenshotSizeInPx
                                : std::max(url->image.sizes[0].width(),
                                           url->image.sizes[0].height());
-    // Passing in kMaximumScreenshotSizeInPx ensures that screenshots above that
-    // size are filtered out by the blink image_downloader implementation.
-    // Thus, we no longer need them to be resized in OnScreenshotFetched().
+    // Do not pass in a maximum icon size so that screenshots larger than
+    // kMaximumScreenshotSizeInPx are not downscaled to the maximum size by
+    // `ManifestIconDownloader::Download`. Screenshots with size larger than
+    // kMaximumScreenshotSizeInPx get filtered out by OnScreenshotFetched.
     bool can_download = content::ManifestIconDownloader::Download(
         GetWebContents(), url->image.src, ideal_size_in_px,
-        kMinimumScreenshotSizeInPx, kMaximumScreenshotSizeInPx,
+        kMinimumScreenshotSizeInPx,
+        /*maximum_icon_size_in_px=*/0,
         base::BindOnce(&InstallableManager::OnScreenshotFetched,
                        weak_factory_.GetWeakPtr(), url->image.src),
         /*square_only=*/false);
@@ -969,7 +971,12 @@
       auto iter = downloaded_screenshots_.find(url->image.src);
       if (iter == downloaded_screenshots_.end())
         continue;
+
       auto screenshot = iter->second;
+      if (screenshot.dimensions().width() > kMaximumScreenshotSizeInPx ||
+          screenshot.dimensions().height() > kMaximumScreenshotSizeInPx) {
+        continue;
+      }
 
       // Screenshots must have the same aspect ratio. Cross-multiplying
       // dimensions checks portrait vs landscape mode (1:2 vs 2:1 for instance).
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 6c7be7d..2096290 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -7,12 +7,10 @@
 #include <algorithm>
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/cxx17_backports.h"
-#include "base/numerics/safe_conversions.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
@@ -41,9 +39,7 @@
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/favicon_size.h"
-#include "ui/gfx/image/image_util.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #include "content/browser/media/session/media_session_android.h"
@@ -869,25 +865,17 @@
     const GURL& image_url,
     const std::vector<SkBitmap>& bitmaps,
     const std::vector<gfx::Size>& sizes) {
-  DCHECK_EQ(bitmaps.size(), sizes.size());
-
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_bitmap_sizes;
-  gfx::FilterAndResizeImagesForMaximalSize(
-      bitmaps, base::checked_cast<uint32_t>(desired_size_px), filtered_images,
-      filtered_bitmap_sizes);
-  DCHECK_EQ(filtered_images.size(), filtered_bitmap_sizes.size());
-
+  DCHECK(bitmaps.size() == sizes.size());
   SkBitmap image;
   double best_image_score = 0.0;
 
-  // Rank |filtered_bitmap_sizes| and |filtered_images| using MediaImageManager.
-  for (size_t i = 0; i < filtered_images.size(); i++) {
+  // Rank |sizes| and |bitmaps| using MediaImageManager.
+  for (size_t i = 0; i < bitmaps.size(); i++) {
     double image_score = media_session::MediaImageManager::GetImageSizeScore(
-        minimum_size_px, desired_size_px, filtered_bitmap_sizes.at(i));
+        minimum_size_px, desired_size_px, sizes.at(i));
 
     if (image_score > best_image_score)
-      image = filtered_images.at(i);
+      image = bitmaps.at(i);
   }
 
   // If the image is the wrong color type then we should convert it.
@@ -1334,7 +1322,7 @@
   const gfx::Size preferred_size(desired_size_px, desired_size_px);
   web_contents()->DownloadImage(
       image.src, false /* is_favicon */, preferred_size,
-      /*max_bitmap_size=*/0, false /* bypass_cache */,
+      desired_size_px /* max_bitmap_size */, false /* bypass_cache */,
       base::BindOnce(&MediaSessionImpl::OnImageDownloadComplete,
                      base::Unretained(this),
                      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index e7ccd06..4d57232 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -20,8 +20,6 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
 #include "content/browser/media/media_web_contents_observer.h"
@@ -37,9 +35,7 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
-#include "skia/ext/image_operations.h"
 #include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_assistant_structure.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_tree_update.h"
@@ -49,7 +45,6 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image_util.h"
 #include "url/android/gurl_android.h"
 #include "url/gurl.h"
 
@@ -726,19 +721,13 @@
     jint max_bitmap_size,
     jboolean bypass_cache,
     const base::android::JavaParamRef<jobject>& jcallback) {
-  ScopedJavaGlobalRef<jobject> j_callback;
-  j_callback.Reset(env, jcallback);
-  // The max_image_size of 0 being passed to web_contents_->DownloadImage()
-  // ensures that all images are fetched by the renderer before being
-  // resized/filtered out in WebContentsAndroid::OnFinishDownloadImage()
-  // using the max_bitmap_size in a separate threadpool.
   const gfx::Size preferred_size;
   return web_contents_->DownloadImage(
       *url::GURLAndroid::ToNativeGURL(env, jurl), is_fav_icon, preferred_size,
-      /*max_image_size=*/0, bypass_cache,
+      max_bitmap_size, bypass_cache,
       base::BindOnce(&WebContentsAndroid::OnFinishDownloadImage,
-                     weak_factory_.GetWeakPtr(), j_callback,
-                     base::checked_cast<uint32_t>(max_bitmap_size)));
+                     weak_factory_.GetWeakPtr(), obj_,
+                     ScopedJavaGlobalRef<jobject>(env, jcallback)));
 }
 
 void WebContentsAndroid::SetHasPersistentVideo(JNIEnv* env, jboolean value) {
@@ -782,45 +771,13 @@
 }
 
 void WebContentsAndroid::OnFinishDownloadImage(
-    const base::android::ScopedJavaGlobalRef<jobject>& callback,
-    uint32_t max_image_size,
-    int id,
-    int http_status_code,
-    const GURL& url,
-    const std::vector<SkBitmap>& bitmaps,
-    const std::vector<gfx::Size>& sizes) {
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_bitmap_sizes;
-
-  base::ThreadPool::PostTaskAndReply(
-      FROM_HERE, {base::TaskPriority::USER_VISIBLE},
-      base::BindOnce(&WebContentsAndroid::FilterOrResizeReceivedImages,
-                     weak_factory_.GetWeakPtr(), bitmaps, max_image_size,
-                     std::ref(filtered_images),
-                     std::ref(filtered_bitmap_sizes)),
-      base::BindOnce(&WebContentsAndroid::ConvertToJavaBitmap,
-                     weak_factory_.GetWeakPtr(), obj_, callback, id,
-                     http_status_code, url, filtered_images,
-                     filtered_bitmap_sizes));
-}
-
-void WebContentsAndroid::FilterOrResizeReceivedImages(
-    const std::vector<SkBitmap>& bitmaps,
-    uint32_t max_image_size,
-    std::vector<SkBitmap>& filtered_images,
-    std::vector<gfx::Size>& filtered_bitmap_sizes) {
-  gfx::FilterAndResizeImagesForMaximalSize(
-      bitmaps, max_image_size, filtered_images, filtered_bitmap_sizes);
-}
-
-void WebContentsAndroid::ConvertToJavaBitmap(
     const JavaRef<jobject>& obj,
     const JavaRef<jobject>& callback,
     int id,
     int http_status_code,
     const GURL& url,
-    const std::vector<SkBitmap>& filtered_images,
-    const std::vector<gfx::Size>& filtered_bitmap_sizes) {
+    const std::vector<SkBitmap>& bitmaps,
+    const std::vector<gfx::Size>& sizes) {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> jbitmaps =
       Java_WebContentsImpl_createBitmapList(env);
@@ -828,15 +785,14 @@
       Java_WebContentsImpl_createSizeList(env);
   ScopedJavaLocalRef<jobject> jurl = url::GURLAndroid::FromNativeGURL(env, url);
 
-  DCHECK_EQ(filtered_images.size(), filtered_bitmap_sizes.size());
-  for (const SkBitmap& bitmap : filtered_images) {
-    // WARNING: converting to java bitmaps results in duplicate memory
+  for (const SkBitmap& bitmap : bitmaps) {
+    // WARNING: convering to java bitmaps results in duplicate memory
     // allocations, which increases the chance of OOMs if DownloadImage() is
     // misused.
     ScopedJavaLocalRef<jobject> jbitmap = gfx::ConvertToJavaBitmap(bitmap);
     Java_WebContentsImpl_addToBitmapList(env, jbitmaps, jbitmap);
   }
-  for (const gfx::Size& size : filtered_bitmap_sizes) {
+  for (const gfx::Size& size : sizes) {
     Java_WebContentsImpl_createSizeAndAddToList(env, jsizes, size.width(),
                                                 size.height());
   }
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index f28c0d19..2b278693 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -215,26 +215,13 @@
   void RemoveDestructionObserver(DestructionObserver* observer);
 
  private:
-  void OnFinishDownloadImage(
-      const base::android::ScopedJavaGlobalRef<jobject>& jcallback,
-      uint32_t max_image_size,
-      int id,
-      int http_status_code,
-      const GURL& url,
-      const std::vector<SkBitmap>& bitmaps,
-      const std::vector<gfx::Size>& sizes);
-  void FilterOrResizeReceivedImages(
-      const std::vector<SkBitmap>& bitmaps,
-      uint32_t max_image_size,
-      std::vector<SkBitmap>& filtered_images,
-      std::vector<gfx::Size>& filtered_bitmap_sizes);
-  void ConvertToJavaBitmap(const base::android::JavaRef<jobject>& obj,
-                           const base::android::JavaRef<jobject>& callback,
-                           int id,
-                           int http_status_code,
-                           const GURL& url,
-                           const std::vector<SkBitmap>& filtered_images,
-                           const std::vector<gfx::Size>& filtered_bitmap_sizes);
+  void OnFinishDownloadImage(const base::android::JavaRef<jobject>& obj,
+                             const base::android::JavaRef<jobject>& callback,
+                             int id,
+                             int http_status_code,
+                             const GURL& url,
+                             const std::vector<SkBitmap>& bitmaps,
+                             const std::vector<gfx::Size>& sizes);
   void SelectAroundCaretAck(blink::mojom::SelectAroundCaretResultPtr result);
   // Walks over the AXTreeUpdate and creates a light weight snapshot.
   void AXTreeSnapshotCallback(
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 2ee2f2a..c12e9514 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -1096,8 +1096,8 @@
   // be called with the bitmaps received from the renderer.
   // If |is_favicon| is true, the cookies are not sent and not accepted during
   // download.
-  // Bitmaps with pixel sizes larger than |max_bitmap_size| are filtered out
-  // from the bitmap results.
+  // If there are no bitmap results <= |max_bitmap_size|, the smallest bitmap
+  // is resized to |max_bitmap_size| and is the only result.
   // A |max_bitmap_size| of 0 means unlimited.
   // For vector images, |preferred_size| will serve as a viewport into which
   // the image will be rendered. This would usually be the dimensions of the
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
index e30f7ae5..db9b9d38 100644
--- a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
+++ b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/check.h"
-#include "base/numerics/safe_conversions.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_registry.h"
@@ -59,12 +58,29 @@
   return DecodeImageData(data, mime_type, preferred_size);
 }
 
-// Images are allowed only if the following criteria is true:
-// If |max_image_size| == 0, denoting that no upper limit is provided for image
-// size.
-// If size of image (width and height) is <= max_image_size.
-// For all other cases, the image is filtered out.
-void FilterImagesBasedOnMaximalSize(
+//  Proportionally resizes the |image| to fit in a box of size
+// |max_image_size|.
+SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) {
+  if (max_image_size == 0)
+    return image;
+  uint32_t max_dimension = std::max(image.width(), image.height());
+  if (max_dimension <= max_image_size)
+    return image;
+  // Proportionally resize the minimal image to fit in a box of size
+  // max_image_size.
+  return skia::ImageOperations::Resize(
+      image, skia::ImageOperations::RESIZE_BEST,
+      static_cast<uint32_t>(image.width()) * max_image_size / max_dimension,
+      static_cast<uint32_t>(image.height()) * max_image_size / max_dimension);
+}
+
+// Filters the array of bitmaps, removing all images that do not fit in a box of
+// size |max_image_size|. Returns the result if it is not empty. Otherwise,
+// find the smallest image in the array and resize it proportionally to fit
+// in a box of size |max_image_size|.
+// Sets |original_image_sizes| to the sizes of |images| before resizing. Both
+// output vectors are guaranteed to have the same size.
+void FilterAndResizeImagesForMaximalSize(
     const WTF::Vector<SkBitmap>& unfiltered,
     uint32_t max_image_size,
     WTF::Vector<SkBitmap>* images,
@@ -75,14 +91,38 @@
   if (unfiltered.IsEmpty())
     return;
 
-  for (const SkBitmap& image : unfiltered) {
-    if ((max_image_size == 0) ||
-        (base::checked_cast<uint32_t>(image.width()) <= max_image_size &&
-         base::checked_cast<uint32_t>(image.height()) <= max_image_size)) {
+  if (max_image_size == 0)
+    max_image_size = std::numeric_limits<uint32_t>::max();
+
+  const SkBitmap* min_image = nullptr;
+  uint32_t min_image_size = std::numeric_limits<uint32_t>::max();
+  // Filter the images by |max_image_size|, and also identify the smallest image
+  // in case all the images are bigger than |max_image_size|.
+  for (auto* it = unfiltered.begin(); it != unfiltered.end(); ++it) {
+    const SkBitmap& image = *it;
+    uint32_t current_size = std::max(it->width(), it->height());
+    if (current_size < min_image_size) {
+      min_image = &image;
+      min_image_size = current_size;
+    }
+    if (static_cast<uint32_t>(image.width()) <= max_image_size &&
+        static_cast<uint32_t>(image.height()) <= max_image_size) {
       images->push_back(image);
       original_image_sizes->push_back(gfx::Size(image.width(), image.height()));
     }
   }
+  DCHECK(min_image);
+  if (images->size())
+    return;
+  // Proportionally resize the minimal image to fit in a box of size
+  // |max_image_size|.
+  SkBitmap resized = ResizeImage(*min_image, max_image_size);
+  // Drop null or empty SkBitmap.
+  if (resized.drawsNothing())
+    return;
+  images->push_back(resized);
+  original_image_sizes->push_back(
+      gfx::Size(min_image->width(), min_image->height()));
 }
 
 }  // namespace
@@ -163,8 +203,8 @@
     const WTF::Vector<SkBitmap>& images) {
   WTF::Vector<SkBitmap> result_images;
   WTF::Vector<gfx::Size> result_original_image_sizes;
-  FilterImagesBasedOnMaximalSize(images, max_image_size, &result_images,
-                                 &result_original_image_sizes);
+  FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images,
+                                      &result_original_image_sizes);
 
   DCHECK_EQ(result_images.size(), result_original_image_sizes.size());
 
diff --git a/ui/gfx/image/image_util.cc b/ui/gfx/image/image_util.cc
index bb49ea5..63305ce 100644
--- a/ui/gfx/image/image_util.cc
+++ b/ui/gfx/image/image_util.cc
@@ -8,17 +8,13 @@
 
 #include <algorithm>
 #include <memory>
-#include <vector>
 
-#include "base/check.h"
 #include "base/cxx17_backports.h"
-#include "base/numerics/safe_conversions.h"
 #include "build/build_config.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/webp_codec.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
@@ -162,61 +158,4 @@
   *right = bitmap.width() - 1 - x;
 }
 
-SkBitmap ResizeImageToLargestSize(const SkBitmap& image,
-                                  uint32_t max_image_size) {
-  uint32_t max_dimension = std::max(image.width(), image.height());
-  if (max_dimension <= max_image_size)
-    return image;
-  // Proportionally resize the minimal image to fit in a box of size
-  // max_image_size.
-  return skia::ImageOperations::Resize(
-      image, skia::ImageOperations::RESIZE_BEST,
-      base::checked_cast<uint32_t>(image.width()) * max_image_size /
-          max_dimension,
-      base::checked_cast<uint32_t>(image.height()) * max_image_size /
-          max_dimension);
-}
-
-void FilterAndResizeImagesForMaximalSize(
-    const std::vector<SkBitmap>& images,
-    uint32_t max_image_size,
-    std::vector<SkBitmap>& filtered_images,
-    std::vector<gfx::Size>& filtered_image_sizes) {
-  filtered_images.clear();
-  filtered_image_sizes.clear();
-
-  if (images.empty())
-    return;
-
-  const SkBitmap* min_image = nullptr;
-  uint32_t min_image_size = std::numeric_limits<uint32_t>::max();
-  // Filter the images by |max_image_size|, and also identify the smallest
-  // image in case all the images are bigger than |max_image_size|.
-  for (const SkBitmap& image : images) {
-    uint32_t current_size = std::max(image.width(), image.height());
-    if (current_size < min_image_size) {
-      min_image = &image;
-      min_image_size = current_size;
-    }
-    if (base::checked_cast<uint32_t>(image.width()) <= max_image_size &&
-        base::checked_cast<uint32_t>(image.height()) <= max_image_size) {
-      filtered_images.emplace_back(image);
-      filtered_image_sizes.emplace_back(
-          gfx::Size(image.width(), image.height()));
-    }
-  }
-  if (!filtered_images.empty())
-    return;
-  // Proportionally resize the minimal image to fit in a box of size
-  // |max_image_size|.
-  DCHECK(min_image);
-  SkBitmap resized = ResizeImageToLargestSize(*min_image, max_image_size);
-  // Drop null or empty SkBitmap.
-  if (resized.drawsNothing())
-    return;
-  filtered_images.emplace_back(resized);
-  filtered_image_sizes.emplace_back(
-      gfx::Size(min_image->width(), min_image->height()));
-}
-
 }  // namespace gfx
diff --git a/ui/gfx/image/image_util.h b/ui/gfx/image/image_util.h
index 140403e50..aa954a2 100644
--- a/ui/gfx/image/image_util.h
+++ b/ui/gfx/image/image_util.h
@@ -9,8 +9,6 @@
 
 #include <vector>
 
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gfx_export.h"
 
 namespace gfx {
@@ -76,24 +74,6 @@
                                                      int max_height,
                                                      int max_area);
 
-// Proportionally resizes the |image| to fit in a box of size
-// |max_image_size|. If the |image| already fits, it is
-// returned without any resizing.
-GFX_EXPORT SkBitmap ResizeImageToLargestSize(const SkBitmap& image,
-                                             uint32_t max_image_size);
-
-// Filters the array of bitmaps, removing all images that do not fit in a box of
-// size |max_image_size|. Returns the result if it is not empty. Otherwise,
-// find the smallest image in the array and resize it proportionally to fit
-// in a box of size |max_image_size|.
-// Sets |filtered_image_sizes| to the sizes of |filtered_images| before
-// resizing. Both output vectors are guaranteed to have the same size.
-GFX_EXPORT void FilterAndResizeImagesForMaximalSize(
-    const std::vector<SkBitmap>& images,
-    uint32_t max_image_size,
-    std::vector<SkBitmap>& filtered_images,
-    std::vector<gfx::Size>& filtered_image_sizes);
-
 }  // namespace gfx
 
 #endif  // UI_GFX_IMAGE_IMAGE_UTIL_H_
diff --git a/ui/gfx/image/image_util_unittest.cc b/ui/gfx/image/image_util_unittest.cc
index 5244772..0ef65fd 100644
--- a/ui/gfx/image/image_util_unittest.cc
+++ b/ui/gfx/image/image_util_unittest.cc
@@ -14,17 +14,6 @@
 #include "ui/gfx/image/image_unittest_util.h"
 #include "ui/gfx/image/resize_image_dimensions.h"
 
-namespace {
-
-SkBitmap CreateRandomImage(int size, SkColor color) {
-  SkBitmap bitmap;
-  bitmap.allocN32Pixels(size, size);
-  bitmap.eraseColor(color);
-  return bitmap;
-}
-
-}  // namespace
-
 TEST(ImageUtilTest, JPEGEncodeAndDecode) {
   gfx::Image original = gfx::test::CreateImage(100, 100);
 
@@ -168,70 +157,3 @@
   EXPECT_EQ(resized_image.Width(), 400);
   EXPECT_EQ(resized_image.Height(), 400);
 }
-
-TEST(ImageUtilTest, NoFilterNoResize) {
-  std::vector<SkBitmap> previous_images;
-  previous_images.push_back(CreateRandomImage(1, SK_ColorBLACK));
-  previous_images.push_back(CreateRandomImage(2, SK_ColorGRAY));
-  previous_images.push_back(CreateRandomImage(3, SK_ColorBLUE));
-
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_sizes;
-  gfx::FilterAndResizeImagesForMaximalSize(
-      previous_images, /*max_image_size=*/5, filtered_images, filtered_sizes);
-
-  // No image gets filtered.
-  EXPECT_EQ(filtered_images.size(), previous_images.size());
-  EXPECT_EQ(3u, filtered_sizes.size());
-  EXPECT_EQ(SK_ColorBLACK, filtered_images.at(0).getColor(0, 0));
-  EXPECT_EQ(SK_ColorGRAY, filtered_images.at(1).getColor(1, 1));
-  EXPECT_EQ(SK_ColorBLUE, filtered_images.at(2).getColor(2, 2));
-}
-
-TEST(ImageUtilTest, FilterImageNoResize) {
-  std::vector<SkBitmap> previous_images;
-  previous_images.push_back(CreateRandomImage(1, SK_ColorBLACK));
-  previous_images.push_back(CreateRandomImage(3, SK_ColorGRAY));
-  previous_images.push_back(CreateRandomImage(4, SK_ColorBLUE));
-
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_sizes;
-  gfx::FilterAndResizeImagesForMaximalSize(
-      previous_images, /*max_image_size=*/2, filtered_images, filtered_sizes);
-
-  // No image gets filtered.
-  EXPECT_EQ(1u, filtered_images.size());
-  EXPECT_EQ(1u, filtered_sizes.size());
-  EXPECT_EQ(SK_ColorBLACK, filtered_images.at(0).getColor(0, 0));
-  // Verify grey and blue SkBitmaps are not in the filtered image.
-  EXPECT_NE(SK_ColorGRAY, filtered_images.at(0).getColor(0, 0));
-  EXPECT_NE(SK_ColorBLUE, filtered_images.at(0).getColor(0, 0));
-}
-
-TEST(ImageUtilTest, AllFilterOnlyResize) {
-  std::vector<SkBitmap> previous_images;
-  previous_images.push_back(CreateRandomImage(6, SK_ColorBLACK));
-  previous_images.push_back(CreateRandomImage(5, SK_ColorGRAY));
-  previous_images.push_back(CreateRandomImage(4, SK_ColorBLUE));
-
-  std::vector<SkBitmap> filtered_images;
-  std::vector<gfx::Size> filtered_sizes;
-  gfx::FilterAndResizeImagesForMaximalSize(
-      previous_images, /*max_image_size=*/3, filtered_images, filtered_sizes);
-
-  // Only 1 image gets resized, and it is the smallest one (the blue one).
-  // All other images are not filtered.
-  EXPECT_EQ(1u, filtered_images.size());
-  EXPECT_EQ(1u, filtered_sizes.size());
-  // Verify that resizing happens to proper size.
-  EXPECT_EQ(3, filtered_images.at(0).dimensions().width());
-  EXPECT_EQ(3, filtered_images.at(0).dimensions().height());
-  // Original sizes.
-  EXPECT_EQ(4, filtered_sizes.at(0).width());
-  EXPECT_EQ(4, filtered_sizes.at(0).height());
-  // Verify grey and black SkBitmaps are not in the filtered image.
-  // Only blue image is filtered.
-  EXPECT_EQ(SK_ColorBLUE, filtered_images.at(0).getColor(0, 0));
-  EXPECT_NE(SK_ColorGRAY, filtered_images.at(0).getColor(0, 0));
-  EXPECT_NE(SK_ColorBLACK, filtered_images.at(0).getColor(0, 0));
-}